Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@lshifr
Last active March 1, 2021 23:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lshifr/7d5d3ef064b2eb1a1e9b997726923331 to your computer and use it in GitHub Desktop.
Save lshifr/7d5d3ef064b2eb1a1e9b997726923331 to your computer and use it in GitHub Desktop.
A new version of lazy Tuples extension for Streaming framework
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