Ejemplo n.º 1
0
 def __init__(self, function, sequence):
     
     self.function = function
     self.sequence = sequence_tools.ensure_iterable_is_immutable_sequence(
         sequence,
         default_type=nifty_collections.LazyTuple
     )
Ejemplo n.º 2
0
    def __init__(self, function, sequence):

        self.function = function
        self.sequence = sequence_tools.ensure_iterable_is_immutable_sequence(
            sequence,
            default_type=nifty_collections.LazyTuple
        )
Ejemplo n.º 3
0
 def get_rapplied(self, sequence):
     '''Get a version of this `PermSpace` that has a range of `sequence`.'''
     if self.is_rapplied:
         raise TypeError('This space is already rapplied, to rapply it to a '
                         'different sequence please use `.unrapplied` '
                         'first.')
     sequence = \
              sequence_tools.ensure_iterable_is_immutable_sequence(sequence)
     if len(sequence) != self.sequence_length:
         raise Exception
     return PermSpace(
         sequence, n_elements=self.n_elements, domain=self.domain,
         fixed_map={key: sequence[value] for key, value in
                                                    self.fixed_map.items()},
         degrees=self.degrees, slice_=self.canonical_slice,
         is_combination=self.is_combination,
         perm_type=self.perm_type
     )
 def get_rapplied(self, sequence):
     '''Get a version of this `PermSpace` that has a range of `sequence`.'''
     if self.is_rapplied:
         raise TypeError('This space is already rapplied, to rapply it to a '
                         'different sequence please use `.unrapplied` '
                         'first.')
     sequence = \
          sequence_tools.ensure_iterable_is_immutable_sequence(sequence)
     if len(sequence) != self.sequence_length:
         raise Exception
     return PermSpace(
         sequence, n_elements=self.n_elements, domain=self.domain,
         fixed_map={key: sequence[value] for key, value in
                                                    self.fixed_map.items()},
         degrees=self.degrees, slice_=self.canonical_slice,
         is_combination=self.is_combination,
         perm_type=self.perm_type
     )
Ejemplo n.º 5
0
    def get_dapplied(self, domain):
        '''Get a version of this `PermSpace` that has a domain of `domain`.'''
        from . import variations

        if self.is_combination:
            raise variations.UnallowedVariationSelectionException(
                {variations.Variation.DAPPLIED: True,
                 variations.Variation.COMBINATION: True,}
            )
        domain = sequence_tools.ensure_iterable_is_immutable_sequence(domain)
        if len(domain) != self.n_elements:
            raise Exception
        return PermSpace(
            self.sequence, n_elements=self.n_elements, domain=domain,
            fixed_map={domain[key]: value for key, value in
                                                   self._undapplied_fixed_map},
            degrees=self.degrees, slice_=self.canonical_slice,
            is_combination=self.is_combination,
            perm_type=self.perm_type
        )
 def get_dapplied(self, domain):
     '''Get a version of this `PermSpace` that has a domain of `domain`.'''
     from . import variations
     
     if self.is_combination:
         raise variations.UnallowedVariationSelectionException(
             {variations.Variation.DAPPLIED: True,
              variations.Variation.COMBINATION: True,}
         )
     domain = sequence_tools.ensure_iterable_is_immutable_sequence(domain)
     if len(domain) != self.n_elements:
         raise Exception
     return PermSpace(
         self.sequence, n_elements=self.n_elements, domain=domain,
         fixed_map={domain[key]: value for key, value in
                                                self._undapplied_fixed_map},
         degrees=self.degrees, slice_=self.canonical_slice,
         is_combination=self.is_combination,
         perm_type=self.perm_type
     )
