def riemann_roch_basis(self, D): """ Interfaces with Singular's BrillNoether command. INPUT: - ``self`` - a plane curve defined by a polynomial eqn f(x,y) = 0 over a prime finite field F = GF(p) in 2 variables x,y representing a curve X: f(x,y) = 0 having n F-rational points (see the Sage function places_on_curve) - ``D`` - an n-tuple of integers `(d1, ..., dn)` representing the divisor `Div = d1*P1+...+dn*Pn`, where `X(F) = \{P1,...,Pn\}`. *The ordering is that dictated by places_on_curve.* OUTPUT: basis of L(Div) EXAMPLE:: sage: R = PolynomialRing(GF(5),2,names = ["x","y"]) sage: x, y = R.gens() sage: f = y^2 - x^9 - x sage: C = Curve(f) sage: D = [6,0,0,0,0,0] sage: C.riemann_roch_basis(D) [1, (y^2*z^4 - x*z^5)/x^6, (y^2*z^5 - x*z^6)/x^7, (y^2*z^6 - x*z^7)/x^8] """ f = self.defining_polynomial() R = f.parent() F = self.base_ring() p = F.characteristic() Dstr = str(tuple(D)) G = singular(','.join([str(x) for x in D]), type='intvec') singular.LIB('brnoeth.lib') S = singular.ring(p, R.gens(), 'lp') fsing = singular(str(f)) X = fsing.Adj_div() P = singular.NSplaces(1, X) T = P[1][2] T.set_ring() LG = G.BrillNoether(P) dim = len(LG) basis = [(LG[i][1], LG[i][2]) for i in range(1, dim + 1)] x, y, z = PolynomialRing(F, 3, names=["x", "y", "z"]).gens() V = [] for g in basis: T.set_ring() # necessary... V.append( eval(g[0].sage_polystring()) / eval(g[1].sage_polystring())) return V
def _singular_init_func(self, singular=singular, have_ring=False): """ Return corresponding Singular polynomial but enforce that a new instance is created in the Singular interpreter. Use ``self._singular_()`` instead. """ if not have_ring: self.parent()._singular_(singular).set_ring() #this is expensive self.__singular = singular(str(self)) return self.__singular
def rational_points(self, algorithm="enum"): r""" Return sorted list of all rational points on this curve. INPUT: - ``algorithm`` - string: + ``'enum'`` - straightforward enumeration + ``'bn'`` - via Singular's Brill-Noether package. + ``'all'`` - use all implemented algorithms and verify that they give the same answer, then return it .. note:: The Brill-Noether package does not always work. When it fails a RuntimeError exception is raised. EXAMPLE:: sage: x, y = (GF(5)['x,y']).gens() sage: f = y^2 - x^9 - x sage: C = Curve(f); C Affine Curve over Finite Field of size 5 defined by -x^9 + y^2 - x sage: C.rational_points(algorithm='bn') [(0, 0), (2, 2), (2, 3), (3, 1), (3, 4)] sage: C = Curve(x - y + 1) sage: C.rational_points() [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] We compare Brill-Noether and enumeration:: sage: x, y = (GF(17)['x,y']).gens() sage: C = Curve(x^2 + y^5 + x*y - 19) sage: v = C.rational_points(algorithm='bn') sage: w = C.rational_points(algorithm='enum') sage: len(v) 20 sage: v == w True """ if algorithm == "enum": return AffineCurve_finite_field.rational_points(self, algorithm="enum") elif algorithm == "bn": f = self.defining_polynomial()._singular_() singular = f.parent() singular.lib('brnoeth') try: X1 = f.Adj_div() except (TypeError, RuntimeError), 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) R = X2[5][1][1] singular.set_ring(R) # 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 = singular('POINTS').sage_flattened_str_list() pnts = [ self(int(v[3 * i]), int(v[3 * i + 1])) for i in range(len(v) / 3) if int(v[3 * i + 2]) != 0 ] # remove multiple points pnts = list(set(pnts)) pnts.sort() return pnts
def _singular_init_(self, singular=singular): """ Return a newly created Singular ring matching this ring. EXAMPLES:: sage: PolynomialRing(QQ,'u_ba')._singular_init_() // characteristic : 0 // number of vars : 1 // block 1 : ordering lp // : names u_ba // block 2 : ordering C """ if not can_convert_to_singular(self): raise TypeError("no conversion of this ring to a Singular ring defined") if self.ngens()==1: _vars = '(%s)'%self.gen() if "*" in _vars: # 1.000...000*x _vars = _vars.split("*")[1] order = 'lp' else: _vars = str(self.gens()) order = self.term_order().singular_str() base_ring = self.base_ring() if is_RealField(base_ring): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() digits = sage.arith.all.integer_ceil((2*precision - 2)/7.0) self.__singular = singular.ring("(real,%d,0)"%digits, _vars, order=order, check=False) elif is_ComplexField(base_ring): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() digits = sage.arith.all.integer_ceil((2*precision - 2)/7.0) self.__singular = singular.ring("(complex,%d,0,I)"%digits, _vars, order=order, check=False) elif is_RealDoubleField(base_ring): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); self.__singular = singular.ring("(real,15,0)", _vars, order=order, check=False) elif is_ComplexDoubleField(base_ring): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); self.__singular = singular.ring("(complex,15,0,I)", _vars, order=order, check=False) elif base_ring.is_prime_field(): self.__singular = singular.ring(self.characteristic(), _vars, order=order, check=False) elif sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring): # not the prime field! gen = str(base_ring.gen()) r = singular.ring( "(%s,%s)"%(self.characteristic(),gen), _vars, order=order, check=False) self.__minpoly = (str(base_ring.modulus()).replace("x",gen)).replace(" ","") if singular.eval('minpoly') != "(" + self.__minpoly + ")": singular.eval("minpoly=%s"%(self.__minpoly) ) self.__minpoly = singular.eval('minpoly')[1:-1] self.__singular = r elif number_field.number_field_base.is_NumberField(base_ring) and base_ring.is_absolute(): # not the rationals! gen = str(base_ring.gen()) poly=base_ring.polynomial() poly_gen=str(poly.parent().gen()) poly_str=str(poly).replace(poly_gen,gen) r = singular.ring( "(%s,%s)"%(self.characteristic(),gen), _vars, order=order, check=False) self.__minpoly = (poly_str).replace(" ","") if singular.eval('minpoly') != "(" + self.__minpoly + ")": singular.eval("minpoly=%s"%(self.__minpoly) ) self.__minpoly = singular.eval('minpoly')[1:-1] self.__singular = r elif sage.rings.fraction_field.is_FractionField(base_ring) and (base_ring.base_ring() is ZZ or base_ring.base_ring().is_prime_field() or is_FiniteField(base_ring.base_ring())): if base_ring.ngens()==1: gens = str(base_ring.gen()) else: gens = str(base_ring.gens()) if not (not base_ring.base_ring().is_prime_field() and is_FiniteField(base_ring.base_ring())) : self.__singular = singular.ring( "(%s,%s)"%(base_ring.characteristic(),gens), _vars, order=order, check=False) else: ext_gen = str(base_ring.base_ring().gen()) _vars = '(' + ext_gen + ', ' + _vars[1:]; R = self.__singular = singular.ring( "(%s,%s)"%(base_ring.characteristic(),gens), _vars, order=order, check=False) self.base_ring().__minpoly = (str(base_ring.base_ring().modulus()).replace("x",ext_gen)).replace(" ","") singular.eval('setring '+R._name); self.__singular = singular("std(ideal(%s))"%(self.base_ring().__minpoly),type='qring') elif sage.rings.function_field.function_field.is_RationalFunctionField(base_ring) and base_ring.constant_field().is_prime_field(): gen = str(base_ring.gen()) self.__singular = singular.ring( "(%s,%s)"%(base_ring.characteristic(),gen), _vars, order=order, check=False) elif is_IntegerModRing(base_ring): ch = base_ring.characteristic() if ch.is_power_of(2): exp = ch.nbits() -1 self.__singular = singular.ring("(integer,2,%d)"%(exp,), _vars, order=order, check=False) else: self.__singular = singular.ring("(integer,%d)"%(ch,), _vars, order=order, check=False) elif base_ring is ZZ: self.__singular = singular.ring("(integer)", _vars, order=order, check=False) else: raise TypeError("no conversion to a Singular ring defined") return self.__singular
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 _points_via_singular(self, sort=True): r""" Return all rational points on this curve, computed using Singular's Brill-Noether implementation. INPUT: - ``sort`` - bool (default: True), if True return the point list sorted. If False, returns the points in the order computed by Singular. EXAMPLE:: sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens() sage: f = y^2*z^7 - x^9 - x*z^8 sage: C = Curve(f); C Projective Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8 sage: C._points_via_singular() [(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1), (3 : 1 : 1), (3 : 4 : 1)] sage: C._points_via_singular(sort=False) #random [(0 : 1 : 0), (3 : 1 : 1), (3 : 4 : 1), (2 : 2 : 1), (0 : 0 : 1), (2 : 3 : 1)] .. note:: The Brill-Noether package does not always work (i.e., the 'bn' algorithm. When it fails a RuntimeError exception is raised. """ 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) R = X2[5][1][1] singular.set_ring(R) # 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 = singular('POINTS').sage_flattened_str_list() pnts = [ self(int(v[3 * i]), int(v[3 * i + 1]), int(v[3 * i + 2])) for i in range(len(v) // 3) ] # singular always dehomogenizes with respect to the last variable # so if this variable divides the curve equation, we need to add # points at infinity F = self.defining_polynomial() z = F.parent().gens()[-1] if z.divides(F): pnts += [self(1, a, 0) for a in self.base_ring()] pnts += [self(0, 1, 0)] # remove multiple points pnts = list(set(pnts)) if sort: pnts.sort() return pnts
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