4
$\begingroup$

I have been looking at some of the questions regarding error handling but i think my problem is unique.

I am running a Do-loop. I get errors only for certain values of the loop variable due to the nature of the problem.

Example

a = {1, 2, 3, 4, 5};
b = {2, 0, 40, 5, 0};
x = {};
Do[Append[x, a[[i]]/b[[i]]], {i, 1, 5}]

At iterations 2 and 5 the above code gives the error message

Power::infy: Infinite expression 1/0 encountered. >>

I want to know at which index value an error occurs -- any error, not only the particular error given it the example -- and I want to store those values in a variable. I have looked at documentations for Check, Catch, etc., but I couldn't see how to use them. Is there a way to do this?

EDIT

My program is pretty much complex than the above example and has to use loops. So an answer with loops is appreciable.

$\endgroup$
2
  • $\begingroup$ Can't you get an If[] statement in there? Loops are discouraged in Mathematica though... $\endgroup$
    – Feyre
    Commented Jul 9, 2016 at 14:14
  • $\begingroup$ You certainly meant AppendTo instead of Append. But anyways, as @Feyre said, use Table instead of Do. And read the documentation more thoroughly. $\endgroup$ Commented Jul 13, 2016 at 15:33

5 Answers 5

6
$\begingroup$

Here's one way to do it:

a = {1, 2, 3, 4, 5}; b = {2, 0, 40, 5, 0}; 
x = Quiet[Table[a[[i]]/b[[i]], {i, 1, 5}]];
Position[x, ComplexInfinity]
{{2}, {5}}

Basically, ans contains the values plus the errors, which in this case are ComplexInfinity. You can locate the errors using Position, in this case, at positions 2 and 5. If you want to check for any old error, you can use Check:

a = {1, 2, 3, 4, 5}; b = {2, 0, 40, 5, 0};
x = Quiet[Table[Check[a[[i]]/b[[i]], $Failed], {i, 1, 5}]];
Position[x, $Failed]

Check returns the first argument (in this case a[[i]]/b[[i]] if there is no error and returns the second argument (in this case the symbol error) if there is an error. Thanks to J.M. for suggesting using the already defined symbol $Failed.

$\endgroup$
3
  • $\begingroup$ Hi @bill s, the error ComplexInfinity is for that particular case. Is there any way to generalize it? $\endgroup$
    – no-one
    Commented Jul 9, 2016 at 15:21
  • $\begingroup$ See updated answer for more general error checking... $\endgroup$
    – bill s
    Commented Jul 9, 2016 at 15:56
  • 1
    $\begingroup$ I would prolly use the built-in $Failed instead of introducing a new global symbol. $\endgroup$ Commented Jul 9, 2016 at 16:08
4
$\begingroup$

Another way (see How to catch complete error message information, including the message text as it would be printed? for more ways to hack messages): This works because i is effectively Block[]-ed by Do[].

badindices = {};
$MessagePrePrint = (AppendTo[badindices, i]; #) &;

Do[Append[x, a[[i]]/b[[i]]], {i, 1, 5}]

$MessagePrePrint = Automatic;
badindices

(*  {2, 5}  *)

As function for running code: This collects the value of an expression expr at the time a message is generated.

SetAttributes[checkrun, HoldAll]
checkrun[code_, expr_] :=
 Module[{exprlist = {}, res},
  $MessagePrePrint = (AppendTo[exprlist, expr]; #) &;
  res = code;
  $MessagePrePrint = Automatic;
  {res, exprlist}
  ]

Example:

i = 100;  (* to show  i  is  Block[]-ed *)
checkrun[
 Do[Append[x, a[[i]]/b[[i]]], {i, 1, 5}]
 , i]

(*  {Null, {2, 5}}  *)
$\endgroup$
1
3
$\begingroup$

In case you want to use Quiet and need to know which error messages were generated during the evaluation, you can use $MessageList. Starting from your code:

Module[{errors = Internal`Bag[{}], mess, a, b, x}, 

    a = {1, 2, 3, 4, 5};
    b = {2, 0, 40, 5, 0};
    x = {};

    Block[{$MessageList = {}},
       Do[
          Quiet[
             AppendTo[x, a[[i]] / b[[i]]];
             mess = $MessageList
          ];
          If[mess =!= {},
             Internal`StuffBag[errors, i -> mess];
             mess = $MessageList = {}
          ],
          {i, 1, 5}
       ];
       {x, Internal`BagPart[errors, All]}
    ]

]

This will evaluate to:

(*
{{1/2, ComplexInfinity, 3/40, 4/5, ComplexInfinity}, 
 {2 -> {Power::infy}, 5 -> {Power::infy}}
}
*)

I am using a bag (with Internal`Bag, Internal`StuffBag, Internal`BagPart), but this can be replaced by lists or associations with the appropriate functions for filling them.

$\endgroup$
2
$\begingroup$

Check is the function supplied with Mathematica for doing what you request. Here is how it can be used in your situation.

a = {1, 2, 3, 4, 5};
b = {2, 0, 40, 5, 0};
Quiet @ Module[{errs = {}, vals},
  vals =
    Table[Check[a[[i]]/b[[i]], AppendTo[errs, i]; Nothing], {i, 5}];
  {vals, errs}]

{{1/2, 3/40, 4/5}, {2, 5}}

$\endgroup$
1
  • $\begingroup$ This seems, as you suggest, a very natural way. For other users, a couple of remarks to show how it can be adapted: (1) It works with Do if one's use-case is not to generate a Table. One can omit Nothing, in this case. (2) One can add res to the Module and use Check[res = a[[i]]/b[[i]], AppendTo[errs, i]; res] to get a table of all results, including the erroneous ones. (Upvoted earlier.) $\endgroup$
    – Michael E2
    Commented Jul 11, 2016 at 14:53
0
$\begingroup$

You may use Check and $MessageList.

x = MapThread[Check[#1/#2, Last@$MessageList] &, {a, b}]
(* {1/2, HoldForm[Power::infy], 3/40, 4/5, HoldForm[Power::infy]} *)

Indices of errors can be obtained by:

errs = Position[x, HoldForm[MessageName[__]]]
(* {{2}, {5}} *)

and extracted by:

Extract[x, errs]
(* {HoldForm[Power::infy], HoldForm[Power::infy]} *)

The above is easily converted for loops if you really really need that.

Hope this helps.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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