def test(): r = (1, 2, 3, 7, 10) assert is_sorted(r) is True assert is_sorted(r, rising=False) is False assert is_sorted(r[::-1], rising=False) is True assert is_sorted(r, strict=True) is True assert is_sorted(r, rising=False, strict=True) is False assert is_sorted(r, key=lambda x: x % 3) is False assert is_sorted(r, rising=False, key=lambda x: x % 3) is False assert is_sorted(r, key=lambda x: -x) is False assert is_sorted(r, rising=False, key=lambda x: -x) is True assert is_sorted(r, rising=False, strict=True, key=lambda x: -x) is True
def __init__(self, variations): self.variations = variations assert cute_iter_tools.is_sorted(self.variations) self.is_rapplied = Variation.RAPPLIED in self.variations self.is_recurrent = Variation.RECURRENT in self.variations self.is_partial = Variation.PARTIAL in self.variations self.is_combination = Variation.COMBINATION in self.variations self.is_dapplied = Variation.DAPPLIED in self.variations self.is_fixed = Variation.FIXED in self.variations self.is_degreed = Variation.DEGREED in self.variations self.is_sliced = Variation.SLICED in self.variations self.is_typed = Variation.TYPED in self.variations self.is_pure = not self.variations
def test(): assert len(combi.perming.variations.variation_selection_space) == \ 2 ** len(combi.perming.variations.Variation) for i, variation_selection in \ enumerate(combi.perming.variations.variation_selection_space): assert isinstance(variation_selection, combi.perming.variations.VariationSelection) assert combi.perming.variations.variation_selection_space. \ index(variation_selection) == i assert cute_iter_tools.is_sorted(variation_selection.variations) assert isinstance(variation_selection.is_allowed, bool)
def test_get_contained_bags(self): bag = self.bag_type("abracadabra") contained_bags = bag.get_contained_bags() assert len(contained_bags) == 6 * 3 * 2 * 2 * 3 had_full_one = False for contained_bag in contained_bags: assert contained_bag <= bag if contained_bag == bag: assert had_full_one is False had_full_one = True else: assert contained_bag < bag if isinstance(bag, nifty_collections.Ordered): assert cute_iter_tools.is_sorted(tuple(contained_bag.keys()), key=tuple(bag.keys()).index) contained_bags_tuple = tuple(contained_bags) assert self.bag_type("abraca") in contained_bags_tuple assert self.bag_type("bd") in contained_bags_tuple assert self.bag_type() in contained_bags_tuple assert self.bag_type("x") not in contained_bags_tuple
def test_get_contained_bags(self): bag = self.bag_type('abracadabra') contained_bags = bag.get_contained_bags() assert len(contained_bags) == 6 * 3 * 2 * 2 * 3 had_full_one = False for contained_bag in contained_bags: assert contained_bag <= bag if contained_bag == bag: assert had_full_one is False had_full_one = True else: assert contained_bag < bag if isinstance(bag, nifty_collections.Ordered): assert cute_iter_tools.is_sorted(tuple(contained_bag.keys()), key=tuple(bag.keys()).index) contained_bags_tuple = tuple(contained_bags) assert self.bag_type('abraca') in contained_bags_tuple assert self.bag_type('bd') in contained_bags_tuple assert self.bag_type() in contained_bags_tuple assert self.bag_type('x') not in contained_bags_tuple
def index(self, perm): '''Get the index number of permutation `perm` in this space.''' if not isinstance(perm, collections.abc.Iterable): raise ValueError perm = sequence_tools.ensure_iterable_is_immutable_sequence(perm) perm_set = set(perm) if not isinstance(perm, UnrecurrentedPerm) \ else set(perm._perm_sequence) if not (perm_set <= set(self.sequence)): raise ValueError if sequence_tools.get_length(perm) != self.n_elements: raise ValueError if not isinstance(perm, self.perm_type): perm = self.perm_type(perm, self) if self.sequence != perm.nominal_perm_space.sequence: # (This also covers `self.rapplied != perm.rapplied`) raise ValueError if self.domain != perm.domain: # (This also covers `self.dapplied != perm.dapplied`) raise ValueError if self.is_degreed and (perm.degree not in self.degrees): raise ValueError # At this point we know the permutation contains the correct items, and # has the correct degree. if perm.is_dapplied: return self.undapplied.index(perm.undapplied) ####################################################################### elif self.is_degreed: if perm.is_rapplied: return self.unrapplied.index(perm.unrapplied) wip_perm_number = 0 wip_perm_sequence_dict = dict(self.fixed_map) unused_values = list(self.free_values) for i, value in enumerate(perm._perm_sequence): if i in self.fixed_indices: continue unused_values.remove(value) lower_values = [j for j in unused_values if j < value] for lower_value in lower_values: temp_fixed_map = dict(wip_perm_sequence_dict) temp_fixed_map[i] = lower_value wip_perm_number += PermSpace( self.sequence_length, degrees=self.degrees, fixed_map=temp_fixed_map).length wip_perm_sequence_dict[self.domain[i]] = value perm_number = wip_perm_number ####################################################################### elif self.is_recurrent: assert not self.is_degreed and not self.is_dapplied wip_perm_number = 0 unused_values = list(self.sequence) reserved_values = list(self.fixed_map.values()) perm_sequence_list = list(perm._perm_sequence) shit_set = set() for i, value in enumerate(perm._perm_sequence): if i in self.fixed_map: if self.fixed_map[i] == value: unused_values.remove(value) reserved_values.remove(value) continue else: raise ValueError lower_values = [ thing for thing in nifty_collections.OrderedSet(unused_values) if (thing not in reserved_values or unused_values.count( thing) > reserved_values.count(thing)) and unused_values.index(thing) < unused_values.index(value) and thing not in shit_set ] unused_values.remove(value) for lower_value in lower_values: temp_fixed_map = dict( enumerate(perm_sequence_list[:i] + [lower_value])) temp_fixed_map.update(self.fixed_map) candidate_sub_perm_space = \ PermSpace._create_with_cut_prefix( self.sequence, n_elements=self.n_elements, fixed_map=temp_fixed_map, is_combination=self.is_combination, shit_set=shit_set, perm_type=self.perm_type ) wip_perm_number += candidate_sub_perm_space.length if self.is_combination: shit_set.add(lower_value) perm_number = wip_perm_number ####################################################################### elif self.is_fixed: assert not self.is_degreed and not self.is_recurrent free_values_perm_sequence = [] for i, perm_item in zip(self.domain, perm._perm_sequence): if i in self.fixed_map: if self.fixed_map[i] != perm_item: raise ValueError else: free_values_perm_sequence.append(perm_item) # At this point we know all the items that should be fixed are # fixed. perm_number = self._free_values_unsliced_perm_space.index( free_values_perm_sequence) ####################################################################### elif self.is_combination: if perm.is_rapplied: return self.unrapplied.index(perm.unrapplied) assert not self.is_rapplied and not self.is_recurrent and \ not self.is_dapplied and not self.is_fixed and \ not self.is_degreed if not cute_iter_tools.is_sorted(perm._perm_sequence): raise ValueError processed_perm_sequence = tuple( self.sequence_length - 1 - item for item in perm._perm_sequence[::-1]) perm_number = self.unsliced.length - 1 - sum( (math_tools.binomial(item, i) for i, item in enumerate(processed_perm_sequence, start=1)), 0) ####################################################################### else: factoradic_number = [] unused_values = list(self.sequence) for i, value in enumerate(perm._perm_sequence): index_of_current_number = unused_values.index(value) factoradic_number.append(index_of_current_number) unused_values.remove(value) perm_number = math_tools.from_factoradic( factoradic_number + [0] * self.n_unused_elements) // math.factorial( self.n_unused_elements) ####################################################################### if perm_number not in self.canonical_slice: raise ValueError return perm_number - self.canonical_slice.start
def test_perm_type(): class Suit(nifty_collections.CuteEnum): club = 'club' diamond = 'diamond' heart = 'heart' spade = 'spade' __order__ = 'club diamond heart spade' @functools.total_ordering class Card(): def __init__(self, number_and_suit): number, suit = number_and_suit assert number in range(1, 14) assert isinstance(suit, Suit) self.number = number self.suit = suit _sequence = \ caching.CachedProperty(lambda self: (self.number, self.suit)) _reduced = \ caching.CachedProperty(lambda self: (type(self), self._sequence)) def __lt__(self, other): if not isinstance(other, Card): return NotImplemented return self._sequence < other._sequence def __eq__(self, other): return type(self) == type(other) and \ self._sequence == other._sequence __hash__ = lambda self: hash(self._reduced) __repr__ = lambda self: '%s%s' % ( self.number if self.number <= 10 else 'jqk'[self.number - 11], str(self.suit.name)[0].capitalize() ) card_space = combi.MapSpace(Card, combi.ProductSpace((range(1, 14), Suit))) class PokerHandSpace(combi.CombSpace): def __init__(self): super(PokerHandSpace, self).__init__(card_space, 5, perm_type=PokerHand) class PokerHand(combi.Comb): @caching.CachedProperty def stupid_score(self): return tuple( zip(*nifty_collections.Bag(card.number for card in self) .most_common()))[1] poker_hand_space = PokerHandSpace() assert isinstance(poker_hand_space[0], PokerHand) some_poker_hands = MapSpace(poker_hand_space.__getitem__, range(1000000, 2000000, 17060)) some_poker_hand_scores = set(poker_hand.stupid_score for poker_hand in some_poker_hands) assert (1, 1, 1, 1, 1) in some_poker_hand_scores assert (2, 1, 1, 1) in some_poker_hand_scores assert (2, 2, 1) in some_poker_hand_scores assert (3, 1, 1) in some_poker_hand_scores card_comb_sequence = (Card((1, Suit.club)), Card((2, Suit.diamond)), Card((3, Suit.heart)), Card((4, Suit.spade)), Card((5, Suit.club))) assert cute_iter_tools.is_sorted(card_comb_sequence) assert card_comb_sequence in poker_hand_space assert PokerHand(card_comb_sequence, poker_hand_space) in poker_hand_space assert card_comb_sequence[::-1] not in poker_hand_space assert PokerHand(card_comb_sequence[::-1], poker_hand_space) \ not in poker_hand_space assert PokerHand(card_comb_sequence, poker_hand_space).stupid_score == \ (1, 1, 1, 1, 1)
def test_partial_perm_space(): empty_partial_perm_space = PermSpace(5, n_elements=6) assert empty_partial_perm_space.length == 0 assert empty_partial_perm_space.variation_selection == \ perming.variations.VariationSelection( set((perming.variations.Variation.PARTIAL,))) assert empty_partial_perm_space != PermSpace(5, n_elements=7) with cute_testing.RaiseAssertor(IndexError): empty_partial_perm_space[0] assert range(4) not in empty_partial_perm_space assert range(5) not in empty_partial_perm_space assert range(6) not in empty_partial_perm_space assert range(7) not in empty_partial_perm_space perm_space_0 = PermSpace(5, n_elements=5) perm_space_1 = PermSpace(5, n_elements=3) perm_space_2 = PermSpace(5, n_elements=2) perm_space_3 = PermSpace(5, n_elements=1) perm_space_4 = PermSpace(5, n_elements=0) perm_space_5 = PermSpace(5, n_elements=5, is_combination=True) perm_space_6 = PermSpace(5, n_elements=3, is_combination=True) perm_space_7 = PermSpace(5, n_elements=2, is_combination=True) perm_space_8 = PermSpace(5, n_elements=1, is_combination=True) perm_space_9 = PermSpace(5, n_elements=0, is_combination=True) assert not perm_space_0.is_partial and not perm_space_0.is_combination assert perm_space_1.is_partial and not perm_space_1.is_combination assert perm_space_2.is_partial and not perm_space_2.is_combination assert perm_space_3.is_partial and not perm_space_3.is_combination assert perm_space_4.is_partial and not perm_space_4.is_combination assert set(map(type, (perm_space_0, perm_space_1, perm_space_2, perm_space_3, perm_space_4))) == set((PermSpace,)) assert not perm_space_5.is_partial and perm_space_5.is_combination assert perm_space_6.is_partial and perm_space_6.is_combination assert perm_space_7.is_partial and perm_space_7.is_combination assert perm_space_8.is_partial and perm_space_8.is_combination assert perm_space_9.is_partial and perm_space_9.is_combination assert set(map(type, (perm_space_5, perm_space_6, perm_space_7, perm_space_8, perm_space_9))) == set((CombSpace,)) assert CombSpace(5, n_elements=2) == perm_space_7 assert perm_space_0.length == math.factorial(5) assert perm_space_1.length == 5 * 4 * 3 assert perm_space_2.length == 5 * 4 assert perm_space_3.length == 5 assert perm_space_4.length == 1 assert perm_space_5.length == 1 assert perm_space_6.length == perm_space_7.length == 5 * 4 / 2 assert perm_space_8.length == 5 assert perm_space_9.length == 1 assert set(map(tuple, perm_space_1)) > set(map(tuple, perm_space_6)) for i, perm in enumerate(perm_space_2): assert len(perm) == 2 assert not perm.is_dapplied assert not perm.is_rapplied assert not isinstance(perm, Comb) assert perm_space_2.index(perm) == i reconstructed_perm = Perm(tuple(perm), perm_space=perm_space_2) assert perm == reconstructed_perm for i, perm in enumerate(perm_space_7): assert len(perm) == 2 assert not perm.is_dapplied assert not perm.is_rapplied assert isinstance(perm, Comb) assert perm_space_7.index(perm) == i assert perm[0] < perm[1] reconstructed_perm = Perm(tuple(perm), perm_space=perm_space_7) assert perm == reconstructed_perm assert cute_iter_tools.is_sorted( [perm_space_2.index(perm) for perm in perm_space_2] ) assert cute_iter_tools.is_sorted( [tuple(perm) for perm in perm_space_2] ) assert cute_iter_tools.is_sorted( [perm_space_7.index(perm) for perm in perm_space_7] ) assert cute_iter_tools.is_sorted( [tuple(perm) for perm in perm_space_7] ) assert empty_partial_perm_space.length == 0
def test_degreed_perm_space(): assert PermSpace(3, degrees=0).length == 1 assert PermSpace(3, degrees=1).length == 3 assert PermSpace(3, degrees=2).length == 2 for perm in PermSpace(3, degrees=1): assert perm.degree == 1 perm_space = PermSpace(5, degrees=(1, 3)) for perm in perm_space: assert perm.degree in (1, 3) assert cute_iter_tools.is_sorted( [perm_space.index(perm) for perm in perm_space] ) assert PermSpace( 7, domain='travels', fixed_map={'l': 5, 'a': 2, 't': 0, 'v': 3, 'r': 1, 'e': 6}, degrees=(1, 3, 5) ).length == 1 assert PermSpace(4, degrees=1, fixed_map={0: 0, 1: 1, 2: 2,}).length == 0 assert PermSpace(4, degrees=1, fixed_map={0: 0, 1: 1}).length == 1 assert PermSpace(4, degrees=1, fixed_map={0: 0, }).length == 3 assert PermSpace(4, degrees=1, fixed_map={0: 1, 1: 0,}).length == 1 assert PermSpace(4, degrees=1, fixed_map={0: 1, 1: 2,}).length == 0 assert PermSpace(4, degrees=2, fixed_map={0: 1, 1: 2,}).length == 1 assert PermSpace(4, degrees=3, fixed_map={0: 1, 1: 2,}).length == 1 assert PermSpace(4, degrees=3, fixed_map={2: 3,}).length == 2 assert PermSpace(4, degrees=1, fixed_map={2: 3,}).length == 1 funky_perm_space = PermSpace('isogram', domain='travels', degrees=(1, 3, 5, 9), fixed_map={'t': 'i', 'v': 'g',})[2:-2] assert funky_perm_space.purified == PermSpace(7) assert funky_perm_space.is_rapplied assert funky_perm_space.is_dapplied assert funky_perm_space.is_degreed assert funky_perm_space.is_fixed assert funky_perm_space.is_sliced assert not funky_perm_space.is_pure assert funky_perm_space.degrees == (1, 3, 5) assert funky_perm_space.sequence == 'isogram' assert funky_perm_space.domain == 'travels' assert funky_perm_space.canonical_slice.start == 2 assert funky_perm_space.unsliced.undegreed.get_degreed(2)[0] \ not in funky_perm_space assert funky_perm_space.unsliced.get_fixed({'t': 'i', 'v': 'g',}) \ [funky_perm_space.slice_] == funky_perm_space for i, perm in enumerate(funky_perm_space): assert perm.is_dapplied assert perm.is_rapplied assert perm['t'] == 'i' assert perm['v'] == 'g' assert perm['s'] in 'isogram' assert 1 not in perm assert perm.degree in (1, 3, 5, 9) assert funky_perm_space.index(perm) == i assert perm.undapplied[0] == 'i' assert perm.unrapplied['t'] == 0 assert perm.unrapplied.undapplied[0] == 0 assert perm.undapplied.is_rapplied assert perm.unrapplied.is_dapplied assert cute_iter_tools.is_sorted( [funky_perm_space.index(perm) for perm in funky_perm_space] ) other_perms_chain_space = ChainSpace((funky_perm_space.unsliced[:2], funky_perm_space.unsliced[-2:])) for perm in other_perms_chain_space: assert perm.is_dapplied assert perm.is_rapplied assert perm['t'] == 'i' assert perm['v'] == 'g' assert perm['s'] in 'isogram' assert 1 not in perm assert perm.degree in (1, 3, 5, 9) assert perm not in funky_perm_space assert perm.unrapplied['t'] == 0 assert perm.unrapplied.undapplied[0] == 0 assert perm.undapplied.is_rapplied assert perm.unrapplied.is_dapplied assert other_perms_chain_space.length + funky_perm_space.length == \ funky_perm_space.unsliced.length assert funky_perm_space.unsliced.length + \ funky_perm_space.unsliced.undegreed.get_degreed( i for i in range(funky_perm_space.sequence_length) if i not in funky_perm_space.degrees ).length == funky_perm_space.unsliced.undegreed.length assert funky_perm_space._just_fixed.is_fixed assert not funky_perm_space._just_fixed.is_rapplied assert not funky_perm_space._just_fixed.is_dapplied assert not funky_perm_space._just_fixed.is_sliced assert not funky_perm_space._just_fixed.is_degreed assert pickle.loads(pickle.dumps(funky_perm_space)) == funky_perm_space assert funky_perm_space != \ pickle.loads(pickle.dumps(funky_perm_space.unsliced.unfixed)) == \ funky_perm_space.unsliced.unfixed
def test_perm_type(): class Suit(nifty_collections.CuteEnum): club = 'club' diamond = 'diamond' heart = 'heart' spade = 'spade' @functools.total_ordering class Card(): def __init__(self, number_and_suit): number, suit = number_and_suit assert number in range(1, 14) assert isinstance(suit, Suit) self.number = number self.suit = suit _sequence = \ caching.CachedProperty(lambda self: (self.number, self.suit)) _reduced = \ caching.CachedProperty(lambda self: (type(self), self._sequence)) def __lt__(self, other): if not isinstance(other, Card): return NotImplemented return self._sequence < other._sequence def __eq__(self, other): return type(self) == type(other) and \ self._sequence == other._sequence __hash__ = lambda self: hash(self._reduced) __repr__ = lambda self: '%s%s' % (self.number if self.number <= 10 else 'jqk'[self.number - 11], str(self.suit.name)[0].capitalize()) card_space = combi.MapSpace(Card, combi.ProductSpace((range(1, 14), Suit))) class PokerHandSpace(combi.CombSpace): def __init__(self): super().__init__(card_space, 5, perm_type=PokerHand) class PokerHand(combi.Comb): @caching.CachedProperty def stupid_score(self): return tuple( zip(*nifty_collections.Bag(card.number for card in self).most_common()))[1] poker_hand_space = PokerHandSpace() assert isinstance(poker_hand_space[0], PokerHand) some_poker_hands = MapSpace(poker_hand_space.__getitem__, range(1000000, 2000000, 17060)) some_poker_hand_scores = set(poker_hand.stupid_score for poker_hand in some_poker_hands) assert (1, 1, 1, 1, 1) in some_poker_hand_scores assert (2, 1, 1, 1) in some_poker_hand_scores assert (2, 2, 1) in some_poker_hand_scores assert (3, 1, 1) in some_poker_hand_scores card_comb_sequence = (Card((1, Suit.club)), Card( (2, Suit.diamond)), Card((3, Suit.heart)), Card( (4, Suit.spade)), Card((5, Suit.club))) assert cute_iter_tools.is_sorted(card_comb_sequence) assert card_comb_sequence in poker_hand_space assert PokerHand(card_comb_sequence, poker_hand_space) in poker_hand_space assert card_comb_sequence[::-1] not in poker_hand_space assert PokerHand(card_comb_sequence[::-1], poker_hand_space) \ not in poker_hand_space assert PokerHand(card_comb_sequence, poker_hand_space).stupid_score == \ (1, 1, 1, 1, 1)
def test_partial_perm_space(): empty_partial_perm_space = PermSpace(5, n_elements=6) assert empty_partial_perm_space.length == 0 assert empty_partial_perm_space.variation_selection == \ perming.variations.VariationSelection( {perming.variations.Variation.PARTIAL}) assert empty_partial_perm_space != PermSpace(5, n_elements=7) with cute_testing.RaiseAssertor(IndexError): empty_partial_perm_space[0] assert range(4) not in empty_partial_perm_space assert range(5) not in empty_partial_perm_space assert range(6) not in empty_partial_perm_space assert range(7) not in empty_partial_perm_space perm_space_0 = PermSpace(5, n_elements=5) perm_space_1 = PermSpace(5, n_elements=3) perm_space_2 = PermSpace(5, n_elements=2) perm_space_3 = PermSpace(5, n_elements=1) perm_space_4 = PermSpace(5, n_elements=0) perm_space_5 = PermSpace(5, n_elements=5, is_combination=True) perm_space_6 = PermSpace(5, n_elements=3, is_combination=True) perm_space_7 = PermSpace(5, n_elements=2, is_combination=True) perm_space_8 = PermSpace(5, n_elements=1, is_combination=True) perm_space_9 = PermSpace(5, n_elements=0, is_combination=True) assert not perm_space_0.is_partial and not perm_space_0.is_combination assert perm_space_1.is_partial and not perm_space_1.is_combination assert perm_space_2.is_partial and not perm_space_2.is_combination assert perm_space_3.is_partial and not perm_space_3.is_combination assert perm_space_4.is_partial and not perm_space_4.is_combination assert set( map(type, (perm_space_0, perm_space_1, perm_space_2, perm_space_3, perm_space_4))) == {PermSpace} assert not perm_space_5.is_partial and perm_space_5.is_combination assert perm_space_6.is_partial and perm_space_6.is_combination assert perm_space_7.is_partial and perm_space_7.is_combination assert perm_space_8.is_partial and perm_space_8.is_combination assert perm_space_9.is_partial and perm_space_9.is_combination assert set( map(type, (perm_space_5, perm_space_6, perm_space_7, perm_space_8, perm_space_9))) == {CombSpace} assert CombSpace(5, n_elements=2) == perm_space_7 assert perm_space_0.length == math.factorial(5) assert perm_space_1.length == 5 * 4 * 3 assert perm_space_2.length == 5 * 4 assert perm_space_3.length == 5 assert perm_space_4.length == 1 assert perm_space_5.length == 1 assert perm_space_6.length == perm_space_7.length == 5 * 4 / 2 assert perm_space_8.length == 5 assert perm_space_9.length == 1 assert set(map(tuple, perm_space_1)) > set(map(tuple, perm_space_6)) for i, perm in enumerate(perm_space_2): assert len(perm) == 2 assert not perm.is_dapplied assert not perm.is_rapplied assert not isinstance(perm, Comb) assert perm_space_2.index(perm) == i reconstructed_perm = Perm(tuple(perm), perm_space=perm_space_2) assert perm == reconstructed_perm for i, perm in enumerate(perm_space_7): assert len(perm) == 2 assert not perm.is_dapplied assert not perm.is_rapplied assert isinstance(perm, Comb) assert perm_space_7.index(perm) == i assert perm[0] < perm[1] reconstructed_perm = Perm(tuple(perm), perm_space=perm_space_7) assert perm == reconstructed_perm assert cute_iter_tools.is_sorted( [perm_space_2.index(perm) for perm in perm_space_2]) assert cute_iter_tools.is_sorted([tuple(perm) for perm in perm_space_2]) assert cute_iter_tools.is_sorted( [perm_space_7.index(perm) for perm in perm_space_7]) assert cute_iter_tools.is_sorted([tuple(perm) for perm in perm_space_7]) assert empty_partial_perm_space.length == 0
def test_degreed_perm_space(): assert PermSpace(3, degrees=0).length == 1 assert PermSpace(3, degrees=1).length == 3 assert PermSpace(3, degrees=2).length == 2 for perm in PermSpace(3, degrees=1): assert perm.degree == 1 perm_space = PermSpace(5, degrees=(1, 3)) for perm in perm_space: assert perm.degree in (1, 3) assert cute_iter_tools.is_sorted( [perm_space.index(perm) for perm in perm_space]) assert PermSpace(7, domain='travels', fixed_map={ 'l': 5, 'a': 2, 't': 0, 'v': 3, 'r': 1, 'e': 6 }, degrees=(1, 3, 5)).length == 1 assert PermSpace(4, degrees=1, fixed_map={ 0: 0, 1: 1, 2: 2, }).length == 0 assert PermSpace(4, degrees=1, fixed_map={0: 0, 1: 1}).length == 1 assert PermSpace(4, degrees=1, fixed_map={ 0: 0, }).length == 3 assert PermSpace(4, degrees=1, fixed_map={ 0: 1, 1: 0, }).length == 1 assert PermSpace(4, degrees=1, fixed_map={ 0: 1, 1: 2, }).length == 0 assert PermSpace(4, degrees=2, fixed_map={ 0: 1, 1: 2, }).length == 1 assert PermSpace(4, degrees=3, fixed_map={ 0: 1, 1: 2, }).length == 1 assert PermSpace(4, degrees=3, fixed_map={ 2: 3, }).length == 2 assert PermSpace(4, degrees=1, fixed_map={ 2: 3, }).length == 1 funky_perm_space = PermSpace('isogram', domain='travels', degrees=(1, 3, 5, 9), fixed_map={ 't': 'i', 'v': 'g', })[2:-2] assert funky_perm_space.purified == PermSpace(7) assert funky_perm_space.is_rapplied assert funky_perm_space.is_dapplied assert funky_perm_space.is_degreed assert funky_perm_space.is_fixed assert funky_perm_space.is_sliced assert not funky_perm_space.is_pure assert funky_perm_space.degrees == (1, 3, 5) assert funky_perm_space.sequence == 'isogram' assert funky_perm_space.domain == 'travels' assert funky_perm_space.canonical_slice.start == 2 assert funky_perm_space.unsliced.undegreed.get_degreed(2)[0] \ not in funky_perm_space assert funky_perm_space.unsliced.get_fixed({'t': 'i', 'v': 'g',}) \ [funky_perm_space.slice_] == funky_perm_space for i, perm in enumerate(funky_perm_space): assert perm.is_dapplied assert perm.is_rapplied assert perm['t'] == 'i' assert perm['v'] == 'g' assert perm['s'] in 'isogram' assert 1 not in perm assert perm.degree in (1, 3, 5, 9) assert funky_perm_space.index(perm) == i assert perm.undapplied[0] == 'i' assert perm.unrapplied['t'] == 0 assert perm.unrapplied.undapplied[0] == 0 assert perm.undapplied.is_rapplied assert perm.unrapplied.is_dapplied assert cute_iter_tools.is_sorted( [funky_perm_space.index(perm) for perm in funky_perm_space]) other_perms_chain_space = ChainSpace( (funky_perm_space.unsliced[:2], funky_perm_space.unsliced[-2:])) for perm in other_perms_chain_space: assert perm.is_dapplied assert perm.is_rapplied assert perm['t'] == 'i' assert perm['v'] == 'g' assert perm['s'] in 'isogram' assert 1 not in perm assert perm.degree in (1, 3, 5, 9) assert perm not in funky_perm_space assert perm.unrapplied['t'] == 0 assert perm.unrapplied.undapplied[0] == 0 assert perm.undapplied.is_rapplied assert perm.unrapplied.is_dapplied assert other_perms_chain_space.length + funky_perm_space.length == \ funky_perm_space.unsliced.length assert funky_perm_space.unsliced.length + \ funky_perm_space.unsliced.undegreed.get_degreed( i for i in range(funky_perm_space.sequence_length) if i not in funky_perm_space.degrees ).length == funky_perm_space.unsliced.undegreed.length assert funky_perm_space._just_fixed.is_fixed assert not funky_perm_space._just_fixed.is_rapplied assert not funky_perm_space._just_fixed.is_dapplied assert not funky_perm_space._just_fixed.is_sliced assert not funky_perm_space._just_fixed.is_degreed assert pickle.loads(pickle.dumps(funky_perm_space)) == funky_perm_space assert funky_perm_space != \ pickle.loads(pickle.dumps(funky_perm_space.unsliced.unfixed)) == \ funky_perm_space.unsliced.unfixed
def index(self, perm): '''Get the index number of permutation `perm` in this space.''' if not isinstance(perm, collections.Iterable): raise ValueError try: perm = sequence_tools.ensure_iterable_is_immutable_sequence( perm, allow_unordered=False ) except sequence_tools.UnorderedIterableException: raise ValueError('An unordered iterable is never contained in a ' '`PermSpace`. Try an ordered one.') perm_set = set(perm) if not isinstance(perm, UnrecurrentedPerm) \ else set(perm._perm_sequence) if not (perm_set <= set(self.sequence)): raise ValueError if sequence_tools.get_length(perm) != self.n_elements: raise ValueError if not isinstance(perm, self.perm_type): perm = self.perm_type(perm, self) if self.sequence != perm.nominal_perm_space.sequence: # (This also covers `self.rapplied != perm.rapplied`) raise ValueError if self.domain != perm.domain: # (This also covers `self.dapplied != perm.dapplied`) raise ValueError if self.is_degreed and (perm.degree not in self.degrees): raise ValueError # At this point we know the permutation contains the correct items, and # has the correct degree. if perm.is_dapplied: return self.undapplied.index(perm.undapplied) ####################################################################### elif self.is_degreed: if perm.is_rapplied: return self.unrapplied.index(perm.unrapplied) wip_perm_number = 0 wip_perm_sequence_dict = dict(self.fixed_map) unused_values = list(self.free_values) for i, value in enumerate(perm._perm_sequence): if i in self.fixed_indices: continue unused_values.remove(value) lower_values = [j for j in unused_values if j < value] for lower_value in lower_values: temp_fixed_map = dict(wip_perm_sequence_dict) temp_fixed_map[i] = lower_value wip_perm_number += PermSpace( self.sequence_length, degrees=self.degrees, fixed_map=temp_fixed_map ).length wip_perm_sequence_dict[self.domain[i]] = value perm_number = wip_perm_number ####################################################################### elif self.is_recurrent: assert not self.is_degreed and not self.is_dapplied wip_perm_number = 0 unused_values = list(self.sequence) reserved_values = list(self.fixed_map.values()) perm_sequence_list = list(perm._perm_sequence) shit_set = set() for i, value in enumerate(perm._perm_sequence): if i in self.fixed_map: if self.fixed_map[i] == value: unused_values.remove(value) reserved_values.remove(value) continue else: raise ValueError lower_values = [ thing for thing in nifty_collections.OrderedSet(unused_values) if (thing not in reserved_values or unused_values.count(thing) > reserved_values.count(thing)) and unused_values.index(thing) < unused_values.index(value) and thing not in shit_set ] unused_values.remove(value) for lower_value in lower_values: temp_fixed_map = dict( enumerate(perm_sequence_list[:i] + [lower_value]) ) temp_fixed_map.update(self.fixed_map) candidate_sub_perm_space = \ PermSpace._create_with_cut_prefix( self.sequence, n_elements=self.n_elements, fixed_map=temp_fixed_map, is_combination=self.is_combination, shit_set=shit_set, perm_type=self.perm_type ) wip_perm_number += candidate_sub_perm_space.length if self.is_combination: shit_set.add(lower_value) perm_number = wip_perm_number ####################################################################### elif self.is_fixed: assert not self.is_degreed and not self.is_recurrent free_values_perm_sequence = [] for i, perm_item in zip(self.domain, perm._perm_sequence): if i in self.fixed_map: if self.fixed_map[i] != perm_item: raise ValueError else: free_values_perm_sequence.append(perm_item) # At this point we know all the items that should be fixed are # fixed. perm_number = self._free_values_unsliced_perm_space.index( free_values_perm_sequence ) ####################################################################### elif self.is_combination: if perm.is_rapplied: return self.unrapplied.index(perm.unrapplied) assert not self.is_rapplied and not self.is_recurrent and \ not self.is_dapplied and not self.is_fixed and \ not self.is_degreed if not cute_iter_tools.is_sorted(perm._perm_sequence): raise ValueError processed_perm_sequence = tuple( self.sequence_length - 1 - item for item in perm._perm_sequence[::-1] ) perm_number = self.unsliced.length - 1 - sum( (math_tools.binomial(item, i) for i, item in enumerate(processed_perm_sequence, start=1)), 0 ) ####################################################################### else: factoradic_number = [] unused_values = list(self.sequence) for i, value in enumerate(perm._perm_sequence): index_of_current_number = unused_values.index(value) factoradic_number.append(index_of_current_number) unused_values.remove(value) perm_number = math_tools.from_factoradic( factoradic_number + [0] * self.n_unused_elements ) // math.factorial(self.n_unused_elements) ####################################################################### if perm_number not in self.canonical_slice: raise ValueError return perm_number - self.canonical_slice.start