def check(x): return isinstance(x, (list, tuple)) or x in Sets().Finite()
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)
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)
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)
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")
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