4

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 for $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?

rcollyer
  • 10,475
  • 4
  • 48
  • 75
Alexey Popkov
  • 9,355
  • 4
  • 42
  • 93
  • @Brett The source of the problem is that the slave kernel considers all evaluations as separate and clears `$MessageList` after each of them. It may be easily simulated: `Unprotect[$MessageList]; Do[$MessageList = {}; 1/0, {20}]`. This code does not stop generating identical Messages and `General::stop` never appears. – Alexey Popkov Mar 02 '11 at 17:12
  • 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." This gives me a hope that there is a way to create a non-standard *Mathematica* session in which `$MessageList` will not be cleared after each line of output is generated. – Alexey Popkov Mar 02 '11 at 17:15

2 Answers2

1

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

Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
0

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;

:)

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