Example #1
0
    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, ))
Example #2
0
    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,) )
Example #5
0
    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
Example #7
0
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
Example #11
0
    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
Example #12
0
    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
Example #13
0
    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))
Example #15
0
    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
Example #16
0
    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)
Example #17
0
    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_" )
Example #19
0
    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)
Example #20
0
    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)
Example #21
0
    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))
Example #25
0
    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_"
        )
Example #26
0
    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())
Example #28
0
    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
Example #32
0
    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
Example #34
0
    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
Example #35
0
    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)
Example #36
0
            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)
Example #37
0
    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)
Example #39
0
    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))
Example #41
0
    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)