def __call__(self, x, type_3_pole_check=True):
        """
        Makes dynamical systems on Berkovich space over ``Cp`` callable.

        INPUT:

        - ``x`` -- a point of projective Berkovich space over ``Cp``.

        - type_3_pole_check -- (default ``True``) A bool. WARNING:
          changing the value of type_3_pole_check can lead to mathematically
          incorrect answers. Only set to ``False`` if there are NO
          poles of the dynamical system in the disk corresponding
          to the type III point ``x``. See Examples.

        OUTPUT: A point of projective Berkovich space over ``Cp``.

        EXAMPLES::

            sage: P.<x,y> = ProjectiveSpace(Qp(3), 1)
            sage: g = DynamicalSystem_projective([x^2 + y^2, x*y])
            sage: G = DynamicalSystem_Berkovich(g)
            sage: B = G.domain()
            sage: Q3 = B(0, 1)
            sage: G(Q3)
            Type II point centered at (0 : 1 + O(3^20)) of radius 3^0

        ::

            sage: P.<x,y> = ProjectiveSpace(Qp(3), 1)
            sage: H = DynamicalSystem_Berkovich([x*y^2, x^3 + 20*y^3])
            sage: B = H.domain()
            sage: Q4 = B(1/9, 1.5)
            sage: H(Q4, False)
            Type III point centered at (3^4 + 3^10 + 2*3^11 + 2*3^13 + 2*3^14 +
            2*3^15 + 3^17 + 2*3^18 + 2*3^19 + 3^20 + 3^21 + 3^22 + O(3^24) : 1 +
            O(3^20)) of radius 0.00205761316872428

        ALGORITHM:

        - For type II points, we use the approach outlined in Example
          7.37 of [Ben2019]_
        - For type III points, we use Proposition 7.6 of [Ben2019]_
        """
        if not isinstance(x.parent(), Berkovich_Cp_Projective):
            try:
                x = self.domain()(x)
            except:
                raise TypeError(
                    'action of dynamical system not defined on %s' %
                    x.parent())
        if x.parent().is_padic_base() != self.domain().is_padic_base():
            raise ValueError('x was not backed by the same type of field as f')
        if x.prime() != self.domain().prime():
            raise ValueError(
                'x and f are defined over Berkovich spaces over Cp for different p'
            )
        if x.type_of_point() == 1:
            return self.domain()(self._system(x.center()))
        if x.type_of_point() == 4:
            raise NotImplementedError(
                'action on Type IV points not implemented')
        f = self._system
        if x.type_of_point() == 2:
            if self.domain().is_number_field_base():
                ideal = self.domain().ideal()
                ring_of_integers = self.domain().base_ring().ring_of_integers()
            field = f.domain().base_ring()
            M = Matrix([[field(x.prime()**(-1 * x.power())),
                         x.center()[0]], [field(0), field(1)]])
            F = list(f * M)
            R = field['z']
            S = f.domain().coordinate_ring()
            z = R.gen(0)
            dehomogenize_hom = S.hom([z, 1])
            for i in range(len(F)):
                F[i] = dehomogenize_hom(F[i])
            lcm = field(1)
            for poly in F:
                for i in poly:
                    if i != 0:
                        lcm = i.denominator().lcm(lcm)
            for i in range(len(F)):
                F[i] *= lcm
            gcd = [i for i in F[0] if i != 0][0]
            for poly in F:
                for i in poly:
                    if i != 0:
                        gcd = gcd * i * gcd.lcm(i).inverse_of_unit()
            for i in range(len(F)):
                F[i] *= gcd.inverse_of_unit()
            gcd = F[0].gcd(F[1])
            F[0] = F[0].quo_rem(gcd)[0]
            F[1] = F[1].quo_rem(gcd)[0]
            fraction = []
            for poly in F:
                new_poly = []
                for i in poly:
                    if self.domain().is_padic_base():
                        new_poly.append(i.residue())
                    else:
                        new_poly.append(ring_of_integers(i).mod(ideal))
                new_poly = R(new_poly)
                fraction.append((new_poly))
            gcd = fraction[0].gcd(fraction[1])
            num = fraction[0].quo_rem(gcd)[0]
            dem = fraction[1].quo_rem(gcd)[0]
            if dem.is_zero():
                f = DynamicalSystem_affine(F[0] / F[1]).homogenize(1)
                f = f.conjugate(Matrix([[0, 1], [1, 0]]))
                g = DynamicalSystem_Berkovich(f)
                return g(self.domain()(QQ(0), QQ(1))).involution_map()
            # if the reduction is not constant, the image is the Gauss point
            if not (num.is_constant() and dem.is_constant()):
                return self.domain()(QQ(0), QQ(1))
            if self.domain().is_padic_base():
                reduced_value = field(num *
                                      dem.inverse_of_unit()).lift_to_precision(
                                          field.precision_cap())
            else:
                reduced_value = field(num * dem.inverse_of_unit())
            new_num = F[0] - reduced_value * F[1]
            if self.domain().is_padic_base():
                power_of_p = min([i.valuation() for i in new_num])
            else:
                power_of_p = min([i.valuation(ideal) for i in new_num])
            inverse_map = field(x.prime()**power_of_p) * z + reduced_value
            if self.domain().is_padic_base():
                return self.domain()(inverse_map(0),
                                     (inverse_map(1) - inverse_map(0)).abs())
            else:
                val = (inverse_map(1) - inverse_map(0)).valuation(ideal)
                if val == Infinity:
                    return self.domain()(inverse_map(0), 0)
                return self.domain()(inverse_map(0), x.prime()**(-1 * val))
        # point is now type III, so we compute using Proposition 7.6 [of Benedetto]
        affine_system = f.dehomogenize(1)
        dem = affine_system.defining_polynomials()[0].denominator(
        ).univariate_polynomial()
        if type_3_pole_check:
            if self.domain().is_padic_base():
                factorization = [i[0] for i in dem.factor()]
                for factor in factorization:
                    if factor.degree() >= 2:
                        try:
                            factor_root_field = factor.root_field('a')
                            factor = factor.change_ring(factor_root_field)
                        except:
                            raise NotImplementedError(
                                'cannot check if poles lie in type III disk')
                    else:
                        factor_root_field = factor.base_ring()
                    center = factor_root_field(x.center()[0])
                    for pole in [i[0] for i in factor.roots()]:
                        if (center - pole).abs() <= x.radius():
                            raise NotImplementedError(
                                'image of type III point not implemented when poles in disk'
                            )
            else:
                dem_splitting_field, embedding = dem.splitting_field('a', True)
                poles = [i[0] for i in dem.roots(dem_splitting_field)]
                primes_above = dem_splitting_field.primes_above(
                    self.domain().ideal())
                # check if all primes of the extension map the roots to outside
                # the disk corresponding to the type III point
                for prime in primes_above:
                    no_poles = True
                    for pole in poles:
                        valuation = (embedding(x.center()[0]) -
                                     pole).valuation(prime)
                        if valuation == Infinity:
                            no_poles = False
                            break
                        elif x.prime()**(-1 * valuation /
                                         prime.absolute_ramification_index()
                                         ) <= x.radius():
                            no_poles = False
                            break
                    if not no_poles:
                        break
                if not no_poles:
                    raise NotImplementedError(
                        'image of type III not implemented when poles in disk')
        nth_derivative = f.dehomogenize(1).defining_polynomials()[0]
        variable = nth_derivative.parent().gens()[0]
        a = x.center()[0]
        Taylor_expansion = []
        from sage.functions.other import factorial
        for i in range(f.degree() + 1):
            Taylor_expansion.append(nth_derivative(a) * 1 / factorial(i))
            nth_derivative = nth_derivative.derivative(variable)
        r = x.radius()
        new_center = f(a)
        if self.domain().is_padic_base():
            new_radius = max([
                Taylor_expansion[i].abs() * r**i
                for i in range(1, len(Taylor_expansion))
            ])
        else:
            if prime is None:
                prime = x.parent().ideal()
                dem_splitting_field = x.parent().base_ring()
            p = x.prime()
            new_radius = 0
            for i in range(1, len(Taylor_expansion)):
                valuation = dem_splitting_field(
                    Taylor_expansion[i]).valuation(prime)
                new_radius = max(
                    new_radius,
                    p**(-valuation / prime.absolute_ramification_index()) *
                    r**i)
        return self.domain()(new_center, new_radius)
