Last active
March 1, 2021 23:39
-
-
Save lshifr/7d5d3ef064b2eb1a1e9b997726923331 to your computer and use it in GitHub Desktop.
A new version of lazy Tuples extension for Streaming framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BeginPackage["LazyTuples`"] | |
LazyTuples::usage = "LazyTuples[lists, opts] create a LazyList of the specified chunk size (\"ChunkSize\" option), containing tuples of the original lists"; | |
TuplesFunction::usage = | |
"TuplesFunction[lists][parts: _Integer | {__Integer} | _Span] generates a tuple or a set of tuples \ | |
found at specific positions indicated, in the full list of tuples, as given by Tuples"; | |
Begin["`Private`"] | |
Needs["Streaming`"]; | |
cCompilerAvailable = Quiet @ Check[ | |
Compile[{a}, a + 1, CompilationTarget -> "C"]; True, | |
False | |
] | |
compilationTarget = If[cCompilerAvailable, "C", "MVM"] | |
(* | |
** TuplesFunction by Carl Woll | |
** https://mathematica.stackexchange.com/questions/109598/lazy-form-of-tuples-outer-to-loop-over-list-of-lists/153609#153609 | |
*) | |
ClearAll[TuplesFunction] | |
TuplesFunction[lists_] := With[{lens = Length /@ lists}, | |
TuplesFunction[ | |
lists, | |
Reverse @ FoldList[Times, 1, Reverse @ Rest @ lens] | |
] | |
] | |
TuplesFunction[lists_, basis_][index_Integer] := With[ | |
{decomp = 1 + decompose[index-1, basis]}, | |
MapThread[Part, {lists, decomp}] | |
] | |
TuplesFunction[lists_, basis_][indices:{__Integer}] := With[ | |
{decomp = 1 + decomposeList[indices-1, basis]}, | |
Transpose @ MapThread[Part, {lists, decomp}] | |
] | |
TuplesFunction[lists_, basis_][span_Span] := With[ | |
{r = toList[span, Times @@ Length /@ lists]}, | |
TuplesFunction[lists, basis][r] | |
] | |
MakeBoxes[t:TuplesFunction[lists_List, ___], StandardForm] ^:= Module[ | |
{lens=Length/@lists}, | |
BoxForm`ArrangeSummaryBox[ | |
TuplesFunction, | |
t, | |
BarChart[lens,ImageSize->30, Axes->False], | |
{ | |
BoxForm`MakeSummaryItem[{"Count: ",Times@@lens}, StandardForm], | |
BoxForm`MakeSummaryItem[{"Length: ", lens}, StandardForm] | |
}, | |
{}, | |
StandardForm, | |
"Interpretable"->True | |
] | |
] | |
decompose := decompose = Compile[{{n, _Integer}, {d, _Integer, 1}}, | |
Module[{c=n, q}, | |
Table[ | |
q = Quotient[c, i]; | |
c = Mod[c, i]; | |
q, | |
{i, d} | |
] | |
], | |
RuntimeAttributes -> {Listable}, | |
CompilationTarget -> compilationTarget | |
]; | |
decomposeList := decomposeList = Compile[{{n, _Integer, 1}, {d, _Integer, 1}}, | |
Module[{c=n, q}, | |
Table[ | |
q = Quotient[c, i]; | |
c = Mod[c, i]; | |
q, | |
{i, d} | |
] | |
], | |
CompilationTarget -> compilationTarget | |
]; | |
toList[Span[a_, b_, c_:1], max_] := With[ | |
{ | |
x = Replace[a, {All->1, UpTo[x_]:>Min[x,max]}], | |
y = Replace[b, {All->max, -1->max, UpTo[x_]:>Min[x,max]}] | |
}, | |
Range[x, y, Replace[c, {All -> If[x<=y, 1, -1], Except[_Integer]->1}]] | |
] | |
ClearAll[$iteratorChunkSize]; | |
ClearAll[lazyTuplesVirtual]; | |
lazyTuplesVirtual[lists:{__List}, chsize:_Integer?Positive:$iteratorChunkSize]:= | |
With[{tf = TuplesFunction[lists], len = Times @@ (Length /@ lists)}, | |
With[{ | |
takeFun = | |
Function[index, | |
Function[ | |
If[(index-1) * chsize+1 > len, | |
{}, | |
tf[((index-1) * chsize+1);;Min[index * chsize, len]] | |
] | |
] | |
] | |
}, | |
Streaming`LazyList`LazyListCreate[ | |
takeFun, | |
Function[index, If[(index-1) * chsize+1 > len, -1, Min[index * chsize, len] - (index-1) * chsize]], | |
"FiniteList" -> True | |
] | |
] | |
]; | |
ClearAll[makeTupleIterator]; | |
makeTupleIterator[lists:{__List}, chunkSize_Integer?Positive]:= | |
With[{len = Times @@ Map[Length, lists], tf = TuplesFunction[lists]}, | |
Module[{ctr = 0, active = False}, | |
Streaming`DataStructures`Interfaces`IteratorCreate[ | |
Streaming`DataStructures`DataTypes`ListIterator, | |
(active = True) &, | |
Function[ | |
If[ctr >= len, | |
{}, | |
(* else *) | |
With[{taken = tf[ctr+1 ;; Min[ctr + chunkSize, len]]}, | |
ctr += Length[taken]; | |
taken | |
] | |
] | |
], | |
TrueQ[active] &, | |
Remove[active, ctr]& | |
] | |
] | |
]; | |
ClearAll[lazyTuplesIterative]; | |
lazyTuplesIterative[lists:{__List}, chunkSize:_Integer?Positive:$iteratorChunkSize]:= | |
Streaming`LazyList`LazyListCreate[makeTupleIterator[lists, chunkSize], chunkSize]; | |
$iteratorChunkSize = 10000; | |
ClearAll[lazyTuples]; | |
lazyTuples["Iterator"] = lazyTuplesIterative; | |
lazyTuples["Virtual"] = lazyTuplesVirtual; | |
lazyTuples[_][args___]:= $Failed; | |
ClearAll[LazyTuples]; | |
Options[LazyTuples] = { | |
"Method" -> "Virtual", | |
"ChunkSize" :> $iteratorChunkSize | |
}; | |
LazyTuples[lists_, opts:OptionsPattern[]]:= | |
lazyTuples[OptionValue["Method"]][lists, OptionValue["ChunkSize"]]; | |
End[] | |
EndPackage[] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment