コード例 #1
0
 def check(x):
     return isinstance(x, (list, tuple)) or x in Sets().Finite()
コード例 #2
0
    def __classcall_private__(cls,
                              generators,
                              ambient=None,
                              one=None,
                              mul=operator.mul,
                              category=None):
        """
        Parse and straighten the arguments; figure out the category.

        TESTS::

            sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup
            sage: R = IntegerModRing(9)
            sage: M = AutomaticSemigroup((), one=R.one())
            sage: M.ambient() == R
            True
            sage: AutomaticSemigroup((0,)).category()
            Join of Category of finitely generated semigroups and Category of subquotients of semigroups and Category of commutative magmas and Category of subobjects of sets
            sage: AutomaticSemigroup((0,), one=1).category()
            Join of Category of subquotients of monoids and
            Category of commutative monoids and
            Category of finitely generated semigroups and
            Category of subobjects of sets
            sage: AutomaticSemigroup((0,), one=0).category()
            Join of Category of commutative monoids and
            Category of finitely generated semigroups and
            Category of subquotients of semigroups and
            Category of subobjects of sets
            sage: AutomaticSemigroup((0,), mul=operator.add).category()
            Join of Category of semigroups and Category of subobjects of sets
            sage: AutomaticSemigroup((0,), one=0, mul=operator.add).category()
            Join of Category of monoids and Category of subobjects of sets

            sage: S5 = SymmetricGroup(5)
            sage: AutomaticSemigroup([S5((1,2))]).category()
            Join of Category of finite groups and
            Category of subquotients of monoids and
            Category of finite finitely generated semigroups and
            Category of subquotients of finite sets and
            Category of subobjects of sets

        .. TODO::

            One would want a subsemigroup of a group to be
            automatically a subgroup (in ``Groups().Subobjects()``).
        """
        generators = Family(generators)
        if ambient is None:
            # Try to guess the ambient semigroup from the generators or the unit
            if generators.cardinality() > 0:
                ambient = generators.first().parent()
            elif one is not None:
                ambient = one.parent()
            else:
                raise ValueError(
                    "AutomaticSemigroup requires at least one generator or `one` to determine the ambient space"
                )
        elif ambient not in Sets:
            raise ValueError("ambient (=%s) should be a set" % ambient)

        # if mul is not operator.mul  and category.is_subcategory(Monoids().Subobjects())  error

        if one is None and category is not None:
            if category.is_subcategory(Monoids().Subobjects()):
                one = ambient.one()
            elif category.is_subcategory(Monoids()):
                raise ValueError(
                    "For a monoid which is just a subsemigroup, the unit should be specified"
                )

        # Try to determine the most specific category
        # This logic should be in the categories
        if mul is operator.mul:
            default_category = Semigroups().FinitelyGenerated()
            if one is not None and one == ambient.one():
                default_category = default_category.Unital()
            if ambient in Semigroups().Commutative():
                default_category = default_category.Commutative()
            if ambient in Groups().Finite():
                default_category = default_category & Groups()
        else:
            default_category = Sets()

        if ambient in Sets().Finite():
            default_category = default_category.Finite()

        default_category = default_category.Subobjects() & Semigroups()
        if one is not None:
            default_category = default_category.Unital()
            cls = AutomaticMonoid

        if category is None:
            category = default_category
        else:
            category = default_category & category
        return super(AutomaticSemigroup, cls).__classcall__(cls,
                                                            generators,
                                                            ambient=ambient,
                                                            one=one,
                                                            mul=mul,
                                                            category=category)
