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.