Path: blob/master/src/sage/schemes/affine/affine_morphism.py
8820 views
r"""1Morphisms on affine varieties23A morphism of schemes determined by rational functions that define4what the morphism does on points in the ambient affine space.567AUTHORS:89- David Kohel, William Stein1011- Volker Braun (2011-08-08): Renamed classes, more documentation, misc12cleanups.1314- Ben Hutz (2013-03) iteration functionality and new directory structure15for affine/projective16"""1718# Historical note: in trac #11599, V.B. renamed19# * _point_morphism_class -> _morphism20# * _homset_class -> _point_homset2122#*****************************************************************************23# Copyright (C) 2011 Volker Braun <[email protected]>24# Copyright (C) 2006 David Kohel <[email protected]>25# Copyright (C) 2006 William Stein <[email protected]>26#27# Distributed under the terms of the GNU General Public License (GPL)28# as published by the Free Software Foundation; either version 2 of29# the License, or (at your option) any later version.30# http://www.gnu.org/licenses/31#*****************************************************************************323334from sage.categories.homset import Hom35from sage.misc.misc import prod36from sage.rings.all import Integer, moebius37from sage.rings.arith import lcm38from sage.rings.complex_field import ComplexField39from sage.rings.integer_ring import ZZ40from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing41from sage.rings.quotient_ring import QuotientRing_generic42from sage.rings.real_mpfr import RealField43from sage.schemes.generic.morphism import SchemeMorphism_polynomial444546474849class SchemeMorphism_polynomial_affine_space(SchemeMorphism_polynomial):50"""51A morphism of schemes determined by rational functions that define52what the morphism does on points in the ambient affine space.5354EXAMPLES::5556sage: RA.<x,y> = QQ[]57sage: A2 = AffineSpace(RA)58sage: RP.<u,v,w> = QQ[]59sage: P2 = ProjectiveSpace(RP)60sage: H = A2.Hom(P2)61sage: f = H([x, y, 1])62sage: f63Scheme morphism:64From: Affine Space of dimension 2 over Rational Field65To: Projective Space of dimension 2 over Rational Field66Defn: Defined on coordinates by sending (x, y) to67(x : y : 1)68"""69def __init__(self, parent, polys, check=True):70r"""71The Python constructor.7273See :class:`SchemeMorphism_polynomial` for details.7475INPUT:7677- ``parent`` -- Hom7879- ``polys`` -- list or tuple of polynomial or rational functions8081- ``check`` -- Boolean8283OUTPUT:8485- :class:`SchemeMorphism_polynomial_affine_space`8687EXAMPLES::8889sage: A.<x,y>=AffineSpace(ZZ,2)90sage: H=Hom(A,A)91sage: H([3/5*x^2,y^2/(2*x^2)])92Traceback (most recent call last):93...94TypeError: polys (=[3/5*x^2, y^2/(2*x^2)]) must be rational functions in95Multivariate Polynomial Ring in x, y over Integer Ring9697::9899sage: A.<x,y>=AffineSpace(ZZ,2)100sage: H=Hom(A,A)101sage: H([3*x^2/(5*y),y^2/(2*x^2)])102Scheme endomorphism of Affine Space of dimension 2 over Integer Ring103Defn: Defined on coordinates by sending (x, y) to104(3*x^2/(5*y), y^2/(2*x^2))105106107sage: A.<x,y>=AffineSpace(QQ,2)108sage: H=Hom(A,A)109sage: H([3/2*x^2,y^2])110Scheme endomorphism of Affine Space of dimension 2 over Rational Field111Defn: Defined on coordinates by sending (x, y) to112(3/2*x^2, y^2)113114115sage: A.<x,y>=AffineSpace(QQ,2)116sage: X=A.subscheme([x-y^2])117sage: H=Hom(X,X)118sage: H([9/4*x^2,3/2*y])119Scheme endomorphism of Closed subscheme of Affine Space of dimension 2120over Rational Field defined by:121-y^2 + x122Defn: Defined on coordinates by sending (x, y) to123(9/4*x^2, 3/2*y)124125sage: P.<x,y,z>=ProjectiveSpace(ZZ,2)126sage: H=Hom(P,P)127sage: f=H([5*x^3 + 3*x*y^2-y^3,3*z^3 + y*x^2, x^3-z^3])128sage: f.dehomogenize(2)129Scheme endomorphism of Affine Space of dimension 2 over Integer Ring130Defn: Defined on coordinates by sending (x0, x1) to131((5*x0^3 + 3*x0*x1^2 - x1^3)/(x0^3 - 1), (x0^2*x1 + 3)/(x0^3 - 1))132"""133if check:134if not isinstance(polys, (list, tuple)):135raise TypeError("polys (=%s) must be a list or tuple"%polys)136source_ring =parent.domain().ambient_space().coordinate_ring()137target = parent.codomain().ambient_space()138if len(polys) != target.ngens():139raise ValueError("there must be %s polynomials"%target.ngens())140try:141polys = [source_ring(poly) for poly in polys]142except TypeError:143if all(p.base_ring()==source_ring.base_ring() for p in polys)==False:144raise TypeError("polys (=%s) must be rational functions in %s"%(polys,source_ring))145try:146polys = [source_ring(poly.numerator())/source_ring(poly.denominator()) for poly in polys]147except TypeError:148raise TypeError("polys (=%s) must be rational functions in %s"%(polys,source_ring))149if isinstance(source_ring, QuotientRing_generic):150polys = [f.lift() for f in polys]151SchemeMorphism_polynomial.__init__(self, parent,polys, False)152153def homogenize(self,n,newvar='h'):154r"""155Return the homogenization of ``self``. If ``self.domain()`` is a subscheme, the domain of156the homogenized map is the projective embedding of ``self.domain()``157158INPUT:159160- ``newvar`` -- the name of the homogenization variable (only used when ``self.domain()`` is affine space)161162- ``n`` -- the n-th projective embedding into projective space163164OUTPUT:165166- :class:`SchemMorphism_polynomial_projective_space`167168EXAMPLES::169170sage: A.<x,y>=AffineSpace(ZZ,2)171sage: H=Hom(A,A)172sage: f=H([(x^2-2)/x^5,y^2])173sage: f.homogenize(2,'z')174Scheme endomorphism of Projective Space of dimension 2 over Integer Ring175Defn: Defined on coordinates by sending (x : y : z) to176(x^2*z^5 - 2*z^7 : x^5*y^2 : x^5*z^2)177178::179180sage: A.<x,y>=AffineSpace(CC,2)181sage: H=Hom(A,A)182sage: f=H([(x^2-2)/(x*y),y^2-x])183sage: f.homogenize(0,'z')184Scheme endomorphism of Projective Space of dimension 2 over Complex185Field with 53 bits of precision186Defn: Defined on coordinates by sending (x : y : z) to187(x*y*z^2 : x^2*z^2 + (-2.00000000000000)*z^4 : x*y^3 - x^2*y*z)188189::190191sage: A.<x,y>=AffineSpace(ZZ,2)192sage: X=A.subscheme([x-y^2])193sage: H=Hom(X,X)194sage: f=H([9*y^2,3*y])195sage: f.homogenize(2)196Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 over Integer Ring defined by:197-x1^2 + x0*x2198Defn: Defined on coordinates by sending (x0 : x1 : x2) to199(9*x0*x2 : 3*x1*x2 : x2^2)200201::202203sage: R.<t>=PolynomialRing(ZZ)204sage: A.<x,y>=AffineSpace(R,2)205sage: H=Hom(A,A)206sage: f=H([(x^2-2)/y,y^2-x])207sage: f.homogenize(0,'z')208Scheme endomorphism of Projective Space of dimension 2 over Univariate209Polynomial Ring in t over Integer Ring210Defn: Defined on coordinates by sending (x : y : z) to211(y*z^2 : x^2*z + (-2)*z^3 : y^3 - x*y*z)212"""213A=self.domain()214B=self.codomain()215N=A.ambient_space().dimension_relative()216NB=B.ambient_space().dimension_relative()217Vars=list(A.ambient_space().variable_names())+[newvar]218S=PolynomialRing(A.base_ring(),Vars)219try:220l=lcm([self[i].denominator() for i in range(N)])221except Exception: #no lcm222l=prod([self[i].denominator() for i in range(N)])223224from sage.rings.polynomial.polynomial_ring import PolynomialRing_general225from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic226if self.domain().base_ring()==RealField() or self.domain().base_ring()==ComplexField():227F=[S(((self[i]*l).numerator())._maxima_().divide(self[i].denominator())[0].sage()) for i in range(N)]228elif isinstance(self.domain().base_ring(),(PolynomialRing_general,MPolynomialRing_generic)):229F=[S(((self[i]*l).numerator())._maxima_().divide(self[i].denominator())[0].sage()) for i in range(N)]230else:231F=[S(self[i]*l) for i in range(N)]232F.insert(n,S(l))233d=max([F[i].degree() for i in range(N+1)])234F=[F[i].homogenize(newvar)*S.gen(N)**(d-F[i].degree()) for i in range(N+1)]235from sage.schemes.affine.affine_space import is_AffineSpace236if is_AffineSpace(A)==True:237from sage.schemes.projective.projective_space import ProjectiveSpace238X=ProjectiveSpace(A.base_ring(),NB,Vars)239else:240X=A.projective_embedding(n).codomain()241phi=S.hom(X.ambient_space().gens(),X.ambient_space().coordinate_ring())242F=[phi(f) for f in F]243H=Hom(X,X)244return(H(F))245246def dynatomic_polynomial(self,period):247r"""248For a map `f:\mathbb{A}^1 \to \mathbb{A}^1` this function computes the (affine) dynatomic polynomial.249The dynatomic polynomial is the analog of the cyclotomic polynomial and its roots are the points250of formal period `n`.251252ALGORITHM:253254Homogenize to a map `f:\mathbb{P}^1 \to \mathbb{P}^1` and compute the dynatomic polynomial there.255Then, dehomogenize.256257INPUT:258259- ``period`` -- a positive integer or a list/tuple `[m,n]` where `m` is the preperiod and `n` is the period260261OUTPUT:262263- If possible, a single variable polynomial in the coordinate ring of ``self``.264Otherwise a fraction field element of the coordinate ring of ``self``265266EXAMPLES::267268sage: A.<x,y>=AffineSpace(QQ,2)269sage: H=Hom(A,A)270sage: f=H([x^2+y^2,y^2])271sage: f.dynatomic_polynomial(2)272Traceback (most recent call last):273...274TypeError: Does not make sense in dimension >1275276::277278sage: A.<x>=AffineSpace(ZZ,1)279sage: H=Hom(A,A)280sage: f=H([(x^2+1)/x])281sage: f.dynatomic_polynomial(4)2822*x^12 + 18*x^10 + 57*x^8 + 79*x^6 + 48*x^4 + 12*x^2 + 1283284::285286sage: A.<x>=AffineSpace(CC,1)287sage: H=Hom(A,A)288sage: f=H([(x^2+1)/(3*x)])289sage: f.dynatomic_polynomial(3)29013.0000000000000*x^6 + 117.000000000000*x^4 + 78.0000000000000*x^2 +2911.00000000000000292293::294295sage: A.<x>=AffineSpace(QQ,1)296sage: H=Hom(A,A)297sage: f=H([x^2-10/9])298sage: f.dynatomic_polynomial([2,1])299531441*x^4 - 649539*x^2 - 524880300"""301if self.domain() != self.codomain():302raise TypeError("Must have same domain and codomain to iterate")303from sage.schemes.affine.affine_space import is_AffineSpace304if is_AffineSpace(self.domain())==False:305raise NotImplementedError("Not implemented for subschemes")306if self.domain().dimension_relative()>1:307raise TypeError("Does not make sense in dimension >1")308F=self.homogenize(1).dynatomic_polynomial(period)309if F.denominator()==1:310R=F.parent()311Vars=list(R.variable_names())312Vars.pop()313S=PolynomialRing(R.base_ring(),Vars)314phi=R.hom([S.gen(0),1],S)315return(phi(F))316else:317R=F.numerator().parent()318Vars=list(R.variable_names())319Vars.pop()320S=PolynomialRing(R.base_ring(),Vars)321phi=R.hom([S.gen(0),1],S)322return(phi(F.numerator())/phi(F.denominator()))323324def nth_iterate_map(self,n):325r"""326This function returns the nth iterate of ``self``327328ALGORITHM:329330Uses a form of successive squaring to reducing computations.331332.. TODO:: This could be improved.333334INPUT:335336- ``n`` - a positive integer.337338OUTPUT:339340- A map between Affine spaces341342EXAMPLES::343344sage: A.<x,y>=AffineSpace(ZZ,2)345sage: H=Hom(A,A)346sage: f=H([(x^2-2)/(2*y),y^2-3*x])347sage: f.nth_iterate_map(2)348Scheme endomorphism of Affine Space of dimension 2 over Integer Ring349Defn: Defined on coordinates by sending (x, y) to350((x^4 - 4*x^2 - 8*y^2 + 4)/(8*y^4 - 24*x*y^2), (2*y^5 - 12*x*y^3351+ 18*x^2*y - 3*x^2 + 6)/(2*y))352353::354355sage: A.<x>=AffineSpace(QQ,1)356sage: H=Hom(A,A)357sage: f=H([(3*x^2-2)/(x)])358sage: f.nth_iterate_map(3)359Scheme endomorphism of Affine Space of dimension 1 over Rational Field360Defn: Defined on coordinates by sending (x) to361((2187*x^8 - 6174*x^6 + 6300*x^4 - 2744*x^2 + 432)/(81*x^7 -362168*x^5 + 112*x^3 - 24*x))363364::365366sage: A.<x,y>=AffineSpace(ZZ,2)367sage: X=A.subscheme([x-y^2])368sage: H=Hom(X,X)369sage: f=H([9*x^2,3*y])370sage: f.nth_iterate_map(2)371Scheme endomorphism of Closed subscheme of Affine Space of dimension 2372over Integer Ring defined by:373-y^2 + x374Defn: Defined on coordinates by sending (x, y) to375(729*x^4, 9*y)376"""377if self.domain() != self.codomain():378raise TypeError("Domain and Codomain of function not equal")379N=self.codomain().ambient_space().dimension_relative()380F=list(self._polys)381R=F[0].parent()382Coord_ring=self.codomain().coordinate_ring()383D=Integer(n).digits(2)384if isinstance(Coord_ring, QuotientRing_generic):385PHI=[Coord_ring.gen(i).lift() for i in range(N)]386else:387PHI=[Coord_ring.gen(i) for i in range(N)]388for i in range(len(D)):389T=[F[j] for j in range(N)]390for k in range(D[i]):391PHI=[PHI[j](T) for j in range(N)]392if i!=len(D)-1: #avoid extra iterate393F=[R(F[j](T)) for j in range(N)] #'square'394H=Hom(self.domain(),self.codomain())395return(H(PHI))396397def nth_iterate(self,P,n):398r"""399Returns the point `self^n(P)`400401INPUT:402403- ``P`` -- a point in ``self.domain()``404- ``n`` -- a positive integer.405406OUTPUT:407408- a point in ``self.codomain()``409410EXAMPLES::411412sage: A.<x,y>=AffineSpace(QQ,2)413sage: H=Hom(A,A)414sage: f=H([(x-2*y^2)/x,3*x*y])415sage: f.nth_iterate(A(9,3),3)416(-104975/13123, -9566667)417418::419420sage: A.<x,y>=AffineSpace(ZZ,2)421sage: X=A.subscheme([x-y^2])422sage: H=Hom(X,X)423sage: f=H([9*y^2,3*y])424sage: f.nth_iterate(X(9,3),4)425(59049, 243)426427::428429sage: R.<t>=PolynomialRing(QQ)430sage: A.<x,y>=AffineSpace(FractionField(R),2)431sage: H=Hom(A,A)432sage: f=H([(x-t*y^2)/x,t*x*y])433sage: f.nth_iterate(A(1,t),3)434((-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)435436"""437return(P.nth_iterate(self,n))438439def orbit(self,P,n):440r"""441Returns the orbit of `P` by ``self``. If `n` is an integer it returns `[P,self(P),\ldots,self^n(P)]`.442443If `n` is a list or tuple `n=[m,k]` it returns `[self^m(P),\ldots,self^k(P)]`444445INPUT:446447- ``P`` -- a point in ``self.domain()``448- ``n`` -- a non-negative integer or list or tuple of two non-negative integers449450OUTPUT:451452- a list of points in ``self.codomain()``453454EXAMPLES::455456sage: A.<x,y>=AffineSpace(QQ,2)457sage: H=Hom(A,A)458sage: f=H([(x-2*y^2)/x,3*x*y])459sage: f.orbit(A(9,3),3)460[(9, 3), (-1, 81), (13123, -243), (-104975/13123, -9566667)]461462::463464sage: A.<x>=AffineSpace(QQ,1)465sage: H=Hom(A,A)466sage: f=H([(x-2)/x])467sage: f.orbit(A(1/2),[1,3])468[(-3), (5/3), (-1/5)]469470::471472sage: A.<x,y>=AffineSpace(ZZ,2)473sage: X=A.subscheme([x-y^2])474sage: H=Hom(X,X)475sage: f=H([9*y^2,3*y])476sage: f.orbit(X(9,3),(0,4))477[(9, 3), (81, 9), (729, 27), (6561, 81), (59049, 243)]478479::480481sage: R.<t>=PolynomialRing(QQ)482sage: A.<x,y>=AffineSpace(FractionField(R),2)483sage: H=Hom(A,A)484sage: f=H([(x-t*y^2)/x,t*x*y])485sage: f.orbit(A(1,t),3)486[(1, t), (-t^3 + 1, t^2), ((-t^5 - t^3 + 1)/(-t^3 + 1), -t^6 + t^3),487((-t^16 + 3*t^13 - 3*t^10 + t^7 + t^5 + t^3 - 1)/(t^5 + t^3 - 1), -t^9 -488t^7 + t^4)]489490"""491return(P.orbit(self,n))492493def global_height(self,prec=None):494r"""495Returns the maximum of the heights of the coefficients in any of the coordinate functions of ``self``.496497INPUT:498499- ``prec`` -- desired floating point precision (default:500default RealField precision).501502OUTPUT:503504- a real number505506EXAMPLES::507508sage: A.<x>=AffineSpace(QQ,1)509sage: H=Hom(A,A)510sage: f=H([1/1331*x^2+4000]);511sage: f.global_height()5128.29404964010203513514::515516sage: R.<x>=PolynomialRing(QQ)517sage: k.<w>=NumberField(x^2+5)518sage: A.<x,y>=AffineSpace(k,2)519sage: H=Hom(A,A)520sage: f=H([13*w*x^2+4*y, 1/w*y^2]);521sage: f.global_height(prec=100)5223.3696683136785869233538671082523524.. TODO::525526add heights to integer.pyx and remove special case527"""528if self.domain().base_ring() == ZZ:529if prec is None:530R = RealField()531else:532R = RealField(prec)533H=R(0)534for i in range(self.domain().ambient_space().dimension_relative()):535C=self[i].coefficients()536h=max([c.abs() for c in C])537H=max(H,R(h).log())538return(H)539H=0540for i in range(self.domain().ambient_space().dimension_relative()):541C=self[i].coefficients()542if C==[]: #to deal with the case self[i]=0543h=0544else:545h=max([c.global_height(prec) for c in C])546H=max(H,h)547return(H)548549class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space):550pass551552class SchemeMorphism_polynomial_affine_space_finite_field(SchemeMorphism_polynomial_affine_space_field):553554def cyclegraph(self):555r"""556returns Digraph of all orbits of self mod `p`. For subschemes, only points on the subscheme whose557image are also on the subscheme are in the digraph.558559OUTPUT:560561- a digraph562563EXAMPLES::564565sage: P.<x,y>=AffineSpace(GF(5),2)566sage: H=Hom(P,P)567sage: f=H([x^2-y,x*y+1])568sage: f.cyclegraph()569Looped digraph on 25 vertices570571::572573sage: P.<x>=AffineSpace(GF(3^3,'t'),1)574sage: H=Hom(P,P)575sage: f=H([x^2-1])576sage: f.cyclegraph()577Looped digraph on 27 vertices578579::580581sage: P.<x,y>=AffineSpace(GF(7),2)582sage: X=P.subscheme(x-y)583sage: H=Hom(X,X)584sage: f=H([x^2,y^2])585sage: f.cyclegraph()586Looped digraph on 7 vertices587"""588if self.domain() != self.codomain():589raise NotImplementedError("Domain and Codomain must be equal")590V=[]591E=[]592from sage.schemes.affine.affine_space import is_AffineSpace593if is_AffineSpace(self.domain())==True:594for P in self.domain():595V.append(str(P))596Q=self(P)597E.append([str(Q)])598else:599X=self.domain()600for P in X.ambient_space():601try:602XP=X.point(P)603V.append(str(XP))604Q=self(XP)605E.append([str(Q)])606except TypeError: # not on the scheme607pass608from sage.graphs.digraph import DiGraph609g=DiGraph(dict(zip(V,E)), loops=True)610return g611612613614615