Ejemplo n.º 1
0
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 combi._python_toolbox import nifty_collections
    return nifty_collections.Bag(seq1) == nifty_collections.Bag(seq2)
Ejemplo n.º 2
0
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 combi._python_toolbox import nifty_collections
    return {
        item: n_recurrences
        for item, n_recurrences in nifty_collections.Bag(
            sequence).most_common() if n_recurrences >= 2
    }
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
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 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)
Ejemplo n.º 5
0
 def stupid_score(self):
     return tuple(
         zip(*nifty_collections.Bag(card.number for card in self)
             .most_common()))[1]