Ejemplo n.º 7
0
 def apply(self, sequence, result_type=None):
     '''
     Apply the perm to a sequence, choosing items from it.
     
     This can also be used as `sequence * perm`. Example:
     
     >>> perm = PermSpace(5)[10]
     >>> perm
     <Perm: (0, 2, 4, 1, 3)>
     >>> perm.apply('growl')
     'golrw'
     >>> 'growl' * perm
     'golrw'
     
     Specify `result_type` to determine the type of the result returned. If
     `result_type=None`, will use `tuple`, except when `other` is a `str` or
     `Perm`, in which case that same type would be used.
     '''
     sequence = \
          sequence_tools.ensure_iterable_is_immutable_sequence(sequence)
     if sequence_tools.get_length(sequence) < \
                                            sequence_tools.get_length(self):
         raise Exception("Can't apply permutation on sequence of "
                         "shorter length.")
     
     permed_generator = (sequence[i] for i in self)
     if result_type is not None:
         if result_type is str:
             return ''.join(permed_generator)
         else:
             return result_type(permed_generator)
     elif isinstance(sequence, Perm):
         return type(self)(permed_generator,
                           sequence.nominal_perm_space)
     elif isinstance(sequence, str):
         return ''.join(permed_generator)
     else:
         return tuple(permed_generator)
Ejemplo n.º 8
0
 def apply(self, sequence, result_type=None):
     '''
     Apply the perm to a sequence, choosing items from it.
     
     This can also be used as `sequence * perm`. Example:
     
         >>> perm = PermSpace(5)[10]
         >>> perm
         <Perm: (0, 2, 4, 1, 3)>
         >>> perm.apply('growl')
         'golrw'
         >>> 'growl' * perm
         'golrw'
     
     Specify `result_type` to determine the type of the result returned. If
     `result_type=None`, will use `tuple`, except when `other` is a `str` or
     `Perm`, in which case that same type would be used.
     '''
     sequence = \
          sequence_tools.ensure_iterable_is_immutable_sequence(sequence)
     if sequence_tools.get_length(sequence) < \
                                            sequence_tools.get_length(self):
         raise Exception("Can't apply permutation on sequence of "
                         "shorter length.")
     
     permed_generator = (sequence[i] for i in self)
     if result_type is not None:
         if result_type is str:
             return ''.join(permed_generator)
         else:
             return result_type(permed_generator)
     elif isinstance(sequence, Perm):
         return type(self)(permed_generator,
                           sequence.nominal_perm_space)
     elif isinstance(sequence, str):
         return ''.join(permed_generator)
     else:
         return tuple(permed_generator)
