7

Mathematica has the CheckAbort function which allows to catch and handle user-generated and programmatic Aborts. But it does not allow to catch interrupts generated by such functions as TimeConstrained and MemoryConstrained:

TimeConstrained[CheckAbort[Pause[100], Print["From CheckAbort"]], 1]

(does not print "From CheckAbort").

Is there a way to catch such interrupts in Mathematica?

EDIT: I do know that third argument of TimeConstrained and MemoryConstrained allows to evaluate some code in the case of interrupt but this way is not what I need: I need a way to handle such interrupts entirely inside of my function allowing a user do not care of its internals.

P.S. The reason why I need this is that I have a function that creates MathLink objects which must be closed in the case of any interrupts or aborts but not in other cases.

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

4 Answers4

13

The construct for this is available in undocumented form.

Internal`WithLocalSettings[
  preprocessing,
  code,
  postprocessing]

will cause postprocessing to take place before returning from aborts or various types of jumps.

See also:

Reliable clean-up in Mathematica

Import big files/arrays with mathematica

Daniel Lichtblau

Community
  • 1
  • 1
Daniel Lichtblau
  • 6,854
  • 1
  • 23
  • 30
  • ``Internal`WithLocalSettings`` evaluates `postprocessing` in any case, not only when an interrupt happens. I need not to close `MathLink` connections after any evaluation of my function - only when some interrupt or abort happens. – Alexey Popkov Sep 28 '11 at 17:12
  • 2
    This could work if a "done" flag is introduced, e.g. ``TimeConstrained[Module[{done=False},Internal`WithLocalSettings[Print@"start",Pause[100];done=True,If[!done, Print@"Interrupted!"]]], 5]`` – WReach Sep 28 '11 at 18:00
  • @WReach Good idea! But your solution does not preserve the semantics of `TimeConstrained` that returns output from the function it the time constrain is met. I also wish to avoid double evaluation of the output of my function. – Alexey Popkov Sep 28 '11 at 18:34
  • @Leonid I felt that your first edit is very close to solution but was unable to find the key - WReach has given it. I will post improved version of WReach's solution as a separate answer. – Alexey Popkov Sep 28 '11 at 19:04
  • @Alexey Ok, the code by WReach is much simpler. I tried similar things but somehow missed this possibility. I will leave my answer for some time and then will delete it. It also sounds like a a good idea to post the answer based on the suggestion of WReach as a separate one. – Leonid Shifrin Sep 28 '11 at 19:15
  • @WReach Please disregard my previous comment - your suggestion is much closer to the OP needs than what I did – Leonid Shifrin Sep 28 '11 at 19:20
  • I used this function a lot recently, like this: `WithLocalSettings[Null, allocateMemoryInCFunction[]; ..., freeCMemory[]]`. I learned about it from [here](http://mathematica.stackexchange.com/a/1603/12). Do you know about any caveats I should be aware of, other than the bad interaction with Throw/Catch that Leonid mentioned? – Szabolcs Apr 04 '13 at 23:25
3

Here is improved version of WReach's solution (he suggested it in a comment to the answer by Daniel Lichtblau). I should redefine my function f as follows (and now call it as ff):

ClearAll[ff];
SetAttributes[ff, HoldAllComplete];
ff[expr_] /; (Unset[done]; True) := 
 Internal`WithLocalSettings[Null, done = f[expr], 
  AbortProtect[If[! ValueQ[done], Print["Interrupt!"]]; Unset[done]]]

Examples:

ff[1 + 1]
(*=>f[2]*)
TimeConstrained[ff[Pause[10]; 1 + 1], 1]
(*=> prints "Interrupt!"*)
TimeConstrained[ff[Pause[.10]; 1 + 1], 1]
(*=>f[2]*)
Alexey Popkov
  • 9,355
  • 4
  • 42
  • 93
1
TimeConstrained[Pause[100], 1, Print["-->Aborted"]]

and

MemoryConstrained[100!, 1, Print["-->Aborted"]]
Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
  • I meant a way to catch aborts entirely inside of my function, allowing a user do not care of closing my `MathLink` connections. – Alexey Popkov Sep 28 '11 at 16:59
  • @Alexey `outerFunc[x_]:=TimeConstrained[innerFunc[x],10, Print[..]]`? ... shieding it ... – Dr. belisarius Sep 28 '11 at 17:01
  • I need not `TimeConstrained` inside of my function. I just wish to allow a user to use it without risk to run into problems. – Alexey Popkov Sep 28 '11 at 17:04
  • @Alexey Could you post an example of your intended usage? One not covered by the third argument, I mean. – Dr. belisarius Sep 28 '11 at 17:07
  • Given `f[expr]` as my `MathLink` function which evaluates `expr` in a slave kernel, I wish to allow a user to write `TimeConstrained[f[expr],10]` without care of internals of `f` (without using of the third argument). – Alexey Popkov Sep 28 '11 at 17:17
  • I just have realized that it probably may be made by defining an `UpValue` for `f`. But it will work only if `f` is on level 1 inside of `TimeConstrained`. – Alexey Popkov Sep 28 '11 at 17:28
  • @Alexey You could also redefine `TimeConstrained` to do wht you want http://stackoverflow.com/questions/6003224/trouble-redefining-an-internal-function – Dr. belisarius Sep 28 '11 at 18:01
  • I do not like to redefine built-in functions but is seems that in this case it is the only possibility. :( – Alexey Popkov Sep 28 '11 at 18:10
0

I am putting this here just to flesh out Danny's answer. I think this is clearly a bug in CheckAbort, and would use this as a workaround:

Attributes[myCheckAbort] = {HoldAll};
myCheckAbort[arg1_, arg2_] := Block[
    {res, aborted},
    WithCleanup[
        aborted = True
        ,
        res = arg1;
        aborted = False;
        res
        ,
        If[aborted,
            arg2;
            res = $Aborted
        ]
    ]
]
Jason B.
  • 162
  • 14