Ejemplo n.º 1
0
 def __eq__(self, other):
     return type(self) == type(other) and \
                   self.nominal_perm_space == other.nominal_perm_space and \
        cute_iter_tools.are_equal(self._perm_sequence, other._perm_sequence)
Ejemplo n.º 2
0
 def __eq__(self, other):
     return type(self) == type(other) and \
                   self.nominal_perm_space == other.nominal_perm_space and \
        cute_iter_tools.are_equal(self._perm_sequence, other._perm_sequence)
Ejemplo n.º 3
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.º 4
0
def test_perm_spaces():
    pure_0a = PermSpace(4)
    pure_0b = PermSpace(range(4))
    pure_0c = PermSpace(list(range(4)))
    pure_0d = PermSpace(iter(range(4)))
    assert pure_0a == pure_0b == pure_0c == pure_0d
    assert len(pure_0a) == len(pure_0b) == len(pure_0c) == len(pure_0d)
    assert repr(pure_0a) == repr(pure_0b) == repr(pure_0c) == \
                                           repr(pure_0d) == '<PermSpace: 0..3>'
    
    assert repr(PermSpace(sequence_tools.CuteRange(3, 7))) == \
                                                            '<PermSpace: 3..6>'
    assert repr(PermSpace(sequence_tools.CuteRange(3, 7, 2))) == \
                                              '<PermSpace: CuteRange(3, 7, 2)>'
    assert repr(PermSpace(tuple(sequence_tools.CuteRange(3, 7, 2)))) == \
                                                          '<PermSpace: (3, 5)>'
    
    assert cute_iter_tools.are_equal(pure_0a, pure_0b, pure_0c, pure_0d)
    
    assert set(map(bool, (pure_0a, pure_0b, pure_0c, pure_0d))) == set((True,))
    
    pure_perm_space = pure_0a
    assert pure_0a.is_pure
    assert not pure_0a.is_rapplied
    assert not pure_0a.is_dapplied
    assert not pure_0a.is_fixed
    assert not pure_0a.is_sliced
    
    first_perm = pure_0a[0]
    some_perm = pure_0a[7]
    last_perm = pure_0a[-1]
    
    assert first_perm.index(2) == 2
    assert first_perm.index(0) == 0
    with cute_testing.RaiseAssertor(ValueError): first_perm.index(5)
    
    assert last_perm.apply('meow') == 'woem'
    assert last_perm.apply('meow', str) == 'woem'
    assert last_perm.apply('meow', tuple) == tuple('woem')
    
    with cute_testing.RaiseAssertor(IndexError): pure_0a[- pure_0a.length - 1]
    with cute_testing.RaiseAssertor(IndexError): pure_0a[- pure_0a.length - 2]
    with cute_testing.RaiseAssertor(IndexError): pure_0a[- pure_0a.length - 30]
    with cute_testing.RaiseAssertor(IndexError): pure_0a[pure_0a.length]
    with cute_testing.RaiseAssertor(IndexError): pure_0a[pure_0a.length + 1]
    with cute_testing.RaiseAssertor(IndexError): pure_0a[pure_0a.length + 2]
    with cute_testing.RaiseAssertor(IndexError): pure_0a[pure_0a.length + 300]
    
    with cute_testing.RaiseAssertor(): pure_0a[24]
    
    assert pure_0a.take_random() in pure_0c
    
    
    # Testing hashing: 
    pure_perm_space_dict = {pure_0a: 'a', pure_0b: 'b',
                            pure_0c: 'c', pure_0d: 'd',}
    (single_value,) = pure_perm_space_dict.values()
    assert len(pure_perm_space_dict) == 1 # They're all the same
    assert pure_perm_space_dict[pure_0a] == pure_perm_space_dict[pure_0b] == \
          pure_perm_space_dict[pure_0c] == pure_perm_space_dict[pure_0d] == \
                                                                   single_value
    
    assert None not in pure_0a # Because, damn.
    assert PermSpace('meow')[0] not in pure_0a
    
    assert type(first_perm) == type(some_perm) == type(last_perm) == Perm
    assert set(some_perm) == set(range(4))
    assert tuple(first_perm) == (0, 1, 2, 3)
    assert tuple(last_perm) == (3, 2, 1, 0)
    assert Perm.coerce(first_perm) == first_perm
    assert Perm.coerce(first_perm, pure_0b) == first_perm
    assert Perm.coerce(tuple(first_perm)) == first_perm
    assert Perm.coerce(list(first_perm)) == first_perm
    assert Perm.coerce(tuple(first_perm), pure_0a) == first_perm
    assert Perm.coerce(list(first_perm), pure_0b) == first_perm
    assert Perm.coerce(tuple(first_perm), PermSpace(5, n_elements=4)) != \
                                                                     first_perm
    
    
    assert isinstance(first_perm.items, combi.perming.perm.PermItems)
    assert first_perm.items[2] == (2, 2)
    assert repr(first_perm.items) == '<PermItems: %s>' % repr(first_perm)
    assert isinstance(first_perm.as_dictoid, combi.perming.perm.PermAsDictoid)
    assert first_perm.as_dictoid[2] == 2
    assert dict(first_perm.as_dictoid) == {0: 0, 1: 1, 2: 2, 3: 3}
    assert not (first_perm != first_perm)
    assert first_perm == first_perm
    assert first_perm
    assert tuple({pure_0a[4]: 1, pure_0b[4]: 2, pure_0c[4]: 3,}.keys()) == \
                                                                 (pure_0d[4], )
    
    
    assert some_perm.inverse == ~ some_perm
    assert ~ ~ some_perm == some_perm
    
    
    assert first_perm in pure_perm_space
    assert set(first_perm) not in pure_perm_space # No order? Not contained.
    assert some_perm in pure_perm_space
    assert last_perm in pure_perm_space
    assert tuple(first_perm) in pure_perm_space
    assert list(some_perm) in pure_perm_space
    assert iter(last_perm) in pure_perm_space
    assert 'meow' not in pure_perm_space
    assert (0, 1, 2, 3, 3) not in pure_perm_space
    
    assert pure_perm_space.index(first_perm) == 0
    assert pure_perm_space.index(last_perm) == \
                                                len(pure_perm_space) - 1
    assert pure_perm_space.index(some_perm) == 7
    
    assert 'meow' * Perm((1, 3, 2, 0)) == 'ewom'
    assert Perm('meow', 'meow') * Perm((1, 3, 2, 0)) == Perm('ewom', 'meow')
    assert [0, 1, 2, 3] * Perm((0, 1, 2, 3)) == (0, 1, 2, 3)
    assert Perm((0, 1, 2, 3)) * Perm((0, 1, 2, 3)) == Perm((0, 1, 2, 3))
    assert Perm((2, 0, 1, 3)) * Perm((0, 1, 3, 2)) == Perm((2, 0, 3, 1))
    
    assert (Perm((0, 1, 2, 3)) ** (- 2)) == (Perm((0, 1, 2, 3)) ** (- 1)) == \
           (Perm((0, 1, 2, 3)) ** (0)) == (Perm((0, 1, 2, 3)) ** (1)) == \
           (Perm((0, 1, 2, 3)) ** 2) == (Perm((0, 1, 2, 3)) ** 3)
    
    assert set(map(bool, (pure_0a[4:4], pure_0a[3:2]))) == set((False,))
    assert pure_0a[2:6][1:-1] == pure_0a[3:5]
    assert tuple(pure_0a[2:6][1:-1]) == tuple(pure_0a[3:5])
    assert pure_0a[2:6][1:-1][1] == pure_0a[3:5][1]
    assert pure_0a[2:5][1:-1] != pure_0a[3:5]
    
    big_perm_space = PermSpace(range(150), fixed_map={1: 5, 70: 3,},
                               degrees=(3, 5))
    
    assert big_perm_space == PermSpace(range(150),
                                       fixed_map={1: 5, 70: 3,}.items(),
                                       degrees=(3, 5))
    
    for i in [10**10, 3*11**9-344, 4*12**8-5, 5*3**20+4]:
        perm = big_perm_space[i]
        assert big_perm_space.index(perm) == i
        
    repr_of_big_perm_space = repr(PermSpace(tuple(range(100, 0, -1))))
    assert '...' in repr_of_big_perm_space
    assert len(repr_of_big_perm_space) <= 100
    
    fixed_perm_space = pure_perm_space.get_fixed({0: 3,})
    assert fixed_perm_space.length == 6
    assert fixed_perm_space.is_fixed
    assert not fixed_perm_space.is_pure
    assert fixed_perm_space.unfixed.is_pure
    assert fixed_perm_space.unfixed == pure_perm_space
    
    assert pickle.loads(pickle.dumps(pure_perm_space)) == pure_perm_space
    assert pickle.loads(pickle.dumps(pure_0b[2])) == pure_0c[2]
    assert pickle.loads(pickle.dumps(pure_0b[3])) != pure_0b[4]
