Intercepting and Controlling Mathematica Exceptions.
- To: mathgroup at smc.vnet.net
- Subject: [mg71889] Intercepting and Controlling Mathematica Exceptions.
- From: "Philipp" <Philipp.M.O at gmail.com>
- Date: Sat, 2 Dec 2006 05:11:23 -0500 (EST)
Dear All, The following code was inspired by, or based upon: 1. the $AbortMessage trap concept by Omega Consulting Group (omegaconsultinggroup.com) originally published as "Aborting Messages" in "In and Out" section of The Mathematica Journal, 9.4, 2. private communication with Dale from Omega Consulting Group (omegaconsultinggroup.com), 3. a posting by Carl Woll from Wolfram Research (http://groups.google.co.uk/group/comp.soft-sys.math.mathematica/browse_frm/thread/b4b92edd3116863b/361984f703ef6306?lnk=gst&q=%24AbortMessage&rnum=1#361984f703ef6306). The described below MessagesAbort[] mechanism is extremely useful, especially in situations where repetitive, though time consuming calculation are performed. I face such situation frequently. I receive updated daily, third party stock market data stored in binary files that I search for interesting patterns (the data, not the files). The file translation functions (to a Mathematica "native" format), which are a part of a package I'd written in Mathematica, contain extensive data integrity checks that generate custom & inbuilt Messages that I interpret either as warnings or as aborting errors. The number of files varies from ~400 to ~1600 and the processing takes at the maximum about 60 minutes, which makes the MessagesAbort[] mechanism indispensable. Although before I commit it to MathSource, I would like to publish it here so anybody interested can test it & bring out THE RESULTING BUGS. ================================================ The MessagesAbort[] Code begins at the next line Begin["System`"] (******** MessagesAbort (Message OVERLOAD) ********) MessagesAbort::usage = "\[FilledSmallSquare] On[MessagesAbort[symbol::\"tag\", ...]] and Off[AbortMessage[]] extend the Mathematica exception handling capacity. \n\[FilledSmallSquare] On[MessagesAbort[]] transparently sets the environment that any Message[symbol::\"tag\"] generated (printed) by Mathematica aborts calculations immediately. \n\[FilledSmallSquare] On[AbortMessages[symbol::\"tag\", ...]] sets the environment to abort immediately but only after any of the symbol::\"tag\", ... messages is generated. \n\[FilledSmallSquare] Off[AbortMessage[]] restores the exception handling capacity to the Mathematica default. \n\[FilledSmallSquare] On[symbol::\"tag\", ...] and Off[symbol::\"tag\", ...] take precedence over On[MessagesAbort[symbol:: \"tag\", ...]], i.e.,\n\t(Off[s::t]; On[MessagesAbort[s::t]]) will neither generate the Message[s::t] nor abort the calculations." On[MessagesAbort[msgNames___MessageName]] ^:= \ (Unprotect[Message, $MessagesAbortQ]; $MessagesAbortQ = False; Message[args___] := (Check[Block[{$MessagesAbortQ = False}, Message[args]], Abort[], msgNames]) /; $MessagesAbortQ; $MessagesAbortQ = True; Protect[Message, $MessagesAbortQ];); Off[MessagesAbort[]] ^:= \ (Unprotect[Message, $MessagesAbortQ]; $MessagesAbortQ = False; Clear[Message]; Protect[Message, $MessagesAbortQ];); SetAttributes[MessagesAbort, HoldAll]; End[(* System` *)] The MessagesAbort[] Code ends at the previous line. =================================================== The MessagesAbort code addresses the problem of intercepting and controlling Mathematica exceptions that generate Messages. The general problem is defined as follows. Suppose that there are several statements executed as a compound statement, say (s1; s2; s3; ...) Each of the sk statements can generate an error Message and it is ESSENTIAL that the execution stops after some specific Message is generated. For example, with the default error handlers, the whole compound statement will be executed, In[1]:= (Log[1, 1]; Prime[-12]; StringLength[ToString[N[Pi, 10^5]]]) Divide::"indet" : Indeterminate expression 0/0 encountered. Prime::"intpp" : Positive integer argument expected in Prime[-12]. Out[1]:= 100001 Wrapping it in Check doesn't help; In[1]:= Check[(Log[1, 1]; Prime[-12]; Print[StringLength[ToString[N[Pi, 10^5]]]]), Abort[]] Divide::"indet" : Indeterminate expression 0/0 encountered. Prime::"intpp" : Positive integer argument expected in Prime[-12]. 100001 Out[1]:= $Aborted i.e., the Abort is issued only AFTER the last statement is evaluated. The MessagesAbort function sets up a mechanism to overload the Message function. Executing, In[]:= On[MessagesAbort[Divide::"indet", Prime::"intpp"]] will result in the following overload of the Message function, In[]:= Information["Message"] Message[args___] := Check[Block[{$MessagesAbortQ = False},Message[args]], Abort[], Divide::indet, Prime::intpp] /; $MessagesAbortQ with $MessagesAbortQ set to True, i.e., In[]:= $MessagesAbortQ Out[]= True The mechanism of action is rather straightforward. 1. Any Message generated will be intercepted by the above overload since the $MessagesAbortQ is True. 2. If the intercepted MessageName[symbol, tag] (symbol::tag) is Divide::"indet" or Prime::"intpp" the expr of Check[expr, failexpr, Divide::"indet", Prime::"intpp"] (i.e., the Block statement) will successfully generate the Message again, but this time using the ORIGINAL Message definition (since $MessagesAbortQ is set to False within the scope of the Block), 3. Successful generation/printing of the Message in 2. is considered a failure from the point of view of the Check statement, thus failexpr (i.e., Abort[]) will be executed and any outstanding computations will terminate immediately ("as soon as possible"). Now, In[1]:= On[MessagesAbort[Divide::"indet"]] (Log[1, 1]; Prime[-12]; StringLength[ToString[N[Pi, 10^5]]]) Divide::"indet" : Indeterminate expression 0/0 encountered. Out[1]:= $Aborted and, In[1]:= On[MessagesAbort[Prime::"intpp"]] (Log[1, 1]; Prime[-12]; StringLength[ToString[N[Pi, 10^5]]]) Divide::"indet" : Indeterminate expression 0/0 encountered. Prime::"intpp" : Positive integer argument expected in Prime[-12]. Out[1]:= $Aborted and, of course, In[1]:= On[MessagesAbort[]] (Log[1, 1]; Prime[-12]; StringLength[ToString[N[Pi, 10^5]]]) Divide::"indet" : Indeterminate expression 0/0 encountered. Out[1]:= $Aborted I suggest that MessagesAbort[] Code is put initially in the Kernel init.m file in (...\Wolfram Research\Mathematica\5.2\Configuration\Kernel) directory. Please feel free to comment on the code, suggest improvements and point out any faults. Treat it as harshly as possible, and please report the bugs. Cheers, Philipp.