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())
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))
def domain(self): """ The domain of ``self`` EXAMPLES:: sage: FiniteSetMaps(3,2).domain() {0, 1, 2} """ return IntegerRange(self._m)
def codomain(self): """ The codomain of ``self`` EXAMPLES:: sage: FiniteSetMaps(3,2).codomain() {0, 1} """ return IntegerRange(self._n)
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 )
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)
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))
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))
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)
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)
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")
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)
def bbox(self): return IntegerRange(Integer(0), Integer(self._mod))
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))
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)
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)
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"
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
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