def iter_positive_forms_with_content(self): if self.__disc is infinity: raise ValueError("infinity is not a true filter index") if self.__reduced: for a in range(1, isqrt(self.__disc // 3) + 1): for b in range(a + 1): g = gcd(a, b) for c in range(a, (b**2 + (self.__disc - 1)) // (4 * a) + 1): yield (a, b, c), gcd(g, c) else: maxtrace = floor(5 * self.__disc / 15 + sqrt(self.__disc) / 2) for a in range(1, maxtrace + 1): for c in range(1, maxtrace - a + 1): g = gcd(a, c) Bu = isqrt(4 * a * c - 1) di = 4 * a * c - self.__disc if di >= 0: Bl = isqrt(di) + 1 else: Bl = 0 for b in range(-Bu, -Bl + 1): yield (a, b, c), gcd(g, b) for b in range(Bl, Bu + 1): yield (a, b, c), gcd(g, b) #! if self.__reduced raise StopIteration
def order_at_cusp(self, cusp): r""" Return the order of vanishing of self at the given cusp. INPUT: - ``cusp`` - a CuspFamily object OUTPUT: - an integer EXAMPLES:: sage: e = EtaProduct(2, {2:24, 1:-24}) sage: e.order_at_cusp(CuspFamily(2, 1)) # cusp at infinity 1 sage: e.order_at_cusp(CuspFamily(2, 2)) # cusp 0 -1 """ if not isinstance(cusp, CuspFamily): raise TypeError("Argument (=%s) should be a CuspFamily" % cusp) if cusp.level() != self.level(): raise ValueError("Cusp not on right curve!") return 1 / ZZ(24) / gcd(cusp.width(), self.level() // cusp.width()) * sum([ ell * self.r(ell) / cusp.width() * (gcd(cusp.width(), self.level() // ell))**2 for ell in self._keys ])
def _find_cusps(self): r""" Calculate the reduced representatives of the equivalence classes of cusps for this group. Adapted from code by Ron Evans. EXAMPLE:: sage: Gamma(8).cusps() # indirect doctest [0, 1/4, 1/3, 3/8, 1/2, 2/3, 3/4, 1, 4/3, 3/2, 5/3, 2, 7/3, 5/2, 8/3, 3, 7/2, 11/3, 4, 14/3, 5, 6, 7, Infinity] """ n = self.level() C = [QQ(x) for x in xrange(n)] n0 = n // 2 n1 = (n + 1) // 2 for r in xrange(1, n1): if r > 1 and gcd(r, n) == 1: C.append(ZZ(r) / ZZ(n)) if n0 == n / 2 and gcd(r, n0) == 1: C.append(ZZ(r) / ZZ(n0)) for s in xrange(2, n1): for r in xrange(1, 1 + n): if GCD_list([s, r, n]) == 1: # GCD_list is ~40x faster than gcd, since gcd wastes loads # of time initialising a Sequence type. u, v = _lift_pair(r, s, n) C.append(ZZ(u) / ZZ(v)) return [Cusp(x) for x in sorted(C)] + [Cusp(1, 0)]
def iter_positive_forms_with_content(self) : if self.__disc is infinity : raise ValueError, "infinity is not a true filter index" if self.__reduced : for a in xrange(1,isqrt(self.__disc // 3) + 1) : for b in xrange(a+1) : g = gcd(a, b) for c in xrange(a, (b**2 + (self.__disc - 1))//(4*a) + 1) : yield (a,b,c), gcd(g,c) else : maxtrace = floor(5*self.__disc / 15 + sqrt(self.__disc)/2) for a in xrange(1, maxtrace + 1) : for c in xrange(1, maxtrace - a + 1) : g = gcd(a,c) Bu = isqrt(4*a*c - 1) di = 4*a*c - self.__disc if di >= 0 : Bl = isqrt(di) + 1 else : Bl = 0 for b in xrange(-Bu, -Bl + 1) : yield (a,b,c), gcd(g,b) for b in xrange(Bl, Bu + 1) : yield (a,b,c), gcd(g,b) #! if self.__reduced raise StopIteration
def DuadicCodeOddPair(F, S1, S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeOddPair(GF(q),S1,S2) ([11, 6] Cyclic Code over GF(3), [11, 6] Cyclic Code over GF(3)) This is consistent with Theorem 6.1.3 in [HP2003]_. """ from sage.misc.stopgap import stopgap stopgap( "The function DuadicCodeOddPair has several issues which may cause wrong results", 25896) from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1, S2, n): raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() k = Mod(q, n).multiplicative_order() FF = GF(q**k, "z") z = FF.gen() zeta = z**((q**k - 1) / n) P1 = PolynomialRing(FF, "x") x = P1.gen() g1 = prod([x - zeta**i for i in S1 + [0]]) g2 = prod([x - zeta**i for i in S2 + [0]]) j = sum([x**i / n for i in range(n)]) P2 = PolynomialRing(F, "x") x = P2.gen() coeffs1 = [ _lift2smallest_field(c)[0] for c in (g1 + j).coefficients(sparse=False) ] coeffs2 = [ _lift2smallest_field(c)[0] for c in (g2 + j).coefficients(sparse=False) ] gg1 = P2(coeffs1) gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) C1 = CyclicCode(length=n, generator_pol=gg1) C2 = CyclicCode(length=n, generator_pol=gg2) return C1, C2
def _iter_positive_forms_with_content_and_discriminant(self) : if self.__disc is infinity : raise ValueError, "infinity is not a true filter index" if self.__reduced : for (l, (u,x)) in enumerate(self.__p1list) : if u == 0 : for a in xrange(self.__level, isqrt(self.__disc // 4) + 1, self.__level) : frpa = 4 * a for b in xrange(a+1) : g = gcd(a // self.__level,b) bsq = b**2 for c in xrange(a, (b**2 + (self.__disc - 1))//(4*a) + 1) : yield (((a,b,c), l), gcd(g,c), frpa*c - bsq) else : for a in xrange(1, isqrt(self.__disc // 3) + 1) : frpa = 4 * a for b in xrange(a+1) : g = gcd(a, b) bsq = b**2 ## We need x**2 * a + x * b + c % N == 0 h = (-((x**2 + 1) * a + x * b)) % self.__level for c in xrange( a + h, (b**2 + (self.__disc - 1))//(4*a) + 1, self.__level ) : yield (((a,b,c), l), gcd(g,(x**2 * a + x * b + c) // self.__level), frpa*c - bsq) #! if self.__reduced else : raise NotImplementedError raise StopIteration
def _find_cusps(self): r""" Calculate the reduced representatives of the equivalence classes of cusps for this group. Adapted from code by Ron Evans. EXAMPLES:: sage: Gamma(8).cusps() # indirect doctest [0, 1/4, 1/3, 3/8, 1/2, 2/3, 3/4, 1, 4/3, 3/2, 5/3, 2, 7/3, 5/2, 8/3, 3, 7/2, 11/3, 4, 14/3, 5, 6, 7, Infinity] """ n = self.level() C = [QQ(x) for x in range(n)] n0=n//2 n1=(n+1)//2 for r in range(1, n1): if r > 1 and gcd(r,n)==1: C.append(ZZ(r)/ZZ(n)) if n0==n/2 and gcd(r,n0)==1: C.append(ZZ(r)/ZZ(n0)) for s in range(2,n1): for r in range(1, 1+n): if GCD_list([s,r,n])==1: # GCD_list is ~40x faster than gcd, since gcd wastes loads # of time initialising a Sequence type. u,v = _lift_pair(r,s,n) C.append(ZZ(u)/ZZ(v)) return [Cusp(x) for x in sorted(C)] + [Cusp(1,0)]
def normalize_coefficients(self, c): r""" If our coefficient ring is the field of fractions over a univariate polynomial ring over the rationals, then we should clear both the numerator and denominator of the denominators of their coefficients. INPUT: - ``self`` -- a Jack basis of the symmetric functions - ``c`` -- a coefficient in the base ring of ``self`` OUTPUT: - divide numerator and denominator by the greatest common divisor EXAMPLES:: sage: JP = SymmetricFunctions(FractionField(QQ['t'])).jack().P() sage: t = JP.base_ring().gen() sage: a = 2/(1/2*t+1/2) sage: JP._normalize_coefficients(a) 4/(t + 1) sage: a = 1/(1/3+1/6*t) sage: JP._normalize_coefficients(a) 6/(t + 2) sage: a = 24/(4*t^2 + 12*t + 8) sage: JP._normalize_coefficients(a) 6/(t^2 + 3*t + 2) """ BR = self.base_ring() if is_FractionField(BR) and BR.base_ring() == QQ: denom = c.denominator() numer = c.numerator() # Clear the denominators a = lcm([i.denominator() for i in denom.coefficients(sparse=False)]) b = lcm([i.denominator() for i in numer.coefficients(sparse=False)]) l = Integer(a).lcm(Integer(b)) denom *= l numer *= l # Divide through by the gcd of the numerators a = gcd([i.numerator() for i in denom.coefficients(sparse=False)]) b = gcd([i.numerator() for i in numer.coefficients(sparse=False)]) l = Integer(a).gcd(Integer(b)) denom = denom // l numer = numer // l return c.parent()(numer, denom) else: return c
def _find_cusps(self): r""" Return an ordered list of inequivalent cusps for self, i.e. a set of representatives for the orbits of self on `\mathbf{P}^1(\QQ)`. These are returned in a reduced form; see self.reduce_cusp for the definition of reduced. ALGORITHM: Lemma 3.2 in Cremona's 1997 book shows that for the action of Gamma1(N) on "signed projective space" `\Q^2 / (\Q_{\geq 0}^+)`, we have `u_1/v_1 \sim u_2 / v_2` if and only if `v_1 = v_2 \bmod N` and `u_1 = u_2 \bmod gcd(v_1, N)`. It follows that every orbit has a representative `u/v` with `v \le N` and `0 \le u \le gcd(v, N)`. We iterate through all pairs `(u,v)` satisfying this. Having found a set containing at least one of every equivalence class modulo Gamma1(N), we can be sure of picking up every class modulo GammaH(N) since this contains Gamma1(N); and the reduce_cusp call does the checking to make sure we don't get any duplicates. EXAMPLES:: sage: Gamma1(5)._find_cusps() [0, 2/5, 1/2, Infinity] sage: Gamma1(35)._find_cusps() [0, 2/35, 1/17, 1/16, 1/15, 1/14, 1/13, 1/12, 3/35, 1/11, 1/10, 1/9, 4/35, 1/8, 2/15, 1/7, 1/6, 6/35, 1/5, 3/14, 8/35, 1/4, 9/35, 4/15, 2/7, 3/10, 11/35, 1/3, 12/35, 5/14, 13/35, 2/5, 3/7, 16/35, 17/35, 1/2, 8/15, 4/7, 3/5, 9/14, 7/10, 5/7, 11/14, 4/5, 6/7, 9/10, 13/14, Infinity] sage: Gamma1(24)._find_cusps() == Gamma1(24).cusps(algorithm='modsym') True sage: GammaH(24, [13,17])._find_cusps() == GammaH(24,[13,17]).cusps(algorithm='modsym') True """ s = [] hashes = [] N = self.level() for d in range(1, 1 + N): w = N.gcd(d) M = int(w) if w > 1 else 2 for a in range(1, M): if gcd(a, w) != 1: continue while gcd(a, d) != 1: a += w c = self.reduce_cusp(Cusp(a, d)) h = hash(c) if not h in hashes: hashes.append(h) s.append(c) return sorted(s)
def _find_cusps(self): r""" Return an ordered list of inequivalent cusps for self, i.e. a set of representatives for the orbits of self on `\mathbf{P}^1(\QQ)`. These are returned in a reduced form; see self.reduce_cusp for the definition of reduced. ALGORITHM: Lemma 3.2 in Cremona's 1997 book shows that for the action of Gamma1(N) on "signed projective space" `\Q^2 / (\Q_{\geq 0}^+)`, we have `u_1/v_1 \sim u_2 / v_2` if and only if `v_1 = v_2 \bmod N` and `u_1 = u_2 \bmod gcd(v_1, N)`. It follows that every orbit has a representative `u/v` with `v \le N` and `0 \le u \le gcd(v, N)`. We iterate through all pairs `(u,v)` satisfying this. Having found a set containing at least one of every equivalence class modulo Gamma1(N), we can be sure of picking up every class modulo GammaH(N) since this contains Gamma1(N); and the reduce_cusp call does the checking to make sure we don't get any duplicates. EXAMPLES:: sage: Gamma1(5)._find_cusps() [0, 2/5, 1/2, Infinity] sage: Gamma1(35)._find_cusps() [0, 2/35, 1/17, 1/16, 1/15, 1/14, 1/13, 1/12, 3/35, 1/11, 1/10, 1/9, 4/35, 1/8, 2/15, 1/7, 1/6, 6/35, 1/5, 3/14, 8/35, 1/4, 9/35, 4/15, 2/7, 3/10, 11/35, 1/3, 12/35, 5/14, 13/35, 2/5, 3/7, 16/35, 17/35, 1/2, 8/15, 4/7, 3/5, 9/14, 7/10, 5/7, 11/14, 4/5, 6/7, 9/10, 13/14, Infinity] sage: Gamma1(24)._find_cusps() == Gamma1(24).cusps(algorithm='modsym') True sage: GammaH(24, [13,17])._find_cusps() == GammaH(24,[13,17]).cusps(algorithm='modsym') True """ s = [] hashes = [] N = self.level() for d in range(1, 1+N): w = N.gcd(d) M = int(w) if w > 1 else 2 for a in range(1,M): if gcd(a, w) != 1: continue while gcd(a, d) != 1: a += w c = self.reduce_cusp(Cusp(a,d)) h = hash(c) if not h in hashes: hashes.append(h) s.append(c) return sorted(s)
def DuadicCodeOddPair(F,S1,S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeOddPair(GF(q),S1,S2) ([11, 6] Cyclic Code over GF(3), [11, 6] Cyclic Code over GF(3)) This is consistent with Theorem 6.1.3 in [HP2003]_. """ from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1,S2,n): raise TypeError("%s, %s must be a splitting of %s."%(S1,S2,n)) q = F.order() k = Mod(q,n).multiplicative_order() FF = GF(q**k,"z") z = FF.gen() zeta = z**((q**k-1)/n) P1 = PolynomialRing(FF,"x") x = P1.gen() g1 = prod([x-zeta**i for i in S1+[0]]) g2 = prod([x-zeta**i for i in S2+[0]]) j = sum([x**i/n for i in range(n)]) P2 = PolynomialRing(F,"x") x = P2.gen() coeffs1 = [_lift2smallest_field(c)[0] for c in (g1+j).coefficients(sparse=False)] coeffs2 = [_lift2smallest_field(c)[0] for c in (g2+j).coefficients(sparse=False)] gg1 = P2(coeffs1) gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) C1 = CyclicCode(length = n, generator_pol = gg1) C2 = CyclicCode(length = n, generator_pol = gg2) return C1,C2
def eval(self, expansion, weight = None) : if weight is None : try : weight = expansion.weight() except AttributeError : raise ValueError, "weight must be defined for the Hecke action" precision = expansion.precision() if precision.is_infinite() : precision = expansion._bounding_precision() else : precision = precision._hecke_operator(self.__l) characters = expansion.non_zero_components() expansion_level = precision.level() if gcd(expansion_level, self.__l) != 1 : raise ValueError, "Level of expansion and of Hecke operator must be coprime." hecke_expansion = dict() for ch in characters : hecke_expansion[ch] = dict( (k, self.hecke_coeff(expansion, ch, k, weight, expansion_level)) for k in precision ) result = expansion.parent()._element_constructor_(hecke_expansion) result._set_precision(expansion.precision()._hecke_operator(self.__l)) return result
def cardinality(self): """ Return the number of Lyndon words with the evaluation e. EXAMPLES:: sage: LyndonWords([]).cardinality() 0 sage: LyndonWords([2,2]).cardinality() 1 sage: LyndonWords([2,3,2]).cardinality() 30 Check to make sure that the count matches up with the number of Lyndon words generated:: sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list() sage: lws = [LyndonWords(comp) for comp in comps] sage: all(lw.cardinality() == len(lw.list()) for lw in lws) True """ evaluation = self._e le = list(evaluation) if not evaluation: return Integer(0) n = sum(evaluation) return sum( moebius(j) * multinomial([ni // j for ni in evaluation]) for j in divisors(gcd(le))) // n
def find_correct_matrix(M, N): r""" Given a matrix M1 that maps infinity to a/c this returns a matrix M2 Matrix([[A,B],[C,D]]) that maps infinity to a Gamma0(N)-equivalent cusp A/C and satisfies, C|N, C>0, (A,N)=1 and N|B. It also returns T^n = Matrix([[1,n],[0,1]]) such that M2*T^n*M1**(-1) is in Gamma0(N). """ a, b, c, d = list(map(lambda x: ZZ(x), M.list())) if (c > 0 and c.divides(N) and gcd(a, N) == 1 and b % N == 0): return M, identity_matrix(2) if c == 0: return Matrix([[1, 0], [N, 1]]), identity_matrix(2) cusps = cusps_of_gamma0(N) for cusp in cusps: if Cusp(QQ(a) / QQ(c)).is_gamma0_equiv(cusp, N): break A, C = cusp.numerator(), cusp.denominator() _, D, b = xgcd(A, N * C) M2 = Matrix([[A, -N * b], [C, D]]) n = 0 T = Matrix([[1, 1], [0, 1]]) tmp = identity_matrix(2) while True: if N.divides((M2 * tmp * M**(-1))[1][0]): return M2, tmp elif N.divides((M2 * tmp**(-1) * M**(-1))[1][0]): return M2, tmp**(-1) tmp = tmp * T
def get_representatives( self, t, N) : r""" A helper function used in hecke_coeff that computes the right coset representatives of $\Gamma^0(t) \cap \Gamma_0(N) \ Gamma_0(N)$ where $\Gamma^0(t)$ is the subgroup of $SL(2,Z)$ where the upper right hand corner is divisible by $t$. NOTE We use the bijection $\Gamma^0(t)\SL(2,Z) \rightarrow P^1(\Z/t\Z)$ given by $A \mapsto [1:0]A$. """ if t == 1 : return [(1,0,0,1)] rep_list = [] for (x,y) in P1List(t): ## we know that (N, x, y) = 1 N1 = gcd(N, x) if N1 != 1 : x = x + t * N // N1 ## we calculate a pair c,d satisfying a minimality condition ## to make later multiplications cheaper (_, d, c) = Integer(x)._xgcd(Integer(N * y), minimal=True) #print (x, y, -N * c, d) rep_list.append((x, y, -N * c, d)) return rep_list
def __init__(self, base_field, length, designed_distance, primitive_root=None, offset=1, jump_size=1, b=0): """ TESTS: ``designed_distance`` must be between 1 and ``length`` (inclusive), otherwise an exception is raised:: sage: C = codes.BCHCode(GF(2), 15, 16) Traceback (most recent call last): ... ValueError: designed_distance must belong to [1, n] """ if not (0 < designed_distance <= length): raise ValueError("designed_distance must belong to [1, n]") if base_field not in Fields() or not base_field.is_finite(): raise ValueError("base_field has to be a finite field") q = base_field.cardinality() s = Zmod(length)(q).multiplicative_order() if gcd(jump_size, q ** s - 1) != 1: raise ValueError("jump_size must be coprime with the order of " "the multiplicative group of the splitting field") D = [(offset + jump_size * i) % length for i in range(designed_distance - 1)] super(BCHCode, self).__init__(field=base_field, length=length, D=D, primitive_root=primitive_root) self._default_decoder_name = "UnderlyingGRS" self._jump_size = jump_size self._offset = offset self._designed_distance = designed_distance
def random_element(self, bound=100, *args, **kwds): r""" Return a random element of `{\rm SL}_2(\ZZ)` with entries whose absolute value is strictly less than bound (default 100). Additional arguments and keywords are passed to the random_element method of ZZ. (Algorithm: Generate a random pair of integers at most bound. If they are not coprime, throw them away and start again. If they are, find an element of `{\rm SL}_2(\ZZ)` whose bottom row is that, and left-multiply it by `\begin{pmatrix} 1 & w \\ 0 & 1\end{pmatrix}` for an integer `w` randomly chosen from a small enough range that the answer still has entries at most bound.) It is, unfortunately, not true that all elements of SL2Z with entries < bound appear with equal probability; those with larger bottom rows are favoured, because there are fewer valid possibilities for w. EXAMPLES:: sage: SL2Z.random_element() [60 13] [83 18] sage: SL2Z.random_element(5) [-1 3] [ 1 -4] Passes extra positional or keyword arguments through:: sage: SL2Z.random_element(5, distribution='1/n') [ 1 -4] [ 0 1] """ if bound <= 1: raise ValueError("bound must be greater than 1") c = ZZ.random_element(1-bound, bound, *args, **kwds) d = ZZ.random_element(1-bound, bound, *args, **kwds) if gcd(c,d) != 1: # try again return self.random_element(bound, *args, **kwds) else: a,b,c,d = lift_to_sl2z(c,d,0) whi = bound wlo = bound if c > 0: whi = min(whi, ((bound - a)/ZZ(c)).ceil()) wlo = min(wlo, ((bound + a)/ZZ(c)).ceil()) elif c < 0: whi = min(whi, ((bound + a)/ZZ(-c)).ceil()) wlo = min(wlo, ((bound - a)/ZZ(-c)).ceil()) if d > 0: whi = min(whi, ((bound - b)/ZZ(d)).ceil()) wlo = min(wlo, ((bound + b)/ZZ(d)).ceil()) elif d < 0: whi = min(whi, ((bound + b)/ZZ(-d)).ceil()) wlo = min(wlo, ((bound - b)/ZZ(-d)).ceil()) w = ZZ.random_element(1-wlo, whi, *args, **kwds) a += c*w b += d*w return self([a,b,c,d])
def hecke_matrix_on_ord(ll, ord_basis, weight = 2, level = 1, eps = None, p=None, prec=None, check_is_operator=True): R = ord_basis.parent().base_ring() if prec is None: try: prec = R.precision_cap() except AttributeError: pass ncols = ZZ(floor( (ord_basis.ncols() - 1) / ll)) + 1 if ncols < ord_basis.nrows(): raise ValueError("Cannot compute the matrix of T_ell with ell=%s because of lack of precision. (nrows = %s, ncols = %s)"%(ll, ord_basis.nrows(), ncols)) M = Matrix(R, ord_basis.nrows(), ncols, 0) if eps is None: eps = lambda ll : ZZ(1) if gcd(level,ll) == 1 else ZZ(0) if weight is None: assert eps(ll) == 0 llpow_eps = 0 else: llpow_eps = ll**(weight-1) * eps(ll) for i, b in enumerate(ord_basis): for j in range(ncols): M[i, j] = b[j * ll] if j % ll == 0: M[i, j] += R(llpow_eps) * b[j // ll] small_mat = ord_basis.submatrix(0,0,ncols = ncols) assert is_echelon(small_mat) ans = solve_xAb_echelon(small_mat,M,p, prec, check=check_is_operator) return ans
def rational_catalan_number(self, p, polynomial=False): r""" Return the ``p``-th rational Catalan number associated to ``self``. It is defined by .. MATH:: \prod_{i = 1}^n \frac{p + (p(d_i-1)) \mod h)}{d_i}, where `d_1, \ldots, d_n` are the degrees and `h` is the Coxeter number. See [STW2016]_ for this formula. INPUT: - ``polynomial`` -- optional boolean (default ``False``) if ``True``, return instead the `q`-analogue as a polynomial in `q` REFERENCES: .. [STW2016] C. Stump, H. Thomas, N. Williams. *Cataland II*, in preparation, 2016. EXAMPLES:: sage: W = ColoredPermutations(1,3) sage: [W.rational_catalan_number(p) for p in [5,7,8]] [7, 12, 15] sage: W = ColoredPermutations(2,2) sage: [W.rational_catalan_number(p) for p in [7,9,11]] [10, 15, 21] TESTS:: sage: W = ColoredPermutations(1,4) sage: W.rational_catalan_number(3, polynomial=True) q^6 + q^4 + q^3 + q^2 + 1 """ from sage.arith.all import gcd from sage.combinat.q_analogues import q_int h = self.coxeter_number() if not gcd(h, p) == 1: raise ValueError( "parameter p = %s is not coprime to the Coxeter number %s" % (p, h)) if polynomial: f = q_int else: f = lambda n: n num = prod( f(p + (p * (deg - 1)) % h) for deg in self.degrees()) den = prod(f(deg) for deg in self.degrees()) return num // den
def _lift_pair(U,V,N): r""" Utility function. Given integers ``U, V, N``, with `N \ge 1` and `{\rm gcd}(U, V, N) = 1`, return a pair `(u, v)` congruent to `(U, V) \bmod N`, such that `{\rm gcd}(u,v) = 1`, `u, v \ge 0`, `v` is as small as possible, and `u` is as small as possible for that `v`. *Warning*: As this function is for internal use, it does not do a preliminary sanity check on its input, for efficiency. It will recover reasonably gracefully if ``(U, V, N)`` are not coprime, but only after wasting quite a lot of cycles! EXAMPLES:: sage: from sage.modular.arithgroup.congroup_gamma import _lift_pair sage: _lift_pair(2,4,7) (9, 4) sage: _lift_pair(2,4,8) # don't do this Traceback (most recent call last): ... ValueError: (U, V, N) must be coprime """ u = U % N v = V % N if v == 0: if u == 1: return (1,0) else: v = N while gcd(u, v) > 1: u = u+N if u > N*v: raise ValueError("(U, V, N) must be coprime") return (u, v)
def eval(self, expansion, weight=None): if weight is None: try: weight = expansion.weight() except AttributeError: raise ValueError, "weight must be defined for the Hecke action" precision = expansion.precision() if precision.is_infinite(): precision = expansion._bounding_precision() else: precision = precision._hecke_operator(self.__l) characters = expansion.non_zero_components() expansion_level = precision.level() if gcd(expansion_level, self.__l) != 1: raise ValueError, "Level of expansion and of Hecke operator must be coprime." hecke_expansion = dict() for ch in characters: hecke_expansion[ch] = dict( (k, self.hecke_coeff(expansion, ch, k, weight, expansion_level)) for k in precision) result = expansion.parent()._element_constructor_(hecke_expansion) result._set_precision(expansion.precision()._hecke_operator(self.__l)) return result
def get_representatives(self, t, N): r""" A helper function used in hecke_coeff that computes the right coset representatives of $\Gamma^0(t) \cap \Gamma_0(N) \ Gamma_0(N)$ where $\Gamma^0(t)$ is the subgroup of $SL(2,Z)$ where the upper right hand corner is divisible by $t$. NOTE We use the bijection $\Gamma^0(t)\SL(2,Z) \rightarrow P^1(\Z/t\Z)$ given by $A \mapsto [1:0]A$. """ if t == 1: return [(1, 0, 0, 1)] rep_list = [] for (x, y) in P1List(t): ## we know that (N, x, y) = 1 N1 = gcd(N, x) if N1 != 1: x = x + t * N // N1 ## we calculate a pair c,d satisfying a minimality condition ## to make later multiplications cheaper (_, d, c) = Integer(x)._xgcd(Integer(N * y), minimal=True) #print (x, y, -N * c, d) rep_list.append((x, y, -N * c, d)) return rep_list
def num_cusps_of_width(N, d): r""" Return the number of cusps on `X_0(N)` of width d. INPUT: - ``N`` - (integer): the level - ``d`` - (integer): an integer dividing N, the cusp width EXAMPLES:: sage: [num_cusps_of_width(18,d) for d in divisors(18)] [1, 1, 2, 2, 1, 1] sage: num_cusps_of_width(4,8) Traceback (most recent call last): ... ValueError: N and d must be positive integers with d|N """ N = ZZ(N) d = ZZ(d) if N <= 0 or d <= 0 or (N % d) != 0: raise ValueError("N and d must be positive integers with d|N") return euler_phi(gcd(d, N//d))
def find_gens_list(klist, r = 0, bound = None, verbose = True): """ Use an elliptic curve variation of Rain's method to find a generator of a subfield of degree r within the ambient fields in klist. """ p = klist[0].characteristic() ngcd = gcd([k.degree() for k in klist]) nlcm = lcm([k.degree() for k in klist]) if r == 0: r = ngcd assert all(k.degree() % r == 0 for k in klist) # This might be useful if elliptic curves defined over an # extension of F_p are used. kb = k.base_ring() # List of candidates for l. lT = find_l(kb, r, bound) if lT is None: raise RuntimeError, "no suitable l found" # Find an elliptic curve with the given trace. E = find_elliptic_curve(kb, lT) if E is None: raise RuntimeError, "no suitable elliptic curve found" return tuple(find_unique_orbit(E.change_ring(k), E.cardinality(extension_degree=k.degree()), lT[0], r) for k in klist)
def bw_shift_rec(dop, shift=ZZ.zero()): Scalars = utilities.mypushout(dop.base_ring().base_ring(), shift.parent()) if dop.parent().is_D(): dop = DifferentialOperator(dop) # compatibility bugware rop = dop._my_to_S() else: # more compatibility bugware Pols_n = PolynomialRing(dop.base_ring().base_ring(), 'n') rop = dop.to_S(ore_algebra.OreAlgebra(Pols_n, 'Sn')) Pols_n, n = rop.base_ring().change_ring(Scalars).objgen() Rops = ore_algebra.OreAlgebra(Pols_n, 'Sn') ordrec = rop.order() rop = Rops([p(n - ordrec + shift) for p in rop]) # Clear_denominators den = lcm([p.denominator() for p in rop]) rop = den * rop # Remove constant common factors to make the recurrence smaller if Scalars is QQ: g = gcd(c for p in rop for c in p) # elif utilities.is_QQi(Scalars): # XXX: too slow (and not general enough) # ZZi = Scalars.maximal_order() # g = ZZi.zero() # for c in (c1 for p in rop for c1 in p): # g = ZZi(g).gcd(ZZi(c)) # gcd returns a nfe # if g.is_one(): # g = None # break else: g = None if g is not None: rop = (1 / g) * rop coeff = [rop[ordrec - k] for k in range(ordrec + 1)] return BwShiftRec(coeff)
def order_at_cusp(self, cusp): r""" Return the order of vanishing of self at the given cusp. INPUT: - ``cusp`` - a CuspFamily object OUTPUT: - an integer EXAMPLES:: sage: e = EtaProduct(2, {2:24, 1:-24}) sage: e.order_at_cusp(CuspFamily(2, 1)) # cusp at infinity 1 sage: e.order_at_cusp(CuspFamily(2, 2)) # cusp 0 -1 """ if not isinstance(cusp, CuspFamily): raise TypeError("Argument (=%s) should be a CuspFamily" % cusp) if cusp.level() != self.level(): raise ValueError("Cusp not on right curve!") return 1/ZZ(24)/gcd(cusp.width(), self.level()//cusp.width()) * sum( [ell*self.r(ell)/cusp.width() * (gcd(cusp.width(), self.level()//ell))**2 for ell in self._keys] )
def random_element(self, bound=100, *args, **kwds): r""" Return a random element of `{\rm SL}_2(\ZZ)` with entries whose absolute value is strictly less than bound (default 100). Additional arguments and keywords are passed to the random_element method of ZZ. (Algorithm: Generate a random pair of integers at most bound. If they are not coprime, throw them away and start again. If they are, find an element of `{\rm SL}_2(\ZZ)` whose bottom row is that, and left-multiply it by `\begin{pmatrix} 1 & w \\ 0 & 1\end{pmatrix}` for an integer `w` randomly chosen from a small enough range that the answer still has entries at most bound.) It is, unfortunately, not true that all elements of SL2Z with entries < bound appear with equal probability; those with larger bottom rows are favoured, because there are fewer valid possibilities for w. EXAMPLES:: sage: SL2Z.random_element() [60 13] [83 18] sage: SL2Z.random_element(5) [-1 3] [ 1 -4] Passes extra positional or keyword arguments through:: sage: SL2Z.random_element(5, distribution='1/n') [ 1 -4] [ 0 1] """ if bound <= 1: raise ValueError("bound must be greater than 1") c = ZZ.random_element(1 - bound, bound, *args, **kwds) d = ZZ.random_element(1 - bound, bound, *args, **kwds) if gcd(c, d) != 1: # try again return self.random_element(bound, *args, **kwds) else: a, b, c, d = lift_to_sl2z(c, d, 0) whi = bound wlo = bound if c > 0: whi = min(whi, ((bound - a) / ZZ(c)).ceil()) wlo = min(wlo, ((bound + a) / ZZ(c)).ceil()) elif c < 0: whi = min(whi, ((bound + a) / ZZ(-c)).ceil()) wlo = min(wlo, ((bound - a) / ZZ(-c)).ceil()) if d > 0: whi = min(whi, ((bound - b) / ZZ(d)).ceil()) wlo = min(wlo, ((bound + b) / ZZ(d)).ceil()) elif d < 0: whi = min(whi, ((bound + b) / ZZ(-d)).ceil()) wlo = min(wlo, ((bound - b) / ZZ(-d)).ceil()) w = ZZ.random_element(1 - wlo, whi, *args, **kwds) a += c * w b += d * w return self([a, b, c, d])
def _lift_pair(U, V, N): r""" Utility function. Given integers ``U, V, N``, with `N \ge 1` and `{\rm gcd}(U, V, N) = 1`, return a pair `(u, v)` congruent to `(U, V) \bmod N`, such that `{\rm gcd}(u,v) = 1`, `u, v \ge 0`, `v` is as small as possible, and `u` is as small as possible for that `v`. *Warning*: As this function is for internal use, it does not do a preliminary sanity check on its input, for efficiency. It will recover reasonably gracefully if ``(U, V, N)`` are not coprime, but only after wasting quite a lot of cycles! EXAMPLE:: sage: from sage.modular.arithgroup.congroup_gamma import _lift_pair sage: _lift_pair(2,4,7) (9, 4) sage: _lift_pair(2,4,8) # don't do this Traceback (most recent call last): ... ValueError: (U, V, N) must be coprime """ u = U % N v = V % N if v == 0: if u == 1: return (1, 0) else: v = N while gcd(u, v) > 1: u = u + N if u > N * v: raise ValueError("(U, V, N) must be coprime") return (u, v)
def num_cusps_of_width(N, d): r""" Return the number of cusps on `X_0(N)` of width d. INPUT: - ``N`` - (integer): the level - ``d`` - (integer): an integer dividing N, the cusp width EXAMPLES:: sage: [num_cusps_of_width(18,d) for d in divisors(18)] [1, 1, 2, 2, 1, 1] sage: num_cusps_of_width(4,8) Traceback (most recent call last): ... ValueError: N and d must be positive integers with d|N """ N = ZZ(N) d = ZZ(d) if N <= 0 or d <= 0 or (N % d) != 0: raise ValueError("N and d must be positive integers with d|N") return euler_phi(gcd(d, N // d))
def get_overconvergent_class_matrices(p,E,prec, sign_at_infinity,use_ps_dists = False,use_sage_db = False,parallelize = False,progress_bar = False): # If the moments are pre-calculated, will load them. Otherwise, calculate and # save them to disk. if use_ps_dists == False: raise NotImplementedError, 'Must use distributions from Pollack-Stevens code in the split case' sgninfty = 'plus' if sign_at_infinity == 1 else 'minus' dist_type = 'ps' if use_ps_dists == True else 'fm' fname = 'moments_%s_%s_%s_%s_%s.sobj'%(p,E.cremona_label(),sgninfty,prec,dist_type) if use_sage_db: try: Phi = db(fname) return Phi except IOError: pass phi0 = E.pollack_stevens_modular_symbol() if sign_at_infinity == 1: phi0 = phi0.plus_part() elif sign_at_infinity == -1: phi0 = phi0.minus_part() else: assert sign_at_infinity == 0 phi0 = phi0.plus_part() + phi0.minus_part() phi0 = 1 / gcd([val.moment(0) for val in phi0.values()]) * phi0 Phi = phi0.lift(p,M = prec - 1,algorithm = 'stevens',eigensymbol = True) Phi._liftee = phi0 return Phi
def _normalize_H(H, level): """ Normalize representatives for a given subgroup H of the units modulo level. .. NOTE:: This function does *not* make any attempt to find a minimal set of generators for H. It simply normalizes the inputs for use in hashing. EXAMPLES:: sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([23], 10) [3] sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([1,5], 7) [5] sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([4,18], 14) Traceback (most recent call last): ... ArithmeticError: The generators [4, 18] must be units modulo 14 sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([3,17], 14) [3] sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([-1,7,9], 10) [7, 9] """ H = [ZZ(h) for h in H] for h in H: if gcd(h, level) > 1: raise ArithmeticError('The generators %s must be units modulo %s'%(H, level)) H = sorted(set([h%level for h in H])) if 1 in H: H.remove(1) return H
def _goodness(n, R, p): """ Return the goodness of ``n`` for the sequence ``R`` and the prime ``p`` -- that is the largest non-``p`` prime power dividing ``period(n)``. INPUT: - ``n`` -- an integer - ``R`` -- an object in the class ``BinaryRecurrenceSequence`` - ``p`` -- a rational prime OUTPUT: - An integer which is the "goodness" of ``n``, i.e. the largest non-``p`` prime power dividing ``period(n)``. EXAMPLES:: sage: R = BinaryRecurrenceSequence(11,2) sage: sage.combinat.binary_recurrence_sequences._goodness(89,R,7) 11 sage: R = BinaryRecurrenceSequence(1,1) sage: sage.combinat.binary_recurrence_sequences._goodness(13,R,7) 4 sage: R.period(13) #the period of R mod 13 is divisible by 7 28 """ #The period of R mod ell K = R.period(n) return _largest_ppower_divisor(K / gcd(K, p))
def __init__(self, base_field, length, designed_distance, primitive_root=None, offset=1, jump_size=1, b=0): """ TESTS: ``designed_distance`` must be between 1 and ``length`` (inclusive), otherwise an exception is raised:: sage: C = codes.BCHCode(GF(2), 15, 16) Traceback (most recent call last): ... ValueError: designed_distance must belong to [1, n] """ if not (0 < designed_distance <= length): raise ValueError("designed_distance must belong to [1, n]") if base_field not in Fields or not base_field.is_finite(): raise ValueError("base_field has to be a finite field") q = base_field.cardinality() s = Zmod(length)(q).multiplicative_order() if gcd(jump_size, q ** s - 1) != 1: raise ValueError("jump_size must be coprime with the order of " "the multiplicative group of the splitting field") D = [(offset + jump_size * i) % length for i in range(designed_distance - 1)] super(BCHCode, self).__init__(field=base_field, length=length, D=D, primitive_root=primitive_root) self._default_decoder_name = "UnderlyingGRS" self._jump_size = jump_size self._offset = offset self._designed_distance = designed_distance
def cardinality(self): """ Returns the number of Lyndon words with the evaluation e. EXAMPLES:: sage: LyndonWords([]).cardinality() 0 sage: LyndonWords([2,2]).cardinality() 1 sage: LyndonWords([2,3,2]).cardinality() 30 Check to make sure that the count matches up with the number of Lyndon words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list() sage: lws = [LyndonWords(comp) for comp in comps] sage: all(lw.cardinality() == len(lw.list()) for lw in lws) True """ evaluation = self._e le = builtins.list(evaluation) if len(evaluation) == 0: return 0 n = sum(evaluation) return sum([ moebius(j) * factorial(n / j) / prod([factorial(ni / j) for ni in evaluation]) for j in divisors(gcd(le)) ]) / n
def blift(LF, Li, p, S=None): r""" Search for a solution to the given list of inequalities. If found, lift the solution to an appropriate valuation. See Lemma 3.3.6 in [Molnar]_ INPUT: - ``LF`` -- a list of integer polynomials in one variable (the normalized coefficients) - ``Li`` -- an integer, the bound on coefficients - ``p`` -- a prime OUTPUT: - boolean -- whether or not the lift is successful - integer -- the lift EXAMPLES:: sage: R.<b> = PolynomialRing(QQ) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import blift sage: blift([8*b^3 + 12*b^2 + 6*b + 1, 48*b^2 + 483*b + 117, 72*b + 1341, -24*b^2 + 411*b + 99, -144*b + 1233, -216*b], 2, 3) (True, 4) """ P = LF[0].parent() #Determine which inequalities are trivial, and scale the rest, so that we only lift #as many times as needed. keepScaledIneqs = [scale(P(coeff), Li, p) for coeff in LF if coeff != 0] keptVals = [i[2] for i in keepScaledIneqs if i[0]] if keptVals != []: #Determine the valuation to lift until. liftval = max(keptVals) else: #All inequalities are satisfied. return True, 1 if S is None: S = PolynomialRing(Zmod(p), 'b') keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]] #We need a solution for each polynomial on the left hand side of the inequalities, #so we need only find a solution for their gcd. g = gcd(keptScaledIneqs) rts = g.roots(multiplicities=False) for r in rts: #Recursively try to lift each root r_initial = QQ(r) newInput = P([r_initial, p]) LG = [F(newInput) for F in LF] lift, lifted = blift(LG, Li, p, S=S) if lift: #Lift successful. return True, r_initial + p * lifted #Lift non successful. return False, 0
def primitive(self, signed=True): """ Return hyperplane defined by primitive equation. INPUT: - ``signed`` -- boolean (optional, default: ``True``); whether to preserve the overall sign OUTPUT: Hyperplane whose linear expression has common factors and denominators cleared. That is, the same hyperplane (with the same sign) but defined by a rescaled equation. Note that different linear expressions must define different hyperplanes as comparison is used in caching. If ``signed``, the overall rescaling is by a positive constant only. EXAMPLES:: sage: H.<x,y> = HyperplaneArrangements(QQ) sage: h = -1/3*x + 1/2*y - 1; h Hyperplane -1/3*x + 1/2*y - 1 sage: h.primitive() Hyperplane -2*x + 3*y - 6 sage: h == h.primitive() False sage: (4*x + 8).primitive() Hyperplane x + 0*y + 2 sage: (4*x - y - 8).primitive(signed=True) # default Hyperplane 4*x - y - 8 sage: (4*x - y - 8).primitive(signed=False) Hyperplane -4*x + y + 8 """ from sage.arith.all import lcm, gcd coeffs = self.coefficients() try: d = lcm([x.denom() for x in coeffs]) n = gcd([x.numer() for x in coeffs]) except AttributeError: return self if not signed: for x in coeffs: if x > 0: break if x < 0: d = -d break parent = self.parent() d = parent.base_ring()(d) n = parent.base_ring()(n) if n == 0: n = parent.base_ring().one() return parent(self * d / n)
def blift(LF, Li, p, S=None): r""" Search for a solution to the given list of inequalities. If found, lift the solution to an appropriate valuation. See Lemma 3.3.6 in [Molnar]_ INPUT: - ``LF`` -- a list of integer polynomials in one variable (the normalized coefficients). - ``Li`` -- an integer, the bound on coefficients. - ``p`` -- a prime. OUTPUT: - Boolean -- whether or not the lift is successful. - integer -- the lift. EXAMPLES:: sage: R.<b> = PolynomialRing(QQ) sage: from sage.schemes.projective.endPN_minimal_model import blift sage: blift([8*b^3 + 12*b^2 + 6*b + 1, 48*b^2 + 483*b + 117, 72*b + 1341, -24*b^2 + 411*b + 99, -144*b + 1233, -216*b], 2, 3) (True, 4) """ P = LF[0].parent() #Determine which inequalities are trivial, and scale the rest, so that we only lift #as many times as needed. keepScaledIneqs = [scale(P(coeff),Li,p) for coeff in LF if coeff != 0] keptVals = [i[2] for i in keepScaledIneqs if i[0]] if keptVals != []: #Determine the valuation to lift until. liftval = max(keptVals) else: #All inequalities are satisfied. return True,1 if S is None: S = PolynomialRing(Zmod(p),'b') keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]] #We need a solution for each polynomial on the left hand side of the inequalities, #so we need only find a solution for their gcd. g = gcd(keptScaledIneqs) rts = g.roots(multiplicities = False) for r in rts: #Recursively try to lift each root r_initial = QQ(r) newInput = P([r_initial, p]) LG = [F(newInput) for F in LF] lift,lifted = blift(LG,Li,p,S=S) if lift: #Lift successful. return True,r_initial + p*lifted #Lift non successful. return False,0
def rational_catalan_number(self, p, polynomial=False): r""" Return the ``p``-th rational Catalan number associated to ``self``. It is defined by .. MATH:: \prod_{i = 1}^n \frac{p + (p(d_i-1)) \mod h)}{d_i}, where `d_1, \ldots, d_n` are the degrees and `h` is the Coxeter number. See [STW2016]_ for this formula. INPUT: - ``polynomial`` -- optional boolean (default ``False``) if ``True``, return instead the `q`-analogue as a polynomial in `q` REFERENCES: .. [STW2016] C. Stump, H. Thomas, N. Williams. *Cataland II*, in preparation, 2016. EXAMPLES:: sage: W = ColoredPermutations(1,3) sage: [W.rational_catalan_number(p) for p in [5,7,8]] [7, 12, 15] sage: W = ColoredPermutations(2,2) sage: [W.rational_catalan_number(p) for p in [7,9,11]] [10, 15, 21] TESTS:: sage: W = ColoredPermutations(1,4) sage: W.rational_catalan_number(3, polynomial=True) q^6 + q^4 + q^3 + q^2 + 1 """ from sage.arith.all import gcd from sage.combinat.q_analogues import q_int h = self.coxeter_number() if not gcd(h,p) == 1: raise ValueError("parameter p = %s is not coprime to the Coxeter number %s" % (p, h)) if polynomial: f = q_int else: f = lambda n: n num = prod(f(p + (p * (deg - 1)) % h) for deg in self.degrees()) den = prod(f(deg) for deg in self.degrees()) return num // den
def arith_prod_of_partitions(l1, l2): # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2` # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a # partition of `nm`. term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) for pair in product(l1, l2)) return Partition(sorted(term_iterable, reverse=True))
def __contains__(self, f) : if self.__disc is infinity : return True (a, b, c) = f disc = 4*a*c - b**2 if disc == 0 : return gcd([a, b, c]) < self._indefinite_content_bound() else : return disc < self.__disc
def __contains__(self, f): if self.__disc is infinity: return True (a, b, c) = f disc = 4 * a * c - b**2 if disc == 0: return gcd([a, b, c]) < self._indefinite_content_bound() else: return disc < self.__disc
def cusps_of_gamma0(N): r""" INPUT: - N, an int OUTPUT: - list of representatives of cusps of Gamma0(N) given in Corollary 6.3.23 of [Cohen-Stromberg]. In particular they are of the form a/b with b|N, b>0 and (a,N) = 1 """ cusps = [] for b in divisors(N): for a0 in range(gcd(b, N / b)): if gcd([a0, b, N / b]) == 1: a = a0 while True: if gcd(a, N) == 1: cusps.append(QQ(a) / QQ(b)) break else: a += gcd(b, N / b) return cusps
def cone_triangulate(C, hyperplane=None): r""" Triangulation of rational cone contained in the positive quadrant. EXAMPLES:: sage: from surface_dynamics.misc.linalg import cone_triangulate sage: P = Polyhedron(rays=[(1,0,0),(0,1,0),(1,0,1),(0,1,1)]) sage: list(cone_triangulate(P)) # random [[(0, 1, 1), (0, 1, 0), (1, 0, 0)], [(0, 1, 1), (1, 0, 1), (1, 0, 0)]] sage: len(_) 2 sage: rays = [(0, 1, 0, -1, 0, 0), ....: (1, 0, -1, 0, 0, -1), ....: (0, 1, -1, 0, 0, -1), ....: (0, 0, 1, 0, 0, 0), ....: (0, 0, 0, 1, 0, -1), ....: (1, -1, 0, 0, 1, -1), ....: (0, 0, 0, 0, 1, -1), ....: (0, 0, 1, -1, 1, 0), ....: (0, 0, 1, -1, 0, 0), ....: (0, 0, 1, 0, -1, 0), ....: (0, 0, 0, 1, -1, -1), ....: (1, -1, 0, 0, 0, -1), ....: (0, 0, 0, 0, 0, -1)] sage: P = Polyhedron(rays=rays) sage: list(cone_triangulate(P, hyperplane=(1, 2, 3, -1, 0, -5))) # random [[(0, 0, 0, 0, 0, -1), (0, 0, 0, 0, 1, -1), (0, 0, 0, 1, -1, -1), (0, 0, 1, 0, 0, 0), (0, 1, -1, 0, 0, -1), (1, -1, 0, 0, 1, -1)], ... (0, 0, 1, 0, 0, 0), (0, 1, -1, 0, 0, -1), (0, 1, 0, -1, 0, 0), (1, -1, 0, 0, 1, -1), (1, 0, -1, 0, 0, -1)]] sage: len(_) 16 """ rays = [r.vector() for r in C.rays()] dim = len(rays[0]) if hyperplane is None: hyperplane = [1] * dim scalings = [sum(x * h for x, h in zip(r, hyperplane)) for r in rays] assert all(s > 0 for s in scalings) normalized_rays = [r / s for r, s in zip(rays, scalings)] P = Polyhedron(vertices=normalized_rays) for t in P.triangulate(): simplex = [P.Vrepresentation(i).vector() for i in t] yield [(r / gcd(r)).change_ring(ZZ) for r in simplex]
def _find_cusps(self): r""" Return an ordered list of inequivalent cusps for self, i.e. a set of representatives for the orbits of self on `\mathbb{P}^1(\QQ)`. These are returned in a reduced form; see self.reduce_cusp for the definition of reduced. ALGORITHM: Uses explicit formulae specific to `\Gamma_0(N)`: a reduced cusp on `\Gamma_0(N)` is always of the form `a/d` where `d | N`, and `a_1/d \sim a_2/d` if and only if `a_1 \cong a_2 \bmod {\rm gcd}(d, N/d)`. EXAMPLES:: sage: Gamma0(90)._find_cusps() [0, 1/45, 1/30, 1/18, 1/15, 1/10, 1/9, 2/15, 1/6, 1/5, 1/3, 11/30, 1/2, 2/3, 5/6, Infinity] sage: Gamma0(1).cusps() [Infinity] sage: Gamma0(180).cusps() == Gamma0(180).cusps(algorithm='modsym') True """ N = self.level() s = [] for d in arith.divisors(N): w = arith.gcd(d, N//d) if w == 1: if d == 1: s.append(Cusp(1,0)) elif d == N: s.append(Cusp(0,1)) else: s.append(Cusp(1,d)) else: for a in xrange(1, w): if arith.gcd(a, w) == 1: while arith.gcd(a, d//w) != 1: a += w s.append(Cusp(a,d)) return sorted(s)
def _find_cusps(self): r""" Return an ordered list of inequivalent cusps for self, i.e. a set of representatives for the orbits of self on `\mathbb{P}^1(\QQ)`. These are returned in a reduced form; see self.reduce_cusp for the definition of reduced. ALGORITHM: Uses explicit formulae specific to `\Gamma_0(N)`: a reduced cusp on `\Gamma_0(N)` is always of the form `a/d` where `d | N`, and `a_1/d \sim a_2/d` if and only if `a_1 \cong a_2 \bmod {\rm gcd}(d, N/d)`. EXAMPLES:: sage: Gamma0(90)._find_cusps() [0, 1/45, 1/30, 1/18, 1/15, 1/10, 1/9, 2/15, 1/6, 1/5, 1/3, 11/30, 1/2, 2/3, 5/6, Infinity] sage: Gamma0(1).cusps() [Infinity] sage: Gamma0(180).cusps() == Gamma0(180).cusps(algorithm='modsym') True """ N = self.level() s = [] for d in arith.divisors(N): w = arith.gcd(d, N // d) if w == 1: if d == 1: s.append(Cusp(1, 0)) elif d == N: s.append(Cusp(0, 1)) else: s.append(Cusp(1, d)) else: for a in xrange(1, w): if arith.gcd(a, w) == 1: while arith.gcd(a, d // w) != 1: a += w s.append(Cusp(a, d)) return sorted(s)
def _kohnen_rho(self, t, a): dt = (-1)**(t.nrows() // 2) * t.det() d = fundamental_discriminant(dt) eps = isqrt(dt // d) res = 1 for (p, e) in gcd(a, eps).factor(): pol = self._kohnen_rho_polynomial(t, p).coefficients() if e < len(pol): res = res * pol[e] return res
def _new_group_from_level(self, level): r""" Return a new group of the same type (Gamma0, Gamma1, or GammaH) as self of the given level. In the case that self is of type GammaH, we take the largest H inside `(\ZZ/ \text{level}\ZZ)^\times` which maps to H, namely its inverse image under the natural reduction map. EXAMPLES:: sage: G = Gamma0(20) sage: G._new_group_from_level(4) Congruence Subgroup Gamma0(4) sage: G._new_group_from_level(40) Congruence Subgroup Gamma0(40) sage: G = Gamma1(10) sage: G._new_group_from_level(6) Traceback (most recent call last): ... ValueError: one level must divide the other sage: G = GammaH(50,[7]); G Congruence Subgroup Gamma_H(50) with H generated by [7] sage: G._new_group_from_level(25) Congruence Subgroup Gamma_H(25) with H generated by [7] sage: G._new_group_from_level(10) Congruence Subgroup Gamma0(10) sage: G._new_group_from_level(100) Congruence Subgroup Gamma_H(100) with H generated by [7, 57] """ from .congroup_gamma0 import is_Gamma0 from .congroup_gamma1 import is_Gamma1 from .congroup_gammaH import is_GammaH from .all import Gamma0, Gamma1, GammaH N = self.level() if (level%N) and (N%level): raise ValueError("one level must divide the other") if is_Gamma0(self): return Gamma0(level) elif is_Gamma1(self): return Gamma1(level) elif is_GammaH(self): H = self._generators_for_H() if level > N: d = level // N diffs = [ N*i for i in range(d) ] newH = [ h + diff for h in H for diff in diffs ] return GammaH(level, [x for x in newH if gcd(level, x) == 1]) else: return GammaH(level, [ h%level for h in H ]) else: raise NotImplementedError
def _kohnen_rho(self, t, a) : dt = (-1)**(t.nrows() // 2) * t.det() d = fundamental_discriminant(dt) eps = isqrt(dt // d) res = 1 for (p,e) in gcd(a, eps).factor() : pol = self._kohnen_rho_polynomial(t, p).coefficients() if e < len(pol) : res = res * pol[e] return res
def ncusps(self): r""" Return the number of cusps of this subgroup `\Gamma_0(N)`. EXAMPLES:: sage: [Gamma0(n).ncusps() for n in [1..19]] [1, 2, 2, 3, 2, 4, 2, 4, 4, 4, 2, 6, 2, 4, 4, 6, 2, 8, 2] sage: [Gamma0(n).ncusps() for n in prime_range(2,100)] [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] """ n = self.level() return sum([arith.euler_phi(arith.gcd(d,n//d)) for d in n.divisors()])
def basiclemma(self,M): """ Finds a number represented by self and coprime to M. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [2, 1, 3]) sage: Q.basiclemma(6) 71 """ a=self(self.basiclemmavec(M)) assert gcd(a,M) == 1 return a
def _mul_(self, other): """ Multiply this Hecke operator by another element of the same algebra. If the other element is of the form `T_m` for some m, we check whether the product is equal to `T_{mn}` and return that; if the product is not (easily seen to be) of the form `T_{mn}`, then we calculate the product of the two matrices and return a Hecke algebra element defined by that. EXAMPLES: We create the space of modular symbols of level `11` and weight `2`, then compute `T_2` and `T_3` on it, along with their composition. :: sage: M = ModularSymbols(11) sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3) sage: t2*t3 # indirect doctest Hecke operator T_6 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field sage: t3.matrix() * t2.matrix() [12 0 -2] [ 0 2 0] [ 0 0 2] sage: (t2*t3).matrix() [12 0 -2] [ 0 2 0] [ 0 0 2] When we compute `T_2^5` the result is not (easily seen to be) a Hecke operator of the form `T_n`, so it is returned as a Hecke module homomorphism defined as a matrix:: sage: t2**5 Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by: [243 0 -55] [ 0 -32 0] [ 0 0 -32] """ if isinstance(other, HeckeOperator) and other.parent() == self.parent(): n = None if arith.gcd(self.__n, other.__n) == 1: n = self.__n * other.__n else: P = set(arith.prime_divisors(self.domain().level())) if P.issubset(set(arith.prime_divisors(self.__n))) and \ P.issubset(set(arith.prime_divisors(other.__n))): n = self.__n * other.__n if n: return HeckeOperator(self.parent(), n) # otherwise return self.matrix_form() * other
def cardinality(self): r""" Return the number of integer necklaces with the evaluation ``content``. The formula for the number of necklaces of content `\alpha` a composition of `n` is: .. MATH:: \sum_{d|gcd(\alpha)} \phi(d) \binom{n/d}{\alpha_1/d, \ldots, \alpha_\ell/d}, where `\phi(d)` is the Euler `\phi` function. EXAMPLES:: sage: Necklaces([]).cardinality() 0 sage: Necklaces([2,2]).cardinality() 2 sage: Necklaces([2,3,2]).cardinality() 30 sage: Necklaces([0,3,2]).cardinality() 2 Check to make sure that the count matches up with the number of necklace words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2],[0,4,2],[2,0,4]]+Compositions(4).list() sage: ns = [Necklaces(comp) for comp in comps] sage: all(n.cardinality() == len(n.list()) for n in ns) True """ evaluation = self._content le = list(evaluation) if not le: return ZZ.zero() n = sum(le) return ZZ.sum(euler_phi(j) * factorial(n // j) // prod(factorial(ni // j) for ni in evaluation) for j in divisors(gcd(le))) // n
def reduce(self, t) : ## We compute the rational diagonal form of t. Whenever a zero entry occures we ## find a primitive isotropic vector and apply a base change, such that t finally ## has the form diag(0,0,...,P) where P is positive definite. P will then be a ## LLL reduced. ot = t t = matrix(QQ, t) n = t.nrows() u = identity_matrix(QQ, n) for i in xrange(n) : if t[i,i] < 0 : return None elif t[i,i] == 0 : ## get the isotropic vector v = u.column(i) v = v.denominator() * v v = v / gcd(list(v)) u = self._gln_lift(v, 0) t = u.transpose() * ot * u ts = self.reduce(t.submatrix(1,1,n-1,n-1)) if ts is None : return None t.set_block(1, 1, ts[0]) t.set_immutable() return (t,1) else : for j in xrange(i + 1, n) : us = identity_matrix(QQ, n, n) us[i,j] = -t[i,j]/t[i,i] u = u * us t.add_multiple_of_row(j, i, -t[j,i]/t[i,i]) t.add_multiple_of_column(j, i, -t[i,j]/t[i,i]) u = ot.LLL_gram() t = u.transpose() * ot * u t.set_immutable() return (t, 1)
def hecke_operator(self, n): """ Return the `n`-th Hecke operator, for `n` any positive integer coprime to the level. EXAMPLES:: sage: T = ModularSymbols(Gamma1(5),3).anemic_hecke_algebra() sage: T.hecke_operator(2) Hecke operator T_2 on Modular Symbols space of dimension 4 for Gamma_1(5) of weight 3 with sign 0 and over Rational Field sage: T.hecke_operator(5) Traceback (most recent call last): ... IndexError: Hecke operator T_5 not defined in the anemic Hecke algebra """ n = int(n) if arith.gcd(self.module().level(), n) != 1: raise IndexError("Hecke operator T_%s not defined in the anemic Hecke algebra"%n) return self.module()._hecke_operator_class()(self, n)