4

Everyone has perhaps been irritated by the Power::infty message:

Cos[0]/Sin[0]

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

(*  ComplexInfinity  *)

But I want such a message in case like this:

Cos[x]/Sin[x] /. x -> 0
(*  ComplexInfinity  *)

There is no message because Cos[x]/Sin[x] evaluates to Cot[x], and Cot[0] evaluates to ComplexInfinity without a warning. Similarly Log[0] evaluates to -Infinity without warning.

Is there a system option or message that can be turned on so that expressions like Cot[0] and Log[0] give a warning?

Notes:

  • These functions may be embedded in larger expressions.
  • It is possible that the infinity will eventually generate an error as it propagates through a computation. But it's also possible that a finite number will be divided by infinity and evaluate to 0, like 1/ComplexInfinity, in which case it might be a disaster:

    1 + 1/(1 + Log[0])
    (*  1  *)
    
Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • Limit[Cos[x]/Sin[x], x -> 0] or FullSimplify[Cos[x]/Sin[x]] /. x -> 0? No errors. – David G. Stork Mar 09 '16 at 16:28
  • 1
    On the flip side, when I had an application dealing with ratios of gamma functions, it was convenient that the reciprocal of a gamma function evaluated at a nonpositive integer evaluated to 0… – J. M.'s missing motivation Mar 09 '16 at 16:29
  • @J.M. Yes, I meant it only might be a disaster. – Michael E2 Mar 09 '16 at 16:32
  • For example, docs for Log[ ] states Zero and infinite arguments give symbolic results: So if you want error messages you'll need to redefine to your own functions – Dr. belisarius Mar 09 '16 at 16:33
  • Not aware of a built-in setting (which might well exist), but you can hack it with something like this: Unprotect[DirectedInfinity]; DirectedInfinity::infy = "Infinite expression encountered"; DirectedInfinity /: call : _[___, _DirectedInfinity, ___] /; ! TrueQ[inInf] := Block[{inInf = True},Message[DirectedInfinity::infy];call]; Protect[DirectedInfinity]. Can wrap that in a dynamic environment using Internal`InheritedBlock, to avoid global redefinitions. This surely isn't remotely as nice as would be a built-in mechanism, but it may work. – Leonid Shifrin Mar 09 '16 at 16:35
  • I'm not at a computer now, but maybe you can use TraceScan[] to find instances of DirectedInfinity[] during evaluation, and throw an appropriate message if it finds one? – J. M.'s missing motivation Mar 09 '16 at 16:44
  • @LeonidShifrin Yes, that seems to work, except for a top-level Cot[0]. If I change the declaration to call : _DirectedInfinity /; ! TrueQ[inInf] :=..., it catches a top-level infinity. – Michael E2 Mar 09 '16 at 16:57
  • @J.M. Yes, I expect that would work, but wouldn't it slow things down? – Michael E2 Mar 09 '16 at 16:58
  • I don't know and can't do the experiment myself, which is why I was suggesting it. :) – J. M.'s missing motivation Mar 09 '16 at 17:00
  • @MichaelE2 Actually, your version is even much better, since it produces a DownValue on DirectedInfinity, which is much better / safer than UpValue of such a general form as I suggested. – Leonid Shifrin Mar 09 '16 at 17:11
  • @Dr.belisarius 1/0 gives a symbolic result, too, doesn't it? I'm not sure a symbolic result means there's no built-in message, off by default, that could be turned on. The more convincing evidence is that no one who has commented, including you and me, seems to know of one. – Michael E2 Mar 09 '16 at 17:26
  • 1
    @DavidG.Stork Maybe it wasn't clear: I want to get an error. – Michael E2 Mar 09 '16 at 20:00
  • @LeonidShifrin No one has come up with a better idea. I realize it is a bit of a hack, but would you consider posting an answer? – Michael E2 Mar 12 '16 at 20:16
  • @MichaelE2 Ok, done. – Leonid Shifrin Mar 13 '16 at 11:05

1 Answers1

2

Redefinition of DirectedInfinity

One way would be to add a DownValue to DirectedInfinity (the final form suggested by MicahelE2):

Unprotect[DirectedInfinity];
Clear[DirectedInfinity];
DirectedInfinity::infy = "Infinite Expression encountered";
DirectedInfinity /: call_DirectedInfinity /; ! TrueQ[inInf] :=  
  Block[{inInf = True},
    Update[DirectedInfinity];
    Message[DirectedInfinity::infy];
    call
  ];
Protect[DirectedInfinity];

So that, for example

1 + 1/(1 + Log[0])

During evaluation of In[67]:= DirectedInfinity::infy: Infinite Expression encountered >>

During evaluation of In[67]:= DirectedInfinity::infy: Infinite Expression encountered >>

1

The call to Update is necessary to prevent an internal optimization, that would otherwise result in the messages being suppressed on subsequent calls of DirectedInfinity.

A safer version using local environment

Note that this isn't a safe modification, since it globally modifies a built-in function. As such, it may have unanticipated consequences. A safer way to do this would be to use Internal`InheritedBlock, and a dynamic environment to wrap around a piece of code you want to evaluate in this mode.

First, we have to remove the changes we made:

Unprotect[DirectedInfinity];
Clear[DirectedInfinity];
Protect[DirectedInfinity];

Here is a reasonably general generator of such dynamic environments:

ClearAll[withRedefined];
SetAttributes[withRedefined, HoldRest];
withRedefined[f_Symbol,beforeCall_,afterCall_, extraCode_]:=
  Function[code,
    Internal`InheritedBlock[{f},
      Module[{inF, dv=DownValues[f]},
        With[{protected = Unprotect[f]},
          DownValues[f]={};
          extraCode;    
          (call:f[args___])/;!TrueQ[inF]:=
            Block[{inF=True},
              beforeCall[args];
              With[{res = call},
                afterCall[args, res];
                res
              ]
            ];
            DownValues[f]=Join[DownValues[f],dv];
            Protect[protected];
        ];
        code
      ]
    ],
    HoldAll
  ];

With this function, we can create our custom dynamic environment easily:

withMessageOnInfinity = 
  withRedefined[
    DirectedInfinity
    ,
    Function[
      Update[DirectedInfinity];
      Message[DirectedInfinity::infy]
    ]
    ,
    Function[Null]
    ,
    DirectedInfinity::infy = "Infinite Expression encountered";
  ];

So now we have without dynamic environment just the usual behavior:

1 + 1/(1 + Log[0])

(* 1 *)

while using the environment we get:

withMessageOnInfinity[1 + 1/(1 + Log[0])]

During evaluation of In[21]:= DirectedInfinity::infy: Infinite Expression encountered >>

1

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420