Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a function running within a Do loop that sometimes issues a warning. I'd like to prepend the warning with the loop ctr so that I can go back and debug that instance later.
Basically, I would like to modify the following line,

Do[i^0, {i, -1, 1}]

so that instead of displaying the warning:

Power::indet: Indeterminate expression 0^0 encountered. >>

it displays:

i=0, Power::indet: Indeterminate expression 0^0 encountered. >>

Where i==0 is the iteration that i^0 issues the warning.

Thanks

share|improve this question

3 Answers

up vote 19 down vote accepted
+100

rcollyer's method looks great but for a reason I have yet to determine it fails in Mathematica 7. Here is a variation that does not.

Block[{$MessagePrePrint},
      $MessagePrePrint := Row@{#, " at i = ", i} ~ToString~ StandardForm &;
  Do[i^0, {i, -1, 1}]
]

This may not be ideal however, as every field in the message gets this tag. For example, if you enter the spurious Inner[f, {{1, 2}}, {3}] you get:

Inner::incom: Length 2 at i = 1 of dimension 2 at i = 1 in {{1,2}} at i = 1 is incommensurate with length 1 at i = 1 of dimension 1 in {3} at i = 1. >>

Perhaps this is a more flexible and convenient form:

EDIT: Full rewrite to place the tag in the message itself

SetAttributes[withTaggedMsg, HoldAll]

withTaggedMsg[sym_] := Function[,
  Internal`InheritedBlock[{MessagePacket},
    Unprotect[MessagePacket];
    MessagePacket[name__, BoxData[obj_, form_]] /; ! TrueQ[$tagMsg] :=
          Block[{$tagMsg = True},
        Identity@MessagePacket[name, BoxData[RowBox[{
          ToBoxes @ Style[
            Row[{"At iteration", HoldForm[sym], "=", sym, Spacer[5]}, " "],
            Black],
        obj}], form]]
      ];
    #
  ], HoldAll]

Usage:

Do[i^0, {i, -1, 1}] // withTaggedMsg[i]

Mathematica graphics


Note: this only works with variables that are either globally accessible or are scoped using Block. For example,

f[x_] := Message[f::brains, x]
f[5] // withTaggedMsg[x]
(* At iteration x = x f::brains: -- Message text not found -- (5) *)

Module[{x = 5},
 Message[f::brains, x]
] // withTaggedMsg[x]
(* At iteration x = x f::brains: -- Message text not found -- (5) *)

With[{x = 5},
 Message[f::brains, x]
] // withTaggedMsg[x]
(* At iteration x = x f::brains: -- Message text not found -- (5) *)

Block[{x = 5},
 Message[f::brains, x]
] // withTaggedMsg[x]
(* At iteration x = 5 f::brains: -- Message text not found -- (5) *)

This means that any variable that is scoped using Block can be used to tag a message. So, loop variables from Do and Table are accessible via this method, in addition to any Block variable. This makes it indispensable as a debugging tool.

share|improve this answer
Argh, I hadn't thought about what happens to the other fields. I do like your second method better, though; it is more readable and closer to what the OP wants. Although, the two cell output isn't to my liking, all that much, it is very nice, overall. +1 – rcollyer Jul 12 '12 at 0:54
I added a fix per Rojo. – rcollyer Jul 13 '12 at 14:23
@rcollyer thanks! – Mr.Wizard Jul 13 '12 at 15:10
This is why I participate here: I'm having to make use of this to debug some code to load a file, and this allows me to spit out the line numbers with the errors. I'd give you another +1 if I could. – rcollyer Oct 11 '12 at 18:34
@rcollyer Glad to be of help, as always. Thanks for letting me know, I value that a lot more than points. – Mr.Wizard Oct 11 '12 at 19:06
show 3 more comments

I cannot seem to make it do exactly what you want do to how messages are created, but here is a serviceable alternative using $MessagePrePrint. $MessagePrePrint formats the variables specified in the message string, and in your example, the message has the form

General::indet = "Indeterminate expression `1` encountered."

where the `1` will be replaced by $0^0$, or whatever else you pass to it. It is that argument that $MessagePrePrint operates on, and we can change it to suit us, as follows

Block[{$MessagePrePrint},
     $MessagePrePrint := ToString[StandardForm[#]] <> " at i = " <> ToString[i] &;
 Do[i^0, {i, -1, 1}]
]

where the output will now read "$0^0\text{ at i} =1$".

share|improve this answer
I voted for this and then removed my vote because on v7 I'm getting: An unknown box name (Set) was sent as the BoxForm for the expression. Check the format rules for the expression. I need to figure out why. – Mr.Wizard Jul 11 '12 at 21:21
1  
It seems that v7 doesn't like the fact that InputForm@ToString@StandardForm@HoldForm[0^0] yields "\!\(\*TagBox[\(0\^0\), HoldForm]\)". Either the form I show in my answer or ToBoxes[ToString[StandardForm@#] <> " at i = " <> ToString[i]] & appear to work. – Mr.Wizard Jul 11 '12 at 22:25
I guess now that I've provided a work-around for v7 users here in the comments I can +1, so, +1! :-) – Mr.Wizard Jul 11 '12 at 23:05

rcollyer has a nice solution. Here's another possibility using Check and printing the list of messages generated at the current evaluation.

Quiet@Block[{$OldMessages = 0}, 
        Do[Check[#^#/# &@Mod[i, 2], 
            Print@StringForm["At i=``, ``", i, $MessageList[[$OldMessages + 1 ;;]]]; 
            $OldMessages = Length@$MessageList;], 
        {i, 0, 5}]
   ];

(* At i=0, {Power::indet,Power::infy}
   At i=2, {Power::indet,Power::infy}
   At i=4, {Power::indet,General::stop,Power::infy,General::stop} *)

Remove the Quiet@ if you want to see the actual messages generated.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.