Skip to main content

function construction - Lazy lists of Tuples and Subsets


I'm trying to build a lazy list that evaluates the n'th m-tuple or subset of a given list using Mathematicas ordering without calculating all the Tuples. The purpose is to allow for example the traversal of very large spaces of tuples without fist having to calculate the complete space of tuples. So far I have defined a function that calcluates which elements goes where for the n'th tuple:


tupleIndexes[l_, t_, n_] := Table[Mod[Quotient[n - 1, l^m] + 1, l, 1], {m, t - 1, 0, -1}] 

And have used this to define a lazy list by defining a SubValue for when Part is applied.


lazyTuple /:Part[lazyTuple[list_, t_], n_Integer] /; 0 < n <= Length[lazyTuple[list, t]]:=
list[[tupleIndexes[Length[list], t, n]]]

The result is that lazyTuple[{1,2,3,4},2] remains unevaluted but lazyTuple[{1,2,3,4},2][[2]] returns {1,2} as expected.


For testing I've defined a function to iterate through the list and return them all:



lazyTuple /: Length[lazyTuple[list_, t_]] := Length[list]^t
lazyTuple /: lazyTakeAll[a_lazyTuple] /; (NumericQ@Length@a) := Table[a[[i]], {i, Length@a}]

And it seems to check out:


 lazyTakeAll[lazyTuple[Range@6, 3]] == Tuples[Range@6, 3]


True



Now my question is firstly if I'm making any subtle mistakes means this isn't returning the correct order with respect to Tuples. But more importantly, how would one go about defining a similar function for lazySubsets[]




Answer



Well since I asked I supose I better supply at least a rudimentary answer. Turns out it was a bit harder then I initially expected to get the right order, but I think my solution is somewhat nice. What I do is, that if we want the n'th subset, I find a list of thresholds for when the first indice changes and test what threshold n is larger then. Then I continue this method on the next level, such that if we wanted the 1'th subset of 4 elements chosen in 6, the first indice is 1, and the second can be found as 1 + the 1'th subset of 3 elements chosen in 5. This way I go through each level and end up with the indices.


thresholds[n_,l_]:=Accumulate[Table[Binomial[n-i,l-1],{i,1,n-l+1}]]
compareToThreshold[n_,num_,group_]:=Position[#>=n&/@thresholds[num,group],True,1,1][[1,1]]

digDeeper[{n_,m_,l_,i_}]:=
{n-Prepend[thresholds[m,l],0][[i]],m-i,l-1}//Append[#,Sow[compareToThreshold@@#]]&

subsetIndices[grouplength_,setlength_,nth_]:=
Accumulate[Reap[Nest[digDeeper,{nth,grouplength+1,setlength+1,1},setlength]][[2,1]]]


For my own usage I only need fixed length subsets, therefore it only works with those. For all subsets, Combinatorica's NthSubset works quite nicely. So now to make a lazySubsets, it's just a question of using the same structure as for lazyTuples in my question.


lazySubsets/:Part[lazySubsets[list_,t_],n_Integer]/;0  list[[subsetIndices[Length[list],t,n]]]

And to test this


lazyTakeAll[a_]/;(NumericQ@Length@a):=Table[a[[i]],{i,Length@a}]

lazyTakeAll[lazySubsets[Range@15, 7]] == Subsets[Range@15, {7}]



True



Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...