Example #1
0
 def restrict(cone):
     patch = dict()
     divide = dict()
     for i in cone.ambient_ray_indices():
         patch[R.gen(i)] = R.zero()   # restrict to torus orbit
         # divide out highest power of R.gen(i)
         divide[R.gen(i)] = R.one()
     ideal = self.defining_ideal().change_ring(R)
     ideal = ideal.subs(patch)
     mat = jacobian(ideal.gens(), R.gens()[:fan.nrays()])
     minors = mat.minors(self.codimension())
     minors = tuple([ideal.reduce(m) for m in minors])
     Jac_patch = R.ideal(ideal.gens() + minors)
     SR_patch = R.ideal([monomial * slack[i] - R.one()
                         for i, monomial in
                         enumerate(SR.subs(divide).gens())])
     return ideal, Jac_patch + SR_patch
Example #2
0
 def restrict(cone):
     patch = dict()
     divide = dict()
     for i in cone.ambient_ray_indices():
         patch[R.gen(i)] = R.zero()   # restrict to torus orbit
         # divide out highest power of R.gen(i)
         divide[R.gen(i)] = R.one()
     ideal = self.defining_ideal().change_ring(R)
     ideal = ideal.subs(patch)
     mat = jacobian(ideal.gens(), R.gens()[:fan.nrays()])
     minors = mat.minors(self.codimension())
     minors = tuple([ideal.reduce(m) for m in minors])
     Jac_patch = R.ideal(ideal.gens() + minors)
     SR_patch = R.ideal([monomial * slack[i] - R.one()
                         for i, monomial in
                         enumerate(SR.subs(divide).gens())])
     return ideal, Jac_patch + SR_patch
Example #3
0
    def jacobian(self):
        r"""
        Returns the Jacobian matrix of partial derivitive of this map.

        The `(i, j)` entry of the Jacobian matrix is the partial derivative
        `diff(functions[i], variables[j])`.

        OUTPUT:

        - matrix with coordinates in the coordinate ring of the map.

        EXAMPLES::

            sage: A.<z> = AffineSpace(QQ, 1)
            sage: H = End(A)
            sage: f = H([z^2 - 3/4])
            sage: f.jacobian()
            [2*z]

        ::

            sage: A.<x,y> = AffineSpace(QQ, 2)
            sage: H = End(A)
            sage: f = H([x^3 - 25*x + 12*y, 5*y^2*x - 53*y + 24])
            sage: f.jacobian()
            [ 3*x^2 - 25          12]
            [      5*y^2 10*x*y - 53]

        ::

            sage: A.<x,y> = AffineSpace(ZZ, 2)
            sage: H = End(A)
            sage: f = H([(x^2 - x*y)/(1+y), (5+y)/(2+x)])
            sage: f.jacobian()
            [         (2*x - y)/(y + 1) (-x^2 - x)/(y^2 + 2*y + 1)]
            [  (-y - 5)/(x^2 + 4*x + 4)                  1/(x + 2)]
        """
        try:
            return self.__jacobian
        except AttributeError:
            pass
        self.__jacobian = jacobian(list(self),
                                   self.domain().ambient_space().gens())
        return self.__jacobian
Example #4
0
    def jacobian(self):
        r"""
        Return the Jacobian matrix of partial derivative of this map.

        The `(i, j)` entry of the Jacobian matrix is the partial derivative
        `diff(functions[i], variables[j])`.

        OUTPUT:

        - matrix with coordinates in the coordinate ring of the map.

        EXAMPLES::

            sage: A.<z> = AffineSpace(QQ, 1)
            sage: H = End(A)
            sage: f = H([z^2 - 3/4])
            sage: f.jacobian()
            [2*z]

        ::

            sage: A.<x,y> = AffineSpace(QQ, 2)
            sage: H = End(A)
            sage: f = H([x^3 - 25*x + 12*y, 5*y^2*x - 53*y + 24])
            sage: f.jacobian()
            [ 3*x^2 - 25          12]
            [      5*y^2 10*x*y - 53]

        ::

            sage: A.<x,y> = AffineSpace(ZZ, 2)
            sage: H = End(A)
            sage: f = H([(x^2 - x*y)/(1+y), (5+y)/(2+x)])
            sage: f.jacobian()
            [         (2*x - y)/(y + 1) (-x^2 - x)/(y^2 + 2*y + 1)]
            [  (-y - 5)/(x^2 + 4*x + 4)                  1/(x + 2)]
        """
        try:
            return self.__jacobian
        except AttributeError:
            pass
        self.__jacobian = jacobian(list(self),self.domain().ambient_space().gens())
        return self.__jacobian
