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 ConditionalExpressions, 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