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.arith.all import factor 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 = 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: # 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) apr2 = self.coefficient_n_recursive(pr//(p*p)) val = self.parent.character_used_in_computation.value(p) if val == 0: c = cp*apr1 else: eps = KZ(val) c = cp*apr1 - eps*(p**(self.weight-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 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_unit_order(self): """ Return a list of :class:`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 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.arith.all 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): """ Return a list of :class:`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 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 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 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 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 Möbius 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 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 Möbius 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.arith.all import factor ev = self.eigenvalues c2 = self._coefficients.get(2) if c2 is not None: K = c2.parent() else: if ev.max_coefficient_in_db() >= 2: if not ev.has_eigenvalue(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 = 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) 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] #emf_logger.debug("c{0} = {1}, parent={2}".format(p,cp,cp.parent())) 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: # 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) apr2 = self.coefficient_n_recursive(pr//(p*p)) val = self.parent.character_used_in_computation.value(p) if val == 0: c = cp*apr1 else: eps = KZ(val) c = cp*apr1 - eps*(p**(self.weight-1)) * apr2 #emf_logger.debug("c({0})={1}".format(pr,c)) #ev[pr]=c self._coefficients[pr]=c try: prod *= K(self._coefficients[pr]) except: if hasattr(self._coefficients[pr],'vector'): if len(self._coefficients[pr].vector()) == len(K.power_basis()): prod *= K(self._coefficients[pr].vector()) else: emf_logger.debug("vec={0}".format(self._coefficients[pr].vector())) raise ArithmeticError,"Wrong size of vectors!" else: raise ArithmeticError,"Can not compute product of coefficients!" return prod
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 Ring of integers modulo 15 sage: D [[0, 1, 2, 4, 5, 8, 10]] sage: print designs.difference_family(15,7,3,explain_construction=True) Singer difference set sage: print designs.difference_family(91,10,1,explain_construction=True) Singer difference set sage: print designs.difference_family(64,28,12, explain_construction=True) McFarland 1973 construction 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.finite_field_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) if len(factorization) == 1: from sage.rings.finite_rings.finite_field_constructor import GF K = GF(v, 'z') if are_mcfarland_1973_parameters(v, k, l): if existence: return True elif explain_construction: return "McFarland 1973 construction" else: _, (q, s) = are_mcfarland_1973_parameters(v, k, l, True) G, D = mcfarland_1973_construction(q, s) elif are_hyperplanes_in_projective_geometry_parameters(v, k, l): if existence: return True elif explain_construction: return "Singer difference set" else: _, (q, d) = are_hyperplanes_in_projective_geometry_parameters( v, k, l, True) G, D = singer_difference_set(q, d) elif len(factorization) == 1 and 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) G = K elif len(factorization) == 1 and 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) G = K elif (k == (v - 1) // 2 and l == (k - 1) // 2 and len(factorization) == 2 and abs(pow(*factorization[0]) - pow(*factorization[1])) == 2): # 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) 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) else: 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,))
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 Asymptotic Ring <QQ^n * n^QQ * log(n)^QQ * Signs^n> over Rational Field sage: O(n) O(n) Application with Puiseux series:: sage: P.<y> = PuiseuxSeriesRing(ZZ) sage: y^(1/5) + O(y^(1/3)) y^(1/5) + O(y^(1/3)) sage: y^(1/3) + O(y^(1/5)) O(y^(1/5)) 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, PuiseuxSeries): return x.add_bigoh(x.valuation(), **kwds) elif isinstance(x, (int, 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, ))
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 dft(self, chi = lambda x: x): r""" A discrete Fourier transform "over `\QQ`" using exact `N`-th roots of unity. EXAMPLES:: sage: J = list(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 = list(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 ## PermutationGroup(...) 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 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 dft(self, chi = lambda x: x): """ A discrete Fourier transform "over `\QQ`" using exact `N`-th roots of unity. EXAMPLES:: sage: J = list(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 = list(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 ## PermutationGroup(...) 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)