def Min(Fun, p, ubRes, conj, all_orbits=False): r""" Local loop for Affine_minimal, where we check minimality at the prime p. First we bound the possible k in our transformations A = zp^k + b. See Theorems 3.3.2 and 3.3.3 in [Molnar]_. INPUT: - ``Fun`` -- a dynamical system on projective space - ``p`` - a prime - ``ubRes`` -- integer, the upper bound needed for Th. 3.3.3 in [Molnar]_ - ``conj`` -- a 2x2 matrix keeping track of the conjugation - ``all_orbits`` -- boolean; whether or not to use ``==`` in the inequalities to find all orbits OUTPUT: - boolean -- ``True`` if ``Fun`` is minimal at ``p``, ``False`` otherwise - a dynamical system on projective space minimal at ``p`` EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import Min sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]])) [ Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (157*x^2 + 72*x*y + 3*y^2 : -24*x^2 + 121*x*y + 54*y^2) , <BLANKLINE> [3 1] [0 1] ] """ d = Fun.degree() AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() # all_orbits scales bounds for >= and <= if searching for orbits instead of min model if dG > (d + 1) / 2: lowerBound = (-2 * (G[dG]).valuation(p) / (2 * dG - d + 1) + 1).floor() - int(all_orbits) else: lowerBound = (-2 * (F[d]).valuation(p) / (d - 1) + 1).floor() - int(all_orbits) upperBound = 2 * (ubRes.valuation(p)) + int(all_orbits) if upperBound < lowerBound: # There are no possible transformations to reduce the resultant. if not all_orbits: return [Fun, conj] return [] # Looping over each possible k, we search for transformations to reduce # the resultant of F/G all_found = [] k = lowerBound Qb = PolynomialRing(QQ, 'b') b = Qb.gen(0) Q = PolynomialRing(Qb, 'z') z = Q.gen(0) while k <= upperBound: A = (p**k) * z + b Ft = Q(F(A) - b * G(A)) Gt = Q((p**k) * G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs RHS = (d + 1) * k / 2 # If there is some b such that Res(phi^A) < Res(phi), we must have # ord_p(c) > RHS for each c in coeffs. # Make sure constant coefficients in coeffs satisfy the inequality. if all( QQ(c).valuation(p) > RHS - int(all_orbits) for c in coeffs if c.degree() == 0): # Constant coefficients in coeffs have large enough valuation, so # check the rest. We start by checking if simply picking b=0 works. if all(c(0).valuation(p) > RHS - int(all_orbits) for c in coeffs): # A = z*p^k satisfies the inequalities, and F/G is not minimal # "Conjugating by", p,"^", k, "*z +", 0 newconj = matrix(QQ, 2, 2, [p**k, 0, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj * newconj] all_found.append([p, k, 0]) # Otherwise we search if any value of b will work. We start by # finding a minimum bound on the valuation of b that is necessary. # See Theorem 3.3.5 in [Molnar, M.Sc. thesis]. bval = max( bCheck(coeff, RHS, p, b) for coeff in coeffs if coeff.degree() > 0) # We scale the coefficients in coeffs, so that we may assume # ord_p(b) is at least 0 scaledCoeffs = [coeff(b * (p**bval)) for coeff in coeffs] # We now scale the inequalities, ord_p(coeff) > RHS, so that # coeff is in ZZ[b] scale = QQ(max(coeff.denominator() for coeff in scaledCoeffs)) normalizedCoeffs = [coeff * scale for coeff in scaledCoeffs] scaleRHS = RHS + scale.valuation(p) # We now search for integers that satisfy the inequality # ord_p(coeff) > RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]. bound = (scaleRHS + 1 - int(all_orbits)).floor() all_blift = blift(normalizedCoeffs, bound, p, k, all_orbits=all_orbits) # If bool is true after lifting, we have a solution b, and F/G # is not minimal. for boolval, sol in all_blift: if boolval: #Rescale, conjugate and return new map bsol = QQ(sol * (p**bval)) #only add 'minimal orbit element' while bsol.abs() >= p**k: if bsol < 0: bsol += p**k else: bsol -= p**k #"Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ, 2, 2, [p**k, bsol, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj * newconj] if [p, k, bsol] not in all_found: all_found.append([p, k, bsol]) k = k + 1 if not all_orbits: return [Fun, conj] return all_found
def Min(Fun, p, ubRes, conj, all_orbits=False): r""" Local loop for Affine_minimal, where we check minimality at the prime p. First we bound the possible k in our transformations A = zp^k + b. See Theorems 3.3.2 and 3.3.3 in [Molnar]_. INPUT: - ``Fun`` -- a dynamical system on projective space - ``p`` - a prime - ``ubRes`` -- integer, the upper bound needed for Th. 3.3.3 in [Molnar]_ - ``conj`` -- a 2x2 matrix keeping track of the conjugation - ``all_orbits`` -- boolean; whether or not to use ``==`` in the inequalities to find all orbits OUTPUT: - boolean -- ``True`` if ``Fun`` is minimal at ``p``, ``False`` otherwise - a dynamical system on projective space minimal at ``p`` EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import Min sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]])) [ Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (157*x^2 + 72*x*y + 3*y^2 : -24*x^2 + 121*x*y + 54*y^2) , <BLANKLINE> [3 1] [0 1] ] """ d = Fun.degree() AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() # all_orbits scales bounds for >= and <= if searching for orbits instead of min model if dG > (d+1)/2: lowerBound = (-2*(G[dG]).valuation(p)/(2*dG - d + 1) + 1).floor() - int(all_orbits) else: lowerBound = (-2*(F[d]).valuation(p)/(d-1) + 1).floor() - int(all_orbits) upperBound = 2*(ubRes.valuation(p)) + int(all_orbits) if upperBound < lowerBound: # There are no possible transformations to reduce the resultant. if not all_orbits: return [Fun, conj] return [] # Looping over each possible k, we search for transformations to reduce # the resultant of F/G all_found = [] k = lowerBound Qb = PolynomialRing(QQ,'b') b = Qb.gen(0) Q = PolynomialRing(Qb,'z') z = Q.gen(0) while k <= upperBound: A = (p**k)*z + b Ft = Q(F(A) - b*G(A)) Gt = Q((p**k)*G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs RHS = (d + 1) * k / 2 # If there is some b such that Res(phi^A) < Res(phi), we must have # ord_p(c) > RHS for each c in coeffs. # Make sure constant coefficients in coeffs satisfy the inequality. if all(QQ(c).valuation(p) > RHS - int(all_orbits) for c in coeffs if c.degree() == 0): # Constant coefficients in coeffs have large enough valuation, so # check the rest. We start by checking if simply picking b=0 works. if all(c(0).valuation(p) > RHS - int(all_orbits) for c in coeffs): # A = z*p^k satisfies the inequalities, and F/G is not minimal # "Conjugating by", p,"^", k, "*z +", 0 newconj = matrix(QQ, 2, 2, [p**k, 0, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj*newconj] all_found.append([p, k, 0]) # Otherwise we search if any value of b will work. We start by # finding a minimum bound on the valuation of b that is necessary. # See Theorem 3.3.5 in [Molnar, M.Sc. thesis]. bval = max(bCheck(coeff, RHS, p, b) for coeff in coeffs if coeff.degree() > 0) # We scale the coefficients in coeffs, so that we may assume # ord_p(b) is at least 0 scaledCoeffs = [coeff(b*(p**bval)) for coeff in coeffs] # We now scale the inequalities, ord_p(coeff) > RHS, so that # coeff is in ZZ[b] scale = QQ(max(coeff.denominator() for coeff in scaledCoeffs)) normalizedCoeffs = [coeff * scale for coeff in scaledCoeffs] scaleRHS = RHS + scale.valuation(p) # We now search for integers that satisfy the inequality # ord_p(coeff) > RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]. bound = (scaleRHS + 1 - int(all_orbits)).floor() all_blift = blift(normalizedCoeffs, bound, p, k, all_orbits=all_orbits) # If bool is true after lifting, we have a solution b, and F/G # is not minimal. for boolval, sol in all_blift: if boolval: #Rescale, conjugate and return new map bsol = QQ(sol * (p**bval)) #only add 'minimal orbit element' while bsol.abs() >= p**k: if bsol < 0: bsol += p**k else: bsol -= p**k #"Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ, 2, 2, [p**k, bsol, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj*newconj] if [p,k,bsol] not in all_found: all_found.append([p, k, bsol]) k = k + 1 if not all_orbits: return [Fun, conj] return all_found