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

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Adding a thick curve to a regionplot

Suppose we have the following simple RegionPlot: f[x_] := 1 - x^2 g[x_] := 1 - 0.5 x^2 RegionPlot[{y < f[x], f[x] < y < g[x], y > g[x]}, {x, 0, 2}, {y, 0, 2}] Now I'm trying to change the curve defined by $y=g[x]$ into a thick black curve, while leaving all other boundaries in the plot unchanged. I've tried adding the region $y=g[x]$ and playing with the plotstyle, which didn't work, and I've tried BoundaryStyle, which changed all the boundaries in the plot. Now I'm kinda out of ideas... Any help would be appreciated! Answer With f[x_] := 1 - x^2 g[x_] := 1 - 0.5 x^2 You can use Epilog to add the thick line: RegionPlot[{y < f[x], f[x] < y < g[x], y > g[x]}, {x, 0, 2}, {y, 0, 2}, PlotPoints -> 50, Epilog -> (Plot[g[x], {x, 0, 2}, PlotStyle -> {Black, Thick}][[1]]), PlotStyle -> {Directive[Yellow, Opacity[0.4]], Directive[Pink, Opacity[0.4]],