Пример #1
0
    def __init__(self, n=3, action="left"):
        r"""
        EXAMPLES::

            sage: from sage_semigroups.categories.examples.finite_h_trivial_monoids import MonoidOfOrderPreservingMaps
            sage: p = MonoidOfOrderPreservingMaps(4)
            sage: TestSuite(p).run()
        """
        assert n in NN
        domain = IntegerRange(Integer(1), Integer(n + 1))
        index_set = IntegerRange(Integer(1), Integer(n))
        ambient_monoid = FiniteSetMaps(domain, action=action)

        def pi(i):
            return ambient_monoid.from_dict(
                dict([(k, k) for k in domain if k != i + 1] + [(i + 1, i)]))

        def opi(i):
            return ambient_monoid.from_dict(
                dict([(k, k) for k in domain if k != i] + [(i, i + 1)]))

        piopi = Family(
            dict([[i, pi(i)] for i in index_set] + [[-i, opi(i)]
                                                    for i in index_set]))

        AutomaticMonoid.__init__(
            self,
            piopi,
            ambient_monoid,
            one=ambient_monoid.one(),
            mul=operator.mul,
            category=Monoids().HTrivial().Finite().FinitelyGenerated()
            & Monoids().Transformation().Subobjects())
Пример #2
0
 def _truncate_region(self, reg):
     emin, emax = reg.erange
     smin, smax = reg.srange
     tmin, tmax = reg.trange
     if smax < 0 or smin > 0 or emax < -1 or emin > 0 or tmin > tmax:
         return Set(())
     if tmin < 0:
         tmin = 0
     if tmax < Infinity:
         tmax = Integer(tmax + 1)
     if emax >= 0 and emin <= -1:
         return IntegerRange(Integer(tmin), tmax)
     elif emax < 0 and emin <= -1:
         return IntegerRange(Integer(tmin | 1), tmax, Integer(2))
     else:
         return IntegerRange(Integer(((tmin + 1) | 1) - 1), tmax,
                             Integer(2))
Пример #3
0
    def domain(self):
        """
        The domain of ``self``

        EXAMPLES::

            sage: FiniteSetMaps(3,2).domain()
            {0, 1, 2}
        """
        return IntegerRange(self._m)
Пример #4
0
    def codomain(self):
        """
        The codomain of ``self``

        EXAMPLES::

            sage: FiniteSetMaps(3,2).codomain()
            {0, 1}
        """
        return IntegerRange(self._n)
Пример #5
0
    def __iter__(self, reg=None):
        if reg is None:
            reg = region()
        tmin, tmax = reg.trange
        octs = self.module.octants()
        assert len(octs) == 1  # TODO: allow more than one octant
        tsign, esign, ssign = octs[0]
        from itertools import chain

        if tsign == +1:
            I = IntegerRange(Integer(0), tmax + 1)
            return chain.from_iterable(
                self._truncate_region(reg.intersect(region(t=n))) for n in I
            )
        else:
            I = IntegerRange(Integer(0), -tmin)
            return chain.from_iterable(
                self._truncate_region(reg.intersect(region(t=-n))) for n in I
            )
Пример #6
0
    def __classcall_private__(cls,
                              domain,
                              codomain=None,
                              action="left",
                              category=None):
        """
        TESTS::

            sage: FiniteSetMaps(3)
            Maps from {0, 1, 2} to itself
            sage: FiniteSetMaps(4, 2)
            Maps from {0, 1, 2, 3} to {0, 1}
            sage: FiniteSetMaps(4, ["a","b","c"])
            Maps from {0, 1, 2, 3} to {'a', 'b', 'c'}
            sage: FiniteSetMaps([1,2], ["a","b","c"])
            Maps from {1, 2} to {'a', 'b', 'c'}
            sage: FiniteSetMaps([1,2,4], 3)
            Maps from {1, 2, 4} to {0, 1, 2}
        """
        if codomain is None:
            if isinstance(domain, (int, Integer)):
                return FiniteSetEndoMaps_N(domain, action, category)
            else:
                if domain not in Sets():
                    domain = FiniteEnumeratedSet(domain)
                return FiniteSetEndoMaps_Set(domain, action, category)

        if isinstance(domain, (int, Integer)):
            if isinstance(codomain, (int, Integer)):
                return FiniteSetMaps_MN(domain, codomain, category)
            else:
                domain = IntegerRange(domain)
        if isinstance(codomain, (int, Integer)):
            codomain = IntegerRange(codomain)

        if domain not in Sets():
            domain = FiniteEnumeratedSet(domain)
        if codomain not in Sets():
            codomain = FiniteEnumeratedSet(codomain)
        return FiniteSetMaps_Set(domain, codomain, category)
