@@ -333,7 +333,7 @@ def order(self, x, check=True):
333
333
raise NotImplementedError
334
334
return self .order_with_basis (basis , check = check )
335
335
336
- def _coerce_map_from_ (self , R ):
336
+ def _coerce_map_from_ (self , source ):
337
337
"""
338
338
Return True if there is a coerce map from R to self.
339
339
@@ -343,14 +343,77 @@ def _coerce_map_from_(self, R):
343
343
sage: L.equation_order()
344
344
Order in Function field in y defined by y^3 + x^3 + 4*x + 1
345
345
sage: L._coerce_map_from_(L.equation_order())
346
- True
346
+ Conversion map:
347
+ From: Order in Function field in y defined by y^3 + x^3 + 4*x + 1
348
+ To: Function field in y defined by y^3 + x^3 + 4*x + 1
347
349
sage: L._coerce_map_from_(GF(7))
348
- False
350
+
351
+ sage: K.<x> = FunctionField(QQ)
352
+ sage: L.<x> = FunctionField(GaussianIntegers().fraction_field())
353
+ sage: L.has_coerce_map_from(K)
354
+ True
355
+
356
+ sage: K.<x> = FunctionField(QQ)
357
+ sage: R.<y> = K[]
358
+ sage: L.<y> = K.extension(y^3 + 1)
359
+ sage: K.<x> = FunctionField(GaussianIntegers().fraction_field())
360
+ sage: R.<y> = K[]
361
+ sage: M.<y> = K.extension(y^3 + 1)
362
+ sage: M.has_coerce_map_from(L) # not tested (the constant field including into a function field is not yet known to be injective)
363
+ True
364
+
365
+ sage: K.<x> = FunctionField(QQ)
366
+ sage: R.<I> = K[]
367
+ sage: L.<I> = K.extension(I^2 + 1)
368
+ sage: M.<x> = FunctionField(GaussianIntegers().fraction_field())
369
+ sage: M.has_coerce_map_from(L)
370
+ True
349
371
"""
350
372
from .function_field_order import FunctionFieldOrder
351
- if isinstance (R , FunctionFieldOrder ) and R .fraction_field () == self :
352
- return True
353
- return False
373
+ if isinstance (source , FunctionFieldOrder ):
374
+ K = source .fraction_field ()
375
+ source_to_K = K ._generic_convert_map (source )
376
+ if K is self :
377
+ return source_to_K
378
+ K_to_self = self .coerce_map_from (K )
379
+ if K_to_self :
380
+ return K_to_self * source_to_K
381
+ from sage .categories .function_fields import FunctionFields
382
+ if source in FunctionFields ():
383
+ if source .base_field () is source :
384
+ if self .base_field () is self :
385
+ # source and self are rational function fields
386
+ if source .variable_name () == self .variable_name ():
387
+ # ... in the same variable
388
+ base_coercion = self .constant_field ().coerce_map_from (source .constant_field ())
389
+ if base_coercion is not None :
390
+ return source .hom ([self .gen ()], base_morphism = base_coercion )
391
+ else :
392
+ # source is an extensions of rational function fields
393
+ base_coercion = self .coerce_map_from (source .base_field ())
394
+ if base_coercion is not None and base_coercion .is_injective ():
395
+ # the base field of source coerces into the base field of self
396
+ self_polynomial = source .polynomial ().map_coefficients (base_coercion )
397
+ # try to find a root of the defining polynomial in self
398
+ if self_polynomial (self .gen ()) == 0 :
399
+ # The defining polynomial of source has a root in self,
400
+ # therefore there is a map. To be sure that it is
401
+ # canonical, we require a root of the defining polynomial
402
+ # of self to be a root of the defining polynomial of
403
+ # source (and that the variables are named equally):
404
+ if source .variable_name () == self .variable_name ():
405
+ return source .hom ([self .gen ()], base_morphism = base_coercion )
406
+
407
+ try :
408
+ sourcegen_in_self = self (source .variable_name ())
409
+ except TypeError :
410
+ pass
411
+ else :
412
+ if self_polynomial (sourcegen_in_self ) == 0 :
413
+ # The defining polynomial of source has a root in self,
414
+ # therefore there is a map. To be sure that it is
415
+ # canonical, we require the names of the roots to match
416
+ return source .hom ([sourcegen_in_self ], base_morphism = base_coercion )
354
417
355
418
def _test_derivation (self , ** options ):
356
419
"""
@@ -1203,12 +1266,16 @@ def hom(self, im_gens, base_morphism=None):
1203
1266
Defn: y |--> -y
1204
1267
x |--> x
1205
1268
1206
- The usage of the keyword base_morphism is not implemented yet ::
1269
+ You can also specify a morphism on the base ::
1207
1270
1208
- sage: L.hom([-y, x-1], base_morphism=phi)
1209
- Traceback (most recent call last):
1210
- ...
1211
- NotImplementedError: Function field homorphisms with optional argument base_morphism are not implemented yet. Please specify the images of the generators of the base fields manually.
1271
+ sage: R1.<r> = K[]
1272
+ sage: L1.<r> = K.extension(r^2 - (x+1)^3 - 1)
1273
+ sage: L.hom(r, base_morphism=phi)
1274
+ Function Field morphism:
1275
+ From: Function field in y defined by y^2 - x^3 - 1
1276
+ To: Function field in r defined by r^2 - x^3 - 3*x^2 - 3*x - 2
1277
+ Defn: y |--> r
1278
+ x |--> x + 1
1212
1279
1213
1280
We make another extension of a rational function field::
1214
1281
@@ -1246,9 +1313,6 @@ def hom(self, im_gens, base_morphism=None):
1246
1313
yy |--> y
1247
1314
1248
1315
"""
1249
- if base_morphism is not None :
1250
- raise NotImplementedError ("Function field homorphisms with optional argument base_morphism are not implemented yet. Please specify the images of the generators of the base fields manually." )
1251
-
1252
1316
if not isinstance (im_gens , (list ,tuple )):
1253
1317
im_gens = [im_gens ]
1254
1318
if len (im_gens ) == 0 :
@@ -1260,8 +1324,8 @@ def hom(self, im_gens, base_morphism=None):
1260
1324
# the codomain of this morphism is the field containing all the im_gens
1261
1325
codomain = im_gens [0 ].parent ();
1262
1326
if base_morphism is not None :
1263
- if base_morphism . codomain (). has_coerce_map_from ( codomain ):
1264
- codomain = base_morphism .codomain ();
1327
+ from sage . categories . pushout import pushout
1328
+ codomain = pushout ( codomain , base_morphism .codomain ())
1265
1329
1266
1330
from .maps import FunctionFieldMorphism_polymod
1267
1331
return FunctionFieldMorphism_polymod (self .Hom (codomain ), im_gens [0 ], base_morphism )
@@ -1821,12 +1885,14 @@ def base_field(self):
1821
1885
1822
1886
def hom (self , im_gens , base_morphism = None ):
1823
1887
"""
1824
- Create a homomorphism from self to another function field .
1888
+ Create a homomorphism from self to another ring .
1825
1889
1826
1890
INPUT:
1827
1891
1828
- - ``im_gens`` -- exactly one element of some function field
1829
- - ``base_morphism`` -- ignored
1892
+ - ``im_gens`` -- exactly one element of some ring. It must be invertible and trascendental over
1893
+ the image of ``base_morphism``; this is not checked.
1894
+ - ``base_morphism`` -- a homomorphism from the base field into the other ring.
1895
+ If ``None``, try to use a coercion map.
1830
1896
1831
1897
OUTPUT:
1832
1898
@@ -1864,8 +1930,11 @@ def hom(self, im_gens, base_morphism=None):
1864
1930
if len (im_gens ) != 1 :
1865
1931
raise ValueError ("there must be exactly one generator" )
1866
1932
x = im_gens [0 ]
1933
+ R = x .parent ()
1934
+ if base_morphism is None and not R .has_coerce_map_from (self .constant_field ()):
1935
+ raise ValueError ("You must specify a morphism on the base field" )
1867
1936
from .maps import FunctionFieldMorphism_rational
1868
- return FunctionFieldMorphism_rational (self .Hom (x . parent ()) , x )
1937
+ return FunctionFieldMorphism_rational (self .Hom (R ) , x , base_morphism )
1869
1938
1870
1939
def field (self ):
1871
1940
"""
0 commit comments