Ejemplo n.º 9
0
 def __init__(self, sequences):
     self.sequences = nifty_collections.LazyTuple(
         (sequence_tools.ensure_iterable_is_immutable_sequence(
             sequence, default_type=nifty_collections.LazyTuple)
                                                  for sequence in sequences)
     )
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    def __init__(self,
                 iterable_or_length,
                 n_elements=None,
                 *,
                 domain=None,
                 fixed_map=None,
                 degrees=None,
                 is_combination=False,
                 slice_=None,
                 perm_type=None):

        ### Making basic argument checks: #####################################
        #                                                                     #
        assert isinstance(iterable_or_length,
                          (collections.abc.Iterable, numbers.Integral))
        if isinstance(iterable_or_length, numbers.Integral):
            assert iterable_or_length >= 0
        if slice_ is not None:
            assert isinstance(slice_, (slice, sequence_tools.CanonicalSlice))
            if slice_.step not in (1, None):
                raise NotImplementedError
        assert isinstance(n_elements, numbers.Integral) or n_elements is None
        assert isinstance(is_combination, bool)
        #                                                                     #
        ### Finished making basic argument checks. ############################

        ### Figuring out sequence and whether space is rapplied: ##############
        #                                                                     #
        if isinstance(iterable_or_length, numbers.Integral):
            self.is_rapplied = False
            self.sequence = sequence_tools.CuteRange(iterable_or_length)
            self.sequence_length = iterable_or_length
        else:
            assert isinstance(iterable_or_length, collections.abc.Iterable)
            self.sequence = sequence_tools. \
                      ensure_iterable_is_immutable_sequence(iterable_or_length)
            range_candidate = sequence_tools.CuteRange(len(self.sequence))

            self.is_rapplied = not (cute_iter_tools.are_equal(
                self.sequence, range_candidate))
            self.sequence_length = len(self.sequence)
            if not self.is_rapplied:
                self.sequence = sequence_tools.CuteRange(self.sequence_length)

        #                                                                     #
        ### Finished figuring out sequence and whether space is rapplied. #####

        ### Figuring out whether sequence is recurrent: #######################
        #                                                                     #
        if self.is_rapplied:
            self.is_recurrent = any(
                count >= 2 for count in self._frozen_ordered_bag.values())
        else:
            self.is_recurrent = False
        #                                                                     #
        ### Finished figuring out whether sequence is recurrent. ##############

        ### Figuring out number of elements: ##################################
        #                                                                     #

        self.n_elements = self.sequence_length if (n_elements is None) \
                                                                else n_elements
        if not isinstance(self.n_elements, int):
            raise TypeError('`n_elements` must be an `int`.')
        if not self.n_elements >= 0:
            raise TypeError('`n_elements` must be positive or zero.')

        self.is_partial = (self.n_elements != self.sequence_length)

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

        #                                                                     #
        ### Finished figuring out number of elements. #########################

        ### Figuring out whether it's a combination: ##########################
        #                                                                     #
        self.is_combination = is_combination
        # Well that was quick.
        #                                                                     #
        ### Finished figuring out whether it's a combination. #################

        ### Figuring out whether space is dapplied: ###########################
        #                                                                     #
        if domain is None:
            domain = self.indices
        domain = \
               sequence_tools.ensure_iterable_is_immutable_sequence(domain)
        if self.is_partial:
            domain = domain[:self.n_elements]
        self.is_dapplied = not cute_iter_tools.are_equal(domain, self.indices)
        if self.is_dapplied:
            if self.is_combination:
                raise UnallowedVariationSelectionException({
                    variations.Variation.DAPPLIED:
                    True,
                    variations.Variation.COMBINATION:
                    True,
                })

            self.domain = domain
            if len(set(self.domain)) < len(self.domain):
                raise Exception('The domain must not have repeating elements.')
        else:
            self.domain = self.indices
            self.undapplied = self
        #                                                                     #
        ### Finished figuring out whether space is dapplied. ##################

        ### Figuring out fixed map: ###########################################
        #                                                                     #
        if fixed_map is None:
            fixed_map = {}
        if not isinstance(fixed_map, dict):
            if isinstance(fixed_map, collections.abc.Callable):
                fixed_map = {item: fixed_map(item) for item in self.sequence}
            else:
                fixed_map = dict(fixed_map)
        if fixed_map:
            self.fixed_map = {
                key: value
                for (key, value) in fixed_map.items()
                if (key in self.domain) and (value in self.sequence)
            }

        else:
            (self.fixed_map, self.free_indices, self.free_keys,
             self.free_values) = ({}, self.indices, self.domain, self.sequence)

        self.is_fixed = bool(self.fixed_map)
        if self.is_fixed:
            if not (self.is_dapplied or self.is_rapplied or degrees or slice_
                    or (n_elements is not None) or self.is_combination):
                self._just_fixed = self
            else:
                self._get_just_fixed = lambda: PermSpace(
                    len(self.sequence),
                    fixed_map=self._undapplied_unrapplied_fixed_map,
                )
        else:

            if not (self.is_dapplied or self.is_rapplied or degrees or slice_
                    or (n_elements is not None) or self.is_combination):
                self._just_fixed = self
            else:
                self._get_just_fixed = lambda: PermSpace(len(self.sequence))

        #                                                                     #
        ### Finished figuring out fixed map. ##################################

        ### Figuring out degrees: #############################################
        #                                                                     #
        all_degrees = sequence_tools.CuteRange(self.sequence_length)
        if degrees is None:
            degrees = ()
        degrees = sequence_tools.to_tuple(degrees, item_type=int)

        if (not degrees) or cute_iter_tools.are_equal(degrees, all_degrees):
            self.is_degreed = False
            self.degrees = all_degrees
        else:
            self.is_degreed = True
            if self.is_combination:
                raise UnallowedVariationSelectionException({
                    variations.Variation.DEGREED:
                    True,
                    variations.Variation.COMBINATION:
                    True,
                })
            if self.is_partial:
                raise UnallowedVariationSelectionException({
                    variations.Variation.DEGREED:
                    True,
                    variations.Variation.PARTIAL:
                    True,
                })
            if self.is_recurrent:
                raise UnallowedVariationSelectionException({
                    variations.Variation.DEGREED:
                    True,
                    variations.Variation.RECURRENT:
                    True,
                })
            # The space is degreed; we canonicalize `degrees` into a sorted
            # tuple.
            self.degrees = tuple(
                sorted(degree for degree in degrees if degree in all_degrees))

        #                                                                     #
        ### Finished figuring out degrees. ####################################

        ### Figuring out slice and length: ####################################
        #                                                                     #
        self.slice_ = slice_
        self.canonical_slice = sequence_tools.CanonicalSlice(
            slice_ or slice(float('inf')), self._unsliced_length)
        self.length = max(
            self.canonical_slice.stop - self.canonical_slice.start, 0)
        self.is_sliced = (self.length != self._unsliced_length)
        #                                                                     #
        ### Finished figuring out slice and length. ###########################

        ### Figuring out perm type: ###########################################
        #                                                                     #
        self.is_typed = perm_type not in (None, self.default_perm_type)

        self.perm_type = perm_type if self.is_typed else self.default_perm_type
        assert issubclass(self.perm_type, Perm)
        #                                                                     #
        ### Finished figuring out perm type. ##################################

        self.is_pure = not (self.is_rapplied or self.is_fixed or self.is_sliced
                            or self.is_degreed or self.is_partial
                            or self.is_combination or self.is_typed)

        if self.is_pure:
            self.purified = self
        if not self.is_rapplied:
            self.unrapplied = self
        if not self.is_recurrent:
            self.unrecurrented = self
        if not self.is_partial:
            self.unpartialled = self
        if not self.is_combination:
            self.uncombinationed = self
        # No need do this for `undapplied`, it's already done above.
        if not self.is_fixed:
            self.unfixed = self
        if not self.is_degreed:
            self.undegreed = self
        if not self.is_sliced:
            self.unsliced = self
        if not self.is_typed:
            self.untyped = self
