def test_factoradics(): for i in range(100): assert from_factoradic(to_factoradic(i)) == i assert tuple(map(to_factoradic, range(10))) == ( (0,), (1, 0,), (1, 0, 0), (1, 1, 0), (2, 0, 0), (2, 1, 0), (1, 0, 0, 0), (1, 0, 1, 0), (1, 1, 0, 0), (1, 1, 1, 0) )
def __getitem__(self, i): if isinstance(i, (slice, sequence_tools.CanonicalSlice)): canonical_slice = sequence_tools.CanonicalSlice( i, self.length, offset=self.canonical_slice.start) return PermSpace(self.sequence, domain=self.domain, n_elements=self.n_elements, fixed_map=self.fixed_map, degrees=self.degrees, is_combination=self.is_combination, slice_=canonical_slice, perm_type=self.perm_type) assert isinstance(i, numbers.Integral) if i <= -1: i += self.length if not (0 <= i < self.length): raise IndexError elif self.is_sliced: return self.unsliced[i + self.canonical_slice.start] elif self.is_dapplied: return self.perm_type(self.undapplied[i], perm_space=self) ####################################################################### elif self.is_degreed: if self.is_rapplied: assert not self.is_recurrent and \ not self.is_partial and not self.is_combination and \ not self.is_dapplied and not self.is_sliced return self.perm_type(map(self.sequence.__getitem__, self.unrapplied[i]), perm_space=self) assert not self.is_rapplied and not self.is_recurrent and \ not self.is_partial and not self.is_combination and \ not self.is_dapplied and not self.is_sliced # If that wasn't an example of asserting one's dominance, I don't # know what is. available_values = list(self.free_values) wip_perm_sequence_dict = dict(self.fixed_map) wip_n_cycles_in_fixed_items = \ self._n_cycles_in_fixed_items_of_just_fixed wip_i = i for j in self.sequence: if j in wip_perm_sequence_dict: continue for unused_value in available_values: candidate_perm_sequence_dict = dict(wip_perm_sequence_dict) candidate_perm_sequence_dict[j] = unused_value ### Checking whether we closed a cycle: ################### # # if j == unused_value: closed_cycle = True else: current = j while True: current = candidate_perm_sequence_dict[current] if current == j: closed_cycle = True break elif current not in candidate_perm_sequence_dict: closed_cycle = False break # # ### Finished checking whether we closed a cycle. ########## candidate_n_cycles_in_fixed_items = \ wip_n_cycles_in_fixed_items + closed_cycle candidate_fixed_perm_space_length = sum( math_tools.abs_stirling( self.sequence_length - len(candidate_perm_sequence_dict), self.sequence_length - degree - candidate_n_cycles_in_fixed_items) for degree in self.degrees) if wip_i < candidate_fixed_perm_space_length: available_values.remove(unused_value) wip_perm_sequence_dict[j] = unused_value wip_n_cycles_in_fixed_items = \ candidate_n_cycles_in_fixed_items break wip_i -= candidate_fixed_perm_space_length else: raise RuntimeError assert wip_i == 0 return self.perm_type( (wip_perm_sequence_dict[k] for k in self.domain), self) ####################################################################### elif self.is_recurrent: assert not self.is_dapplied and not self.is_degreed and \ not self.is_sliced available_values = list(self.sequence) reserved_values = nifty_collections.Bag(self.fixed_map.values()) wip_perm_sequence_dict = dict(self.fixed_map) wip_i = i shit_set = set() for j in range(self.n_elements): if j in self.fixed_map: available_values.remove(self.fixed_map[j]) reserved_values[self.fixed_map[j]] -= 1 continue unused_values = [ item for item in nifty_collections.OrderedBag(available_values) - reserved_values if item not in shit_set ] for unused_value in unused_values: wip_perm_sequence_dict[j] = unused_value candidate_sub_perm_space = \ PermSpace._create_with_cut_prefix( self.sequence, n_elements=self.n_elements, fixed_map=wip_perm_sequence_dict, is_combination=self.is_combination, shit_set=shit_set, perm_type=self.perm_type ) if wip_i < candidate_sub_perm_space.length: available_values.remove(unused_value) break else: wip_i -= candidate_sub_perm_space.length if self.is_combination: shit_set.add(wip_perm_sequence_dict[j]) del wip_perm_sequence_dict[j] else: raise RuntimeError assert wip_i == 0 return self.perm_type( dict_tools.get_tuple(wip_perm_sequence_dict, self.domain), self) ####################################################################### elif self.is_fixed: free_values_perm = self._free_values_unsliced_perm_space[i] free_values_perm_iterator = iter(free_values_perm) return self.perm_type( tuple((self._undapplied_fixed_map[m] if ( m in self.fixed_indices ) else next(free_values_perm_iterator)) for m in self.indices), self) ####################################################################### elif self.is_combination: wip_number = self.length - 1 - i wip_perm_sequence = [] for i in range(self.n_elements, 0, -1): for j in range(self.sequence_length, i - 2, -1): candidate = math_tools.binomial(j, i) if candidate <= wip_number: wip_perm_sequence.append(self.sequence[-(j + 1)]) wip_number -= candidate break else: raise RuntimeError result = tuple(wip_perm_sequence) assert len(result) == self.n_elements return self.perm_type(result, self) ####################################################################### else: factoradic_number = math_tools.to_factoradic( i * math.factorial(self.n_unused_elements), n_digits_pad=self.sequence_length) if self.is_partial: factoradic_number = factoradic_number[:-self.n_unused_elements] unused_numbers = list(self.sequence) result = tuple( unused_numbers.pop(factoradic_digit) for factoradic_digit in factoradic_number) assert sequence_tools.get_length(result) == self.n_elements return self.perm_type(result, self)
def __getitem__(self, i): if isinstance(i, (slice, sequence_tools.CanonicalSlice)): canonical_slice = sequence_tools.CanonicalSlice( i, self.length, offset=self.canonical_slice.start ) return PermSpace( self.sequence, domain=self.domain, n_elements=self.n_elements, fixed_map=self.fixed_map, degrees=self.degrees, is_combination=self.is_combination, slice_=canonical_slice, perm_type=self.perm_type ) assert isinstance(i, numbers.Integral) if i <= -1: i += self.length if not (0 <= i < self.length): raise IndexError elif self.is_sliced: return self.unsliced[i + self.canonical_slice.start] elif self.is_dapplied: return self.perm_type(self.undapplied[i], perm_space=self) ####################################################################### elif self.is_degreed: if self.is_rapplied: assert not self.is_recurrent and \ not self.is_partial and not self.is_combination and \ not self.is_dapplied and not self.is_sliced return self.perm_type(map(self.sequence.__getitem__, self.unrapplied[i]), perm_space=self) assert not self.is_rapplied and not self.is_recurrent and \ not self.is_partial and not self.is_combination and \ not self.is_dapplied and not self.is_sliced # If that wasn't an example of asserting one's dominance, I don't # know what is. available_values = list(self.free_values) wip_perm_sequence_dict = dict(self.fixed_map) wip_n_cycles_in_fixed_items = \ self._n_cycles_in_fixed_items_of_just_fixed wip_i = i for j in self.sequence: if j in wip_perm_sequence_dict: continue for unused_value in available_values: candidate_perm_sequence_dict = dict(wip_perm_sequence_dict) candidate_perm_sequence_dict[j] = unused_value ### Checking whether we closed a cycle: ################### # # if j == unused_value: closed_cycle = True else: current = j while True: current = candidate_perm_sequence_dict[current] if current == j: closed_cycle = True break elif current not in candidate_perm_sequence_dict: closed_cycle = False break # # ### Finished checking whether we closed a cycle. ########## candidate_n_cycles_in_fixed_items = \ wip_n_cycles_in_fixed_items + closed_cycle candidate_fixed_perm_space_length = sum( math_tools.abs_stirling( self.sequence_length - len(candidate_perm_sequence_dict), self.sequence_length - degree - candidate_n_cycles_in_fixed_items ) for degree in self.degrees ) if wip_i < candidate_fixed_perm_space_length: available_values.remove(unused_value) wip_perm_sequence_dict[j] = unused_value wip_n_cycles_in_fixed_items = \ candidate_n_cycles_in_fixed_items break wip_i -= candidate_fixed_perm_space_length else: raise RuntimeError assert wip_i == 0 return self.perm_type((wip_perm_sequence_dict[k] for k in self.domain), self) ####################################################################### elif self.is_recurrent: assert not self.is_dapplied and not self.is_degreed and \ not self.is_sliced available_values = list(self.sequence) reserved_values = nifty_collections.Bag(self.fixed_map.values()) wip_perm_sequence_dict = dict(self.fixed_map) wip_i = i shit_set = set() for j in range(self.n_elements): if j in self.fixed_map: available_values.remove(self.fixed_map[j]) reserved_values[self.fixed_map[j]] -= 1 continue unused_values = [ item for item in nifty_collections.OrderedBag(available_values) - reserved_values if item not in shit_set ] for unused_value in unused_values: wip_perm_sequence_dict[j] = unused_value candidate_sub_perm_space = \ PermSpace._create_with_cut_prefix( self.sequence, n_elements=self.n_elements, fixed_map=wip_perm_sequence_dict, is_combination=self.is_combination, shit_set=shit_set, perm_type=self.perm_type ) if wip_i < candidate_sub_perm_space.length: available_values.remove(unused_value) break else: wip_i -= candidate_sub_perm_space.length if self.is_combination: shit_set.add(wip_perm_sequence_dict[j]) del wip_perm_sequence_dict[j] else: raise RuntimeError assert wip_i == 0 return self.perm_type( dict_tools.get_tuple(wip_perm_sequence_dict, self.domain), self ) ####################################################################### elif self.is_fixed: free_values_perm = self._free_values_unsliced_perm_space[i] free_values_perm_iterator = iter(free_values_perm) return self.perm_type( tuple( (self._undapplied_fixed_map[m] if (m in self.fixed_indices) else next(free_values_perm_iterator)) for m in range(self.sequence_length) ), self ) ####################################################################### elif self.is_combination: wip_number = self.length - 1 - i wip_perm_sequence = [] for i in range(self.n_elements, 0, -1): for j in range(self.sequence_length, i - 2, -1): candidate = math_tools.binomial(j, i) if candidate <= wip_number: wip_perm_sequence.append( self.sequence[-(j+1)] ) wip_number -= candidate break else: raise RuntimeError result = tuple(wip_perm_sequence) assert len(result) == self.n_elements return self.perm_type(result, self) ####################################################################### else: factoradic_number = math_tools.to_factoradic( i * math.factorial( self.n_unused_elements), n_digits_pad=self.sequence_length ) if self.is_partial: factoradic_number = factoradic_number[:-self.n_unused_elements] unused_numbers = list(self.sequence) result = tuple(unused_numbers.pop(factoradic_digit) for factoradic_digit in factoradic_number) assert sequence_tools.get_length(result) == self.n_elements return self.perm_type(result, self)