Example #5
0
def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001):
    r"""
    Return the covariant and Julia invariant from Cremona-Stoll [CS2003]_.

    In [CS2003]_ and [HS2018]_ the Julia invariant is denoted as `\Theta(F)`
    or `R(F, z(F))`. Note that you may get faster convergence if you first move
    `z_0(F)` to the fundamental domain before computing the true covariant

    INPUT:

    - ``F`` -- binary form of degree at least 3 with no multiple roots

    - ``z0_cov`` -- boolean, compute only the `z_0` invariant. Otherwise, solve
      the minimization problem

    - ``prec``-- positive integer. precision to use in CC

    - ``emb`` -- embedding into CC

    - ``error_limit`` -- sets the error tolerance (default:0.000001)


    OUTPUT: a complex number, a real number

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import covariant_z0
        sage: R.<x,y> = QQ[]
        sage: F = 19*x^8 - 262*x^7*y + 1507*x^6*y^2 - 4784*x^5*y^3 + 9202*x^4*y^4\
        ....: - 10962*x^3*y^5 + 7844*x^2*y^6 - 3040*x*y^7 + 475*y^8
        sage: covariant_z0(F, prec=80, z0_cov=True)
        (1.3832330115323681438175 + 0.31233552177413614978744*I,
         3358.4074848663492819259)
        sage: F = -x^8 + 6*x^7*y - 7*x^6*y^2 - 12*x^5*y^3 + 27*x^4*y^4\
        ....: - 4*x^3*y^5 - 19*x^2*y^6 + 10*x*y^7 - 5*y^8
        sage: covariant_z0(F, prec=80)
        (0.64189877107807122203366 + 1.1852516565091601348355*I,
         3134.5148284344627168276)

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(x^3 + 2*x^2*y - 3*x*y^2, z0_cov=True)[0]
        0.230769230769231 + 0.799408065031789*I
        sage: -1/covariant_z0(-y^3 + 2*y^2*x + 3*y*x^2, z0_cov=True)[0]
        0.230769230769231 + 0.799408065031789*I

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(2*x^2*y - 3*x*y^2, z0_cov=True)[0]
        0.750000000000000 + 1.29903810567666*I
        sage: -1/covariant_z0(-x^3 - x^2*y + 2*x*y^2, z0_cov=True)[0] + 1
        0.750000000000000 + 1.29903810567666*I

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(x^2*y - x*y^2, prec=100) # tol 1e-28
         (0.50000000000000000000000000003 + 0.86602540378443864676372317076*I,
         1.5396007178390020386910634147)

    TESTS::

        sage: R.<x,y>=QQ[] 
        sage: covariant_z0(x^2 + 24*x*y + y^2)
        Traceback (most recent call last):
        ...
        ValueError: must be at least degree 3
        sage: covariant_z0((x+y)^3, z0_cov=True)
        Traceback (most recent call last):
        ...
        ValueError: cannot have multiple roots for z0 invariant
        sage: covariant_z0(x^3 + 3*x*y + y)
        Traceback (most recent call last):
        ...
        TypeError: must be a binary form
        sage: covariant_z0(-2*x^2*y^3 + 3*x*y^4 + 127*y^5)
        Traceback (most recent call last):
        ...
        ValueError: cannot have a root with multiplicity >= 5/2
        sage: covariant_z0((x^2+2*y^2)^2)
        Traceback (most recent call last):
        ...
        ValueError: must have at least 3 distinct roots
    """
    R = F.parent()
    d = ZZ(F.degree())
    if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()):
        raise TypeError('must be a binary form')
    if d < 3:
        raise ValueError('must be at least degree 3')

    f = F.subs({R.gen(1): 1}).univariate_polynomial()
    if f.degree() < d:
        # we have a root at infinity
        if f.constant_coefficient() != 0:
            # invert so we find all roots!
            mat = matrix(ZZ, 2, 2, [0, -1, 1, 0])
        else:
            t = 0
            while f(t) == 0:
                t += 1
            mat = matrix(ZZ, 2, 2, [t, -1, 1, 0])
    else:
        mat = matrix(ZZ, 2, 2, [1, 0, 0, 1])
    f = F(list(mat * vector(R.gens()))).subs({
        R.gen(1): 1
    }).univariate_polynomial()
    # now we have a single variable polynomial with all the roots of F
    K = ComplexField(prec=prec)
    if f.base_ring() != K:
        if emb is None:
            f = f.change_ring(K)
        else:
            f = f.change_ring(emb)
    roots = f.roots()
    if max(ex for _, ex in roots) > 1 or f.degree() < d - 1:
        if z0_cov:
            raise ValueError('cannot have multiple roots for z0 invariant')
        else:
            # just need a starting point for Newton's method
            f = f.lc() * prod([p for p, ex in f.factor()
                               ])  # removes multiple roots
            if f.degree() < 3:
                raise ValueError('must have at least 3 distinct roots')
            roots = f.roots()
    roots = [p for p, _ in roots]

    # finding quadratic Q_0, gives us our covariant, z_0
    dF = f.derivative()
    n = ZZ(f.degree())
    PR = PolynomialRing(K, 'x,y')
    x, y = PR.gens()
    # finds Stoll and Cremona's Q_0
    q  = sum([(1/(dF(r).abs()**(2/(n-2)))) * ((x-(r*y)) * (x-(r.conjugate()*y)))\
              for r in roots])
    # this is Q_0 , always positive def as long as F has distinct roots
    A = q.monomial_coefficient(x**2)
    B = q.monomial_coefficient(x * y)
    C = q.monomial_coefficient(y**2)
    # need positive root
    try:
        z = ((-B + ((B**2) - (4 * A * C)).sqrt()) / (2 * A))
    except ValueError:
        raise ValueError("not enough precision")
    if z.imag() < 0:
        z = (-B - ((B**2) - (4 * A * C)).sqrt()) / (2 * A)

    if z0_cov:
        FM = f  # for Julia's invariant
    else:
        # solve the minimization problem for 'true' covariant
        CF = ComplexIntervalField(
            prec=prec)  # keeps trac of our precision error
        z = CF(z)
        FM = F(list(mat * vector(R.gens()))).subs({
            R.gen(1): 1
        }).univariate_polynomial()
        from sage.rings.polynomial.complex_roots import complex_roots
        L1 = complex_roots(FM, min_prec=prec)
        L = []
        err = z.diameter()
        # making sure multiplicity isn't too large using convergence conditions in paper
        for p, e in L1:
            if e >= d / 2:
                raise ValueError(
                    'cannot have a root with multiplicity >= %s/2' % d)
            for _ in range(e):
                L.append(p)
        RCF = PolynomialRing(CF, 'u,t')
        a = RCF(0)
        c = RCF(0)
        u, t = RCF.gens()
        for l in L:
            a += u**2 / ((t - l) * (t - l.conjugate()) + u**2)
            c += (t - l.real()) / ((t - l) * (t - l.conjugate()) + u**2)
        # Newton's Method, to find solutions. Error bound is less than diameter of our z
        err = z.diameter()
        zz = z.diameter()
        g1 = a.numerator() - d / 2 * a.denominator()
        g2 = c.numerator()
        G = vector([g1, g2])
        J = jacobian(G, [u, t])
        v0 = vector([z.imag(), z.real()])  # z0 as starting point
        # finds our correct z
        while err <= zz:
            NJ = J.subs({u: v0[0], t: v0[1]})
            NJinv = NJ.inverse()
            # inverse for CIF matrix seems to return fractions not CIF elements, fix them
            if NJinv.base_ring() != CF:
                NJinv = matrix(CF, 2, 2, [
                    CF(zw.numerator() / zw.denominator())
                    for zw in NJinv.list()
                ])
            w = z
            v0 = v0 - NJinv * G.subs({u: v0[0], t: v0[1]})
            z = v0[1].constant_coefficient(
            ) + v0[0].constant_coefficient() * CF.gen(0)
            err = z.diameter()  # precision
            zz = (w - z).abs()  # difference in w and z
        else:
            if err > error_limit or err.is_NaN():
                raise ValueError(
                    "accuracy of Newton's root not within tolerance(%s > %s), increase precision"
                    % (err, error_limit))
        if z.imag() <= z.diameter():
            raise ArithmeticError(
                "Newton's method converged to z not in the upper half plane")
        z = z.center()

    # Julia's invariant
    if FM.base_ring() != ComplexField(prec=prec):
        FM = FM.change_ring(ComplexField(prec=prec))
    tF = z.real()
    uF = z.imag()
    th = FM.lc().abs()**2
    for r, ex in FM.roots():
        for _ in range(ex):
            th = th * ((((r - tF).abs())**2 + uF**2) / uF)

    # undo shift and invert (if needed)
    # since F \cdot m ~ m^(-1)\cdot z
    # we apply m to z to undo m acting on F
    l = mat * vector([z, 1])
    return l[0] / l[1], th