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)
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'")