Ejemplo n.º 5
0
def test_perm_spaces():
    pure_0a = PermSpace(4)
    pure_0b = PermSpace(range(4))
    pure_0c = PermSpace(list(range(4)))
    pure_0d = PermSpace(iter(range(4)))
    assert pure_0a == pure_0b == pure_0c == pure_0d
    assert len(pure_0a) == len(pure_0b) == len(pure_0c) == len(pure_0d)
    assert repr(pure_0a) == repr(pure_0b) == repr(pure_0c) == \
                                           repr(pure_0d) == '<PermSpace: 0..3>'

    assert repr(PermSpace(sequence_tools.CuteRange(3, 7))) == \
                                                            '<PermSpace: 3..6>'
    assert repr(PermSpace(sequence_tools.CuteRange(3, 7, 2))) == \
                                              '<PermSpace: CuteRange(3, 7, 2)>'
    assert repr(PermSpace(tuple(sequence_tools.CuteRange(3, 7, 2)))) == \
                                                          '<PermSpace: (3, 5)>'

    assert cute_iter_tools.are_equal(pure_0a, pure_0b, pure_0c, pure_0d)

    assert set(map(bool, (pure_0a, pure_0b, pure_0c, pure_0d))) == {True}

    pure_perm_space = pure_0a
    assert pure_0a.is_pure
    assert not pure_0a.is_rapplied
    assert not pure_0a.is_dapplied
    assert not pure_0a.is_fixed
    assert not pure_0a.is_sliced

    first_perm = pure_0a[0]
    some_perm = pure_0a[7]
    last_perm = pure_0a[-1]

    assert first_perm.index(2) == 2
    assert first_perm.index(0) == 0
    with cute_testing.RaiseAssertor(ValueError):
        first_perm.index(5)

    assert last_perm.apply('meow') == 'woem'
    assert last_perm.apply('meow', str) == 'woem'
    assert last_perm.apply('meow', tuple) == tuple('woem')

    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[-pure_0a.length - 1]
    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[-pure_0a.length - 2]
    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[-pure_0a.length - 30]
    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[pure_0a.length]
    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[pure_0a.length + 1]
    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[pure_0a.length + 2]
    with cute_testing.RaiseAssertor(IndexError):
        pure_0a[pure_0a.length + 300]

    with cute_testing.RaiseAssertor():
        pure_0a[24]

    assert pure_0a.take_random() in pure_0c

    # Testing hashing:
    pure_perm_space_dict = {
        pure_0a: 'a',
        pure_0b: 'b',
        pure_0c: 'c',
        pure_0d: 'd',
    }
    assert len(pure_perm_space_dict) == 1  # They're all the same
    assert pure_perm_space_dict[pure_0a] == pure_perm_space_dict[pure_0b] == \
          pure_perm_space_dict[pure_0c] == pure_perm_space_dict[pure_0d] == 'd'

    assert None not in pure_0a  # Because, damn.
    assert PermSpace('meow')[0] not in pure_0a

    assert type(first_perm) == type(some_perm) == type(last_perm) == Perm
    assert set(some_perm) == set(range(4))
    assert tuple(first_perm) == (0, 1, 2, 3)
    assert tuple(last_perm) == (3, 2, 1, 0)
    assert Perm.coerce(first_perm) == first_perm
    assert Perm.coerce(first_perm, pure_0b) == first_perm
    assert Perm.coerce(tuple(first_perm)) == first_perm
    assert Perm.coerce(list(first_perm)) == first_perm
    assert Perm.coerce(tuple(first_perm), pure_0a) == first_perm
    assert Perm.coerce(list(first_perm), pure_0b) == first_perm
    assert Perm.coerce(tuple(first_perm), PermSpace(5, n_elements=4)) != \
                                                                     first_perm

    assert isinstance(first_perm.items, combi.perming.perm.PermItems)
    assert first_perm.items[2] == (2, 2)
    assert repr(first_perm.items) == '<PermItems: %s>' % repr(first_perm)
    assert isinstance(first_perm.as_dictoid, combi.perming.perm.PermAsDictoid)
    assert first_perm.as_dictoid[2] == 2
    assert dict(first_perm.as_dictoid) == {0: 0, 1: 1, 2: 2, 3: 3}
    assert not (first_perm != first_perm)
    assert first_perm == first_perm
    assert first_perm
    assert {
        pure_0a[4]: 1,
        pure_0b[4]: 2,
        pure_0c[4]: 3,
    } == {
        pure_0d[4]: 3,
    }

    assert some_perm.inverse == ~some_perm
    assert ~~some_perm == some_perm

    assert first_perm in pure_perm_space
    assert set(first_perm) not in pure_perm_space  # No order? Not contained.
    assert some_perm in pure_perm_space
    assert last_perm in pure_perm_space
    assert tuple(first_perm) in pure_perm_space
    assert list(some_perm) in pure_perm_space
    assert iter(last_perm) in pure_perm_space
    assert 'meow' not in pure_perm_space
    assert (0, 1, 2, 3, 3) not in pure_perm_space

    assert pure_perm_space.index(first_perm) == 0
    assert pure_perm_space.index(last_perm) == \
                                                len(pure_perm_space) - 1
    assert pure_perm_space.index(some_perm) == 7

    assert 'meow' * Perm((1, 3, 2, 0)) == 'ewom'
    assert Perm('meow', 'meow') * Perm((1, 3, 2, 0)) == Perm('ewom', 'meow')
    assert [0, 1, 2, 3] * Perm((0, 1, 2, 3)) == (0, 1, 2, 3)
    assert Perm((0, 1, 2, 3)) * Perm((0, 1, 2, 3)) == Perm((0, 1, 2, 3))
    assert Perm((2, 0, 1, 3)) * Perm((0, 1, 3, 2)) == Perm((2, 0, 3, 1))

    assert (Perm((0, 1, 2, 3)) ** (- 2)) == (Perm((0, 1, 2, 3)) ** (- 1)) == \
           (Perm((0, 1, 2, 3)) ** (0)) == (Perm((0, 1, 2, 3)) ** (1)) == \
           (Perm((0, 1, 2, 3)) ** 2) == (Perm((0, 1, 2, 3)) ** 3)

    assert set(map(bool, (pure_0a[4:4], pure_0a[3:2]))) == {False}
    assert pure_0a[2:6][1:-1] == pure_0a[3:5]
    assert tuple(pure_0a[2:6][1:-1]) == tuple(pure_0a[3:5])
    assert pure_0a[2:6][1:-1][1] == pure_0a[3:5][1]
    assert pure_0a[2:5][1:-1] != pure_0a[3:5]

    big_perm_space = PermSpace(range(150),
                               fixed_map={
                                   1: 5,
                                   70: 3,
                               },
                               degrees=(3, 5))

    assert big_perm_space == PermSpace(range(150),
                                       fixed_map={
                                           1: 5,
                                           70: 3,
                                       }.items(),
                                       degrees=(3, 5))

    for i in [10**10, 3 * 11**9 - 344, 4 * 12**8 - 5, 5 * 3**20 + 4]:
        perm = big_perm_space[i]
        assert big_perm_space.index(perm) == i

    repr_of_big_perm_space = repr(PermSpace(tuple(range(100, 0, -1))))
    assert '...' in repr_of_big_perm_space
    assert len(repr_of_big_perm_space) <= 100

    fixed_perm_space = pure_perm_space.get_fixed({
        0: 3,
    })
    assert fixed_perm_space.length == 6
    assert fixed_perm_space.is_fixed
    assert not fixed_perm_space.is_pure
    assert fixed_perm_space.unfixed.is_pure
    assert fixed_perm_space.unfixed == pure_perm_space

    assert pickle.loads(pickle.dumps(pure_perm_space)) == pure_perm_space
    assert pickle.loads(pickle.dumps(pure_0b[2])) == pure_0c[2]
    assert pickle.loads(pickle.dumps(pure_0b[3])) != pure_0b[4]
Ejemplo n.º 6
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