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 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 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) 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])) for i in range(len(v)/3) if int(v[3*i+2])!=0] # remove multiple points pnts = sorted(set(pnts)) return pnts elif algorithm == "all": S_enum = self.rational_points(algorithm = "enum") S_bn = self.rational_points(algorithm = "bn") if S_enum != S_bn: raise RuntimeError("Bug in rational_points -- different algorithms give different answers for curve %s!"%self) return S_enum else: raise ValueError("No algorithm '%s' known"%algorithm)
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
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
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) # 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()
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')