def are_equal_regardless_of_order(seq1, seq2): ''' Do `seq1` and `seq2` contain the same elements, same number of times? Disregards order of elements. Currently will fail for items that have problems with comparing. ''' from python_toolbox import nifty_collections return nifty_collections.Bag(seq1) == nifty_collections.Bag(seq2)
def get_recurrences(sequence): ''' Get a `dict` of all items that repeat at least twice. The values of the dict are the numbers of repititions of each item. ''' from python_toolbox import nifty_collections return {item: n_recurrences for item, n_recurrences in nifty_collections.Bag(sequence).most_common() if n_recurrences >= 2}
def _unsliced_length(self): ''' The number of perms in the space, ignoring any slicing. This is used as an interim step in calculating the actual length of the space with the slice taken into account. ''' if self.n_elements > self.sequence_length: return 0 if self.is_degreed: assert not self.is_recurrent and not self.is_partial and \ not self.is_combination return sum( math_tools.abs_stirling( self.sequence_length - len(self.fixed_map), self.sequence_length - degree - self._n_cycles_in_fixed_items_of_just_fixed) for degree in self.degrees) elif self.is_fixed: assert not self.is_degreed and not self.is_combination if self.is_recurrent: return calculate_length_of_recurrent_perm_space( self.n_elements - len(self.fixed_map), nifty_collections.FrozenBagBag( nifty_collections.Bag(self.free_values).values())) else: return math_tools.factorial( len(self.free_indices), start=(len(self.free_indices) - (self.n_elements - len(self.fixed_map)) + 1)) else: assert not self.is_degreed and not self.is_fixed if self.is_recurrent: if self.is_combination: return calculate_length_of_recurrent_comb_space( self.n_elements, self._frozen_bag_bag) else: return calculate_length_of_recurrent_perm_space( self.n_elements, self._frozen_bag_bag) else: return math_tools.factorial( self.sequence_length, start=(self.sequence_length - self.n_elements + 1)) // (math_tools.factorial(self.n_elements) if self.is_combination else 1)
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 get_bag(*args, **kwargs): kwargs.update({ 'round_mode': RoundMode.PROBABILISTIC, }) return nifty_collections.Bag( cute_round(*args, **kwargs) for i in range(1000))
def stupid_score(self): return tuple( zip(*nifty_collections.Bag(card.number for card in self).most_common()))[1]