Skip to content

Commit 5bd2943

Browse files
committed
Merge remote-tracking branch 'origin/no_perm_number' into fixed
Conflicts: source_py3/python_toolbox/combi/comb.py source_py3/python_toolbox/combi/perm.py
2 parents 19aec6e + 200d532 commit 5bd2943

File tree

11 files changed

+107
-186
lines changed

11 files changed

+107
-186
lines changed

source_py3/python_toolbox/combi/comb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77

88
class Comb(Perm):
9-
def __init__(self, number_or_perm_sequence, perm_space):
9+
def __init__(self, perm_sequence, perm_space):
1010
assert isinstance(perm_space, CombSpace)
11-
Perm.__init__(self, number_or_perm_sequence=number_or_perm_sequence,
11+
Perm.__init__(self, perm_sequence=perm_sequence,
1212
perm_space=perm_space)
1313

1414

source_py3/python_toolbox/combi/perm.py

Lines changed: 19 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -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

source_py3/python_toolbox/combi/perm_space.py

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def __init__(self, iterable_or_length, domain=None, n_elements=None,
272272
if self.is_recurrent:
273273
self._unsliced_undegreed_length = math_tools.shitfuck(
274274
self.n_elements - len(self.fixed_map),
275-
nifty_collections.FrozenCrateCounter(
275+
nifty_collections.FrozenCounterCounter(
276276
collections.Counter(self.free_values).values()
277277
)
278278
)
@@ -297,7 +297,7 @@ def __init__(self, iterable_or_length, domain=None, n_elements=None,
297297
function_to_use = math_tools.catshit if self.is_combination else \
298298
math_tools.shitfuck
299299
self._unsliced_undegreed_length = \
300-
function_to_use(self.n_elements, self._frozen_crate_counter)
300+
function_to_use(self.n_elements, self._frozen_counter_counter)
301301
else:
302302
self._unsliced_undegreed_length = \
303303
math_tools.factorial(
@@ -441,8 +441,8 @@ def _sequence_counteroid(self):
441441

442442

443443
@caching.CachedProperty
444-
def _frozen_crate_counter(self):
445-
return nifty_collections.FrozenCrateCounter(
444+
def _frozen_counter_counter(self):
445+
return nifty_collections.FrozenCounterCounter(
446446
self._sequence_counteroid.values()
447447
)
448448

@@ -615,8 +615,40 @@ def __getitem__(self, i):
615615
),
616616
self
617617
)
618+
619+
elif self.is_combination:
620+
wip_number = self.length - 1 - i
621+
wip_perm_sequence = []
622+
for i in range(self.n_elements, 0, -1):
623+
for j in range(self.sequence_length, i - 2, -1):
624+
candidate = math_tools.binomial(j, i)
625+
if candidate <= wip_number:
626+
wip_perm_sequence.append(
627+
self.sequence[-(j+1)]
628+
)
629+
wip_number -= candidate
630+
break
631+
else:
632+
raise RuntimeError
633+
result = tuple(wip_perm_sequence)
634+
assert len(result) == self.n_elements
635+
return self.perm_type(result, self)
636+
637+
618638
else:
619-
return self.perm_type(i, self)
639+
factoradic_number = math_tools.to_factoradic(
640+
i * math.factorial(
641+
self.n_unused_elements),
642+
n_digits_pad=self.sequence_length
643+
)
644+
if self.is_partial:
645+
factoradic_number = factoradic_number[:-self.n_unused_elements]
646+
unused_numbers = list(self.sequence)
647+
result = tuple(unused_numbers.pop(factoradic_digit) for
648+
factoradic_digit in factoradic_number)
649+
assert sequence_tools.get_length(result) == self.n_elements
650+
651+
return self.perm_type(result, self)
620652

621653

622654
enumerated_sequence = caching.CachedProperty(
@@ -746,9 +778,36 @@ def index(self, perm):
746778
free_values_perm_sequence
747779
)
748780

781+
782+
elif self.is_combination:
783+
if perm.is_rapplied:
784+
return self.unrapplied.index(perm.unrapplied)
785+
786+
processed_perm_sequence = tuple(
787+
self.sequence_length - 1 -
788+
item for item in perm._perm_sequence[::-1]
789+
)
790+
perm_number = self.unsliced.length - 1 - sum(
791+
(math_tools.binomial(item, i) for i, item in
792+
enumerate(processed_perm_sequence, start=1)),
793+
0
794+
)
795+
796+
749797

750798
else:
751-
perm_number = perm.number
799+
800+
factoradic_number = []
801+
unused_values = list(self.sequence)
802+
for i, value in enumerate(perm):
803+
index_of_current_number = unused_values.index(value)
804+
factoradic_number.append(index_of_current_number)
805+
unused_values.remove(value)
806+
perm_number = math_tools.from_factoradic(
807+
factoradic_number +
808+
[0] * self.n_unused_elements
809+
) // math.factorial(self.n_unused_elements)
810+
752811

753812
if perm_number not in self.canonical_slice:
754813
raise ValueError

source_py3/python_toolbox/combi/variations.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
class UnallowedVariationSelectionException(exceptions.CuteException):
1111
'''
1212
13-
blocktodo use everywhere
1413
let it take variations
1514
make variation classes mostly for this and testing'''
1615
def __init__(self, variation_clash):

source_py3/python_toolbox/math_tools/sequences.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ def abs_stirling(n, k):
6363
def shitfuck(k, recurrence_counter):
6464
from python_toolbox import nifty_collections
6565
from python_toolbox import cute_iter_tools
66-
if not isinstance(recurrence_counter, nifty_collections.FrozenCrateCounter):
66+
if not isinstance(recurrence_counter, nifty_collections.FrozenCounterCounter):
6767
recurrence_counter = \
68-
nifty_collections.FrozenCrateCounter(recurrence_counter)
68+
nifty_collections.FrozenCounterCounter(recurrence_counter)
6969
if k == 0:
7070
return 1
7171
elif k == 1:
@@ -119,9 +119,9 @@ def catshit(k, recurrence_counter):
119119
'''
120120
from python_toolbox import nifty_collections
121121
from python_toolbox import cute_iter_tools
122-
if not isinstance(recurrence_counter, nifty_collections.FrozenCrateCounter):
122+
if not isinstance(recurrence_counter, nifty_collections.FrozenCounterCounter):
123123
recurrence_counter = \
124-
nifty_collections.FrozenCrateCounter(recurrence_counter)
124+
nifty_collections.FrozenCounterCounter(recurrence_counter)
125125
if k == 1:
126126
assert recurrence_counter
127127
# (Works because `FrozenCrateCounter` has a functioning `__bool__`,

source_py3/python_toolbox/nifty_collections/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from .lazy_tuple import LazyTuple
1111
from .frozen_dict import FrozenDict
1212
from .frozen_counter import FrozenCounter
13-
from .frozen_crate_counter import FrozenCrateCounter
13+
from .frozen_counter_counter import FrozenCounterCounter
1414
from .default_sorted_dict import DefaultSortedDict
1515
from .cute_enum import CuteEnum
1616

0 commit comments

Comments
 (0)