performance tuning - Delay Evaluation of First Argument of ConditionalExpression until Second Argument Evaluated
A particular set of equations I am solving,
sol = Solve[...]
yields a lengthy List
of ConditionalExpression
s, the arguments of which take a bit of time to evaluate
(sol /. x -> .22) // AbsoluteTiming
(* {0.26925, {...}} *)
which adds up when performed for hundreds of values of x
. This is so even though most instances of ConditionalExpression
return Undefined
, because both arguments of ConditionalExpression
are evaluated, even when the second argument evaluates to False
. A work-around is
((sol /. ConditionalExpression[z1_, z2_] :> ConditionalExpression[z1, z2 /. x -> .22])
/. x -> .22) // AbsoluteTiming
(* {0.0504917, {...}} *)
What alternatives are more compact or elegant?
Answer
The first solution is to use Unevaluated
:
sol := ConditionalExpression[Pause[y], y > 2]
sol /. y -> 1 // RepeatedTiming
{1.01, Undefined}
So it takes the whole second to evaluate even though the condition is false.
Now let's make a simple rule:
rule = ConditionalExpression[a_, b_] :> ConditionalExpression[Unevaluated[a], b];
and test it
sol /. rule /. y -> 1 // RepeatedTiming
{7.*10^-6, Undefined}
sol /. rule /. y -> 2.1 // RepeatedTiming
{2.101, Null}
So the first argument evaluates only when the condition is true.
The second (and slower) solution is to use Refine
, which allows us to avoid using ReplaceAll
:
Refine[sol, y == 1] // Quiet // RepeatedTiming
{0.00014, Undefined}
Refine[sol, y == 2.1] // Quiet // RepeatedTiming
{2.1007, Null}
Note that Quiet
is needed to suppress FE complaints about conditions evaluating to false (which is expected).
Comments
Post a Comment