def __init__(self,R, index_set=None, central_elements=None, category=None, element_class=None, prefix=None, **kwds): """ Initialize self. TESTS:: sage: V = lie_conformal_algebras.Virasoro(QQ) sage: TestSuite(V).run() """ self._generators = Family(index_set) E = cartesian_product([index_set, NonNegativeIntegers()]) if central_elements is not None: self._generators = DisjointUnionEnumeratedSets([index_set, Family(central_elements)]) E = DisjointUnionEnumeratedSets((cartesian_product([ Family(central_elements), {Integer(0)}]),E)) super(FreelyGeneratedLieConformalAlgebra,self).__init__(R, basis_keys=E, element_class=element_class, category=category, prefix=prefix, **kwds) if central_elements is not None: self._central_elements = Family(central_elements) else: self._central_elements = tuple()
def __init__(self, n, k, q, F): r""" Initialize ``self``. EXAMPLES:: sage: Cl = algebras.QuantumClifford(1,2) sage: TestSuite(Cl).run(elements=Cl.basis()) sage: Cl = algebras.QuantumClifford(1,3) sage: TestSuite(Cl).run(elements=Cl.basis()) # long time sage: Cl = algebras.QuantumClifford(3) # long time sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) # long time sage: TestSuite(Cl).run(elements=elts) # long time sage: Cl = algebras.QuantumClifford(2,4) # long time sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) # long time sage: TestSuite(Cl).run(elements=elts) # long time """ self._n = n self._k = k self._q = q self._psi = cartesian_product([(-1,0,1)]*n) self._w_poly = PolynomialRing(F, n, 'w') indices = [(tuple(psi), tuple(w)) for psi in self._psi for w in product(*[list(range((4-2*abs(psi[i]))*k)) for i in range(n)])] indices = FiniteEnumeratedSet(indices) cat = Algebras(F).FiniteDimensional().WithBasis() CombinatorialFreeModule.__init__(self, F, indices, category=cat) self._assign_names(self.algebra_generators().keys())
def add_degree_symmetric(d1, d2): """ Compute the sum componentwise of d1 and d2 and return a sorted grading set with no negative component as result. INPUT: - ``d1``,``d2`` -- lists of integers EXAMPLES:: sage: D = cartesian_product([ZZ for i in range(3)]) sage: add_degree_symmetric(D([3,2,1]), D([-2,0,0])) (2, 1, 1) sage: add_degree_symmetric(D([3,2,1]), D([-2,1,4])) (5, 3, 1) sage: add_degree_symmetric(D([3,2,1]), D([2,1,1])) (5, 3, 2) sage: add_degree_symmetric(D([3,2,1]), D([2,1,-2])) Traceback (most recent call last): ... ValueError: invalid degree """ d = d1 + d2 D = cartesian_product([ZZ for i in range(len(d))]) if not all(i >= 0 for i in d): raise ValueError("invalid degree") return D(sorted(d, reverse=True))
def group_generators(self): """ Return the group generators of ``self``. EXAMPLES:: sage: C5 = CyclicPermutationGroup(5) sage: C4 = CyclicPermutationGroup(4) sage: S4 = SymmetricGroup(3) sage: C = cartesian_product([C5, C4, S4]) sage: C.group_generators() Family (((1,2,3,4,5), (), ()), ((), (1,2,3,4), ()), ((), (), (1,2)), ((), (), (2,3))) We check the other portion of :trac:`16718` is fixed:: sage: len(C.j_classes()) 1 An example with an infinitely generated group (a better output is needed):: sage: G = Groups.free([1,2]) sage: H = Groups.free(ZZ) sage: C = cartesian_product([G, H]) sage: C.monoid_generators() Lazy family (gen(i))_{i in The Cartesian product of (...)} """ F = self.cartesian_factors() ids = tuple(G.one() for G in F) def lift(i, gen): cur = list(ids) cur[i] = gen return self._cartesian_product_of_elements(cur) from sage.sets.family import Family # Finitely generated cat = FiniteEnumeratedSets() if all(G.group_generators() in cat or isinstance(G.group_generators(), (tuple, list)) for G in F): ret = [ lift(i, gen) for i, G in enumerate(F) for gen in G.group_generators() ] return Family(ret) # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things from sage.categories.cartesian_product import cartesian_product gens_prod = cartesian_product([ Family(G.group_generators(), lambda g: (i, g)) for i, G in enumerate(F) ]) return Family(gens_prod, lift, name="gen")
def Possible(n): r""" Possible stack of DyckWords inside a n x n cube. EXAMPLES:: sage: from slabbe.dyck_3d import Possible sage: Possible(1) The Cartesian product of ({[1, 0]},) sage: Possible(2) The Cartesian product of ({[1, 1, 0, 0]}, {[1, 0, 1, 0], [1, 1, 0, 0]}) sage: Possible(3).list() [([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 0, 1, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 0, 1, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 1, 0, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 1, 0, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 1, 1, 0, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 0, 1, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 0, 1, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 0, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0])] """ from sage.combinat.dyck_word import DyckWords, DyckWord from sage.categories.cartesian_product import cartesian_product L = [] for i in range(1, n+1): K = [] for w in DyckWords(i): w = DyckWord([1]*(n-i) + list(w) + [0]*(n-i)) K.append(w) L.append(K) return cartesian_product(L)
def basis(self): r""" Return the basis of ``self``. EXAMPLES:: sage: g = LieAlgebra(QQ, cartan_type=['D',4,1]) sage: B = g.basis() sage: al = RootSystem(['D',4]).root_lattice().simple_roots() sage: B[al[1]+al[2]+al[4],4] (E[alpha[1] + alpha[2] + alpha[4]])#t^4 sage: B[-al[1]-2*al[2]-al[3]-al[4],2] (E[-alpha[1] - 2*alpha[2] - alpha[3] - alpha[4]])#t^2 sage: B[al[4],-2] (E[alpha[4]])#t^-2 sage: B['c'] c sage: B['d'] d """ K = cartesian_product([self._g.basis().keys(), ZZ]) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet c = FiniteEnumeratedSet(['c']) if self._kac_moody: d = FiniteEnumeratedSet(['d']) keys = DisjointUnionEnumeratedSets([c, d, K]) else: keys = DisjointUnionEnumeratedSets([c, K]) return Family(keys, self.monomial)
def strongly_fatter(self): """ Return the set of ordered set partitions which are strongly fatter than ``self``. See :meth:`strongly_finer` for the definition of "strongly fatter". EXAMPLES:: sage: C = OrderedSetPartition([[2, 5], [1], [3, 4]]).strongly_fatter() sage: C.cardinality() 2 sage: sorted(C) [[{2, 5}, {1, 3, 4}], [{2, 5}, {1}, {3, 4}]] sage: OrderedSetPartition([[4, 9], [-1, 2]]).strongly_fatter().list() [[{4, 9}, {-1, 2}]] Some extreme cases:: sage: list(OrderedSetPartition([[5]]).strongly_fatter()) [[{5}]] sage: list(OrderedSetPartition([]).strongly_fatter()) [[]] sage: sorted(OrderedSetPartition([[1], [2], [3], [4]]).strongly_fatter()) [[{1, 2, 3, 4}], [{1, 2, 3}, {4}], [{1, 2}, {3, 4}], [{1, 2}, {3}, {4}], [{1}, {2, 3, 4}], [{1}, {2, 3}, {4}], [{1}, {2}, {3, 4}], [{1}, {2}, {3}, {4}]] sage: sorted(OrderedSetPartition([[1], [3], [2], [4]]).strongly_fatter()) [[{1, 3}, {2, 4}], [{1, 3}, {2}, {4}], [{1}, {3}, {2, 4}], [{1}, {3}, {2}, {4}]] sage: sorted(OrderedSetPartition([[4], [1], [5], [3]]).strongly_fatter()) [[{4}, {1, 5}, {3}], [{4}, {1}, {5}, {3}]] """ c = [sorted(X) for X in self] l = len(c) g = [-1] + [i for i in range(l - 1) if c[i][-1] > c[i + 1][0]] + [l - 1] # g lists the positions of the blocks that cannot be merged # with their right neighbors. subcomps = [ OrderedSetPartition(c[g[i] + 1:g[i + 1] + 1]) for i in range(len(g) - 1) ] # Now, self is the concatenation of the entries of subcomps. # We can fatten each of the ordered set partitions setcomps # arbitrarily, and then concatenate the results. fattenings = [list(subcomp.fatter()) for subcomp in subcomps] return FiniteEnumeratedSet([ OrderedSetPartition(sum([list(gg) for gg in fattening], [])) for fattening in cartesian_product(fattenings) ])
def strongly_finer(self): """ Return the set of ordered set partitions which are strongly finer than ``self``. See :meth:`is_strongly_finer` for the definition of "strongly finer". EXAMPLES:: sage: C = OrderedSetPartition([[1, 3], [2]]).strongly_finer() sage: C.cardinality() 2 sage: C.list() [[{1}, {3}, {2}], [{1, 3}, {2}]] sage: OrderedSetPartition([]).strongly_finer() {[]} sage: W = OrderedSetPartition([[4, 9], [-1, 2]]) sage: W.strongly_finer().list() [[{4}, {9}, {-1}, {2}], [{4}, {9}, {-1, 2}], [{4, 9}, {-1}, {2}], [{4, 9}, {-1, 2}]] """ par = parent(self) if not self: return FiniteEnumeratedSet([self]) else: buo = OrderedSetPartition.bottom_up_osp return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) for C in cartesian_product([[buo(X, comp) for comp in Compositions(len(X))] for X in self])])
def __init__(self, crystals, **options): """ TESTS:: sage: from sage.combinat.crystals.tensor_product import FullTensorProductOfCrystals sage: C = crystals.Letters(['A',2]) sage: T = crystals.TensorProduct(C,C) sage: isinstance(T, FullTensorProductOfCrystals) True sage: TestSuite(T).run() """ category = Category.meet([crystal.category() for crystal in crystals]) category = category.TensorProducts() if any(c in Sets().Infinite() for c in crystals): category = category.Infinite() Parent.__init__(self, category=category) self.crystals = crystals if 'cartan_type' in options: self._cartan_type = CartanType(options['cartan_type']) else: if not crystals: raise ValueError( "you need to specify the Cartan type if the tensor product list is empty" ) else: self._cartan_type = crystals[0].cartan_type() self.cartesian_product = cartesian_product(self.crystals) self.module_generators = self
def __init__(self, space, number_errors, number_erasures): r""" TESTS: If the sum of number of errors and number of erasures exceeds (or may exceed, in the case of tuples) the dimension of the input space, it will return an error:: sage: n_err, n_era = 21, 21 sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) Traceback (most recent call last): ... ValueError: The total number of errors and erasures can not exceed the dimension of the input space """ if isinstance(number_errors, (Integer, int)): number_errors = (number_errors, number_errors) if not isinstance(number_errors, (tuple, list)): raise ValueError("number_errors must be a tuple, a list, an Integer or a Python int") if isinstance(number_erasures, (Integer, int)): number_erasures = (number_erasures, number_erasures) if not isinstance(number_erasures, (tuple, list)): raise ValueError("number_erasures must be a tuple, a list, an Integer or a Python int") output_space = cartesian_product([space, VectorSpace(GF(2), space.dimension())]) super(ErrorErasureChannel, self).__init__(space, output_space) if number_errors[1] + number_erasures[1] > space.dimension(): raise ValueError("The total number of errors and erasures can not exceed the dimension of the input space") self._number_errors = number_errors self._number_erasures = number_erasures
def Possible(n): r""" Possible stack of DyckWords inside a n x n cube. EXAMPLES:: sage: from slabbe.dyck_3d import Possible sage: Possible(1) The Cartesian product of ({[1, 0]},) sage: Possible(2) The Cartesian product of ({[1, 1, 0, 0]}, {[1, 0, 1, 0], [1, 1, 0, 0]}) sage: Possible(3).list() [([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 0, 1, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 0, 1, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 1, 0, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 1, 0, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0], [1, 1, 1, 0, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 0, 1, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 0, 1, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 0, 0, 1, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0]), ([1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0])] """ from sage.combinat.dyck_word import DyckWords, DyckWord from sage.categories.cartesian_product import cartesian_product L = [] for i in range(1, n + 1): K = [] for w in DyckWords(i): w = DyckWord([1] * (n - i) + list(w) + [0] * (n - i)) K.append(w) L.append(K) return cartesian_product(L)
def __init__(self, crystals, **options): """ TESTS:: sage: from sage.combinat.crystals.tensor_product import FullTensorProductOfCrystals sage: C = crystals.Letters(['A',2]) sage: T = crystals.TensorProduct(C,C) sage: isinstance(T, FullTensorProductOfCrystals) True sage: TestSuite(T).run() """ category = Category.meet([crystal.category() for crystal in crystals]) category = category.TensorProducts() if any(c in Sets().Infinite() for c in crystals): category = category.Infinite() Parent.__init__(self, category=category) self.crystals = crystals if 'cartan_type' in options: self._cartan_type = CartanType(options['cartan_type']) else: if not crystals: raise ValueError("you need to specify the Cartan type if the tensor product list is empty") else: self._cartan_type = crystals[0].cartan_type() self.cartesian_product = cartesian_product(self.crystals) self.module_generators = self
def symmetrized_coordinate_sums(dim, n): """ Return formal symmetrized sum of multi-indices INPUT: - ``dim`` -- integer. The dimension (range of each index). - ``n`` -- integer. The total number of indices. OUTPUT: A symmetrized formal sum of multi-indices (tuples of integers) EXAMPLES:: sage: from sage.modules.tensor_operations import symmetrized_coordinate_sums sage: symmetrized_coordinate_sums(2, 2) ((0, 1) + (1, 0), (0, 0), (1, 1)) """ from sage.structure.formal_sum import FormalSum coordinates = [range(dim) for i in range(n)] table = dict() from sage.categories.cartesian_product import cartesian_product for i in cartesian_product(coordinates): sort_i = tuple(sorted(i)) x = table.get(sort_i, []) x.append([+1, tuple(i)]) table[sort_i] = x return tuple(FormalSum(x) for x in table.values())
def one(self): """ EXAMPLES:: sage: cartesian_product([QQ, ZZ, RR]).one() (1, 1, 1.00000000000000) """ return cartesian_product([set.one() for set in self._sets])
def bitstring_rotation(n, ones=None): r""" Return the invertible finite discrete dynamical system consisting of all bitstrings of size `n` (that is, of all `n`-tuples `(i_1, \ldots, i_n) \in \{0, 1\}^n`), evolving by cyclic rotation. If the optional parameter ``ones`` is provided, the system is restricted only to those bitstrings whose number of ones is the value of this parameter. EXAMPLES:: sage: F = finite_dynamical_systems.bitstring_rotation(5) sage: sorted(F.orbit_lengths()) [1, 1, 5, 5, 5, 5, 5, 5] sage: F.orbit((0, 1, 1, 0, 1)) [(0, 1, 1, 0, 1), (1, 1, 0, 1, 0), (1, 0, 1, 0, 1), (0, 1, 0, 1, 1), (1, 0, 1, 1, 0)] sage: F.is_homomesic(lambda x: sum(1 for i in range(5) for j in range(i) if x[j] > x[i])) False sage: F.is_homomesic(lambda x: x[0]) False sage: F = finite_dynamical_systems.bitstring_rotation(5, ones=3) sage: F.verify_inverse_evolution() True sage: sorted(F.orbit_lengths()) [5, 5] sage: F.orbit((0, 1, 1, 0, 1)) [(0, 1, 1, 0, 1), (1, 1, 0, 1, 0), (1, 0, 1, 0, 1), (0, 1, 0, 1, 1), (1, 0, 1, 1, 0)] sage: F.is_homomesic(lambda x: sum(1 for i in range(5) for j in range(i) if x[j] > x[i])) True sage: F.is_homomesic(lambda x: x[0]) True """ if ones is None: from sage.categories.cartesian_product import cartesian_product X = cartesian_product([[0, 1]] * n) else: from itertools import combinations X = [ tuple((1 if i in cs else 0) for i in range(n)) for cs in combinations(range(n), ones) ] if n == 0: phi = lambda x: x psi = phi else: phi = lambda x: x[1:] + (x[0], ) psi = lambda x: (x[-1], ) + x[:-1] return InvertibleFiniteDynamicalSystem(X, phi, inverse=psi)
def _init_product_vectors(self, i): r""" Helper to build up ``self._vectors`` incrementally during the constructor. INPUT: - `i` -- list/tuple of integers. Multi-index of length equal to the number of constituent vector collections. The $j$-th entry $i[j]$ indexes a ray in the $j$-th vector collection. Hence, $i$ specifies one element in each vector collection. OUTPUT: This method mutates the :class:`TensorOperation` instance. In particular, the tensor product of the vectors of the vector collection is computed, and added to the elements of the tensor operation if it has not been encountered before. The index of this tensor product vector is returned as an integer. .. NOTE:: In a convenient choice of coordinates the tensor product of, say, two vectors $(a,b)$ and $(c,d)$, is $(ac, ad, bc, bd)$. EXAMPLES:: sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2) sage: S = VectorCollection([(1,), (-1,)], QQ, 1) sage: R_tensor_S = TensorOperation([R,S]) sage: R_tensor_S.index_map(1, 1) 3 sage: R_tensor_S.index_map(2, 0) 3 sage: R_tensor_S.vectors() # indirect doctest ((1, 0), (-1, 0), (1, 2), (-1, -2)) """ # Pick out the i[j]-th vector rays = [list(self._V[j].vectors()[k]) for j, k in enumerate(i)] v = [] # Note: convert to list, as cartesian_product of vectors is unrelated from sage.categories.cartesian_product import cartesian_product for r in cartesian_product(map(list, rays)): v.append(prod(r)) # build up the tensor product v = tuple(v) # Use index of pre-existing tensor product vector if there is one try: result = self._vectors.index(v) except ValueError: self._vectors.append(v) result = len(self._vectors) - 1 return result
def twin_prime_powers_difference_set(p, check=True): r""" Return a difference set on `GF(p) \times GF(p+2)`. The difference set is built from the following element of the cartesian product of finite fields `GF(p) \times GF(p+2)`: - `(x,0)` with any `x` - `(x,y)` with `x` and `y` squares - `(x,y)` with `x` and `y` non-squares For more information see :wikipedia:`Difference_set`. INPUT: - ``check`` -- boolean (default: ``True``). If ``True`` then the result of the computation is checked before being returned. This should not be needed but ensures that the output is correct. EXAMPLES:: sage: from sage.combinat.designs.difference_family import twin_prime_powers_difference_set sage: G,D = twin_prime_powers_difference_set(3) sage: G The cartesian product of (Finite Field of size 3, Finite Field of size 5) sage: D [[(1, 1), (1, 4), (2, 2), (2, 3), (0, 0), (1, 0), (2, 0)]] """ from sage.rings.finite_rings.constructor import FiniteField from sage.categories.cartesian_product import cartesian_product from itertools import product Fp = FiniteField(p, 'x') Fq = FiniteField(p + 2, 'x') Fpset = set(Fp) Fqset = set(Fq) Fp_squares = set(x**2 for x in Fpset) Fq_squares = set(x**2 for x in Fqset) # Pairs of squares, pairs of non-squares d = [] d.extend(product(Fp_squares.difference([0]), Fq_squares.difference([0]))) d.extend( product(Fpset.difference(Fp_squares), Fqset.difference(Fq_squares))) # All (x,0) d.extend((x, 0) for x in Fpset) G = cartesian_product([Fp, Fq]) if check and not is_difference_family(G, [d]): raise RuntimeError("twin_prime_powers_difference_set produced a wrong " "difference set with p={}. Please contact " "*****@*****.**".format(p)) return G, [d]
def strongly_fatter(self): """ Return the set of ordered set partitions which are strongly fatter than ``self``. See :meth:`strongly_finer` for the definition of "strongly fatter". EXAMPLES:: sage: C = OrderedSetPartition([[2, 5], [1], [3, 4]]).strongly_fatter() sage: C.cardinality() 2 sage: sorted(C) [[{2, 5}, {1, 3, 4}], [{2, 5}, {1}, {3, 4}]] sage: OrderedSetPartition([[4, 9], [-1, 2]]).strongly_fatter().list() [[{4, 9}, {-1, 2}]] Some extreme cases:: sage: list(OrderedSetPartition([[5]]).strongly_fatter()) [[{5}]] sage: list(OrderedSetPartition([]).strongly_fatter()) [[]] sage: sorted(OrderedSetPartition([[1], [2], [3], [4]]).strongly_fatter()) [[{1, 2, 3, 4}], [{1, 2, 3}, {4}], [{1, 2}, {3, 4}], [{1, 2}, {3}, {4}], [{1}, {2, 3, 4}], [{1}, {2, 3}, {4}], [{1}, {2}, {3, 4}], [{1}, {2}, {3}, {4}]] sage: sorted(OrderedSetPartition([[1], [3], [2], [4]]).strongly_fatter()) [[{1, 3}, {2, 4}], [{1, 3}, {2}, {4}], [{1}, {3}, {2, 4}], [{1}, {3}, {2}, {4}]] sage: sorted(OrderedSetPartition([[4], [1], [5], [3]]).strongly_fatter()) [[{4}, {1, 5}, {3}], [{4}, {1}, {5}, {3}]] """ c = [sorted(X) for X in self] l = len(c) g = [-1] + [i for i in range(l-1) if c[i][-1] > c[i+1][0]] + [l-1] # g lists the positions of the blocks that cannot be merged # with their right neighbors. subcomps = [OrderedSetPartition(c[g[i] + 1 : g[i+1] + 1]) for i in range(len(g)-1)] # Now, self is the concatenation of the entries of subcomps. # We can fatten each of the ordered set partitions setcomps # arbitrarily, and then concatenate the results. fattenings = [list(subcomp.fatter()) for subcomp in subcomps] return FiniteEnumeratedSet([OrderedSetPartition(sum([list(g) for g in fattening], [])) for fattening in cartesian_product(fattenings)])
def twin_prime_powers_difference_set(p, check=True): r""" Return a difference set on `GF(p) \times GF(p+2)`. The difference set is built from the following element of the cartesian product of finite fields `GF(p) \times GF(p+2)`: - `(x,0)` with any `x` - `(x,y)` with `x` and `y` squares - `(x,y)` with `x` and `y` non-squares For more information see :wikipedia:`Difference_set`. INPUT: - ``check`` -- boolean (default: ``True``). If ``True`` then the result of the computation is checked before being returned. This should not be needed but ensures that the output is correct. EXAMPLES:: sage: from sage.combinat.designs.difference_family import twin_prime_powers_difference_set sage: G,D = twin_prime_powers_difference_set(3) sage: G The cartesian product of (Finite Field of size 3, Finite Field of size 5) sage: D [[(1, 1), (1, 4), (2, 2), (2, 3), (0, 0), (1, 0), (2, 0)]] """ from sage.rings.finite_rings.constructor import FiniteField from sage.categories.cartesian_product import cartesian_product from itertools import product Fp = FiniteField(p,'x') Fq = FiniteField(p+2,'x') Fpset = set(Fp) Fqset = set(Fq) Fp_squares = set(x**2 for x in Fpset) Fq_squares = set(x**2 for x in Fqset) # Pairs of squares, pairs of non-squares d = [] d.extend(product(Fp_squares.difference([0]),Fq_squares.difference([0]))) d.extend(product(Fpset.difference(Fp_squares),Fqset.difference(Fq_squares))) # All (x,0) d.extend((x,0) for x in Fpset) G = cartesian_product([Fp,Fq]) if check and not is_difference_family(G, [d]): raise RuntimeError("twin_prime_powers_difference_set produced a wrong " "difference set with p={}. Please contact " "*****@*****.**".format(p)) return G, [d]
def group_generators(self): """ Return the group generators of ``self``. EXAMPLES:: sage: C5 = CyclicPermutationGroup(5) sage: C4 = CyclicPermutationGroup(4) sage: S4 = SymmetricGroup(3) sage: C = cartesian_product([C5, C4, S4]) sage: C.group_generators() Family (((1,2,3,4,5), (), ()), ((), (1,2,3,4), ()), ((), (), (1,2)), ((), (), (2,3))) We check the other portion of :trac:`16718` is fixed:: sage: len(C.j_classes()) 1 An example with an infinitely generated group (a better output is needed):: sage: G = Groups.free([1,2]) sage: H = Groups.free(ZZ) sage: C = cartesian_product([G, H]) sage: C.monoid_generators() Lazy family (gen(i))_{i in The Cartesian product of (...)} """ F = self.cartesian_factors() ids = tuple(G.one() for G in F) def lift(i, gen): cur = list(ids) cur[i] = gen return self._cartesian_product_of_elements(cur) from sage.sets.family import Family # Finitely generated cat = FiniteEnumeratedSets() if all(G.group_generators() in cat or isinstance(G.group_generators(), (tuple, list)) for G in F): ret = [lift(i, gen) for i,G in enumerate(F) for gen in G.group_generators()] return Family(ret) # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things from sage.categories.cartesian_product import cartesian_product gens_prod = cartesian_product([Family(G.group_generators(), lambda g: (i, g)) for i,G in enumerate(F)]) return Family(gens_prod, lift, name="gen")
def _power_operation(self, n, operation): """ Return tensor power operation. INPUT: - ``n`` -- integer. the number of factors of ``self``. - ``operation`` -- string. See :class:`~sage.modules.tensor_operations.TensorOperation` for details. EXAMPLES:: sage: F = FilteredVectorSpace(1, 1) + FilteredVectorSpace(1, 2); F QQ^2 >= QQ^1 >= 0 sage: F._power_operation(2, 'symmetric') QQ^3 >= QQ^2 >= QQ^1 >= 0 sage: F._power_operation(2, 'antisymmetric') QQ^1 >= 0 """ from sage.modules.tensor_operations import VectorCollection, TensorOperation generators, indices = self.presentation() V = VectorCollection(generators, self.base_ring(), self.dimension()) T = TensorOperation([V] * n, operation) iters = [self.support()] * n filtration = dict() from sage.categories.cartesian_product import cartesian_product for degrees in cartesian_product(iters): deg = sum(degrees) filt_deg = filtration.get(deg, set()) for i in cartesian_product([indices.get(d) for d in degrees]): pow_i = T.index_map(*i) if pow_i is not None: filt_deg.add(pow_i) filtration[deg] = filt_deg return FilteredVectorSpace(T.vectors(), filtration, base_ring=self.base_ring())
def difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=True): r""" Return the product of the ``(G1,k,lmbda1)`` and ``(G2,k,lmbda2)`` difference matrices ``M1`` and ``M2``. The result is a `(G1 \times G2, k, \lambda_1 \lambda_2)`-difference matrix. INPUT: - ``k,lmbda1,lmbda2`` -- positive integer - ``G1, G2`` -- groups - ``M1, M2`` -- ``(G1,k,lmbda1)`` and ``(G,k,lmbda2)`` difference matrices - ``check`` (boolean) -- if ``True`` (default), the output is checked before being returned. EXAMPLES:: sage: from sage.combinat.designs.difference_matrices import ( ....: difference_matrix_product, ....: is_difference_matrix) sage: G1,M1 = designs.difference_matrix(11,6) sage: G2,M2 = designs.difference_matrix(7,6) sage: G,M = difference_matrix_product(6,M1,G1,1,M2,G2,1) sage: G1 Finite Field of size 11 sage: G2 Finite Field of size 7 sage: G The cartesian product of (Finite Field of size 11, Finite Field of size 7) sage: is_difference_matrix(M,G,6,1) True """ g1 = G1.cardinality() g2 = G2.cardinality() g = g1 * g2 lmbda = lmbda1 * lmbda2 from sage.categories.cartesian_product import cartesian_product G = cartesian_product([G1, G2]) M = [[G((M1[j1][i], M2[j2][i])) for i in range(k)] for j1 in range(lmbda1 * g1) for j2 in range(lmbda2 * g2)] if check and not is_difference_matrix(M, G, k, lmbda, True): raise RuntimeError( "In the product construction, Sage built something which is not a ({},{},{})-DM!" .format(g, k, lmbda)) return G, M
def difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=True): r""" Return the product of the ``(G1,k,lmbda1)`` and ``(G2,k,lmbda2)`` difference matrices ``M1`` and ``M2``. The result is a `(G1 \times G2, k, \lambda_1 \lambda_2)`-difference matrix. INPUT: - ``k,lmbda1,lmbda2`` -- positive integer - ``G1, G2`` -- groups - ``M1, M2`` -- ``(G1,k,lmbda1)`` and ``(G,k,lmbda2)`` difference matrices - ``check`` (boolean) -- if ``True`` (default), the output is checked before being returned. EXAMPLES:: sage: from sage.combinat.designs.difference_matrices import ( ....: difference_matrix_product, ....: is_difference_matrix) sage: G1,M1 = designs.difference_matrix(11,6) sage: G2,M2 = designs.difference_matrix(7,6) sage: G,M = difference_matrix_product(6,M1,G1,1,M2,G2,1) sage: G1 Finite Field of size 11 sage: G2 Finite Field of size 7 sage: G The Cartesian product of (Finite Field of size 11, Finite Field of size 7) sage: is_difference_matrix(M,G,6,1) True """ g1 = G1.cardinality() g2 = G2.cardinality() g = g1 * g2 lmbda = lmbda1 * lmbda2 from sage.categories.cartesian_product import cartesian_product G = cartesian_product([G1, G2]) M = [[G((M1[j1][i], M2[j2][i])) for i in range(k)] for j1 in range(lmbda1 * g1) for j2 in range(lmbda2 * g2)] if check and not is_difference_matrix(M, G, k, lmbda, True): raise RuntimeError( "In the product construction, Sage built something which is not a ({},{},{})-DM!".format(g, k, lmbda) ) return G, M
def __init__(self, R, n, r, inert=0): names = ["x%s%s" % (i, j) for i in range(r) for j in range(n)] + [ "theta%s%s" % (i, j) for i in range(inert) for j in range(n) ] P = PolynomialRing(R, n * (r + inert), names) IsomorphicObject.__init__(self, P, Algebras(R)) self._n = n self._r = r self._inert = inert self._P = P self._R = R self._grading_set = cartesian_product([ZZ for i in range(r)]) self._hilbert_parent = PolynomialRing(ZZ, r, 'q')
def monoid_generators(self): """ Return the generators of ``self``. EXAMPLES:: sage: M = Monoids.free([1,2,3]) sage: N = Monoids.free(['a','b']) sage: C = cartesian_product([M, N]) sage: C.monoid_generators() Family ((F[1], 1), (F[2], 1), (F[3], 1), (1, F['a']), (1, F['b'])) An example with an infinitely generated group (a better output is needed):: sage: N = Monoids.free(ZZ) sage: C = cartesian_product([M, N]) sage: C.monoid_generators() Lazy family (gen(i))_{i in The Cartesian product of (...)} """ F = self.cartesian_factors() ids = tuple(M.one() for M in F) def lift(i, gen): cur = list(ids) cur[i] = gen return self._cartesian_product_of_elements(cur) from sage.sets.family import Family # Finitely generated cat = FiniteEnumeratedSets() if all(M.monoid_generators() in cat or isinstance(M.monoid_generators(), (tuple, list)) for M in F): ret = [ lift(i, gen) for i, M in enumerate(F) for gen in M.monoid_generators() ] return Family(ret) # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things from sage.categories.cartesian_product import cartesian_product gens_prod = cartesian_product([ Family(M.monoid_generators(), lambda g: (i, g)) for i, M in enumerate(F) ]) return Family(gens_prod, lift, name="gen")
def example(self): """ EXAMPLES:: sage: Sets().CartesianProducts().example() The cartesian product of (Set of prime numbers (basic implementation), An example of an infinite enumerated set: the non negative integers, An example of a finite enumerated set: {1,2,3}) """ from finite_enumerated_sets import FiniteEnumeratedSets from infinite_enumerated_sets import InfiniteEnumeratedSets from cartesian_product import cartesian_product S1 = Sets().example() S2 = InfiniteEnumeratedSets().example() S3 = FiniteEnumeratedSets().example() return cartesian_product([S1, S2, S3])
def _test_cartesian_product(self, tester=None, **options): from sage.misc.sage_unittest import TestSuite from sage.misc.lazy_format import LazyFormat if hasattr(self, "_suspension_tested"): return # avoids infinity test cycle is_sub_testsuite = tester is not None tester = self._tester(tester=tester, **options) myatt = "_ycp_cartesian_product_tested" if not hasattr(self, myatt): X = cartesian_product((self, self)) setattr(X, myatt, "yo") try: tester.info( "\n Running the test suite of (self (+) self)") TestSuite(X).run( verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite, ) f = X.cartesian_projection(0) tester.info( "\n Running the test suite of the projection (self (+) self) -> self" ) TestSuite(f).run( verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite, skip=[ "_test_category", "_test_nonzero_equal", "_test_pickling", ], ) f = X.summand_embedding(1) tester.info( "\n Running the test suite of the embedding self -> (self (+) self)" ) TestSuite(f).run( verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite, skip=[ "_test_category", "_test_nonzero_equal", "_test_pickling", ], ) finally: delattr(X, myatt)
def monoid_generators(self): """ Return the generators of ``self``. EXAMPLES:: sage: M = Monoids.free([1,2,3]) sage: N = Monoids.free(['a','b']) sage: C = cartesian_product([M, N]) sage: C.monoid_generators() Family ((F[1], 1), (F[2], 1), (F[3], 1), (1, F['a']), (1, F['b'])) An example with an infinitely generated group (a better output is needed):: sage: N = Monoids.free(ZZ) sage: C = cartesian_product([M, N]) sage: C.monoid_generators() Lazy family (gen(i))_{i in The Cartesian product of (...)} """ F = self.cartesian_factors() ids = tuple(M.one() for M in F) def lift(i, gen): cur = list(ids) cur[i] = gen return self._cartesian_product_of_elements(cur) from sage.sets.family import Family # Finitely generated cat = FiniteEnumeratedSets() if all(M.monoid_generators() in cat or isinstance(M.monoid_generators(), (tuple, list)) for M in F): ret = [lift(i, gen) for i, M in enumerate(F) for gen in M.monoid_generators()] return Family(ret) # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things from sage.categories.cartesian_product import cartesian_product gens_prod = cartesian_product( [Family(M.monoid_generators(), lambda g: (i, g)) for i, M in enumerate(F)] ) return Family(gens_prod, lift, name="gen")
def __init__(self, R): """ Initialize ``self``. EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, oo) sage: TestSuite(L).run() sage: L.p(1).bracket(L.q(1)) == L.z() True sage: L.q(1).bracket(L.p(1)) == -L.z() True """ S = cartesian_product([PositiveIntegers(), ['p','q']]) cat = LieAlgebras(R).Nilpotent().WithBasis() LieAlgebraWithGenerators.__init__(self, R, index_set=S, category=cat) HeisenbergAlgebra_abstract.__init__(self, S)
def __init__(self, R): """ Initialize ``self``. EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, oo) sage: TestSuite(L).run() sage: L.p(1).bracket(L.q(1)) == L.z() True sage: L.q(1).bracket(L.p(1)) == -L.z() True """ S = cartesian_product([PositiveIntegers(), ['p', 'q']]) cat = LieAlgebras(R).Nilpotent().WithBasis() LieAlgebraWithGenerators.__init__(self, R, index_set=S, category=cat) HeisenbergAlgebra_abstract.__init__(self, S)
def __init__(self, R, q): r""" Initialize ``self``. EXAMPLES:: sage: AW = algebras.AskeyWilson(QQ) sage: TestSuite(AW).run() # long time """ self._q = q cat = Algebras(Rings().Commutative()).WithBasis() indices = cartesian_product([NonNegativeIntegers()]*6) CombinatorialFreeModule.__init__(self, R, indices, prefix='AW', sorting_key=_basis_key, sorting_reverse=True, category=cat) self._assign_names('A,B,C,a,b,g')
def cartesian_product(*elements): """ Returns the cartesian product of its arguments, as an element of the cartesian product of the parents of those elements. EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) sage: A = C.example() sage: (a,b,c) = A.algebra_generators() sage: a.cartesian_product(b, c) B[(0, word: a)] + B[(1, word: b)] + B[(2, word: c)] FIXME: is this a policy that we want to enforce on all parents? """ from sage.structure.element import parent, Element assert(all(isinstance(element, Element) for element in elements)) parents = [parent(element) for element in elements] return cartesian_product(parents)._cartesian_product_of_elements(elements) # good name???
def _init_product(self): """ Initialization for the tensor product EXAMPLES:: sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2) sage: S = VectorCollection([(1,), (-1,)], QQ, 1) sage: R_tensor_S = TensorOperation([R,S], operation='product') sage: sorted(R_tensor_S._index_map.iteritems()) # indirect doctest [((0, 0), 0), ((0, 1), 1), ((1, 0), 2), ((1, 1), 3), ((2, 0), 3), ((2, 1), 2)] """ V_list_indices = [range(V.n_vectors()) for V in self._V] from sage.categories.cartesian_product import cartesian_product for i in cartesian_product(V_list_indices): self._index_map[tuple(i)] = self._init_product_vectors(i) self._symmetrize_indices = False
def add_degrees_symmetric(gen_deg, op_deg): """ Compute the sum componentwise of the lists of integrers contained in d1 and d2 and return an ordered grading set and the partition contained in d2 as result. INPUT: - ``d1`` -- list containing a list of integers and a partition - ``d2`` -- list of integers EXAMPLES:: sage: d1 = ([0,3],[2,1]) sage: d2 = [0,-1] sage: add_degrees_symmetric(d1, d2) ((2, 0), [2, 1]) sage: add_degrees_symmetric(([2,0,1],[3,2]), [-1,0,0]) ((1, 1, 0), [3, 2]) """ D = cartesian_product([ZZ for i in range(len(gen_deg[0]))]) d1, d2 = add_degrees_isotypic(gen_deg, op_deg) return D(sorted(d1, reverse=True)), d2
def cartesian_product(*elements): """ Returns the cartesian product of its arguments, as an element of the cartesian product of the parents of those elements. EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) sage: A = C.example() sage: (a,b,c) = A.algebra_generators() sage: a.cartesian_product(b, c) B[(0, word: a)] + B[(1, word: b)] + B[(2, word: c)] FIXME: is this a policy that we want to enforce on all parents? """ from sage.structure.element import parent, Element assert (all(isinstance(element, Element) for element in elements)) parents = [parent(element) for element in elements] return cartesian_product(parents)._cartesian_product_of_elements( elements) # good name???
def basis(self): """ Return the basis of ``self``. EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.basis() Lazy family (basis map(i))_{i in Disjoint union of Family ({'z'}, The Cartesian product of (Positive integers, {'p', 'q'}))} sage: L.basis()['z'] z sage: L.basis()[(12, 'p')] p12 """ S = cartesian_product([PositiveIntegers(), ['p','q']]) I = DisjointUnionEnumeratedSets([Set(['z']), S]) def basis_elt(x): if isinstance(x, str): return self.monomial(x) return self.monomial(x[1] + str(x[0])) return Family(I, basis_elt, name="basis map")
def __init__(self, R, cartan_matrix, wt, prefix): """ Initialize ``self``. """ self._cartan_matrix = cartan_matrix self._weight = wt self._d = sum(wt) # Reduced words #red_words = Family(Permutations(self._d), lambda p: tuple(p.reduced_word())) red_words = FiniteEnumeratedSet([tuple(p.reduced_word()) for p in Permutations(self._d)]) red_words.rename("reduced words of S_{}".format(self._d)) # The monomials M = FreeAbelianMonoid(self._d, names=['x%s'%i for i in range(1, self._d+1)]) # Idempotents (i.e. the colors of the strands) index_set = self._cartan_matrix.index_set() P = Permutations(sum([[index_set[i]]*v for i,v in enumerate(wt)],[])) I = cartesian_product([red_words, M, P]) CombinatorialFreeModule.__init__(self, R, I, prefix=prefix, monomial_key=KLRAlgebra._monomial_key, category=Algebras(R).WithBasis().Graded())
def _init_symmetric(self): """ Initialization for the symmetric product. EXAMPLES:: sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2) sage: Sym2_R = TensorOperation([R,R], operation='symmetric') # indirect doctest sage: sorted(Sym2_R._index_map.iteritems()) [((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((1, 1), 3), ((1, 2), 4), ((2, 2), 3)] """ V_list_indices = [range(V.n_vectors()) for V in self._V] Sym = symmetrized_coordinate_sums(self._V[0].dimension(), len(self._V)) from sage.categories.cartesian_product import cartesian_product N = len(V_list_indices) for i in cartesian_product(V_list_indices): if any(i[j - 1] > i[j] for j in range(1, N)): continue self._index_map[tuple(i)] = self._init_power_operation_vectors(i, Sym) self._symmetrize_indices = True
def finer(self): """ Return the set of ordered set partitions which are finer than ``self``. See :meth:`is_finer` for the definition of "finer". EXAMPLES:: sage: C = OrderedSetPartition([[1, 3], [2]]).finer() sage: C.cardinality() 3 sage: C.list() [[{1}, {3}, {2}], [{3}, {1}, {2}], [{1, 3}, {2}]] sage: OrderedSetPartition([]).finer() {[]} sage: W = OrderedSetPartition([[4, 9], [-1, 2]]) sage: W.finer().list() [[{9}, {4}, {2}, {-1}], [{9}, {4}, {-1}, {2}], [{9}, {4}, {-1, 2}], [{4}, {9}, {2}, {-1}], [{4}, {9}, {-1}, {2}], [{4}, {9}, {-1, 2}], [{4, 9}, {2}, {-1}], [{4, 9}, {-1}, {2}], [{4, 9}, {-1, 2}]] """ par = parent(self) if not self: return FiniteEnumeratedSet([self]) else: return FiniteEnumeratedSet([ par(sum((list(i) for i in C), [])) for C in cartesian_product( [OrderedSetPartitions(X) for X in self]) ])
def _construct_spx(r, s, multiedges = None, **kargs): r""" Construct a SPX(2, r, s) graph. Return a tuple containing the data that can be used to construct the requested SPX graph, and a boolean indicating whether the constructed graph should be considered a multigraph. INPUT: - ``r`` - the ``r`` parameter indicating the range of the counter. - ``s`` - the ``s`` parameter indicating the length of the string. - ``multiedges`` - whether the constructed graph should be considered a multigraph. If ``None`` (default), the second element of the output will be set to ``True`` when ``r = 1``. If ``False`` and ``r = 1``, a ``ValueError`` is raised. Otherwise, the second element of the output will be ``multiedges``. - any other named parameters are silently ignored. """ c = [tuple(x) for x in cartesian_product([[tuple(y) for y in Integers(2)**Integer(s)], Integers(r), [Integer(1), Integer(-1)]])] if r == 1: if multiedges is False: raise ValueError("A SPX graph with r = 1 has multiple edges") data = sum([[((v, n, t), (v, n, -t)), ((v, n, t), (v[1:] + (Integer(0),), n, -t)), ((v, n, t), (v[1:] + (Integer(1),), n, -t))] for v, n, t in c if t == 1], []) multiedges = True else: data = [c, spx_adj] return (data, multiedges)
def finer(self): """ Return the set of ordered set partitions which are finer than ``self``. See :meth:`is_finer` for the definition of "finer". EXAMPLES:: sage: C = OrderedSetPartition([[1, 3], [2]]).finer() sage: C.cardinality() 3 sage: C.list() [[{1}, {3}, {2}], [{3}, {1}, {2}], [{1, 3}, {2}]] sage: OrderedSetPartition([]).finer() {[]} sage: W = OrderedSetPartition([[4, 9], [-1, 2]]) sage: W.finer().list() [[{9}, {4}, {2}, {-1}], [{9}, {4}, {-1}, {2}], [{9}, {4}, {-1, 2}], [{4}, {9}, {2}, {-1}], [{4}, {9}, {-1}, {2}], [{4}, {9}, {-1, 2}], [{4, 9}, {2}, {-1}], [{4, 9}, {-1}, {2}], [{4, 9}, {-1, 2}]] """ par = parent(self) if not self: return FiniteEnumeratedSet([self]) else: return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) for C in cartesian_product([OrderedSetPartitions(X) for X in self])])
def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, precision=None, normalized=True): r""" Return the asymptotic expansion of the coefficients of an power series with specified pole and logarithmic singularity. More precisely, this extracts the `n`-th coefficient .. MATH:: [z^n] \left(\frac{1}{1-z/\zeta}\right)^\alpha \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)^\beta \left(\frac{1}{z/\zeta} \log \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)\right)^\delta (if ``normalized=True``, the default) or .. MATH:: [z^n] \left(\frac{1}{1-z/\zeta}\right)^\alpha \left(\log \frac{1}{1-z/\zeta}\right)^\beta \left(\log \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)\right)^\delta (if ``normalized=False``). INPUT: - ``var`` -- a string for the variable name. - ``zeta`` -- (default: `1`) the location of the singularity. - ``alpha`` -- (default: `0`) the pole order of the singularty. - ``beta`` -- (default: `0`) the order of the logarithmic singularity. - ``delta`` -- (default: `0`) the order of the log-log singularity. Not yet implemented for ``delta != 0``. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. - ``normalized`` -- (default: ``True``) a boolean, see above. OUTPUT: An asymptotic expansion. EXAMPLES:: sage: asymptotic_expansions.SingularityAnalysis('n', alpha=1) 1 sage: asymptotic_expansions.SingularityAnalysis('n', alpha=2) n + 1 sage: asymptotic_expansions.SingularityAnalysis('n', alpha=3) 1/2*n^2 + 3/2*n + 1 sage: _.parent() Asymptotic Ring <n^ZZ> over Rational Field :: sage: asymptotic_expansions.SingularityAnalysis('n', alpha=-3/2, ....: precision=3) 3/4/sqrt(pi)*n^(-5/2) + 45/32/sqrt(pi)*n^(-7/2) + 1155/512/sqrt(pi)*n^(-9/2) + O(n^(-11/2)) sage: asymptotic_expansions.SingularityAnalysis('n', alpha=-1/2, ....: precision=3) -1/2/sqrt(pi)*n^(-3/2) - 3/16/sqrt(pi)*n^(-5/2) - 25/256/sqrt(pi)*n^(-7/2) + O(n^(-9/2)) sage: asymptotic_expansions.SingularityAnalysis('n', alpha=1/2, ....: precision=4) 1/sqrt(pi)*n^(-1/2) - 1/8/sqrt(pi)*n^(-3/2) + 1/128/sqrt(pi)*n^(-5/2) + 5/1024/sqrt(pi)*n^(-7/2) + O(n^(-9/2)) sage: _.parent() Asymptotic Ring <n^QQ> over Symbolic Constants Subring :: sage: S = SR.subring(rejecting_variables=('n',)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=S.var('a'), ....: precision=4).map_coefficients(lambda c: c.factor()) 1/gamma(a)*n^(a - 1) + (1/2*(a - 1)*a/gamma(a))*n^(a - 2) + (1/24*(3*a - 1)*(a - 1)*(a - 2)*a/gamma(a))*n^(a - 3) + (1/48*(a - 1)^2*(a - 2)*(a - 3)*a^2/gamma(a))*n^(a - 4) + O(n^(a - 5)) sage: _.parent() Asymptotic Ring <n^(Symbolic Subring rejecting the variable n)> over Symbolic Subring rejecting the variable n :: sage: ae = asymptotic_expansions.SingularityAnalysis('n', ....: alpha=1/2, beta=1, precision=4); ae 1/sqrt(pi)*n^(-1/2)*log(n) + ((euler_gamma + 2*log(2))/sqrt(pi))*n^(-1/2) - 5/8/sqrt(pi)*n^(-3/2)*log(n) + (1/8*(3*euler_gamma + 6*log(2) - 8)/sqrt(pi) - (euler_gamma + 2*log(2) - 2)/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) sage: n = ae.parent().gen() sage: ae.subs(n=n-1).map_coefficients(lambda x: x.canonicalize_radical()) 1/sqrt(pi)*n^(-1/2)*log(n) + ((euler_gamma + 2*log(2))/sqrt(pi))*n^(-1/2) - 1/8/sqrt(pi)*n^(-3/2)*log(n) + (-1/8*(euler_gamma + 2*log(2))/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) :: sage: asymptotic_expansions.SingularityAnalysis('n', ....: alpha=1, beta=1/2, precision=4) log(n)^(1/2) + 1/2*euler_gamma*log(n)^(-1/2) + (-1/8*euler_gamma^2 + 1/48*pi^2)*log(n)^(-3/2) + (1/16*euler_gamma^3 - 1/32*euler_gamma*pi^2 + 1/8*zeta(3))*log(n)^(-5/2) + O(log(n)^(-7/2)) :: sage: ae = asymptotic_expansions.SingularityAnalysis('n', ....: alpha=0, beta=2, precision=14) sage: n = ae.parent().gen() sage: ae.subs(n=n-2) 2*n^(-1)*log(n) + 2*euler_gamma*n^(-1) - n^(-2) - 1/6*n^(-3) + O(n^(-5)) :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=-1/2, beta=1, precision=2, normalized=False) -1/2/sqrt(pi)*n^(-3/2)*log(n) + (-1/2*(euler_gamma + 2*log(2) - 2)/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1/2, alpha=0, beta=1, precision=3, normalized=False) 2^n*n^(-1) + O(2^n*n^(-2)) ALGORITHM: See [FS2009]_ together with the `errata list <http://algo.inria.fr/flajolet/Publications/AnaCombi/errata.pdf>`_. REFERENCES: .. [FS2009] Philippe Flajolet and Robert Sedgewick, `Analytic combinatorics <http://algo.inria.fr/flajolet/Publications/AnaCombi/book.pdf>`_. Cambridge University Press, Cambridge, 2009. TESTS:: sage: ex = asymptotic_expansions.SingularityAnalysis('n', alpha=-1/2, ....: precision=4) sage: n = ex.parent().gen() sage: coefficients = ((1-x)^(1/2)).series( ....: x, 21).truncate().coefficients(x, sparse=False) sage: ex.compare_with_values(n, # rel tol 1e-6 ....: lambda k: coefficients[k], [5, 10, 20]) [(5, 0.015778873294?), (10, 0.01498952777?), (20, 0.0146264622?)] sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=2) 1/2*n^2 + 3/2*n + O(1) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=3) 1/2*n^2 + 3/2*n + 1 sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=4) 1/2*n^2 + 3/2*n + 1 :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=0) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'm', alpha=-1/2, precision=3) -1/2/sqrt(pi)*m^(-3/2) - 3/16/sqrt(pi)*m^(-5/2) - 25/256/sqrt(pi)*m^(-7/2) + O(m^(-9/2)) sage: _.parent() Asymptotic Ring <m^QQ> over Symbolic Constants Subring Location of the singularity:: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=2, precision=3) (1/2)^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=1/2, precision=3) 2^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=CyclotomicField(3).gen(), ....: precision=3) (-zeta3 - 1)^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=4, zeta=2, precision=3) 1/6*(1/2)^n*n^3 + (1/2)^n*n^2 + 11/6*(1/2)^n*n + O((1/2)^n) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1, zeta=2, precision=3) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1/2, zeta=2, precision=3) 1/sqrt(pi)*(1/2)^n*n^(-1/2) - 1/8/sqrt(pi)*(1/2)^n*n^(-3/2) + 1/128/sqrt(pi)*(1/2)^n*n^(-5/2) + O((1/2)^n*n^(-7/2)) The following tests correspond to Table VI.5 in [FS2009]_. :: sage: A.<n> = AsymptoticRing('n^QQ * log(n)^QQ', QQ) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=-1/2, beta=1, precision=2, ....: normalized=False) * (- sqrt(pi*n^3)) 1/2*log(n) + 1/2*euler_gamma + log(2) - 1 + O(n^(-1)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=0, beta=1, precision=3, ....: normalized=False) n^(-1) + O(n^(-2)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=0, beta=2, precision=14, ....: normalized=False) * n 2*log(n) + 2*euler_gamma - n^(-1) - 1/6*n^(-2) + O(n^(-4)) sage: (asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1/2, beta=1, precision=4, ....: normalized=False) * sqrt(pi*n)).\ ....: map_coefficients(lambda x: x.expand()) log(n) + euler_gamma + 2*log(2) - 1/8*n^(-1)*log(n) + (-1/8*euler_gamma - 1/4*log(2))*n^(-1) + O(n^(-2)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1, beta=1, precision=13, ....: normalized=False) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1, beta=2, precision=4, ....: normalized=False) log(n)^2 + 2*euler_gamma*log(n) + euler_gamma^2 - 1/6*pi^2 + O(n^(-1)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=3/2, beta=1, precision=3, ....: normalized=False) * sqrt(pi/n) 2*log(n) + 2*euler_gamma + 4*log(2) - 4 + 3/4*n^(-1)*log(n) + O(n^(-1)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=2, beta=1, precision=5, ....: normalized=False) n*log(n) + (euler_gamma - 1)*n + log(n) + euler_gamma + 1/2 + O(n^(-1)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=2, beta=2, precision=4, ....: normalized=False) / n log(n)^2 + (2*euler_gamma - 2)*log(n) - 2*euler_gamma + euler_gamma^2 - 1/6*pi^2 + 2 + n^(-1)*log(n)^2 + O(n^(-1)*log(n)) Be aware that the last result does *not* coincide with [FS2009]_, they do have a different error term. Checking parameters:: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, 1, 1/2, precision=0, normalized=False) Traceback (most recent call last): ... ValueError: beta and delta must be integers sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, 1, 1, 1/2, normalized=False) Traceback (most recent call last): ... ValueError: beta and delta must be integers :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=0, beta=0, delta=1, precision=3) Traceback (most recent call last): ... NotImplementedError: not implemented for delta!=0 """ from itertools import islice, count from asymptotic_ring import AsymptoticRing from growth_group import ExponentialGrowthGroup, \ MonomialGrowthGroup from sage.arith.all import falling_factorial from sage.categories.cartesian_product import cartesian_product from sage.functions.other import binomial, gamma from sage.calculus.calculus import limit from sage.misc.cachefunc import cached_function from sage.arith.srange import srange from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.symbolic.ring import SR SCR = SR.subring(no_variables=True) s = SR('s') iga = 1/gamma(alpha) if iga.parent() is SR: try: iga = SCR(iga) except TypeError: pass coefficient_ring = iga.parent() if beta != 0: coefficient_ring = SCR @cached_function def inverse_gamma_derivative(shift, r): """ Return value of `r`-th derivative of 1/Gamma at alpha-shift. """ if r == 0: result = iga*falling_factorial(alpha-1, shift) else: result = limit((1/gamma(s)).diff(s, r), s=alpha-shift) try: return coefficient_ring(result) except TypeError: return result if isinstance(alpha, int): alpha = ZZ(alpha) if isinstance(beta, int): beta = ZZ(beta) if isinstance(delta, int): delta = ZZ(delta) if precision is None: precision = AsymptoticRing.__default_prec__ if not normalized and not (beta in ZZ and delta in ZZ): raise ValueError("beta and delta must be integers") if delta != 0: raise NotImplementedError("not implemented for delta!=0") groups = [] if zeta != 1: groups.append(ExponentialGrowthGroup((1/zeta).parent(), var)) groups.append(MonomialGrowthGroup(alpha.parent(), var)) if beta != 0: groups.append(MonomialGrowthGroup(beta.parent(), 'log({})'.format(var))) group = cartesian_product(groups) A = AsymptoticRing(growth_group=group, coefficient_ring=coefficient_ring, default_prec=precision) n = A.gen() if zeta == 1: exponential_factor = 1 else: exponential_factor = n.rpow(1/zeta) if beta in ZZ and beta >= 0: it = ((k, r) for k in count() for r in srange(beta+1)) k_max = precision else: it = ((0, r) for r in count()) k_max = 0 if beta != 0: log_n = n.log() else: # avoid construction of log(n) # because it does not exist in growth group. log_n = 1 it = reversed(list(islice(it, precision+1))) if normalized: beta_denominator = beta else: beta_denominator = 0 L = _sa_coefficients_lambda_(max(1, k_max), beta=beta_denominator) (k, r) = next(it) result = (n**(-k) * log_n**(-r)).O() if alpha in ZZ and beta == 0: if alpha > 0 and alpha <= precision: result = A(0) elif alpha <= 0 and precision > 0: from misc import NotImplementedOZero raise NotImplementedOZero(A) for (k, r) in it: result += binomial(beta, r) * \ sum(L[(k, ell)] * (-1)**ell * inverse_gamma_derivative(ell, r) for ell in srange(k, 2*k+1) if (k, ell) in L) * \ n**(-k) * log_n**(-r) result *= exponential_factor * n**(alpha-1) * log_n**beta return result
def mcfarland_1973_construction(q, s): r""" Return a difference set. The difference set returned has the following parameters .. MATH:: v = \frac{q^{s+1}(q^{s+1}+q-2)}{q-1}, k = \frac{q^s (q^{s+1}-1)}{q-1}, \lambda = \frac{q^s(q^s-1)}{q-1} This construction is due to [McF1973]_. INPUT: - ``q``, ``s`` - (integers) parameters for the difference set (see the above formulas for the expression of ``v``, ``k``, ``l`` in terms of ``q`` and ``s``) .. SEEALSO:: The function :func:`are_mcfarland_1973_parameters` makes the translation between the parameters `(q,s)` corresponding to a given triple `(v,k,\lambda)`. REFERENCES: .. [McF1973] Robert L. McFarland "A family of difference sets in non-cyclic groups" Journal of Combinatorial Theory (A) vol 15 (1973). http://dx.doi.org/10.1016/0097-3165(73)90031-9 EXAMPLES:: sage: from sage.combinat.designs.difference_family import ( ....: mcfarland_1973_construction, is_difference_family) sage: G,D = mcfarland_1973_construction(3, 1) sage: assert is_difference_family(G, D, 45, 12, 3) sage: G,D = mcfarland_1973_construction(2, 2) sage: assert is_difference_family(G, D, 64, 28, 12) """ from sage.rings.finite_rings.finite_field_constructor import GF from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.categories.cartesian_product import cartesian_product from itertools import izip r = (q**(s+1)-1) // (q-1) F = GF(q,'a') V = VectorSpace(F, s+1) K = Zmod(r+1) G = cartesian_product([F]*(s+1) + [K]) D = [] for k,H in izip(K, V.subspaces(s)): for v in H: D.append(G((tuple(v) + (k,)))) return G,[D]
def _pushout_(self, other): r""" Construct the pushout of this and the other growth group. This is called by :func:`sage.categories.pushout.pushout`. TESTS:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.categories.pushout import pushout sage: cm = sage.structure.element.get_coercion_model() sage: A = GrowthGroup('QQ^x * x^ZZ') sage: B = GrowthGroup('x^ZZ * log(x)^ZZ') sage: A._pushout_(B) Growth Group QQ^x * x^ZZ * log(x)^ZZ sage: pushout(A, B) Growth Group QQ^x * x^ZZ * log(x)^ZZ sage: cm.discover_coercion(A, B) ((map internal to coercion system -- copy before use) Conversion map: From: Growth Group QQ^x * x^ZZ To: Growth Group QQ^x * x^ZZ * log(x)^ZZ, (map internal to coercion system -- copy before use) Conversion map: From: Growth Group x^ZZ * log(x)^ZZ To: Growth Group QQ^x * x^ZZ * log(x)^ZZ) sage: cm.common_parent(A, B) Growth Group QQ^x * x^ZZ * log(x)^ZZ :: sage: C = GrowthGroup('QQ^x * x^QQ * y^ZZ') sage: D = GrowthGroup('x^ZZ * log(x)^QQ * QQ^z') sage: C._pushout_(D) Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z sage: cm.common_parent(C, D) Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z sage: A._pushout_(D) Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z sage: cm.common_parent(A, D) Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z sage: cm.common_parent(B, D) Growth Group x^ZZ * log(x)^QQ * QQ^z sage: cm.common_parent(A, C) Growth Group QQ^x * x^QQ * y^ZZ sage: E = GrowthGroup('log(x)^ZZ * y^ZZ') sage: cm.common_parent(A, E) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Growth Group QQ^x * x^ZZ' and 'Growth Group log(x)^ZZ * y^ZZ' :: sage: F = GrowthGroup('z^QQ') sage: pushout(C, F) Growth Group QQ^x * x^QQ * y^ZZ * z^QQ :: sage: pushout(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ')) Growth Group QQ^x * x^QQ sage: cm.common_parent(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ')) Growth Group QQ^x * x^QQ """ from growth_group import GenericGrowthGroup, AbstractGrowthGroupFunctor from misc import merge_overlapping from misc import underlying_class if isinstance(other, GenericProduct): Ofactors = other.cartesian_factors() elif isinstance(other, GenericGrowthGroup): Ofactors = (other,) elif other.construction() is not None and isinstance(other.construction()[0], AbstractGrowthGroupFunctor): Ofactors = (other,) else: return def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): try: return merge_overlapping(Sfactors, Ofactors, lambda f: (underlying_class(f), f._var_.var_repr)) except ValueError: pass cm = sage.structure.element.get_coercion_model() try: Z = cm.common_parent(*Sfactors + Ofactors) return (Z,), (Z,) except TypeError: pass def subfactors(F): for f in F: if isinstance(f, GenericProduct): for g in subfactors(f.cartesian_factors()): yield g else: yield f try: return merge_overlapping( tuple(subfactors(Sfactors)), tuple(subfactors(Ofactors)), lambda f: (underlying_class(f), f._var_.var_repr), ) except ValueError: pass from sage.structure.coerce_exceptions import CoercionException raise CoercionException( "Cannot construct the pushout of %s and %s: The factors " "with variables %s are not overlapping, " "no common parent was found, and " "splitting the factors was unsuccessful." % (self, other, var) ) class it: def __init__(self, it): self.it = it self.var = None self.factors = None def next(self): try: self.var, factors = next(self.it) self.factors = tuple(factors) except StopIteration: self.var = None self.factors = tuple() from itertools import groupby S = it(groupby(self.cartesian_factors(), key=lambda k: k.variable_names())) O = it(groupby(Ofactors, key=lambda k: k.variable_names())) newS = [] newO = [] S.next() O.next() while S.var is not None or O.var is not None: if S.var is not None and S.var < O.var: newS.extend(S.factors) newO.extend(S.factors) S.next() elif O.var is not None and S.var > O.var: newS.extend(O.factors) newO.extend(O.factors) O.next() else: SL, OL = pushout_univariate_factors(self, other, S.var, S.factors, O.factors) newS.extend(SL) newO.extend(OL) S.next() O.next() assert len(newS) == len(newO) if len(self.cartesian_factors()) == len(newS) and len(other.cartesian_factors()) == len(newO): # We had already all factors in each of the self and # other, thus splitting it in subproblems (one for # each factor) is the strategy to use. If a pushout is # possible :func:`sage.categories.pushout.pushout` # will manage this by itself. return from sage.categories.pushout import pushout from sage.categories.cartesian_product import cartesian_product return pushout(cartesian_product(newS), cartesian_product(newO))
def polygon_labels(self): from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.categories.cartesian_product import cartesian_product return cartesian_product([self._words, FiniteEnumeratedSet([0,1,2,3])])
def CartesianProduct(*iters): """ This is deprecated. Use :obj:`cartesian_product` instead. EXAMPLES:: sage: cp = CartesianProduct([1,2], [3,4]); cp doctest:...: DeprecationWarning: CartesianProduct is deprecated. Use cartesian_product instead See http://trac.sagemath.org/18411 for details. The Cartesian product of ({1, 2}, {3, 4}) sage: cp.list() [(1, 3), (1, 4), (2, 3), (2, 4)] Note that you must not use a generator-type object that is returned by a function (using "yield"). They cannot be copied or rewound (you cannot jump back to the beginning), but this is necessary to construct the Cartesian product:: sage: def a(n): yield 1*n; yield 2*n sage: def b(): yield 'a'; yield 'b' sage: CartesianProduct(a(3), b()).list() Traceback (most recent call last): ... ValueError: generators are not allowed, see the documentation (type "CartesianProduct?") for a workaround The usage of iterable is also deprecated, so the following will no longer be supported:: sage: from sage.combinat.misc import IterableFunctionCall sage: C = CartesianProduct(IterableFunctionCall(a, 3), IterableFunctionCall(b)) doctest:...: DeprecationWarning: Usage of IterableFunctionCall in CartesianProduct is deprecated. You can use EnumeratedSetFromIterator (in sage.sets.set_from_iterator) instead. See http://trac.sagemath.org/18411 for details. sage: list(C) 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. [(3, 'a'), (3, 'b'), (6, 'a'), (6, 'b')] You might use :class:`~sage.sets.set_from_iterator.EnumeratedSetFromIterator` for that purpose.:: sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator sage: A = EnumeratedSetFromIterator(a, (3,), category=FiniteEnumeratedSets()) sage: B = EnumeratedSetFromIterator(b, category=FiniteEnumeratedSets()) sage: C = cartesian_product([A, B]) sage: C.list() [(3, 'a'), (3, 'b'), (6, 'a'), (6, 'b')] """ if any(isgenerator(i) for i in iters): raise ValueError('generators are not allowed, see the documentation '+ '(type "CartesianProduct?") for a workaround') from sage.misc.superseded import deprecation deprecation(18411, "CartesianProduct is deprecated. Use cartesian_product instead") from sage.combinat.misc import IterableFunctionCall deprecate_ifc = False iiters = [] for a in iters: if isinstance(a, IterableFunctionCall): deprecate_ifc = True iiters.append(EnumeratedSetFromIterator(a.f, a.args, a.kwargs)) else: iiters.append(a) iters = tuple(iiters) if deprecate_ifc: deprecation(18411, """Usage of IterableFunctionCall in CartesianProduct is deprecated. You can use EnumeratedSetFromIterator (in sage.sets.set_from_iterator) instead.""") from sage.categories.cartesian_product import cartesian_product return cartesian_product(iters)
def difference_family(v, k, l=1, existence=False, explain_construction=False, check=True): r""" Return a (``k``, ``l``)-difference family on an Abelian group of cardinality ``v``. Let `G` be a finite Abelian group. For a given subset `D` of `G`, we define `\Delta D` to be the multi-set of differences `\Delta D = \{x - y; x \in D, y \in D, x \not= y\}`. A `(G,k,\lambda)`-*difference family* is a collection of `k`-subsets of `G`, `D = \{D_1, D_2, \ldots, D_b\}` such that the union of the difference sets `\Delta D_i` for `i=1,...b`, seen as a multi-set, contains each element of `G \backslash \{0\}` exactly `\lambda`-times. When there is only one block, i.e. `\lambda(v - 1) = k(k-1)`, then a `(G,k,\lambda)`-difference family is also called a *difference set*. See also :wikipedia:`Difference_set`. If there is no such difference family, an ``EmptySetError`` is raised and if there is no construction at the moment ``NotImplementedError`` is raised. INPUT: - ``v,k,l`` -- parameters of the difference family. If ``l`` is not provided it is assumed to be ``1``. - ``existence`` -- if ``True``, then return either ``True`` if Sage knows how to build such design, ``Unknown`` if it does not and ``False`` if it knows that the design does not exist.. - ``explain_construction`` -- instead of returning a difference family, returns a string that explains the construction used. - ``check`` -- boolean (default: ``True``). If ``True`` then the result of the computation is checked before being returned. This should not be needed but ensures that the output is correct. OUTPUT: A pair ``(G,D)`` made of a group `G` and a difference family `D` on that group. Or, if ``existence`` is ``True`` a troolean or if ``explain_construction`` is ``True`` a string. EXAMPLES:: sage: G,D = designs.difference_family(73,4) sage: G Finite Field of size 73 sage: D [[0, 1, 8, 64], [0, 2, 16, 55], [0, 3, 24, 46], [0, 25, 54, 67], [0, 35, 50, 61], [0, 36, 41, 69]] sage: print designs.difference_family(73, 4, explain_construction=True) Radical difference family on a finite field sage: G,D = designs.difference_family(15,7,3) sage: G The cartesian product of (Finite Field of size 3, Finite Field of size 5) sage: D [[(1, 1), (1, 4), (2, 2), (2, 3), (0, 0), (1, 0), (2, 0)]] sage: print designs.difference_family(15,7,3,explain_construction=True) Twin prime powers difference family sage: print designs.difference_family(91,10,1,explain_construction=True) Singer difference set For `k=6,7` we look at the set of small prime powers for which a construction is available:: sage: def prime_power_mod(r,m): ....: k = m+r ....: while True: ....: if is_prime_power(k): ....: yield k ....: k += m sage: from itertools import islice sage: l6 = {True:[], False: [], Unknown: []} sage: for q in islice(prime_power_mod(1,30), 60): ....: l6[designs.difference_family(q,6,existence=True)].append(q) sage: l6[True] [31, 121, 151, 181, 211, ..., 3061, 3121, 3181] sage: l6[Unknown] [61] sage: l6[False] [] sage: l7 = {True: [], False: [], Unknown: []} sage: for q in islice(prime_power_mod(1,42), 60): ....: l7[designs.difference_family(q,7,existence=True)].append(q) sage: l7[True] [337, 421, 463, 883, 1723, 3067, 3319, 3529, 3823, 3907, 4621, 4957, 5167] sage: l7[Unknown] [43, 127, 169, 211, ..., 4999, 5041, 5209] sage: l7[False] [] List available constructions:: sage: for v in xrange(2,100): ....: constructions = [] ....: for k in xrange(2,10): ....: for l in xrange(1,10): ....: if designs.difference_family(v,k,l,existence=True): ....: constructions.append((k,l)) ....: _ = designs.difference_family(v,k,l) ....: if constructions: ....: print "%2d: %s"%(v, ', '.join('(%d,%d)'%(k,l) for k,l in constructions)) 3: (2,1) 4: (3,2) 5: (2,1), (4,3) 6: (5,4) 7: (2,1), (3,1), (3,2), (4,2), (6,5) 8: (7,6) 9: (2,1), (4,3), (8,7) 10: (9,8) 11: (2,1), (4,6), (5,2), (5,4), (6,3) 13: (2,1), (3,1), (3,2), (4,1), (4,3), (5,5), (6,5) 15: (3,1), (4,6), (5,6), (7,3) 16: (3,2), (5,4), (6,2) 17: (2,1), (4,3), (5,5), (8,7) 19: (2,1), (3,1), (3,2), (4,2), (6,5), (9,4), (9,8) 21: (3,1), (4,3), (5,1), (6,3), (6,5) 22: (4,2), (6,5), (7,4), (8,8) 23: (2,1) 25: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (7,7), (8,7) 27: (2,1), (3,1) 28: (3,2), (6,5) 29: (2,1), (4,3), (7,3), (7,6), (8,4), (8,6) 31: (2,1), (3,1), (3,2), (4,2), (5,2), (5,4), (6,1), (6,5) 33: (3,1), (5,5), (6,5) 34: (4,2) 35: (5,2) 37: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (9,2), (9,8) 39: (3,1), (6,5) 40: (3,2), (4,1) 41: (2,1), (4,3), (5,1), (5,4), (6,3), (8,7) 43: (2,1), (3,1), (3,2), (4,2), (6,5), (7,2), (7,3), (7,6), (8,4) 45: (3,1), (5,1) 46: (4,2), (6,2) 47: (2,1) 49: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (8,7), (9,3) 51: (3,1), (5,2), (6,3) 52: (4,1) 53: (2,1), (4,3) 55: (3,1), (9,4) 57: (3,1), (7,3), (8,1) 59: (2,1) 61: (2,1), (3,1), (3,2), (4,3), (5,1), (5,4), (6,2), (6,3), (6,5) 63: (3,1) 64: (3,2), (4,1), (7,2), (7,6), (9,8) 65: (5,1) 67: (2,1), (3,1), (3,2), (6,5) 69: (3,1) 71: (2,1), (5,2), (5,4), (7,3), (7,6), (8,4) 73: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (8,7), (9,1), (9,8) 75: (3,1), (5,2) 76: (4,1) 79: (2,1), (3,1), (3,2), (6,5) 81: (2,1), (3,1), (4,3), (5,1), (5,4), (8,7) 83: (2,1) 85: (4,1), (7,2), (7,3), (8,2) 89: (2,1), (4,3), (8,7) 91: (6,1) 97: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (8,7), (9,3) TESTS: Check more of the Wilson constructions from [Wi72]_:: sage: Q5 = [241, 281,421,601,641, 661, 701, 821,881] sage: Q9 = [73, 1153, 1873, 2017] sage: Q15 = [76231] sage: Q4 = [13, 73, 97, 109, 181, 229, 241, 277, 337, 409, 421, 457] sage: Q8 = [1009, 3137, 3697] sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]: ....: for q in Q: ....: assert designs.difference_family(q,k,1,existence=True) is True ....: _ = designs.difference_family(q,k,1) Check Singer difference sets:: sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1)) sage: for q in range(2,10): ....: if is_prime_power(q): ....: for d in [2,3,4]: ....: v,k,l = sgp(q,d) ....: assert designs.difference_family(v,k,l,existence=True) is True ....: _ = designs.difference_family(v,k,l) Check twin primes difference sets:: sage: for p in [3,5,7,9,11]: ....: v = p*(p+2); k = (v-1)/2; lmbda = (k-1)/2 ....: G,D = designs.difference_family(v,k,lmbda) Check the database: sage: from sage.combinat.designs.database import DF sage: for v,k,l in DF: ....: df = designs.difference_family(v,k,l,check=True) Check a failing construction (:trac:`17528`): sage: designs.difference_family(9,3) Traceback (most recent call last): ... NotImplementedError: No construction available for (9,3,1)-difference family .. TODO:: Implement recursive constructions from Buratti "Recursive for difference matrices and relative difference families" (1998) and Jungnickel "Composition theorems for difference families and regular planes" (1978) """ from block_design import are_hyperplanes_in_projective_geometry_parameters from database import DF if (v,k,l) in DF: if existence: return True elif explain_construction: return "The database contains a ({},{},{})-difference family".format(v,k,l) vv, blocks = next(DF[v,k,l].iteritems()) # Build the group from sage.rings.finite_rings.integer_mod_ring import Zmod if len(vv) == 1: G = Zmod(vv[0]) else: from sage.categories.cartesian_product import cartesian_product G = cartesian_product([Zmod(i) for i in vv]) df = [[G(i) for i in b] for b in blocks] if check and not is_difference_family(G, df, v=v, k=k, l=l): raise RuntimeError("There is an invalid ({},{},{})-difference " "family in the database... Please contact " "*****@*****.**".format(v,k,l)) return G,df e = k*(k-1) if (l*(v-1)) % e: if existence: return Unknown raise NotImplementedError("No construction available for ({},{},{})-difference family".format(v,k,l)) t = l*(v-1) // e # number of blocks # trivial construction if k == (v-1) and l == (v-2): from sage.rings.finite_rings.integer_mod_ring import Zmod G = Zmod(v) return G, [range(1,v)] factorization = arith.factor(v) D = None if len(factorization) == 1: # i.e. is v a prime power from sage.rings.finite_rings.constructor import GF G = K = GF(v,'z') if radical_difference_family(K, k, l, existence=True): if existence: return True elif explain_construction: return "Radical difference family on a finite field" else: D = radical_difference_family(K,k,l) elif l == 1 and k == 6 and df_q_6_1(K,existence=True): if existence: return True elif explain_construction: return "Wilson 1972 difference family made from the union of two cyclotomic cosets" else: D = df_q_6_1(K) # Twin prime powers construction # i.e. v = p(p+2) where p and p+2 are prime powers # k = (v-1)/2 # lambda = (k-1)/2 (ie 2l+1 = k) elif (k == (v-1)//2 and l == (k-1)//2 and len(factorization) == 2 and abs(pow(*factorization[0]) - pow(*factorization[1])) == 2): if existence: return True elif explain_construction: return "Twin prime powers difference family" else: p = pow(*factorization[0]) q = pow(*factorization[1]) if p > q: p,q = q,p G,D = twin_prime_powers_difference_set(p,check=False) if D is None and are_hyperplanes_in_projective_geometry_parameters(v,k,l): _, (q,d) = are_hyperplanes_in_projective_geometry_parameters(v,k,l,True) if existence: return True elif explain_construction: return "Singer difference set" else: G,D = singer_difference_set(q,d) if D is None: if existence: return Unknown raise NotImplementedError("No constructions for these parameters") if check and not is_difference_family(G,D,v=v,k=k,l=l,verbose=False): raise RuntimeError("There is a problem. Sage built the following " "difference family on G='{}' with parameters ({},{},{}):\n " "{}\nwhich seems to not be a difference family... " "Please contact [email protected]".format(G,v,k,l,D)) return G, D