@@ -65,7 +65,7 @@ def coerce(cls, item, perm_space=None):
6565 return cls (item , perm_space )
6666
6767
68- def __init__ (self , number_or_perm_sequence , perm_space = None ):
68+ def __init__ (self , perm_sequence , perm_space = None ):
6969 '''
7070
7171 Not supplying `perm_space` is allowed only if given either a number (in
@@ -74,32 +74,23 @@ def __init__(self, number_or_perm_sequence, perm_space=None):
7474 '''
7575 perm_space = None if perm_space is None \
7676 else PermSpace .coerce (perm_space )
77- if isinstance (number_or_perm_sequence , collections .Iterable ):
78- number_or_perm_sequence = sequence_tools . \
79- ensure_iterable_is_immutable_sequence (number_or_perm_sequence )
80- assert isinstance (number_or_perm_sequence , (numbers .Integral ,
81- collections .Sequence ))
77+ assert isinstance (perm_sequence , collections .Iterable )
78+ perm_sequence = sequence_tools . \
79+ ensure_iterable_is_immutable_sequence (perm_sequence )
8280
8381 ### Analyzing `perm_space`: ###########################################
8482 # #
8583 if perm_space is None :
86- if not isinstance (number_or_perm_sequence ,
87- collections .Sequence ):
88- raise Exception (
89- "You tried creating a `Perm` using a number instead of a "
90- "sequence and without specifying `PermSpace`, so we have "
91- "no way of knowing which `PermSpace` to use."
92- )
9384 # We're assuming that `number_or_perm_sequence` is a pure
9485 # permutation sequence. Not asserting this because that would
9586 # be O(n).
96- self .nominal_perm_space = PermSpace (len (number_or_perm_sequence ))
87+ self .nominal_perm_space = PermSpace (len (perm_sequence ))
9788 else : # perm_space is not None
9889 self .nominal_perm_space = perm_space .unsliced .undegreed .unfixed
9990
10091 # `self.nominal_perm_space` is a perm space that preserves only the
101- # rapplied, dapplied , partial and combination properties of the
102- # original `PermSpace`.
92+ # rapplied, recurrent , partial, dapplied and combination properties of
93+ # the original `PermSpace`.
10394
10495 # #
10596 ### Finished analyzing `perm_space`. ##################################
@@ -116,33 +107,16 @@ def __init__(self, number_or_perm_sequence, perm_space=None):
116107 if not self .is_dapplied : self .undapplied = self
117108 if not self .is_combination : self .uncombinationed = self
118109
119- if isinstance (number_or_perm_sequence , numbers .Integral ):
120- if not (0 <= number_or_perm_sequence <
121- self .nominal_perm_space .length ):
122- raise Exception (
123- "You're creating a `Perm` with number %s, but the chosen "
124- "`PermSpace` only goes from 0 up to %s." % (
125- number_or_perm_sequence ,
126- self .nominal_perm_space .length - 1
127- )
128- )
129-
130- self .number = number_or_perm_sequence
131- else :
132- assert isinstance (number_or_perm_sequence , collections .Iterable )
133- self ._perm_sequence = sequence_tools . \
134- ensure_iterable_is_immutable_sequence (number_or_perm_sequence )
110+ self ._perm_sequence = sequence_tools . \
111+ ensure_iterable_is_immutable_sequence (perm_sequence )
135112
136113 assert self .is_combination == isinstance (self , Comb )
137114
138115
139116 _reduced = property (lambda self : (
140- type (self ), self .number ,
141- self .nominal_perm_space )
142- )
117+ type (self ), self ._perm_sequence , self .nominal_perm_space
118+ ))
143119
144- __int__ = lambda self : self .number
145- __mod__ = lambda self , other : self .number % other
146120 __iter__ = lambda self : iter (self ._perm_sequence )
147121
148122 __eq__ = lambda self , other : (isinstance (other , Perm ) and
@@ -160,11 +134,9 @@ def __contains__(self, item):
160134 return False
161135
162136 def __repr__ (self ):
163- return '<%s%s: (%s / %s) %s(%s%s)>' % (
137+ return '<%s%s: %s(%s%s)>' % (
164138 type (self ).__name__ ,
165139 (', n_elements=%s' % len (self )) if self .is_partial else '' ,
166- self .number ,
167- self .nominal_perm_space .short_length_string ,
168140 ('(%s) => ' % ', ' .join (map (repr , self .domain )))
169141 if self .is_dapplied else '' ,
170142 ', ' .join (repr (item ) for item in self ),
@@ -176,88 +148,6 @@ def index(self, member):
176148 return self .nominal_perm_space . \
177149 domain [numerical_index ] if self .is_dapplied else numerical_index
178150
179- @caching .CachedProperty
180- def number (self ):
181- '''
182-
183- The number here is not necessarily the number with which the perm was
184- fetched from the perm space; it's the number of the perm in its nominal
185- perm space, i.e. a perm space that is neither degreed, fixed or sliced.
186- '''
187- if self .is_dapplied :
188- return self .undapplied .number
189-
190- if self .is_recurrent :
191- return self .nominal_perm_space .index (self )
192-
193- if self .is_combination :
194- if self .is_rapplied :
195- return self .unrapplied .number
196-
197- processed_perm_sequence = tuple (
198- self .nominal_perm_space .sequence_length - 1 -
199- item for item in self ._perm_sequence [::- 1 ]
200- )
201- return self .nominal_perm_space .length - 1 - sum (
202- (math_tools .binomial (item , i ) for i , item in
203- enumerate (processed_perm_sequence , start = 1 )),
204- 0
205- )
206-
207- factoradic_number = []
208- unused_values = list (self .nominal_perm_space .sequence )
209- for i , value in enumerate (self ):
210- index_of_current_number = unused_values .index (value )
211- factoradic_number .append (index_of_current_number )
212- unused_values .remove (value )
213- return math_tools .from_factoradic (
214- factoradic_number +
215- [0 ] * self .nominal_perm_space .n_unused_elements
216- ) // math .factorial (
217- self .nominal_perm_space .n_unused_elements )
218-
219-
220- @caching .CachedProperty
221- def _perm_sequence (self ):
222- assert (0 <= self .number <
223- self .nominal_perm_space .length )
224- if self .is_combination :
225- wip_number = (self .nominal_perm_space .length - 1 - self .number )
226- wip_perm_sequence = []
227- for i in range (self .nominal_perm_space .n_elements , 0 , - 1 ):
228- for j in range (self .nominal_perm_space .sequence_length , i - 2 , - 1 ):
229- candidate = math_tools .binomial (j , i )
230- if candidate <= wip_number :
231- wip_perm_sequence .append (
232- self .nominal_perm_space .sequence [- (j + 1 )]
233- )
234- wip_number -= candidate
235- break
236- else :
237- raise RuntimeError
238- result = tuple (wip_perm_sequence )
239- assert len (result ) == self .length
240- return result
241-
242- else :
243- factoradic_number = math_tools .to_factoradic (
244- self .number * math .factorial (
245- self .nominal_perm_space .n_unused_elements ),
246- n_digits_pad = self .nominal_perm_space .sequence_length
247- )
248- if self .is_partial :
249- factoradic_number = factoradic_number [
250- :- self .nominal_perm_space .n_unused_elements
251- ]
252- unused_numbers = list (self .nominal_perm_space .sequence )
253- result = tuple (unused_numbers .pop (factoradic_digit ) for
254- factoradic_digit in factoradic_number )
255- assert sequence_tools .get_length (result ) == self .length
256-
257-
258- return nifty_collections .LazyTuple (result )
259-
260-
261151
262152 @caching .CachedProperty
263153 def inverse (self ):
@@ -432,9 +322,9 @@ def get_neighbors(self, *, degrees=(1,), perm_space=None):
432322
433323
434324 def __lt__ (self , other ):
435- if isinstance (other , Perm ):
436- return ( self .nominal_perm_space , self . number ) < \
437- ( other .nominal_perm_space , other . number )
325+ if isinstance (other , Perm ) and \
326+ self .nominal_perm_space == other . nominal_perm_space :
327+ return self . _perm_sequence < other ._perm_sequence
438328 else :
439329 return NotImplemented
440330
@@ -444,6 +334,10 @@ def __lt__(self, other):
444334 items = caching .CachedProperty (PermItems )
445335 as_dictoid = caching .CachedProperty (PermAsDictoid )
446336
337+ def __eq__ (self , other ):
338+ return type (self ) == type (other ) and \
339+ self .nominal_perm_space == other .nominal_perm_space and \
340+ cute_iter_tools .are_equal (self ._perm_sequence , other ._perm_sequence )
447341
448342
449343
0 commit comments