Skip to content

Commit 176ea56

Browse files
committed
-
1 parent f08ee70 commit 176ea56

File tree

2 files changed

+91
-56
lines changed

2 files changed

+91
-56
lines changed

source_py3/python_toolbox/combi/perming/perm_space.py

Lines changed: 78 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,12 @@ def __init__(self, iterable_or_length, domain=None, *, n_elements=None,
193193

194194
self.n_elements = self.sequence_length if (n_elements is None) \
195195
else n_elements
196-
if not 0 <= self.n_elements <= self.sequence_length:
197-
raise Exception(
198-
'`n_elements` must be between 0 and %s, you gave %s' %
199-
(self.sequence_length, self.n_elements)
200-
)
201-
self.is_partial = (self.n_elements < self.sequence_length)
196+
if not isinstance(self.n_elements, int):
197+
raise TypeError('`n_elements` must be an `int`.')
198+
if not self.n_elements >= 0:
199+
raise TypeError('`n_elements` must be positive or zero.')
200+
201+
self.is_partial = (self.n_elements != self.sequence_length)
202202

203203
self.indices = sequence_tools.CuteRange(self.n_elements)
204204

@@ -365,6 +365,8 @@ def _unsliced_length(self):
365365
This is used as an interim step in calculating the actual length of the
366366
space with the slice taken into account.
367367
'''
368+
if self.n_elements > self.sequence_length:
369+
return 0
368370
if self.is_degreed:
369371
assert not self.is_recurrent and not self.is_partial and \
370372
not self.is_combination
@@ -503,7 +505,9 @@ def __getitem__(self, i):
503505
return self.perm_type(self.undapplied[i], perm_space=self)
504506
elif self.is_degreed:
505507
if self.is_rapplied:
506-
assert not self.is_recurrent
508+
assert not self.is_recurrent and \
509+
not self.is_partial and not self.is_combination and \
510+
not self.is_dapplied and not self.is_sliced
507511
return self.perm_type(map(self.sequence.__getitem__,
508512
self.unrapplied[i]),
509513
perm_space=self)
@@ -585,62 +589,29 @@ def __getitem__(self, i):
585589
for unused_value in nifty_collections.OrderedSet((
586590
value for value in available_values if not
587591
((value in reserved_values and available_values.count(value)
588-
== reserved_values.count(value)) or value in shit_set)
592+
== reserved_values.count(value)) or value in shit_set)
589593

590594
)):
591595
wip_perm_sequence_dict[j] = unused_value
592-
593-
###########################################################
594-
# #
595-
# Tricky thing here: Trying to put as much as we can in a
596-
# sequence head that'll shorten the sequence we'll give to
597-
# the candidate space instead of using a fixed map, if
598-
# possible. This is crucial for `CombSpace` which can't use
599-
# `fixed_map`.
600-
head = []
601-
fixed_map_to_use = dict(wip_perm_sequence_dict)
602-
n_elements_to_use = self.n_elements
603-
for k in sequence_tools.CuteRange(infinity):
604-
try:
605-
head.append(wip_perm_sequence_dict[k])
606-
except KeyError:
607-
break
608-
else:
609-
del fixed_map_to_use[k]
610-
n_elements_to_use -= 1
611-
sequence_to_use = list(self.sequence)
612-
for item in head:
613-
if self.is_combination:
614-
sequence_to_use = sequence_to_use[
615-
sequence_to_use.index(item) + 1:
616-
]
617-
else:
618-
sequence_to_use.remove(item)
619-
620-
sequence_to_use = [x for x in sequence_to_use if x not in
621-
shit_set]
622-
623-
fixed_map_to_use = {key - len(head): value for key, value
624-
in fixed_map_to_use.items()}
625-
626-
if len(sequence_to_use) < n_elements_to_use:
627-
class O: length = 0
628-
candidate_sub_perm_space = O()
596+
sequence = [item for item in self.sequence
597+
if item not in shit_set]
598+
if any(value in shit_set for value
599+
in wip_perm_sequence_dict.values()):
600+
candidate_sub_perm_space_length = 0
629601
else:
630-
candidate_sub_perm_space = PermSpace(
631-
sequence_to_use,
632-
n_elements=n_elements_to_use,
633-
fixed_map=fixed_map_to_use,
602+
candidate_sub_perm_space_length = \
603+
PermSpace._create_with_cut_prefix(
604+
sequence,
605+
n_elements=self.n_elements,
606+
fixed_map=wip_perm_sequence_dict,
634607
is_combination=self.is_combination
635-
)
636-
# #
637-
###########################################################
608+
).length
638609

639-
if wip_i < candidate_sub_perm_space.length:
610+
if wip_i < candidate_sub_perm_space_length:
640611
available_values.remove(unused_value)
641612
break
642613
else:
643-
wip_i -= candidate_sub_perm_space.length
614+
wip_i -= candidate_sub_perm_space_length
644615
if self.is_combination:
645616
shit_set.add(wip_perm_sequence_dict[j])
646617
del wip_perm_sequence_dict[j]
@@ -944,6 +915,59 @@ def _coerce_perm(self, perm):
944915
'''Coerce `perm` to be a permutation of this space.'''
945916
return Perm(perm, self)
946917

918+
prefix = None
919+
920+
@classmethod
921+
def _create_with_cut_prefix(cls, sequence, domain=None, *,
922+
n_elements=None, fixed_map=None, degrees=None, is_combination=False,
923+
slice_=None):
924+
925+
# Tricky thing here: Trying to put as much as we can in a
926+
# sequence head that'll shorten the sequence we'll give to
927+
# the candidate space instead of using a fixed map, if
928+
# possible. This is crucial for `CombSpace` which can't use
929+
# `fixed_map`.
930+
931+
if degrees is not None:
932+
raise NotImplementedError
933+
934+
935+
prefix = []
936+
fixed_map = dict(fixed_map)
937+
for i in sequence_tools.CuteRange(infinity):
938+
try:
939+
prefix.append(fixed_map[i])
940+
except KeyError:
941+
break
942+
else:
943+
del fixed_map[i]
944+
n_elements -= 1
945+
946+
947+
sequence = list(sequence)
948+
for item in prefix:
949+
if is_combination:
950+
sequence = sequence[sequence.index(item) + 1:]
951+
else:
952+
sequence[sequence.index(item)] = misc.MISSING_ELEMENT
953+
# More efficient than removing the element, we filter these out
954+
# later.
955+
if not is_combination:
956+
sequence = [item for item in sequence
957+
if (item is not misc.MISSING_ELEMENT)]
958+
959+
fixed_map = {key - len(prefix): value
960+
for key, value in fixed_map.items()}
961+
962+
perm_space = cls(
963+
sequence, n_elements=n_elements, fixed_map=fixed_map,
964+
is_combination=is_combination, slice_=slice_,
965+
)
966+
perm_space.prefix = tuple(prefix)
967+
return perm_space
968+
969+
970+
947971

948972

949973

source_py3/test_python_toolbox/test_combi/test_perm_space.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,17 @@ def test_degreed_perm_space():
397397

398398

399399
def test_partial_perm_space():
400-
with cute_testing.RaiseAssertor():
401-
PermSpace(5, n_elements=6)
400+
empty_partial_perm_space = PermSpace(5, n_elements=6)
401+
assert empty_partial_perm_space.length == 0
402+
assert empty_partial_perm_space.variation_selection == \
403+
variations.VariationSelection({variations.Variation.PARTIAL})
404+
assert empty_partial_perm_space != PermSpace(5, n_elements=7)
405+
with cute_testing.RaiseAssertor(IndexError):
406+
empty_partial_perm_space[0]
407+
assert range(4) not in empty_partial_perm_space
408+
assert range(5) not in empty_partial_perm_space
409+
assert range(6) not in empty_partial_perm_space
410+
assert range(7) not in empty_partial_perm_space
402411

403412
perm_space_0 = PermSpace(5, n_elements=5)
404413
perm_space_1 = PermSpace(5, n_elements=3)
@@ -476,6 +485,8 @@ def test_partial_perm_space():
476485
[tuple(perm) for perm in perm_space_7]
477486
)
478487

488+
assert empty_partial_perm_space.length == 0
489+
479490

480491
def test_neighbors():
481492
perm = Perm('wome', 'meow')

0 commit comments

Comments
 (0)