4

By default pressing Alt+. or calling Abort[] within the evaluation causes abort of the currently evaluating input. But when working in the FrontEnd we usually send to the kernel a sequence of inputs. For example, if we type the following three expressions on separate lines in one Cell and then press Shift+Enter we get infinite evaluation:

f := CheckAbort[Pause[.1], Abort[]]
While[True, f]
While[True, f]
While[True, f]

To stop this infinite evaluation we must to press Alt+. three times.

How to define the function f in the example above in such a way that pressing Alt+. one time will abort the evaluation of the full sequence of inputs without quitting the kernel?

EDIT

I think that if the FrontEnd creates an input queue for MathKernel it probably can also cancel this queue.

Alexey Popkov
  • 9,355
  • 4
  • 42
  • 93
  • I would split the input into four cells. – Sasha Apr 11 '11 at 18:51
  • 1
    @Sasha, true, however, the behavior extends over several input cells. If you are running multiple calculations sequentially and one fails, it is ***very*** difficult to shut it down. – rcollyer Apr 11 '11 at 23:36
  • @rcollyer You have explained the primary reason why we need to have a way to STOP evaluation of the whole `EvaluationNotebook[]` not just the current input line. It is very strange that up to this time we have no way to do this in the FrontEnd! A keyboard combination for this would be VERY useful for many people and it is so easy to implement this! FrontEnd must just cancel unsent input packets queried for sending to the kernel! – Alexey Popkov Apr 13 '11 at 07:32
  • And in really we even have no way just to stop evaluation of the current input line securely! Pressing Alt+"." we just send Abort[] command to the kernel but not necessarily terminate evaluation! It would be right design if we would have explicit control over interception of aborts. But we have no such control! [Some built-in functions can absorb the abort sent!](http://stackoverflow.com/questions/5636135/checkabort-inside-mathlink-functions) – Alexey Popkov Apr 13 '11 at 07:40
  • it was worse in earlier versions, pre-v.6, if execution got into the rendering loop, i.e. front-end, then it was impossible to abort, period. So, if you had done something wrong, as often indicated by it taking forever, then you had to wait for it to complete, or completely kill it. In later versions, it is a little more responsive to that, but it is still not perfect. – rcollyer Apr 13 '11 at 12:41

3 Answers3

6

Sasha's suggestion to just use four cells is valid, because that's basically what the FrontEnd does anyway, submitting several distinct evaluations to the Kernel. If you insist in using one cell, wrap it in parens (CompoundExpression), which causes those four lines to be treated as one evaluation (note the need for ; too):

(
   f := CheckAbort[Pause[.1], Abort[]];
   While[True, f];
   While[True, f];
   While[True, f]
)

Then, one abort issued will abort the evaluation as a whole.

Michael Pilat
  • 6,480
  • 27
  • 30
  • 2
    This approach has at least one disadvantage: we must explicitly wrap every expression we wish to see in the output by `Print`. However by using `CellEvaluationFunction` (uncovered by WReach [here](http://stackoverflow.com/questions/4198961/what-is-in-your-mathematica-tool-bag/5451304#5451304)) we probably could do this automatically. – Alexey Popkov Apr 13 '11 at 07:05
1

I have found a way to do what I want. The only problem is that at this moment I do not know how to check whether the FrontEnd has some pending inputs. I am forced just to wait 1 second. In the most cases it is sufficient time for sending all pending inputs to the kernel but probably not always.

In[1]:= $new$PreRead = False;
AbortAllPendingInputs := 
  AbortProtect[If[! $new$PreRead, $new$PreRead = True;
    $TimeOfAbort = SessionTime[];
    last$PreRead = ToString[Definition[$PreRead], InputForm];
    ClearAll[$PreRead];
    $PreRead := If[TrueQ[SessionTime[] - $TimeOfAbort < 1], "",
       $new$PreRead = False;
       ClearAll[$PreRead];
       If[last$PreRead === "Null", #, 
        ToExpression[last$PreRead]; $PreRead@#]
       ] &;]];

In[3]:= f := CheckAbort[Pause[10], AbortAllPendingInputs; Abort[]]

In[4]:= While[True, f]
While[True, f]
While[True, f]

Out[4]= $Aborted

But I am still looking for more elegant solution. I think that if the FrontEnd creates an input queue for MathKernel it probably can also cancel this queue.

Alexey Popkov
  • 9,355
  • 4
  • 42
  • 93
1

Alexey, please try this version of your code and tell me if/when it fails:

AbortAllPendingInputs :=
  AbortProtect[
    $new$PreRead = True;
    $TimeOfAbort = SessionTime[];
    last$PreRead = $PreRead;
    $PreRead = 
      If[
         TrueQ[SessionTime[] - $TimeOfAbort < 1], 
         "",
         $new$PreRead = False; $PreRead = last$PreRead; $PreRead[#]
        ] &;
  ] /; ! TrueQ[$new$PreRead]
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • Thank you for more elegant version of my function. But the only fail is related to the fact that sometimes the last input packet is sent *later* than 1 second after pressing Alt+".". But we can not increase this time constrain because if we do this then sometimes a user can press Shift+Inter before the constrain fires... – Alexey Popkov Apr 13 '11 at 07:48
  • If we would have the function [I am asking for](http://stackoverflow.com/questions/5643302/how-to-check-whether-the-frontend-considers-evaluation-still-running) we could use a combination of `$PreRead` and `$Post` to cancel unsent packets in a secure way. – Alexey Popkov Apr 13 '11 at 07:51
  • @Alexey I am working on other things right now, and I don't usually dig into the "nuts and bolts" of Mathematica this much. Regarding your overarching problem, did you exhaust the possibility of using `Evaluator` or `CellEvaluationFunction` etc., for passing code to the 5.2 kernel? – Mr.Wizard Apr 13 '11 at 08:02
  • @Mr.Wizard I have not tried `CellEvaluationFunction` yet. This approach requires modifying `EvaluationNotebook[]` and changing the default way how *Mathematica* outputs the results. We also must change the original Cell's content on the fly. I'll think about it. – Alexey Popkov Apr 13 '11 at 08:15
  • @Mr.Wizard Regarding your modification of `last$PreRead` definition. It will work only if `$PreRead` was defined as `OwnValue` but not `DownValue`. And your version can not restore `Attributes`. I think my original solution is more general. – Alexey Popkov Apr 13 '11 at 08:26
  • @Alexey, in review, I agree. I was trying to respond with a "more elegant solution" but I did not give this the time it deserved. I don't know when I'll get around to it, but I will think about your main objective, and see if I have anything to offer. – Mr.Wizard Apr 13 '11 at 08:45