Exemple #2
0
    def chebyshev_polynomial(self, n, kind='first', monic=False):
        """
        Generates an endomorphism of this affine line by a Chebyshev polynomial.

        Chebyshev polynomials are a sequence of recursively defined orthogonal
        polynomials. Chebyshev of the first kind are defined as `T_0(x) = 1`,
        `T_1(x) = x`, and `T_{n+1}(x) = 2xT_n(x) - T_{n-1}(x)`. Chebyshev of
        the second kind are defined as `U_0(x) = 1`,
        `U_1(x) = 2x`, and `U_{n+1}(x) = 2xU_n(x) - U_{n-1}(x)`.

        INPUT:

        - ``n`` -- a non-negative integer.

        - ``kind`` -- ``first`` or ``second`` specifying which kind of chebyshev the user would like
          to generate. Defaults to ``first``.

        - ``monic`` -- ``True`` or ``False`` specifying if the polynomial defining the system 
          should be monic or not. Defaults to ``False``.

        OUTPUT: :class:`DynamicalSystem_affine`

        EXAMPLES::

            sage: A.<x> = AffineSpace(QQ, 1)
            sage: A.chebyshev_polynomial(5, 'first')
            Dynamical System of Affine Space of dimension 1 over Rational Field
            Defn: Defined on coordinates by sending (x) to
            (16*x^5 - 20*x^3 + 5*x)

        ::

            sage: A.<x> = AffineSpace(QQ, 1)
            sage: A.chebyshev_polynomial(3, 'second')
            Dynamical System of Affine Space of dimension 1 over Rational Field
            Defn: Defined on coordinates by sending (x) to
            (8*x^3 - 4*x)

        ::

            sage: A.<x> = AffineSpace(QQ, 1)
            sage: A.chebyshev_polynomial(3, 2)
            Traceback (most recent call last):
            ...
            ValueError: keyword 'kind' must have a value of either 'first' or 'second'

        ::

            sage: A.<x> = AffineSpace(QQ, 1)
            sage: A.chebyshev_polynomial(-4, 'second')
            Traceback (most recent call last):
            ...
            ValueError: first parameter 'n' must be a non-negative integer

        ::

            sage: A = AffineSpace(QQ, 2, 'x')
            sage: A.chebyshev_polynomial(2)
            Traceback (most recent call last):
            ...
            TypeError: affine space must be of dimension 1

        ::

            sage: A.<x> = AffineSpace(QQ, 1)
            sage: A.chebyshev_polynomial(7, monic=True)
            Dynamical System of Affine Space of dimension 1 over Rational Field
              Defn: Defined on coordinates by sending (x) to
                    (x^7 - 7*x^5 + 14*x^3 - 7*x)

        ::

            sage: F.<t> = FunctionField(QQ)
            sage: A.<x> = AffineSpace(F,1)
            sage: A.chebyshev_polynomial(4, monic=True)
            Dynamical System of Affine Space of dimension 1 over Rational function field in t over Rational Field
              Defn: Defined on coordinates by sending (x) to
                    (x^4 + (-4)*x^2 + 2)
        """
        if self.dimension_relative() != 1:
            raise TypeError("affine space must be of dimension 1")
        n = ZZ(n)
        if (n < 0):
            raise ValueError("first parameter 'n' must be a non-negative integer")
        from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine
        if kind == 'first':
            if monic and self.base().characteristic() != 2:
                f = DynamicalSystem_affine([chebyshev_T(n, self.gen(0))], domain=self)
                f = f.homogenize(1)
                f = f.conjugate(matrix([[1/ZZ(2), 0],[0, 1]]))
                f = f.dehomogenize(1)
                return f
            return DynamicalSystem_affine([chebyshev_T(n, self.gen(0))], domain=self)
        elif kind == 'second':
            if monic and self.base().characteristic() != 2:
                f = DynamicalSystem_affine([chebyshev_T(n, self.gen(0))], domain=self)
                f = f.homogenize(1)
                f = f.conjugate(matrix([[1/ZZ(2), 0],[0, 1]]))
                f = f.dehomogenize(1)
                return f
            return DynamicalSystem_affine([chebyshev_U(n, self.gen(0))], domain=self)
        else:
            raise ValueError("keyword 'kind' must have a value of either 'first' or 'second'")