5
$\begingroup$

I am a beginner in Mathematica. I have this in Mathematica v12:

A = {1, 1, 1, 1}
B = {2, 2, 2, 2}
A+B
(* 3,3,3,3 *)

I'd like to experiment with evaluating arbitrary expressions on arrays, like this:

C = {4, 2, 4, 2}
(A+B)<C
(* I want this output: *)
(* True, False, True, False *)

In the example, above:

  • {1,1,1,1} + {2,2,2,2} evaluates to {3,3,3,3} which is an element-wise operation.
  • {3,3,3,3} < {4,2,4,2} should evaluate to { True, False, True, False }, but it does not do an element-wise operation (which seems logically inconsistent!).

What I have tried

Tried about 30 combinations and permutations of existing functions, none of them appeared to work. Tried the top 6 answers that were vaguely relevant on SO. Browsed through Mathematica documentation to try and find anything relevant.

$\endgroup$
2
  • 1
    $\begingroup$ In haskell: zipWith (<) (zipWith (+) [1,1,1,1] [2,2,2,2]) [4,2,4,2] $\endgroup$ Mar 19, 2021 at 10:43
  • 1
    $\begingroup$ In python: [x+y<z for x,y,z in zip([1,1,1,1],[2,2,2,2],[4,2,4,2])] $\endgroup$ Mar 19, 2021 at 18:26

4 Answers 4

5
$\begingroup$

Update

Can generalize this to account for scalars using ReplaceRepeated and some pattern matching.

bolVectorEval[exp_] := 
 exp //. h_[params : OrderlessPatternSequence[_List .., _?NumericQ ...]] :> 
   Thread[h[params]]

then

bolVectorEval[(a > c) || (4.3 < (b + c))]
{True, False, True, False}

OP

You may use Thread.

Thread[(a + b) < c]
{True, False, True, False}

Hope this helps.

$\endgroup$
1
  • $\begingroup$ Thanks! The first answer works perfectly to evaluate expressions with logical operators such as || or &&, e.g. bolVectorEval[((a + b) > (c + a)) || (a > c)]. @Henrik Schumacher also recommended BoolEval by Szabolcz, that works perfectly as well, and claims to be optimised for efficiency. Example: BoolEval[((a + b) > (c + a)) || (a > c)]. $\endgroup$
    – Contango
    Mar 18, 2021 at 13:43
6
$\begingroup$

You may exploit that UnitStep step is vectorized like this:

a = {1, 1, 1, 1};
b = {2, 2, 2, 2};
c = {4, 2, 4, 2};
{False, True}[[2 - UnitStep[(a + b) - c]]]

{True, False, True, False}

If you can life with 0 and 1 instead of False and True, the the following will serve your needs and is more efficient (for large lists):

Subtract[1, UnitStep[Subtract[(a + b), c]]]

In particular, it is two orders of magnitude faster than Thread:

n = 1000000;
a = RandomInteger[{0, 1000}, {n}];
b = RandomInteger[{0, 1000}, {n}];
c = RandomInteger[{0, 1000}, {n}];

r1 = Thread[(a + b) < c]; // RepeatedTiming // First
r2 = Subtract[1, UnitStep[Subtract[(a + b), c]]]; // RepeatedTiming // First
And @@ ({False, True}[[r2 + 1]] == r1)

0.34

0.0025

True

But of course, Thread is more convenient and also more readible.

Szabolcs wrote a nice packaged that gives you the best of both worlds: It's called BoolEval.

$\endgroup$
6
  • $\begingroup$ Thank you for your answer. I'm after a more general solver, i.e. I could plug in (a+b)>c or even ((a+b)>(c+d)) || (a>d), and it would do an element-wise apply of that function to get something like { True, False, True, False } $\endgroup$
    – Contango
    Mar 18, 2021 at 12:41
  • 1
    $\begingroup$ Unitize[UnitStep[(a + b) - (c + d)] + UnitStep[a - d]] ;) But I see your point. Szabolcz wrote a nice packaged with the name BoolEval. Have a look! $\endgroup$ Mar 18, 2021 at 12:44
  • $\begingroup$ BoolEval works brilliantly, thanks! $\endgroup$
    – Contango
    Mar 18, 2021 at 13:33
  • $\begingroup$ Thank you for your answer. I've marked the answer by @Edmund as the one that worked for me. $\endgroup$
    – Contango
    Mar 18, 2021 at 13:41
  • 1
    $\begingroup$ You're welcome. $\endgroup$ Mar 18, 2021 at 13:42
4
$\begingroup$
vecLess = Negative @* Subtract;

vecLess[a + b, c]
{True, False, True, False}
a + b < c /. Less -> vecLess
{True, False, True, False}
$\endgroup$
4
$\begingroup$

Here's a very idiosyncratic way of handling the problem. This would be my goto method if I just needed to get things done and didn't care about performance. It's not the easiest to read, but there's a lot going on that someone new to MMA can learn from:

a = {1, 1, 1, 1};
b = {2, 2, 2, 2};
c = {4, 2, 4, 2};
#1+#2<#3&@@@Transpose[{a,b,c}]

{True, False, True, False}

This post is a great place to start if you're just getting into Mathematica.

$\endgroup$
1
  • 1
    $\begingroup$ Thank you, and that post you referenced is amazing. $\endgroup$
    – Contango
    Mar 18, 2021 at 13:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.