コード例 #3
0
def Set(X=[]):
    r"""
    Create the underlying set of ``X``.

    If ``X`` is a list, tuple, Python set, or ``X.is_finite()`` is
    ``True``, this returns a wrapper around Python's enumerated immutable
    ``frozenset`` type with extra functionality.  Otherwise it returns a
    more formal wrapper.

    If you need the functionality of mutable sets, use Python's
    builtin set type.

    EXAMPLES::

        sage: X = Set(GF(9,'a'))
        sage: X
        {0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2}
        sage: type(X)
        <class 'sage.sets.set.Set_object_enumerated_with_category'>
        sage: Y = X.union(Set(QQ))
        sage: Y
        Set-theoretic union of {0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2} and Set of elements of Rational Field
        sage: type(Y)
        <class 'sage.sets.set.Set_object_union_with_category'>

    Usually sets can be used as dictionary keys.

    ::

        sage: d={Set([2*I,1+I]):10}
        sage: d                  # key is randomly ordered
        {{I + 1, 2*I}: 10}
        sage: d[Set([1+I,2*I])]
        10
        sage: d[Set((1+I,2*I))]
        10

    The original object is often forgotten.

    ::

        sage: v = [1,2,3]
        sage: X = Set(v)
        sage: X
        {1, 2, 3}
        sage: v.append(5)
        sage: X
        {1, 2, 3}
        sage: 5 in X
        False

    Set also accepts iterators, but be careful to only give *finite*
    sets::

        sage: from six.moves import range
        sage: sorted(Set(range(1,6)))
        [1, 2, 3, 4, 5]
        sage: sorted(Set(list(range(1,6))))
        [1, 2, 3, 4, 5]
        sage: sorted(Set(iter(range(1,6))))
        [1, 2, 3, 4, 5]

    We can also create sets from different types::

        sage: sorted(Set([Sequence([3,1], immutable=True), 5, QQ, Partition([3,1,1])]), key=str)
        [5, Rational Field, [3, 1, 1], [3, 1]]

    Sets with unhashable objects work, but with less functionality::

        sage: A = Set([QQ, (3, 1), 5])  # hashable
        sage: sorted(A.list(), key=repr)
        [(3, 1), 5, Rational Field]
        sage: type(A)
        <class 'sage.sets.set.Set_object_enumerated_with_category'>
        sage: B = Set([QQ, [3, 1], 5])  # unhashable
        sage: sorted(B.list(), key=repr)
        Traceback (most recent call last):
        ...
        AttributeError: 'Set_object_with_category' object has no attribute 'list'
        sage: type(B)
        <class 'sage.sets.set.Set_object_with_category'>

    TESTS::

        sage: Set(Primes())
        Set of all prime numbers: 2, 3, 5, 7, ...
        sage: Set(Subsets([1,2,3])).cardinality()
        8
        sage: S = Set(iter([1,2,3])); S
        {1, 2, 3}
        sage: type(S)
        <class 'sage.sets.set.Set_object_enumerated_with_category'>
        sage: S = Set([])
        sage: TestSuite(S).run()

    Check that :trac:`16090` is fixed::

        sage: Set()
        {}
    """
    if isinstance(X, CategoryObject):
        if isinstance(X, Set_generic):
            return X
        elif X in Sets().Finite():
            return Set_object_enumerated(X)
        else:
            return Set_object(X)

    if isinstance(X, Element):
        raise TypeError("Element has no defined underlying set")

    try:
        X = frozenset(X)
    except TypeError:
        return Set_object(X)
    else:
        return Set_object_enumerated(X)
コード例 #4
0
    def __classcall_private__(cls,
                              universe,
                              *predicates,
                              vars=None,
                              names=None,
                              category=None):
        r"""
        Normalize init arguments.

        TESTS::

            sage: ConditionSet(ZZ, names=["x"]) is ConditionSet(ZZ, names=x)
            True
            sage: ConditionSet(RR, x > 0, names=x) is ConditionSet(RR, (x > 0).function(x))
            True
        """
        if category is None:
            category = Sets()
        if isinstance(universe, Parent):
            if universe in Sets().Finite():
                category &= Sets().Finite()
            if universe in EnumeratedSets():
                category &= EnumeratedSets()

        if vars is not None:
            if names is not None:
                raise ValueError(
                    'cannot use names and vars at the same time; they are aliases'
                )
            names, vars = vars, None

        if names is not None:
            names = normalize_names(-1, names)

        callable_symbolic_predicates = []
        other_predicates = []

        for predicate in predicates:
            if isinstance(predicate, Expression) and predicate.is_callable():
                if names is None:
                    names = tuple(str(var) for var in predicate.args())
                elif len(names) != len(predicate.args()):
                    raise TypeError('mismatch in number of arguments')
                if vars is None:
                    vars = predicate.args()
                callable_symbolic_predicates.append(predicate)
            elif isinstance(predicate, Expression):
                if names is None:
                    raise TypeError(
                        'use callable symbolic expressions or provide variable names'
                    )
                if vars is None:
                    from sage.symbolic.ring import SR
                    vars = tuple(SR.var(name) for name in names)
                callable_symbolic_predicates.append(predicate.function(*vars))
            else:
                other_predicates.append(predicate)

        predicates = list(
            _stable_uniq(callable_symbolic_predicates + other_predicates))

        if not other_predicates and not callable_symbolic_predicates:
            if names is None and category is None:
                # No conditions, no variable names, no category, just use Set.
                return Set(universe)

        if any(predicate.args() != vars
               for predicate in callable_symbolic_predicates):
            # TODO: Implement safe renaming of the arguments of a callable symbolic expressions
            raise NotImplementedError(
                'all callable symbolic expressions must use the same arguments'
            )

        if names is None:
            names = ("x", )
        return super().__classcall__(cls,
                                     universe,
                                     *predicates,
                                     names=names,
                                     category=category)
