def generator_relations(self, K): """ An ideal `I` in the attach polynomial ring `R`, such that the ring of modular forms is a quotient of `R / I`. This ideal must be unique for `K`. INPUT: - `K` -- A ring or module; The ring of Fourier coefficients. OUTPUT: An ideal in a polynomial ring. TESTS:: sage: from hermitianmodularforms import * sage: HermitianModularFormD2_Gamma(-3).generator_relations(QQ) Ideal (0) of Multivariate Polynomial Ring in HE4, HE6, HE10, HE12, Hphi9 over Rational Field sage: HermitianModularFormD2_Gamma(-3).generator_relations(GF(2)) Traceback (most recent call last): ... NotImplementedError: Only Fourier coefficients in a number fields are implemented. """ if self.__D == -3: if K is QQ or K in NumberFields(): R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError( "Only Fourier coefficients in a number fields are implemented." ) raise NotImplementedError("Discriminant %s is not implemented." % (self.__D, ))
def __init__(this, p, category=None): """ TESTS:: sage: from yacop.testing.testalgebra import Testclass1 sage: X=Testclass1(5) sage: X.monomial((2,1,8,0)) x^2*a*y^8 sage: X.monomial((3,0,-17,1)) x^3*b/y^17 sage: from yacop.utils.region import region sage: X._manual_test_left_action(region(tmax=20)) 1126 non-zero multiplications checked sage: X._manual_test_left_conj_action(region(tmax=20)) # long time 1148 non-zero multiplications checked """ # must admit the "category" keyword for suspendability R = PolynomialRing(FiniteField(p), "x,a,y,b") x, a, y, b = R.gens() I = R.ideal([a**2, b**2]) degs = lambda idx: (1, -1, 0) if (idx & 1) else (2, 0, 0) SteenrodAlgebraBase.__init__(this, R, [degs(n) for n in range(4)], I, SteenrodAlgebra(p), category=category)
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 generator_relations(self, K) : """ An ideal `I` in the attach polynomial ring `R`, such that the ring of modular forms is a quotient of `R / I`. This ideal must be unique for `K`. INPUT: - `K` -- A ring or module; The ring of Fourier coefficients. OUTPUT: An ideal in a polynomial ring. TESTS:: sage: from hermitianmodularforms import * sage: HermitianModularFormD2_Gamma(-3).generator_relations(QQ) Ideal (0) of Multivariate Polynomial Ring in HE4, HE6, HE10, HE12, Hphi9 over Rational Field sage: HermitianModularFormD2_Gamma(-3).generator_relations(GF(2)) Traceback (most recent call last): ... NotImplementedError: Only Fourier coefficients in a number fields are implemented. """ if self.__D == -3 : if K is QQ or K in NumberFields() : R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError( "Only Fourier coefficients in a number fields are implemented." ) raise NotImplementedError( "Discriminant %s is not implemented." % (self.__D,) )
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 has_rep(self, n, restrict=None, force=False): """ Returns `True` if there exists an `n`-dimensional representation of `self`, and `False` otherwise. The optional argument `restrict` may be used to restrict the possible images of the generators. To do so, `restrict` must be a tuple with entries of `None`, `'diagonal'`, `'lower'`, or `'upper'`. Its length must match the number of generators of `self`. Use `force=True` if the function does not recognize the base field as computable, but the field is computable. """ if (not force and self.base_field() not in NumberFields and self.base_field() not in FiniteFields): raise TypeError( 'Base field must be computable. If %s is computable' % self.base_field() + ' then use force=True to bypass this.') if n not in ZZ or n < 1: raise ValueError('Dimension must be a positive integer.') from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import math B = PolynomialRing(self.base_field(), (self.ngens() * n**2 + 1), 'x', order='deglex') M = MatrixSpace(B, n, sparse=True) gen_matrix = list() if not isinstance(restrict, (tuple, list)): restrict = [None for i in range(self.ngens())] if len(restrict) != self.ngens(): raise ValueError( 'Length of restrict does not match number of generators.') for i in range(self.ngens()): ith_gen_matrix = [] for j in range(n): for k in range(n): if restrict[i] == 'upper' and j > k: ith_gen_matrix.append(B.zero()) elif restrict[i] == 'lower' and j < k: ith_gen_matrix.append(B.zero()) elif restrict[i] == 'diagonal' and j != k: ith_gen_matrix.append(B.zero()) else: ith_gen_matrix.append(B.gen(j + (j + 1) * k + i * n**2)) gen_matrix.append(M(ith_gen_matrix)) relB_list = list() for i in range(self.nrels()): relB_list += self._to_matrix(self.rel(i), M, gen_matrix).list() relB = B.ideal(relB_list) if relB.dimension() == -1: return False else: return True
def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): r""" Helper function used by eta_poly_relations. Finds a basis for the space of linear relations between the first qexp_terms of the `q`-expansions of the monomials `\eta_1^i * \eta_2^j` for `0 \le i,j < degree`, and calculates a Groebner basis for the ideal generated by these relations. Liable to return meaningless results if qexp_terms isn't at least `1 + d*(m_1,m_2)` where .. math:: m_i = min(0, {\text degree of the pole of $\eta_i$ at $\infty$}) as then 1 will be in the ideal. EXAMPLE:: sage: from sage.modular.etaproducts import _eta_relations_helper sage: r,s = EtaGroup(4).basis() sage: _eta_relations_helper(r,s,4,100,['a','b'],False) [a*b - a + 16] sage: _eta_relations_helper(EtaProduct(26, {2:2,13:2,26:-2,1:-2}),EtaProduct(26, {2:4,13:2,26:-4,1:-2}),3,12,['a','b'],False) # not enough terms, will return rubbish [1] """ indices = [(i,j) for j in range(degree) for i in range(degree)] inf = CuspFamily(eta1.level(), 1) pole_at_infinity = -(min([0, eta1.order_at_cusp(inf)]) + min([0,eta2.order_at_cusp(inf)]))*degree if verbose: print "Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1) rows = [] for j in xrange(qexp_terms): rows.append([]) for i in indices: func = (eta1**i[0]*eta2**i[1]).qexp(qexp_terms) for j in xrange(qexp_terms): rows[j].append(func[j - pole_at_infinity]) M = matrix(rows) V = M.right_kernel() if V.dimension() == 0: if verbose: print "No polynomial relation of order %s valid for %s terms" % (degree, qexp_terms) return None if V.dimension() >= 1: #print "Found relation: " R = PolynomialRing(QQ, 2, labels) x,y = R.gens() relations = [] for c in V.basis(): relations.append(sum( [ c[v] * x**indices[v][0] * y**indices[v][1] for v in xrange(len(indices))])) #print relations[-1], " = 0" id = R.ideal(relations) return id.groebner_basis()
def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): r""" Helper function used by eta_poly_relations. Finds a basis for the space of linear relations between the first qexp_terms of the `q`-expansions of the monomials `\eta_1^i * \eta_2^j` for `0 \le i,j < degree`, and calculates a Groebner basis for the ideal generated by these relations. Liable to return meaningless results if qexp_terms isn't at least `1 + d*(m_1,m_2)` where .. math:: m_i = min(0, {\text degree of the pole of $\eta_i$ at $\infty$}) as then 1 will be in the ideal. EXAMPLE:: sage: from sage.modular.etaproducts import _eta_relations_helper sage: r,s = EtaGroup(4).basis() sage: _eta_relations_helper(r,s,4,100,['a','b'],False) [a*b - a + 16] sage: _eta_relations_helper(EtaProduct(26, {2:2,13:2,26:-2,1:-2}),EtaProduct(26, {2:4,13:2,26:-4,1:-2}),3,12,['a','b'],False) # not enough terms, will return rubbish [1] """ indices = [(i,j) for j in range(degree) for i in range(degree)] inf = CuspFamily(eta1.level(), 1) pole_at_infinity = -(min([0, eta1.order_at_cusp(inf)]) + min([0,eta2.order_at_cusp(inf)]))*degree if verbose: print "Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1) rows = [] for j in xrange(qexp_terms): rows.append([]) for i in indices: func = (eta1**i[0]*eta2**i[1]).qexp(qexp_terms) for j in xrange(qexp_terms): rows[j].append(func[j - pole_at_infinity]) M = matrix(rows) V = M.right_kernel() if V.dimension() == 0: if verbose: print "No polynomial relation of order %s valid for %s terms" % (degree, qexp_terms) return None if V.dimension() >= 1: #print "Found relation: " R = PolynomialRing(QQ, 2, labels) x,y = R.gens() relations = [] for c in V.basis(): relations.append(sum( [ c[v] * x**indices[v][0] * y**indices[v][1] for v in xrange(len(indices))])) #print relations[-1], " = 0" id = R.ideal(relations) return id.groebner_basis()
def generator_relations(self, K) : r""" An ideal `I` in a polynomial ring `R`, such that the associated ring is `R / I`. This ideal must be unique for `K`. """ if K is QQ or K in NumberFields() : R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError
def generator_relations(self, K) : r""" An ideal I in a polynomial ring R, such that the associated module is (R / I)_1. """ if K is QQ or K in NumberFields() : R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError
def generator_relations(self, K): r""" An ideal I in a polynomial ring R, such that the associated module is (R / I)_1. """ if K is QQ or K in NumberFields(): R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError
def is_morphism(self): r""" returns ``True`` if self is a morphism (no common zero of defining polynomials). The map is a morphism if and only if the ideal generated by the defining polynomials is the unit ideal. OUTPUT: - Boolean EXAMPLES:: sage: P.<x,y>=ProjectiveSpace(QQ,1) sage: H=Hom(P,P) sage: f=H([x^2+y^2,y^2]) sage: f.is_morphism() True :: sage: P.<x,y,z>=ProjectiveSpace(RR,2) sage: H=Hom(P,P) sage: f=H([x*z-y*z,x^2-y^2,z^2]) sage: f.is_morphism() False :: sage: R.<t>=PolynomialRing(GF(5)) sage: P.<x,y,z>=ProjectiveSpace(R,2) sage: H=Hom(P,P) sage: f=H([x*z-t*y^2,x^2-y^2,t*z^2]) sage: f.is_morphism() True """ from sage.schemes.projective.projective_space import is_ProjectiveSpace if is_ProjectiveSpace(self.domain())==False or is_ProjectiveSpace(self.codomain())==False: raise NotImplementedError R=self.coordinate_ring() F=self._polys if R.base_ring().is_field(): J=R.ideal(F) else: S=PolynomialRing(R.base_ring().fraction_field(),R.gens(),R.ngens()) J=S.ideal([S.coerce(F[i]) for i in range(R.ngens())]) if J.dimension()>0: return False else: return True
def canonical_scheme(self, t=None): """ Return the canonical scheme. This is a scheme that contains this hypergeometric motive in its cohomology. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([3],[4])) sage: H.gamma_list() [-1, 2, 3, -4] sage: H.canonical_scheme() Spectrum of Quotient of Multivariate Polynomial Ring in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^2*X1^3 + 27/64*Y0*Y1^4) sage: H = Hyp(gamma_list=[-2, 3, 4, -5]) sage: H.canonical_scheme() Spectrum of Quotient of Multivariate Polynomial Ring in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^3*X1^4 + 1728/3125*Y0^2*Y1^5) REFERENCES: [Kat1991]_, section 5.4 """ if t is None: t = FractionField(QQ['t']).gen() basering = t.parent() gamma_pos = [u for u in self.gamma_list() if u > 0] gamma_neg = [u for u in self.gamma_list() if u < 0] N_pos = len(gamma_pos) N_neg = len(gamma_neg) varX = ['X{}'.format(i) for i in range(N_pos)] varY = ['Y{}'.format(i) for i in range(N_neg)] ring = PolynomialRing(basering, varX + varY) gens = ring.gens() X = gens[:N_pos] Y = gens[N_pos:] eq0 = ring.sum(X) - 1 eq1 = ring.sum(Y) - 1 eq2_pos = ring.prod(X[i] ** gamma_pos[i] for i in range(N_pos)) eq2_neg = ring.prod(Y[j] ** -gamma_neg[j] for j in range(N_neg)) ideal = ring.ideal([eq0, eq1, self.M_value() * eq2_neg - t * eq2_pos]) return Spec(ring.quotient(ideal))
def canonical_scheme(self, t=None): """ Return the canonical scheme. This is a scheme that contains this hypergeometric motive in its cohomology. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([3],[4])) sage: H.gamma_list() [-1, 2, 3, -4] sage: H.canonical_scheme() Spectrum of Quotient of Multivariate Polynomial Ring in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^2*X1^3 + 27/64*Y0*Y1^4) sage: H = Hyp(gamma_list=[-2, 3, 4, -5]) sage: H.canonical_scheme() Spectrum of Quotient of Multivariate Polynomial Ring in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^3*X1^4 + 1728/3125*Y0^2*Y1^5) REFERENCES: [Kat1991]_, section 5.4 """ if t is None: t = FractionField(QQ['t']).gen() basering = t.parent() gamma_pos = [u for u in self.gamma_list() if u > 0] gamma_neg = [u for u in self.gamma_list() if u < 0] N_pos = len(gamma_pos) N_neg = len(gamma_neg) varX = ['X{}'.format(i) for i in range(N_pos)] varY = ['Y{}'.format(i) for i in range(N_neg)] ring = PolynomialRing(basering, varX + varY) gens = ring.gens() X = gens[:N_pos] Y = gens[N_pos:] eq0 = ring.sum(X) - 1 eq1 = ring.sum(Y) - 1 eq2_pos = ring.prod(X[i] ** gamma_pos[i] for i in range(N_pos)) eq2_neg = ring.prod(Y[j] ** -gamma_neg[j] for j in range(N_neg)) ideal = ring.ideal([eq0, eq1, self.M_value() * eq2_neg - t * eq2_pos]) return Spec(ring.quotient(ideal))
def get_ideal(self, name, base_ring=QQ, term_order="degrevlex"): """ Returns the ideal given by 'name' over the base ring given by 'base_ring' in a polynomial ring with the term order given by 'term_order'. INPUT: - ``name`` - name as on the symbolic data website - ``base_ring`` - base ring for the polynomial ring (default: ``QQ``) - ``term_order`` - term order for the polynomial ring (default: ``degrevlex``) OUTPUT: ideal as given by ``name`` in ``PolynomialRing(base_ring,vars,term_order)`` EXAMPLES:: sage: sd = SymbolicData() # optional - database_symbolic_data sage: sd.get_ideal('Katsura_3',GF(127),'degrevlex') # optional - database_symbolic_data Ideal (u0 + 2*u1 + 2*u2 + 2*u3 - 1, u1^2 + 2*u0*u2 + 2*u1*u3 - u2, 2*u0*u1 + 2*u1*u2 + 2*u2*u3 - u1, u0^2 + 2*u1^2 + 2*u2^2 + 2*u3^2 - u0) of Multivariate Polynomial Ring in u0, u1, u2, u3 over Finite Field of size 127 """ def _getTextFromNode(node): t = "" for n in node.childNodes: if n.nodeType == n.TEXT_NODE: t += str(n.nodeValue) else: raise TypeError('not a text node') return t def _dom2ideal(node): """ """ l = [] if str(node.nodeName) in ['vars','poly']: l.append(_getTextFromNode(node)) for c in node.childNodes: l += _dom2ideal(c) return l orig_name = name name = name.replace('__','.') try: name = self.__intpath + name + ".xml" open(name) except IOError: try: name = self.__genpath + name + ".xml" open(name) except IOError: raise AttributeError("No ideal matching '%s' found in database."%orig_name) dom = parse(name) res = _dom2ideal(dom) variables, polys = res[0].replace("_",""), [p.replace("_","") for p in res[1:]] P = PolynomialRing(base_ring, len(variables.split(",")), variables) I = P.ideal([P(f) for f in polys]) return I
def points(self, B=0): r""" Return some or all rational points of an affine scheme. INPUT: - ``B`` -- integer (optional, default: 0). The bound for the height of the coordinates. OUTPUT: - If the base ring is a finite field: all points of the scheme, given by coordinate tuples. - If the base ring is `\QQ` or `\ZZ`: the subset of points whose coordinates have height ``B`` or less. EXAMPLES: The bug reported at #11526 is fixed:: sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: A2(F).points() [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] sage: R = ZZ sage: A.<x,y> = R[] sage: I = A.ideal(x^2-y^2-1) sage: V = AffineSpace(R, 2) sage: X = V.subscheme(I) sage: M = X(R) sage: M.points(1) [(-1, 0), (1, 0)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: A.<x,y> = AffineSpace(K, 2) sage: len(A(K).points(9)) 361 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) sage: E(A.base_ring()).points() [(-1, 0), (0, -1), (0, 1), (1, 0)] """ X = self.codomain() from sage.schemes.affine.affine_space import is_AffineSpace if not is_AffineSpace(X) and X.base_ring() in Fields(): # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 0: # no points return [] if dim_ideal == 0: # if X zero-dimensional N = len(X.ambient_space().gens()) S = X.defining_polynomials()[0].parent() R = PolynomialRing(S.base_ring(), 's', N, order='lex') phi = S.hom(R.gens(),R) J = R.ideal([phi(t) for t in X.defining_polynomials()]) D = J.variety() points = [] for d in D: P = [d[t] for t in R.gens()] points.append(X(P)) points.sort() return points R = self.value_ring() if is_RationalField(R) or R == ZZ: if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field return enum_affine_rational_field(self,B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self,B) elif is_FiniteField(R): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: raise TypeError("unable to enumerate points over %s"%R)
def points(self, B=0): r""" Return some or all rational points of an affine scheme. INPUT: - ``B`` -- integer (optional, default: 0). The bound for the height of the coordinates. OUTPUT: - If the base ring is a finite field: all points of the scheme, given by coordinate tuples. - If the base ring is `\QQ` or `\ZZ`: the subset of points whose coordinates have height ``B`` or less. EXAMPLES: The bug reported at #11526 is fixed:: sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: A2(F).points() [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] sage: R = ZZ sage: A.<x,y> = R[] sage: I = A.ideal(x^2-y^2-1) sage: V = AffineSpace(R, 2) sage: X = V.subscheme(I) sage: M = X(R) sage: M.points(1) [(-1, 0), (1, 0)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: A.<x,y> = AffineSpace(K, 2) sage: len(A(K).points(9)) 361 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) sage: E(A.base_ring()).points() [(-1, 0), (0, -1), (0, 1), (1, 0)] """ X = self.codomain() from sage.schemes.affine.affine_space import is_AffineSpace if not is_AffineSpace(X) and X.base_ring() in Fields(): # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 0: # no points return [] if dim_ideal == 0: # if X zero-dimensional N = len(X.ambient_space().gens()) S = X.defining_polynomials()[0].parent() R = PolynomialRing(S.base_ring(), 's', N, order='lex') phi = S.hom(R.gens(), R) J = R.ideal([phi(t) for t in X.defining_polynomials()]) D = J.variety() points = [] for d in D: P = [d[t] for t in R.gens()] points.append(X(P)) points.sort() return points R = self.value_ring() if is_RationalField(R) or R == ZZ: if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field return enum_affine_rational_field(self, B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self, B) elif is_FiniteField(R): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: raise TypeError("unable to enumerate points over %s" % R)
def __init__ ( self, base_ring_generators, generators, relations, grading, all_relations = True, reduce_before_evaluating = True) : """ The degree one part of the monomials that correspond to generators over the base expansion ring will serve as the coordinates of the elements. INPUT: - ``base_ring_generators`` -- A list of (equivariant) monoid power series with coefficient domain the base ring of the coefficient domain of the generators or ``None``. - ``generators`` -- A list of (equivariant) monoid power series; The generators of the ambient over the ring generated by the base ring generators. - ``relations`` -- An ideal in a polynomial ring with ``len(base_ring_generators) + len(generators)`` variables. - ``grading`` -- A grading deriving from :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_grading`; A grading for the polynomial ring of the relations. - ``all_relations`` -- A boolean (default: ``True``); If ``True`` the relations given for the polynomial ring are all relations that the Fourier expansion have. - ``reduce_before_evaluating`` -- A boolean (default: ``True``); If ``True`` any monomial will be Groebner reduced before the Fourier expansion is calculated. NOTE: The grading must respect the relations of the generators. TESTS:: sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import * sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import * sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import * sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import * sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False)) sage: ger = GradedExpansionRing_class(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2))) sage: ger.base_ring() Graded expansion ring with generators a """ if not hasattr(self, '_element_class') : self._element_class = GradedExpansion_class if hasattr(self, "_extended_base_ring") : Algebra.__init__(self, self._extended_base_ring) elif base_ring_generators is None or len(base_ring_generators) == 0 : Algebra.__init__(self, relations.base_ring()) else : gb = filter( lambda p: all( all(a == 0 for a in list(e)[len(base_ring_generators):]) for e in p.exponents() ), relations.groebner_basis() ) P = PolynomialRing( relations.base_ring(), list(relations.ring().variable_names())[:len(base_ring_generators)] ) base_relations = P.ideal(gb) R = GradedExpansionRing_class(None, base_ring_generators, base_relations, grading.subgrading(xrange(len(base_ring_generators))), all_relations, reduce_before_evaluating) Algebra.__init__(self, R) GradedExpansionAmbient_abstract.__init__(self, base_ring_generators, generators, relations, grading, all_relations, reduce_before_evaluating) self._populate_coercion_lists_( coerce_list = [GradedExpansionBaseringInjection(self.base_ring(), self)], convert_list = [self.relations().ring()], convert_method_name = "_graded_expansion_submodule_to_graded_ambient_" )
def points(self, **kwds): """ Return some or all rational points of a projective scheme. For dimension 0 subschemes points are determined through a groebner basis calculation. For schemes or subschemes with dimension greater than 1 points are determined through enumeration up to the specified bound. INPUT: kwds: - ``bound`` - real number (optional, default=0). The bound for the coordinates for subschemes with dimension at least 1. - ``precision`` - integer (optional, default=53). The precision to use to compute the elements of bounded height for number fields. - ``point_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, two points are considered the same if their coordinates are within tolerance. - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 for enumeration over number fields. OUTPUT: - a list of rational points of a projective scheme .. WARNING:: For numerically inexact fields such as ComplexField or RealField the list of points returned is very likely to be incomplete. It may also contain repeated points due to tolerances. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P(QQ).points(bound=4) [(-4 : 1), (-3 : 1), (-2 : 1), (-3/2 : 1), (-4/3 : 1), (-1 : 1), (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: len(P(K).points(bound=1.8)) 381 :: sage: P1 = ProjectiveSpace(GF(2),1) sage: F.<a> = GF(4,'a') sage: P1(F).points() [(0 : 1), (1 : 0), (1 : 1), (a : 1), (a + 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2),(y^3-y*z^2) + (x^3-x*z^2)]) sage: E(P.base_ring()).points() [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(CC, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: L=E(P.base_ring()).points(); sorted(L, key=str) verbose 0 (71: projective_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. [(-0.500000000000000 + 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), (-0.500000000000000 - 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), (-1.00000000000000*I : 0.000000000000000 : 1.00000000000000), (0.000000000000000 : 0.000000000000000 : 1.00000000000000), (1.00000000000000 : 1.00000000000000 : 0.000000000000000), (1.00000000000000*I : 0.000000000000000 : 1.00000000000000)] sage: L[0].codomain() Projective Space of dimension 2 over Complex Field with 53 bits of precision :: sage: P.<x,y,z> = ProjectiveSpace(CDF, 2) sage: E = P.subscheme([y^2 + x^2 + z^2, x*y*z]) sage: len(E(P.base_ring()).points()) verbose 0 (71: projective_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. 6 """ from sage.schemes.projective.projective_space import is_ProjectiveSpace X = self.codomain() if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): if hasattr(X.base_ring(), 'precision'): numerical = True verbose( "Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly.", level=0) pt_tol = RR(kwds.pop('point_tolerance', 10**(-10))) zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if pt_tol <= 0 or zero_tol <= 0: raise ValueError("tolerance must be positive") else: numerical = False #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k): 1}).groebner_basis() if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({R.gen(k): 1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if numerical: for pol in L.univariate_polynomial( ).roots(multiplicities=False): good = 1 r = L.variables()[0] varindex = R.gens().index(r) P.update({R.gen(varindex): pol}) new_points.append(copy(P)) else: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len( pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({ R.gen(varindex): -pol.constant_coefficient( ) / pol.monomial_coefficient(r) }) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into projective points for i in range(len(points)): if numerical: if len(points[i]) == N + 1: S = PS([ points[i][R.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() if all( g(list(S)) < zero_tol for g in X.defining_polynomials()): rat_points.add(S) else: if len(points[i]) == N + 1 and I.subs( points[i]) == I0: S = X([ points[i][R.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() rat_points.add(S) # remove duplicate element using tolerance if numerical: dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] for j in range(i + 1, len(dupl_points)): v = dupl_points[j] if all((u[k] - v[k]).abs() < pt_tol for k in range(len(u))): rat_points.remove(u) break rat_points = sorted(rat_points) return rat_points R = self.value_ring() B = kwds.pop('bound', 0) tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) if isinstance(X, AlgebraicScheme_subscheme ): # sieve should only be called for subschemes from sage.schemes.projective.projective_rational_point import sieve return sieve(X, B) else: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field return enum_projective_rational_field(self, B) elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field return enum_projective_number_field(self, bound=B, tolerance=tol, precision=prec) elif is_FiniteField(R): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field return enum_projective_finite_field(self.extended_codomain()) else: raise TypeError("unable to enumerate points over %s" % R)
def points(self, **kwds): """ Return some or all rational points of a projective scheme. Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound are returned. For a zero-dimensional subscheme, all points are returned regardless of whether the base ring is a field or not. For number fields, this uses the Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for computing algebraic numbers up to a given height [Doyle-Krumm]_. The algorithm requires floating point arithmetic, so the user is allowed to specify the precision for such calculations. Additionally, due to floating point issues, points slightly larger than the bound may be returned. This can be controlled by lowering the tolerance. INPUT: - ``bound`` - a real number - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 - ``precision`` - the precision to use for computing the elements of bounded height of number fields. OUTPUT: - a list of rational points of a projective scheme EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P(QQ).points(bound=4) [(-4 : 1), (-3 : 1), (-2 : 1), (-3/2 : 1), (-4/3 : 1), (-1 : 1), (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: len(P(K).points(bound=1.8)) 381 :: sage: P1 = ProjectiveSpace(GF(2),1) sage: F.<a> = GF(4,'a') sage: P1(F).points() [(0 : 1), (1 : 0), (1 : 1), (a : 1), (a + 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2),(y^3-y*z^2) + (x^3-x*z^2)]) sage: E(P.base_ring()).points() [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] """ B = kwds.pop('bound', 0) tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) X = self.codomain() from sage.schemes.projective.projective_space import is_ProjectiveSpace if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k): 1}).groebner_basis() if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({R.gen(k): 1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if L != 0: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len( pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({ R.gen(varindex): -pol.constant_coefficient() / pol.monomial_coefficient(r) }) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into projective points for i in range(len(points)): if len(points[i]) == N + 1 and I.subs( points[i]) == I0: S = X([ points[i][R.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() rat_points.add(S) rat_points = sorted(rat_points) return rat_points R = self.value_ring() if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) if isinstance(X, AlgebraicScheme_subscheme ): # sieve should only be called for subschemes from sage.schemes.projective.projective_rational_point import sieve return sieve(X, B) else: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field return enum_projective_rational_field(self, B) elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field return enum_projective_number_field(self, bound=B, tolerance=tol, precision=prec) elif is_FiniteField(R): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field return enum_projective_finite_field(self.extended_codomain()) else: raise TypeError("unable to enumerate points over %s" % R)
def points(self, B=0, prec=53): """ Return some or all rational points of a projective scheme. INPUT: - ``B`` - integer (optional, default=0). The bound for the coordinates. - ``prec`` - he precision to use to compute the elements of bounded height for number fields. OUTPUT: A list of points. Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound are returned. .. WARNING:: In the current implementation, the output of the [Doyle-Krumm] algorithm cannot be guaranteed to be correct due to the necessity of floating point computations. In some cases, the default 53-bit precision is considerably lower than would be required for the algorithm to generate correct output. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P(QQ).points(4) [(-4 : 1), (-3 : 1), (-2 : 1), (-3/2 : 1), (-4/3 : 1), (-1 : 1), (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: len(P(K).points(1.8)) 381 :: sage: P1 = ProjectiveSpace(GF(2),1) sage: F.<a> = GF(4,'a') sage: P1(F).points() [(0 : 1), (1 : 0), (1 : 1), (a : 1), (a + 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2),(y^3-y*z^2) + (x^3-x*z^2)]) sage: E(P.base_ring()).points() [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] """ X = self.codomain() from sage.schemes.projective.projective_space import is_ProjectiveSpace if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.gens(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k):1}).groebner_basis() if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({R.gen(k):1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if L != 0: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len(pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({R.gen(varindex):-pol.constant_coefficient() / pol.monomial_coefficient(r)}) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into projective points for i in range(len(points)): if len(points[i]) == N + 1 and I.subs(points[i]) == I0: S = X([points[i][R.gen(j)] for j in range(N + 1)]) S.normalize_coordinates() rat_points.add(S) rat_points = sorted(rat_points) return rat_points R = self.value_ring() if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) from sage.schemes.projective.projective_rational_point import enum_projective_rational_field return enum_projective_rational_field(self,B) elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field return enum_projective_number_field(self,B, prec=prec) elif is_FiniteField(R): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field return enum_projective_finite_field(self.extended_codomain()) else: raise TypeError("unable to enumerate points over %s"%R)
def dual(self): r""" Return the projective dual of the given subscheme of projective space. INPUT: - ``X`` -- A subscheme of projective space. At present, ``X`` is required to be an irreducible and reduced hypersurface defined over `\QQ` or a finite field. OUTPUT: - The dual of ``X`` as a subscheme of the dual projective space. EXAMPLES: The dual of a smooth conic in the plane is also a smooth conic:: sage: R.<x, y, z> = QQ[] sage: P.<x, y, z> = ProjectiveSpace(2, QQ) sage: I = R.ideal(x^2 + y^2 + z^2) sage: X = P.subscheme(I) sage: X.dual() Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: y0^2 + y1^2 + y2^2 The dual of the twisted cubic curve in projective 3-space is a singular quartic surface. In the following example, we compute the dual of this surface, which by double duality is equal to the twisted cubic itself. The output is the twisted cubic as an intersection of three quadrics:: sage: R.<x, y, z, w> = QQ[] sage: P.<x, y, z, w> = ProjectiveSpace(3, QQ) sage: I = R.ideal(y^2*z^2 - 4*x*z^3 - 4*y^3*w + 18*x*y*z*w - 27*x^2*w^2) sage: X = P.subscheme(I) sage: X.dual() Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: y2^2 - y1*y3, y1*y2 - y0*y3, y1^2 - y0*y2 The singular locus of the quartic surface in the last example is itself supported on a twisted cubic:: sage: X.Jacobian().radical() Ideal (z^2 - 3*y*w, y*z - 9*x*w, y^2 - 3*x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field An example over a finite field:: sage: R = PolynomialRing(GF(61), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) sage: X.dual() Closed subscheme of Projective Space of dimension 2 over Finite Field of size 61 defined by: y0^2 - 30*y1^2 - 20*y2^2 TESTS:: sage: R = PolynomialRing(Qp(3), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) sage: X.dual() Traceback (most recent call last): ... NotImplementedError: base ring must be QQ or a finite field """ from sage.libs.singular.function_factory import ff K = self.base_ring() if not(is_RationalField(K) or is_FiniteField(K)): raise NotImplementedError("base ring must be QQ or a finite field") I = self.defining_ideal() m = I.ngens() n = I.ring().ngens() - 1 if (m != 1 or (n < 1) or I.is_zero() or I.is_trivial() or not I.is_prime()): raise NotImplementedError("At the present, the method is only" " implemented for irreducible and" " reduced hypersurfaces and the given" " list of generators for the ideal must" " have exactly one element.") R = PolynomialRing(K, 'x', n + 1) from sage.schemes.projective.projective_space import ProjectiveSpace Pd = ProjectiveSpace(n, K, 'y') Rd = Pd.coordinate_ring() x = R.variable_names() y = Rd.variable_names() S = PolynomialRing(K, x + y + ('t',)) if S.has_coerce_map_from(I.ring()): T = PolynomialRing(K, 'w', n + 1) I_S = (I.change_ring(T)).change_ring(S) else: I_S = I.change_ring(S) f_S = I_S.gens()[0] z = S.gens() J = I_S for i in range(n + 1): J = J + S.ideal(z[-1] * f_S.derivative(z[i]) - z[i + n + 1]) sat = ff.elim__lib.sat max_ideal = S.ideal(z[n + 1: 2 * n + 2]) J_sat_gens = sat(J, max_ideal)[0] J_sat = S.ideal(J_sat_gens) L = J_sat.elimination_ideal(z[0: n + 1] + (z[-1],)) return Pd.subscheme(L.change_ring(Rd))
def _forward_image(self, f, check = True): """ Compute the forward image of this subscheme by the morphism ``f``. The forward image is computed through elimination and ``f`` must be a morphism for this to be well defined. In particular, let $X = V(h_1,\ldots, h_t)$ and define the ideal $I = (h_1,\ldots,h_t,y_0-f_0(\bar{x}), \ldots, y_n-f_n(\bar{x}))$. Then the elimination ideal $I_{n+1} = I \cap K[y_0,\ldots,y_n]$ is a homogeneous ideal and $self(X) = V(I_{n+1})$. INPUT: - ``f`` -- a map whose domain contains ``self`` - ``check`` -- Boolean, if `False` no input checking is done OUTPUT: - a subscheme in the codomain of ``f``. EXAMPLES:: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(PS) sage: f = H([x^2, y^2-2*z^2, z^2]) sage: X = PS.subscheme(y-2*z) sage: X._forward_image(f) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: y - 2*z :: sage: set_verbose(None) sage: PS.<x,y,z,w> = ProjectiveSpace(ZZ, 3) sage: H = End(PS) sage: f = H([y^2, x^2, w^2, z^2]) sage: X = PS.subscheme([z^2+y*w, x-w]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Integer Ring defined by: y - z, x*z - w^2 :: sage: PS.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: H = End(PS) sage: f = H([x^2 + y^2, y^2, z^2-y^2, w^2]) sage: X = PS.subscheme([z-2*w]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Complex Field with 53 bits of precision defined by: y + z + (-4.00000000000000)*w :: sage: R.<t> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([x^2 + 2*y*z, t^2*y^2, z^2]) sage: f([t^2*y-z]) Closed subscheme of Projective Space of dimension 2 over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by: y + (-1/t^2)*z :: sage: set_verbose(-1) sage: PS.<x,y,z> = ProjectiveSpace(Qp(3), 2) sage: H = End(PS) sage: f = H([x^2,2*y^2,z^2]) sage: X = PS.subscheme([2*x-y,z]) sage: f(X) Closed subscheme of Projective Space of dimension 2 over 3-adic Field with capped relative precision 20 defined by: z, x + (1 + 3^2 + 3^4 + 3^6 + 3^8 + 3^10 + 3^12 + 3^14 + 3^16 + 3^18 + O(3^20))*y :: sage: R.<y0,y1,y2,y3> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([y0*x^2+y1*z^2, y2*y^2+y3*z^2, z^2]) sage: X = P.subscheme(x*z) sage: X._forward_image(f) Closed subscheme of Projective Space of dimension 2 over Fraction Field of Multivariate Polynomial Ring in y0, y1, y2, y3 over Rational Field defined by: x*z + (-y1)*z^2 :: sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P5.<z0,z1,z2,z3,z4,z5> = ProjectiveSpace(QQ, 5) sage: H = Hom(P2, P5) sage: f = H([x^2,x*y,x*z,y^2,y*z,z^2]) #Veronese map sage: X = P2.subscheme([]) sage: f(X) Closed subscheme of Projective Space of dimension 5 over Rational Field defined by: -z4^2 + z3*z5, -z2*z4 + z1*z5, -z2*z3 + z1*z4, -z2^2 + z0*z5, -z1*z2 + z0*z4, -z1^2 + z0*z3 :: sage: P2.<x,y,z>=ProjectiveSpace(QQ, 2) sage: P3.<u,v,w,t>=ProjectiveSpace(QQ, 3) sage: H = Hom(P2, P3) sage: X = P2.subscheme([x-y,x-z]) sage: f = H([x^2,y^2,z^2,x*y]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: w - t, v - t, u - t :: sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = Hom(P2,P1) sage: f = H([x^2,y*z]) sage: X = P2.subscheme([x-y]) sage: f(X) Traceback (most recent call last): ... TypeError: map must be a morphism :: sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(PS) sage: f = H([x^3, x*y^2, x*z^2]) sage: X = PS.subscheme([x-y]) sage: X._forward_image(f) Traceback (most recent call last): ... TypeError: map must be a morphism :: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: Y = P1.subscheme([u-v]) sage: H = End(PS) sage: f = H([x^2, y^2, z^2]) sage: Y._forward_image(f) Traceback (most recent call last): ... TypeError: subscheme must be in ambient space of domain of map """ dom = f.domain() codom = f.codomain() if check: if not f.is_morphism(): raise TypeError("map must be a morphism") if self.ambient_space() != dom: raise TypeError("subscheme must be in ambient space of domain of map") CR_dom = dom.coordinate_ring() CR_codom = codom.coordinate_ring() n = CR_dom.ngens() m = CR_codom.ngens() #can't call eliminate if the base ring is polynomial so we do it ourselves #with a lex ordering R = PolynomialRing(f.base_ring(), n+m, 'tempvar', order = 'lex') Rvars = R.gens()[0 : n] phi = CR_dom.hom(Rvars,R) zero = n*[0] psi = R.hom(zero + list(CR_codom.gens()),CR_codom) #set up ideal L = R.ideal([phi(t) for t in self.defining_polynomials()] + [R.gen(n+i) - phi(f[i]) for i in range(m)]) G = L.groebner_basis() #eliminate newL = [] #get only the elimination ideal portion for i in range (len(G)-1,0,-1): v = G[i].variables() if all([Rvars[j] not in v for j in range(n)]): newL.append(psi(G[i])) return(codom.subscheme(newL))
def Chow_form(self): r""" Returns the Chow form associated to this subscheme. For a `k`-dimensional subvariety of `\mathbb{P}^N` of degree `D`. The `(N-k-1)`-dimensional projective linear subspaces of `\mathbb{P}^N` meeting `X` form a hypersurface in the Grassmannian `G(N-k-1,N)`. The homogeneous form of degree `D` defining this hypersurface in Plucker coordinates is called the Chow form of `X`. The base ring needs to be a number field, finite field, or `\QQbar`. ALGORITHM: For a `k`-dimension subscheme `X` consider the `k+1` linear forms `l_i = u_{i0}x_0 + \cdots + u_{in}x_n`. Let `J` be the ideal in the polynomial ring `K[x_i,u_{ij}]` defined by the equations of `X` and the `l_i`. Let `J'` be the saturation of `J` with respect to the irrelevant ideal of the ambient projective space of `X`. The elimination ideal `I = J' \cap K[u_{ij}]` is a principal ideal, let `R` be its generator. The Chow form is obtained by writing `R` as a polynomial in Plucker coordinates (i.e. bracket polynomials). [DalbecSturmfels]_. OUTPUT: a homogeneous polynomial. REFERENCES: .. [DalbecSturmfels] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. EXAMPLES:: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(17), 3) sage: X = P.subscheme([x3+x1,x2-x0,x2-x3]) sage: X.Chow_form() t0 - t1 + t2 + t3 :: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ,3) sage: X = P.subscheme([x3^2 -101*x1^2 - 3*x2*x0]) sage: X.Chow_form() t0^2 - 101*t2^2 - 3*t1*t3 :: sage: P.<x0,x1,x2,x3>=ProjectiveSpace(QQ,3) sage: X = P.subscheme([x0*x2-x1^2, x0*x3-x1*x2, x1*x3-x2^2]) sage: Ch = X.Chow_form(); Ch t2^3 + 2*t2^2*t3 + t2*t3^2 - 3*t1*t2*t4 - t1*t3*t4 + t0*t4^2 + t1^2*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: x2^2*x3 - x1*x3^2, -x2^3 + x0*x3^2, -x2^2*x3 + x1*x3^2, x1*x2*x3 - x0*x3^2, 3*x1*x2^2 - 3*x0*x2*x3, -2*x1^2*x3 + 2*x0*x2*x3, -3*x1^2*x2 + 3*x0*x1*x3, x1^3 - x0^2*x3, x2^3 - x1*x2*x3, -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, 2*x0*x2^2 - 2*x0*x1*x3, 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, -x0*x1*x2 + x0^2*x3, -x0*x1^2 + x0^2*x2, -x1^3 + x0*x1*x2, x0*x1^2 - x0^2*x2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field """ I = self.defining_ideal() P = self.ambient_space() R = P.coordinate_ring() N = P.dimension()+1 d = self.dimension() #create the ring for the generic linear hyperplanes # u0x0 + u1x1 + ... SS = PolynomialRing(R.base_ring(), 'u', N*(d+1), order='lex') vars = SS.variable_names() + R.variable_names() S = PolynomialRing(R.base_ring(), vars, order='lex') n = S.ngens() newcoords = [S.gen(n-N+t) for t in range(N)] #map the generators of the subscheme into the ring with the hyperplane variables phi = R.hom(newcoords,S) phi(self.defining_polynomials()[0]) #create the dim(X)+1 linear hyperplanes l = [] for i in range(d+1): t = 0 for j in range(N): t += S.gen(N*i + j)*newcoords[j] l.append(t) #intersect the hyperplanes with X J = phi(I) + S.ideal(l) #saturate the ideal with respect to the irrelevant ideal J2 = J.saturation(S.ideal([phi(t) for t in R.gens()]))[0] #eliminate the original variables to be left with the hyperplane coefficients 'u' E = J2.elimination_ideal(newcoords) #create the plucker coordinates D = binomial(N,N-d-1) #number of plucker coordinates tvars = [str('t') + str(i) for i in range(D)] #plucker coordinates T = PolynomialRing(R.base_ring(), tvars+list(S.variable_names()), order='lex') L = [] coeffs = [T.gen(i) for i in range(0+len(tvars), N*(d+1)+len(tvars))] M = matrix(T,d+1,N,coeffs) i = 0 for c in M.minors(d+1): L.append(T.gen(i)-c) i += 1 #create the ideal that we can use for eliminating to get a polynomial #in the plucker coordinates (brackets) br = T.ideal(L) #create a mapping into a polynomial ring over the plucker coordinates #and the hyperplane coefficients psi = S.hom(coeffs + [0 for i in range(N)],T) E2 = T.ideal([psi(u) for u in E.gens()] +br) #eliminate the hyperplane coefficients CH = E2.elimination_ideal(coeffs) #CH should be a principal ideal, but because of the relations among #the plucker coordinates, the elimination will probably have several generators #get the relations among the plucker coordinates rel = br.elimination_ideal(coeffs) #reduce CH with respect to the relations reduced = [] for f in CH.gens(): reduced.append(f.reduce(rel)) #find the principal generator #polynomial ring in just the plucker coordinates T2 = PolynomialRing(R.base_ring(), tvars) alp = T.hom(tvars + (N*(d+1) +N)*[0], T2) #get the degrees of the reduced generators of CH degs = [u.degree() for u in reduced] mind = max(degs) #need the smallest degree form that did not reduce to 0 for d in degs: if d < mind and d >0: mind = d ind = degs.index(mind) CF = reduced[ind] #this should be the Chow form of X #check that it is correct (i.e., it is a principal generator for CH + the relations) rel2 = rel + [CF] assert all([f in rel2 for f in CH.gens()]), "did not find a principal generator" return(alp(CF))
def __init__(self, base_ring_generators, generators, relations, grading, all_relations=True, reduce_before_evaluating=True): r""" The degree one part of the monomials that correspond to generators over the base expansion ring will serve as the coordinates of the elements. INPUT: - ``base_ring_generators`` -- A list of (equivariant) monoid power series with coefficient domain the base ring of the coefficient domain of the generators or ``None``. - ``generators`` -- A list of (equivariant) monoid power series; The generators of the ambient over the ring generated by the base ring generators. - ``relations`` -- An ideal in a polynomial ring with ``len(base_ring_generators) + len(generators)`` variables. - ``grading`` -- A grading deriving from :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_grading`; A grading for the polynomial ring of the relations. - ``all_relations`` -- A boolean (default: ``True``); If ``True`` the relations given for the polynomial ring are all relations that the Fourier expansion have. - ``reduce_before_evaluating`` -- A boolean (default: ``True``); If ``True`` any monomial will be Groebner reduced before the Fourier expansion is calculated. NOTE: The grading must respect the relations of the generators. TESTS:: sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import * sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import * sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import * sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_module import * sage: m = FreeModule(QQ, 3) sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False)) sage: mps = mpsm.base_ring() sage: ger = GradedExpansionModule_class(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mpsm, {1: m([1,1,1]), 2: m([1,3,-3])}, mpsm.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2))) sage: ger.base_ring() Graded expansion ring with generators a """ if not hasattr(self, '_element_class'): self._element_class = GradedExpansionVector_class if hasattr(self, "_extended_base_ring"): Module.__init__(self, self._extended_base_ring) elif base_ring_generators is None or len(base_ring_generators) == 0: Module.__init__(self, relations.base_ring()) else: gb = filter( lambda p: all( all(a == 0 for a in list(e)[len(base_ring_generators):]) for e in p.exponents()), relations.groebner_basis()) P = PolynomialRing( relations.base_ring(), list(relations.ring().variable_names()) [:len(base_ring_generators)]) base_relations = P.ideal(gb) R = GradedExpansionRing_class( None, base_ring_generators, base_relations, grading.subgrading(xrange(len(base_ring_generators))), all_relations, reduce_before_evaluating) Module.__init__(self, R) GradedExpansionAmbient_abstract.__init__(self, base_ring_generators, generators, relations, grading, all_relations, reduce_before_evaluating) self._populate_coercion_lists_( convert_list=[self.relations().ring()], convert_method_name="_graded_expansion_submodule_to_graded_ambient_" )
def points(self, B=0, tolerance=0.9): r""" Return some or all rational points of an affine scheme. INPUT: - ``B`` -- integer (optional, default: 0). The bound for the height of the coordinates. OUTPUT: - If the base ring is a finite field: all points of the scheme, given by coordinate tuples. - If the base ring is `\QQ` or `\ZZ`: the subset of points whose coordinates have height ``B`` or less. EXAMPLES: The bug reported at #11526 is fixed:: sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: A2(F).points() [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] sage: R = ZZ sage: A.<x,y> = R[] sage: I = A.ideal(x^2-y^2-1) sage: V = AffineSpace(R, 2) sage: X = V.subscheme(I) sage: M = X(R) sage: M.points(1) [(-1, 0), (1, 0)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: A.<x,y> = AffineSpace(K, 2) sage: len(A(K).points(9)) 361 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) sage: E(A.base_ring()).points() [(-1, 0), (0, -1), (0, 1), (1, 0)] :: sage: A.<x,y> = AffineSpace(CC, 2) sage: E = A.subscheme([y^3-x^3-x^2, x*y]) sage: E(A.base_ring()).points() [(-1.00000000000000, 0.000000000000000), (0.000000000000000, 0.000000000000000)] :: sage: A.<x1,x2> = AffineSpace(CDF, 2) sage: E = A.subscheme([x1^2+x2^2+x1*x2, x1+x2]) sage: E(A.base_ring()).points() [(0.0, 0.0)] """ from sage.schemes.affine.affine_space import is_AffineSpace from sage.rings.all import CC, CDF, RR X = self.codomain() tolerance_RR = RR(tolerance) if tolerance_RR.sign() != 1: raise ValueError("Tolerance must be positive") if not is_AffineSpace(X) and X.base_ring() in Fields(): if X.base_ring() == CC or X.base_ring() == CDF: complex = True else: complex = False # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 0: # no points return [] if dim_ideal == 0: # if X zero-dimensional rat_points = [] PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N, PS.gens(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. G = I.groebner_basis() if G != [1]: P = {} points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if complex: for pol in L.univariate_polynomial().roots( multiplicities=False): r = L.variables()[0] varindex = R.gens().index(r) P.update({R.gen(varindex): pol}) new_points.append(copy(P)) good = 1 else: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len( pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({ R.gen(varindex): -pol.constant_coefficient() / pol.monomial_coefficient(r) }) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into projective points for i in range(len(points)): if complex: if len(points[i]) == N: S = X.ambient_space()( [points[i][R.gen(j)] for j in range(N)]) #S.normalize_coordinates() rat_points.append(S) else: if len(points[i]) == N and I.subs(points[i]) == I0: S = X([points[i][R.gen(j)] for j in range(N)]) #S.normalize_coordinates() rat_points.append(S) # remove duplicate element using tolerance if complex: tol = (X.base_ring().precision() * tolerance_RR).floor() dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] for j in range(i + 1, len(dupl_points)): v = dupl_points[j] if all([(u[k] - v[k]).abs() < 2**(-tol) for k in range(len(u))]): rat_points.remove(u) break rat_points = sorted(rat_points) return rat_points R = self.value_ring() if is_RationalField(R) or R == ZZ: if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field return enum_affine_rational_field(self, B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self, B) elif is_FiniteField(R): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: raise TypeError("unable to enumerate points over %s" % R)
def algebraic_dependence(self): r""" Returns the ideal of annihilating polynomials for the polynomials in ``self``, if those polynomials are algebraically dependent. Otherwise, returns the zero ideal. OUTPUT: If the polynomials `f_1,\ldots,f_r` in ``self`` are algebraically dependent, then the output is the ideal `\{F \in K[T_1,\ldots,T_r] : F(f_1,\ldots,f_r) = 0\}` of annihilating polynomials of `f_1,\ldots,f_r`. Here `K` is the coefficient ring of polynomial ring of `f_1,\ldots,f_r` and `T_1,\ldots,T_r` are new indeterminates. If `f_1,\ldots,f_r` are algebraically independent, then the output is the zero ideal in `K[T_1,\ldots,T_r]`. EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) sage: S = Sequence([x, x*y]) sage: I = S.algebraic_dependence(); I Ideal (0) of Multivariate Polynomial Ring in T0, T1 over Rational Field :: sage: R.<x,y> = PolynomialRing(QQ) sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) sage: I = S.algebraic_dependence(); I Ideal (16 + 32*T2 - 8*T0^2 + 24*T2^2 - 8*T0^2*T2 + 8*T2^3 + 9*T0^4 - 2*T0^2*T2^2 + T2^4 - T0^4*T1 + 8*T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) of Multivariate Polynomial Ring in T0, T1, T2 over Rational Field sage: [F(S) for F in I.gens()] [0] :: sage: R.<x,y> = PolynomialRing(GF(7)) sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) sage: I = S.algebraic_dependence(); I Ideal (2 - 3*T2 - T0^2 + 3*T2^2 - T0^2*T2 + T2^3 + 2*T0^4 - 2*T0^2*T2^2 + T2^4 - T0^4*T1 + T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) of Multivariate Polynomial Ring in T0, T1, T2 over Finite Field of size 7 sage: [F(S) for F in I.gens()] [0] .. NOTE:: This function's code also works for sequences of polynomials from a univariate polynomial ring, but i don't know where in the Sage codebase to put it to use it to that effect. AUTHORS: - Alex Raichev (2011-06-22) """ R = self.ring() K = R.base_ring() Xs = list(R.gens()) r = len(self) d = len(Xs) # Expand R by r new variables. T = 'T' while T in [str(x) for x in Xs]: T = T+'T' Ts = [T + str(j) for j in range(r)] RR = PolynomialRing(K,d+r,tuple(Xs+Ts)) Vs = list(RR.gens()) Xs = Vs[0 :d] Ts = Vs[d:] J = RR.ideal([ Ts[j] - RR(self[j]) for j in range(r)]) JJ = J.elimination_ideal(Xs) # By the elimination theorem, JJ is the kernel of the ring homorphism # `phi:K[\bar T] \to K[\bar X]` that fixes `K` and sends each # `T_i` to `f_i`. # So JJ is the ideal of annihilating polynomials of `f_1,\ldots,f_r`, # which is the zero ideal in case `f_1,\ldots,f_r` are algebraically # independent. # Coerce JJ into `K[T_1,\ldots,T_r]`. # Choosing the negdeglex order simply because i find it useful in my work. RRR = PolynomialRing(K,r,tuple(Ts),order='negdeglex') return RRR.ideal(JJ.gens())
def numerical_points(self, F=None, **kwds): """ Return some or all numerical approximations of rational points of a projective scheme. This is for dimension 0 subschemes only and the points are determined through a groebner calculation over the base ring and then numerically approximating the roots of the resulting polynomials. If the base ring is a number field, the embedding into ``F`` must be known. INPUT: ``F`` - numerical ring kwds: - ``point_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, two points are considered the same if their coordinates are within tolerance. - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. OUTPUT: A list of points in the ambient space. .. WARNING:: For numerically inexact fields the list of points returned may contain repeated or be missing points due to tolerance. EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: L = E(QQ).numerical_points(F=RR); L [(0.000000000000000 : 0.000000000000000 : 1.00000000000000), (1.00000000000000 : 1.00000000000000 : 0.000000000000000)] sage: L[0].codomain() Projective Space of dimension 2 over Real Field with 53 bits of precision :: sage: S.<a> = QQ[] sage: K.<v> = NumberField(a^5 - 7, embedding=CC((7)**(1/5))) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: X = P.subscheme([x^2 - v^2*z^2, y-v*z]) sage: len(X(K).numerical_points(F=CDF)) 2 :: sage: P.<x1, x2, x3> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([3000*x1^50 + 9875643*x2^2*x3^48 + 12334545*x2^50, x1 + x2]) sage: len(E(P.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-6)) 49 TESTS:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: E(QQ).numerical_points(F=CDF, point_tolerance=-1) Traceback (most recent call last): ... ValueError: tolerance must be positive :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: E(QQ).numerical_points(F=CC, zero_tolerance=-1) Traceback (most recent call last): ... ValueError: tolerance must be positive :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: E(QQ).numerical_points(F=QQbar) Traceback (most recent call last): ... TypeError: F must be a numerical field """ from sage.schemes.projective.projective_space import is_ProjectiveSpace if F is None: F = CC if F not in Fields() or not hasattr(F, 'precision'): raise TypeError('F must be a numerical field') X = self.codomain() if X.base_ring() not in NumberFields(): raise TypeError('base ring must be a number field') PP = X.ambient_space().change_ring(F) if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional pt_tol = RR(kwds.pop('point_tolerance', 10**(-10))) zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if pt_tol <= 0 or zero_tol <= 0: raise ValueError("tolerance must be positive") rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') RF = R.change_ring(F) I = R.ideal(X.defining_polynomials()) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k): 1}).groebner_basis() G = [RF(g) for g in G] if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({RF.gen(k): 1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if len(RF(L).variables()) == 1: for pol in L.univariate_polynomial().roots( ring=F, multiplicities=False): r = L.variables()[0] varindex = RF.gens().index(r) P.update({RF.gen(varindex): pol}) new_points.append(copy(P)) good = 1 else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are approximate solutions to the equations #make them into projective points polys = [ g.change_ring(F) for g in X.defining_polynomials() ] for i in range(len(points)): if len(points[i]) == N + 1: S = PP([ points[i][RF.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() if all(g(list(S)) < zero_tol for g in polys): rat_points.add(S) # remove duplicate element using tolerance #since they are normalized we can just compare coefficients dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] for j in range(i + 1, len(dupl_points)): v = dupl_points[j] if all((u[k] - v[k]).abs() < pt_tol for k in range(len(u))): rat_points.remove(u) break rat_points = sorted(rat_points) return rat_points raise NotImplementedError( 'numerical approximation of points only for dimension 0 subschemes' )
def _forward_image(self, f, check=True): r""" Compute the forward image of this subscheme by the morphism ``f``. The forward image is computed through elimination and ``f`` must be a morphism for this to be well defined. In particular, let $X = V(h_1,\ldots, h_t)$ and define the ideal $I = (h_1,\ldots,h_t,y_0-f_0(\bar{x}), \ldots, y_n-f_n(\bar{x}))$. Then the elimination ideal $I_{n+1} = I \cap K[y_0,\ldots,y_n]$ is a homogeneous ideal and $self(X) = V(I_{n+1})$. INPUT: - ``f`` -- a map whose domain contains ``self`` - ``check`` -- Boolean, if `False` no input checking is done OUTPUT: - a subscheme in the codomain of ``f``. EXAMPLES:: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(PS) sage: f = H([x^2, y^2-2*z^2, z^2]) sage: X = PS.subscheme(y-2*z) sage: X._forward_image(f) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: y - 2*z :: sage: set_verbose(None) sage: PS.<x,y,z,w> = ProjectiveSpace(ZZ, 3) sage: H = End(PS) sage: f = H([y^2, x^2, w^2, z^2]) sage: X = PS.subscheme([z^2+y*w, x-w]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Integer Ring defined by: y - z, x*z - w^2 :: sage: PS.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: H = End(PS) sage: f = H([x^2 + y^2, y^2, z^2-y^2, w^2]) sage: X = PS.subscheme([z-2*w]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Complex Field with 53 bits of precision defined by: y + z + (-4.00000000000000)*w :: sage: R.<t> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([x^2 + 2*y*z, t^2*y^2, z^2]) sage: f([t^2*y-z]) Closed subscheme of Projective Space of dimension 2 over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by: y + (-1/t^2)*z :: sage: set_verbose(-1) sage: PS.<x,y,z> = ProjectiveSpace(Qp(3), 2) sage: H = End(PS) sage: f = H([x^2,2*y^2,z^2]) sage: X = PS.subscheme([2*x-y,z]) sage: f(X) Closed subscheme of Projective Space of dimension 2 over 3-adic Field with capped relative precision 20 defined by: z, x + (1 + 3^2 + 3^4 + 3^6 + 3^8 + 3^10 + 3^12 + 3^14 + 3^16 + 3^18 + O(3^20))*y :: sage: R.<y0,y1,y2,y3> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([y0*x^2+y1*z^2, y2*y^2+y3*z^2, z^2]) sage: X = P.subscheme(x*z) sage: X._forward_image(f) Closed subscheme of Projective Space of dimension 2 over Fraction Field of Multivariate Polynomial Ring in y0, y1, y2, y3 over Rational Field defined by: x*z + (-y1)*z^2 :: sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P5.<z0,z1,z2,z3,z4,z5> = ProjectiveSpace(QQ, 5) sage: H = Hom(P2, P5) sage: f = H([x^2,x*y,x*z,y^2,y*z,z^2]) #Veronese map sage: X = P2.subscheme([]) sage: f(X) Closed subscheme of Projective Space of dimension 5 over Rational Field defined by: -z4^2 + z3*z5, -z2*z4 + z1*z5, -z2*z3 + z1*z4, -z2^2 + z0*z5, -z1*z2 + z0*z4, -z1^2 + z0*z3 :: sage: P2.<x,y,z>=ProjectiveSpace(QQ, 2) sage: P3.<u,v,w,t>=ProjectiveSpace(QQ, 3) sage: H = Hom(P2, P3) sage: X = P2.subscheme([x-y,x-z]) sage: f = H([x^2,y^2,z^2,x*y]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: w - t, v - t, u - t :: sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = Hom(P2,P1) sage: f = H([x^2,y*z]) sage: X = P2.subscheme([x-y]) sage: f(X) Traceback (most recent call last): ... TypeError: map must be a morphism :: sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(PS) sage: f = H([x^3, x*y^2, x*z^2]) sage: X = PS.subscheme([x-y]) sage: X._forward_image(f) Traceback (most recent call last): ... TypeError: map must be a morphism :: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: Y = P1.subscheme([u-v]) sage: H = End(PS) sage: f = H([x^2, y^2, z^2]) sage: Y._forward_image(f) Traceback (most recent call last): ... TypeError: subscheme must be in ambient space of domain of map """ dom = f.domain() codom = f.codomain() if check: if not f.is_morphism(): raise TypeError("map must be a morphism") if self.ambient_space() != dom: raise TypeError( "subscheme must be in ambient space of domain of map") CR_dom = dom.coordinate_ring() CR_codom = codom.coordinate_ring() n = CR_dom.ngens() m = CR_codom.ngens() #can't call eliminate if the base ring is polynomial so we do it ourselves #with a lex ordering R = PolynomialRing(f.base_ring(), n + m, 'tempvar', order='lex') Rvars = R.gens()[0:n] phi = CR_dom.hom(Rvars, R) zero = n * [0] psi = R.hom(zero + list(CR_codom.gens()), CR_codom) #set up ideal L = R.ideal([phi(t) for t in self.defining_polynomials()] + [R.gen(n + i) - phi(f[i]) for i in range(m)]) G = L.groebner_basis() #eliminate newL = [] #get only the elimination ideal portion for i in range(len(G) - 1, 0, -1): v = G[i].variables() if all(Rvars[j] not in v for j in range(n)): newL.append(psi(G[i])) return (codom.subscheme(newL))
def algebraic_dependence(self): r""" Returns the ideal of annihilating polynomials for the polynomials in ``self``, if those polynomials are algebraically dependent. Otherwise, returns the zero ideal. OUTPUT: If the polynomials `f_1,\ldots,f_r` in ``self`` are algebraically dependent, then the output is the ideal `\{F \in K[T_1,\ldots,T_r] : F(f_1,\ldots,f_r) = 0\}` of annihilating polynomials of `f_1,\ldots,f_r`. Here `K` is the coefficient ring of polynomial ring of `f_1,\ldots,f_r` and `T_1,\ldots,T_r` are new indeterminates. If `f_1,\ldots,f_r` are algebraically independent, then the output is the zero ideal in `K[T_1,\ldots,T_r]`. EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) sage: S = Sequence([x, x*y]) sage: I = S.algebraic_dependence(); I Ideal (0) of Multivariate Polynomial Ring in T0, T1 over Rational Field :: sage: R.<x,y> = PolynomialRing(QQ) sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) sage: I = S.algebraic_dependence(); I Ideal (16 + 32*T2 - 8*T0^2 + 24*T2^2 - 8*T0^2*T2 + 8*T2^3 + 9*T0^4 - 2*T0^2*T2^2 + T2^4 - T0^4*T1 + 8*T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) of Multivariate Polynomial Ring in T0, T1, T2 over Rational Field sage: [F(S) for F in I.gens()] [0] :: sage: R.<x,y> = PolynomialRing(GF(7)) sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) sage: I = S.algebraic_dependence(); I Ideal (2 - 3*T2 - T0^2 + 3*T2^2 - T0^2*T2 + T2^3 + 2*T0^4 - 2*T0^2*T2^2 + T2^4 - T0^4*T1 + T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) of Multivariate Polynomial Ring in T0, T1, T2 over Finite Field of size 7 sage: [F(S) for F in I.gens()] [0] .. NOTE:: This function's code also works for sequences of polynomials from a univariate polynomial ring, but i don't know where in the Sage codebase to put it to use it to that effect. AUTHORS: - Alex Raichev (2011-06-22) """ R = self.ring() K = R.base_ring() Xs = list(R.gens()) r = len(self) d = len(Xs) # Expand R by r new variables. T = 'T' while T in [str(x) for x in Xs]: T = T+'T' Ts = [T + str(j) for j in range(r)] RR = PolynomialRing(K,d+r,tuple(Xs+Ts)) Vs = list(RR.gens()) Xs = Vs[0 :d] Ts = Vs[d:] J = RR.ideal([ Ts[j] - RR(self[j]) for j in range(r)]) JJ = J.elimination_ideal(Xs) # By the elimination theorem, JJ is the kernel of the ring homorphism # `phi:K[\bar T] \to K[\bar X]` that fixes `K` and sends each # `T_i` to `f_i`. # So JJ is the ideal of annihilating polynomials of `f_1,\ldots,f_r`, # which is the zero ideal in case `f_1,\ldots,f_r` are algebraically # independent. # Coerce JJ into `K[T_1,\ldots,T_r]`. # Choosing the negdeglex order simply because i find it useful in my work. RRR = PolynomialRing(K,r,tuple(Ts),order='negdeglex') return RRR.ideal(JJ.gens())
def get_ideal(self, name, base_ring=QQ, term_order="degrevlex"): """ Returns the ideal given by 'name' over the base ring given by 'base_ring' in a polynomial ring with the term order given by 'term_order'. INPUT: - ``name`` - name as on the symbolic data website - ``base_ring`` - base ring for the polynomial ring (default: ``QQ``) - ``term_order`` - term order for the polynomial ring (default: ``degrevlex``) OUTPUT: ideal as given by ``name`` in ``PolynomialRing(base_ring,vars,term_order)`` EXAMPLES:: sage: sd = SymbolicData() # optional - database_symbolic_data sage: sd.get_ideal('Katsura_3',GF(127),'degrevlex') # optional - database_symbolic_data Ideal (u0 + 2*u1 + 2*u2 + 2*u3 - 1, u1^2 + 2*u0*u2 + 2*u1*u3 - u2, 2*u0*u1 + 2*u1*u2 + 2*u2*u3 - u1, u0^2 + 2*u1^2 + 2*u2^2 + 2*u3^2 - u0) of Multivariate Polynomial Ring in u0, u1, u2, u3 over Finite Field of size 127 """ def _getTextFromNode(node): t = "" for n in node.childNodes: if n.nodeType == n.TEXT_NODE: t += str(n.nodeValue) else: raise NotTextNodeError return t def _dom2ideal(node): """ """ l = [] if str(node.nodeName) in ['vars', 'poly']: l.append(_getTextFromNode(node)) for c in node.childNodes: l += _dom2ideal(c) return l orig_name = name name = name.replace('__', '.') try: name = self.__intpath + name + ".xml" open(name) except IOError: try: name = self.__genpath + name + ".xml" open(name) except IOError: raise AttributeError( "No ideal matching '%s' found in database." % orig_name) dom = parse(name) res = _dom2ideal(dom) variables, polys = res[0].replace( "_", ""), [p.replace("_", "") for p in res[1:]] P = PolynomialRing(base_ring, len(variables.split(",")), variables) I = P.ideal([P(f) for f in polys]) return I
def points(self, **kwds): r""" Return some or all rational points of an affine scheme. Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound are returned. For a zero-dimensional subscheme, all points are returned regardless of whether the field is infinite or not. For number fields, this uses the Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for computing algebraic numbers up to a given height [Doyle-Krumm]_. The algorithm requires floating point arithmetic, so the user is allowed to specify the precision for such calculations. Additionally, due to floating point issues, points slightly larger than the bound may be returned. This can be controlled by lowering the tolerance. INPUT: - ``bound`` - a real number - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 - ``precision`` - the precision to use for computing the elements of bounded height of number fields. OUTPUT: - a list of rational points of a affine scheme EXAMPLES: The bug reported at #11526 is fixed:: sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: A2(F).points() [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] sage: R = ZZ sage: A.<x,y> = R[] sage: I = A.ideal(x^2-y^2-1) sage: V = AffineSpace(R, 2) sage: X = V.subscheme(I) sage: M = X(R) sage: M.points(bound=1) [(-1, 0), (1, 0)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: A.<x,y> = AffineSpace(K, 2) sage: len(A(K).points(bound=2)) 1849 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) sage: E(A.base_ring()).points() [(-1, 0), (0, -1), (0, 1), (1, 0)] """ B = kwds.pop('bound', 0) tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) X = self.codomain() from sage.schemes.affine.affine_space import is_AffineSpace if not is_AffineSpace(X) and X.base_ring() in Fields(): # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 0: # no points return [] if dim_ideal == 0: # if X zero-dimensional N = len(X.ambient_space().gens()) S = X.defining_polynomials()[0].parent() R = PolynomialRing(S.base_ring(), 's', N, order='lex') phi = S.hom(R.gens(), R) J = R.ideal([phi(t) for t in X.defining_polynomials()]) D = J.variety() points = [] for d in D: P = [d[t] for t in R.gens()] points.append(X(P)) points.sort() return points R = self.value_ring() if is_RationalField(R) or R == ZZ: if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field return enum_affine_rational_field(self, B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self, bound=B, tolerance=tol, precision=prec) elif is_FiniteField(R): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: raise TypeError("unable to enumerate points over %s" % R)
def has_irred_rep(self, n, gen_set=None, restrict=None, force=False): """ Returns `True` if there exists an `n`-dimensional irreducible representation of `self`, and `False` otherwise. Of course, this function runs `has_rep(n, restrict)` to verify there is a representation in the first place, and returns `False` if not. The argument `restrict` may be used equivalenty to its use in `has_rep()`. The argument `gen_set` may be set to `'PBW'` or `'pbw'`, if `self` has an algebra basis similar to that of a Poincaré-Birkhoff-Witt basis. Alternatively, an explicit generating set for the algorithm implemented by this function can be given, as a tuple or array of `FreeAlgebraElements`. This is only useful if the package cannot reduce the elements of `self`, but they can be reduced in theory. Use `force=True` if the function does not recognize the base field as computable, but the field is computable. """ if (not force and self.base_field() not in NumberFields and self.base_field() not in FiniteFields): raise TypeError( 'Base field must be computable. If %s is computable' % self.base_field() + ' then use force=True to bypass this.') if n not in ZZ or n < 1: raise ValueError('Dimension must be a positive integer.') if not self.has_rep(n, restrict): return False from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.groups.all import SymmetricGroup import math B = PolynomialRing(self.base_field(), (self.ngens() * n**2 + 1), 'x', order='deglex') M = MatrixSpace(B, n, sparse=True) gen_matrix = list() if not isinstance(restrict, (tuple, list)): restrict = [None for i in range(self.ngens())] if len(restrict) != self.ngens(): raise ValueError( 'Length of restrict does not match number of generators.') for i in range(self.ngens()): ith_gen_matrix = [] for j in range(n): for k in range(n): if restrict[i] == 'upper' and j > k: ith_gen_matrix.append(B.zero()) elif restrict[i] == 'lower' and j < k: ith_gen_matrix.append(B.zero()) elif restrict[i] == 'diagonal' and j != k: ith_gen_matrix.append(B.zero()) else: ith_gen_matrix.append(B.gen(j + (j + 1) * k + i * n**2)) gen_matrix.append(M(ith_gen_matrix)) relB = list() for i in range(self.nrels()): relB += self._to_matrix(self.rel(i), M, gen_matrix).list() Z = FreeAlgebra(ZZ, 2 * n - 2, 'Y') standard_poly = Z(0) for s in SymmetricGroup(2 * n - 2).list(): standard_poly += s.sign() * reduce( lambda x, y: x * y, [Z('Y%s' % (i - 1)) for i in s.tuple()]) if n <= 6 and is_NumberField(self.base_field()): p = 2 * n else: p = int( math.floor(n * math.sqrt(2 * n**2 / float(n - 1) + 1 / float(4)) + n / float(2) - 3)) if isinstance(gen_set, (tuple, list)): try: gen_set = [ self._to_matrix(elt, M, gen_matrix) for elt in gen_set ] except (NameError, TypeError) as error: print(error) if gen_set == None: word_gen_set = list(self._create_rep_gen_set(n, p)) gen_set = [ self._to_matrix(_to_element(self, [[word, self.one()]]), M, gen_matrix) for word in word_gen_set ] elif gen_set == 'pbw' or gen_set == 'PBW': word_gen_set = list(self._create_pbw_rep_gen_set(n, p)) gen_set = [ self._to_matrix(_to_element(self, [[word, self.one()]]), M, gen_matrix) for word in word_gen_set ] else: raise TypeError('Invalid generating set.') ordering = [i for i in range(2 * n - 2)] max_ordering = [ len(gen_set) - (2 * n - 2) + i for i in range(2 * n - 2) ] ordering.insert(0, 0) max_ordering.insert(0, len(gen_set)) rep_exists = False z = B.gen(B.ngens() - 1) while ordering[0] != max_ordering[0]: y = gen_set[ordering[0]].trace_of_product( standard_poly.subs({ Z('Y%s' % (j - 1)): gen_set[ordering[j]] for j in range(1, 2 * n - 1) })) radB_test = relB + [B(1) - z * y] if B.one() not in B.ideal(radB_test): rep_exists = True break for i in range(2 * n - 2, -1, -1): if i != 0 and ordering[i] != max_ordering[i]: ordering[i] += 1 break elif i == 0: ordering[i] += 1 if ordering[i] != max_ordering[i]: for j in range(1, 2 * n - 1): ordering[j] = j - 1 return rep_exists
def segre_embedding(self, PP=None): r""" Return the Segre embedding of this subscheme into the appropriate projective space. INPUT: - ``PP`` -- (default: ``None``) ambient image projective space; this is constructed if it is not given. OUTPUT: Hom from this subscheme to the appropriate subscheme of projective space EXAMPLES:: sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2,2], QQ) sage: P = ProjectiveSpace(QQ,8,'t') sage: L = (-w - v)*x + (-w*y - u*z) sage: Q = (-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + \ ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2) sage: W = X.subscheme([L,Q]) sage: phi = W.segre_embedding(P) sage: phi.codomain().ambient_space() == P True :: sage: PP.<x,y,u,v,s,t> = ProductProjectiveSpaces([1,1,1], CC) sage: PP.subscheme([]).segre_embedding() Scheme morphism: From: Closed subscheme of Product of projective spaces P^1 x P^1 x P^1 over Complex Field with 53 bits of precision defined by: (no polynomials) To: Closed subscheme of Projective Space of dimension 7 over Complex Field with 53 bits of precision defined by: -u5*u6 + u4*u7, -u3*u6 + u2*u7, -u3*u4 + u2*u5, -u3*u5 + u1*u7, -u3*u4 + u1*u6, -u3*u4 + u0*u7, -u2*u4 + u0*u6, -u1*u4 + u0*u5, -u1*u2 + u0*u3 Defn: Defined by sending (x : y , u : v , s : t) to (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t). :: sage: PP.<x,y,z,u,v,s,t> = ProductProjectiveSpaces([2,1,1], ZZ) sage: PP.subscheme([x^3, u-v, s^2-t^2]).segre_embedding() Scheme morphism: From: Closed subscheme of Product of projective spaces P^2 x P^1 x P^1 over Integer Ring defined by: x^3, u - v, s^2 - t^2 To: Closed subscheme of Projective Space of dimension 11 over Integer Ring defined by: u10^2 - u11^2, u9 - u11, u8 - u10, -u7*u10 + u6*u11, u6*u10 - u7*u11, u6^2 - u7^2, u5 - u7, u4 - u6, u3^3, -u3*u10 + u2*u11, u2*u10 - u3*u11, -u3*u6 + u2*u7, u2*u6 - u3*u7, u2*u3^2, u2^2 - u3^2, u1 - u3, u0 - u2 Defn: Defined by sending (x : y : z , u : v , s : t) to (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t : z*u*s : z*u*t : z*v*s : z*v*t). """ AS = self.ambient_space() CR = AS.coordinate_ring() N = AS.dimension_relative_components() M = prod([n + 1 for n in N]) - 1 vars = list(AS.coordinate_ring().variable_names()) + [ 'u' + str(i) for i in range(M + 1) ] R = PolynomialRing(AS.base_ring(), AS.ngens() + M + 1, vars, order='lex') #set-up the elimination for the segre embedding mapping = [] k = AS.ngens() index = AS.num_components() * [0] for count in range(M + 1): mapping.append( R.gen(k + count) - prod([CR(AS[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()[:AS.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()[AS.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 = AS.num_components() * [0] for count in range(M + 1): mapping.append( prod([CR(AS[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 points(self, B=0, prec=53): """ Return some or all rational points of a projective scheme. INPUT: - ``B`` - integer (optional, default=0). The bound for the coordinates. - ``prec`` - he precision to use to compute the elements of bounded height for number fields. OUTPUT: A list of points. Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound are returned. .. WARNING:: In the current implementation, the output of the [Doyle-Krumm] algorithm cannot be guaranteed to be correct due to the necessity of floating point computations. In some cases, the default 53-bit precision is considerably lower than would be required for the algorithm to generate correct output. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P(QQ).points(4) [(-4 : 1), (-3 : 1), (-2 : 1), (-3/2 : 1), (-4/3 : 1), (-1 : 1), (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: len(P(K).points(1.8)) 381 :: sage: P1 = ProjectiveSpace(GF(2),1) sage: F.<a> = GF(4,'a') sage: P1(F).points() [(0 : 1), (1 : 0), (1 : 1), (a : 1), (a + 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2),(y^3-y*z^2) + (x^3-x*z^2)]) sage: E(P.base_ring()).points() [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] """ X = self.codomain() from sage.schemes.projective.projective_space import is_ProjectiveSpace if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k): 1}).groebner_basis() if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({R.gen(k): 1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if L != 0: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len( pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({ R.gen(varindex): -pol.constant_coefficient() / pol.monomial_coefficient(r) }) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into projective points for i in range(len(points)): if len(points[i]) == N + 1 and I.subs( points[i]) == I0: S = X([ points[i][R.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() rat_points.add(S) rat_points = sorted(rat_points) return rat_points R = self.value_ring() if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_rational_field return enum_projective_rational_field(self, B) elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field return enum_projective_number_field(self, B, prec=prec) elif is_FiniteField(R): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field return enum_projective_finite_field(self.extended_codomain()) else: raise TypeError("unable to enumerate points over %s" % R)
def expand(self, n, letter='x'): r""" Expand ``self`` written in the `\mathbf{w}` basis in `n^2` commuting variables which satisfy the relation `x_{ij} x_{ik} = 0` for all `i`, `j`, and `k`. The expansion of an element of the `\mathbf{w}` basis is given by equations (26) and (55) in [HNT06]_. INPUT: - ``n`` -- an integer - ``letter`` -- (default: ``'x'``) a string OUTPUT: - The symmetric function of ``self`` expressed in the ``n*n`` non-commuting variables described by ``letter``. REFERENCES: .. [HNT06] \F. Hivert, J.-C. Novelli, J.-Y. Thibon. *Commutative combinatorial Hopf algebras*. (2006). :arxiv:`0605262v1`. EXAMPLES:: sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: w[[1,3],[2]].expand(4) x02*x11*x20 + x03*x11*x30 + x03*x22*x30 + x13*x22*x31 One can use a different set of variable by using the optional argument ``letter``:: sage: w[[1,3],[2]].expand(3, letter='y') y02*y11*y20 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.combinat.permutation import Permutations m = self.parent() names = ['{}{}{}'.format(letter, i, j) for i in range(n) for j in range(n)] R = PolynomialRing(m.base_ring(), n*n, names) x = [[R.gens()[i*n+j] for j in range(n)] for i in range(n)] I = R.ideal([x[i][j]*x[i][k] for j in range(n) for k in range(n) for i in range(n)]) Q = R.quotient(I, names) x = [[Q.gens()[i*n+j] for j in range(n)] for i in range(n)] P = SetPartitions() def on_basis(A): k = A.size() ret = R.zero() if n < k: return ret for p in Permutations(k): if P(p.to_cycles()) == A: # -1 for indexing ret += R.sum(prod(x[I[i]][I[p[i]-1]] for i in range(k)) for I in Subsets(range(n), k)) return ret return m._apply_module_morphism(self, on_basis, codomain=R)
def points(self, **kwds): r""" Return some or all rational points of an affine scheme. For dimension 0 subschemes points are determined through a groebner basis calculation. For schemes or subschemes with dimension greater than 1 points are determined through enumeration up to the specified bound. Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound are returned. For a zero-dimensional subscheme, all points are returned regardless of whether the field is infinite or not. For number fields, this uses the Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for computing algebraic numbers up to a given height [Doyle-Krumm]_. The algorithm requires floating point arithmetic, so the user is allowed to specify the precision for such calculations. Additionally, due to floating point issues, points slightly larger than the bound may be returned. This can be controlled by lowering the tolerance. INPUT: kwds: - ``bound`` - real number (optional, default: 0). The bound for the height of the coordinates. Only used for subschemes with dimension at least 1. - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 for enumeration over number fields. - ``precision`` - the precision to use for computing the elements of bounded height of number fields. OUTPUT: - a list of rational points of a affine scheme .. WARNING:: For numerically inexact fields such as ComplexField or RealField the list of points returned is very likely to be incomplete. It may also contain repeated points due to tolerance. EXAMPLES: The bug reported at #11526 is fixed:: sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: A2(F).points() [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] :: sage: A.<x,y> = ZZ[] sage: I = A.ideal(x^2-y^2-1) sage: V = AffineSpace(ZZ, 2) sage: X = V.subscheme(I) sage: M = X(ZZ) sage: M.points(bound=1) [(-1, 0), (1, 0)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: A.<x,y> = AffineSpace(K, 2) sage: len(A(K).points(bound=2)) 1849 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) sage: E(A.base_ring()).points() [(-1, 0), (0, -1), (0, 1), (1, 0)] :: sage: A.<x,y> = AffineSpace(CC, 2) sage: E = A.subscheme([y^3 - x^3 - x^2, x*y]) sage: E(A.base_ring()).points() verbose 0 (124: affine_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. [(-1.00000000000000, 0.000000000000000), (0.000000000000000, 0.000000000000000)] :: sage: A.<x1,x2> = AffineSpace(CDF, 2) sage: E = A.subscheme([x1^2 + x2^2 + x1*x2, x1 + x2]) sage: E(A.base_ring()).points() verbose 0 (124: affine_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. [(0.0, 0.0)] """ from sage.schemes.affine.affine_space import is_AffineSpace X = self.codomain() if not is_AffineSpace(X) and X.base_ring() in Fields(): if hasattr(X.base_ring(), 'precision'): numerical = True verbose("Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly.", level=0) zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if zero_tol <= 0: raise ValueError("tolerance must be positive") else: numerical = False # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 0: # no points return [] if dim_ideal == 0: # if X zero-dimensional rat_points = [] AS = X.ambient_space() N = AS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N, AS.gens(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. G = I.groebner_basis() if G != [1]: P = {} points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if numerical: for pol in L.univariate_polynomial().roots(multiplicities=False): r = L.variables()[0] varindex = R.gens().index(r) P.update({R.gen(varindex):pol}) new_points.append(copy(P)) good = 1 else: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len(pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({R.gen(varindex):-pol.constant_coefficient() / pol.monomial_coefficient(r)}) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into affine points for i in range(len(points)): if numerical: if len(points[i]) == N: S = AS([points[i][R.gen(j)] for j in range(N)]) if all([g(list(S)) < zero_tol for g in X.defining_polynomials()]): rat_points.append(S) else: if len(points[i]) == N and I.subs(points[i]) == I0: S = X([points[i][R.gen(j)] for j in range(N)]) rat_points.append(S) rat_points = sorted(rat_points) return rat_points R = self.value_ring() B = kwds.pop('bound', 0) tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) if is_RationalField(R) or R == ZZ: if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field return enum_affine_rational_field(self,B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self, bound=B, tolerance=tol, precision=prec) elif is_FiniteField(R): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: raise TypeError("unable to enumerate points over %s"%R)
def Chow_form(self): r""" Returns the Chow form associated to this subscheme. For a `k`-dimensional subvariety of `\mathbb{P}^N` of degree `D`. The `(N-k-1)`-dimensional projective linear subspaces of `\mathbb{P}^N` meeting `X` form a hypersurface in the Grassmannian `G(N-k-1,N)`. The homogeneous form of degree `D` defining this hypersurface in Plucker coordinates is called the Chow form of `X`. The base ring needs to be a number field, finite field, or `\QQbar`. ALGORITHM: For a `k`-dimension subscheme `X` consider the `k+1` linear forms `l_i = u_{i0}x_0 + \cdots + u_{in}x_n`. Let `J` be the ideal in the polynomial ring `K[x_i,u_{ij}]` defined by the equations of `X` and the `l_i`. Let `J'` be the saturation of `J` with respect to the irrelevant ideal of the ambient projective space of `X`. The elimination ideal `I = J' \cap K[u_{ij}]` is a principal ideal, let `R` be its generator. The Chow form is obtained by writing `R` as a polynomial in Plucker coordinates (i.e. bracket polynomials). [DalbecSturmfels]_. OUTPUT: a homogeneous polynomial. REFERENCES: .. [DalbecSturmfels] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. EXAMPLES:: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(17), 3) sage: X = P.subscheme([x3+x1,x2-x0,x2-x3]) sage: X.Chow_form() t0 - t1 + t2 + t3 :: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ,3) sage: X = P.subscheme([x3^2 -101*x1^2 - 3*x2*x0]) sage: X.Chow_form() t0^2 - 101*t2^2 - 3*t1*t3 :: sage: P.<x0,x1,x2,x3>=ProjectiveSpace(QQ,3) sage: X = P.subscheme([x0*x2-x1^2, x0*x3-x1*x2, x1*x3-x2^2]) sage: Ch = X.Chow_form(); Ch t2^3 + 2*t2^2*t3 + t2*t3^2 - 3*t1*t2*t4 - t1*t3*t4 + t0*t4^2 + t1^2*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: x2^2*x3 - x1*x3^2, -x2^3 + x0*x3^2, -x2^2*x3 + x1*x3^2, x1*x2*x3 - x0*x3^2, 3*x1*x2^2 - 3*x0*x2*x3, -2*x1^2*x3 + 2*x0*x2*x3, -3*x1^2*x2 + 3*x0*x1*x3, x1^3 - x0^2*x3, x2^3 - x1*x2*x3, -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, 2*x0*x2^2 - 2*x0*x1*x3, 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, -x0*x1*x2 + x0^2*x3, -x0*x1^2 + x0^2*x2, -x1^3 + x0*x1*x2, x0*x1^2 - x0^2*x2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field """ I = self.defining_ideal() P = self.ambient_space() R = P.coordinate_ring() N = P.dimension() + 1 d = self.dimension() # create the ring for the generic linear hyperplanes # u0x0 + u1x1 + ... SS = PolynomialRing(R.base_ring(), 'u', N * (d + 1), order='lex') vars = SS.variable_names() + R.variable_names() S = PolynomialRing(R.base_ring(), vars, order='lex') n = S.ngens() newcoords = [S.gen(n - N + t) for t in range(N)] # map the generators of the subscheme into the ring with the hyperplane variables phi = R.hom(newcoords, S) phi(self.defining_polynomials()[0]) # create the dim(X)+1 linear hyperplanes l = [] for i in range(d + 1): t = 0 for j in range(N): t += S.gen(N * i + j) * newcoords[j] l.append(t) # intersect the hyperplanes with X J = phi(I) + S.ideal(l) # saturate the ideal with respect to the irrelevant ideal J2 = J.saturation(S.ideal([phi(u) for u in R.gens()]))[0] # eliminate the original variables to be left with the hyperplane coefficients 'u' E = J2.elimination_ideal(newcoords) # create the plucker coordinates D = binomial(N, N - d - 1) #number of plucker coordinates tvars = [str('t') + str(i) for i in range(D)] #plucker coordinates T = PolynomialRing(R.base_ring(), tvars + list(S.variable_names()), order='lex') L = [] coeffs = [ T.gen(i) for i in range(0 + len(tvars), N * (d + 1) + len(tvars)) ] M = matrix(T, d + 1, N, coeffs) i = 0 for c in M.minors(d + 1): L.append(T.gen(i) - c) i += 1 # create the ideal that we can use for eliminating to get a polynomial # in the plucker coordinates (brackets) br = T.ideal(L) # create a mapping into a polynomial ring over the plucker coordinates # and the hyperplane coefficients psi = S.hom(coeffs + [0 for _ in range(N)], T) E2 = T.ideal([psi(u) for u in E.gens()] + br) # eliminate the hyperplane coefficients CH = E2.elimination_ideal(coeffs) # CH should be a principal ideal, but because of the relations among # the plucker coordinates, the elimination will probably have several generators # get the relations among the plucker coordinates rel = br.elimination_ideal(coeffs) # reduce CH with respect to the relations reduced = [] for f in CH.gens(): reduced.append(f.reduce(rel)) # find the principal generator # polynomial ring in just the plucker coordinates T2 = PolynomialRing(R.base_ring(), tvars) alp = T.hom(tvars + (N * (d + 1) + N) * [0], T2) # get the degrees of the reduced generators of CH degs = [u.degree() for u in reduced] mind = max(degs) # need the smallest degree form that did not reduce to 0 for d in degs: if d < mind and d > 0: mind = d ind = degs.index(mind) CF = reduced[ind] #this should be the Chow form of X # check that it is correct (i.e., it is a principal generator for CH + the relations) rel2 = rel + [CF] assert all(f in rel2 for f in CH.gens()), "did not find a principal generator" return alp(CF)
def numerical_points(self, F=None, **kwds): """ Return some or all numerical approximations of rational points of an affine scheme. This is for dimension 0 subschemes only and the points are determined through a groebner calculation over the base ring and then numerically approximating the roots of the resulting polynomials. If the base ring is a number field, the embedding into ``F`` must be known. INPUT: ``F`` - numerical ring kwds: - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. OUTPUT: A list of points in the ambient space. .. WARNING:: For numerically inexact fields the list of points returned may contain repeated or be missing points due to tolerance. EXAMPLES:: sage: K.<v> = QuadraticField(3) sage: A.<x,y> = AffineSpace(K, 2) sage: X = A.subscheme([x^3 - v^2*y, y - v*x^2 + 3]) sage: L = X(K).numerical_points(F=RR); L # abs tol 1e-14 [(-1.18738247880014, -0.558021142104134), (1.57693558184861, 1.30713548084184), (4.80659931965815, 37.0162574656220)] sage: L[0].codomain() Affine Space of dimension 2 over Real Field with 53 bits of precision :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) sage: len(X(QQ).numerical_points(F=ComplexField(100))) 4 :: sage: A.<x1, x2> = AffineSpace(QQ, 2) sage: E = A.subscheme([30*x1^100 + 1000*x2^2 + 2000*x1*x2 + 1, x1 + x2]) sage: len(E(A.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-9)) 100 TESTS:: sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) sage: X(QQ).numerical_points(F=QQ) Traceback (most recent call last): ... TypeError: F must be a numerical field :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) sage: X(QQ).numerical_points(F=CC, zero_tolerance=-1) Traceback (most recent call last): ... ValueError: tolerance must be positive """ from sage.schemes.affine.affine_space import is_AffineSpace if F is None: F = CC if not F in Fields() or not hasattr(F, 'precision'): raise TypeError('F must be a numerical field') X = self.codomain() if X.base_ring() not in NumberFields(): raise TypeError('base ring must be a number field') AA = X.ambient_space().change_ring(F) if not is_AffineSpace(X) and X.base_ring() in Fields(): # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal != 0: # no points return [] else: return [] # if X zero-dimensional zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if zero_tol <= 0: raise ValueError("tolerance must be positive") rat_points = [] PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() # need a lexicographic ordering for elimination R = PolynomialRing(BR, N, PS.gens(), order='lex') RF = R.change_ring(F) I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) # Determine the points through elimination This is much faster # than using the I.variety() function on each affine chart. G = I.groebner_basis() G = [RF(g) for g in G] if G != [1]: P = {} points = [P] # work backwards from solving each equation for the possible # values of the next coordinate for g in reversed(G): new_points = [] good = False for P in points: # substitute in our dictionary entry that has the # values of coordinates known so far. This results # in a single variable polynomial (by elimination) L = g.substitute(P) if len(RF(L).variables()) == 1: r = L.variables()[0] var = RF.gen(RF.gens().index(r)) for pol in L.univariate_polynomial().roots(ring=F, multiplicities=False): P[var] = pol new_points.append(copy(P)) good = True else: new_points.append(P) good = True if good: points = new_points # the dictionary entries now have values for all # coordinates they are the rational solutions to the # equations make them into affine points polys = [g.change_ring(F) for g in X.defining_polynomials()] for P in points: if len(P) == N: S = AA([P[R.gen(j)] for j in range(N)]) if all([g(list(S)) < zero_tol for g in polys]): rat_points.append(S) rat_points = sorted(rat_points) return rat_points
def dual(self): r""" Return the projective dual of the given subscheme of projective space. INPUT: - ``X`` -- A subscheme of projective space. At present, ``X`` is required to be an irreducible and reduced hypersurface defined over `\QQ` or a finite field. OUTPUT: - The dual of ``X`` as a subscheme of the dual projective space. EXAMPLES: The dual of a smooth conic in the plane is also a smooth conic:: sage: R.<x, y, z> = QQ[] sage: P.<x, y, z> = ProjectiveSpace(2, QQ) sage: I = R.ideal(x^2 + y^2 + z^2) sage: X = P.subscheme(I) sage: X.dual() Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: y0^2 + y1^2 + y2^2 The dual of the twisted cubic curve in projective 3-space is a singular quartic surface. In the following example, we compute the dual of this surface, which by double duality is equal to the twisted cubic itself. The output is the twisted cubic as an intersection of three quadrics:: sage: R.<x, y, z, w> = QQ[] sage: P.<x, y, z, w> = ProjectiveSpace(3, QQ) sage: I = R.ideal(y^2*z^2 - 4*x*z^3 - 4*y^3*w + 18*x*y*z*w - 27*x^2*w^2) sage: X = P.subscheme(I) sage: X.dual() Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: y2^2 - y1*y3, y1*y2 - y0*y3, y1^2 - y0*y2 The singular locus of the quartic surface in the last example is itself supported on a twisted cubic:: sage: X.Jacobian().radical() Ideal (z^2 - 3*y*w, y*z - 9*x*w, y^2 - 3*x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field An example over a finite field:: sage: R = PolynomialRing(GF(61), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) sage: X.dual() Closed subscheme of Projective Space of dimension 2 over Finite Field of size 61 defined by: y0^2 - 30*y1^2 - 20*y2^2 TESTS:: sage: R = PolynomialRing(Qp(3), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) sage: X.dual() Traceback (most recent call last): ... NotImplementedError: base ring must be QQ or a finite field """ from sage.libs.singular.function_factory import ff K = self.base_ring() if not (is_RationalField(K) or is_FiniteField(K)): raise NotImplementedError("base ring must be QQ or a finite field") I = self.defining_ideal() m = I.ngens() n = I.ring().ngens() - 1 if (m != 1 or (n < 1) or I.is_zero() or I.is_trivial() or not I.is_prime()): raise NotImplementedError("At the present, the method is only" " implemented for irreducible and" " reduced hypersurfaces and the given" " list of generators for the ideal must" " have exactly one element.") R = PolynomialRing(K, 'x', n + 1) from sage.schemes.projective.projective_space import ProjectiveSpace Pd = ProjectiveSpace(n, K, 'y') Rd = Pd.coordinate_ring() x = R.variable_names() y = Rd.variable_names() S = PolynomialRing(K, x + y + ('t', )) if S.has_coerce_map_from(I.ring()): T = PolynomialRing(K, 'w', n + 1) I_S = (I.change_ring(T)).change_ring(S) else: I_S = I.change_ring(S) f_S = I_S.gens()[0] z = S.gens() J = I_S for i in range(n + 1): J = J + S.ideal(z[-1] * f_S.derivative(z[i]) - z[i + n + 1]) sat = ff.elim__lib.sat max_ideal = S.ideal(z[n + 1:2 * n + 2]) J_sat_gens = sat(J, max_ideal)[0] J_sat = S.ideal(J_sat_gens) L = J_sat.elimination_ideal(z[0:n + 1] + (z[-1], )) return Pd.subscheme(L.change_ring(Rd))
def primes_of_bad_reduction(self, check=True): r""" Determines the primes of bad reduction for a map `self: \mathbb{P}^N \to \mathbb{P}^N` defined over `\ZZ` or `\QQ`. If ``check`` is ``True``, each prime is verified to be of bad reduction. ALGORITHM: `p` is a prime of bad reduction if and only if the defining polynomials of self have a common zero. Or stated another way, `p` is a prime of bad reducion if and only if the radical of the ideal defined by the defining polynomials of self is not `(x_0,x_1,\ldots,x_N)`. This happens if and only if some power of each `x_i` is not in the ideal defined by the defining polynomials of self. This last condition is what is checked. The lcm of the coefficients of the monomials `x_i` in a groebner basis is computed. This may return extra primes. INPUT: - ``check`` -- Boolean (optional - default: ``True``) OUTPUT: - a list of integer primes. EXAMPLES:: sage: P.<x,y>=ProjectiveSpace(QQ,1) sage: H=Hom(P,P) sage: f=H([1/3*x^2+1/2*y^2,y^2]) sage: print f.primes_of_bad_reduction() [2, 3] :: sage: P.<x,y,z,w>=ProjectiveSpace(QQ,3) sage: H=Hom(P,P) sage: f=H([12*x*z-7*y^2,31*x^2-y^2,26*z^2,3*w^2-z*w]) sage: f.primes_of_bad_reduction() [2, 3, 7, 13, 31] :: This is an example where check=False returns extra primes sage: P.<x,y,z>=ProjectiveSpace(ZZ,2) sage: H=Hom(P,P) sage: f=H([3*x*y^2 + 7*y^3 - 4*y^2*z + 5*z^3, -5*x^3 + x^2*y + y^3 + 2*x^2*z, -2*x^2*y + x*y^2 + y^3 - 4*y^2*z + x*z^2]) sage: f.primes_of_bad_reduction(False) [2, 5, 37, 2239, 304432717] sage: f.primes_of_bad_reduction() [5, 37, 2239, 304432717] """ if self.base_ring() != ZZ and self.base_ring() != QQ: raise TypeError("Must be ZZ or QQ") from sage.schemes.projective.projective_space import is_ProjectiveSpace if is_ProjectiveSpace(self.domain())==False or is_ProjectiveSpace(self.codomain())==False: raise NotImplementedError R=self.coordinate_ring() F=self._polys if R.base_ring().is_field(): J=R.ideal(F) else: S=PolynomialRing(R.base_ring().fraction_field(),R.gens(),R.ngens()) J=S.ideal([S.coerce(F[i]) for i in range(R.ngens())]) if J.dimension()>0: raise TypeError("Not a morphism.") #normalize to coefficients in the ring not the fraction field. F=[F[i]*lcm([F[j].denominator() for j in range(len(F))]) for i in range(len(F))] #move the ideal to the ring of integers if R.base_ring().is_field(): S=PolynomialRing(R.base_ring().ring_of_integers(),R.gens(),R.ngens()) F=[F[i].change_ring(R.base_ring().ring_of_integers()) for i in range(len(F))] J=S.ideal(F) else: J=R.ideal(F) GB=J.groebner_basis() badprimes=[] #get the primes dividing the coefficients of the monomials x_i^k_i for i in range(len(GB)): LT=GB[i].lt().degrees() power=0 for j in range(R.ngens()): if LT[j]!=0: power+=1 if power==1: badprimes=badprimes+GB[i].lt().coefficients()[0].support() badprimes=list(set(badprimes)) badprimes.sort() #check to return only the truly bad primes if check==True: index=0 while index < len(badprimes): #figure out which primes are really bad primes... S=PolynomialRing(GF(badprimes[index]),R.gens(),R.ngens()) J=S.ideal([S.coerce(F[j]) for j in range(R.ngens())]) if J.dimension()==0: badprimes.pop(index) else: index+=1 return(badprimes)