Message Boards Message Boards

GROUPS:

BoolEval package for fast vectorized evaluation of comparisons

Posted 1 year ago
5577 Views
|
1 Reply
|
5 Total Likes
|

It's been out for quite a while now, but for those who don't know about it, I would like to announce the BoolEval package.

Note: You can try a preview of the main function from the Wolfram Function Repository.

The package provides a fast vectorized way to evaluate array comparisons (equalities or inequalities, possibly joined with logical operations).

Suppose we want to select the numbers greater than 3 from the list {1, 2, ..., 10}.

In[1]:= Needs["BoolEval`"]

In[2]:= mask = BoolEval[Range[10] > 3]
Out[2]= {0, 0, 0, 1, 1, 1, 1, 1, 1, 1}

BoolEval returns an array which contains 1s where the condition is true and 0 elsewhere.

We can use this result for various things, such as masking the array: mask*Range[10]; counting the number of elements that satisfy the condition: Total[mask]; or Picking them out. BoolEval includes convenient helper functions for this:

In[3]:= arr = Range[10];
BoolPick[arr, arr > 3]

Out[4]= {4, 5, 6, 7, 8, 9, 10}

In[5]:= BoolCount[arr > 3]
Out[5]= 7

Those who use basically any other scientific computing system (such as MATLAB, numpy, R, Julia, etc.) will immediately recognize this way of working. Indeed, the original idea for BoolEval came from a StackExchange thread asking for this feature back in 2012: Does Mathematica have advanced indexing?

Of course, the very same operations can be performed with Select, Cases and Count. Why do we need BoolEval then? The answer: BoolEval is much, much faster.

In[6]:= arr = RandomReal[1, 1000000];

In[7]:= res1 = Select[arr, # < 0.3 &]; // RepeatedTiming
Out[7]= {0.490, Null}

In[8]:= res2 = Cases[arr, x_ /; x < 0.3]; // RepeatedTiming
Out[8]= {0.4638, Null}

In[9]:= res3 = BoolPick[arr, arr < 0.3]; // RepeatedTiming
Out[9]= {0.017, Null}

In this case, it's faster by a factor of 30. It achieved this amazing speed by converting the comparisons to arithmetic. E.g. arr >= 0 can be computed as UnitStep[arr]. To see how BoolEval converts a complex expression into arithmetic, just pass a symbolic expression to it:

In[11]:= BoolEval[3 < a < 5 || a^2 < 1]
Out[11]= Unitize[1 + (1 - UnitStep[3 - a]) (1 - UnitStep[-5 + a]) - UnitStep[-1 + a^2]]

Advanced Mathematica users will often use the UnitStep trick to get fast results, but as you can see, the complexity of the arithmetic transcription will quickly get out of hand ... It's difficult not to make a mistake. BoolEval does the conversion automatically, and behind the scenes. It basically allows one to use a convenient, human-readable notation while still getting the performance boost.

BoolEval works with any expression that Mathematica can do arithmetic on, including images. E.g., we can select image levels between 0.75 and 0.85 intensity:

im = ColorConvert[ExampleData[{"AerialImage", "Oakland2"}], "Grayscale"]
BoolEval[0.75 < im < 0.85]

I am preparing to release a new version of BoolEval in the coming days. I made this post to collect feedback. Please let me know if you have any suggestion, especially if you have any ideas about how to improve the documentation or what cool examples to include. Please be sure to read the tutorial included in the documentation.

enter image description here - Congratulations! This post is now featured in our Staff Pick column as distinguished by a badge on your profile of a Featured Contributor! We have also featured it in our Mathematica Add-Ons group. Thank you, keep it coming!

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract