def __call__(self, Q, P): from sage.rings.all import ZZ, QQ from sage.misc.all import sage_eval s, Q, P = self.raw(Q, P) raw = s if 'the prime to 2 part of the conductor' in s: prime_to_2_conductor_only = True else: prime_to_2_conductor_only = False x = QQ['x'].gen(0) i = s.find('y^2 = ') + len('y^2 = ') j = i + s[i:].find('\n') minimal_equation = sage_eval(s[i:j], locals={'x': x}) s = s[j + 1:] i = s.find('[') j = s.find(']') minimal_disc = ZZ(eval(s[i + 1:j].replace(',', '**').replace(';', '*'))) phrase = 'the conductor is ' j = s.find(phrase) assert j != -1 k = s[j:].find('\n') prime_to_2_conductor = ZZ(s[j + len(phrase):j + k]) local_data = {} while True: i = s.find('p=') if i == -1: break j = s[i + 2:].find('p=') if j == -1: j = s.find('\n \n') assert j != -1 else: j = j + (i + 2) k = i + s[i:].find('\n') p = ZZ(s[i + 2:k]) data = s[k + 1:j].strip().replace(' : ', ': ') local_data[p] = data s = s[j:] return ReductionData(raw, P, Q, minimal_equation, minimal_disc, local_data, prime_to_2_conductor, prime_to_2_conductor_only)
def __call__(self, Q, P): from sage.rings.all import ZZ, QQ from sage.misc.all import sage_eval s, Q, P = self.raw(Q, P) raw = s if 'the prime to 2 part of the conductor' in s: prime_to_2_conductor_only = True else: prime_to_2_conductor_only = False x = QQ['x'].gen(0) i = s.find('y^2 = ') + len('y^2 = ') j = i + s[i:].find('\n') minimal_equation = sage_eval(s[i:j], locals={'x':x}) s = s[j+1:] i = s.find('[') j = s.find(']') minimal_disc = ZZ(eval(s[i+1:j].replace(',','**').replace(';','*'))) phrase = 'the conductor is ' j = s.find(phrase) assert j != -1 k = s[j:].find('\n') prime_to_2_conductor = ZZ(s[j+len(phrase):j+k]) local_data = {} while True: i = s.find('p=') if i == -1: break j = s[i+2:].find('p=') if j == -1: j = s.find('\n \n') assert j != -1 else: j = j + (i+2) k = i + s[i:].find('\n') p = ZZ(s[i+2:k]) data = s[k+1:j].strip().replace(' : ',': ') local_data[p] = data s = s[j:] return ReductionData(raw, P, Q, minimal_equation, minimal_disc, local_data, prime_to_2_conductor, prime_to_2_conductor_only)
def __call__(self, Q, P): from sage.rings.all import ZZ, QQ from sage.misc.all import sage_eval s, Q, P = self.raw(Q, P) raw = s if "the prime to 2 part of the conductor" in s: prime_to_2_conductor_only = True else: prime_to_2_conductor_only = False x = QQ["x"].gen(0) i = s.find("y^2 = ") + len("y^2 = ") j = i + s[i:].find("\n") minimal_equation = sage_eval(s[i:j], locals={"x": x}) s = s[j + 1 :] i = s.find("[") j = s.find("]") minimal_disc = ZZ(eval(s[i + 1 : j].replace(",", "**").replace(";", "*"))) phrase = "the conductor is " j = s.find(phrase) assert j != -1 k = s[j:].find("\n") prime_to_2_conductor = ZZ(s[j + len(phrase) : j + k]) local_data = {} while True: i = s.find("p=") if i == -1: break j = s[i + 2 :].find("p=") if j == -1: j = s.find("\n \n") assert j != -1 else: j = j + (i + 2) k = i + s[i:].find("\n") p = ZZ(s[i + 2 : k]) data = s[k + 1 : j].strip().replace(" : ", ": ") local_data[p] = data s = s[j:] return ReductionData( raw, P, Q, minimal_equation, minimal_disc, local_data, prime_to_2_conductor, prime_to_2_conductor_only )
def buzzard_tpslopes(p, N, kmax): """ Returns a vector of length kmax, whose `k`'th entry (`0 \leq k \leq k_{max}`) is the conjectural sequence of valuations of eigenvalues of `T_p` on forms of level `N`, weight `k`, and trivial character. This conjecture is due to Kevin Buzzard, and is only made assuming that `p` does not divide `N` and if `p` is `\Gamma_0(N)`-regular. EXAMPLES:: sage: c = buzzard_tpslopes(2,1,50) sage: c[50] [4, 8, 13] Hence Buzzard would conjecture that the `2`-adic valuations of the eigenvalues of `T_2` on cusp forms of level 1 and weight `50` are `[4,8,13]`, which indeed they are, as one can verify by an explicit computation using, e.g., modular symbols:: sage: M = ModularSymbols(1,50, sign=1).cuspidal_submodule() sage: T = M.hecke_operator(2) sage: f = T.charpoly('x') sage: f.newton_slopes(2) [13, 8, 4] AUTHORS: - Kevin Buzzard: several PARI/GP scripts - William Stein (2006-03-17): small Sage wrapper of Buzzard's scripts """ v = gp().eval('tpslopes(%s, %s, %s)' % (p, N, kmax)) v = sage_eval(v) v.insert(0, []) # so v[k] = info about weight k (since python is 0-based) return v
def buzzard_tpslopes(p, N, kmax): """ Returns a vector of length kmax, whose `k`'th entry (`0 \leq k \leq k_{max}`) is the conjectural sequence of valuations of eigenvalues of `T_p` on forms of level `N`, weight `k`, and trivial character. This conjecture is due to Kevin Buzzard, and is only made assuming that `p` does not divide `N` and if `p` is `\Gamma_0(N)`-regular. EXAMPLES:: sage: c = buzzard_tpslopes(2,1,50) sage: c[50] [4, 8, 13] Hence Buzzard would conjecture that the `2`-adic valuations of the eigenvalues of `T_2` on cusp forms of level 1 and weight `50` are `[4,8,13]`, which indeed they are, as one can verify by an explicit computation using, e.g., modular symbols:: sage: M = ModularSymbols(1,50, sign=1).cuspidal_submodule() sage: T = M.hecke_operator(2) sage: f = T.charpoly('x') sage: f.newton_slopes(2) [13, 8, 4] AUTHORS: - Kevin Buzzard: several PARI/GP scripts - William Stein (2006-03-17): small Sage wrapper of Buzzard's scripts """ v = gp().eval('tpslopes(%s, %s, %s)'%(p,N,kmax)) v = sage_eval(v) v.insert(0, []) # so v[k] = info about weight k (since python is 0-based) return v
def guess(self, sequence, algorithm='sage'): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'sage' - the default is to use Sage's matrix kernel function - 'pari' - use Pari's implementation of LLL - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found With the default kernel method, trailing zeroes are chopped off before a guessing attempt. This may reduce the data below the accepted length of six values. EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: C.guess([1,2,4,8,16,32]) C-finite sequence, generated by -1/2/(x - 1/2) sage: r = C.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by -1/2/(x - 1/2) sage: r[0:5] [1, 2, 4, 8, 16] """ S = self.polynomial_ring() if algorithm == 'bm': from sage.matrix.berlekamp_massey import berlekamp_massey if len(sequence) < 2: raise ValueError('Sequence too short for guessing.') R = PowerSeriesRing(QQ, 'x') if len(sequence) % 2: sequence.pop() l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).reverse()) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) elif algorithm == 'pari': global _gp if len(sequence) < 6: raise ValueError('Sequence too short for guessing.') if _gp is None: _gp = Gp() _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") _gp.set('gf', sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix from sage.functions.other import ceil from numpy import trim_zeros seq = sequence[:] while seq and sequence[-1] == 0: seq.pop() l = len(seq) if l == 0: return 0 if l < 6: raise ValueError('Sequence too short for guessing.') hl = ceil(ZZ(l) / 2) A = matrix([sequence[k:k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 R = PolynomialRing(QQ, 'x') den = R(trim_zeros(K.basis()[-1].list()[::-1])) if den == 1: return 0 offset = next((i for i, x in enumerate(sequence) if x), None) S = PowerSeriesRing(QQ, 'x', default_prec=l - offset) num = S(R(sequence) * den).truncate(ZZ(l) // 2 + 1) if num == 0 or sequence != S(num / den).list(): return 0 else: return CFiniteSequence(num / den)
def guess(self, sequence, algorithm="sage"): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'sage' - the default is to use Sage's matrix kernel function - 'pari' - use Pari's implementation of LLL - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found With the default kernel method, trailing zeroes are chopped off before a guessing attempt. This may reduce the data below the accepted length of six values. EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: C.guess([1,2,4,8,16,32]) C-finite sequence, generated by 1/(-2*x + 1) sage: r = C.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by 1/(-2*x + 1) sage: r[0:5] [1, 2, 4, 8, 16] """ S = self.polynomial_ring() if algorithm == "bm": from sage.matrix.berlekamp_massey import berlekamp_massey if len(sequence) < 2: raise ValueError("Sequence too short for guessing.") R = PowerSeriesRing(QQ, "x") if len(sequence) % 2 == 1: sequence = sequence[:-1] l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).list()[::-1]) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) elif algorithm == "pari": global _gp if len(sequence) < 6: raise ValueError("Sequence too short for guessing.") if _gp is None: _gp = Gp() _gp( "ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q" ) _gp.set("gf", sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix from sage.functions.other import floor, ceil from numpy import trim_zeros l = len(sequence) while l > 0 and sequence[l - 1] == 0: l -= 1 sequence = sequence[:l] if l == 0: return 0 if l < 6: raise ValueError("Sequence too short for guessing.") hl = ceil(ZZ(l) / 2) A = matrix([sequence[k : k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 R = PolynomialRing(QQ, "x") den = R(trim_zeros(K.basis()[-1].list()[::-1])) if den == 1: return 0 offset = next((i for i, x in enumerate(sequence) if x != 0), None) S = PowerSeriesRing(QQ, "x", default_prec=l - offset) num = S(R(sequence) * den).add_bigoh(floor(ZZ(l) / 2 + 1)).truncate() if num == 0 or sequence != S(num / den).list(): return 0 else: return CFiniteSequence(num / den)
def riemann_roch_basis(self, D): r""" Return a basis for the Riemann-Roch space corresponding to `D`. This uses Singular's Brill-Noether implementation. INPUT: - ``D`` - a divisor OUTPUT: A list of function field elements that form a basis of the Riemann-Roch space EXAMPLE:: sage: R.<x,y,z> = GF(2)[] sage: f = x^3*y + y^3*z + x*z^3 sage: C = Curve(f); pts = C.rational_points() sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ]) sage: C.riemann_roch_basis(D) [x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)] :: sage: R.<x,y,z> = GF(5)[] sage: f = x^7 + y^7 + z^7 sage: C = Curve(f); pts = C.rational_points() sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ]) sage: C.riemann_roch_basis(D) [(-2*x + y)/(x + y), (-x + z)/(x + y)] .. NOTE:: Currently this only works over prime field and divisors supported on rational points. """ f = self.defining_polynomial()._singular_() singular = f.parent() singular.lib('brnoeth') try: X1 = f.Adj_div() except (TypeError, RuntimeError) as s: raise RuntimeError(str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above).") X2 = singular.NSplaces(1, X1) # retrieve list of all computed closed points (possibly of degree >1) v = X2[3].sage_flattened_str_list() # We use sage_flattened_str_list since iterating through # the entire list through the sage/singular interface directly # would involve hundreds of calls to singular, and timing issues with # the expect interface could crop up. Also, this is vastly # faster (and more robust). v = [ v[i].partition(',') for i in range(len(v)) ] pnts = [ ( int(v[i][0]), int(v[i][2])-1 ) for i in range(len(v))] # retrieve coordinates of rational points R = X2[5][1][1] singular.set_ring(R) v = singular('POINTS').sage_flattened_str_list() coords = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)//3)] # build correct representation of D for singular Dsupport = D.support() Dcoeffs = [] for x in pnts: if x[0] == 1: Dcoeffs.append(D.coefficient(coords[x[1]])) else: Dcoeffs.append(0) Dstr = str(tuple(Dcoeffs)) G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec') # call singular's brill noether routine and return T = X2[1][2] T.set_ring() LG = G.BrillNoether(X2) LG = [X.split(',\n') for X in LG.sage_structured_str_list()] x,y,z = self.ambient_space().coordinate_ring().gens() vars = {'x':x, 'y':y, 'z':z} V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG] return V
def __to_CC(self, s): s = s.replace('.E','.0E').replace(' ','') return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))
def riemann_roch_basis(self, D): r""" Return a basis for the Riemann-Roch space corresponding to `D`. This uses Singular's Brill-Noether implementation. INPUT: - ``D`` - a divisor OUTPUT: A list of function field elements that form a basis of the Riemann-Roch space EXAMPLE:: sage: R.<x,y,z> = GF(2)[] sage: f = x^3*y + y^3*z + x*z^3 sage: C = Curve(f); pts = C.rational_points() sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ]) sage: C.riemann_roch_basis(D) [x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)] :: sage: R.<x,y,z> = GF(5)[] sage: f = x^7 + y^7 + z^7 sage: C = Curve(f); pts = C.rational_points() sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ]) sage: C.riemann_roch_basis(D) [(-2*x + y)/(x + y), (-x + z)/(x + y)] .. NOTE:: Currently this only works over prime field and divisors supported on rational points. """ f = self.defining_polynomial()._singular_() singular = f.parent() singular.lib('brnoeth') try: X1 = f.Adj_div() except (TypeError, RuntimeError) as s: raise RuntimeError( str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above)." ) X2 = singular.NSplaces(1, X1) # retrieve list of all computed closed points (possibly of degree >1) v = X2[3].sage_flattened_str_list( ) # We use sage_flattened_str_list since iterating through # the entire list through the sage/singular interface directly # would involve hundreds of calls to singular, and timing issues with # the expect interface could crop up. Also, this is vastly # faster (and more robust). v = [v[i].partition(',') for i in range(len(v))] pnts = [(int(v[i][0]), int(v[i][2]) - 1) for i in range(len(v))] # retrieve coordinates of rational points R = X2[5][1][1] singular.set_ring(R) v = singular('POINTS').sage_flattened_str_list() coords = [ self(int(v[3 * i]), int(v[3 * i + 1]), int(v[3 * i + 2])) for i in range(len(v) // 3) ] # build correct representation of D for singular Dsupport = D.support() Dcoeffs = [] for x in pnts: if x[0] == 1: Dcoeffs.append(D.coefficient(coords[x[1]])) else: Dcoeffs.append(0) Dstr = str(tuple(Dcoeffs)) G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec') # call singular's brill noether routine and return T = X2[1][2] T.set_ring() LG = G.BrillNoether(X2) LG = [X.split(',\n') for X in LG.sage_structured_str_list()] x, y, z = self.ambient_space().coordinate_ring().gens() vars = {'x': x, 'y': y, 'z': z} V = [(sage_eval(a, vars) / sage_eval(b, vars)) for a, b in LG] return V
def __to_CC(self, s): s = s.replace('.E','.0E').replace(' ','') return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))
Dcoeffs = [] for x in pnts: if x[0] == 1: Dcoeffs.append(D.coefficient(coords[x[1]])) else: Dcoeffs.append(0) Dstr = str(tuple(Dcoeffs)) G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec') # call singular's brill noether routine and return T = X2[1][2] T.set_ring() LG = G.BrillNoether(X2) LG = [X.split(',\n') for X in LG.sage_structured_str_list()] x,y,z = self.ambient_space().coordinate_ring().gens() vars = {'x':x, 'y':y, 'z':z} V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG] return V def rational_points(self, algorithm="enum", sort=True): r""" INPUT: - ``algorithm`` - string: - ``'enum'`` - straightforward enumeration - ``'bn'`` - via Singular's brnoeth package. EXAMPLE::
Dcoeffs = [] for x in pnts: if x[0] == 1: Dcoeffs.append(D.coefficient(coords[x[1]])) else: Dcoeffs.append(0) Dstr = str(tuple(Dcoeffs)) G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec') # call singular's brill noether routine and return T = X2[1][2] T.set_ring() LG = G.BrillNoether(X2) LG = [X.split(',\n') for X in LG.sage_structured_str_list()] x, y, z = self.ambient_space().coordinate_ring().gens() vars = {'x': x, 'y': y, 'z': z} V = [(sage_eval(a, vars) / sage_eval(b, vars)) for a, b in LG] return V def rational_points(self, algorithm="enum", sort=True): r""" INPUT: - ``algorithm`` - string: - ``'enum'`` - straightforward enumeration - ``'bn'`` - via Singular's brnoeth package. EXAMPLE::
def guess(sequence, algorithm='pari'): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'pari' - use Pari's implementation of LLL (fast) - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found EXAMPLES:: sage: CFiniteSequence.guess([1,2,4,8,16,32]) C-finite sequence, generated by 1/(-2*x + 1) sage: r = CFiniteSequence.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. sage: CFiniteSequence.guess([1,0,0,0,0,0]) Finite sequence [1], offset = 0 With Pari LLL, all values are taken into account, and if no o.g.f. can be found, `0` is returned:: sage: CFiniteSequence.guess([1,0,0,0,0,1]) 0 With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = CFiniteSequence.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by 1/(-2*x + 1) sage: r[0:5] [1, 2, 4, 8, 16] """ S = PolynomialRing(QQ, 'x') if algorithm == 'bm': if len(sequence) < 2: raise ValueError('Sequence too short for guessing.') R = PowerSeriesRing(QQ, 'x') if len(sequence) % 2 == 1: sequence = sequence[:-1] l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).list()[::-1]) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) else: global _gp if len(sequence) < 6: raise ValueError('Sequence too short for guessing.') if _gp is None: _gp = Gp() _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") _gp.set('gf', sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) """