コード例 #5
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, (int,long,Integer)) or names == Infinity \
            or (data is None and names is not None):
        data,names = names,data

    # data is an integer
    if isinstance(data, (int,long,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 xrange(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)) 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")
コード例 #6
0
ファイル: enumerated_sets.py プロジェクト: matsen/sage
            def __iter__(self):
                r"""
                Return a lexicographic iterator for the elements of this cartesian product.

                EXAMPLES::

                    sage: A = FiniteEnumeratedSets()(["a", "b"])
                    sage: B = FiniteEnumeratedSets().example(); B
                    An example of a finite enumerated set: {1,2,3}
                    sage: C = cartesian_product([A, B, A]); C
                    The cartesian product of ({'a', 'b'}, An example of a finite enumerated set: {1,2,3}, {'a', 'b'})
                    sage: C in FiniteEnumeratedSets()
                    True
                    sage: list(C)
                    [('a', 1, 'a'), ('a', 1, 'b'), ('a', 2, 'a'), ('a', 2, 'b'), ('a', 3, 'a'), ('a', 3, 'b'),
                     ('b', 1, 'a'), ('b', 1, 'b'), ('b', 2, 'a'), ('b', 2, 'b'), ('b', 3, 'a'), ('b', 3, 'b')]
                    sage: C.__iter__.__module__
                    'sage.categories.enumerated_sets'

                    sage: F22 = GF(2).cartesian_product(GF(2))
                    sage: list(F22)
                    [(0, 0), (0, 1), (1, 0), (1, 1)]

                    sage: C = cartesian_product([Permutations(10)]*4)
                    sage: it = iter(C)
                    sage: next(it)
                    ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
                    sage: next(it)
                    ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                     [1, 2, 3, 4, 5, 6, 7, 8, 10, 9])

                .. WARNING::

                    The elements are returned in lexicographic order,
                    which gives a valid enumeration only if all
                    factors, but possibly the first one, are
                    finite. So the following one is fine::

                        sage: it = iter(cartesian_product([ZZ, GF(2)]))
                        sage: [next(it) for _ in range(10)]
                        [(0, 0), (0, 1), (1, 0), (1, 1),
                         (-1, 0), (-1, 1), (2, 0), (2, 1),
                         (-2, 0), (-2, 1)]

                    But this one is not::

                        sage: it = iter(cartesian_product([GF(2), ZZ]))
                        sage: [next(it) for _ in range(10)]
                        doctest:...: UserWarning: Sage is not able to determine
                        whether the factors of this cartesian product are
                        finite. The lexicographic ordering might not go through
                        all elements.
                        [(0, 0), (0, 1), (0, -1), (0, 2), (0, -2),
                         (0, 3), (0, -3), (0, 4), (0, -4), (0, 5)]

                .. NOTE::

                    Here it would be faster to use :func:`itertools.product` for sets
                    of small size. But the latter expands all factor in memory!
                    So we can not reasonably use it in general.

                ALGORITHM:

                Recipe 19.9 in the Python Cookbook by Alex Martelli
                and David Ascher.
                """
                if any(f not in Sets().Finite()
                       for f in self.cartesian_factors()[1:]):
                    from warnings import warn
                    warn(
                        "Sage is not able to determine whether the factors of "
                        "this cartesian product are finite. The lexicographic "
                        "ordering might not go through all elements.")

                # visualize an odometer, with "wheels" displaying "digits"...:
                factors = list(self.cartesian_factors())
                wheels = map(iter, factors)
                digits = [next(it) for it in wheels]
                while True:
                    yield self._cartesian_product_of_elements(digits)
                    for i in range(len(digits) - 1, -1, -1):
                        try:
                            digits[i] = next(wheels[i])
                            break
                        except StopIteration:
                            wheels[i] = iter(factors[i])
                            digits[i] = next(wheels[i])
                    else:
                        break