1 """Utilities for enumeration of finite and countably infinite sets.
3 from __future__
import absolute_import
, division
, print_function
7 # Simplifies some calculations
11 if type._singleton
is None:
12 type._singleton
= int.__new
__(type)
13 return type._singleton
14 def __repr__(self
): return '<aleph0>'
15 def __str__(self
): return 'inf'
21 raise ValueError("Cannot subtract aleph0")
33 def __floordiv__(self
, b
):
34 if b
== 0: raise ZeroDivisionError
36 __rfloordiv__
= __floordiv__
37 __truediv__
= __floordiv__
38 __rtuediv__
= __floordiv__
39 __div__
= __floordiv__
40 __rdiv__
= __floordiv__
48 return line
*(line
+1)//2
53 return base(line
)+index
55 def getNthPairInfo(N
):
56 # Avoid various singularities
60 # Gallop to find bounds for line
67 # Binary search for starting line
71 #assert base(lo) <= N < base(hi)
79 return line
, N
- base(line
)
82 line
,index
= getNthPairInfo(N
)
83 return (line
- index
, index
)
85 def getNthPairBounded(N
,W
=aleph0
,H
=aleph0
,useDivmod
=False):
86 """getNthPairBounded(N, W, H) -> (x, y)
88 Return the N-th pair such that 0 <= x < W and 0 <= y < H."""
91 raise ValueError("Invalid bounds")
93 raise ValueError("Invalid input (out of bounds)")
96 if W
is aleph0
and H
is aleph0
:
99 # Otherwise simplify by assuming W < H
101 x
,y
= getNthPairBounded(N
,H
,W
,useDivmod
=useDivmod
)
107 # Conceptually we want to slide a diagonal line across a
108 # rectangle. This gives more interesting results for large
109 # bounds than using divmod.
111 # If in lower left, just return as usual
116 # Otherwise if in upper right, subtract from corner
123 # Otherwise, compile line and index from number of times we
126 index
,offset
= N
%W
,N
//W
127 # p = (W-1, 1+offset) + (-1,1)*index
128 return (W
-1-index
, 1+offset
+index
)
129 def getNthPairBoundedChecked(N
,W
=aleph0
,H
=aleph0
,useDivmod
=False,GNP
=getNthPairBounded
):
130 x
,y
= GNP(N
,W
,H
,useDivmod
)
131 assert 0 <= x
< W
and 0 <= y
< H
134 def getNthNTuple(N
, W
, H
=aleph0
, useLeftToRight
=False):
135 """getNthNTuple(N, W, H) -> (x_0, x_1, ..., x_W)
137 Return the N-th W-tuple, where for 0 <= x_i < H."""
142 elts
[i
],N
= getNthPairBounded(N
, H
)
150 return getNthPairBounded(N
, H
, H
)
152 LW
,RW
= W
//2, W
- (W
//2)
153 L
,R
= getNthPairBounded(N
, H
**LW
, H
**RW
)
154 return (getNthNTuple(L
,LW
,H
=H
,useLeftToRight
=useLeftToRight
) +
155 getNthNTuple(R
,RW
,H
=H
,useLeftToRight
=useLeftToRight
))
156 def getNthNTupleChecked(N
, W
, H
=aleph0
, useLeftToRight
=False, GNT
=getNthNTuple
):
157 t
= GNT(N
,W
,H
,useLeftToRight
)
163 def getNthTuple(N
, maxSize
=aleph0
, maxElement
=aleph0
, useDivmod
=False, useLeftToRight
=False):
164 """getNthTuple(N, maxSize, maxElement) -> x
166 Return the N-th tuple where len(x) < maxSize and for y in x, 0 <=
169 # All zero sized tuples are isomorphic, don't ya know.
173 if maxElement
is not aleph0
:
174 if maxSize
is aleph0
:
175 raise NotImplementedError('Max element size without max size unhandled')
176 bounds
= [maxElement
**i
for i
in range(1, maxSize
+1)]
177 S
,M
= getNthPairVariableBounds(N
, bounds
)
179 S
,M
= getNthPairBounded(N
, maxSize
, useDivmod
=useDivmod
)
180 return getNthNTuple(M
, S
+1, maxElement
, useLeftToRight
=useLeftToRight
)
181 def getNthTupleChecked(N
, maxSize
=aleph0
, maxElement
=aleph0
,
182 useDivmod
=False, useLeftToRight
=False, GNT
=getNthTuple
):
183 # FIXME: maxsize is inclusive
184 t
= GNT(N
,maxSize
,maxElement
,useDivmod
,useLeftToRight
)
185 assert len(t
) <= maxSize
187 assert i
< maxElement
190 def getNthPairVariableBounds(N
, bounds
):
191 """getNthPairVariableBounds(N, bounds) -> (x, y)
193 Given a finite list of bounds (which may be finite or aleph0),
194 return the N-th pair such that 0 <= x < len(bounds) and 0 <= y <
198 raise ValueError("Invalid bounds")
199 if not (0 <= N
< sum(bounds
)):
200 raise ValueError("Invalid input (out of bounds)")
203 active
= list(range(len(bounds
)))
204 active
.sort(key
=lambda i
: bounds
[i
])
206 for i
,index
in enumerate(active
):
207 level
= bounds
[index
]
212 H
= level
- prevLevel
214 if N
<levelSize
: # Found the level
215 idelta
,delta
= getNthPairBounded(N
, W
, H
)
216 return active
[i
+idelta
],prevLevel
+delta
221 raise RuntimError("Unexpected loop completion")
223 def getNthPairVariableBoundsChecked(N
, bounds
, GNVP
=getNthPairVariableBounds
):
225 assert 0 <= x
< len(bounds
) and 0 <= y
< bounds
[x
]
233 a
= [[' ' for x
in range(10)] for y
in range(10)]
234 b
= [[' ' for x
in range(10)] for y
in range(10)]
235 for i
in range(min(W
*H
,40)):
236 x
,y
= getNthPairBounded(i
,W
,H
)
237 x2
,y2
= getNthPairBounded(i
,W
,H
,useDivmod
=True)
238 print(i
,(x
,y
),(x2
,y2
))
244 if ''.join(ln
).strip():
248 if ''.join(ln
).strip():
252 bounds
= [2,2,4,aleph0
,5,aleph0
]
253 a
= [[' ' for x
in range(15)] for y
in range(15)]
254 b
= [[' ' for x
in range(15)] for y
in range(15)]
255 for i
in range(min(sum(bounds
),40)):
256 x
,y
= getNthPairVariableBounds(i
, bounds
)
262 if ''.join(ln
).strip():
267 # Toggle to use checked versions of enumeration routines.
269 getNthPairVariableBounds
= getNthPairVariableBoundsChecked
270 getNthPairBounded
= getNthPairBoundedChecked
271 getNthNTuple
= getNthNTupleChecked
272 getNthTuple
= getNthTupleChecked
274 if __name__
== '__main__':