Пример #7
0
    def _sets_keys(self):
        """
        Return the indices of the Cartesian factors of ``self``
        as per
        :meth:`Sets.CartesianProducts.ParentMethods._sets_keys()
        <sage.categories.sets_cat.Sets.CartesianProducts.ParentMethods._sets_keys>`.

        EXAMPLES::

            sage: cartesian_product([QQ, ZZ, ZZ])._sets_keys()
            {0, 1, 2}
            sage: cartesian_product([ZZ]*100)._sets_keys()
            {0, ..., 99}
        """
        from sage.sets.integer_range import IntegerRange
        return IntegerRange(len(self._sets))
Пример #8
0
    def __iter__(self, reg=None):
        if reg is None:
            reg = region()
        tmin, tmax = reg.trange
        if tmin > tmax:
            return iter([])
        from itertools import chain

        mi, ma = self.dim_min(), self.dim_max()
        mi = max(mi, tmin)
        ma = min(ma, tmax)
        if mi > -Infinity:
            mi = Integer(mi)
        if ma < +Infinity:
            ma = Integer(ma + 1)
        return chain.from_iterable(
            self._basis_in_dim(n, reg) for n in IntegerRange(mi, ma))
Пример #9
0
    def _truncate_region(self, reg):
        from copy import copy

        reg = copy(reg)
        reg = reg.intersect(self.bbox())
        emin, emax = reg.erange
        smin, smax = reg.srange
        tmin, tmax = reg.trange
        if smax < 0 or smin > 0 or emax < 0 or emin > 0 or tmin > tmax:
            return Set(())
        tmin = max((tmin + self._field - 1) // self._field, self._bot)
        if tmax < Infinity:
            tmax = min(self._top, tmax // self._field)
        else:
            tmax = self._top
        if tmax < Infinity:
            tmax = Integer(tmax + 1)
        return IntegerRange(Integer(tmin), tmax)
Пример #10
0
    def __init__(self, fielddim, topexp, botexp, prefix, category=None):
        """
        mod 2 cohomology of kP^topexp/kP^{botexp-1} where dim_R k = fielddim
        """
        self._prime = 2
        self._bot = botexp
        self._top = topexp
        self._field = fielddim
        self._prefix = prefix
        if self._top < Infinity:
            n = Set(list(range(self._bot, self._top)))
        else:
            n = IntegerRange(Integer(self._bot), self._top)

        if category is None:
            category = YacopLeftModuleAlgebras(SteenrodAlgebra(self._prime))
        SteenrodModuleBase.__init__(self,
                                    ProjectiveSpaceBasis(self),
                                    category=category)
Пример #11
0
def build_alphabet(data=None, names=None, name=None):
    r"""
    Return an object representing an ordered alphabet.

    INPUT:

    - ``data`` -- the letters of the alphabet; it can be:

      * a list/tuple/iterable of letters; the iterable may be infinite
      * an integer `n` to represent `\{1, \ldots, n\}`, or infinity to
        represent `\NN`

    - ``names`` -- (optional) a list for the letters (i.e. variable names) or
      a string for prefix for all letters; if given a list, it must have the
      same cardinality as the set represented by ``data``

    - ``name`` -- (optional) if given, then return a named set and can be
      equal to : ``'lower', 'upper', 'space',
      'underscore', 'punctuation', 'printable', 'binary', 'octal', 'decimal',
      'hexadecimal', 'radix64'``.

      You can use many of them at once, separated by spaces : ``'lower
      punctuation'`` represents the union of the two alphabets ``'lower'`` and
      ``'punctuation'``.

      Alternatively, ``name`` can be set to ``"positive integers"`` (or
      ``"PP"``) or ``"natural numbers"`` (or ``"NN"``).

      ``name`` cannot be combined with ``data``.

    EXAMPLES:

    If the argument is a Set, it just returns it::

        sage: build_alphabet(ZZ) is ZZ
        True
        sage: F = FiniteEnumeratedSet('abc')
        sage: build_alphabet(F) is F
        True

    If a list, tuple or string is provided, then it builds a proper Sage class
    (:class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet`)::

        sage: build_alphabet([0,1,2])
        {0, 1, 2}
        sage: F = build_alphabet('abc'); F
        {'a', 'b', 'c'}
        sage: print(type(F).__name__)
        TotallyOrderedFiniteSet_with_category

    If an integer and a set is given, then it constructs a
    :class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet`::

        sage: build_alphabet(3, ['a','b','c'])
        {'a', 'b', 'c'}

    If an integer and a string is given, then it considers that string as a
    prefix::

        sage: build_alphabet(3, 'x')
        {'x0', 'x1', 'x2'}

    If no data is provided, ``name`` may be a string which describe an alphabet.
    The available names decompose into two families. The first one are 'positive
    integers', 'PP', 'natural numbers' or 'NN' which refer to standard set of
    numbers::

        sage: build_alphabet(name="positive integers")
        Positive integers
        sage: build_alphabet(name="PP")
        Positive integers
        sage: build_alphabet(name="natural numbers")
        Non negative integers
        sage: build_alphabet(name="NN")
        Non negative integers

    The other families for the option ``name`` are among 'lower', 'upper',
    'space', 'underscore', 'punctuation', 'printable', 'binary', 'octal',
    'decimal', 'hexadecimal', 'radix64' which refer to standard set of
    charaters. Theses names may be combined by separating them by a space::

        sage: build_alphabet(name="lower")
        {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
        sage: build_alphabet(name="hexadecimal")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
        sage: build_alphabet(name="decimal punctuation")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ',', '.', ';', ':', '!', '?'}

    In the case the alphabet is built from a list or a tuple, the order on the
    alphabet is given by the elements themselves::

        sage: A = build_alphabet([0,2,1])
        sage: A(0) < A(2)
        True
        sage: A(2) < A(1)
        False

    If a different order is needed, you may use
    :class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet` and
    set the option ``facade`` to ``False``. That way, the comparison fits the
    order of the input::

        sage: A = TotallyOrderedFiniteSet([4,2,6,1], facade=False)
        sage: A(4) < A(2)
        True
        sage: A(1) < A(6)
        False

    Be careful, the element of the set in the last example are no more
    integers and do not compare equal with integers::

        sage: type(A.an_element())
        <class 'sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet_with_category.element_class'>
        sage: A(1) == 1
        False
        sage: 1 == A(1)
        False

    We give an example of an infinite alphabet indexed by the positive
    integers and the prime numbers::

        sage: build_alphabet(oo, 'x')
        Lazy family (x(i))_{i in Non negative integers}
        sage: build_alphabet(Primes(), 'y')
        Lazy family (y(i))_{i in Set of all prime numbers: 2, 3, 5, 7, ...}

    TESTS::

        sage: Alphabet(3, name="punctuation")
        Traceback (most recent call last):
        ...
        ValueError: name cannot be specified with any other argument
        sage: Alphabet(8, ['e']*10)
        Traceback (most recent call last):
        ...
        ValueError: invalid value for names
        sage: Alphabet(8, x)
        Traceback (most recent call last):
        ...
        ValueError: invalid value for names
        sage: Alphabet(name=x, names="punctuation")
        Traceback (most recent call last):
        ...
        ValueError: name cannot be specified with any other argument
        sage: Alphabet(x)
        Traceback (most recent call last):
        ...
        ValueError: unable to construct an alphabet from the given parameters
    """
    # If both 'names' and 'data' are defined
    if name is not None and (data is not None or names is not None):
        raise ValueError("name cannot be specified with any other argument")

    # Swap arguments if we need to to try and make sure we have "good" user input
    if isinstance(names, integer_types + (Integer,)) or names == Infinity \
            or (data is None and names is not None):
        data,names = names,data

    # data is an integer
    if isinstance(data, integer_types + (Integer,)):
        if names is None:
            from sage.sets.integer_range import IntegerRange
            return IntegerRange(Integer(data))
        if isinstance(names, str):
            return TotallyOrderedFiniteSet([names + '%d'%i for i in range(data)])
        if len(names) == data:
            return TotallyOrderedFiniteSet(names)
        raise ValueError("invalid value for names")

    if data == Infinity:
        data = NonNegativeIntegers()

    # data is an iterable
    if isinstance(data, (tuple, list, str, range)) or data in Sets():
        if names is not None:
            if not isinstance(names, str):
                raise TypeError("names must be a string when data is a set")
            return Family(data, lambda i: names + str(i), name=names)
        if data in Sets():
            return data
        return TotallyOrderedFiniteSet(data)

    # Alphabet defined from a name
    if name is not None:
        if not isinstance(name, str):
            raise TypeError("name must be a string")
        if name == "positive integers" or name == "PP":
            from sage.sets.positive_integers import PositiveIntegers
            return PositiveIntegers()
        if name == "natural numbers" or name == "NN":
            return NonNegativeIntegers()

        data = []
        for alpha_name in name.split(' '):
            try:
                data.extend(list(set_of_letters[alpha_name]))
            except KeyError:
                raise TypeError("name is not recognized")
        return TotallyOrderedFiniteSet(data)

    # Alphabet(**nothing**)
    if data is None: # name is also None
        from sage.structure.parent import Set_PythonType
        return Set_PythonType(object)

    raise ValueError("unable to construct an alphabet from the given parameters")
Пример #12
0
def Subsets(s, k=None, submultiset=False):
    """
    Returns the combinatorial class of the subsets of the finite set ``s``. The
    set can be given as a list, Set or any iterable convertible to a set. It can
    alternatively be given a non-negative integer `n` which encode the set
    `\{1,2,\dots,n\}` (i.e. the Sage ``range(1,s+1)``).

    A second optional parameter ``k`` can be given. In this case, Subsets
    returns the combinatorial class of subsets of ``s`` of size ``k``.

    Finally the option ``submultiset`` allows one to deal with sets with
    repeated elements usually called multisets.

    EXAMPLES::

        sage: S = Subsets([1, 2, 3]); S
        Subsets of {1, 2, 3}
        sage: S.cardinality()
        8
        sage: S.first()
        {}
        sage: S.last()
        {1, 2, 3}
        sage: S.random_element()  # random
        {2}
        sage: S.list()
        [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]

    Here is the same example where the set is given as an integer::

        sage: S = Subsets(3)
        sage: S.list()
        [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]

    We demonstrate various the effect of the various options::

        sage: S = Subsets(3, 2); S
        Subsets of {1, 2, 3} of size 2
        sage: S.list()
        [{1, 2}, {1, 3}, {2, 3}]

        sage: S = Subsets([1, 2, 2], submultiset=True); S
        SubMultiset of [1, 2, 2]
        sage: S.list()
        [[], [1], [2], [1, 2], [2, 2], [1, 2, 2]]

        sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S
        SubMultiset of [1, 2, 2, 3] of size 3
        sage: S.list()
        [[1, 2, 2], [1, 2, 3], [2, 2, 3]]

        sage: S = Subsets(['a','b','a','b'], 2, submultiset=True); S.list()
        [['a', 'a'], ['a', 'b'], ['b', 'b']]


    And it is possible to play with subsets of subsets::

        sage: S = Subsets(3)
        sage: S2 = Subsets(S); S2
        Subsets of Subsets of {1, 2, 3}
        sage: S2.cardinality()
        256
        sage: it = iter(S2)
        sage: [it.next() for _ in xrange(8)]
        [{}, {{}}, {{1}}, {{2}}, {{3}}, {{1, 2}},  {{1, 3}}, {{2, 3}}]
        sage: S2.random_element()     # random
        {{2}, {1, 2, 3}, {}}
        sage: [S2.unrank(k) for k in xrange(256)] == S2.list()
        True

        sage: S3 = Subsets(S2)
        sage: S3.cardinality()
        115792089237316195423570985008687907853269984665640564039457584007913129639936
        sage: S3.unrank(14123091480)
        {{{1, 3}, {1, 2, 3}, {2}, {1}},
         {{2}, {1, 2, 3}, {}, {1, 2}},
         {},
         {{2}, {1, 2, 3}, {}, {3}, {1, 2}},
         {{1, 2, 3}, {}, {1}}, {{2}, {2, 3}, {}, {1, 2}}}

        sage: T = Subsets(S2, 10)
        sage: T.cardinality()
        278826214642518400
        sage: T.unrank(1441231049)
        {{{3}, {1, 2}, {}, {2, 3}, {1}, {1, 3}, ..., {{2, 3}, {}}, {{}}}
    """
    if k is not None:
        k = Integer(k)

    if isinstance(s, (int, Integer)):
        if s < 0:
            raise ValueError("s must be non-negative")
        from sage.sets.integer_range import IntegerRange
        s = IntegerRange(1, s + 1)


#    if len(Set(s)) != len(s):
#        multi = True

    if k is None:
        if submultiset:
            return SubMultiset_s(s)
        else:
            return Subsets_s(s)
    else:
        if submultiset:
            return SubMultiset_sk(s, k)
        else:
            return Subsets_sk(s, k)
Пример #13
0
 def bbox(self):
     return IntegerRange(Integer(0), Integer(self._mod))
Пример #14
0
 def bbox(self):
     r = self._other.bbox()
     f, l = r.first(), r.last()
     o = self._off
     return IntegerRange(Integer(f + o), Integer(l + 1 + o))
Пример #15
0
def build_alphabet(data=None, names=None, name=None):
    r"""
    Returns an object representing an ordered alphabet.

    EXAMPLES:

    If the argument is a Set, it just returns it::

        sage: build_alphabet(ZZ) is ZZ
        True
        sage: F = FiniteEnumeratedSet('abc')
        sage: build_alphabet(F) is F
        True

    If a list, tuple or string is provided, then it builds a proper Sage class
    (:class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet`)::

        sage: build_alphabet([0,1,2])
        {0, 1, 2}
        sage: F = build_alphabet('abc'); F
        {'a', 'b', 'c'}
        sage: print type(F).__name__
        TotallyOrderedFiniteSet_with_category

    If no data is provided, ``name`` may be a string which describe an alphabet.
    The available names decompose into two families. The first one are 'positive
    integers', 'PP', 'natural numbers' or 'NN' which refer to standard set of
    numbers::

        sage: build_alphabet(name="positive integers")
        Positive integers
        sage: build_alphabet(name="PP")
        Positive integers
        sage: build_alphabet(name="natural numbers")
        Non negative integers
        sage: build_alphabet(name="NN")
        Non negative integers

    The other families for the option ``name`` are among 'lower', 'upper',
    'space', 'underscore', 'punctuation', 'printable', 'binary', 'octal',
    'decimal', 'hexadecimal', 'radix64' which refer to standard set of
    charaters. Theses names may be combined by separating them by a space::

        sage: build_alphabet(name="lower")
        {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
        sage: build_alphabet(name="hexadecimal")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
        sage: build_alphabet(name="decimal punctuation")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ',', '.', ';', ':', '!', '?'}

    In the case the alphabet is built from a list or a tuple, the order on the
    alphabet is given by the elements themselves::

        sage: A = build_alphabet([0,2,1])
        sage: A(0) < A(2)
        True
        sage: A(2) < A(1)
        False

    If a different order is needed, you may use
    :class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet` and
    set the option ``facade`` to ``False``. That way, the comparison fits the
    order of the input::

        sage: A = TotallyOrderedFiniteSet([4,2,6,1], facade=False)
        sage: A(4) < A(2)
        True
        sage: A(1) < A(6)
        False

    Be careful, the element of the set in the last example are no more
    integers and do not compare equal with integers::

        sage: type(A.an_element())
        <class 'sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet_with_category.element_class'>
        sage: A(1) == 1
        False
        sage: 1 == A(1)
        False
    """
    if data in Sets():
        return data
    if isinstance(data, (int, long, Integer)):
        if names is None:
            from sage.sets.integer_range import IntegerRange
            return IntegerRange(Integer(data))
        elif len(names) == data:
            return TotallyOrderedFiniteSet(data)
        elif isinstance(names, str):
            return TotallyOrderedFiniteSet(
                [names + '%d' % i for i in xrange(data)])
        raise ValueError("not possible")
    elif data == Infinity:
        if names is None:
            return NonNegativeIntegers()
        else:
            Family(NonNegativeIntegers(), lambda i: 'x%d' % i)
    if data is None and name is None:
        from sage.structure.parent import Set_PythonType
        return Set_PythonType(object)
    if data is None:
        if name == "positive integers" or name == "PP":
            from sage.sets.positive_integers import PositiveIntegers
            return PositiveIntegers()
        elif name == "natural numbers" or name == "NN":
            return NonNegativeIntegers()
        else:
            names = name.split(' ')
            data = []
            for name in names:
                if name in set_of_letters:
                    data.extend(list(set_of_letters[name]))
                else:
                    raise TypeError("name is not recognized")
            return TotallyOrderedFiniteSet(data)
        raise TypeError("name is not recognized")
    elif isinstance(data, (tuple, list, str)):
        return TotallyOrderedFiniteSet(data)
Пример #16
0
def Subsets(s, k=None, submultiset=False):
    r"""
    Return the combinatorial class of the subsets of the finite set
    ``s``. The set can be given as a list, Set or any iterable
    convertible to a set. Alternatively, a non-negative integer `n`
    can be provided in place of ``s``; in this case, the result is
    the combinatorial class of the subsets of the set
    `\{1,2,\dots,n\}` (i.e. of the Sage ``range(1,n+1)``).

    A second optional parameter ``k`` can be given. In this case,
    ``Subsets`` returns the combinatorial class of subsets of ``s``
    of size ``k``.

    .. WARNING::

        The subsets are returned as Sets. Do not assume that
        these Sets are ordered; they often are not!
        (E.g., ``Subsets(10).list()[619]`` returns
        ``{10, 4, 5, 6, 7}`` on my system.)
        See :class:`SubsetsSorted` for a similar class which
        returns the subsets as sorted tuples.

    Finally the option ``submultiset`` allows one to deal with sets with
    repeated elements, usually called multisets. The method then
    returns the class of all multisets in which every element is
    contained at most as often as it is contained in ``s``. These
    multisets are encoded as lists.

    EXAMPLES::

        sage: S = Subsets([1, 2, 3]); S
        Subsets of {1, 2, 3}
        sage: S.cardinality()
        8
        sage: S.first()
        {}
        sage: S.last()
        {1, 2, 3}
        sage: S.random_element()  # random
        {2}
        sage: S.list()
        [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]

    Here is the same example where the set is given as an integer::

        sage: S = Subsets(3)
        sage: S.list()
        [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]

    We demonstrate various the effect of the various options::

        sage: S = Subsets(3, 2); S
        Subsets of {1, 2, 3} of size 2
        sage: S.list()
        [{1, 2}, {1, 3}, {2, 3}]

        sage: S = Subsets([1, 2, 2], submultiset=True); S
        SubMultiset of [1, 2, 2]
        sage: S.list()
        [[], [1], [2], [1, 2], [2, 2], [1, 2, 2]]

        sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S
        SubMultiset of [1, 2, 2, 3] of size 3
        sage: S.list()
        [[1, 2, 2], [1, 2, 3], [2, 2, 3]]

        sage: S = Subsets(['a','b','a','b'], 2, submultiset=True); S.list()
        [['a', 'a'], ['a', 'b'], ['b', 'b']]


    And it is possible to play with subsets of subsets::

        sage: S = Subsets(3)
        sage: S2 = Subsets(S); S2
        Subsets of Subsets of {1, 2, 3}
        sage: S2.cardinality()
        256
        sage: it = iter(S2)
        sage: [next(it) for _ in range(8)]
        [{}, {{}}, {{1}}, {{2}}, {{3}}, {{1, 2}},  {{1, 3}}, {{2, 3}}]
        sage: S2.random_element()     # random
        {{2}, {1, 2, 3}, {}}
        sage: [S2.unrank(k) for k in range(256)] == S2.list()
        True

        sage: S3 = Subsets(S2)
        sage: S3.cardinality()
        115792089237316195423570985008687907853269984665640564039457584007913129639936
        sage: S3.unrank(14123091480)
        {{{1, 3}, {1, 2, 3}, {2}, {1}},
         {{2}, {1, 2, 3}, {}, {1, 2}},
         {},
         {{2}, {1, 2, 3}, {}, {3}, {1, 2}},
         {{1, 2, 3}, {}, {1}}, {{2}, {2, 3}, {}, {1, 2}}}

        sage: T = Subsets(S2, 10)
        sage: T.cardinality()
        278826214642518400
        sage: T.unrank(1441231049)
        {{{3}, {1, 2}, {}, {2, 3}, {1}, {1, 3}, ..., {{2, 3}, {}}, {{}}}
    """
    if k is not None:
        k = Integer(k)

    if isinstance(s, (int, Integer)):
        if s < 0:
            raise ValueError("s must be non-negative")
        from sage.sets.integer_range import IntegerRange
        s = IntegerRange(1, s + 1)


#    if len(Set(s)) != len(s):
#        multi = True

    if k is None:
        if submultiset:
            return SubMultiset_s(s)
        else:
            return Subsets_s(s)
    else:
        if submultiset:
            return SubMultiset_sk(s, k)
        else:
            return Subsets_sk(s, k)
Пример #17
0
def Words(alphabet=None, length=None, finite=True, infinite=True):
    """
    Returns the combinatorial class of words of length k over an alphabet.

    EXAMPLES::

        sage: Words()
        Words
        sage: Words(length=7)
        Words of length 7
        sage: Words(5)
        Words over {1, 2, 3, 4, 5}
        sage: Words(5, 3)
        Words of length 3 over {1, 2, 3, 4, 5}
        sage: Words(5, infinite=False)
        Words over {1, 2, 3, 4, 5}
        sage: Words(5, finite=False)
        Infinite Words over {1, 2, 3, 4, 5}
        sage: Words('ab')
        Words over {'a', 'b'}
        sage: Words('ab', 2)
        Words of length 2 over {'a', 'b'}
        sage: Words('ab', infinite=False)
        Words over {'a', 'b'}
        sage: Words('ab', finite=False)
        Infinite Words over {'a', 'b'}
        sage: Words('positive integers', finite=False)
        Infinite Words over Positive integers
        sage: Words('natural numbers')
        Words over Non negative integers
    """
    if isinstance(alphabet, Words_all):
        return alphabet
    if alphabet is None:
        if length is None:
            if finite and infinite:
                return Words_all()
            elif finite:
                raise NotImplementedError
            else:
                raise NotImplementedError
        elif isinstance(length, (int, Integer)) and finite:
            return Words_n(length)
    else:
        if isinstance(alphabet, (int, Integer)):
            from sage.sets.integer_range import IntegerRange
            alphabet = IntegerRange(1, alphabet + 1)
        elif alphabet == "integers" \
                or alphabet == "positive integers" \
                or alphabet == "natural numbers":
            alphabet = build_alphabet(name=alphabet)
        else:
            alphabet = build_alphabet(data=alphabet)
        if length is None:
            if finite and infinite:
                return Words_over_OrderedAlphabet(alphabet)
            elif finite:
                return FiniteWords_over_OrderedAlphabet(alphabet)
            else:
                return InfiniteWords_over_OrderedAlphabet(alphabet)
        elif isinstance(length, (int, Integer)):
            return FiniteWords_length_k_over_OrderedAlphabet(alphabet, length)
    raise ValueError, "do not know how to make a combinatorial class of words from your input"
Пример #18
0
def _check_pbd(B, v, S):
    r"""
    Checks that ``B`` is a PBD on ``v`` points with given block sizes ``S``.

    The points of the balanced incomplete block design are implicitely assumed
    to be `\{0, ..., v-1\}`.

    INPUT:

    - ``B`` -- a list of blocks

    - ``v`` (integer) -- number of points

    - ``S`` -- list of integers `\geq 2`.

    EXAMPLE::

        sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest
        [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10],
         [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28],
         [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34],
        ...
        sage: from sage.combinat.designs.bibd import _check_pbd
        sage: _check_pbd([[1],[]],1,[1,0])
        Traceback (most recent call last):
        ...
        RuntimeError: All integers of S must be >=2

    TESTS::

        sage: _check_pbd([[1,2]],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The PBD covers a point 2 which is not in {0, 1}
        sage: _check_pbd([[1,2]]*2,2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The pair (1,2) is covered more than once
        sage: _check_pbd([],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The pair (0,1) is not covered
        sage: _check_pbd([[1,2],[1]],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: A block has size 1 while S=[2]
    """
    from itertools import combinations
    from sage.graphs.graph import Graph

    for X in B:
        if len(X) not in S:
            raise RuntimeError("A block has size {} while S={}".format(
                len(X), S))

    if any(x < 2 for x in S):
        raise RuntimeError("All integers of S must be >=2")

    if v == 0 or v == 1:
        if B:
            raise RuntimeError("A PBD with v<=1 is expected to be empty.")

    g = Graph()
    g.add_vertices(range(v))
    m = 0
    for X in B:
        for i, j in combinations(X, 2):
            g.add_edge(i, j)
            m_tmp = g.size()
            if m_tmp != m + 1:
                raise RuntimeError(
                    "The pair ({},{}) is covered more than once".format(i, j))
            m = m_tmp

    if g.vertices() != range(v):
        from sage.sets.integer_range import IntegerRange
        p = (set(g.vertices()) - set(range(v))).pop()
        raise RuntimeError(
            "The PBD covers a point {} which is not in {}".format(
                p, IntegerRange(v)))

    if not g.is_clique():
        for p1 in g:
            if g.degree(p1) != v - 1:
                break
        neighbors = g.neighbors(p1) + [p1]
        p2 = (set(g.vertices()) - set(neighbors)).pop()
        raise RuntimeError("The pair ({},{}) is not covered".format(p1, p2))

    return B
Пример #19
0
def build_alphabet_with_inverse(data,
                                names=None,
                                name=None,
                                neg=None,
                                inverse=None):
    r"""
    Returns a triple (positive_letters, negative_letters, involution on pos u
    neg).

    EXAMPLES::

        sage: pos,neg,inverse = build_alphabet_with_inverse('abc')
        sage: pos
        {'a', 'b', 'c'}
        sage: neg
        {'A', 'B', 'C'}
        sage: inverse('b')
        'B'
        sage: inverse('C')
        'c'

        sage: pos,neg,inverse=build_alphabet_with_inverse(3,'a')
        sage: pos
        {'a0', 'a1', 'a2'}
        sage: neg
        {'A0', 'A1', 'A2'}
        sage: inverse('a0')
        'A0'
        sage: inverse('A0')
        'a0'
    """
    if data in Sets():
        if neg in Sets():
            assert data.cardinality() == neg.cardinality()
            if inverse is not None:
                return data, neg, inverse
            else:
                return data, neg, InverseFromRank(data, neg)

    if isinstance(data, (int, long, Integer)):
        if names is None:
            from sage.sets.integer_range import IntegerRange
            return IntegerRange(1, data + 1), IntegerRange(-data,
                                                           0), neg_operation
        elif isinstance(names, str):
            if is_lower_character(names):
                pos = TotallyOrderedFiniteSet(
                    [names + '%d' % i for i in xrange(data)])
                neg = TotallyOrderedFiniteSet(
                    [lower_upper(names) + '%d' % i for i in xrange(data)])
                return pos, neg, fast_inverse_dictionnary(pos, neg)
        raise ValueError("not possible")

    if data is not None:
        data = build_alphabet(data)
    if neg is not None:
        neg = build_alphabet(data)
        assert data.cardinality() == neg.cardinality()
        if data.is_finite():
            return data, neg, fast_inverse_dictionnary(data, neg)
        return data, neg, InverseFromRank(data, neg)

    # now we want to build an inverse
    if not data.is_finite():
        raise ValueError("if ``pos`` is infinite you should provide ``neg``")
    if all(is_lower_character(a) for a in data):
        neg = build_alphabet([a.upper() for a in data])
        inverse = lower_upper
    elif all(is_positive_integer(a) for a in data):
        neg = build_alphabet([-a for a in data])
        inverse = neg_operation
    else:
        raise ValueError(
            "does not know how to build ``neg`` from the given ``pos``")

    return data, neg, inverse