开发者

Changing behavior of General::stop and the main loop

On the Documentation page for General::stop we read:

This message is generated after the indicated message has been generated for the third time in a single evaluation.

Messages are suppressed to prevent redundant or repetitive messages in long calculations.

My problem is that when working through MathLink I pass every point as a single evaluation and so General::stop never appears.

For example, if I define:

link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
f[z_?NumericQ] := (Print@LinkRead[link]; 
   LinkWrite[link, 
    Unevaluated[
     EnterExpressionPacket[NIntegrate[Sin[1/x], {x, .001, z}]]]]; 
   While[Head[packet = LinkRead[link]] =!= OutputNamePacket, 
    Print[packet]]; First@LinkRead[link]);
Plot[f[z], {z, 1, 10}, PlotPoints -> 6, MaxRecursion -> 0]

I get as many Message packets as many evaluations of f[z]. Of course I would like message generarion to be stopped in the slave kernel by General::stop after generating the same message 3 times. Is there a way to achieve this?

On the documentation page fo开发者_开发技巧r $MessageList we read that

With the standard Mathematica main loop, $MessageList is reset to {} when the processing of a particular input line is complete.

And on the page tutorial/Messages we read:

In every computation you do, Mathematica maintains a list $MessageList of all the messages that are produced. In a standard Mathematica session, this list is cleared after each line of output is generated.

May be this is a reason why General::stop does not appear? If it is true is there a way to control this aspect of the Main Loop? Is there a way to create such a non-standard Mathematica session?

EDIT: It seems that my supposition was right. If we will clear $MessageList after every Message, then General::stop never appears:

Unprotect[$MessageList]
Do[$MessageList = {}; 1/0, {10}]

So the question remains: how to disable automatic clearing $MessageList after generating output?


There are probably better solutions, but here is one that seems to work. As far as I understand, all that matters is that you have some persistent variable in the slave kernel that accumulates messages.

link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
f[z_?NumericQ] := 
(Print@LinkRead[link];
LinkWrite[link, Unevaluated[EnterExpressionPacket[
  If[! ValueQ[oldMessageList], oldMessageList = {}];
  Block[{$MessageList = oldMessageList},
   Module[{result},
    oldMessageList  = 
     Join[oldMessageList, (result = 
        NIntegrate[Sin[1/x], {x, .001, z}]; $MessageList)];
    result
    ]]]]];
While[Head[packet = LinkRead[link]] =!= OutputNamePacket, 
Print[packet]]; First@LinkRead[link]);

Plot[f[z], {z, 1, 10}, PlotPoints -> 6, MaxRecursion -> 0]

HTH


I have found the solution. It exploites again elegant hack by Todd Gayley. Here it is (of course, it must be evaluated in the slave kernel):

$globalMessageList = {};
Unprotect[Message];
Message[args___] := 
  Block[{$inMsg = True, $MessageList = $globalMessageList},
    Message[args];
    $globalMessageList = $MessageList;
    ] /; ! TrueQ[$inMsg];
Protect[Message];

One can fully emulate standard behavior of Messages in the slave kernel by checking the current value of $Line and comparing it with previous value:

If[TrueQ[$Line > lastLine], 
 LinkWrite[$kern, 
  Unevaluated[ExpressionPacket[$globalMessageList = {};]]]; 
 LinkRead[$kern]]; lastLine = $Line;

:)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