One can do this in a procedural manner. A direct version did not give much (it was about the same speed as the original code). Instead I'll show a method that works only with the list of first (5-tuple) elements. The benefit is one can use Compile
and that gives a quite measurable speed gain.
I use a dummy function for the checkCondC
. If the max value of the difference of two 5-tuples is less than some threshold, we say the condition fails and do not add the second arg to the list under construction.
This version constructs the list of keepers, and for every new 5-tuple in the original list, tests against keepers before determining whether to add the new on or move on. It is an O(n^2) algorithm but does not have excessive costs from creating/destroying intermediate lists. We simply create an output of the same dimensions as the input, and replace dummy elements by keepers while maintaining a caount of how many keepers we have at any step.
checkCondC =
Compile[{{ll1, _Real, 1}, {ll2, _Real, 1}}, Max[Abs[ll1 - ll2]]];
maxNonintersectingC = Compile[{{ll, _Real, 2}, {eps, _Real}}, Module[
{res = ConstantArray[0., Dimensions[ll]], next, max = 1, good},
res[[1]] = ll[[1]];
Do[
next = ll[[j]];
good =
Catch[Do[
If[checkCondC[res[[k]], next] < eps,
Throw[False]]
, {k, max}];
True];
If[good, max++; res[[max]] = next];
, {j, Length[ll]}];
Take[res, max]
], CompilationOptions -> {"InlineCompiledFunctions" -> True},
CompilationTarget -> "C"];
Now we take a large example.
m = 8000;
inlist = Map[{{1, 1, 1/3, 1, 1}*Most[#], 1/120*Last[#]} &,
RandomReal[{80, 120}, {m, 6}]];
Check that these look a bit like the elements in the original post.
In[282]:= inlist[[1 ;; 3]]
(* Out[282]= {{{114.210179264, 94.9872032272, 30.742668711,
83.7376433634, 119.920328664},
0.928968044627}, {{104.641626332, 92.2701423248, 29.4891773984,
114.993318079, 80.4115524547},
0.960390210004}, {{90.6277601511, 98.6345852935, 30.8461476176,
85.7636679809, 111.535125216}, 0.868401515828}} *)
Timing:
Timing[
mx = Reverse[maxNonintersectingC[inlist[[All, 1]], eps]];]
Length[mx]
(* Out[283]= {0.096, Null}
Out[284]= 512 *)
If we do not compile to C it is still fairly fast, at around 0.27 seconds. By contrast, my pedestrian non-compiled version took around 6.3 seconds.
It is not too difficult to add support for retaining those second elements in the lists. One way would be to feed them in as a separate vark 1 list of reals, Append
the jth such element to the jth list when that list is a keeper, and appropriately restructuring after the compiled part is finished.
checkCond
you will use. $\endgroup$checkCond
? $\endgroup$rest
list is packable? Is it sorted in any way? How many elements does it have? Does order, in which elements in finalkeep
list end-up, matter? IscheckCond
compilable? Is it fast compared to other operations in iteration?checkCond[First@keep1[[1]], #[[1]]] < threshold &
code seems to give a relation onrest
, is this relation transitive? All above details can greatly affect performance. $\endgroup$