Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/affine/affine_morphism.py
8820 views
1
r"""
2
Morphisms on affine varieties
3
4
A morphism of schemes determined by rational functions that define
5
what the morphism does on points in the ambient affine space.
6
7
8
AUTHORS:
9
10
- David Kohel, William Stein
11
12
- Volker Braun (2011-08-08): Renamed classes, more documentation, misc
13
cleanups.
14
15
- Ben Hutz (2013-03) iteration functionality and new directory structure
16
for affine/projective
17
"""
18
19
# Historical note: in trac #11599, V.B. renamed
20
# * _point_morphism_class -> _morphism
21
# * _homset_class -> _point_homset
22
23
#*****************************************************************************
24
# Copyright (C) 2011 Volker Braun <[email protected]>
25
# Copyright (C) 2006 David Kohel <[email protected]>
26
# Copyright (C) 2006 William Stein <[email protected]>
27
#
28
# Distributed under the terms of the GNU General Public License (GPL)
29
# as published by the Free Software Foundation; either version 2 of
30
# the License, or (at your option) any later version.
31
# http://www.gnu.org/licenses/
32
#*****************************************************************************
33
34
35
from sage.categories.homset import Hom
36
from sage.misc.misc import prod
37
from sage.rings.all import Integer, moebius
38
from sage.rings.arith import lcm
39
from sage.rings.complex_field import ComplexField
40
from sage.rings.integer_ring import ZZ
41
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
42
from sage.rings.quotient_ring import QuotientRing_generic
43
from sage.rings.real_mpfr import RealField
44
from sage.schemes.generic.morphism import SchemeMorphism_polynomial
45
46
47
48
49
50
class SchemeMorphism_polynomial_affine_space(SchemeMorphism_polynomial):
51
"""
52
A morphism of schemes determined by rational functions that define
53
what the morphism does on points in the ambient affine space.
54
55
EXAMPLES::
56
57
sage: RA.<x,y> = QQ[]
58
sage: A2 = AffineSpace(RA)
59
sage: RP.<u,v,w> = QQ[]
60
sage: P2 = ProjectiveSpace(RP)
61
sage: H = A2.Hom(P2)
62
sage: f = H([x, y, 1])
63
sage: f
64
Scheme morphism:
65
From: Affine Space of dimension 2 over Rational Field
66
To: Projective Space of dimension 2 over Rational Field
67
Defn: Defined on coordinates by sending (x, y) to
68
(x : y : 1)
69
"""
70
def __init__(self, parent, polys, check=True):
71
r"""
72
The Python constructor.
73
74
See :class:`SchemeMorphism_polynomial` for details.
75
76
INPUT:
77
78
- ``parent`` -- Hom
79
80
- ``polys`` -- list or tuple of polynomial or rational functions
81
82
- ``check`` -- Boolean
83
84
OUTPUT:
85
86
- :class:`SchemeMorphism_polynomial_affine_space`
87
88
EXAMPLES::
89
90
sage: A.<x,y>=AffineSpace(ZZ,2)
91
sage: H=Hom(A,A)
92
sage: H([3/5*x^2,y^2/(2*x^2)])
93
Traceback (most recent call last):
94
...
95
TypeError: polys (=[3/5*x^2, y^2/(2*x^2)]) must be rational functions in
96
Multivariate Polynomial Ring in x, y over Integer Ring
97
98
::
99
100
sage: A.<x,y>=AffineSpace(ZZ,2)
101
sage: H=Hom(A,A)
102
sage: H([3*x^2/(5*y),y^2/(2*x^2)])
103
Scheme endomorphism of Affine Space of dimension 2 over Integer Ring
104
Defn: Defined on coordinates by sending (x, y) to
105
(3*x^2/(5*y), y^2/(2*x^2))
106
107
108
sage: A.<x,y>=AffineSpace(QQ,2)
109
sage: H=Hom(A,A)
110
sage: H([3/2*x^2,y^2])
111
Scheme endomorphism of Affine Space of dimension 2 over Rational Field
112
Defn: Defined on coordinates by sending (x, y) to
113
(3/2*x^2, y^2)
114
115
116
sage: A.<x,y>=AffineSpace(QQ,2)
117
sage: X=A.subscheme([x-y^2])
118
sage: H=Hom(X,X)
119
sage: H([9/4*x^2,3/2*y])
120
Scheme endomorphism of Closed subscheme of Affine Space of dimension 2
121
over Rational Field defined by:
122
-y^2 + x
123
Defn: Defined on coordinates by sending (x, y) to
124
(9/4*x^2, 3/2*y)
125
126
sage: P.<x,y,z>=ProjectiveSpace(ZZ,2)
127
sage: H=Hom(P,P)
128
sage: f=H([5*x^3 + 3*x*y^2-y^3,3*z^3 + y*x^2, x^3-z^3])
129
sage: f.dehomogenize(2)
130
Scheme endomorphism of Affine Space of dimension 2 over Integer Ring
131
Defn: Defined on coordinates by sending (x0, x1) to
132
((5*x0^3 + 3*x0*x1^2 - x1^3)/(x0^3 - 1), (x0^2*x1 + 3)/(x0^3 - 1))
133
"""
134
if check:
135
if not isinstance(polys, (list, tuple)):
136
raise TypeError("polys (=%s) must be a list or tuple"%polys)
137
source_ring =parent.domain().ambient_space().coordinate_ring()
138
target = parent.codomain().ambient_space()
139
if len(polys) != target.ngens():
140
raise ValueError("there must be %s polynomials"%target.ngens())
141
try:
142
polys = [source_ring(poly) for poly in polys]
143
except TypeError:
144
if all(p.base_ring()==source_ring.base_ring() for p in polys)==False:
145
raise TypeError("polys (=%s) must be rational functions in %s"%(polys,source_ring))
146
try:
147
polys = [source_ring(poly.numerator())/source_ring(poly.denominator()) for poly in polys]
148
except TypeError:
149
raise TypeError("polys (=%s) must be rational functions in %s"%(polys,source_ring))
150
if isinstance(source_ring, QuotientRing_generic):
151
polys = [f.lift() for f in polys]
152
SchemeMorphism_polynomial.__init__(self, parent,polys, False)
153
154
def homogenize(self,n,newvar='h'):
155
r"""
156
Return the homogenization of ``self``. If ``self.domain()`` is a subscheme, the domain of
157
the homogenized map is the projective embedding of ``self.domain()``
158
159
INPUT:
160
161
- ``newvar`` -- the name of the homogenization variable (only used when ``self.domain()`` is affine space)
162
163
- ``n`` -- the n-th projective embedding into projective space
164
165
OUTPUT:
166
167
- :class:`SchemMorphism_polynomial_projective_space`
168
169
EXAMPLES::
170
171
sage: A.<x,y>=AffineSpace(ZZ,2)
172
sage: H=Hom(A,A)
173
sage: f=H([(x^2-2)/x^5,y^2])
174
sage: f.homogenize(2,'z')
175
Scheme endomorphism of Projective Space of dimension 2 over Integer Ring
176
Defn: Defined on coordinates by sending (x : y : z) to
177
(x^2*z^5 - 2*z^7 : x^5*y^2 : x^5*z^2)
178
179
::
180
181
sage: A.<x,y>=AffineSpace(CC,2)
182
sage: H=Hom(A,A)
183
sage: f=H([(x^2-2)/(x*y),y^2-x])
184
sage: f.homogenize(0,'z')
185
Scheme endomorphism of Projective Space of dimension 2 over Complex
186
Field with 53 bits of precision
187
Defn: Defined on coordinates by sending (x : y : z) to
188
(x*y*z^2 : x^2*z^2 + (-2.00000000000000)*z^4 : x*y^3 - x^2*y*z)
189
190
::
191
192
sage: A.<x,y>=AffineSpace(ZZ,2)
193
sage: X=A.subscheme([x-y^2])
194
sage: H=Hom(X,X)
195
sage: f=H([9*y^2,3*y])
196
sage: f.homogenize(2)
197
Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 over Integer Ring defined by:
198
-x1^2 + x0*x2
199
Defn: Defined on coordinates by sending (x0 : x1 : x2) to
200
(9*x0*x2 : 3*x1*x2 : x2^2)
201
202
::
203
204
sage: R.<t>=PolynomialRing(ZZ)
205
sage: A.<x,y>=AffineSpace(R,2)
206
sage: H=Hom(A,A)
207
sage: f=H([(x^2-2)/y,y^2-x])
208
sage: f.homogenize(0,'z')
209
Scheme endomorphism of Projective Space of dimension 2 over Univariate
210
Polynomial Ring in t over Integer Ring
211
Defn: Defined on coordinates by sending (x : y : z) to
212
(y*z^2 : x^2*z + (-2)*z^3 : y^3 - x*y*z)
213
"""
214
A=self.domain()
215
B=self.codomain()
216
N=A.ambient_space().dimension_relative()
217
NB=B.ambient_space().dimension_relative()
218
Vars=list(A.ambient_space().variable_names())+[newvar]
219
S=PolynomialRing(A.base_ring(),Vars)
220
try:
221
l=lcm([self[i].denominator() for i in range(N)])
222
except Exception: #no lcm
223
l=prod([self[i].denominator() for i in range(N)])
224
225
from sage.rings.polynomial.polynomial_ring import PolynomialRing_general
226
from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic
227
if self.domain().base_ring()==RealField() or self.domain().base_ring()==ComplexField():
228
F=[S(((self[i]*l).numerator())._maxima_().divide(self[i].denominator())[0].sage()) for i in range(N)]
229
elif isinstance(self.domain().base_ring(),(PolynomialRing_general,MPolynomialRing_generic)):
230
F=[S(((self[i]*l).numerator())._maxima_().divide(self[i].denominator())[0].sage()) for i in range(N)]
231
else:
232
F=[S(self[i]*l) for i in range(N)]
233
F.insert(n,S(l))
234
d=max([F[i].degree() for i in range(N+1)])
235
F=[F[i].homogenize(newvar)*S.gen(N)**(d-F[i].degree()) for i in range(N+1)]
236
from sage.schemes.affine.affine_space import is_AffineSpace
237
if is_AffineSpace(A)==True:
238
from sage.schemes.projective.projective_space import ProjectiveSpace
239
X=ProjectiveSpace(A.base_ring(),NB,Vars)
240
else:
241
X=A.projective_embedding(n).codomain()
242
phi=S.hom(X.ambient_space().gens(),X.ambient_space().coordinate_ring())
243
F=[phi(f) for f in F]
244
H=Hom(X,X)
245
return(H(F))
246
247
def dynatomic_polynomial(self,period):
248
r"""
249
For a map `f:\mathbb{A}^1 \to \mathbb{A}^1` this function computes the (affine) dynatomic polynomial.
250
The dynatomic polynomial is the analog of the cyclotomic polynomial and its roots are the points
251
of formal period `n`.
252
253
ALGORITHM:
254
255
Homogenize to a map `f:\mathbb{P}^1 \to \mathbb{P}^1` and compute the dynatomic polynomial there.
256
Then, dehomogenize.
257
258
INPUT:
259
260
- ``period`` -- a positive integer or a list/tuple `[m,n]` where `m` is the preperiod and `n` is the period
261
262
OUTPUT:
263
264
- If possible, a single variable polynomial in the coordinate ring of ``self``.
265
Otherwise a fraction field element of the coordinate ring of ``self``
266
267
EXAMPLES::
268
269
sage: A.<x,y>=AffineSpace(QQ,2)
270
sage: H=Hom(A,A)
271
sage: f=H([x^2+y^2,y^2])
272
sage: f.dynatomic_polynomial(2)
273
Traceback (most recent call last):
274
...
275
TypeError: Does not make sense in dimension >1
276
277
::
278
279
sage: A.<x>=AffineSpace(ZZ,1)
280
sage: H=Hom(A,A)
281
sage: f=H([(x^2+1)/x])
282
sage: f.dynatomic_polynomial(4)
283
2*x^12 + 18*x^10 + 57*x^8 + 79*x^6 + 48*x^4 + 12*x^2 + 1
284
285
::
286
287
sage: A.<x>=AffineSpace(CC,1)
288
sage: H=Hom(A,A)
289
sage: f=H([(x^2+1)/(3*x)])
290
sage: f.dynatomic_polynomial(3)
291
13.0000000000000*x^6 + 117.000000000000*x^4 + 78.0000000000000*x^2 +
292
1.00000000000000
293
294
::
295
296
sage: A.<x>=AffineSpace(QQ,1)
297
sage: H=Hom(A,A)
298
sage: f=H([x^2-10/9])
299
sage: f.dynatomic_polynomial([2,1])
300
531441*x^4 - 649539*x^2 - 524880
301
"""
302
if self.domain() != self.codomain():
303
raise TypeError("Must have same domain and codomain to iterate")
304
from sage.schemes.affine.affine_space import is_AffineSpace
305
if is_AffineSpace(self.domain())==False:
306
raise NotImplementedError("Not implemented for subschemes")
307
if self.domain().dimension_relative()>1:
308
raise TypeError("Does not make sense in dimension >1")
309
F=self.homogenize(1).dynatomic_polynomial(period)
310
if F.denominator()==1:
311
R=F.parent()
312
Vars=list(R.variable_names())
313
Vars.pop()
314
S=PolynomialRing(R.base_ring(),Vars)
315
phi=R.hom([S.gen(0),1],S)
316
return(phi(F))
317
else:
318
R=F.numerator().parent()
319
Vars=list(R.variable_names())
320
Vars.pop()
321
S=PolynomialRing(R.base_ring(),Vars)
322
phi=R.hom([S.gen(0),1],S)
323
return(phi(F.numerator())/phi(F.denominator()))
324
325
def nth_iterate_map(self,n):
326
r"""
327
This function returns the nth iterate of ``self``
328
329
ALGORITHM:
330
331
Uses a form of successive squaring to reducing computations.
332
333
.. TODO:: This could be improved.
334
335
INPUT:
336
337
- ``n`` - a positive integer.
338
339
OUTPUT:
340
341
- A map between Affine spaces
342
343
EXAMPLES::
344
345
sage: A.<x,y>=AffineSpace(ZZ,2)
346
sage: H=Hom(A,A)
347
sage: f=H([(x^2-2)/(2*y),y^2-3*x])
348
sage: f.nth_iterate_map(2)
349
Scheme endomorphism of Affine Space of dimension 2 over Integer Ring
350
Defn: Defined on coordinates by sending (x, y) to
351
((x^4 - 4*x^2 - 8*y^2 + 4)/(8*y^4 - 24*x*y^2), (2*y^5 - 12*x*y^3
352
+ 18*x^2*y - 3*x^2 + 6)/(2*y))
353
354
::
355
356
sage: A.<x>=AffineSpace(QQ,1)
357
sage: H=Hom(A,A)
358
sage: f=H([(3*x^2-2)/(x)])
359
sage: f.nth_iterate_map(3)
360
Scheme endomorphism of Affine Space of dimension 1 over Rational Field
361
Defn: Defined on coordinates by sending (x) to
362
((2187*x^8 - 6174*x^6 + 6300*x^4 - 2744*x^2 + 432)/(81*x^7 -
363
168*x^5 + 112*x^3 - 24*x))
364
365
::
366
367
sage: A.<x,y>=AffineSpace(ZZ,2)
368
sage: X=A.subscheme([x-y^2])
369
sage: H=Hom(X,X)
370
sage: f=H([9*x^2,3*y])
371
sage: f.nth_iterate_map(2)
372
Scheme endomorphism of Closed subscheme of Affine Space of dimension 2
373
over Integer Ring defined by:
374
-y^2 + x
375
Defn: Defined on coordinates by sending (x, y) to
376
(729*x^4, 9*y)
377
"""
378
if self.domain() != self.codomain():
379
raise TypeError("Domain and Codomain of function not equal")
380
N=self.codomain().ambient_space().dimension_relative()
381
F=list(self._polys)
382
R=F[0].parent()
383
Coord_ring=self.codomain().coordinate_ring()
384
D=Integer(n).digits(2)
385
if isinstance(Coord_ring, QuotientRing_generic):
386
PHI=[Coord_ring.gen(i).lift() for i in range(N)]
387
else:
388
PHI=[Coord_ring.gen(i) for i in range(N)]
389
for i in range(len(D)):
390
T=[F[j] for j in range(N)]
391
for k in range(D[i]):
392
PHI=[PHI[j](T) for j in range(N)]
393
if i!=len(D)-1: #avoid extra iterate
394
F=[R(F[j](T)) for j in range(N)] #'square'
395
H=Hom(self.domain(),self.codomain())
396
return(H(PHI))
397
398
def nth_iterate(self,P,n):
399
r"""
400
Returns the point `self^n(P)`
401
402
INPUT:
403
404
- ``P`` -- a point in ``self.domain()``
405
- ``n`` -- a positive integer.
406
407
OUTPUT:
408
409
- a point in ``self.codomain()``
410
411
EXAMPLES::
412
413
sage: A.<x,y>=AffineSpace(QQ,2)
414
sage: H=Hom(A,A)
415
sage: f=H([(x-2*y^2)/x,3*x*y])
416
sage: f.nth_iterate(A(9,3),3)
417
(-104975/13123, -9566667)
418
419
::
420
421
sage: A.<x,y>=AffineSpace(ZZ,2)
422
sage: X=A.subscheme([x-y^2])
423
sage: H=Hom(X,X)
424
sage: f=H([9*y^2,3*y])
425
sage: f.nth_iterate(X(9,3),4)
426
(59049, 243)
427
428
::
429
430
sage: R.<t>=PolynomialRing(QQ)
431
sage: A.<x,y>=AffineSpace(FractionField(R),2)
432
sage: H=Hom(A,A)
433
sage: f=H([(x-t*y^2)/x,t*x*y])
434
sage: f.nth_iterate(A(1,t),3)
435
((-t^16 + 3*t^13 - 3*t^10 + t^7 + t^5 + t^3 - 1)/(t^5 + t^3 - 1), -t^9 - t^7 + t^4)
436
437
"""
438
return(P.nth_iterate(self,n))
439
440
def orbit(self,P,n):
441
r"""
442
Returns the orbit of `P` by ``self``. If `n` is an integer it returns `[P,self(P),\ldots,self^n(P)]`.
443
444
If `n` is a list or tuple `n=[m,k]` it returns `[self^m(P),\ldots,self^k(P)]`
445
446
INPUT:
447
448
- ``P`` -- a point in ``self.domain()``
449
- ``n`` -- a non-negative integer or list or tuple of two non-negative integers
450
451
OUTPUT:
452
453
- a list of points in ``self.codomain()``
454
455
EXAMPLES::
456
457
sage: A.<x,y>=AffineSpace(QQ,2)
458
sage: H=Hom(A,A)
459
sage: f=H([(x-2*y^2)/x,3*x*y])
460
sage: f.orbit(A(9,3),3)
461
[(9, 3), (-1, 81), (13123, -243), (-104975/13123, -9566667)]
462
463
::
464
465
sage: A.<x>=AffineSpace(QQ,1)
466
sage: H=Hom(A,A)
467
sage: f=H([(x-2)/x])
468
sage: f.orbit(A(1/2),[1,3])
469
[(-3), (5/3), (-1/5)]
470
471
::
472
473
sage: A.<x,y>=AffineSpace(ZZ,2)
474
sage: X=A.subscheme([x-y^2])
475
sage: H=Hom(X,X)
476
sage: f=H([9*y^2,3*y])
477
sage: f.orbit(X(9,3),(0,4))
478
[(9, 3), (81, 9), (729, 27), (6561, 81), (59049, 243)]
479
480
::
481
482
sage: R.<t>=PolynomialRing(QQ)
483
sage: A.<x,y>=AffineSpace(FractionField(R),2)
484
sage: H=Hom(A,A)
485
sage: f=H([(x-t*y^2)/x,t*x*y])
486
sage: f.orbit(A(1,t),3)
487
[(1, t), (-t^3 + 1, t^2), ((-t^5 - t^3 + 1)/(-t^3 + 1), -t^6 + t^3),
488
((-t^16 + 3*t^13 - 3*t^10 + t^7 + t^5 + t^3 - 1)/(t^5 + t^3 - 1), -t^9 -
489
t^7 + t^4)]
490
491
"""
492
return(P.orbit(self,n))
493
494
def global_height(self,prec=None):
495
r"""
496
Returns the maximum of the heights of the coefficients in any of the coordinate functions of ``self``.
497
498
INPUT:
499
500
- ``prec`` -- desired floating point precision (default:
501
default RealField precision).
502
503
OUTPUT:
504
505
- a real number
506
507
EXAMPLES::
508
509
sage: A.<x>=AffineSpace(QQ,1)
510
sage: H=Hom(A,A)
511
sage: f=H([1/1331*x^2+4000]);
512
sage: f.global_height()
513
8.29404964010203
514
515
::
516
517
sage: R.<x>=PolynomialRing(QQ)
518
sage: k.<w>=NumberField(x^2+5)
519
sage: A.<x,y>=AffineSpace(k,2)
520
sage: H=Hom(A,A)
521
sage: f=H([13*w*x^2+4*y, 1/w*y^2]);
522
sage: f.global_height(prec=100)
523
3.3696683136785869233538671082
524
525
.. TODO::
526
527
add heights to integer.pyx and remove special case
528
"""
529
if self.domain().base_ring() == ZZ:
530
if prec is None:
531
R = RealField()
532
else:
533
R = RealField(prec)
534
H=R(0)
535
for i in range(self.domain().ambient_space().dimension_relative()):
536
C=self[i].coefficients()
537
h=max([c.abs() for c in C])
538
H=max(H,R(h).log())
539
return(H)
540
H=0
541
for i in range(self.domain().ambient_space().dimension_relative()):
542
C=self[i].coefficients()
543
if C==[]: #to deal with the case self[i]=0
544
h=0
545
else:
546
h=max([c.global_height(prec) for c in C])
547
H=max(H,h)
548
return(H)
549
550
class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space):
551
pass
552
553
class SchemeMorphism_polynomial_affine_space_finite_field(SchemeMorphism_polynomial_affine_space_field):
554
555
def cyclegraph(self):
556
r"""
557
returns Digraph of all orbits of self mod `p`. For subschemes, only points on the subscheme whose
558
image are also on the subscheme are in the digraph.
559
560
OUTPUT:
561
562
- a digraph
563
564
EXAMPLES::
565
566
sage: P.<x,y>=AffineSpace(GF(5),2)
567
sage: H=Hom(P,P)
568
sage: f=H([x^2-y,x*y+1])
569
sage: f.cyclegraph()
570
Looped digraph on 25 vertices
571
572
::
573
574
sage: P.<x>=AffineSpace(GF(3^3,'t'),1)
575
sage: H=Hom(P,P)
576
sage: f=H([x^2-1])
577
sage: f.cyclegraph()
578
Looped digraph on 27 vertices
579
580
::
581
582
sage: P.<x,y>=AffineSpace(GF(7),2)
583
sage: X=P.subscheme(x-y)
584
sage: H=Hom(X,X)
585
sage: f=H([x^2,y^2])
586
sage: f.cyclegraph()
587
Looped digraph on 7 vertices
588
"""
589
if self.domain() != self.codomain():
590
raise NotImplementedError("Domain and Codomain must be equal")
591
V=[]
592
E=[]
593
from sage.schemes.affine.affine_space import is_AffineSpace
594
if is_AffineSpace(self.domain())==True:
595
for P in self.domain():
596
V.append(str(P))
597
Q=self(P)
598
E.append([str(Q)])
599
else:
600
X=self.domain()
601
for P in X.ambient_space():
602
try:
603
XP=X.point(P)
604
V.append(str(XP))
605
Q=self(XP)
606
E.append([str(Q)])
607
except TypeError: # not on the scheme
608
pass
609
from sage.graphs.digraph import DiGraph
610
g=DiGraph(dict(zip(V,E)), loops=True)
611
return g
612
613
614
615