Ejemplo n.º 12
0
 def __init__(self, sequence):
     self.sequence = \
          sequence_tools.ensure_iterable_is_immutable_sequence(sequence)
     self.sequence_length = len(self.sequence)
     self._sequence_set = set(self.sequence)
     self.length = 2 ** self.sequence_length
Ejemplo n.º 13
0
 def __init__(self, characters):
     self.characters = \
            sequence_tools.ensure_iterable_is_immutable_sequence(characters)
     recurrences = sequence_tools.get_recurrences(self.characters)
     if recurrences:
         raise Exception('`characters` must not have recurring characters.')
Ejemplo n.º 14
0
 def __init__(self, characters):
     self.characters = sequence_tools.ensure_iterable_is_immutable_sequence(characters)
     recurrences = sequence_tools.get_recurrences(self.characters)
     if recurrences:
         raise Exception("`characters` must not have recurring characters.")
Ejemplo n.º 15
0
 def __init__(self, sequence):
     self.sequence = \
          sequence_tools.ensure_iterable_is_immutable_sequence(sequence)
     self.sequence_length = len(self.sequence)
     self._sequence_set = set(self.sequence)
     self.length = 2**self.sequence_length
Ejemplo n.º 16
0
    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
Ejemplo n.º 17
0
 def __init__(self, sequences):
     self.sequences = nifty_collections.LazyTuple(
         (sequence_tools.ensure_iterable_is_immutable_sequence(
             sequence, default_type=nifty_collections.LazyTuple)
                                                  for sequence in sequences)
     )
