Selecting lists from lists of lists

I have the following list:

points = Tuples[Range[0, 1.25, 0.25], 9]


I would like to select only those lists who have the following properties, naming the elements of each lists with slots:

• 1) #1>0.4
• 2) #9>#8,#8>#7,#7>#6
• 3) #1+#2+#3< 1.22
• 4) #5<#4
• 5) #4<1.21
• 6) 0.5 (#1 (2.42-#6+#7)+#2(#4+1.21-#6)+#3 (#5+#4))<0.625
• 7) All #>0

Any suggestions to do this?

UPDATE

As Rashid pointed out, this is terribly slow to solve. If any brilliant lad can think of a way to directly construct such a list, chapeau!

In the spirit of making the code less slow as suggested by Rashid, I have written this code for the first list of lists:

points = Partition[#, 9] &@
Flatten@Tuples[{Tuples[Range[0.25, 0.75, 0.25], 1],
Tuples[Range[0, 0.75, 0.25], 4],
Tuples[Range[0, Pi/3, Pi/12], 4]}];


Please use this code instead of the first. With this code condition 1 is implicitly given. Any other suggestions for building the list is welcomed. I also added some extra conditions to limit the length of this list.

• You can drop condition 7 as well by starting the second inner Tuples at 0.25 and the third at Pi/12. – Edmund May 15 '16 at 16:12
• Yeah, yet I just realized that the code I wrote then mixes the order of the elements of each list. This is not what I needed! – Mirko Aveta May 15 '16 at 16:16

Update for applying all test simultaneously.

There do not appear to be any lists that simultaneously satisfy all seven conditions.

oneSelectTests = MapAt[Function[{f}, f[Sequence @@ #] &], ;; -2]@tests;
oneSelectRes = Select[And @@ Through[oneSelectTests[#]] &]@points;
Dimensions@oneSelectRes
(* {0} *)


A solution with Slot.

tests = {
#1 > 0.4 &,
And @@ {#9 > #8, #8 > #7, #7 > #6} &,
#1 + #2 + #3 < 1.22 &,
#5 < #4 &, #4 < 1.21 &,
0.5 (#1 (2.42 - #6 + #7) + #2 (#4 + 1.21 - #6) + #3 (#5 + #4)) < 0.625 &,
And @@ Positive[#] &
}


Then build the set of Select functions that take each sublist as its list of parameters. The last test is not mapped as it needs to take the list.

selTests = Select /@ MapAt[Function[{f}, f[Sequence @@ #] &], ;; -2]@tests;


Then apply the selTests to points.

res = Through@selTests@points;
Dimensions /@ res

(* {{6718464, 9}, {116640, 9}, {1632960, 9}, {4199040, 9},
{8398080, 9}, {1292004, 9}, {1953125, 9}} *)


Hope this helps.

• Dear Edmund, thank you for your suggestion. Does your code consider all the conditions together? I need all conditions to be considered. – Mirko Aveta May 15 '16 at 14:09
• Oh, I thought you wanted 7 separate sets to each condition. Misread. Let me think about that. – Edmund May 15 '16 at 14:11
• @MirkoAveta See update. There do not appear to be any list that simultaneously satisfy all conditions. – Edmund May 15 '16 at 15:22
• Yes, thanks for pointing that out. I must firstly say that the first condition has been suppressed, as I have said in Rashed's reply update. I will see if this happens also in the new definition of 'points'. – Mirko Aveta May 15 '16 at 15:29
points = Tuples[Range[0, 1.25, 0.25], 9];

pnts1b = Select[points, #[[1]] > 0.4 &]; // AbsoluteTiming // First


11.617923

Pick instead of Select is faster:

pnts1a = Pick[points, UnitStep[points[[All, 1]] - .4], 1]; // AbsoluteTiming // First


0.545490

As suggested by @Rashid, using the conditions upfront is much faster:

pnts1c = Tuples[{Select[Range[0, 1.25, .25], # > .4 &],
## & @@ (ConstantArray[Range[0, 1.25, 0.25], 8])}]; // AbsoluteTiming // First


0.126385

Update: constructing tuples bottom up using the conditions

In the following the list cxyz stands for a list of tuples satisfying conditions x, y and z. Since conditions 1, 3 and 7 relate to entries 1,2,3 and conditions 4,5,7 to entries 4 and 5, and conditions 2,7 apply to entries 6,7,8,9 we can piece together 9-tuples from 3-tuples satisying conditions 1,2,7 and, 2-tuples satisfying conditions 4,5,7 and 4-tuples satisfying conditions 2,7. Then we can filter the resulting list of 9-tuples using condition 6.

AbsoluteTiming[c137 = Pick[tt = Tuples[{Range[.5, 1.25, .25], Range[.25, 1.25, .25],
Range[.25, 1.25, .25]}], Total[#] < 1.22 & /@ tt];
c457 = Partition[Flatten[Table[{j, i}, {j, .25, 1.0, .25}, {i, .25, j - .25, .25}]], 2];
c13457 = Join @@@ Tuples[{c137, c457}];
c27 = Partition[Flatten[Table[{i, j, k, l}, {i, .25, 1.25, .25},
{j, i + .25, 1.25, .25}, {k, j + .25, 1.25, .25}, {l, k + .25, 1.25, .25}]],  4];
c123457 = Join @@@ Tuples[{c13457, c27}]]


Finally checking for condition 6, we get an empty set as the final result

Pick[c123457, 0.5 (#[[1]] (2.42 - #[[6]] + #[[7]]) + #[[2]] (#[[4]] +
1.21 - #[[6]]) + #[[3]] (#[[5]] + #[[4]])) < 0.625 & /@ c123457]


{}

Incidentally, identifying 9-tuples satisfying condition 6 only takes a long time:

lengthc6 = Length[Pick[tuples, 0.5 (#[[1]] (2.42 - #[[6]] + #[[7]]) + #[[2]] (#[[4]] +
1.21 - #[[6]]) + #[[3]] (#[[5]] + #[[4]])) < 0.625 & /@ tuples]] // AbsoluteTiming


{89.781723, 1292004}

• Thanks for your suggestions. I didn't know that Pick was that faster!! – Mirko Aveta May 15 '16 at 14:34

Here is a direct approach using Select with Part([[]]) and Slot (#), but given the size of points, this will definitely be very slow. Each selection takes 2-3 minutes to run on my computer for a total of ~20 minutes:

points = Tuples[Range[0, 1.25, 0.25], 9];
points1 = Select[points, #[[1]] > 0.25 &]
points2 = Select[points, #[[9]] > #[[8]] && #[[8]] > #[[7]] && #[[7]] > #[[6]] &]
points3 = Select[points, #[[1]] + #[[2]] + #[[3]] < 1.22 &]
points4 = Select[points, #[[5]] < #[[4]] &]
points5 = Select[points, #[[4]] < 1.21 &]
points6 = Select[points,  0.5 (#[[1]] (2.42 - #[[6]] + #[[7]]) + #[[2]] (#[[4]] + 1.21 - #[[6]]) + #[[3]] (#[[5]] + #[[4]])) < 0.625 &]
points7 = Select[points, Apply[Times, #] > 0 &]


Note that points7 assumes all numbers are either zero or positive. A more generally implementation would be something like points7b = Select[points, Min[Sign[#]] > 0 &]

Since the tuples list in points is so large, I suspect you would be better off just constructing the final lists you want. For example, using points7=Tuples[Range[0.25,1.25,0.25],9] rather than selecting the ones without zeros.

Edit -by Mirko Aveta

In the spirit of making the code less slow as suggested by Rashid, I have written this code for the first list of lists:

points = Partition[#, 8] &@
Flatten@Tuples[{Tuples[Range[0.25, 0.75, 0.25], 1],
Tuples[Range[0, 0.75, 0.25], 4],
Tuples[Range[0, Pi/3, Pi/12], 4]}];


Please use this code instead of the first. With this code condition 1 is implicitly given. Any other suggestions for building the list is welcomed. I also added some extra conditions to limit the length of this list. d

• Thanks for your suggestion. Indeed I used a step of 0.25 because I knew it was too slow for testing. I will have to change the step once the code is done, so I would have values much closer to the zero. It would be much more efficient to write down the list directly selected, that would be really perfect! – Mirko Aveta May 15 '16 at 13:40
• @MirkoAveta, yes, I would definitely go with defining the lists you want upfront. For the more complicated cases, I would probably just use Table with 9 explicit indexes and integer ranges, and then divide in the end by the appropriate integer. For example, Table[{x1,x2,x3,...x9},{x1,0,5},{x2...}] then divide by 5*9 in this case.... – Rashid May 15 '16 at 13:49