def genus(self): """ Return the genus of this function field For now, the genus is computed using singular EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) sage: L.genus() 3 """ # unfortunately singular can not compute the genus with the polynomial_ring()._singular_ # object because genus method only accepts a ring of transdental degree 2 over a prime field # not a ring of transdental degree 1 over a rational function field of one variable if is_RationalFunctionField(self._base_field) and self._base_field.constant_field().is_prime_field(): #Making the auxiliary ring which only has polynomials with integral coefficients. tmpAuxRing = PolynomialRing(self._base_field.constant_field(), str(self._base_field.gen())+','+str(self._ring.gen())) intMinPoly, d = self._make_monic_integral(self._polynomial) curveIdeal = tmpAuxRing.ideal(intMinPoly) singular.lib('normal.lib') #loading genus method in singular return int(curveIdeal._singular_().genus()) else: raise NotImplementedError("Computation of genus over this rational function field not implemented yet")
def genus(self): """ Return the genus of this function field For now, the genus is computed using singular EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) sage: L.genus() 3 """ # unfortunately singular can not compute the genus with the polynomial_ring()._singular_ # object because genus method only accepts a ring of transdental degree 2 over a prime field # not a ring of transdental degree 1 over a rational function field of one variable if is_RationalFunctionField( self._base_field) and self._base_field.constant_field( ).is_prime_field(): #Making the auxiliary ring which only has polynomials with integral coefficients. tmpAuxRing = PolynomialRing( self._base_field.constant_field(), str(self._base_field.gen()) + ',' + str(self._ring.gen())) intMinPoly, d = self._make_monic_integral(self._polynomial) curveIdeal = tmpAuxRing.ideal(intMinPoly) singular.lib('normal.lib') #loading genus method in singular return int(curveIdeal._singular_().genus()) else: raise NotImplementedError( "Computation of genus over this rational function field not implemented yet" )
def is_complete_intersection(self): r""" Return whether this projective curve is or is not a complete intersection. OUTPUT: Boolean. EXAMPLES:: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P) sage: C.is_complete_intersection() False :: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y*w - x^2, z*w^2 - x^3], P) sage: C.is_complete_intersection() True sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([z^2 - y*w, y*z - x*w, y^2 - x*z], P) sage: C.is_complete_intersection() False """ singular.lib("sing.lib") I = singular.simplify(self.defining_ideal(), 10) L = singular.is_ci(I).sage() return len(self.ambient_space().gens()) - len(I.sage().gens()) == L[-1]
def is_complete_intersection(self): r""" Return whether this projective curve is or is not a complete intersection. OUTPUT: Boolean. EXAMPLES:: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P) sage: C.is_complete_intersection() False :: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y*w - x^2, z*w^2 - x^3], P) sage: C.is_complete_intersection() True sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([z^2 - y*w, y*z - x*w, y^2 - x*z], P) sage: C.is_complete_intersection() False """ singular.lib("sing.lib") I = singular.simplify(self.defining_ideal(), 10) L = singular.is_ci(I).sage() return len(self.ambient_space().gens()) - len(I.sage().gens()) == L[-1]
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), s: raise RuntimeError, str( s ) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above)."
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), s: raise RuntimeError, str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above)."
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), s: raise RuntimeError, str(s) + "\n\n ** Unable to use the\
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), s: raise RuntimeError, str(s) + "\n\n ** Unable to use the\
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 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 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
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
def intersection_multiplicity(self, X, P): r""" Return the intersection multiplicity of this subscheme and the subscheme ``X`` at the point ``P``. The intersection of this subscheme with ``X`` must be proper, that is `\mathrm{codim}(self\cap X) = \mathrm{codim}(self) + \mathrm{codim}(X)`, and must also be finite. We use Serre's Tor formula to compute the intersection multiplicity. If `I`, `J` are the defining ideals of ``self``, ``X``, respectively, then this is `\sum_{i=0}^{\infty}(-1)^i\mathrm{length}(\mathrm{Tor}_{\mathcal{O}_{A,p}}^{i} (\mathcal{O}_{A,p}/I,\mathcal{O}_{A,p}/J))` where `A` is the affine ambient space of these subschemes. INPUT: - ``X`` -- subscheme in the same ambient space as this subscheme. - ``P`` -- a point in the intersection of this subscheme with ``X``. OUTPUT: An integer. EXAMPLES:: sage: A.<x,y> = AffineSpace(QQ, 2) sage: C = Curve([y^2 - x^3 - x^2], A) sage: D = Curve([y^2 + x^3], A) sage: Q = A([0,0]) sage: C.intersection_multiplicity(D, Q) 4 :: sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^6 - 3*a^5 + 5*a^4 - 5*a^3 + 5*a^2 - 3*a + 1) sage: A.<x,y,z,w> = AffineSpace(K, 4) sage: X = A.subscheme([x*y, y*z + 7, w^3 - x^3]) sage: Y = A.subscheme([x - z^3 + z + 1]) sage: Q = A([0, -7*b^5 + 21*b^4 - 28*b^3 + 21*b^2 - 21*b + 14, -b^5 + 2*b^4 - 3*b^3 \ + 2*b^2 - 2*b, 0]) sage: X.intersection_multiplicity(Y, Q) 3 :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: X = A.subscheme([z^2 - 1]) sage: Y = A.subscheme([z - 1, y - x^2]) sage: Q = A([1,1,1]) sage: X.intersection_multiplicity(Y, Q) Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: z - 1, -x^2 + y) must be proper and finite :: sage: A.<x,y,z,w,t> = AffineSpace(QQ, 5) sage: X = A.subscheme([x*y, t^2*w, w^3*z]) sage: Y = A.subscheme([y*w + z]) sage: Q = A([0,0,0,0,0]) sage: X.intersection_multiplicity(Y, Q) Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 5 over Rational Field defined by: y*w + z) must be proper and finite """ AA = self.ambient_space() if AA != X.ambient_space(): raise TypeError( "this subscheme and (=%s) must be defined in the same ambient space" % X) W = self.intersection(X) try: W._check_satisfies_equations(P) except TypeError: raise TypeError( "(=%s) must be a point in the intersection of this subscheme and (=%s)" % (P, X)) if AA.dimension() != self.dimension() + X.dimension() or W.dimension( ) != 0: raise TypeError( "the intersection of this subscheme and (=%s) must be proper and finite" % X) I = self.defining_ideal() J = X.defining_ideal() # move P to the origin and localize chng_coords = [ AA.gens()[i] + P[i] for i in range(AA.dimension_relative()) ] R = AA.coordinate_ring().change_ring(order="negdegrevlex") Iloc = R.ideal([f(chng_coords) for f in I.gens()]) Jloc = R.ideal([f(chng_coords) for f in J.gens()]) # compute the intersection multiplicity with Serre's Tor formula using Singular singular.lib("homolog.lib") i = 0 s = 0 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) while t != 0: s = s + ((-1)**i) * t i = i + 1 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) return s
def intersection_multiplicity(self, X, P): r""" Return the intersection multiplicity of this subscheme and the subscheme ``X`` at the point ``P``. The intersection of this subscheme with ``X`` must be proper, that is `\mathrm{codim}(self\cap X) = \mathrm{codim}(self) + \mathrm{codim}(X)`, and must also be finite. We use Serre's Tor formula to compute the intersection multiplicity. If `I`, `J` are the defining ideals of ``self``, ``X``, respectively, then this is `\sum_{i=0}^{\infty}(-1)^i\mathrm{length}(\mathrm{Tor}_{\mathcal{O}_{A,p}}^{i} (\mathcal{O}_{A,p}/I,\mathcal{O}_{A,p}/J))` where `A` is the affine ambient space of these subschemes. INPUT: - ``X`` -- subscheme in the same ambient space as this subscheme. - ``P`` -- a point in the intersection of this subscheme with ``X``. OUTPUT: An integer. EXAMPLES:: sage: A.<x,y> = AffineSpace(QQ, 2) sage: C = Curve([y^2 - x^3 - x^2], A) sage: D = Curve([y^2 + x^3], A) sage: Q = A([0,0]) sage: C.intersection_multiplicity(D, Q) 4 :: sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^6 - 3*a^5 + 5*a^4 - 5*a^3 + 5*a^2 - 3*a + 1) sage: A.<x,y,z,w> = AffineSpace(K, 4) sage: X = A.subscheme([x*y, y*z + 7, w^3 - x^3]) sage: Y = A.subscheme([x - z^3 + z + 1]) sage: Q = A([0, -7*b^5 + 21*b^4 - 28*b^3 + 21*b^2 - 21*b + 14, -b^5 + 2*b^4 - 3*b^3 \ + 2*b^2 - 2*b, 0]) sage: X.intersection_multiplicity(Y, Q) 3 :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: X = A.subscheme([z^2 - 1]) sage: Y = A.subscheme([z - 1, y - x^2]) sage: Q = A([1,1,1]) sage: X.intersection_multiplicity(Y, Q) Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: z - 1, -x^2 + y) must be proper and finite :: sage: A.<x,y,z,w,t> = AffineSpace(QQ, 5) sage: X = A.subscheme([x*y, t^2*w, w^3*z]) sage: Y = A.subscheme([y*w + z]) sage: Q = A([0,0,0,0,0]) sage: X.intersection_multiplicity(Y, Q) Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 5 over Rational Field defined by: y*w + z) must be proper and finite """ AA = self.ambient_space() if AA != X.ambient_space(): raise TypeError("this subscheme and (=%s) must be defined in the same ambient space"%X) W = self.intersection(X) try: W._check_satisfies_equations(P) except TypeError: raise TypeError("(=%s) must be a point in the intersection of this subscheme and (=%s)"%(P,X)) if AA.dimension() != self.dimension() + X.dimension() or W.dimension() != 0: raise TypeError("the intersection of this subscheme and (=%s) must be proper and finite"%X) I = self.defining_ideal() J = X.defining_ideal() # move P to the origin and localize chng_coords = [AA.gens()[i] + P[i] for i in range(AA.dimension_relative())] R = AA.coordinate_ring().change_ring(order="negdegrevlex") Iloc = R.ideal([f(chng_coords) for f in I.gens()]) Jloc = R.ideal([f(chng_coords) for f in J.gens()]) # compute the intersection multiplicity with Serre's Tor formula using Singular singular.lib("homolog.lib") i = 0 s = 0 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) while t != 0: s = s + ((-1)**i)*t i = i + 1 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) return s