Ejemplo n.º 18
0
    def __init__(self, iterable_or_length, n_elements=None, *, domain=None, 
                 fixed_map=None, degrees=None, is_combination=False,
                 slice_=None, perm_type=None):
        
        ### Making basic argument checks: #####################################
        #                                                                     #
        assert isinstance(
            iterable_or_length,
            (collections.Iterable, numbers.Integral)
        )
        if isinstance(iterable_or_length, numbers.Integral):
            assert iterable_or_length >= 0
        if slice_ is not None:
            assert isinstance(slice_,
                              (slice, sequence_tools.CanonicalSlice))
            if slice_.step not in (1, None):
                raise NotImplementedError
        assert isinstance(n_elements, numbers.Integral) or n_elements is None
        assert isinstance(is_combination, bool)
        #                                                                     #
        ### Finished making basic argument checks. ############################

        ### Figuring out sequence and whether space is rapplied: ##############
        #                                                                     #
        if isinstance(iterable_or_length, numbers.Integral):
            self.is_rapplied = False
            self.sequence = sequence_tools.CuteRange(iterable_or_length)
            self.sequence_length = iterable_or_length
        else:
            assert isinstance(iterable_or_length, collections.Iterable)
            self.sequence = sequence_tools. \
                      ensure_iterable_is_immutable_sequence(iterable_or_length)
            range_candidate = sequence_tools.CuteRange(len(self.sequence))
            
            self.is_rapplied = not (
                cute_iter_tools.are_equal(self.sequence,
                                              range_candidate)
            )
            self.sequence_length = len(self.sequence)
            if not self.is_rapplied:
                self.sequence = sequence_tools.CuteRange(self.sequence_length)
        
        #                                                                     #
        ### Finished figuring out sequence and whether space is rapplied. #####
        
        ### Figuring out whether sequence is recurrent: #######################
        #                                                                     #
        if self.is_rapplied:
            self.is_recurrent = any(count >= 2 for count in
                                    self._frozen_ordered_bag.values())
        else:
            self.is_recurrent = False
        #                                                                     #
        ### Finished figuring out whether sequence is recurrent. ##############
        
        ### Figuring out number of elements: ##################################
        #                                                                     #
        
        self.n_elements = self.sequence_length if (n_elements is None) \
                                                                else n_elements
        if not isinstance(self.n_elements, int):
            raise TypeError('`n_elements` must be an `int`.')
        if not self.n_elements >= 0:
            raise TypeError('`n_elements` must be positive or zero.')
        
        self.is_partial = (self.n_elements != self.sequence_length)
        
        self.indices = sequence_tools.CuteRange(self.n_elements)
        
        #                                                                     #
        ### Finished figuring out number of elements. #########################

        ### Figuring out whether it's a combination: ##########################
        #                                                                     #
        self.is_combination = is_combination
        # Well that was quick.
        #                                                                     #
        ### Finished figuring out whether it's a combination. #################
        
        ### Figuring out whether space is dapplied: ###########################
        #                                                                     #
        if domain is None:
            domain = self.indices
        domain = \
               sequence_tools.ensure_iterable_is_immutable_sequence(domain)
        if self.is_partial:
            domain = domain[:self.n_elements]
        self.is_dapplied = not cute_iter_tools.are_equal(
            domain, self.indices
        )
        if self.is_dapplied:
            if self.is_combination:
                raise UnallowedVariationSelectionException(
                    {variations.Variation.DAPPLIED: True,
                     variations.Variation.COMBINATION: True,}
                )

            self.domain = domain
            if len(set(self.domain)) < len(self.domain):
                raise Exception('The domain must not have repeating elements.')
        else:
            self.domain = self.indices
            self.undapplied = self
        #                                                                     #
        ### Finished figuring out whether space is dapplied. ##################
        
        ### Figuring out fixed map: ###########################################
        #                                                                     #
        if fixed_map is None:
            fixed_map = {}
        if not isinstance(fixed_map, dict):
            if isinstance(fixed_map, collections.Callable):
                fixed_map = {item: fixed_map(item) for item in self.sequence}
            else:
                fixed_map = dict(fixed_map) 
        if fixed_map:
            self.fixed_map = {key: value for (key, value) in
                              fixed_map.items() if (key in self.domain) and
                              (value in self.sequence)}
                
        else:
            (self.fixed_map, self.free_indices, self.free_keys,
             self.free_values) = (
                {},
                self.indices,
                self.domain, 
                self.sequence
            )
                
        self.is_fixed = bool(self.fixed_map)
        if self.is_fixed:
            if not (self.is_dapplied or self.is_rapplied or degrees or slice_
                    or (n_elements is not None) or self.is_combination):
                self._just_fixed = self
            else:
                self._get_just_fixed = lambda: PermSpace(
                    len(self.sequence),
                    fixed_map=self._undapplied_unrapplied_fixed_map,
                )
        else:
                
            if not (self.is_dapplied or self.is_rapplied or degrees or slice_
                    or (n_elements is not None) or self.is_combination):
                self._just_fixed = self
            else:
                self._get_just_fixed = lambda: PermSpace(len(self.sequence))
        
        #                                                                     #
        ### Finished figuring out fixed map. ##################################
        
        ### Figuring out degrees: #############################################
        #                                                                     #
        all_degrees = sequence_tools.CuteRange(self.sequence_length)
        if degrees is None:
            degrees = ()
        degrees = sequence_tools.to_tuple(degrees, item_type=int)
        
        if (not degrees) or cute_iter_tools.are_equal(degrees, all_degrees):
            self.is_degreed = False
            self.degrees = all_degrees
        else:
            self.is_degreed = True
            if self.is_combination:
                raise UnallowedVariationSelectionException(
                    {variations.Variation.DEGREED: True,
                     variations.Variation.COMBINATION: True,}
                )
            if self.is_partial:
                raise UnallowedVariationSelectionException(
                    {variations.Variation.DEGREED: True,
                     variations.Variation.PARTIAL: True,}
                )
            if self.is_recurrent:
                raise UnallowedVariationSelectionException(
                    {variations.Variation.DEGREED: True,
                     variations.Variation.RECURRENT: True,}
                )
            # The space is degreed; we canonicalize `degrees` into a sorted
            # tuple.
            self.degrees = tuple(sorted(
                degree for degree in degrees if degree in all_degrees
            ))
            
        #                                                                     #
        ### Finished figuring out degrees. ####################################
            
        ### Figuring out slice and length: ####################################
        #                                                                     #
        self.slice_ = slice_
        self.canonical_slice = sequence_tools.CanonicalSlice(
            slice_ or slice(float('inf')),
            self._unsliced_length
        )
        self.length = max(
            self.canonical_slice.stop - self.canonical_slice.start,
            0
        )
        self.is_sliced = (self.length != self._unsliced_length)
        #                                                                     #
        ### Finished figuring out slice and length. ###########################
        
        ### Figuring out perm type: ###########################################
        #                                                                     #
        self.is_typed = perm_type not in (None, self.default_perm_type)
            
        self.perm_type = perm_type if self.is_typed else self.default_perm_type
        assert issubclass(self.perm_type, Perm)
        #                                                                     #
        ### Finished figuring out perm type. ##################################
        
        
        self.is_pure = not (self.is_rapplied or self.is_fixed or self.is_sliced
                            or self.is_degreed or self.is_partial or
                            self.is_combination or self.is_typed)
        
        if self.is_pure:
            self.purified = self
        if not self.is_rapplied:
            self.unrapplied = self
        if not self.is_recurrent:
            self.unrecurrented = self
        if not self.is_partial:
            self.unpartialled = self
        if not self.is_combination:
            self.uncombinationed = self
        # No need do this for `undapplied`, it's already done above.
        if not self.is_fixed:
            self.unfixed = self
        if not self.is_degreed:
            self.undegreed = self
        if not self.is_sliced:
            self.unsliced = self
        if not self.is_typed:
            self.untyped = self