4
$\begingroup$

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  *)
    
$\endgroup$
  • $\begingroup$ Limit[Cos[x]/Sin[x], x -> 0] or FullSimplify[Cos[x]/Sin[x]] /. x -> 0? No errors. $\endgroup$ – David G. Stork Mar 9 '16 at 16:28
  • 1
    $\begingroup$ 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… $\endgroup$ – J. M. will be back soon Mar 9 '16 at 16:29
  • $\begingroup$ @J.M. Yes, I meant it only might be a disaster. $\endgroup$ – Michael E2 Mar 9 '16 at 16:32
  • $\begingroup$ 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 $\endgroup$ – Dr. belisarius Mar 9 '16 at 16:33
  • 1
    $\begingroup$ @DavidG.Stork Maybe it wasn't clear: I want to get an error. $\endgroup$ – Michael E2 Mar 9 '16 at 20:00
2
$\begingroup$

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

$\endgroup$
  • $\begingroup$ Thank you. I always learn something from your code generation examples. $\endgroup$ – Michael E2 Mar 13 '16 at 12:10
  • $\begingroup$ @MichaelE2 Glad to help, as always. Thanks for the accept. $\endgroup$ – Leonid Shifrin Mar 13 '16 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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