def hasse_conductor(self): """ This is the product of all primes where the Hasse invariant equals -1 EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.hasse_invariant(2) -1 sage: Q.hasse_invariant(37) -1 sage: Q.hasse_conductor() 74 :: sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() 1 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() 10 """ D = self.disc() return prod( filter(lambda p: self.hasse_invariant(p) == -1, map(lambda x: x[0], factor(2 * self.level()))))
def mumu(N): """ Return 0 if any cube divides `N`. Otherwise return `(-2)^v` where `v` is the number of primes that exactly divide `N`. This is similar to the Moebius function. INPUT: - ``N`` - an integer at least 1 OUTPUT: Integer EXAMPLES:: sage: from sage.modular.arithgroup.congroup_gammaH import mumu sage: mumu(27) 0 sage: mumu(6*25) 4 sage: mumu(7*9*25) -2 sage: mumu(9*25) 1 """ if N < 1: raise ValueError, "N must be at least 1" p = 1 for _,r in factor(N): if r > 2: return ZZ(0) elif r == 1: p *= -2 return ZZ(p)
def multiplicative_order(self): r""" Returns the *multiplicative* order of this element, which must be nonzero. EXAMPLES:: sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari sage: a = FiniteField_ext_pari(5**3, 'a').0 sage: a.multiplicative_order() 124 sage: a**124 1 """ try: return self.__multiplicative_order except AttributeError: if self.is_zero(): raise ArithmeticError("Multiplicative order of 0 not defined.") n = self.parent().order() - 1 order = 1 for p, e in arith.factor(n): # Determine the power of p that divides the order. a = self**(n//(p**e)) while a != 1: order *= p a = a**p self.__multiplicative_order = order return order
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), 'conway', None, '{}', 3, 2, True), {}) sage: GF.create_key_and_extra_args(9, 'a', foo='value') ((9, ('a',), 'conway', None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'}) """ from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() with WithProof('arithmetic', proof): order = int(order) if order <= 1: raise ValueError("the order of a finite field must be > 1.") if arith.is_prime(order): name = None modulus = None p = integer.Integer(order) n = integer.Integer(1) elif arith.is_prime_power(order): if not names is None: name = names name = normalize_names(1, name) p, n = arith.factor(order)[0] if modulus is None or modulus == "default": if exists_conway_polynomial(p, n): modulus = "conway" else: if p == 2: modulus = "minimal_weight" else: modulus = "random" elif modulus == "random": modulus += str(random.randint(0, 1 << 128)) if isinstance(modulus, (list, tuple)): modulus = FiniteField(p)['x'](modulus) # some classes use 'random' as the modulus to # generate a random modulus, but we don't want # to cache it elif sage.rings.polynomial.polynomial_element.is_Polynomial( modulus): modulus = modulus.change_variable_name('x') elif not isinstance(modulus, str): raise ValueError("Modulus parameter not understood.") else: # Neither a prime, nor a prime power raise ValueError( "the order of a finite field must be a prime power.") return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def multiplicative_order(self): r""" Returns the *multiplicative* order of this element, which must be nonzero. EXAMPLES:: sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari sage: a = FiniteField_ext_pari(5**3, 'a').0 sage: a.multiplicative_order() 124 sage: a**124 1 """ try: return self.__multiplicative_order except AttributeError: if self.is_zero(): raise ArithmeticError("Multiplicative order of 0 not defined.") n = self.parent().order() - 1 order = 1 for p, e in arith.factor(n): # Determine the power of p that divides the order. a = self**(n // (p**e)) while a != 1: order *= p a = a**p self.__multiplicative_order = order return order
def mumu(N): """ Return 0 if any cube divides `N`. Otherwise return `(-2)^v` where `v` is the number of primes that exactly divide `N`. This is similar to the Moebius function. INPUT: - ``N`` - an integer at least 1 OUTPUT: Integer EXAMPLES:: sage: from sage.modular.arithgroup.congroup_gammaH import mumu sage: mumu(27) 0 sage: mumu(6*25) 4 sage: mumu(7*9*25) -2 sage: mumu(9*25) 1 """ if N < 1: raise ValueError, "N must be at least 1" p = 1 for _, r in factor(N): if r > 2: return ZZ(0) elif r == 1: p *= -2 return ZZ(p)
def coefficient_n_recursive(self, n): r""" Reimplement the recursive algorithm in sage modular/hecke/module.py We do this because of a bug in sage with .eigenvalue() """ from sage.rings import arith ev = self.eigenvalues c2 = self._coefficients.get(2) if c2 is not None: K = c2.parent() else: if ev.max_coefficient_in_db() >= 2: ev.init_dynamic_properties() else: raise StopIteration, "Newform does not have eigenvalue a(2)!" self._coefficients[2] = ev[2] K = ev[2].parent() prod = K(1) if K.absolute_degree() > 1 and K.is_relative(): KZ = K.base_field() else: KZ = K #emf_logger.debug("K= {0}".format(K)) F = arith.factor(n) for p, r in F: #emf_logger.debug("parent_char_val[{0}]={1}".format(p,self.parent.character_used_in_computation.value(p))) #emf_logger.debug("char_val[{0}]={1}".format(p,self.character.value(p))) (p, r) = (int(p), int(r)) pr = p**r cp = self._coefficients.get(p) # emf_logger.debug("c{0} = {1}".format(p,cp)) if cp is None: if ev.has_eigenvalue(p): cp = ev[p] elif ev.max_coefficient_in_db() >= p: ev.init_dynamic_properties() cp = ev[p] if cp is None: raise IndexError, "p={0} is outside the range of computed primes (primes up to {1})! for label:{2}".format( p, max(ev.primes()), self.label) if self._coefficients.get(pr) is None: if r == 1: c = cp else: eps = KZ( self.parent.character_used_in_computation.value(p)) # a_{p^r} := a_p * a_{p^{r-1}} - eps(p)p^{k-1} a_{p^{r-2}} apr1 = self.coefficient_n_recursive(pr // p) #ap = self.coefficient_n_recursive(p) k = self.weight apr2 = self.coefficient_n_recursive(pr // (p * p)) c = cp * apr1 - eps * (p**(k - 1)) * apr2 #emf_logger.debug("c({0})={1}".format(pr,c)) #ev[pr]=c self._coefficients[pr] = c prod *= self._coefficients[pr] return prod
def coefficient_n_recursive(self, n): r""" Reimplement the recursive algorithm in sage modular/hecke/module.py We do this because of a bug in sage with .eigenvalue() """ from sage.rings import arith ev = self.eigenvalues c2 = self._coefficients.get(2) if c2 is not None: K = c2.parent() else: if ev.max_coefficient_in_db() >= 2: ev.init_dynamic_properties() else: raise StopIteration,"Newform does not have eigenvalue a(2)!" self._coefficients[2]=ev[2] K = ev[2].parent() prod = K(1) if K.absolute_degree()>1 and K.is_relative(): KZ = K.base_field() else: KZ = K #emf_logger.debug("K= {0}".format(K)) F = arith.factor(n) for p, r in F: #emf_logger.debug("parent_char_val[{0}]={1}".format(p,self.parent.character_used_in_computation.value(p))) #emf_logger.debug("char_val[{0}]={1}".format(p,self.character.value(p))) (p, r) = (int(p), int(r)) pr = p**r cp = self._coefficients.get(p) # emf_logger.debug("c{0} = {1}".format(p,cp)) if cp is None: if ev.has_eigenvalue(p): cp = ev[p] elif ev.max_coefficient_in_db() >= p: ev.init_dynamic_properties() cp = ev[p] if cp is None: raise IndexError,"p={0} is outside the range of computed primes (primes up to {1})! for label:{2}".format(p,max(ev.primes()),self.label) if self._coefficients.get(pr) is None: if r == 1: c = cp else: eps = KZ(self.parent.character_used_in_computation.value(p)) # a_{p^r} := a_p * a_{p^{r-1}} - eps(p)p^{k-1} a_{p^{r-2}} apr1 = self.coefficient_n_recursive(pr//p) #ap = self.coefficient_n_recursive(p) k = self.weight apr2 = self.coefficient_n_recursive(pr//(p*p)) c = cp*apr1 - eps*(p**(k-1)) * apr2 #emf_logger.debug("c({0})={1}".format(pr,c)) #ev[pr]=c self._coefficients[pr]=c prod *= self._coefficients[pr] return prod
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), 'conway', None, '{}', 3, 2, True), {}) sage: GF.create_key_and_extra_args(9, 'a', foo='value') ((9, ('a',), 'conway', None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'}) """ from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() with WithProof("arithmetic", proof): order = int(order) if order <= 1: raise ValueError("the order of a finite field must be > 1.") if arith.is_prime(order): name = None modulus = None p = integer.Integer(order) n = integer.Integer(1) elif arith.is_prime_power(order): if not names is None: name = names name = normalize_names(1, name) p, n = arith.factor(order)[0] if modulus is None or modulus == "default": if exists_conway_polynomial(p, n): modulus = "conway" else: if p == 2: modulus = "minimal_weight" else: modulus = "random" elif modulus == "random": modulus += str(random.randint(0, 1 << 128)) if isinstance(modulus, (list, tuple)): modulus = FiniteField(p)["x"](modulus) # some classes use 'random' as the modulus to # generate a random modulus, but we don't want # to cache it elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus): modulus = modulus.change_variable_name("x") elif not isinstance(modulus, str): raise ValueError("Modulus parameter not understood.") else: # Neither a prime, nor a prime power raise ValueError("the order of a finite field must be a prime power.") return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def factored_order(self): """ EXAMPLES:: sage: R = IntegerModRing(18) sage: FF = IntegerModRing(17) sage: R.factored_order() 2 * 3^2 sage: FF.factored_order() 17 """ return factor(self.__order, int_=(self.__order < 2**31))
def factored_order(self): """ EXAMPLES:: sage: R = IntegerModRing(18) sage: FF = IntegerModRing(17) sage: R.factored_order() 2 * 3^2 sage: FF.factored_order() 17 """ return factor(self.__order, int_=(self.__order < 2 ** 31))
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {}) sage: GF.create_key_and_extra_args(9, 'a', foo='value') ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'}) """ from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() with WithProof('arithmetic', proof): order = int(order) if order <= 1: raise ValueError("the order of a finite field must be > 1.") if arith.is_prime(order): name = None modulus = None p = integer.Integer(order) n = integer.Integer(1) elif arith.is_prime_power(order): if not names is None: name = names name = normalize_names(1, name) p, n = arith.factor(order)[0] if modulus is None or isinstance(modulus, str): # A string specifies an algorithm to find a suitable modulus. if modulus == "default": # for backward compatibility modulus = None modulus = GF(p)['x'].irreducible_element(n, algorithm=modulus) elif isinstance(modulus, (list, tuple)): modulus = GF(p)['x'](modulus) elif sage.rings.polynomial.polynomial_element.is_Polynomial( modulus): modulus = modulus.change_variable_name('x') else: raise TypeError("wrong type for modulus parameter") else: raise ValueError( "the order of a finite field must be a prime power.") return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def irred(K, n): F = [] p = K.characteristic() for ell, exp in factor(n): if ell == 2: F.append(rand_irred(K, ell**exp)) elif ell.divides(p-1): F.append(kummer(K, ell, exp)) elif ell.divides(p+1): F.append(cheby(K, ell, exp)) else: F.append(rand_irred(K, ell**exp)) return reduce(comp_prod, F)
def factored_order(self): """ EXAMPLES:: sage: R = IntegerModRing(18) sage: FF = IntegerModRing(17) sage: R.factored_order() 2 * 3^2 sage: FF.factored_order() 17 """ if self.__factored_order is not None: return self.__factored_order self.__factored_order = factor(self.__order, int_=(self.__order < 2**31)) return self.__factored_order
def squarefree_part(x): """ Returns the square free part of `x`, i.e., a divisor `z` such that `x = z y^2`, for a perfect square `y^2`. EXAMPLES:: sage: squarefree_part(100) 1 sage: squarefree_part(12) 3 sage: squarefree_part(10) 10 sage: squarefree_part(216r) # see #8976 6 :: sage: x = QQ['x'].0 sage: S = squarefree_part(-9*x*(x-6)^7*(x-3)^2); S -9*x^2 + 54*x sage: S.factor() (-9) * (x - 6) * x :: sage: f = (x^3 + x + 1)^3*(x-1); f x^10 - x^9 + 3*x^8 + 3*x^5 - 2*x^4 - x^3 - 2*x - 1 sage: g = squarefree_part(f); g x^4 - x^3 + x^2 - 1 sage: g.factor() (x - 1) * (x^3 + x + 1) """ try: return x.squarefree_part() except AttributeError: pass from sage.rings.arith import factor from sage.structure.all import parent F = factor(x) n = parent(x)(1) for p, e in F: if e%2 != 0: n *= p return n * F.unit()
def factored_unit_order(self): """ Returns a list of Factorization objects, each the factorization of the order of the units in a `\ZZ / p^n \ZZ` component of this group (using the Chinese Remainder Theorem). EXAMPLES:: sage: R = Integers(8*9*25*17*29) sage: R.factored_unit_order() [2^2, 2 * 3, 2^2 * 5, 2^4, 2^2 * 7] """ ans = [] from sage.structure.factorization import Factorization for p, e in self.factored_order(): ans.append(Factorization([(p,e-1)]) * factor(p-1, int_=(self.__order < 2**31))) return ans
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {}) sage: GF.create_key_and_extra_args(9, 'a', foo='value') ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'}) """ from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() with WithProof('arithmetic', proof): order = int(order) if order <= 1: raise ValueError("the order of a finite field must be > 1.") if arith.is_prime(order): name = None modulus = None p = integer.Integer(order) n = integer.Integer(1) elif arith.is_prime_power(order): if not names is None: name = names name = normalize_names(1,name) p, n = arith.factor(order)[0] if modulus is None or isinstance(modulus, str): # A string specifies an algorithm to find a suitable modulus. if modulus == "default": # for backward compatibility modulus = None modulus = GF(p)['x'].irreducible_element(n, algorithm=modulus) elif isinstance(modulus, (list, tuple)): modulus = GF(p)['x'](modulus) elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus): modulus = modulus.change_variable_name('x') else: raise TypeError("wrong type for modulus parameter") else: raise ValueError("the order of a finite field must be a prime power.") return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def clifford_conductor(self): """ This is the product of all primes where the Clifford invariant is -1 Note: For ternary forms, this is the discriminant of the quaternion algebra associated to the quadratic space (i.e. the even Clifford algebra) EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.clifford_invariant(2) 1 sage: Q.clifford_invariant(37) -1 sage: Q.clifford_conductor() 37 :: sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() 2 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() 30 For hyperbolic spaces, the clifford conductor is 1:: sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_conductor() 1 sage: (H + H).clifford_conductor() 1 sage: (H + H + H).clifford_conductor() 1 sage: (H + H + H + H).clifford_conductor() 1 """ D = self.disc() return prod([ x[0] for x in factor(2 * self.level()) if self.clifford_invariant(x[0]) == -1 ])
def other_keys(self, key, K): """ EXAMPLES:: sage: key, extra = GF.create_key_and_extra_args(9, 'a'); key (9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True) sage: K = GF.create_object(0, key); K Finite Field in a of size 3^2 sage: GF.other_keys(key, K) [(9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), (9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True)] """ if len(key) == 5: # backward compat order, name, modulus, impl, _ = key p, n = arith.factor(order)[0] proof = True else: order, name, modulus, impl, _, p, n, proof = key from sage.structure.proof.all import WithProof with WithProof('arithmetic', proof): if K.degree() > 1: modulus = K.modulus().change_variable_name('x') new_keys = [(order, name, modulus, impl, _, p, n, proof)] from finite_field_prime_modn import FiniteField_prime_modn if isinstance(K, FiniteField_prime_modn): impl = 'modn' elif isinstance(K, FiniteField_givaro): impl = 'givaro' else: from finite_field_ntl_gf2e import FiniteField_ntl_gf2e from finite_field_ext_pari import FiniteField_ext_pari from finite_field_pari_ffelt import FiniteField_pari_ffelt if isinstance(K, FiniteField_ntl_gf2e): impl = 'ntl' elif isinstance(K, FiniteField_ext_pari): impl = 'pari_mod' elif isinstance(K, FiniteField_pari_ffelt): impl = 'pari_ffelt' new_keys.append((order, name, modulus, impl, _, p, n, proof)) return new_keys
def other_keys(self, key, K): """ EXAMPLES:: sage: key, extra = GF.create_key_and_extra_args(9, 'a'); key (9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True) sage: K = GF.create_object(0, key); K Finite Field in a of size 3^2 sage: GF.other_keys(key, K) [(9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), (9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True)] """ if len(key) == 5: # backward compat order, name, modulus, impl, _ = key p, n = arith.factor(order)[0] proof = True else: order, name, modulus, impl, _, p, n, proof = key from sage.structure.proof.all import WithProof with WithProof('arithmetic', proof): if K.degree() > 1: modulus = K.modulus().change_variable_name('x') new_keys = [(order, name, modulus, impl, _, p, n, proof)] from finite_field_prime_modn import FiniteField_prime_modn if isinstance(K, FiniteField_prime_modn): impl = 'modn' elif isinstance(K, FiniteField_givaro): impl = 'givaro' else: from finite_field_ntl_gf2e import FiniteField_ntl_gf2e from finite_field_ext_pari import FiniteField_ext_pari from finite_field_pari_ffelt import FiniteField_pari_ffelt if isinstance(K, FiniteField_ntl_gf2e): impl = 'ntl' elif isinstance(K, FiniteField_ext_pari): impl = 'pari_mod' elif isinstance(K, FiniteField_pari_ffelt): impl = 'pari_ffelt' new_keys.append( (order, name, modulus, impl, _, p, n, proof) ) return new_keys
def clifford_conductor(self): """ This is the product of all primes where the Clifford invariant is -1 Note: For ternary forms, this is the discriminant of the quaternion algebra associated to the quadratic space (i.e. the even Clifford algebra) EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.clifford_invariant(2) 1 sage: Q.clifford_invariant(37) -1 sage: Q.clifford_conductor() 37 :: sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() 2 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() 30 For hyperbolic spaces, the clifford conductor is 1:: sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_conductor() 1 sage: (H + H).clifford_conductor() 1 sage: (H + H + H).clifford_conductor() 1 sage: (H + H + H + H).clifford_conductor() 1 """ D = self.disc() return prod(filter(lambda p: self.clifford_invariant(p) == -1, map(lambda x: x[0], factor(2 * self.level()))))
def hasse_conductor(self): """ This is the product of all primes where the Hasse invariant equals -1 EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.hasse_invariant(2) -1 sage: Q.hasse_invariant(37) -1 sage: Q.hasse_conductor() 74 :: sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() 1 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() 10 """ D = self.disc() return prod([x[0] for x in factor(2 * self.level()) if self.hasse_invariant(x[0]) == -1])
def hasse_conductor(self): """ This is the product of all primes where the Hasse invariant equals -1 EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.hasse_invariant(2) -1 sage: Q.hasse_invariant(37) -1 sage: Q.hasse_conductor() 74 :: sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() 1 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() 10 """ D = self.disc() return prod(filter(lambda(p):self.hasse_invariant(p)==-1, \ map(lambda(x):x[0],factor(2*self.level()))))
""" Example use of the count_finite_algebras tool. Charlotte Aten ([email protected]) 2016 """ import sage.all from count_finite_algebras import * from sage.rings.arith import factor print("Dislpay a tuple of all partitions of the natural number `i` from 1 through 6.") for n in range(1,6): print(partition(n)) print("") print("Display the cycle counts for each partition of 4.") for part in partition(4): print([part,cycle_count(part, 4)]) print("") print("Display the summand for each of the partitions of 4.") for part in partition(4): print("The summand for {} is {}.".format(part,summand(part,4))) print("") print("For `n` from 1 through 10 show the number `c` of isomorphism classes of magmas of order `n`") print("as well as the prime factorization of `c`.") for n in range(1,11): c = finite_algebra_count(n) print((n,c,factor(c)))
def difference_family(v, k, l=1, existence=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. EXAMPLES:: sage: K,D = designs.difference_family(73,4) sage: D [[0, 1, 8, 64], [0, 25, 54, 67], [0, 41, 36, 69], [0, 3, 24, 46], [0, 2, 16, 55], [0, 50, 35, 61]] sage: K,D = designs.difference_family(337,7) sage: D [[1, 175, 295, 64, 79, 8, 52], [326, 97, 125, 307, 142, 249, 102], [121, 281, 310, 330, 123, 294, 226], [17, 279, 297, 77, 332, 136, 210], [150, 301, 103, 164, 55, 189, 49], [35, 59, 215, 218, 69, 280, 135], [289, 25, 331, 298, 252, 290, 200], [191, 62, 66, 92, 261, 180, 159]] 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] [] Other constructions for `\lambda > 1`:: sage: for v in xrange(2,100): ....: constructions = [] ....: for k in xrange(2,10): ....: for l in xrange(2,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)) 2: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 3: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 4: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 5: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 7: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 8: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 9: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 11: (3,2), (4,3), (4,6), (5,2), (5,3), (5,4), (6,5), (7,6), (8,7), (9,8) 13: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8) 15: (4,6), (5,6), (7,3) 16: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 17: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8) 19: (3,2), (4,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,4), (9,5), (9,6), (9,7), (9,8) 21: (4,3), (6,3), (6,5) 22: (4,2), (6,5), (7,4), (8,8) 23: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 25: (3,2), (4,3), (5,4), (6,5), (7,6), (7,7), (8,7), (9,8) 27: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 28: (3,2), (6,5) 29: (3,2), (4,3), (5,4), (6,5), (7,3), (7,6), (8,4), (8,6), (8,7), (9,8) 31: (3,2), (4,2), (4,3), (5,2), (5,4), (6,5), (7,6), (8,7), (9,8) 32: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 33: (5,5), (6,5) 34: (4,2) 35: (5,2), (8,4) 37: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,2), (9,3), (9,8) 39: (6,5) 40: (3,2) 41: (3,2), (4,3), (5,4), (6,3), (6,5), (7,6), (8,7), (9,8) 43: (3,2), (4,2), (4,3), (5,4), (6,5), (7,2), (7,3), (7,6), (8,4), (8,7), (9,8) 46: (4,2), (6,2) 47: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 49: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8) 51: (5,2), (6,3) 53: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 55: (9,4) 57: (7,3) 59: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 61: (3,2), (4,3), (5,4), (6,2), (6,3), (6,5), (7,6), (8,7), (9,8) 64: (3,2), (4,3), (5,4), (6,5), (7,2), (7,6), (8,7), (9,8) 67: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 71: (3,2), (4,3), (5,2), (5,4), (6,5), (7,3), (7,6), (8,4), (8,7), (9,8) 73: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 75: (5,2) 79: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 81: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 83: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 85: (7,2), (7,3), (8,2) 89: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) 97: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8) 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) .. 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 vv, blocks = DF[v, k, l].iteritems().next() # 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: assert is_difference_family( G, df, v=v, k=k, l=l), "Sage built an invalid ({},{},{})-DF!".format(v, k, l) return G, df e = k * (k - 1) t = l * (v - 1) // e # number of blocks D = None factorization = arith.factor(v) if len(factorization) == 1: # i.e. is v a prime power from sage.rings.finite_rings.constructor import GF G = K = GF(v, 'z') x = K.multiplicative_generator() if l == (k - 1): if existence: return True return K, K.cyclotomic_cosets(x**((v - 1) // k))[1:] if t == 1: # some of the difference set constructions VI.18.48 from the # Handbook of combinatorial designs # q = 3 mod 4 if v % 4 == 3 and k == (v - 1) // 2: if existence: return True D = K.cyclotomic_cosets(x**2, [1]) # q = 4t^2 + 1, t odd elif v % 8 == 5 and k == (v - 1) // 4 and arith.is_square( (v - 1) // 4): if existence: return True D = K.cyclotomic_cosets(x**4, [1]) # q = 4t^2 + 9, t odd elif v % 8 == 5 and k == (v + 3) // 4 and arith.is_square( (v - 9) // 4): if existence: return True D = K.cyclotomic_cosets(x**4, [1]) D[0].insert(0, K.zero()) if D is None and l == 1: one = K.one() # Wilson (1972), Theorem 9 if k % 2 == 1: m = (k - 1) // 2 xx = x**m to_coset = { x**i * xx**j: i for i in xrange(m) for j in xrange((v - 1) / m) } r = x**((v - 1) // k) # primitive k-th root of unity if len(set(to_coset[r**j - one] for j in xrange(1, m + 1))) == m: if existence: return True B = [r**j for j in xrange(k) ] # = H^((k-1)t) whose difference is # H^(mt) (r^i - 1, i=1,..,m) # Now pick representatives a translate of R for by a set of # representatives of H^m / H^(mt) D = [[x**(i * m) * b for b in B] for i in xrange(t)] # Wilson (1972), Theorem 10 else: m = k // 2 xx = x**m to_coset = { x**i * xx**j: i for i in xrange(m) for j in xrange((v - 1) / m) } r = x**((v - 1) // (k - 1)) # primitive (k-1)-th root of unity if (all(to_coset[r**j - one] != 0 for j in xrange(1, m)) and len(set(to_coset[r**j - one] for j in xrange(1, m))) == m - 1): if existence: return True B = [K.zero()] + [r**j for j in xrange(k - 1)] D = [[x**(i * m) * b for b in B] for i in xrange(t)] # Wilson (1972), Theorem 11 if D is None and k == 6: r = x**((v - 1) // 3) # primitive cube root of unity r2 = r * r xx = x**5 to_coset = { x**i * xx**j: i for i in xrange(5) for j in xrange((v - 1) / 5) } for c in to_coset: if c == 1 or c == r or c == r2: continue if len( set(to_coset[elt] for elt in (r - 1, c * (r - 1), c - 1, c - r, c - r**2))) == 5: if existence: return True B = [one, r, r**2, c, c * r, c * r**2] D = [[x**(i * 5) * b for b in B] for i in xrange(t)] break # Twin prime powers construction (see :wikipedia:`Difference_set`) # # i.e. v = p(p+2) where p and p+2 are prime powers # k = (v-1)/2 # lambda = (k-1)/2 elif (len(factorization) == 2 and abs(pow(*factorization[0]) - pow(*factorization[1])) == 2 and k == (v - 1) // 2 and (l is None or 2 * l == (v - 1) // 2 - 1)): # A difference set can be built from the set of elements # (x,y) in GF(p) x GF(p+2) such that: # # - either y=0 # - x and y with x and y squares # - x and y with x and y non-squares if existence: return True from sage.rings.finite_rings.constructor import FiniteField from sage.categories.cartesian_product import cartesian_product from itertools import product p, q = pow(*factorization[0]), pow(*factorization[1]) if p > q: p, q = q, p Fp = FiniteField(p, 'x') Fq = FiniteField(q, '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]) D = [d] 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 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, verbose=False): raise RuntimeError return G, D
def O(*x): """ Big O constructor for various types. EXAMPLES: This is useful for writing power series elements. :: sage: R.<t> = ZZ[['t']] sage: (1+t)^10 + O(t^5) 1 + 10*t + 45*t^2 + 120*t^3 + 210*t^4 + O(t^5) A power series ring is created implicitly if a polynomial element is passed in. :: sage: R.<x> = QQ['x'] sage: O(x^100) O(x^100) sage: 1/(1+x+O(x^5)) 1 - x + x^2 - x^3 + x^4 + O(x^5) sage: R.<u,v> = QQ[[]] sage: 1 + u + v^2 + O(u, v)^5 1 + u + v^2 + O(u, v)^5 This is also useful to create p-adic numbers. :: sage: O(7^6) O(7^6) sage: 1/3 + O(7^6) 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + O(7^6) It behaves well with respect to adding negative powers of p:: sage: a = O(11^-32); a O(11^-32) sage: a.parent() 11-adic Field with capped relative precision 20 There are problems if you add a rational with very negative valuation to a big_oh. :: sage: 11^-12 + O(11^15) 11^-12 + O(11^8) The reason that this fails is that the O function doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue. :: sage: K = Qp(11, 30) sage: K(11^-12) + O(11^15) 11^-12 + O(11^15) sage: 11^-12 + K(O(11^15)) 11^-12 + O(11^15) sage: K(11^-12, absprec = 15) 11^-12 + O(11^15) sage: K(11^-12, 15) 11^-12 + O(11^15) """ if len(x) > 1: if isinstance(x[0], multi_power_series_ring_element.MPowerSeries): return multi_power_series_ring_element.MO(x) x = x[0] if isinstance(x, power_series_ring_element.PowerSeries): return x.parent()(0, x.degree()) elif isinstance(x, Polynomial): if x.parent().ngens() != 1: raise NotImplementedError("completion only currently defined for univariate polynomials") if not x.is_monomial(): raise NotImplementedError("completion only currently defined for the maximal ideal (x)") return x.parent().completion(x.parent().gen())(0, x.degree()) elif isinstance(x, laurent_series_ring_element.LaurentSeries): return laurent_series_ring_element.LaurentSeries(x.parent(), 0).add_bigoh(x.valuation()) elif isinstance(x, (int,long,integer.Integer,rational.Rational)): # p-adic number if x <= 0: raise ArithmeticError("x must be a prime power >= 2") F = arith.factor(x) if len(F) != 1: raise ArithmeticError("x must be prime power") p, r = F[0] if r >= 0: return padics_factory.Zp(p, prec = max(r, 20), type = 'capped-rel')(0, absprec = r) else: return padics_factory.Qp(p, prec = max(r, 20), type = 'capped-rel')(0, absprec = r) elif isinstance(x, padic_generic_element.pAdicGenericElement): return x.parent()(0, absprec = x.valuation()) raise ArithmeticError("O(x) not defined")
def create_object(self, version, key, check_irreducible=True, elem_cache=None, names=None, **kwds): """ EXAMPLES:: sage: K = GF(19) # indirect doctest sage: TestSuite(K).run() """ # IMPORTANT! If you add a new class to the list of classes # that get cached by this factor object, then you *must* add # the following method to that class in order to fully support # pickling: # # def __reduce__(self): # and include good doctests, please! # return self._factory_data[0].reduce_data(self) # # This is not in the base class for finite fields, since some finite # fields need not be created using this factory object, e.g., residue # class fields. if len(key) == 5: # for backward compatibility of pickles (see trac 10975). order, name, modulus, impl, _ = key p, n = arith.factor(order)[0] proof = True else: order, name, modulus, impl, _, p, n, proof = key if elem_cache is None: elem_cache = order < 500 if n == 1 and (impl is None or impl == 'modn'): from finite_field_prime_modn import FiniteField_prime_modn # Using a check option here is probably a worthwhile # compromise since this constructor is simple and used a # huge amount. K = FiniteField_prime_modn(order, check=False) else: # We have to do this with block so that the finite field # constructors below will use the proof flag that was # passed in when checking for primality, factoring, etc. # Otherwise, we would have to complicate all of their # constructors with check options (like above). from sage.structure.proof.all import WithProof with WithProof('arithmetic', proof): if check_irreducible and polynomial_element.is_Polynomial(modulus): if modulus.parent().base_ring().characteristic() == 0: modulus = modulus.change_ring(FiniteField(p)) if not modulus.is_irreducible(): raise ValueError("finite field modulus must be irreducible but it is not.") if modulus.degree() != n: raise ValueError("The degree of the modulus does not correspond to the cardinality of the field.") if name is None: raise TypeError("you must specify the generator name.") if impl is None: if order < zech_log_bound: # DO *NOT* use for prime subfield, since that would lead to # a circular reference in the call to ParentWithGens in the # __init__ method. impl = 'givaro' elif order % 2 == 0: impl = 'ntl' else: impl = 'pari_ffelt' if impl == 'givaro': if kwds.has_key('repr'): repr = kwds['repr'] else: repr = 'poly' K = FiniteField_givaro(order, name, modulus, repr=repr, cache=elem_cache) elif impl == 'ntl': from finite_field_ntl_gf2e import FiniteField_ntl_gf2e K = FiniteField_ntl_gf2e(order, name, modulus) elif impl == 'pari_ffelt': from finite_field_pari_ffelt import FiniteField_pari_ffelt K = FiniteField_pari_ffelt(p, modulus, name) elif (impl == 'pari_mod' or impl == 'pari'): # for unpickling old pickles from finite_field_ext_pari import FiniteField_ext_pari K = FiniteField_ext_pari(order, name, modulus) else: raise ValueError("no such finite field implementation: %s" % impl) # Temporary; see create_key_and_extra_args() above. if kwds.has_key('prefix'): K._prefix = kwds['prefix'] return K
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {}) sage: GF.create_key_and_extra_args(9, 'a', foo='value') ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'}) """ from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() with WithProof('arithmetic', proof): order = int(order) if order <= 1: raise ValueError("the order of a finite field must be > 1.") if arith.is_prime(order): name = None modulus = None p = integer.Integer(order) n = integer.Integer(1) elif arith.is_prime_power(order): if not names is None: name = names name = normalize_names(1,name) p, n = arith.factor(order)[0] # The following is a temporary solution that allows us # to construct compatible systems of finite fields # until algebraic closures of finite fields are # implemented in Sage. It requires the user to # specify two parameters: # # - `conway` -- boolean; if True, this field is # constructed to fit in a compatible system using # a Conway polynomial. # - `prefix` -- a string used to generate names for # automatically constructed finite fields # # See the docstring of FiniteFieldFactory for examples. # # Once algebraic closures of finite fields are # implemented, this syntax should be superseded by # something like the following: # # sage: Fpbar = GF(5).algebraic_closure('z') # sage: F, e = Fpbar.subfield(3) # e is the embedding into Fpbar # sage: F # Finite field in z3 of size 5^3 # # This temporary solution only uses actual Conway # polynomials (no pseudo-Conway polynomials), since # pseudo-Conway polynomials are not unique, and until # we have algebraic closures of finite fields, there # is no good place to store a specific choice of # pseudo-Conway polynomials. if name is None: if not (kwds.has_key('conway') and kwds['conway']): raise ValueError("parameter 'conway' is required if no name given") if not kwds.has_key('prefix'): raise ValueError("parameter 'prefix' is required if no name given") name = kwds['prefix'] + str(n) if kwds.has_key('conway') and kwds['conway']: from conway_polynomials import conway_polynomial if not kwds.has_key('prefix'): raise ValueError("a prefix must be specified if conway=True") if modulus is not None: raise ValueError("no modulus may be specified if conway=True") # The following raises a RuntimeError if no polynomial is found. modulus = conway_polynomial(p, n) if modulus is None or isinstance(modulus, str): # A string specifies an algorithm to find a suitable modulus. if modulus == "default": # for backward compatibility modulus = None modulus = GF(p)['x'].irreducible_element(n, algorithm=modulus) elif isinstance(modulus, (list, tuple)): modulus = GF(p)['x'](modulus) elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus): modulus = modulus.change_variable_name('x') else: raise TypeError("wrong type for modulus parameter") else: raise ValueError("the order of a finite field must be a prime power.") return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
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
def CohenOesterle(eps, k): r""" Compute the Cohen-Oesterle function associate to eps, `k`. This is a summand in the formula for the dimension of the space of cusp forms of weight `2` with character `\varepsilon`. INPUT: - ``eps`` - Dirichlet character - ``k`` - integer OUTPUT: element of the base ring of eps. EXAMPLES:: sage: G.<eps> = DirichletGroup(7) sage: sage.modular.dims.CohenOesterle(eps, 2) -2/3 sage: sage.modular.dims.CohenOesterle(eps, 4) -1 """ N = eps.modulus() facN = factor(N) f = eps.conductor() gamma_k = 0 if k % 4 == 2: gamma_k = frac(-1, 4) elif k % 4 == 0: gamma_k = frac(1, 4) mu_k = 0 if k % 3 == 2: mu_k = frac(-1, 3) elif k % 3 == 0: mu_k = frac(1, 3) def _lambda(r, s, p): """ Used internally by the CohenOesterle function. INPUT: - ``r, s, p`` - integers OUTPUT: Integer EXAMPLES: (indirect doctest) :: sage: K = CyclotomicField(3) sage: eps = DirichletGroup(7*43,K).0^2 sage: sage.modular.dims.CohenOesterle(eps,2) -4/3 """ if 2 * s <= r: if r % 2 == 0: return p**(r // 2) + p**((r // 2) - 1) return 2 * p**((r - 1) // 2) return 2 * (p**(r - s)) #end def of lambda K = eps.base_ring() return K(frac(-1,2) * mul([_lambda(r,valuation(f,p),p) for p, r in facN]) + \ gamma_k * mul([CO_delta(r,p,N,eps) for p, r in facN]) + \ mu_k * mul([CO_nu(r,p,N,eps) for p, r in facN]))
def create_object(self, version, key, check_irreducible=True, elem_cache=None, names=None, **kwds): """ EXAMPLES:: sage: K = GF(19) sage: TestSuite(K).run() """ # IMPORTANT! If you add a new class to the list of classes # that get cached by this factor object, then you *must* add # the following method to that class in order to fully support # pickling: # # def __reduce__(self): # and include good doctests, please! # return self._factory_data[0].reduce_data(self) # # This is not in the base class for finite fields, since some finite # fields need not be created using this factory object, e.g., residue # class fields. if len(key) == 5: # for backward compatibility of pickles (see trac 10975). order, name, modulus, impl, _ = key p, n = arith.factor(order)[0] proof = True else: order, name, modulus, impl, _, p, n, proof = key if isinstance(modulus, str) and modulus.startswith("random"): modulus = "random" if elem_cache is None: elem_cache = order < 500 if n == 1 and (impl is None or impl == 'modn'): from finite_field_prime_modn import FiniteField_prime_modn # Using a check option here is probably a worthwhile # compromise since this constructor is simple and used a # huge amount. K = FiniteField_prime_modn(order, check=False, **kwds) else: # We have to do this with block so that the finite field # constructors below will use the proof flag that was # passed in when checking for primality, factoring, etc. # Otherwise, we would have to complicate all of their # constructors with check options (like above). from sage.structure.proof.all import WithProof with WithProof('arithmetic', proof): if check_irreducible and polynomial_element.is_Polynomial( modulus): if modulus.parent().base_ring().characteristic() == 0: modulus = modulus.change_ring(FiniteField(p)) if not modulus.is_irreducible(): raise ValueError( "finite field modulus must be irreducible but it is not." ) if modulus.degree() != n: raise ValueError( "The degree of the modulus does not correspond to the cardinality of the field." ) if name is None: raise TypeError("you must specify the generator name.") if order < zech_log_bound: # DO *NOT* use for prime subfield, since that would lead to # a circular reference in the call to ParentWithGens in the # __init__ method. K = FiniteField_givaro(order, name, modulus, cache=elem_cache, **kwds) else: if order % 2 == 0 and (impl is None or impl == 'ntl'): from element_ntl_gf2e import FiniteField_ntl_gf2e K = FiniteField_ntl_gf2e(order, name, modulus, **kwds) else: from finite_field_ext_pari import FiniteField_ext_pari K = FiniteField_ext_pari(order, name, modulus, **kwds) return K
def O(*x): """ Big O constructor for various types. EXAMPLES: This is useful for writing power series elements. :: sage: R.<t> = ZZ[['t']] sage: (1+t)^10 + O(t^5) 1 + 10*t + 45*t^2 + 120*t^3 + 210*t^4 + O(t^5) A power series ring is created implicitly if a polynomial element is passed in. :: sage: R.<x> = QQ['x'] sage: O(x^100) O(x^100) sage: 1/(1+x+O(x^5)) 1 - x + x^2 - x^3 + x^4 + O(x^5) sage: R.<u,v> = QQ[[]] sage: 1 + u + v^2 + O(u, v)^5 1 + u + v^2 + O(u, v)^5 This is also useful to create p-adic numbers. :: sage: O(7^6) O(7^6) sage: 1/3 + O(7^6) 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + O(7^6) It behaves well with respect to adding negative powers of p:: sage: a = O(11^-32); a O(11^-32) sage: a.parent() 11-adic Field with capped relative precision 20 There are problems if you add a rational with very negative valuation to a big_oh. :: sage: 11^-12 + O(11^15) 11^-12 + O(11^8) The reason that this fails is that the O function doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue. :: sage: K = Qp(11, 30) sage: K(11^-12) + O(11^15) 11^-12 + O(11^15) sage: 11^-12 + K(O(11^15)) 11^-12 + O(11^15) sage: K(11^-12, absprec = 15) 11^-12 + O(11^15) sage: K(11^-12, 15) 11^-12 + O(11^15) """ if len(x) > 1: if isinstance(x[0], multi_power_series_ring_element.MPowerSeries): return multi_power_series_ring_element.MO(x) x = x[0] if isinstance(x, power_series_ring_element.PowerSeries): return x.parent()(0, x.degree()) elif isinstance(x, Polynomial): if x.parent().ngens() != 1: raise NotImplementedError( "completion only currently defined for univariate polynomials") if not x.is_monomial(): raise NotImplementedError( "completion only currently defined for the maximal ideal (x)") return x.parent().completion(x.parent().gen())(0, x.degree()) elif isinstance(x, laurent_series_ring_element.LaurentSeries): return laurent_series_ring_element.LaurentSeries( x.parent(), 0).add_bigoh(x.valuation()) elif isinstance( x, (int, long, integer.Integer, rational.Rational)): # p-adic number if x <= 0: raise ArithmeticError("x must be a prime power >= 2") F = arith.factor(x) if len(F) != 1: raise ArithmeticError("x must be prime power") p, r = F[0] if r >= 0: return padics_factory.Zp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r) else: return padics_factory.Qp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r) elif isinstance(x, padic_generic_element.pAdicGenericElement): return x.parent()(0, absprec=x.valuation()) raise ArithmeticError("O(x) not defined")
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {}) sage: GF.create_key_and_extra_args(9, 'a', foo='value') ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'}) """ from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() with WithProof('arithmetic', proof): order = int(order) if order <= 1: raise ValueError("the order of a finite field must be > 1.") if arith.is_prime(order): name = None modulus = None p = integer.Integer(order) n = integer.Integer(1) elif arith.is_prime_power(order): if not names is None: name = names name = normalize_names(1, name) p, n = arith.factor(order)[0] # The following is a temporary solution that allows us # to construct compatible systems of finite fields # until algebraic closures of finite fields are # implemented in Sage. It requires the user to # specify two parameters: # # - `conway` -- boolean; if True, this field is # constructed to fit in a compatible system using # a Conway polynomial. # - `prefix` -- a string used to generate names for # automatically constructed finite fields # # See the docstring of FiniteFieldFactory for examples. # # Once algebraic closures of finite fields are # implemented, this syntax should be superseded by # something like the following: # # sage: Fpbar = GF(5).algebraic_closure('z') # sage: F, e = Fpbar.subfield(3) # e is the embedding into Fpbar # sage: F # Finite field in z3 of size 5^3 # # This temporary solution only uses actual Conway # polynomials (no pseudo-Conway polynomials), since # pseudo-Conway polynomials are not unique, and until # we have algebraic closures of finite fields, there # is no good place to store a specific choice of # pseudo-Conway polynomials. if name is None: if not (kwds.has_key('conway') and kwds['conway']): raise ValueError( "parameter 'conway' is required if no name given") if not kwds.has_key('prefix'): raise ValueError( "parameter 'prefix' is required if no name given") name = kwds['prefix'] + str(n) if kwds.has_key('conway') and kwds['conway']: from conway_polynomials import conway_polynomial if not kwds.has_key('prefix'): raise ValueError( "a prefix must be specified if conway=True") if modulus is not None: raise ValueError( "no modulus may be specified if conway=True") # The following raises a RuntimeError if no polynomial is found. modulus = conway_polynomial(p, n) if modulus is None or isinstance(modulus, str): # A string specifies an algorithm to find a suitable modulus. if modulus == "default": # for backward compatibility modulus = None modulus = GF(p)['x'].irreducible_element(n, algorithm=modulus) elif isinstance(modulus, (list, tuple)): modulus = GF(p)['x'](modulus) elif sage.rings.polynomial.polynomial_element.is_Polynomial( modulus): modulus = modulus.change_variable_name('x') else: raise TypeError("wrong type for modulus parameter") else: raise ValueError( "the order of a finite field must be a prime power.") return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def mutually_orthogonal_latin_squares(n,k=None, partitions = False): r""" Returns `k` Mutually Orthogonal `n\times n` Latin Squares (MOLS). For more information on Latin Squares and MOLS, see :mod:`~sage.combinat.designs.latin_squares` or the :wikipedia:`Latin_square`, or even the :wikipedia:`Wikipedia entry on MOLS <Graeco-Latin_square#Mutually_orthogonal_Latin_squares>`. INPUT: - ``n`` (integer) -- size of the latin square. - ``k`` (integer) -- returns `k` MOLS. If set to ``None`` (default), returns the maximum number of MOLS that Sage can build. .. WARNING:: This has no reason to be the maximum number of `n\times n` MOLS, just the best Sage can do ! - ``partition`` (boolean) -- a Latin Square can be seen as 3 partitions of the `n^2` cells of the array into `n` sets of size `n`, respectively : * The partition of rows * The partition of columns * The partition of number (cells numbered with 0, cells numbered with 1, ...) These partitions have the additional property that any two sets from different partitions intersect on exactly one element. When ``partition`` is set to ``True``, this function returns a list of `k+2` partitions satisfying this intersection property instead of the `k+2` MOLS (though the data is exactly the same in both cases). EXAMPLES:: sage: designs.mutually_orthogonal_latin_squares(5) [ [0 1 2 3 4] [0 1 2 3 4] [0 1 2 3 4] [0 1 2 3 4] [3 0 1 4 2] [4 3 0 2 1] [1 2 4 0 3] [2 4 3 1 0] [4 3 0 2 1] [1 2 4 0 3] [2 4 3 1 0] [3 0 1 4 2] [1 2 4 0 3] [2 4 3 1 0] [3 0 1 4 2] [4 3 0 2 1] [2 4 3 1 0], [3 0 1 4 2], [4 3 0 2 1], [1 2 4 0 3] ] sage: designs.mutually_orthogonal_latin_squares(7,3) [ [0 1 2 3 4 5 6] [0 1 2 3 4 5 6] [0 1 2 3 4 5 6] [4 0 3 1 6 2 5] [5 6 0 4 2 1 3] [6 4 1 0 5 3 2] [5 6 0 4 2 1 3] [6 4 1 0 5 3 2] [1 3 5 2 0 6 4] [6 4 1 0 5 3 2] [1 3 5 2 0 6 4] [2 5 4 6 3 0 1] [1 3 5 2 0 6 4] [2 5 4 6 3 0 1] [3 2 6 5 1 4 0] [2 5 4 6 3 0 1] [3 2 6 5 1 4 0] [4 0 3 1 6 2 5] [3 2 6 5 1 4 0], [4 0 3 1 6 2 5], [5 6 0 4 2 1 3] ] sage: designs.mutually_orthogonal_latin_squares(5,2,partitions=True) [[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24]], [[0, 5, 10, 15, 20], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]], [[0, 6, 12, 18, 24], [1, 7, 14, 15, 23], [2, 9, 13, 16, 20], [3, 5, 11, 19, 22], [4, 8, 10, 17, 21]], [[0, 7, 13, 19, 21], [1, 9, 10, 18, 22], [2, 8, 11, 15, 24], [3, 6, 14, 17, 20], [4, 5, 12, 16, 23]]] TESTS:: sage: designs.mutually_orthogonal_latin_squares(5,5) Traceback (most recent call last): ... ValueError: There exist at most n-1 MOLS of size n. """ from sage.rings.finite_rings.constructor import FiniteField from sage.combinat.designs.block_design import AffineGeometryDesign from sage.rings.arith import is_prime_power from sage.matrix.constructor import Matrix from sage.rings.arith import factor if k is not None and k >= n: raise ValueError("There exist at most n-1 MOLS of size n.") if is_prime_power(n): if k is None: k = n-1 # Section 6.4.1 of [Stinson2004] Fp = FiniteField(n,'x') B = AffineGeometryDesign(2,1,Fp).blocks() parallel_classes = [[] for _ in range(k+2)] for b in B: for p in parallel_classes: if (not p) or all(i not in p[0] for i in b): p.append(b) break if partitions: return parallel_classes coord = {v:i for i,L in enumerate(parallel_classes[0]) for v in L} coord = {v:(coord[v],i) for i,L in enumerate(parallel_classes[1]) for v in L} matrices = [] for P in parallel_classes[2:]: matrices.append(Matrix({coord[v]:i for i,L in enumerate(P) for v in L })) return matrices else: # Theorem 6.33 of [Stinson2004], MacNeish's theorem. subcases = [p**i for p,i in factor(n)] s = min(subcases)-1 if k is None: k = s elif k > s: raise NotImplementedError("I don't know how to build these MOLS.") subcalls = [mutually_orthogonal_latin_squares(p,k) for p in subcases] matrices = [latin_square_product(*[sc[i] for sc in subcalls]) for i in range(k)] if partitions: partitions = [[[i*n+j for j in range(n)] for i in range(n)], [[j*n+i for j in range(n)] for i in range(n)]] for m in matrices: partition = [[] for i in range(n)] for i in range(n): for j in range(n): partition[m[i,j]].append(i*n+j) partitions.append(partition) return partitions else: return matrices
def CohenOesterle(eps, k): r""" Compute the Cohen-Oesterle function associate to eps, `k`. This is a summand in the formula for the dimension of the space of cusp forms of weight `2` with character `\varepsilon`. INPUT: - ``eps`` - Dirichlet character - ``k`` - integer OUTPUT: element of the base ring of eps. EXAMPLES:: sage: G.<eps> = DirichletGroup(7) sage: sage.modular.dims.CohenOesterle(eps, 2) -2/3 sage: sage.modular.dims.CohenOesterle(eps, 4) -1 """ N = eps.modulus() facN = factor(N) f = eps.conductor() gamma_k = 0 if k%4==2: gamma_k = frac(-1,4) elif k%4==0: gamma_k = frac(1,4) mu_k = 0 if k%3==2: mu_k = frac(-1,3) elif k%3==0: mu_k = frac(1,3) def _lambda(r,s,p): """ Used internally by the CohenOesterle function. INPUT: - ``r, s, p`` - integers OUTPUT: Integer EXAMPLES: (indirect doctest) :: sage: K = CyclotomicField(3) sage: eps = DirichletGroup(7*43,K).0^2 sage: sage.modular.dims.CohenOesterle(eps,2) -4/3 """ if 2*s<=r: if r%2==0: return p**(r//2) + p**((r//2)-1) return 2*p**((r-1)//2) return 2*(p**(r-s)) #end def of lambda K = eps.base_ring() return K(frac(-1,2) * mul([_lambda(r,valuation(f,p),p) for p, r in facN]) + \ gamma_k * mul([CO_delta(r,p,N,eps) for p, r in facN]) + \ mu_k * mul([CO_nu(r,p,N,eps) for p, r in facN]))
def mutually_orthogonal_latin_squares(n, k=None, partitions=False): r""" Returns `k` Mutually Orthogonal `n\times n` Latin Squares (MOLS). For more information on Latin Squares and MOLS, see :mod:`~sage.combinat.designs.latin_squares` or the :wikipedia:`Latin_square`, or even the :wikipedia:`Wikipedia entry on MOLS <Graeco-Latin_square#Mutually_orthogonal_Latin_squares>`. INPUT: - ``n`` (integer) -- size of the latin square. - ``k`` (integer) -- returns `k` MOLS. If set to ``None`` (default), returns the maximum number of MOLS that Sage can build. .. WARNING:: This has no reason to be the maximum number of `n\times n` MOLS, just the best Sage can do ! - ``partition`` (boolean) -- a Latin Square can be seen as 3 partitions of the `n^2` cells of the array into `n` sets of size `n`, respectively : * The partition of rows * The partition of columns * The partition of number (cells numbered with 0, cells numbered with 1, ...) These partitions have the additional property that any two sets from different partitions intersect on exactly one element. When ``partition`` is set to ``True``, this function returns a list of `k+2` partitions satisfying this intersection property instead of the `k+2` MOLS (though the data is exactly the same in both cases). EXAMPLES:: sage: designs.mutually_orthogonal_latin_squares(5) [ [0 1 2 3 4] [0 1 2 3 4] [0 1 2 3 4] [0 1 2 3 4] [3 0 1 4 2] [4 3 0 2 1] [1 2 4 0 3] [2 4 3 1 0] [4 3 0 2 1] [1 2 4 0 3] [2 4 3 1 0] [3 0 1 4 2] [1 2 4 0 3] [2 4 3 1 0] [3 0 1 4 2] [4 3 0 2 1] [2 4 3 1 0], [3 0 1 4 2], [4 3 0 2 1], [1 2 4 0 3] ] sage: designs.mutually_orthogonal_latin_squares(7,3) [ [0 1 2 3 4 5 6] [0 1 2 3 4 5 6] [0 1 2 3 4 5 6] [4 0 3 1 6 2 5] [5 6 0 4 2 1 3] [6 4 1 0 5 3 2] [5 6 0 4 2 1 3] [6 4 1 0 5 3 2] [1 3 5 2 0 6 4] [6 4 1 0 5 3 2] [1 3 5 2 0 6 4] [2 5 4 6 3 0 1] [1 3 5 2 0 6 4] [2 5 4 6 3 0 1] [3 2 6 5 1 4 0] [2 5 4 6 3 0 1] [3 2 6 5 1 4 0] [4 0 3 1 6 2 5] [3 2 6 5 1 4 0], [4 0 3 1 6 2 5], [5 6 0 4 2 1 3] ] sage: designs.mutually_orthogonal_latin_squares(5,2,partitions=True) [[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24]], [[0, 5, 10, 15, 20], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]], [[0, 6, 12, 18, 24], [1, 7, 14, 15, 23], [2, 9, 13, 16, 20], [3, 5, 11, 19, 22], [4, 8, 10, 17, 21]], [[0, 7, 13, 19, 21], [1, 9, 10, 18, 22], [2, 8, 11, 15, 24], [3, 6, 14, 17, 20], [4, 5, 12, 16, 23]]] TESTS:: sage: designs.mutually_orthogonal_latin_squares(5,5) Traceback (most recent call last): ... ValueError: There exist at most n-1 MOLS of size n. """ from sage.rings.finite_rings.constructor import FiniteField from sage.combinat.designs.block_design import AffineGeometryDesign from sage.rings.arith import is_prime_power from sage.matrix.constructor import Matrix from sage.rings.arith import factor if k is not None and k >= n: raise ValueError("There exist at most n-1 MOLS of size n.") if is_prime_power(n): if k is None: k = n - 1 # Section 6.4.1 of [Stinson2004] Fp = FiniteField(n, 'x') B = AffineGeometryDesign(2, 1, Fp).blocks() parallel_classes = [[] for _ in range(k + 2)] for b in B: for p in parallel_classes: if (not p) or all(i not in p[0] for i in b): p.append(b) break if partitions: return parallel_classes coord = {v: i for i, L in enumerate(parallel_classes[0]) for v in L} coord = { v: (coord[v], i) for i, L in enumerate(parallel_classes[1]) for v in L } matrices = [] for P in parallel_classes[2:]: matrices.append( Matrix({coord[v]: i for i, L in enumerate(P) for v in L})) return matrices else: # Theorem 6.33 of [Stinson2004], MacNeish's theorem. subcases = [p**i for p, i in factor(n)] s = min(subcases) - 1 if k is None: k = s elif k > s: raise NotImplementedError("I don't know how to build these MOLS.") subcalls = [mutually_orthogonal_latin_squares(p, k) for p in subcases] matrices = [ latin_square_product(*[sc[i] for sc in subcalls]) for i in range(k) ] if partitions: partitions = [[[i * n + j for j in range(n)] for i in range(n)], [[j * n + i for j in range(n)] for i in range(n)]] for m in matrices: partition = [[] for i in range(n)] for i in range(n): for j in range(n): partition[m[i, j]].append(i * n + j) partitions.append(partition) return partitions else: return matrices
def dft(self, chi = lambda x: x): """ A discrete Fourier transform "over `\QQ`" using exact `N`-th roots of unity. EXAMPLES:: sage: J = range(6) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) sage: s.dft(lambda x:x^2) Indexed sequence: [6, 0, 0, 6, 0, 0] indexed by [0, 1, 2, 3, 4, 5] sage: s.dft() Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] sage: G = SymmetricGroup(3) sage: J = G.conjugacy_classes_representatives() sage: s = IndexedSequence([1,2,3],J) # 1,2,3 are the values of a class fcn on G sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn Indexed sequence: [8, 2, 2] indexed by [(), (1,2), (1,2,3)] sage: J = AbelianGroup(2,[2,3],names='ab') sage: s = IndexedSequence([1,2,3,4,5,6],J) sage: s.dft() # the precision of output is somewhat random and architecture dependent. Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] indexed by Multiplicative Abelian group isomorphic to C2 x C3 sage: J = CyclicPermutationGroup(6) sage: s = IndexedSequence([1,2,3,4,5,6],J) sage: s.dft() # the precision of output is somewhat random and architecture dependent. Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] indexed by Cyclic group of order 6 as a permutation group sage: p = 7; J = range(p); A = [kronecker_symbol(j,p) for j in J] sage: s = IndexedSequence(A,J) sage: Fs = s.dft() sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() [0, 1, 1, -1, 1, -1, -1] [0, 1, 1, -1, 1, -1, -1] The DFT of the values of the quadratic residue symbol is itself, up to a constant factor (denoted c on the last line above). .. TODO:: Read the parent of the elements of S; if `\QQ` or `\CC` leave as is; if AbelianGroup, use abelian_group_dual; if some other implemented Group (permutation, matrix), call .characters() and test if the index list is the set of conjugacy classes. """ J = self.index_object() ## index set of length N N = len(J) S = self.list() F = self.base_ring() ## elements must be coercible into QQ(zeta_N) if not(J[0] in ZZ): G = J[0].parent() ## if J is not a range it is a group G if J[0] in ZZ and F.base_ring().fraction_field()==QQ: ## assumes J is range(N) zeta = CyclotomicField(N).gen() FT = [sum([S[i]*chi(zeta**(i*j)) for i in J]) for j in J] elif not(J[0] in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring()==QQ): if is_PermutationGroupElement(J[0]): ## J is a CyclicPermGp n = G.order() a = list(factor(n)) invs = [x[0]**x[1] for x in a] G = AbelianGroup(len(a),invs) ## assumes J is AbelianGroup(...) Gd = G.dual_group() FT = [sum([S[i]*chid(G.list()[i]) for i in range(N)]) for chid in Gd] elif not(J[0] in ZZ) and G.is_finite() and F == ZZ or (F.is_field() and F.base_ring()==QQ): ## assumes J is the list of conj class representatives of a ## PermuationGroup(...) or Matrixgroup(...) chi = G.character_table() FT = [sum([S[i]*chi[i,j] for i in range(N)]) for j in range(N)] else: raise ValueError("list elements must be in QQ(zeta_"+str(N)+")") return IndexedSequence(FT,J)
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, 5, 18], [0, 3, 15, 54], [0, 9, 45, 16], [0, 27, 62, 48], [0, 8, 40, 71], [0, 24, 47, 67]] sage: print designs.difference_family(73, 4, explain_construction=True) The database contains a (73,4)-evenly distributed set 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] [169, 337, 379, 421, 463, 547, 631, 673, 757, 841, 883, 967, ..., 4621, 4957, 5167] sage: l7[Unknown] [43, 127, 211, 2017, 2143, 2269, 2311, 2437, 2521, 2647, ..., 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,1), (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), (7,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,EDS sage: for v,k,l in DF: ....: assert designs.difference_family(v,k,l,existence=True) is True ....: df = designs.difference_family(v,k,l,check=True) sage: for k in EDS: ....: for v in EDS[k]: ....: assert designs.difference_family(v,k,1,existence=True) is True ....: df = designs.difference_family(v,k,1,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, EDS 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 elif l == 1 and k in EDS and v in EDS[k]: if existence: return True elif explain_construction: return "The database contains a ({},{})-evenly distributed set".format(v,k) from sage.rings.finite_rings.constructor import GF poly,B = EDS[k][v] if poly is None: # q is prime K = G = GF(v) else: K = G = GF(v,'a',modulus=poly) B = map(K,B) e = k*(k-1)/2 xe = G.multiplicative_generator()**e df = [[xe**j*b for b in B] for j in range((v-1)/(2*e))] if check and not is_difference_family(G, df, v=v, k=k, l=l): raise RuntimeError("There is an invalid ({},{})-evenly distributed " "set 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
def O(*x, **kwds): """ Big O constructor for various types. EXAMPLES: This is useful for writing power series elements:: sage: R.<t> = ZZ[['t']] sage: (1+t)^10 + O(t^5) 1 + 10*t + 45*t^2 + 120*t^3 + 210*t^4 + O(t^5) A power series ring is created implicitly if a polynomial element is passed:: sage: R.<x> = QQ['x'] sage: O(x^100) O(x^100) sage: 1/(1+x+O(x^5)) 1 - x + x^2 - x^3 + x^4 + O(x^5) sage: R.<u,v> = QQ[[]] sage: 1 + u + v^2 + O(u, v)^5 1 + u + v^2 + O(u, v)^5 This is also useful to create `p`-adic numbers:: sage: O(7^6) O(7^6) sage: 1/3 + O(7^6) 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + O(7^6) It behaves well with respect to adding negative powers of `p`:: sage: a = O(11^-32); a O(11^-32) sage: a.parent() 11-adic Field with capped relative precision 20 There are problems if you add a rational with very negative valuation to an `O`-Term:: sage: 11^-12 + O(11^15) 11^-12 + O(11^8) The reason that this fails is that the constructor doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue:: sage: K = Qp(11, 30) sage: K(11^-12) + O(11^15) 11^-12 + O(11^15) sage: 11^-12 + K(O(11^15)) 11^-12 + O(11^15) sage: K(11^-12, absprec = 15) 11^-12 + O(11^15) sage: K(11^-12, 15) 11^-12 + O(11^15) We can also work with `asymptotic expansions`_:: sage: A.<n> = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', coefficient_ring=QQ); A doctest:...: FutureWarning: This class/method/function is marked as experimental. ... Asymptotic Ring <QQ^n * n^QQ * log(n)^QQ> over Rational Field sage: O(n) O(n) TESTS:: sage: var('x, y') (x, y) sage: O(x) Traceback (most recent call last): ... ArithmeticError: O(x) not defined sage: O(y) Traceback (most recent call last): ... ArithmeticError: O(y) not defined sage: O(x, y) Traceback (most recent call last): ... ArithmeticError: O(x, y) not defined sage: O(4, 2) Traceback (most recent call last): ... ArithmeticError: O(4, 2) not defined """ if len(x) > 1: if isinstance(x[0], multi_power_series_ring_element.MPowerSeries): return multi_power_series_ring_element.MO(x, **kwds) else: raise ArithmeticError("O(%s) not defined" % (', '.join(str(e) for e in x),)) x = x[0] if isinstance(x, power_series_ring_element.PowerSeries): return x.parent()(0, x.degree(), **kwds) elif isinstance(x, Polynomial): if x.parent().ngens() != 1: raise NotImplementedError("completion only currently defined " "for univariate polynomials") if not x.is_monomial(): raise NotImplementedError("completion only currently defined " "for the maximal ideal (x)") return x.parent().completion(x.parent().gen())(0, x.degree(), **kwds) elif isinstance(x, laurent_series_ring_element.LaurentSeries): return laurent_series_ring_element.LaurentSeries(x.parent(), 0).\ add_bigoh(x.valuation(), **kwds) elif isinstance(x, (int, long, integer.Integer, rational.Rational)): # p-adic number if x <= 0: raise ArithmeticError("x must be a prime power >= 2") F = arith.factor(x) if len(F) != 1: raise ArithmeticError("x must be prime power") p, r = F[0] if r >= 0: return padics_factory.Zp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r, **kwds) else: return padics_factory.Qp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r, **kwds) elif isinstance(x, padic_generic_element.pAdicGenericElement): return x.parent()(0, absprec=x.valuation(), **kwds) elif hasattr(x, 'O'): return x.O(**kwds) raise ArithmeticError("O(%s) not defined" % (x,))