def segre_embedding(self, PP=None, var='u'): r""" Return the Segre embedding of this space into the appropriate projective space. INPUT: - ``PP`` -- (default: ``None``) ambient image projective space; this is constructed if it is not given. - ``var`` -- string, variable name of the image projective space, default `u` (optional). OUTPUT: Hom -- from this space to the appropriate subscheme of projective space. .. TODO:: Cartesian products with more than two components. EXAMPLES:: sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ, [2, 2]) sage: phi = X.segre_embedding(); phi Scheme morphism: From: Product of projective spaces P^2 x P^2 over Integer Ring To: Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by: -u5*u7 + u4*u8, -u5*u6 + u3*u8, -u4*u6 + u3*u7, -u2*u7 + u1*u8, -u2*u4 + u1*u5, -u2*u6 + u0*u8, -u1*u6 + u0*u7, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5). :: sage: T = ProductProjectiveSpaces([1, 2], CC, 'z') sage: T.segre_embedding() Scheme morphism: From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision To: Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by: -u2*u4 + u1*u5, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4). :: sage: T = ProductProjectiveSpaces([1, 2, 1], QQ, 'z') sage: T.segre_embedding() Scheme morphism: From: Product of projective spaces P^1 x P^2 x P^1 over Rational Field To: Closed subscheme of Projective Space of dimension 11 over Rational Field defined by: -u9*u10 + u8*u11, -u7*u10 + u6*u11, -u7*u8 + u6*u9, -u5*u10 + u4*u11, -u5*u8 + u4*u9, -u5*u6 + u4*u7, -u5*u9 + u3*u11, -u5*u8 + u3*u10, -u5*u8 + u2*u11, -u4*u8 + u2*u10, -u3*u8 + u2*u9, -u3*u6 + u2*u7, -u3*u4 + u2*u5, -u5*u7 + u1*u11, -u5*u6 + u1*u10, -u3*u7 + u1*u9, -u3*u6 + u1*u8, -u5*u6 + u0*u11, -u4*u6 + u0*u10, -u3*u6 + u0*u9, -u2*u6 + u0*u8, -u1*u6 + u0*u7, -u1*u4 + u0*u5, -u1*u2 + u0*u3 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4 , z5 : z6) to (z0*z2*z5 : z0*z2*z6 : z0*z3*z5 : z0*z3*z6 : z0*z4*z5 : z0*z4*z6 : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6). """ N = self._dims M = prod([n + 1 for n in N]) - 1 CR = self.coordinate_ring() vars = list(self.coordinate_ring().variable_names()) + [ var + str(i) for i in range(M + 1) ] R = PolynomialRing(self.base_ring(), self.ngens() + M + 1, vars, order='lex') #set-up the elimination for the segre embedding mapping = [] k = self.ngens() index = self.num_components() * [0] for count in range(M + 1): mapping.append( R.gen(k + count) - prod([CR(self[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 break #only increment once #change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() s = set(R.gens()[:self.ngens()]) n = len(J) - 1 L = [] while s.isdisjoint(J[n].variables()): L.append(J[n]) n = n - 1 #create new subscheme if PP is None: PS = ProjectiveSpace(self.base_ring(), M, R.variable_names()[self.ngens():]) Y = PS.subscheme(L) else: if PP.dimension_relative() != M: raise ValueError( "projective Space %s must be dimension %s") % (PP, M) S = PP.coordinate_ring() psi = R.hom([0] * k + list(S.gens()), S) L = [psi(l) for l in L] Y = PP.subscheme(L) #create embedding for points mapping = [] index = self.num_components() * [0] for count in range(M + 1): mapping.append( prod([CR(self[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 break #only increment once phi = self.hom(mapping, Y) return phi
def rational_type(f, n=ZZ(3), base_ring=ZZ): r""" Return the basic analytic properties that can be determined directly from the specified rational function ``f`` which is interpreted as a representation of an element of a FormsRing for the Hecke Triangle group with parameter ``n`` and the specified ``base_ring``. In particular the following degree of the generators is assumed: `deg(1) := (0, 1)` `deg(x) := (4/(n-2), 1)` `deg(y) := (2n/(n-2), -1)` `deg(z) := (2, -1)` The meaning of homogeneous elements changes accordingly. INPUT: - ``f`` - A rational function in ``x,y,z,d`` over ``base_ring``. - ``n`` - An integer greater or equal to ``3`` corresponding to the ``HeckeTriangleGroup`` with that parameter (default: ``3``). - ``base_ring``` - The base ring of the corresponding forms ring, resp. polynomial ring (default: ``ZZ``). OUTPUT: A tuple ``(elem, h**o, k, ep, analytic_type)`` describing the basic analytic properties of ``f`` (with the interpretation indicated above). - ``elem`` - ``True`` if ``f`` has a homogeneous denominator. - ``h**o`` - ``True`` if ``f`` also has a homogeneous numerator. - ``k`` - ``None`` if ``f`` is not homogeneneous, otherwise the weight of ``f`` (which is the first component of its degree). - ``ep`` - ``None`` if ``f`` is not homogeneous, otherwise the multiplier of ``f`` (which is the second component of its degree) - ``analytic_type`` - The ``AnalyticType`` of ``f``. For the zero function the degree ``(0, 1)`` is choosen. This function is (heavily) used to determine the type of elements and to check if the element really is contained in its parent. EXAMPLES:: sage: (x,y,z,d) = var("x,y,z,d") sage: rational_type(0, n=4) (True, True, 0, 1, zero) sage: rational_type(1, n=12) (True, True, 0, 1, modular) sage: rational_type(x^3 - y^2) (True, True, 12, 1, cuspidal) sage: rational_type(x * z, n=7) (True, True, 14/5, -1, quasi modular) sage: rational_type(1/(x^3 - y^2) + z/d) (True, False, None, None, quasi weakly holomorphic modular) sage: rational_type(x^3/(x^3 - y^2)) (True, True, 0, 1, weakly holomorphic modular) sage: rational_type(1/(x + z)) (False, False, None, None, None) sage: rational_type(1/x + 1/z) (True, False, None, None, quasi meromorphic modular) sage: rational_type(d/x, n=10) (True, True, -1/2, 1, meromorphic modular) sage: rational_type(1.1 * z * (x^8-y^2), n=8, base_ring=CC) (True, True, 22/3, -1, quasi cuspidal) """ from analytic_type import AnalyticType AT = AnalyticType() # Determine whether f is zero if (f == 0): # elem, h**o, k, ep, analytic_type return (True, True, QQ(0), ZZ(1), AT([])) analytic_type = AT(["quasi", "mero"]) R = PolynomialRing(base_ring,'x,y,z,d') F = FractionField(R) (x,y,z,d) = R.gens() R2 = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z') dhom = R.hom( R2.gens() + (R2.base().gen(),), R2) f = F(f) n = ZZ(n) num = R(f.numerator()) denom = R(f.denominator()) hom_num = R( num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) hom_denom = R( denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) ep_num = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in dhom(num).monomials()]) ep_denom = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in dhom(denom).monomials()]) # Determine whether the denominator of f is homogeneous if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()): elem = True else: # elem, h**o, k, ep, analytic_type return (False, False, None, None, None) # Determine whether f is homogeneous if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()): h**o = True weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n-2) ep = ep_num.pop() / ep_denom.pop() # TODO: decompose f (resp. its degrees) into homogeneous parts else: h**o = False weight = None ep = None # Note that we intentially leave out the d-factor! finf_pol = x**n-y**2 # Determine whether f is modular if not ( (num.degree(z) > 0) or (denom.degree(z) > 0) ): analytic_type = analytic_type.reduce_to("mero") # Determine whether f is holomorphic if (dhom(denom).is_constant()): analytic_type = analytic_type.reduce_to(["quasi", "holo"]) # Determine whether f is cuspidal in the sense that finf divides it... # Bug in singular: finf_pol.dividess(1.0) fails over RR if (not dhom(num).is_constant()) and finf_pol.divides(num): analytic_type = analytic_type.reduce_to(["quasi", "cusp"]) else: # -> because of a bug with singular in case some cases try: while (finf_pol.divides(denom)): # a simple "denom /= finf_pol" is strangely not enough for non-exact rings denom = denom.quo_rem(finf_pol)[0] denom = R(denom) except TypeError: pass # Determine whether f is weakly holomorphic in the sense that at most powers of finf occur in denom if (dhom(denom).is_constant()): analytic_type = analytic_type.reduce_to(["quasi", "weak"]) return (elem, h**o, weight, ep, analytic_type)
def segre_embedding(self, PP=None, var='u'): r""" Return the Segre embedding of ``self`` into the appropriate projective space. INPUT: - ``PP`` -- (default: ``None``) ambient image projective space; this is constructed if it is not given. - ``var`` -- string, variable name of the image projective space, default `u` (optional) OUTPUT: Hom -- from ``self`` to the appropriate subscheme of projective space .. TODO:: Cartesian products with more than two components EXAMPLES:: sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ,[2,2]) sage: phi = X.segre_embedding(); phi Scheme morphism: From: Product of projective spaces P^2 x P^2 over Integer Ring To: Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by: -u5*u7 + u4*u8, -u5*u6 + u3*u8, -u4*u6 + u3*u7, -u2*u7 + u1*u8, -u2*u4 + u1*u5, -u2*u6 + u0*u8, -u1*u6 + u0*u7, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5). :: sage: T = ProductProjectiveSpaces([1,2],CC,'z') sage: T.segre_embedding() Scheme morphism: From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision To: Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by: -u2*u4 + u1*u5, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4). """ N = self._dims if len(N) > 2: raise NotImplementedError("Cannot have more than two components.") M = (N[0]+1)*(N[1]+1)-1 vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M+1)] R = PolynomialRing(self.base_ring(),self.ngens()+M+1, vars, order='lex') #set-up the elimination for the segre embedding mapping = [] k = self.ngens() for i in range(N[0]+1): for j in range(N[0]+1,N[0]+N[1]+2): mapping.append(R.gen(k)-R(self.gen(i)*self.gen(j))) k+=1 #change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() s = set(R.gens()[:self.ngens()]) n = len(J)-1 L = [] while s.isdisjoint(J[n].variables()): L.append(J[n]) n = n-1 #create new subscheme if PP is None: PS = ProjectiveSpace(self.base_ring(),M,R.gens()[self.ngens():]) Y = PS.subscheme(L) else: if PP.dimension_relative()!= M: raise ValueError("Projective Space %s must be dimension %s")%(PP, M) S = PP.coordinate_ring() psi = R.hom([0]*(N[0]+N[1]+2) + list(S.gens()),S) L = [psi(l) for l in L] Y = PP.subscheme(L) #create embedding for points mapping = [] for i in range(N[0]+1): for j in range(N[0]+1,N[0]+N[1]+2): mapping.append(self.gen(i)*self.gen(j)) phi = self.hom(mapping,Y) return phi
def rational_type(f, n=ZZ(3), base_ring=ZZ): r""" Return the basic analytic properties that can be determined directly from the specified rational function ``f`` which is interpreted as a representation of an element of a FormsRing for the Hecke Triangle group with parameter ``n`` and the specified ``base_ring``. In particular the following degree of the generators is assumed: `deg(1) := (0, 1)` `deg(x) := (4/(n-2), 1)` `deg(y) := (2n/(n-2), -1)` `deg(z) := (2, -1)` The meaning of homogeneous elements changes accordingly. INPUT: - ``f`` -- A rational function in ``x,y,z,d`` over ``base_ring``. - ``n`` -- An integer greater or equal to `3` corresponding to the ``HeckeTriangleGroup`` with that parameter (default: `3`). - ``base_ring`` -- The base ring of the corresponding forms ring, resp. polynomial ring (default: ``ZZ``). OUTPUT: A tuple ``(elem, h**o, k, ep, analytic_type)`` describing the basic analytic properties of `f` (with the interpretation indicated above). - ``elem`` -- ``True`` if `f` has a homogeneous denominator. - ``h**o`` -- ``True`` if `f` also has a homogeneous numerator. - ``k`` -- ``None`` if `f` is not homogeneous, otherwise the weight of `f` (which is the first component of its degree). - ``ep`` -- ``None`` if `f` is not homogeneous, otherwise the multiplier of `f` (which is the second component of its degree) - ``analytic_type`` -- The ``AnalyticType`` of `f`. For the zero function the degree `(0, 1)` is choosen. This function is (heavily) used to determine the type of elements and to check if the element really is contained in its parent. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.constructor import rational_type sage: (x,y,z,d) = var("x,y,z,d") sage: rational_type(0, n=4) (True, True, 0, 1, zero) sage: rational_type(1, n=12) (True, True, 0, 1, modular) sage: rational_type(x^3 - y^2) (True, True, 12, 1, cuspidal) sage: rational_type(x * z, n=7) (True, True, 14/5, -1, quasi modular) sage: rational_type(1/(x^3 - y^2) + z/d) (True, False, None, None, quasi weakly holomorphic modular) sage: rational_type(x^3/(x^3 - y^2)) (True, True, 0, 1, weakly holomorphic modular) sage: rational_type(1/(x + z)) (False, False, None, None, None) sage: rational_type(1/x + 1/z) (True, False, None, None, quasi meromorphic modular) sage: rational_type(d/x, n=10) (True, True, -1/2, 1, meromorphic modular) sage: rational_type(1.1 * z * (x^8-y^2), n=8, base_ring=CC) (True, True, 22/3, -1, quasi cuspidal) sage: rational_type(x-y^2, n=infinity) (True, True, 4, 1, modular) sage: rational_type(x*(x-y^2), n=infinity) (True, True, 8, 1, cuspidal) sage: rational_type(1/x, n=infinity) (True, True, -4, 1, weakly holomorphic modular) """ from .analytic_type import AnalyticType AT = AnalyticType() # Determine whether f is zero if (f == 0): # elem, h**o, k, ep, analytic_type return (True, True, QQ(0), ZZ(1), AT([])) analytic_type = AT(["quasi", "mero"]) R = PolynomialRing(base_ring, 'x,y,z,d') F = FractionField(R) (x, y, z, d) = R.gens() R2 = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z') dhom = R.hom(R2.gens() + (R2.base().gen(), ), R2) f = F(f) num = R(f.numerator()) denom = R(f.denominator()) ep_num = set([ ZZ(1) - 2 * ((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials() ]) ep_denom = set([ ZZ(1) - 2 * ((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials() ]) if (n == infinity): hom_num = R(num.subs(x=x**4, y=y**2, z=z**2)) hom_denom = R(denom.subs(x=x**4, y=y**2, z=z**2)) else: n = ZZ(n) hom_num = R(num.subs(x=x**4, y=y**(2 * n), z=z**(2 * (n - 2)))) hom_denom = R(denom.subs(x=x**4, y=y**(2 * n), z=z**(2 * (n - 2)))) # Determine whether the denominator of f is homogeneous if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()): elem = True else: # elem, h**o, k, ep, analytic_type return (False, False, None, None, None) # Determine whether f is homogeneous if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()): h**o = True if (n == infinity): weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) else: weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n - 2) ep = ep_num.pop() / ep_denom.pop() # TODO: decompose f (resp. its degrees) into homogeneous parts else: h**o = False weight = None ep = None # Note that we intentionally leave out the d-factor! if (n == infinity): finf_pol = (x - y**2) else: finf_pol = x**n - y**2 # Determine whether f is modular if not ((num.degree(z) > 0) or (denom.degree(z) > 0)): analytic_type = analytic_type.reduce_to("mero") # Determine whether f is holomorphic if (dhom(denom).is_constant()): analytic_type = analytic_type.reduce_to(["quasi", "holo"]) # Determine whether f is cuspidal in the sense that finf divides it... # Bug in singular: finf_pol.divides(1.0) fails over RR if (not dhom(num).is_constant() and finf_pol.divides(num)): if (n != infinity or x.divides(num)): analytic_type = analytic_type.reduce_to(["quasi", "cusp"]) else: # -> Because of a bug with singular in some cases try: while (finf_pol.divides(denom)): # a simple "denom /= finf_pol" is strangely not enough for non-exact rings # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(finf_pol)[0] denom = R(denom) if (n == infinity): while (x.divides(denom)): # a simple "denom /= x" is strangely not enough for non-exact rings # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(x)[0] denom = R(denom) except TypeError: pass # Determine whether f is weakly holomorphic in the sense that at most powers of finf occur in denom if (dhom(denom).is_constant()): analytic_type = analytic_type.reduce_to(["quasi", "weak"]) return (elem, h**o, weight, ep, analytic_type)
def segre_embedding(self, PP=None, var='u'): r""" Return the Segre embedding of this space into the appropriate projective space. INPUT: - ``PP`` -- (default: ``None``) ambient image projective space; this is constructed if it is not given. - ``var`` -- string, variable name of the image projective space, default `u` (optional). OUTPUT: Hom -- from this space to the appropriate subscheme of projective space. .. TODO:: Cartesian products with more than two components. EXAMPLES:: sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ, [2, 2]) sage: phi = X.segre_embedding(); phi Scheme morphism: From: Product of projective spaces P^2 x P^2 over Integer Ring To: Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by: -u5*u7 + u4*u8, -u5*u6 + u3*u8, -u4*u6 + u3*u7, -u2*u7 + u1*u8, -u2*u4 + u1*u5, -u2*u6 + u0*u8, -u1*u6 + u0*u7, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5). :: sage: T = ProductProjectiveSpaces([1, 2], CC, 'z') sage: T.segre_embedding() Scheme morphism: From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision To: Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by: -u2*u4 + u1*u5, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4). :: sage: T = ProductProjectiveSpaces([1, 2, 1], QQ, 'z') sage: T.segre_embedding() Scheme morphism: From: Product of projective spaces P^1 x P^2 x P^1 over Rational Field To: Closed subscheme of Projective Space of dimension 11 over Rational Field defined by: -u9*u10 + u8*u11, -u7*u10 + u6*u11, -u7*u8 + u6*u9, -u5*u10 + u4*u11, -u5*u8 + u4*u9, -u5*u6 + u4*u7, -u5*u9 + u3*u11, -u5*u8 + u3*u10, -u5*u8 + u2*u11, -u4*u8 + u2*u10, -u3*u8 + u2*u9, -u3*u6 + u2*u7, -u3*u4 + u2*u5, -u5*u7 + u1*u11, -u5*u6 + u1*u10, -u3*u7 + u1*u9, -u3*u6 + u1*u8, -u5*u6 + u0*u11, -u4*u6 + u0*u10, -u3*u6 + u0*u9, -u2*u6 + u0*u8, -u1*u6 + u0*u7, -u1*u4 + u0*u5, -u1*u2 + u0*u3 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4 , z5 : z6) to (z0*z2*z5 : z0*z2*z6 : z0*z3*z5 : z0*z3*z6 : z0*z4*z5 : z0*z4*z6 : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6). """ N = self._dims M = prod([n+1 for n in N]) - 1 CR = self.coordinate_ring() vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M+1)] R = PolynomialRing(self.base_ring(), self.ngens()+M+1, vars, order='lex') #set-up the elimination for the segre embedding mapping = [] k = self.ngens() index = self.num_components()*[0] for count in range(M + 1): mapping.append(R.gen(k+count)-prod([CR(self[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index)-1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 break #only increment once #change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() s = set(R.gens()[:self.ngens()]) n = len(J)-1 L = [] while s.isdisjoint(J[n].variables()): L.append(J[n]) n = n-1 #create new subscheme if PP is None: PS = ProjectiveSpace(self.base_ring(), M, R.variable_names()[self.ngens():]) Y = PS.subscheme(L) else: if PP.dimension_relative() != M: raise ValueError("projective Space %s must be dimension %s")%(PP, M) S = PP.coordinate_ring() psi = R.hom([0]*k + list(S.gens()), S) L = [psi(l) for l in L] Y = PP.subscheme(L) #create embedding for points mapping = [] index = self.num_components()*[0] for count in range(M + 1): mapping.append(prod([CR(self[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index)-1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 break #only increment once phi = self.hom(mapping, Y) return phi