Message Boards Message Boards

GROUPS:

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

Posted 5 months ago
1879 Views
|
16 Replies
|
5 Total Likes
|

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?

16 Replies
Posted 5 months ago

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 5 months ago

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 5 months 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 5 months ago

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 5 months ago

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

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

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 5 months 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 5 months 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 5 months 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.

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

Posted 5 months 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.

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

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 5 months 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?

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