def __init__(self, poly, ambient=None): """ Return the affine hypersurface in the space ambient defined by the polynomial poly. If ambient is not given, it will be constructed based on poly. EXAMPLES:: sage: A.<x, y, z> = AffineSpace(ZZ, 3) sage: AffineHypersurface(x*y-z^3, A) Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Integer Ring :: sage: A.<x, y, z> = QQ[] sage: AffineHypersurface(x*y-z^3) Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Rational Field TESTS:: sage: H = AffineHypersurface(x*y-z^3) sage: H == loads(dumps(H)) True """ if not is_MPolynomial(poly): raise TypeError, "Defining polynomial (= %s) must be a multivariate polynomial" % poly if ambient == None: R = poly.parent() from sage.schemes.affine.affine_space import AffineSpace ambient = AffineSpace(R.base_ring(), R.ngens()) ambient._coordinate_ring = R AlgebraicScheme_subscheme_affine.__init__(self, ambient, [poly])
def __init__(self, poly, ambient=None): """ Return the affine hypersurface in the space ambient defined by the polynomial poly. If ambient is not given, it will be constructed based on poly. EXAMPLES:: sage: A.<x, y, z> = AffineSpace(ZZ, 3) sage: AffineHypersurface(x*y-z^3, A) Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Integer Ring :: sage: A.<x, y, z> = QQ[] sage: AffineHypersurface(x*y-z^3) Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Rational Field TESTS:: sage: H = AffineHypersurface(x*y-z^3) sage: H == loads(dumps(H)) True """ if not is_MPolynomial(poly): raise TypeError, "Defining polynomial (= %s) must be a multivariate polynomial"%poly if ambient == None: R = poly.parent() from sage.schemes.affine.affine_space import AffineSpace ambient = AffineSpace(R.base_ring(), R.ngens()) ambient._coordinate_ring = R AlgebraicScheme_subscheme_affine.__init__(self, ambient, [poly])
def affine_patch(self, i): r""" Return the `i^{th}` affine patch of this projective space. This is an ambient affine space `\mathbb{A}^n_R,` where `R` is the base ring of self, whose "projective embedding" map is `1` in the `i^{th}` factor. INPUT: - ``i`` -- integer between 0 and dimension of self, inclusive. OUTPUT: - An ambient affine space with fixed projective_embedding map. EXAMPLES:: sage: PP = ProjectiveSpace(5) / QQ sage: AA = PP.affine_patch(2) sage: AA Affine Space of dimension 5 over Rational Field sage: AA.projective_embedding() Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (x0 : x1 : 1 : x2 : x3 : x4) sage: AA.projective_embedding(0) Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (1 : x0 : x1 : x2 : x3 : x4) """ i = int(i) # implicit type checking n = self.dimension_relative() if i < 0 or i > n: raise ValueError("Argument i (= %s) must be between 0 and %s." % (i, n)) try: return self.__affine_patches[i] except AttributeError: self.__affine_patches = {} except KeyError: pass from sage.schemes.affine.affine_space import AffineSpace AA = AffineSpace(n, self.base_ring(), names='x') AA._default_embedding_index = i phi = AA.projective_embedding(i, self) self.__affine_patches[i] = AA return AA
def affine_patch(self, i): r""" Return the `i^{th}` affine patch of this projective space. This is an ambient affine space `\mathbb{A}^n_R,` where `R` is the base ring of self, whose "projective embedding" map is `1` in the `i^{th}` factor. INPUT: - ``i`` -- integer between 0 and dimension of self, inclusive. OUTPUT: - An ambient affine space with fixed projective_embedding map. EXAMPLES:: sage: PP = ProjectiveSpace(5) / QQ sage: AA = PP.affine_patch(2) sage: AA Affine Space of dimension 5 over Rational Field sage: AA.projective_embedding() Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (x0 : x1 : 1 : x2 : x3 : x4) sage: AA.projective_embedding(0) Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (1 : x0 : x1 : x2 : x3 : x4) """ i = int(i) # implicit type checking n = self.dimension_relative() if i < 0 or i > n: raise ValueError("Argument i (= %s) must be between 0 and %s."%(i, n)) try: return self.__affine_patches[i] except AttributeError: self.__affine_patches = {} except KeyError: pass from sage.schemes.affine.affine_space import AffineSpace AA = AffineSpace(n, self.base_ring(), names='x') AA._default_embedding_index = i phi = AA.projective_embedding(i, self) self.__affine_patches[i] = AA return AA
def affine_algebraic_patch(self, cone=None, names=None): r""" Return the affine patch corresponding to ``cone`` as an affine algebraic scheme. INPUT: - ``cone`` -- a :class:`Cone <sage.geometry.cone.ConvexRationalPolyhedralCone>` `\sigma` of the fan. It can be omitted for an affine toric variety, in which case the single generating cone is used. OUTPUT: An :class:`affine algebraic subscheme <sage.schemes.affine.affine_subscheme.AlgebraicScheme_subscheme_affine>` corresponding to the patch `\mathop{Spec}(\sigma^\vee \cap M)` associated to the cone `\sigma`. See also :meth:`affine_patch`, which expresses the patches as subvarieties of affine toric varieties instead. REFERENCES: .. David A. Cox, "The Homogeneous Coordinate Ring of a Toric Variety", Lemma 2.2. :arxiv:`alg-geom/9210008v2` EXAMPLES:: sage: P2.<x,y,z> = toric_varieties.P2() sage: cone = P2.fan().generating_cone(0) sage: V = P2.subscheme(x^3+y^3+z^3) sage: V.affine_algebraic_patch(cone) Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: z0^3 + z1^3 + 1 sage: cone = Cone([(0,1),(2,1)]) sage: A2Z2.<x,y> = AffineToricVariety(cone) sage: A2Z2.affine_algebraic_patch() Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2 sage: V = A2Z2.subscheme(x^2+y^2-1) sage: patch = V.affine_algebraic_patch(); patch Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2, z0 + z1 - 1 sage: nbhd_patch = V.neighborhood([1,0]).affine_algebraic_patch(); nbhd_patch Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2, z0 + z1 - 1 sage: nbhd_patch.embedding_center() (0, 1, 0) Here we got two defining equations. The first one describes the singularity of the ambient space and the second is the pull-back of `x^2+y^2-1` :: sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)], ....: lattice=ToricLattice(3)) sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp) sage: Y = X.subscheme(x*v+y*u+t) sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)]) sage: Y.affine_algebraic_patch(cone) Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: z0*z2 - z1*z3, z1 + z3 + 1 """ from sage.modules.free_module_element import vector from sage.misc.misc_c import prod ambient = self.ambient_space() fan = ambient.fan() if cone is None: assert ambient.is_affine() cone = fan.generating_cone(0) else: cone = fan.embed(cone) # R/I = C[sigma^dual cap M] R, I, dualcone = ambient._semigroup_ring(cone, names) # inhomogenize the Cox homogeneous polynomial with respect to the given cone inhomogenize = dict((ambient.coordinate_ring().gen(i), 1) for i in range(0, fan.nrays()) if i not in cone.ambient_ray_indices()) polynomials = [ p.subs(inhomogenize) for p in self.defining_polynomials() ] # map the monomial x^{D_m} to m, see reference. n_rho_matrix = cone.rays().matrix() def pullback_polynomial(p): result = R.zero() for coefficient, monomial in p: exponent = monomial.exponents()[0] exponent = [exponent[i] for i in cone.ambient_ray_indices()] exponent = vector(ZZ, exponent) m = n_rho_matrix.solve_right(exponent) assert all(x in ZZ for x in m), \ 'The polynomial '+str(p)+' does not define a ZZ-divisor!' m_coeffs = dualcone.Hilbert_coefficients(m) result += coefficient * prod( R.gen(i)**m_coeffs[i] for i in range(0, R.ngens())) return result # construct the affine algebraic scheme to use as patch polynomials = [pullback_polynomial(_) for _ in polynomials] from sage.schemes.affine.affine_space import AffineSpace patch_cover = AffineSpace(R) polynomials = list(I.gens()) + polynomials polynomials = [x for x in polynomials if not x.is_zero()] patch = patch_cover.subscheme(polynomials) # TODO: If the cone is not smooth, then the coordinate_ring() # of the affine toric variety is wrong; it should be the # G-invariant part. So we can't construct the embedding # morphism in that case. if cone.is_smooth(): x = ambient.coordinate_ring().gens() phi = [] for i in range(0, fan.nrays()): if i in cone.ambient_ray_indices(): phi.append(pullback_polynomial(x[i])) else: phi.append(1) patch._embedding_morphism = patch.hom(phi, self) else: patch._embedding_morphism = ( NotImplementedError, 'I only know how to construct embedding morphisms for smooth patches' ) try: point = self.embedding_center() except AttributeError: return patch # it remains to find the preimage of point # map m to the monomial x^{D_m}, see reference. F = ambient.coordinate_ring().fraction_field() image = [] for m in dualcone.Hilbert_basis(): x_Dm = prod([F.gen(i)**(m * n) for i, n in enumerate(fan.rays())]) image.append(x_Dm) patch._embedding_center = tuple(f(list(point)) for f in image) return patch
def affine_patch(self, I, return_embedding=False): r""" Return the `I^{th}` affine patch of this projective space product where ``I`` is a multi-index. INPUT: - ``I`` -- a list or tuple of positive integers. - ``return_embedding`` -- Boolean, if true the projective embedding is also returned. OUTPUT: - An affine space. - An embedding into a product of projective spaces (optional). EXAMPLES:: sage: PP = ProductProjectiveSpaces([2, 2, 2], ZZ, 'x') sage: phi = PP.affine_patch([0, 1, 2], True) sage: phi.domain() Affine Space of dimension 6 over Integer Ring sage: phi Scheme morphism: From: Affine Space of dimension 6 over Integer Ring To: Product of projective spaces P^2 x P^2 x P^2 over Integer Ring Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4, x5) to (1 : x0 : x1 , x2 : 1 : x3 , x4 : x5 : 1) """ if not isinstance(I, (list, tuple)): raise TypeError( 'the argument I=%s must be a list or tuple of positive integers' % I) PP = self.ambient_space() N = PP._dims if len(I) != len(N): raise ValueError('the argument I=%s must have %s entries' % (I, len(N))) I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: raise ValueError( "argument i (= %s) must be between 0 and %s." % (I[i], N[i])) try: if return_embedding: return self.__affine_patches[I][1] else: return self.__affine_patches[I][0] except AttributeError: self.__affine_patches = {} except KeyError: pass from sage.schemes.affine.affine_space import AffineSpace AA = AffineSpace(PP.base_ring(), sum(N), 'x') v = list(AA.gens()) index = 0 for i in range(len(I)): v.insert(index + I[i], 1) index += N[i] + 1 phi = AA.hom(v, self) self.__affine_patches.update({I: (AA, phi)}) if return_embedding: return phi else: return AA
def affine_patch(self, i, AA=None): r""" Return the `i^{th}` affine patch of this projective space. This is an ambient affine space `\mathbb{A}^n_R,` where `R` is the base ring of self, whose "projective embedding" map is `1` in the `i^{th}` factor. INPUT: - ``i`` -- integer between 0 and dimension of self, inclusive. - ``AA`` -- (default: None) ambient affine space, this is constructed if it is not given. OUTPUT: - An ambient affine space with fixed projective_embedding map. EXAMPLES:: sage: PP = ProjectiveSpace(5) / QQ sage: AA = PP.affine_patch(2) sage: AA Affine Space of dimension 5 over Rational Field sage: AA.projective_embedding() Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (x0 : x1 : 1 : x2 : x3 : x4) sage: AA.projective_embedding(0) Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (1 : x0 : x1 : x2 : x3 : x4) :: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P.affine_patch(0).projective_embedding(0).codomain() == P True """ i = int(i) # implicit type checking n = self.dimension_relative() if i < 0 or i > n: raise ValueError("Argument i (= %s) must be between 0 and %s." % (i, n)) try: A = self.__affine_patches[i] #assume that if you've passed in a new affine space you want to override #the existing patch if AA is None or A == AA: return (A) except AttributeError: self.__affine_patches = {} except KeyError: pass #if no ith patch exists, we may still be here with AA==None if AA == None: from sage.schemes.affine.affine_space import AffineSpace AA = AffineSpace(n, self.base_ring(), names='x') elif AA.dimension_relative() != n: raise ValueError("Affine Space must be of the dimension %s" % (n)) AA._default_embedding_index = i phi = AA.projective_embedding(i, self) self.__affine_patches[i] = AA return AA
def affine_patch(self, I, return_embedding = False): r""" Return the `I^{th}` affine patch of this projective space product where ``I`` is a multi-index. INPUT: - ``I`` -- a list or tuple of positive integers - ``return_embedding`` -- Boolean, if true the projective embedding is also returned OUTPUT: - An affine space - An embedding into a product of projective spaces (optional) EXAMPLES:: sage: PP = ProductProjectiveSpaces([2,2,2], ZZ, 'x') sage: phi = PP.affine_patch([0,1,2], True) sage: phi.domain() Affine Space of dimension 6 over Integer Ring sage: phi Scheme morphism: From: Affine Space of dimension 6 over Integer Ring To: Product of projective spaces P^2 x P^2 x P^2 over Integer Ring Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4, x5) to (1 : x0 : x1 , x2 : 1 : x3 , x4 : x5 : 1) """ if not isinstance(I, (list, tuple)): raise TypeError('The argument I=%s must be a list or tuple of positive integers'%I) PP = self.ambient_space() N = PP._dims if len(I) != len(N): raise ValueError('The argument I=%s must have %s entries'%(I,len(N))) I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: raise ValueError("Argument i (= %s) must be between 0 and %s."%(I[i], N[i])) try: if return_embedding: return self.__affine_patches[I][1] else: return self.__affine_patches[I][0] except AttributeError: self.__affine_patches = {} except KeyError: pass from sage.schemes.affine.affine_space import AffineSpace AA = AffineSpace(PP.base_ring(),sum(N),'x') v = list(AA.gens()) index = 0 for i in range(len(I)): v.insert(index+I[i],1) index += N[i]+1 phi = AA.hom(v,self) self.__affine_patches.update({I:(AA,phi)}) if return_embedding: return phi else: return AA
def CyclicCover(r, f, names=None, check_smooth=True): r""" Return the cyclic cover of the projective line given by `y^r = f`, for a univariate polynomial `f`. INPUT: - ``r`` - the order of the cover - ``f`` - univariate polynomial if not given, then it defaults to 0. - ``names`` (default: ``["x","y"]``) - names for the coordinate functions - ``check_squarefree`` (default: ``True``) - test if the input defines a unramified cover of the projective line. .. WARNING:: When setting ``check_smooth=False`` or using a base ring that is not a field, the output curves are not to be trusted. For example, the output of ``is_singular`` or ``is_smooth`` only tests smoothness over the field of fractions. .. NOTE:: The words "cyclic cover" are usually used for covers of degree greater than two. We usually refer to smooth double covers of the projective line as "hyperelliptic curves" or "elliptic curves" if the genus is one. We allow such cases in this implementation, but we highly recommend to use the more specific constructors/classes HyperellipticCurve and EllipticCurve for a wider range of tools. EXAMPLES: Basic examples:: sage: R.<x> = QQ[] sage: CyclicCover(2, x^5 + x + 1) Cyclic Cover of P^1 over Rational Field defined by y^2 = x^5 + x + 1 sage: CyclicCover(3, x^5 + x + 1) Cyclic Cover of P^1 over Rational Field defined by y^3 = x^5 + x + 1 sage: CyclicCover(5, x^5 + x + 1) Cyclic Cover of P^1 over Rational Field defined by y^5 = x^5 + x + 1 sage: CyclicCover(15, x^9 + x + 1) Cyclic Cover of P^1 over Rational Field defined by y^15 = x^9 + x + 1 sage: k.<a> = GF(9); R.<x> = k[] sage: CyclicCover(5, x^9 + x + 1) Cyclic Cover of P^1 over Finite Field in a of size 3^2 defined by y^5 = x^9 + x + 1 sage: CyclicCover(15, x^9 + x + 1) Traceback (most recent call last): ... ValueError: As the characteristic divides the order of the cover, this model is not smooth. We can change the names of the variables in the output:: sage: k.<a> = GF(9); R.<x> = k[] sage: CyclicCover(5, x^9 + x + 1, names = ["A","B"]) Cyclic Cover of P^1 over Finite Field in a of size 3^2 defined by B^5 = A^9 + A + 1 Double roots:: sage: P.<x> = GF(7)[] sage: CyclicCover(2,(x^3-x+2)^2*(x^6-1)) Traceback (most recent call last): ... ValueError: Not a smooth Cyclic Cover of P^1: singularity in the provided affine patch. sage: CyclicCover(2, (x^3-x+2)^2*(x^6-1), check_smooth=False) Cyclic Cover of P^1 over Finite Field of size 7 defined by y^2 = x^12 - 2*x^10 - 3*x^9 + x^8 + 3*x^7 + 3*x^6 + 2*x^4 + 3*x^3 - x^2 - 3*x + 3 Input with integer coefficients creates objects with the integers as base ring, but only checks smoothness over `\QQ`, not over Spec(`\ZZ`). In other words, it is checked that the discriminant is non-zero, but it is not checked whether the discriminant is a unit in `\ZZ^*`.:: sage: R.<x> = ZZ[] sage: CyclicCover(5,(x^3-x+2)*(x^6-1)) Cyclic Cover of P^1 over Integer Ring defined by y^5 = x^9 - x^7 + 2*x^6 - x^3 + x - 2 """ if not is_Polynomial(f): raise TypeError("Arguments f (= %s) must be a polynomial" % (f,)) P = f.parent() f = P(f) if check_smooth: if P(r) == 0: raise ValueError( "As the characteristic divides the order of the cover, " "this model is not smooth." ) try: smooth = f.is_squarefree() except NotImplementedError as err: raise NotImplementedError( str(err) + "Use " "check_smooth=False to skip this check." ) if not smooth: raise ValueError( "Not a smooth Cyclic Cover of P^1: " "singularity in the provided affine patch." ) R = P.base_ring() if names is None: names = ["x", "y"] A2 = AffineSpace(2, R, names=names) if is_FiniteField(R): return CyclicCover_finite_field(A2, r, f, names=names) else: return CyclicCover_generic(A2, r, f, names=names)
def affine_minimal(vp, return_transformation=False, D=None, quick=False): r""" Determine if given map is affine minimal. Given vp a scheme morphism on the projective line over the rationals, this procedure determines if `\phi` is minimal. In particular, it determines if the map is affine minimal, which is enough to decide if it is minimal or not. See Proposition 2.10 in [Bruin-Molnar]_. INPUT: - ``vp`` -- dynamical system on the projective line - ``D`` -- a list of primes, in case one only wants to check minimality at those specific primes - ``return_transformation`` -- (default: ``False``) boolean; this signals a return of the `PGL_2` transformation to conjugate this map to the calculated models - ``quick`` -- a boolean value. If true the algorithm terminates once algorithm determines F/G is not minimal, otherwise algorithm only terminates once a minimal model has been found OUTPUT: - ``newvp`` -- dynamical system on the projective line - ``conj`` -- linear fractional transformation which conjugates ``vp`` to ``newvp`` EXAMPLES:: sage: PS.<X,Y> = ProjectiveSpace(QQ, 1) sage: vp = DynamicalSystem_projective([X^2 + 9*Y^2, X*Y]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import affine_minimal sage: affine_minimal(vp, True) ( Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (X : Y) to (X^2 + Y^2 : X*Y) , [3 0] [0 1] ) """ from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine BR = vp.domain().base_ring() conj = matrix(BR, 2, 2, 1) flag = True vp.normalize_coordinates() d = vp.degree() Affvp = vp.dehomogenize(1) R = Affvp.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(Affvp[0].numerator()) G = R(Affvp[0].denominator()) if R(G.degree()) == 0 or R(F.degree()) == 0: raise TypeError( "affine minimality is only considered for maps not of the form f or 1/f for a polynomial f" ) z = F.parent().gen(0) minF, minG = F, G #If the valuation of a prime in the resultant is small enough, we can say the #map is affine minimal at that prime without using the local minimality loop. See #Theorem 3.2.2 in [Molnar, M.Sc. thesis] if d % 2 == 0: g = d else: g = 2 * d Res = vp.resultant() #Some quantities needed for the local minimization loop, but we compute now #since the value is constant, so we do not wish to compute in every local loop. #See Theorem 3.3.3 in [Molnar, M.Sc thesis] H = F - z * minG d1 = F.degree() A = AffineSpace(BR, 1, H.parent().variable_name()) ubRes = DynamicalSystem_affine([H / minG], domain=A).homogenize(1).resultant() #Set the primes to check minimality at, if not already prescribed if D is None: D = ZZ(Res).prime_divisors() #Check minimality at all primes in D. If D is all primes dividing #Res(minF/minG), this is enough to show whether minF/minG is minimal or not. See #Propositions 3.2.1 and 3.3.7 in [Molnar, M.Sc. thesis]. for p in D: while True: if Res.valuation(p) < g: #The model is minimal at p min = True else: #The model may not be minimal at p. newvp, conj = Min(vp, p, ubRes, conj, all_orbits=False) if newvp == vp: min = True else: vp = newvp Affvp = vp.dehomogenize(1) min = False if min: #The model is minimal at p break elif F == Affvp[0].numerator() and G == Affvp[0].denominator(): #The model is minimal at p break else: #The model is not minimal at p flag = False if quick: break if quick and not flag: break if quick: #only return whether the model is minimal return flag if return_transformation: return vp, conj return vp
def __classcall_private__(cls, morphism_or_polys, domain=None): r""" Return the appropriate dynamical system on an affine scheme. TESTS:: sage: A.<x> = AffineSpace(ZZ,1) sage: A1.<z> = AffineSpace(CC,1) sage: H = End(A1) sage: f2 = H([z^2+1]) sage: f = DynamicalSystem_affine(f2, A) sage: f.domain() is A False :: sage: P1.<x,y> = ProjectiveSpace(QQ,1) sage: DynamicalSystem_affine([y, 2*x], domain=P1) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme sage: H = End(P1) sage: DynamicalSystem_affine(H([y, 2*x])) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme """ if isinstance(morphism_or_polys, SchemeMorphism_polynomial): morphism = morphism_or_polys R = morphism.base_ring() polys = list(morphism) domain = morphism.domain() if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if domain != morphism_or_polys.codomain(): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys,(list, tuple)): polys = list(morphism_or_polys) else: polys = [morphism_or_polys] # We now arrange for all of our list entries to lie in the same ring # Fraction field case first fraction_field = False for poly in polys: P = poly.parent() if is_FractionField(P): fraction_field = True break if fraction_field: K = P.base_ring().fraction_field() # Replace base ring with its fraction field P = P.ring().change_ring(K).fraction_field() polys = [P(poly) for poly in polys] else: # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. quotient_ring = False for poly in polys: P = poly.parent() if is_QuotientRing(P): quotient_ring = True break if quotient_ring: polys = [P(poly).lift() for poly in polys] else: poly_ring = False for poly in polys: P = poly.parent() if is_PolynomialRing(P) or is_MPolynomialRing(P): poly_ring = True break if poly_ring: polys = [P(poly) for poly in polys] if domain is None: f = polys[0] CR = f.parent() if CR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: CR = CR.ring() domain = AffineSpace(CR) R = domain.base_ring() if R is SR: raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain)
def __classcall_private__(cls, morphism_or_polys, domain=None): r""" Return the appropriate dynamical system on an affine scheme. TESTS:: sage: A.<x> = AffineSpace(ZZ,1) sage: A1.<z> = AffineSpace(CC,1) sage: H = End(A1) sage: f2 = H([z^2+1]) sage: f = DynamicalSystem_affine(f2, A) sage: f.domain() is A False :: sage: P1.<x,y> = ProjectiveSpace(QQ,1) sage: DynamicalSystem_affine([y, 2*x], domain=P1) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme sage: H = End(P1) sage: DynamicalSystem_affine(H([y, 2*x])) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme """ if isinstance(morphism_or_polys, SchemeMorphism_polynomial): morphism = morphism_or_polys R = morphism.base_ring() polys = list(morphism) domain = morphism.domain() if not is_AffineSpace(domain) and not isinstance( domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if domain != morphism_or_polys.codomain(): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys, (list, tuple)): polys = list(morphism_or_polys) else: polys = [morphism_or_polys] # We now arrange for all of our list entries to lie in the same ring # Fraction field case first fraction_field = False for poly in polys: P = poly.parent() if is_FractionField(P): fraction_field = True break if fraction_field: K = P.base_ring().fraction_field() # Replace base ring with its fraction field P = P.ring().change_ring(K).fraction_field() polys = [P(poly) for poly in polys] else: # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. quotient_ring = False for poly in polys: P = poly.parent() if is_QuotientRing(P): quotient_ring = True break if quotient_ring: polys = [P(poly).lift() for poly in polys] else: poly_ring = False for poly in polys: P = poly.parent() if is_PolynomialRing(P) or is_MPolynomialRing(P): poly_ring = True break if poly_ring: polys = [P(poly) for poly in polys] if domain is None: f = polys[0] CR = f.parent() if CR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: CR = CR.ring() domain = AffineSpace(CR) R = domain.base_ring() if R is SR: raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance( domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain)
def reduce_base_field(self): """ Return this map defined over the field of definition of the coefficients. The base field of the map could be strictly larger than the field where all of the coefficients are defined. This function reduces the base field to the minimal possible. This can be done when the base ring is a number field, QQbar, a finite field, or algebraic closure of a finite field. OUTPUT: A scheme morphism. EXAMPLES:: sage: K.<t> = GF(5^4) sage: A.<x> = AffineSpace(K, 1) sage: A2.<a,b> = AffineSpace(K, 2) sage: H = End(A) sage: H2 = Hom(A,A2) sage: H3 = Hom(A2,A) sage: f = H([x^2 + 2*(t^3 + t^2 + t + 3)]) sage: f.reduce_base_field() Scheme endomorphism of Affine Space of dimension 1 over Finite Field in t2 of size 5^2 Defn: Defined on coordinates by sending (x) to (x^2 + (2*t2)) sage: f2 = H2([x^2 + 4, 2*x]) sage: f2.reduce_base_field() Scheme morphism: From: Affine Space of dimension 1 over Finite Field of size 5 To: Affine Space of dimension 2 over Finite Field of size 5 Defn: Defined on coordinates by sending (x) to (x^2 - 1, 2*x) sage: f3 = H3([a^2 + t*b]) sage: f3.reduce_base_field() Scheme morphism: From: Affine Space of dimension 2 over Finite Field in t of size 5^4 To: Affine Space of dimension 1 over Finite Field in t of size 5^4 Defn: Defined on coordinates by sending (a, b) to (a^2 + (t)*b) :: sage: K.<v> = CyclotomicField(4) sage: A.<x> = AffineSpace(K, 1) sage: H = End(A) sage: f = H([x^2 + v]) sage: g = f.reduce_base_field();g Scheme endomorphism of Affine Space of dimension 1 over Cyclotomic Field of order 4 and degree 2 Defn: Defined on coordinates by sending (x) to (x^2 + (v)) sage: g.base_ring() is K True :: sage: A.<x> = AffineSpace(QQbar, 1) sage: H = End(A) sage: f = H([(QQbar(sqrt(2))*x^2 + 1/QQbar(sqrt(3))) / (5*x)]) sage: f.reduce_base_field() Scheme endomorphism of Affine Space of dimension 1 over Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a = 1.931851652578137? Defn: Defined on coordinates by sending (x) to (((a^3 - 3*a)*x^2 + (1/3*a^2 - 2/3))/(5*x)) :: sage: R.<x> = PolynomialRing(QQ) sage: A.<x> =AffineSpace(QQbar,1) sage: H = End(A) sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))]) sage: f.reduce_base_field() Scheme endomorphism of Affine Space of dimension 1 over Number Field in a with defining polynomial y^6 + 6*y^4 - 6*y^3 + 12*y^2 + 36*y + 17 with a = 1.442249570307409? + 1.414213562373095?*I Defn: Defined on coordinates by sending (x) to ((-48/269*a^5 + 27/269*a^4 - 320/269*a^3 + 468/269*a^2 - 772/269*a - 1092/269)*x^2 + (48/269*a^5 - 27/269*a^4 + 320/269*a^3 - 468/269*a^2 + 1041/269*a + 1092/269)) :: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3-x+1, embedding=(x^3+x+1).roots(ring=CC)[0][0]) sage: A.<x> = AffineSpace(K,1) sage: A2.<u,v> = AffineSpace(K,2) sage: H = Hom(A, A2) sage: f = H([x^2 + a*x + 3, 5*x]) sage: f.reduce_base_field() Scheme morphism: From: Affine Space of dimension 1 over Number Field in a with defining polynomial x^3 - x + 1 with a = -1.324717957244746? To: Affine Space of dimension 2 over Number Field in a with defining polynomial x^3 - x + 1 with a = -1.324717957244746? Defn: Defined on coordinates by sending (x) to (x^2 + (a)*x + 3, 5*x) :: sage: K.<v> = QuadraticField(2) sage: A.<x> =AffineSpace(K,1) sage: H = End(A) sage: f = H([3*x^2 + x + 1]) sage: f.reduce_base_field() Scheme endomorphism of Affine Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x) to (3*x^2 + x + 1) :: sage: K.<t> = GF(5^6) sage: A.<x> = AffineSpace(K, 1) sage: H = End(A) sage: f = H([x^2 + x*(t^3 + 2*t^2 + 4*t) + (t^5 + 3*t^4 + t^2 + 4*t)]) sage: f.reduce_base_field() Scheme endomorphism of Affine Space of dimension 1 over Finite Field in t of size 5^6 Defn: Defined on coordinates by sending (x) to (x^2 + (t^3 + 2*t^2 - t)*x + (t^5 - 2*t^4 + t^2 - t)) """ g = self.homogenize(0).reduce_base_field().dehomogenize(0) from sage.schemes.affine.affine_space import AffineSpace new_domain = AffineSpace(g.domain().base_ring(), self.domain().dimension_relative(), self.domain().variable_names()) new_codomain = AffineSpace(g.codomain().base_ring(), self.codomain().dimension_relative(), self.codomain().variable_names()) R = new_domain.coordinate_ring() H = Hom(new_domain, new_codomain) if isinstance(g[0], FractionFieldElement): return H([R(G.numerator()) / R(G.denominator()) for G in g]) return H([R(G) for G in g])
def __classcall_private__(cls, morphism_or_polys, domain=None): r""" Return the appropriate dynamical system on an affine scheme. TESTS:: sage: A.<x> = AffineSpace(ZZ,1) sage: A1.<z> = AffineSpace(CC,1) sage: H = End(A1) sage: f2 = H([z^2+1]) sage: f = DynamicalSystem_affine(f2, A) sage: f.domain() is A False :: sage: P1.<x,y> = ProjectiveSpace(QQ,1) sage: DynamicalSystem_affine([y, 2*x], domain=P1) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme sage: H = End(P1) sage: DynamicalSystem_affine(H([y, 2*x])) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme :: sage: R.<x,y,z> = QQ[] sage: f = DynamicalSystem_affine([x+y+z, y*z]) Traceback (most recent call last): ... ValueError: Number of polys does not match dimension of Affine Space of dimension 3 over Rational Field :: sage: A.<x,y> = AffineSpace(QQ,2) sage: f = DynamicalSystem_affine([CC.0*x^2, y^2], domain=A) Traceback (most recent call last): ... TypeError: coefficients of polynomial not in Rational Field """ if isinstance(morphism_or_polys, SchemeMorphism_polynomial): morphism = morphism_or_polys R = morphism.base_ring() polys = list(morphism) domain = morphism.domain() if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if domain != morphism_or_polys.codomain(): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys,(list, tuple)): polys = list(morphism_or_polys) else: polys = [morphism_or_polys] PR = get_coercion_model().common_parent(*polys) fraction_field = any(is_FractionField(poly.parent()) for poly in polys) if fraction_field: K = PR.base_ring().fraction_field() # Replace base ring with its fraction field PR = PR.ring().change_ring(K).fraction_field() polys = [PR(poly) for poly in polys] else: quotient_ring = any(is_QuotientRing(poly.parent()) for poly in polys) # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. if quotient_ring: polys = [PR(poly).lift() for poly in polys] else: polys = [PR(poly) for poly in polys] if domain is None: if PR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: PR = PR.ring() domain = AffineSpace(PR) else: # Check if we can coerce the given polynomials over the given domain PR = domain.ambient_space().coordinate_ring() try: if fraction_field: PR = PR.fraction_field() polys = [PR(poly) for poly in polys] except TypeError: raise TypeError('coefficients of polynomial not in {}'.format(domain.base_ring())) if len(polys) != domain.ambient_space().coordinate_ring().ngens(): raise ValueError('Number of polys does not match dimension of {}'.format(domain)) R = domain.base_ring() if R is SR: raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain)
def __classcall_private__(cls, morphism_or_polys, domain=None): r""" Return the appropriate dynamical system on an affine scheme. TESTS:: sage: A.<x> = AffineSpace(ZZ,1) sage: A1.<z> = AffineSpace(CC,1) sage: H = End(A1) sage: f2 = H([z^2+1]) sage: f = DynamicalSystem_affine(f2, A) sage: f.domain() is A False :: sage: P1.<x,y> = ProjectiveSpace(QQ,1) sage: DynamicalSystem_affine([y, 2*x], domain=P1) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme sage: H = End(P1) sage: DynamicalSystem_affine(H([y, 2*x])) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme :: sage: R.<x,y,z> = QQ[] sage: f = DynamicalSystem_affine([x+y+z, y*z]) Traceback (most recent call last): ... ValueError: Number of polys does not match dimension of Affine Space of dimension 3 over Rational Field :: sage: A.<x,y> = AffineSpace(QQ,2) sage: f = DynamicalSystem_affine([CC.0*x^2, y^2], domain=A) Traceback (most recent call last): ... TypeError: coefficients of polynomial not in Rational Field """ if isinstance(morphism_or_polys, SchemeMorphism_polynomial): morphism = morphism_or_polys R = morphism.base_ring() polys = list(morphism) domain = morphism.domain() if not is_AffineSpace(domain) and not isinstance( domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if domain != morphism_or_polys.codomain(): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys, (list, tuple)): polys = list(morphism_or_polys) else: polys = [morphism_or_polys] PR = get_coercion_model().common_parent(*polys) fraction_field = any(is_FractionField(poly.parent()) for poly in polys) if fraction_field: K = PR.base_ring().fraction_field() # Replace base ring with its fraction field PR = PR.ring().change_ring(K).fraction_field() polys = [PR(poly) for poly in polys] else: quotient_ring = any( is_QuotientRing(poly.parent()) for poly in polys) # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. if quotient_ring: polys = [PR(poly).lift() for poly in polys] else: polys = [PR(poly) for poly in polys] if domain is None: if PR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: PR = PR.ring() domain = AffineSpace(PR) else: # Check if we can coerce the given polynomials over the given domain PR = domain.ambient_space().coordinate_ring() try: if fraction_field: PR = PR.fraction_field() polys = [PR(poly) for poly in polys] except TypeError: raise TypeError('coefficients of polynomial not in {}'.format( domain.base_ring())) if len(polys) != domain.ambient_space().coordinate_ring().ngens(): raise ValueError( 'Number of polys does not match dimension of {}'.format( domain)) R = domain.base_ring() if R is SR: raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance( domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain)
def affine_patch(self, I, return_embedding=False): r""" Return the `I^{th}` affine patch of this projective scheme where 'I' is a multi-index. INPUT: - ``I`` -- a list or tuple of positive integers - ``return_embedding`` -- Boolean, if true the projective embedding is also returned OUTPUT: - An affine algebraic scheme - An embedding into a product of projective space (optional) EXAMPLES:: sage: PP.<x,y,z,w,u,v> = ProductProjectiveSpaces([3,1],QQ) sage: W = PP.subscheme([y^2*z-x^3,z^2-w^2,u^3-v^3]) sage: W.affine_patch([0,1],True) (Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: x0^2*x1 - 1, x1^2 - x2^2, x3^3 - 1, Scheme morphism: From: Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: x0^2*x1 - 1, x1^2 - x2^2, x3^3 - 1 To: Closed subscheme of Product of projective spaces P^3 x P^1 over Rational Field defined by: -x^3 + y^2*z, z^2 - w^2, u^3 - v^3 Defn: Defined on coordinates by sending (x0, x1, x2, x3) to (1 : x0 : x1 : x2 , x3 : 1)) """ if not isinstance(I, (list, tuple)): raise TypeError( 'The argument I=%s must be a list or tuple of positive integers' % I) PP = self.ambient_space() N = PP.dimension_relative_components() if len(I) != len(N): raise ValueError('The argument I=%s must have %s entries' % (I, len(N))) I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: raise ValueError( "Argument i (= %s) must be between 0 and %s." % (I[i], N[i])) #see if we've already created this affine patch try: if return_embedding: return self.__affine_patches[I] else: return self.__affine_patches[I][0] except AttributeError: self.__affine_patches = {} except KeyError: pass AA = AffineSpace(PP.base_ring(), sum(N), 'x') v = list(AA.gens()) # create the projective embedding index = 0 for i in range(len(I)): v.insert(index + I[i], 1) index += N[i] + 1 phi = AA.hom(v, self) #find the image of the subscheme polys = self.defining_polynomials() xi = phi.defining_polynomials() U = AA.subscheme([f(xi) for f in polys]) phi = U.hom(v, self) self.__affine_patches.update({I: (U, phi)}) if return_embedding: return U, phi else: return U
def affine_patch(self, i, AA = None): r""" Return the `i^{th}` affine patch of this projective space. This is an ambient affine space `\mathbb{A}^n_R,` where `R` is the base ring of self, whose "projective embedding" map is `1` in the `i^{th}` factor. INPUT: - ``i`` -- integer between 0 and dimension of self, inclusive. - ``AA`` -- (default: None) ambient affine space, this is constructed if it is not given. OUTPUT: - An ambient affine space with fixed projective_embedding map. EXAMPLES:: sage: PP = ProjectiveSpace(5) / QQ sage: AA = PP.affine_patch(2) sage: AA Affine Space of dimension 5 over Rational Field sage: AA.projective_embedding() Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (x0 : x1 : 1 : x2 : x3 : x4) sage: AA.projective_embedding(0) Scheme morphism: From: Affine Space of dimension 5 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4) to (1 : x0 : x1 : x2 : x3 : x4) :: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P.affine_patch(0).projective_embedding(0).codomain() == P True """ i = int(i) # implicit type checking n = self.dimension_relative() if i < 0 or i > n: raise ValueError("Argument i (= %s) must be between 0 and %s."%(i, n)) try: A = self.__affine_patches[i] #assume that if you've passed in a new affine space you want to override #the existing patch if AA is None or A == AA: return(A) except AttributeError: self.__affine_patches = {} except KeyError: pass #if no ith patch exists, we may still be here with AA==None if AA == None: from sage.schemes.affine.affine_space import AffineSpace AA = AffineSpace(n, self.base_ring(), names = 'x') elif AA.dimension_relative() != n: raise ValueError("Affine Space must be of the dimension %s"%(n)) AA._default_embedding_index = i phi = AA.projective_embedding(i, self) self.__affine_patches[i] = AA return AA
def BM_all_minimal(vp, return_transformation=False, D=None): r""" Determine a representative in each `SL(2,\ZZ)` orbit with minimal resultant. This function modifies the Bruin-Molnar algorithm ([BM2012]_) to solve in the inequalities as ``<=`` instead of ``<``. Among the list of solutions is all conjugations that preserve the resultant. From that list the `SL(2,\ZZ)` orbits are identified and one representative from each orbit is returned. This function assumes that the given model is a minimal model. INPUT: - ``vp`` -- a minimal model of a dynamical system on the projective line - ``return_transformation`` -- (default: ``False``) boolean; this signals a return of the ``PGL_2`` transformation to conjugate ``vp`` to the calculated minimal model - ``D`` -- a list of primes, in case one only wants to check minimality at those specific primes OUTPUT: List of pairs ``[f, m]`` where ``f`` is a dynamical system and ``m`` is a `2 \times 2` matrix. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem([x^3 - 13^2*y^3, x*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal sage: BM_all_minimal(f) [Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^3 - 169*y^3 : x*y^2), Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (13*x^3 - y^3 : x*y^2)] :: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem([x^3 - 6^2*y^3, x*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal sage: BM_all_minimal(f, D=[3]) [Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^3 - 36*y^3 : x*y^2), Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (3*x^3 - 4*y^3 : x*y^2)] :: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem([x^3 - 4^2*y^3, x*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal sage: cl = BM_all_minimal(f, return_transformation=True) sage: all(f.conjugate(m) == g for g, m in cl) True """ mp = copy(vp) mp.normalize_coordinates() BR = mp.domain().base_ring() MS = MatrixSpace(QQ, 2) M_Id = MS.one() d = mp.degree() F, G = list(mp) #coordinate polys aff_map = mp.dehomogenize(1) f, g = aff_map[0].numerator(), aff_map[0].denominator() z = aff_map.domain().gen(0) dg = f.parent()(g).degree() Res = mp.resultant() ##### because of how the bound is compute in lemma 3.3 from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine h = f - z * g A = AffineSpace(BR, 1, h.parent().variable_name()) res = DynamicalSystem_affine([h / g], domain=A).homogenize(1).resultant() if D is None: D = ZZ(Res).prime_divisors() # get the conjugations for each prime independently # these are returning (p,k,b) so that the matrix is [p^k,b,0,1] all_pM = [] for p in D: # all_orbits used to scale inequalities to equalities all_pM.append(Min(mp, p, res, M_Id, all_orbits=True)) # need the identity for each prime if [p, 0, 0] not in all_pM[-1]: all_pM[-1].append([p, 0, 0]) #combine conjugations for all primes all_M = [M_Id] for prime_data in all_pM: #these are (p,k,b) so that the matrix is [p^k,b,0,1] new_M = [] if prime_data: p = prime_data[0][0] for m in prime_data: mat = MS([m[0]**m[1], m[2], 0, 1]) new_map = mp.conjugate(mat) new_map.normalize_coordinates() # make sure the resultant didn't change and that it is a different SL(2,ZZ) orbit if (mat == M_Id) or (new_map.resultant().valuation(p) == Res.valuation(p) and mat.det() not in [1, -1]): new_M.append(m) if new_M: all_M = [ m1 * MS([m[0]**m[1], m[2], 0, 1]) for m1 in all_M for m in new_M ] #get all models with same resultant all_maps = [] for M in all_M: new_map = mp.conjugate(M) new_map.normalize_coordinates() if not [new_map, M] in all_maps: all_maps.append([new_map, M]) #Split into conjugacy classes #We just keep track of the two matrices that come from #the original to get the conjugation that goes between these!! classes = [] for funct, mat in all_maps: if not classes: classes.append([funct, mat]) else: found = False for Func, Mat in classes: #get conjugation M = mat.inverse() * Mat assert funct.conjugate(M) == Func if M.det() in [1, -1]: #same SL(2,Z) orbit found = True break if found is False: classes.append([funct, mat]) if return_transformation: return classes else: return [funct for funct, matr in classes]
def affine_algebraic_patch(self, cone=None, names=None): r""" Return the affine patch corresponding to ``cone`` as an affine algebraic scheme. INPUT: - ``cone`` -- a :class:`Cone <sage.geometry.cone.ConvexRationalPolyhedralCone>` `\sigma` of the fan. It can be omitted for an affine toric variety, in which case the single generating cone is used. OUTPUT: An :class:`affine algebraic subscheme <sage.schemes.affine.affine_subscheme.AlgebraicScheme_subscheme_affine>` corresponding to the patch `\mathop{Spec}(\sigma^\vee \cap M)` associated to the cone `\sigma`. See also :meth:`affine_patch`, which expresses the patches as subvarieties of affine toric varieties instead. REFERENCES: .. David A. Cox, "The Homogeneous Coordinate Ring of a Toric Variety", Lemma 2.2. :arxiv:`alg-geom/9210008v2` EXAMPLES:: sage: P2.<x,y,z> = toric_varieties.P2() sage: cone = P2.fan().generating_cone(0) sage: V = P2.subscheme(x^3+y^3+z^3) sage: V.affine_algebraic_patch(cone) Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: z0^3 + z1^3 + 1 sage: cone = Cone([(0,1),(2,1)]) sage: A2Z2.<x,y> = AffineToricVariety(cone) sage: A2Z2.affine_algebraic_patch() Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2 sage: V = A2Z2.subscheme(x^2+y^2-1) sage: patch = V.affine_algebraic_patch(); patch Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2, z0 + z1 - 1 sage: nbhd_patch = V.neighborhood([1,0]).affine_algebraic_patch(); nbhd_patch Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2, z0 + z1 - 1 sage: nbhd_patch.embedding_center() (0, 1, 0) Here we got two defining equations. The first one describes the singularity of the ambient space and the second is the pull-back of `x^2+y^2-1` :: sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)], ....: lattice=ToricLattice(3)) sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp) sage: Y = X.subscheme(x*v+y*u+t) sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)]) sage: Y.affine_algebraic_patch(cone) Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: z0*z2 - z1*z3, z1 + z3 + 1 """ from sage.modules.all import vector from sage.misc.all import prod ambient = self.ambient_space() fan = ambient.fan() if cone is None: assert ambient.is_affine() cone = fan.generating_cone(0) else: cone = fan.embed(cone) # R/I = C[sigma^dual cap M] R, I, dualcone = ambient._semigroup_ring(cone, names) # inhomogenize the Cox homogeneous polynomial with respect to the given cone inhomogenize = dict( (ambient.coordinate_ring().gen(i), 1) for i in range(0,fan.nrays()) if not i in cone.ambient_ray_indices() ) polynomials = [ p.subs(inhomogenize) for p in self.defining_polynomials() ] # map the monomial x^{D_m} to m, see reference. n_rho_matrix = cone.rays().matrix() def pullback_polynomial(p): result = R.zero() for coefficient, monomial in p: exponent = monomial.exponents()[0] exponent = [ exponent[i] for i in cone.ambient_ray_indices() ] exponent = vector(ZZ,exponent) m = n_rho_matrix.solve_right(exponent) assert all(x in ZZ for x in m), \ 'The polynomial '+str(p)+' does not define a ZZ-divisor!' m_coeffs = dualcone.Hilbert_coefficients(m) result += coefficient * prod(R.gen(i)**m_coeffs[i] for i in range(0,R.ngens())) return result # construct the affine algebraic scheme to use as patch polynomials = [pullback_polynomial(_) for _ in polynomials] from sage.schemes.affine.affine_space import AffineSpace patch_cover = AffineSpace(R) polynomials = list(I.gens()) + polynomials polynomials = [x for x in polynomials if not x.is_zero()] patch = patch_cover.subscheme(polynomials) # TODO: If the cone is not smooth, then the coordinate_ring() # of the affine toric variety is wrong; it should be the # G-invariant part. So we can't construct the embedding # morphism in that case. if cone.is_smooth(): x = ambient.coordinate_ring().gens() phi = [] for i in range(0,fan.nrays()): if i in cone.ambient_ray_indices(): phi.append(pullback_polynomial(x[i])) else: phi.append(1) patch._embedding_morphism = patch.hom(phi, self) else: patch._embedding_morphism = (NotImplementedError, 'I only know how to construct embedding morphisms for smooth patches') try: point = self.embedding_center() except AttributeError: return patch # it remains to find the preimage of point # map m to the monomial x^{D_m}, see reference. F = ambient.coordinate_ring().fraction_field() image = [] for m in dualcone.Hilbert_basis(): x_Dm = prod([ F.gen(i)**(m*n) for i,n in enumerate(fan.rays()) ]) image.append(x_Dm) patch._embedding_center = tuple( f(list(point)) for f in image ) return patch