Take the following example:
big = RandomReal[1, 10000000];
Head[big >= 0.66] // AbsoluteTiming
(* {0.53489, GreaterEqual} *)
Why does this take a long time to evaluate, given that the expression doesn't actually change?
Update: Simon Woods points out that the slowdown is due to unpacking. There is also some strange interaction with ReplaceAll that I do not understand. Both are demonstrated by the following:
r=RandomReal[1,10000000];
On["Packing"]
Hold[Greater[r,0.5]]/.{x_?ArrayQ:>x}//AbsoluteTiming
Developer`FromPackedArray::unpack: Unpacking array in call to Greater.
{0.497073,Hold[r>0.5]}
Hold[greater[r,0.5]]/.{x_?ArrayQ:>x}//AbsoluteTiming
{0.000017,Hold[greater[r,0.5]]}
ArrayQ[r]//AbsoluteTiming
{3.*10^-6,True}
Note:
bigis a large packed arraybig >= 0.66is the same asGreaterEqual[big, 0.66]- the result is identical to
GreaterEqual[big, 0.66]
This is a problem for my BoolEval package, which has a BoolEval function that transforms the expression big >= x to UnitStep[big - x] to speed up element-wise comparisons. big >= x takes longer to evaluate than UnitStep[big - x].
Here's a much simplified version of the function:
greatereq[a_, b_] := UnitStep[a-b]
BoolEval[expr_] := expr /. GreaterEqual -> greatereq
A potential solution is
SetAttributes[BoolEval, HoldAll]
BoolEval[expr_] := Unevaluated[expr] /. GreaterEqual -> greatereq
The problem with this is that it will not work with
f[] := big >= 66
BoolEval[f[]]
Such a function would simply be too confusing to use.
0.1 < arr < 0.5 && arr != 0.4. This solution would hide the performance problem for a few common cases, but otherwise it will still be slow. So I'm not fully happy with it. – Szabolcs Jul 12 '16 at 13:30On["Packing"]reveals that the array is unpacked in the call to GreaterEqual – Simon Woods Jul 12 '16 at 20:21HoldAllversion but instead ofUnevaluateduseBlock[{GreaterEqual}, ...]– Simon Woods Jul 12 '16 at 20:25BoolEval[myFun[] > 1]andmyFun[]usesGreater? I am probably going to doHoldAlland require the boolean expressions and comparisons to appears explicitly in the argument. I.e.BoolEval[x > 1]is okay, butfun[]:=x>1; BoolEval[fun[]]is not. However, I am not willing to breakBoolEval[myFun[] > 1]as well. – Szabolcs Jul 13 '16 at 08:29ReplaceAll" are you observing? The unpacking? That comes fromArrayQ[Greater[r, 0.5]]. Can we directly overload all boolean operators and apply those within your call,Block[{Greater = myGreater, Less = myLess}, body]? Make them general andmyFun[] > 1should still work, right? – Mr.Wizard Feb 26 '17 at 17:37ReplaceAll—embarrassing oversight. I don't thinkBlockwill be a good approach, but too little space to explain here ... I wanted to entirely rewrite BoolEval and blog about it. We can discuss next week in chat if you're interested, otherwise I'll ping you when the blog is out. – Szabolcs Feb 26 '17 at 19:38HoldAll, a basic definition respecting thisHoldAll, and one that evaluates to check anything not matching this form: i.e. defineBE[ a_ > b_ ] := greater[a, b]and thenBE[ e_ ] /; !TrueQ[$inBE] := Block[{$inBE=True, res}, res = BE[Evaluate@e] /; Head[res] =!= BE ]. Unfortunately this would probably confuse users who notice performance differences betweenBE[ a > b]andBE[ f[] ]forf[] := a > b– b3m2a1 Feb 01 '18 at 19:15