3
$\begingroup$

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?

$\endgroup$
5
$\begingroup$

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).

$\endgroup$
3
$\begingroup$

Perhaps clearer is to just explicitly do the flow-control:

In[323]:= 
sol = Table[
   ConditionalExpression[
    Integrate[LegendreP[RandomInteger[100], t] x, {t, 0, \[Pi]}] + 
     RandomReal[], x > RandomReal[]], 10];

In[340]:= (sol /. ConditionalExpression[z1_, z2_] :>
    If[Unevaluated[z2] /. x -> .22,
     Unevaluated[z1] /. x -> .22,
     Undefined
     ]
  ) // AbsoluteTiming

Out[340]= {0.000078, {Undefined, Undefined, Undefined, Undefined, 
  Undefined, Undefined, Undefined, 147944., Undefined, Undefined}}

or we can just delay evaluation of the first argument, but we still need 3 ReplaceAlls:

((sol /. ConditionalExpression[z1_, z2_] :> 
     ConditionalExpression[Unevaluated[z1 /. x -> .22], 
      z2 /. x -> .22])) // AbsoluteTiming

{0.000077, {Undefined, Undefined, Undefined, Undefined, Undefined, 
  Undefined, Undefined, 147944., Undefined, Undefined}}

I'm not sure we can avoid a three ReplaceAll based mechanism, honestly, without sacrificing some performance.

$\endgroup$

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.