Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/projective/endPN_minimal_model.py
8820 views
1
r"""
2
Sage functions to compute minimal models of rational functions
3
under the conjugation action of `PGL_2(QQ)`.
4
5
AUTHORS:
6
7
- Alex Molnar (May 22, 2012)
8
9
- Brian Stout, Ben Hutz (Nov 2013): Modified code to use projective morphism functionality
10
so that it can be included in Sage.
11
12
REFERENCES:
13
14
.. [Bruin-Molnar] N. Bruin and A. Molnar, Minimal models for rational
15
functions in a dynamical setting
16
LMS Journal of Computation and Mathematics, Volume 15 (2012), pp 400-417.
17
18
.. [Molnar] A. Molnar, Fractional Linear Minimal Models of Rational Functions,
19
M.Sc. Thesis.
20
"""
21
22
#*****************************************************************************
23
# Copyright (C) 2012 Alexander Molnar
24
#
25
# Distributed under the terms of the GNU General Public License (GPL)
26
# as published by the Free Software Foundation; either version 2 of
27
# the License, or (at your option) any later version.
28
# http://www.gnu.org/licenses/
29
#*****************************************************************************
30
31
from sage.categories.homset import End
32
from copy import copy
33
from sage.matrix.constructor import matrix
34
from sage.rings.arith import gcd
35
from sage.rings.finite_rings.integer_mod_ring import Zmod
36
from sage.rings.integer_ring import ZZ
37
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
38
from sage.rings.rational_field import QQ
39
from sage.schemes.affine.affine_space import AffineSpace
40
41
def bCheck(c,v,p,b):
42
r"""
43
Compute a lower bound on the value of ``b`` needed, for a transformation
44
`A(z) = z*p^k + b` to satisfy `ord_p(Res(\phi^A)) < ord_p(Res(\phi))` for a
45
rational map `\phi`. See Theorem 3.3.5 in [Molnar, M.Sc. thesis].
46
47
INPUT:
48
49
- ``c`` -- a list of polynomials in `b`. See v for their use.
50
51
- ``v`` -- a list of rational numbers, where we are considering the inequalities
52
`ord_p(c[i]) > v[i]`.
53
54
- ``p`` -- a prime.
55
56
- ``b`` -- local variable.
57
58
OUTPUT:
59
60
- ``bval`` -- Integer, lower bound in Theorem 3.3.5
61
62
EXAMPLES::
63
64
sage: R.<b> = PolynomialRing(QQ)
65
sage: from sage.schemes.projective.endPN_minimal_model import bCheck
66
sage: bCheck(11664*b^2 + 70227*b + 76059, 15/2, 3, b)
67
-1
68
"""
69
val = (v+1).floor()
70
deg = c.degree()
71
coeffs = c.coeffs()
72
lcoeff = coeffs[deg]; coeffs.remove(lcoeff)
73
check1 = [(coeffs[i].valuation(p) - lcoeff.valuation(p))/(deg - i) for i in range(0,len(coeffs)) if coeffs[i] != 0]
74
check2 = (val - lcoeff.valuation(p))/deg
75
check1.append(check2)
76
bval = min(check1)
77
return (bval).ceil()
78
79
80
def scale(c,v,p):
81
r"""
82
Given an integral polynomial ``c``, we can write `c = p^i*c'`, where ``p`` does not
83
divide ``c``. Returns ``c'`` and `v - i` where `i` is the smallest valuation of the
84
coefficients of `c`.
85
86
INPUT:
87
88
- ``c`` -- an integer polynomial
89
90
- ``v`` -- an integer - the bound on the exponent from blift
91
92
- ``p`` -- a prime
93
94
OUTPUT:
95
96
- Boolean -- the new exponent bound is 0 or negative
97
98
- the scaled integer polynomial
99
100
- an integer the new exponent bound
101
102
EXAMPLES::
103
104
sage: R.<b> = PolynomialRing(QQ)
105
sage: from sage.schemes.projective.endPN_minimal_model import scale
106
sage: scale(24*b^3 + 108*b^2 + 162*b + 81, 1, 3)
107
[False, 8*b^3 + 36*b^2 + 54*b + 27, 0]
108
"""
109
scaleval = min([coeff.valuation(p) for coeff in c.coefficients()])
110
if scaleval > 0:
111
c = c/(p**scaleval)
112
v = v - scaleval
113
if v <= 0:
114
flag = False
115
else:
116
flag = True
117
return [flag,c,v]
118
119
120
def blift(LF,Li,p,S=None):
121
r"""
122
Search for a solution to the given list of inequalities. If found, lift the solution to
123
an appropriate valuation. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]
124
125
INPUT:
126
127
- ``LF`` -- a list of integer polynomials in one variable (the normalized coefficients)
128
129
- ``Li`` -- an integer, the bound on coefficients
130
131
- ``p`` -- a prime
132
133
OUTPUT:
134
135
- Boolean -- whether or not the lift is successful
136
137
- integer -- the lift
138
139
EXAMPLES::
140
141
sage: R.<b> = PolynomialRing(QQ)
142
sage: from sage.schemes.projective.endPN_minimal_model import blift
143
sage: blift([8*b^3 + 12*b^2 + 6*b + 1, 48*b^2 + 483*b + 117, 72*b + 1341, -24*b^2 + 411*b + 99, -144*b + 1233, -216*b], 2, 3)
144
(True, 4)
145
"""
146
147
P = LF[0].parent()
148
#Determine which inequalities are trivial, and scale the rest, so that we only lift
149
#as many times as needed.
150
keepScaledIneqs = [scale(P(coeff),Li,p) for coeff in LF if coeff != 0]
151
keptVals = [i[2] for i in keepScaledIneqs if i[0]]
152
if keptVals != []:
153
#Determine the valuation to lift until.
154
liftval = max(keptVals)
155
else:
156
#All inequalities are satisfied.
157
return True,1
158
if S is None:
159
S = PolynomialRing(Zmod(p),'b')
160
keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]]
161
#We need a solution for each polynomial on the left hand side of the inequalities,
162
#so we need only find a solution for their gcd.
163
g = gcd(keptScaledIneqs)
164
rts = g.roots(multiplicities=False)
165
for r in rts:
166
#Recursively try to lift each root
167
r_initial=QQ(r)
168
newInput = P([r_initial,p])
169
LG = [F(newInput) for F in LF]
170
lift,lifted = blift(LG,Li,p,S=S)
171
if lift:
172
#Lift successful.
173
return True,r_initial+ p*lifted
174
#Lift non successful.
175
return False,0
176
177
178
def affine_minimal(vp, return_transformation = False,D=None, quick = False):
179
r"""
180
Given vp a scheme morphisms on the projective line over the rationals,
181
this procedure determines if `\phi` is minimal. In particular, it determines
182
if the map is affine minimal, which is enough to decide if it is minimal
183
or not. See Proposition 2.10 in [Bruin-Molnar].
184
185
INPUT:
186
187
- ``vp`` -- scheme morphism on the projective line.
188
189
- ``D`` -- a list of primes, in case one only wants to check minimality
190
at those specific primes.
191
192
- ``return_transformation`` -- a boolean value, default value True. This
193
signals a return of the ``PGL_2`` transformation
194
to conjugate ``vp`` to the calculated minimal
195
model. default: False
196
197
- ``quick`` -- a boolean value. If true the algorithm terminates once
198
algorithm determines F/G is not minimal, otherwise algorithm
199
only terminates once a minimal model has been found.
200
201
OUTPUT:
202
203
- ``newvp`` -- scheme morphism on the projective line.
204
205
- ``conj`` -- linear fractional transformation which conjugates ``vp`` to ``newvp``
206
207
EXAMPLES::
208
sage: PS.<X,Y> = ProjectiveSpace(QQ,1)
209
sage: H = Hom(PS,PS)
210
sage: vp = H([X^2+9*Y^2,X*Y])
211
sage: from sage.schemes.projective.endPN_minimal_model import affine_minimal
212
sage: affine_minimal(vp,True)
213
(
214
Scheme endomorphism of Projective Space of dimension 1 over Rational
215
Field
216
Defn: Defined on coordinates by sending (X : Y) to
217
(X^2 + Y^2 : X*Y)
218
,
219
[3 0]
220
[0 1]
221
)
222
"""
223
BR=vp.domain().base_ring()
224
conj=matrix(BR,2,2,1)
225
flag = True
226
d = vp.degree()
227
228
vp.normalize_coordinates();
229
Affvp=vp.dehomogenize(1)
230
R=Affvp.coordinate_ring()
231
if R.is_field():
232
#want the polynomial ring not the fraction field
233
R=R.ring()
234
F=R(Affvp[0].numerator())
235
G=R(Affvp[0].denominator())
236
if G.degree()==0 or F.degree()==0:
237
raise TypeError("Affine minimality is only considered for maps not of the form f or 1/f for a polynomial f.")
238
z=F.parent().gen(0)
239
minF,minG = F,G
240
#If the valuation of a prime in the resultant is small enough, we can say the
241
#map is affine minimal at that prime without using the local minimality loop. See
242
#Theorem 3.2.2 in [Molnar, M.Sc. thesis]
243
if d%2 == 0:
244
g = d
245
else:
246
g = 2*d
247
Res = vp.resultant();
248
249
#Some quantities needed for the local minimization loop, but we compute now
250
#since the value is constant, so we do not wish to compute in every local loop.
251
#See Theorem 3.3.3 in [Molnar, M.Sc thesis]
252
253
H=F-z*minG
254
d1=F.degree()
255
A=AffineSpace(BR,1,H.parent().variable_name())
256
end_ring=End(A)
257
258
ubRes = end_ring([H/minG]).homogenize(1).resultant()
259
#Set the primes to check minimality at, if not already prescribed
260
if D is None:
261
D = ZZ(Res).prime_divisors()
262
263
#Check minimality at all primes in D. If D is all primes dividing
264
#Res(minF/minG), this is enough to show whether minF/minG is minimal or not. See
265
#Propositions 3.2.1 and 3.3.7 in [Molnar, M.Sc. thesis].
266
for p in D:
267
while True:
268
if Res.valuation(p) < g:
269
#The model is minimal at p
270
min = True
271
else:
272
#The model may not be minimal at p.
273
newvp,conj = Min(vp,p,ubRes,conj)
274
if newvp==vp:
275
min=True
276
else:
277
vp=newvp
278
Affvp=vp.dehomogenize(1)
279
min=False
280
if min:
281
#The model is minimal at p
282
break
283
elif F == Affvp[0].numerator() and G == Affvp[0].denominator():
284
#The model is minimal at p
285
break
286
else:
287
#The model is not minimal at p
288
flag = False
289
if quick:
290
break
291
if quick and not flag:
292
break
293
294
if quick: #only return whether the model is minimal
295
return flag
296
297
if return_transformation:
298
return vp, conj
299
return vp
300
301
def Min(Fun,p,ubRes,conj):
302
r"""
303
Local loop for Affine_minimal, where we check minimality at the prime p.
304
First we bound the possible k in our transformations A = zp^k + b. See Theorems
305
3.3.2 and 3.3.3 in [Molnar, M.Sc. thesis].
306
307
INPUT:
308
309
- ``Fun`` -- a projective space morphisms
310
311
- ``p`` - a prime.
312
313
- ``ubRes`` -- integer -- The upper bound needed for Theorem 3.3.3 in [Molnar, M.Sc. thesis].
314
315
- ``conj`` -- a 2x2 matrix keeping track of the conjugation
316
317
OUTPUT:
318
319
- Boolean -- True if Fun is minimal at ``p``, False otherwise
320
321
- a projective morphism minimal at ``p``
322
323
EXAMPLES::
324
325
sage: P.<x,y> = ProjectiveSpace(QQ,1)
326
sage: H = End(P)
327
sage: f = H([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2])
328
sage: from sage.schemes.projective.endPN_minimal_model import Min
329
sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]]))
330
(
331
Scheme endomorphism of Projective Space of dimension 1 over Rational
332
Field
333
Defn: Defined on coordinates by sending (x : y) to
334
(181*x^2 + 313*x*y + 81*y^2 : -24*x^2 + 73*x*y + 151*y^2)
335
,
336
[3 4]
337
[0 1]
338
)
339
"""
340
341
d=Fun.degree()
342
AffFun=Fun.dehomogenize(1)
343
R=AffFun.coordinate_ring()
344
if R.is_field():
345
#want the polynomial ring not the fraction field
346
R=R.ring()
347
F=R(AffFun[0].numerator())
348
G=R(AffFun[0].denominator())
349
dG = G.degree()
350
if dG > (d+1)/2:
351
lowerBound = (-2*(G[dG]).valuation(p)/(2*dG - d + 1) + 1).floor()
352
else:
353
lowerBound = (-2*(F[d]).valuation(p)/(d-1) + 1).floor()
354
upperBound = 2*(ubRes.valuation(p))
355
356
if upperBound < lowerBound:
357
#There are no possible transformations to reduce the resultant.
358
return Fun,conj
359
else:
360
#Looping over each possible k, we search for transformations to reduce the
361
#resultant of F/G
362
k = lowerBound
363
Qb = PolynomialRing(QQ,'b')
364
b=Qb.gen(0)
365
Q = PolynomialRing(Qb,'z')
366
z=Q.gen(0)
367
while k <= upperBound:
368
A = (p**k)*z + b
369
Ft = Q(F(A) - b*G(A))
370
Gt = Q((p**k)*G(A))
371
Fcoeffs = Ft.coeffs()
372
Gcoeffs = Gt.coeffs()
373
coeffs = Fcoeffs + Gcoeffs
374
RHS = (d + 1)*k/2
375
#If there is some b such that Res(phi^A) < Res(phi), we must have ord_p(c) >
376
#RHS for each c in coeffs.
377
378
#Make sure constant coefficients in coeffs satisfy the inequality.
379
380
if all( QQ(c).valuation(p) > RHS for c in coeffs if c.degree() ==0 ):
381
#Constant coefficients in coeffs have large enough valuation, so check
382
#the rest.
383
#We start by checking if simply picking b=0 works
384
if all(c(0).valuation(p) > RHS for c in coeffs):
385
#A = z*p^k satisfies the inequalities, and F/G is not minimal
386
387
#"Conjugating by", p,"^", k, "*z +", 0
388
newconj=matrix(QQ,2,2,[p**k,0,0,1])
389
minFun=Fun.conjugate(newconj)
390
conj=conj*newconj
391
392
minFun.normalize_coordinates()
393
return minFun, conj
394
395
#Otherwise we search if any value of b will work. We start by finding a
396
#minimum bound on the valuation of b that is necessary. See Theorem 3.3.5
397
#in [Molnar, M.Sc. thesis].
398
bval = max([bCheck(coeff,RHS,p,b) for coeff in coeffs if coeff.degree() > 0])
399
400
#We scale the coefficients in coeffs, so that we may assume ord_p(b) is
401
#at least 0
402
scaledCoeffs = [coeff(b*(p**bval)) for coeff in coeffs]
403
404
#We now scale the inequalities, ord_p(coeff) > RHS, so that coeff is in
405
#ZZ[b]
406
scale = QQ(max([coeff.denominator() for coeff in scaledCoeffs]))
407
normalizedCoeffs = [coeff*scale for coeff in scaledCoeffs]
408
scaleRHS = RHS + scale.valuation(p)
409
410
#We now search for integers that satisfy the inequality ord_p(coeff) >
411
#RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis].
412
bound = (scaleRHS+1).floor()
413
bool,sol = blift(normalizedCoeffs,bound,p)
414
415
#If bool is true after lifting, we have a solution b, and F/G is not
416
#minimal.
417
if bool:
418
#Rescale, conjugate and return new map
419
bsol = QQ(sol*(p**bval))
420
#"Conjugating by ", p,"^", k, "*z +", bsol
421
newconj=matrix(QQ,2,2,[p**k,bsol,0,1])
422
minFun=Fun.conjugate(newconj)
423
conj=conj*newconj
424
425
minFun.normalize_coordinates()
426
return minFun, conj
427
k = k + 1
428
return Fun, conj
429
430