Message Boards Message Boards

0
|
8414 Views
|
16 Replies
|
5 Total Likes
View groups...
Share
Share this post:

In Mathematica 9, how do I check if all list members are True?

Posted 3 years ago

Seems like maybe Mathematica 9 didn't have AllTrue[] function.

Anyway, I'm working with Pascal's triangle, trying to see if all members [except first/last] are divisible by the row number. I create a list or members, a list of divisibilities [evaluates to true/false].

But then I want to check the list of disvisibilities for ALL being True, which is what I'm really looking for.

So, I want to evaluate a variable that has a list of boolean true/false values and evaluate if all members are "true" [I suppose I could also evaluate if 'any' are False, but I'd prefer "all true"].

So, how would I go about that without the AllTrue[] function, which I'm guessing was added in a later revision?

Seems like this should be a fairly trivial thing? But not sure how to go about it?

I mean, I guess I could go the opposite route and say something like:

VariableNameHere=MemberQ[{ListNameVariable},False]

IE, check whether false is a member, in which case the entire list isn't divisible by the row number.

But I'd rather directly check that all members are True, as opposed to back@$$wardly checking whether any member is false.

So, is there some simpler way to check for "AllTrue" without the AllTrue[] function?

POSTED BY: Michael Gmirkin
16 Replies

It performs exactly as I would expect. In some cases the test you wish to run is very fast, so that it is faster to run that test on all the inputs and check the results after than it is to do the incremental checks needed for the short circuit.

As mentioned above, OddQ is written in low-level kernel code and is optimised when mapped:

In[13]:= list = RandomInteger[100, 10^6];

In[14]:= First@RepeatedTiming[OddQ /@ list]

Out[14]= 0.21808

In[15]:= oddQ[x_] := OddQ[x];

In[16]:= First@RepeatedTiming[oddQ /@ list]

Out[16]= 0.524905

But if running your predicate function is not as fast as OddQ then you do want to use avoid applying it to all elements of the list if possible.

Lastly, OddQ is listable, so you can be even faster by avoiding map:

In[17]:= First@RepeatedTiming[OddQ@list]

Out[17]= 0.0154204
POSTED BY: Jason Biggs
Posted 3 years ago

Jason,

Agreed.

Do you have any idea why the allTrue implementation you provided, that attempts to short-circuit Map, does not perform as expected?

POSTED BY: Rohit Namjoshi

I think the point is, if you already have a list of boolean values, list = {True, False, False, ....} then And @@ list is absolutely the right thing to do. AllTrue or any of the v9 implementations of it listed above would be overkill.

POSTED BY: Jason Biggs

Obviously, this will not short circuit, it will first map everything and then apply the And operator.

You would have to do this:

And[Print[2]; EvenQ[2], Print[4]; EvenQ[4], Print[6]; EvenQ[6], 
 Print[1]; EvenQ[1], Print[3]; EvenQ[3], Print[5]; EvenQ[5]]

2
4
6
1
False
POSTED BY: Sander Huisman
Posted 3 years ago

Jason is right; it doesn't short circuit. You see the difference in

And @@ ((Print[#]; EvenQ[#]) & /@ {2, 4, 6, 1, 3, 5})

versus

AllTrue[{2, 4, 6, 1, 3, 5}, (Print[#]; EvenQ[#]) &]

This shatters illusions.

POSTED BY: Bernd Günther

Map (/@) will probably get compiled for large lists, so that could explain the difference…

POSTED BY: Sander Huisman
Posted 3 years ago

I think Jason's point is that AllTrue short-circuits the Map. However, the timings suggest that it is slower. What am I missing?

test1 = {1}~Join~ConstantArray[2, 10^6];
test2 = ConstantArray[2, 10^6]~Join~{1};

allTrue[list_, test_] := test /@ list // MatchQ[{True ..}]
allTrueJason[list_, test_] := Catch[Map[Function[If[! test@#, Throw[False]]], list];
  True]

allTrue[test1, OddQ] // AbsoluteTiming
(* {0.204723, False} *)

allTrueJason[test1, OddQ] // AbsoluteTiming
(* {0.461795, False} *)

Similar timings for test2.

POSTED BY: Rohit Namjoshi
Posted 3 years ago

This might be relevant. From the documentation reference of And:

enter image description here

As I see it, the OP had a list consisting of only True or False and wanted to see if all elements were True. The additional condition of OddQ somehow crept in later in the discussion.

POSTED BY: Hans Milton
Posted 3 years ago

Careful. For conjunctions, Mathematica performs a short circuit evaluation, i.e. it stops anding up Booleans as soon as it encounters false. Btw this is standard procedure for any modern programming languages.

POSTED BY: Bernd Günther

The suggestions so far miss the efficiency of AllTrue , that it stops checking the solutions at the first failure. So

AllTrue[{1,2,3,4,5,6,7}, OddQ]

is only going to evaluate OddQ twice, and will stop trying at that point. Something like this would work I think:

allTrue[list_, test_] := Catch[
    Map[Function[If[!test @ #, Throw[False]]], list];
    True
]
POSTED BY: Jason Biggs

This is clearly the most Wolframian way of doing it, perhaps faster is And @@, but harder to read perhaps…

POSTED BY: Sander Huisman
Posted 3 years ago

What about using And@@? Something like And @@ EvenQ /@ {2,4,6} ?

POSTED BY: Bernd Günther

Interesting, if a bit more ... complicated.

[My kludge-y solution got it done in basically 2 lines with MemberQ[list, False] and then simply doing a check whether the output is "[Output]==False" to flip the output bit from False to True. ;) ]

POSTED BY: Michael Gmirkin
Posted 3 years ago

Hi Michael,

You can use pattern matching

listTF = {True, False, False, True};
listT = {True, True, True, True};

listTF // MatchQ[{True ..}]
(* False *)

listT // MatchQ[{True ..}]
(* True *)

Combine that with mapping a predicate function

allTrue[list_, test_] := test /@ list // MatchQ[{True ..}]

allTrue[{2, 3, 4, 6, 8}, EvenQ]
(* False *)

allTrue[{2, 4, 6, 8}, EvenQ]
(* True *)
POSTED BY: Rohit Namjoshi

As you can see, I simply took the row divisibility-by-row-number list ad did a MemberQ check versus "False," and then Simply did a check whether the check is false or not, which returns true if false, or false if true, to "invert" the value.

Ridiculous workaround. But, as long as it works, right? :P

Seriously though, is there an easier way to check that all list members are specifically true as opposed to "no members are false"?

I feel like there should be, save for the fact AllTrue[] apparently wasn't a thing in Mathematica 9 (I know, I'm a few versions back; been meaning to upgrade for a while, just haven't gotten around to it yet).

POSTED BY: Michael Gmirkin

Well, here's my first pass at a ridiculously stupid workaround:

SomePrimeCandidate = 191;
PascalStart = 1;
PascalEnd = Ceiling[(SomePrimeCandidate - 1)/2];
PascalRange = Range[PascalStart, PascalEnd];
PascalRow = Factorial[SomePrimeCandidate]/((Factorial[(SomePrimeCandidate-PascalRange)])*(Factorial[PascalRange]));
PascalDivisibility = Divisible[PascalRow, SomePrimeCandidate];
IsComposite = MemberQ[PascalDivisibility, False];
IsPrime = (IsComposite == False)
PascalDivisibilityArray = Transpose[{PascalRow, PascalDivisibility}];
PascalDivisibilityGrid = Grid[PascalDivisibilityArray]
POSTED BY: Michael Gmirkin
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