How do I make $0 \times (\mathsf{anything})=0$?
Updated solution
@Michael E2 pointed out some issues with the previous solution, so here's another take:
expr = (t + s - 1) (t + s) LegendreQ[s - 1, t - 1, x] LegendreP[s - 1, t - 1, n]
myTimes[___,0, ___] := 0
myTimes[args___] := Times[args]
expr /. {Times -> myTimes, t -> 1, s -> 0}
(* 0 *)
This works by replacing Times
with myTimes
before inserting the numerical values. myTimes
has two properties:
myTimes
with a0
factor is0
myTimes[args___]
of anything else is the same thing asTimes[args]
Old solution
The following should do what you want:
expr = (t + s - 1) (t + s) LegendreQ[s - 1, t - 1, x] LegendreP[s - 1, t - 1, n]
Activate[
Inactivate[Evaluate@expr, Times] /.
{t -> 1, s -> 0} /.
Inactive[Times][___, 0, ___] :> 0
]
(* 0 *)
It works like this:
- Apply
Inactivate
to all products - Insert the values for
s
andt
- Replace any products containing a
0
factor with0
Activate
the whole expression again
Similar in spirit to Mathe's answer:
With[{t = 1, s = 0},
Block[{LegendreQ}, (t + s - 1) (t + s) LegendreQ[s - 1, t - 1, x]
LegendreP[s - 1, t - 1, n]]]
0
This is because MMA, in principle, already replaces anything times exact 0
to 0
. When LegendreQ
is blocked, it doesn't have a chance to evaluate to ComplexInfinity
so MMA can then apply its usual rules to products with 0
.
By the time the Block
is released, there is no LegendreQ
remaining in the expression.
Here's a function you can wrap around an expression to inspect if there are any multiplications by 0 inside (and set those multiplications to zero if necessary):
SetAttributes[zeroCheck, HoldFirst];
zeroCheck[expr_] := ReplaceAll[
Unevaluated[expr],
t_Times :> If[
AnyTrue[Unevaluated[t], TrueQ[# == 0] &],
0,
t
]
]
We can use it like this to deal with your problem:
In[12]:= Module[{
t = 1,
s = 0
},
zeroCheck[(t + s - 1) (t + s) LegendreQ[s - 1, t - 1, x] LegendreP[s - 1, t - 1, n]]
]
Out[12]= 0
Note, however, that zeroCheck
is HoldFirst
, so the following will not work:
expr = (t + s - 1) (t + s) LegendreQ[s - 1, t - 1, x] LegendreP[s - 1, t - 1, n];
Module[{t = 1, s = 0}, zeroCheck[expr]]
Instead, you'd have to do something like this:
Clear[expr];
expr[t_, s_] := (t + s - 1) (t + s) LegendreQ[s - 1, t - 1, x] LegendreP[s - 1, t - 1, n];
With[{evaluated = expr[t, s]},
Block[{t = 1, s = 0},
zeroCheck[evaluated]
]
]
0
edit
I noticed that my definition of zeroCheck
fails in certain situations (particularly, if fails to propagate zeroes inside of nested Times
upwards). This new version should avoid this issue:
SetAttributes[zeroCheck2, HoldFirst];
zeroCheck2[expr_] :=
ReleaseHold[
Hold[expr] //. {
t_Times /; Quiet[AnyTrue[Unevaluated[t], EqualTo[0]]] :> 0
}
]
Compare, e.g., zeroCheck[\[Infinity]*(0*\[Infinity])]
and zeroCheck2[\[Infinity]*(0*\[Infinity])]
.
edit 2
As pointed out by Michael E2, zeroCheck2
can produce side effects when testing for equality to zero. We can avert this with the following change:
SetAttributes[zeroCheck3, HoldFirst];
zeroCheck3[expr_] := ReleaseHold[
Hold[expr] //. {
t_Times /;
Quiet[
AnyTrue[
Unevaluated[t],
Function[x, Unevaluated[x] == 0, HoldFirst]
]
] :> 0
}
]