From b00d97f3c38b19ba30ce53fdd084c6d06eaa2b2d Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 9 Jun 2017 20:27:08 +0000 Subject: [PATCH 1/4] Make DefaultConvertMaps have a more refined category (than SetsWithPartialMaps) when they're actually coercions --- src/sage/categories/homset.py | 6 ++-- src/sage/rings/complex_field.py | 6 ++-- src/sage/rings/complex_mpc.pyx | 2 +- src/sage/rings/number_field/number_field.py | 6 ++-- .../rings/number_field/number_field_rel.py | 6 ++-- src/sage/rings/real_mpfr.pyx | 2 +- src/sage/structure/coerce_maps.pyx | 8 +++-- src/sage/structure/parent.pxd | 2 +- src/sage/structure/parent.pyx | 32 +++++++++++++++---- src/sage/structure/parent_old.pyx | 4 +-- 10 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index b442d8a278d..e62bb5e4030 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -707,7 +707,7 @@ def __bool__(self): __nonzero__ = __bool__ - def _generic_convert_map(self, S): + def _generic_convert_map(self, S, category=None): """ Return a generic map from a given homset to ``self``. @@ -715,6 +715,8 @@ def _generic_convert_map(self, S): - ``S`` -- a homset + - ``category`` -- a category + OUTPUT: A map (by default: a Call morphism) from ``S`` to ``self``. @@ -771,7 +773,7 @@ def _generic_convert_map(self, S): from sage.categories.homset import Hom return CallMorphism(Hom(S, self)) else: - return Parent._generic_convert_map(self, S) + return Parent._generic_convert_map(self, S, category) def homset_category(self): """ diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index 1796fcccbcb..aeedc185d36 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -424,7 +424,7 @@ def _coerce_map_from_(self, S): return RRtoCC(RR, self) * RR._internal_coerce_map_from(S) if is_ComplexField(S): if self._prec <= S._prec: - return self._generic_convert_map(S) + return self._generic_convert_map(S, S.category()) else: return None if S is complex: @@ -435,11 +435,11 @@ def _coerce_map_from_(self, S): late_import() if S is CDF: if self._prec <= 53: - return self._generic_convert_map(S) + return self._generic_convert_map(S, S.category()) else: return None if S in [AA, QQbar, CLF, RLF]: - return self._generic_convert_map(S) + return self._generic_convert_map(S, S.category()) return self._coerce_map_via([CLF], S) def _repr_(self): diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 2c1b137d57e..58744667361 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -472,7 +472,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): late_import() if S in [AA, QQbar, CLF, RLF] or (S == CDF and self._prec <= 53): - return self._generic_convert_map(S) + return self._generic_convert_map(S, S.category()) return self._coerce_map_via([CLF], S) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index d2324ab8f41..8f886bda6b1 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -6899,11 +6899,13 @@ def _coerce_map_from_(self, R): """ - if R in integer_types + (ZZ, QQ, self.base()): + if R in integer_types: return self._generic_convert_map(R) + elif R in (ZZ, QQ, self.base()): + return self._generic_convert_map(R, R.category()._meet_(self.category())) from sage.rings.number_field.order import is_NumberFieldOrder if is_NumberFieldOrder(R) and self.has_coerce_map_from(R.number_field()): - return self._generic_convert_map(R) + return self._generic_convert_map(R, R.category()._meet_(self.category())) # R is not QQ by the above tests if is_NumberField(R) and R.coerce_embedding() is not None: if self.coerce_embedding() is not None: diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index c1c5e0fcebe..9173233f9cf 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -1054,11 +1054,13 @@ def _coerce_map_from_(self, R): 2/3 sage: c = a + b # no output """ - if R in integer_types + (ZZ, QQ, self.base_field()): + if R in integer_types: return self._generic_convert_map(R) + elif R in (ZZ, QQ, self.base_field()): + return self._generic_convert_map(R, R.category()._meet_(self.category())) from sage.rings.number_field.order import is_NumberFieldOrder if is_NumberFieldOrder(R) and R.number_field() is self: - return self._generic_convert_map(R) + return self._generic_convert_map(R, R.category()._meet_(self.category())) mor = self.base_field()._internal_coerce_map_from(R) if mor is not None: return self._internal_coerce_map_from(self.base_field()) * mor diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index e7fc8a28eeb..f6abef23fd0 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -712,7 +712,7 @@ cdef class RealField_class(sage.rings.ring.Field): from sage.rings.qqbar import AA from sage.rings.real_lazy import RLF if S == AA or S is RLF: - return self._generic_convert_map(S) + return self._generic_convert_map(S, S.category()) return self._coerce_map_via([RLF], S) def __cmp__(self, other): diff --git a/src/sage/structure/coerce_maps.pyx b/src/sage/structure/coerce_maps.pyx index 223c7d96c62..d44328dc348 100644 --- a/src/sage/structure/coerce_maps.pyx +++ b/src/sage/structure/coerce_maps.pyx @@ -21,7 +21,7 @@ cdef class DefaultConvertMap(Map): This morphism simply calls the codomain's element_constructor method, passing in the codomain as the first argument. """ - def __init__(self, domain, codomain, force_use=False): + def __init__(self, domain, codomain, category=None, force_use=False): """ TESTS: @@ -37,8 +37,10 @@ cdef class DefaultConvertMap(Map): """ if not isinstance(domain, Parent): domain = Set_PythonType(domain) - from sage.categories.sets_with_partial_maps import SetsWithPartialMaps - parent = domain.Hom(codomain, category=SetsWithPartialMaps()) + if category is None: + from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + category = SetsWithPartialMaps() + parent = domain.Hom(codomain, category=category) Map.__init__(self, parent) self._coerce_cost = 100 self._force_use = force_use diff --git a/src/sage/structure/parent.pxd b/src/sage/structure/parent.pxd index 6bad96d83b0..0d309a4d9d1 100644 --- a/src/sage/structure/parent.pxd +++ b/src/sage/structure/parent.pxd @@ -61,7 +61,7 @@ cdef class Parent(category_object.CategoryObject): cdef public object _cache_an_element # For internal use - cpdef _generic_convert_map(self, S) + cpdef _generic_convert_map(self, S, category=*) cdef discover_coerce_map_from(self, S) cdef discover_convert_map_from(self, S) cdef discover_action(self, S, op, bint self_on_left, self_el=*, S_el=*) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index a7ec72d0642..c3b80e557e7 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1559,7 +1559,13 @@ cdef class Parent(category_object.CategoryObject): if isinstance(mor, map.Map): if mor.codomain() is not self: raise ValueError("Map's codomain must be self (%s) is not (%s)" % (self, mor.codomain())) - elif isinstance(mor, Parent) or isinstance(mor, type): + elif isinstance(mor, Parent): + try: + category = mor.category()._meet_(self.category()) + except Exception: + category = None + mor = self._generic_convert_map(mor, category) + elif isinstance(mor, type): mor = self._generic_convert_map(mor) else: raise TypeError("coercions must be parents or maps (got %s)" % type(mor)) @@ -1770,7 +1776,11 @@ cdef class Parent(category_object.CategoryObject): raise ValueError("embedding's domain must be self") self._embedding = embedding elif isinstance(embedding, Parent): - self._embedding = embedding._generic_convert_map(self) + try: + category = self.category()._meet_(embedding.category()) + except Exception: + category = None + self._embedding = embedding._generic_convert_map(self, category) elif embedding is not None: raise TypeError("embedding must be a parent or map") self._embedding._make_weak_references() @@ -1802,7 +1812,7 @@ cdef class Parent(category_object.CategoryObject): """ return copy(self._embedding) # It might be overkill to make a copy here - cpdef _generic_convert_map(self, S): + cpdef _generic_convert_map(self, S, category=None): r""" Returns the default conversion map based on the data provided to :meth:`_populate_coercion_lists_`. @@ -1832,9 +1842,9 @@ cdef class Parent(category_object.CategoryObject): return coerce_maps.NamedConvertMap(S, self, self._convert_method_name) if self._element_init_pass_parent: - return coerce_maps.DefaultConvertMap(S, self) + return coerce_maps.DefaultConvertMap(S, self, category) else: - return coerce_maps.DefaultConvertMap_unique(S, self) + return coerce_maps.DefaultConvertMap_unique(S, self, category) def _coerce_map_via(self, v, S): """ @@ -2053,7 +2063,11 @@ cdef class Parent(category_object.CategoryObject): # non-unique parents if debug.unique_parent_warnings: print("Warning: non-unique parents %s" % (type(S))) - mor = self._generic_convert_map(S) + try: + category = S.category()._meet_(self.category()) + except Exception: + category = None + mor = self._generic_convert_map(S, category) self._coerce_from_hash.set(S, mor) mor._make_weak_references() return mor @@ -2209,7 +2223,11 @@ cdef class Parent(category_object.CategoryObject): from coerce_maps import DefaultConvertMap, DefaultConvertMap_unique, NamedConvertMap, CallableConvertMap if user_provided_mor is True: - mor = self._generic_convert_map(S) + try: + category = S.category()._meet_(self.category()) + except Exception: + category = None + mor = self._generic_convert_map(S, category) elif isinstance(user_provided_mor, Map): mor = user_provided_mor elif callable(user_provided_mor): diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index de671181b47..892b85f3288 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -380,7 +380,7 @@ cdef class Parent(parent.Parent): else: return parent.Parent._an_element_(self) - cpdef _generic_convert_map(self, S): + cpdef _generic_convert_map(self, S, category=None): if self._element_constructor is None: if hasattr(self, '_element_constructor_'): assert callable(self._element_constructor_) @@ -391,4 +391,4 @@ cdef class Parent(parent.Parent): if isinstance(S, type): S = Set_PythonType(S) return CallMorphism(Hom(S, self)) - return parent.Parent._generic_convert_map(self, S) + return parent.Parent._generic_convert_map(self, S, category) From 3cc08d1ad81c264d7af4794ed9e41387d645edc2 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 10 Jun 2017 16:51:22 +0000 Subject: [PATCH 2/4] Fix a problem in quivers from changing the category of DefaultConvertMaps, add doctests to _generic_convert_map --- src/sage/quivers/morphism.py | 4 ++-- src/sage/structure/parent.pyx | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index 231adfe54b4..a0ed5e77aa7 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -271,9 +271,9 @@ def __init__(self, domain, codomain, data={}): for v in self._quiver: if v in maps_dict: if is_Map(maps_dict[v]): - if hasattr(maps_dict[v], 'matrix'): + try: m = maps_dict[v].matrix() - else: + except (AttributeError, ValueError): gens_images = [codomain._spaces[v].coordinate_vector(maps_dict[v](x)) for x in domain._spaces[v].gens()] m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v], gens_images) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index c3b80e557e7..070ead698a2 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1824,7 +1824,24 @@ cdef class Parent(category_object.CategoryObject): ``DefaultConvertMap`` or ``DefaultConvertMap_unique`` depending on whether or not init_no_parent is set. - EXAMPLES: + EXAMPLES:: + + sage: QQ['x']._generic_convert_map(SR) + Conversion via _polynomial_ method map: + From: Symbolic Ring + To: Univariate Polynomial Ring in x over Rational Field + sage: GF(11)._generic_convert_map(GF(7)) + Conversion map: + From: Finite Field of size 7 + To: Finite Field of size 11 + + TESTS: + + We check that `trac`:23184 has been resolved:: + + sage: QQ[['x']].coerce_map_from(QQ).category_for() + Category of euclidean domains + sage: """ import coerce_maps if self._convert_method_name is not None: From 09d34563e2dd6359b2350e8a4865b45b9a49b8b3 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 11 Jun 2017 00:59:46 +0000 Subject: [PATCH 3/4] Fix a dangling sage: prompt --- src/sage/structure/parent.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 070ead698a2..53cf46599df 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1841,7 +1841,6 @@ cdef class Parent(category_object.CategoryObject): sage: QQ[['x']].coerce_map_from(QQ).category_for() Category of euclidean domains - sage: """ import coerce_maps if self._convert_method_name is not None: From 5eccb5217999af4dc094b8a21d8b00071457c04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Sun, 11 Jun 2017 05:34:45 +0000 Subject: [PATCH 4/4] Refactor _default_convert_map to allow for a convenient _default_coerce_map and limit duplication of code --- src/sage/rings/complex_field.py | 8 +-- src/sage/rings/complex_mpc.pyx | 2 +- src/sage/rings/number_field/number_field.py | 6 +- .../rings/number_field/number_field_rel.py | 6 +- src/sage/rings/real_mpfr.pyx | 2 +- src/sage/structure/parent.pxd | 1 + src/sage/structure/parent.pyx | 71 +++++++++++-------- src/sage/structure/parent_old.pyx | 10 +++ 8 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index aeedc185d36..cd6c3b55fb8 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -424,22 +424,22 @@ def _coerce_map_from_(self, S): return RRtoCC(RR, self) * RR._internal_coerce_map_from(S) if is_ComplexField(S): if self._prec <= S._prec: - return self._generic_convert_map(S, S.category()) + return self._generic_coerce_map(S) else: return None if S is complex: if self._prec <= 53: - return self._generic_convert_map(S) + return self._generic_coerce_map(S) else: return None late_import() if S is CDF: if self._prec <= 53: - return self._generic_convert_map(S, S.category()) + return self._generic_coerce_map(S) else: return None if S in [AA, QQbar, CLF, RLF]: - return self._generic_convert_map(S, S.category()) + return self._generic_coerce_map(S) return self._coerce_map_via([CLF], S) def _repr_(self): diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 58744667361..8a4c7da2e54 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -472,7 +472,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): late_import() if S in [AA, QQbar, CLF, RLF] or (S == CDF and self._prec <= 53): - return self._generic_convert_map(S, S.category()) + return self._generic_coerce_map(S) return self._coerce_map_via([CLF], S) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 8f886bda6b1..dbb493ef1ac 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -6900,12 +6900,12 @@ def _coerce_map_from_(self, R): """ if R in integer_types: - return self._generic_convert_map(R) + return self._generic_coerce_map(R) elif R in (ZZ, QQ, self.base()): - return self._generic_convert_map(R, R.category()._meet_(self.category())) + return self._generic_coerce_map(R) from sage.rings.number_field.order import is_NumberFieldOrder if is_NumberFieldOrder(R) and self.has_coerce_map_from(R.number_field()): - return self._generic_convert_map(R, R.category()._meet_(self.category())) + return self._generic_coerce_map(R) # R is not QQ by the above tests if is_NumberField(R) and R.coerce_embedding() is not None: if self.coerce_embedding() is not None: diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 9173233f9cf..0d29db46a5d 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -1055,12 +1055,12 @@ def _coerce_map_from_(self, R): sage: c = a + b # no output """ if R in integer_types: - return self._generic_convert_map(R) + return self._generic_coerce_map(R) elif R in (ZZ, QQ, self.base_field()): - return self._generic_convert_map(R, R.category()._meet_(self.category())) + return self._generic_coerce_map(R) from sage.rings.number_field.order import is_NumberFieldOrder if is_NumberFieldOrder(R) and R.number_field() is self: - return self._generic_convert_map(R, R.category()._meet_(self.category())) + return self._generic_coerce_map(R) mor = self.base_field()._internal_coerce_map_from(R) if mor is not None: return self._internal_coerce_map_from(self.base_field()) * mor diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index f6abef23fd0..039d98422d8 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -712,7 +712,7 @@ cdef class RealField_class(sage.rings.ring.Field): from sage.rings.qqbar import AA from sage.rings.real_lazy import RLF if S == AA or S is RLF: - return self._generic_convert_map(S, S.category()) + return self._generic_coerce_map(S) return self._coerce_map_via([RLF], S) def __cmp__(self, other): diff --git a/src/sage/structure/parent.pxd b/src/sage/structure/parent.pxd index 0d309a4d9d1..77a5dfe43cf 100644 --- a/src/sage/structure/parent.pxd +++ b/src/sage/structure/parent.pxd @@ -62,6 +62,7 @@ cdef class Parent(category_object.CategoryObject): # For internal use cpdef _generic_convert_map(self, S, category=*) + cpdef _generic_coerce_map(self, S) cdef discover_coerce_map_from(self, S) cdef discover_convert_map_from(self, S) cdef discover_action(self, S, op, bint self_on_left, self_el=*, S_el=*) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 53cf46599df..7c53a220329 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1559,14 +1559,8 @@ cdef class Parent(category_object.CategoryObject): if isinstance(mor, map.Map): if mor.codomain() is not self: raise ValueError("Map's codomain must be self (%s) is not (%s)" % (self, mor.codomain())) - elif isinstance(mor, Parent): - try: - category = mor.category()._meet_(self.category()) - except Exception: - category = None - mor = self._generic_convert_map(mor, category) - elif isinstance(mor, type): - mor = self._generic_convert_map(mor) + elif isinstance(mor, (type, Parent)): + mor = self._generic_coerce_map(mor) else: raise TypeError("coercions must be parents or maps (got %s)" % type(mor)) D = mor.domain() @@ -1776,11 +1770,7 @@ cdef class Parent(category_object.CategoryObject): raise ValueError("embedding's domain must be self") self._embedding = embedding elif isinstance(embedding, Parent): - try: - category = self.category()._meet_(embedding.category()) - except Exception: - category = None - self._embedding = embedding._generic_convert_map(self, category) + self._embedding = embedding._generic_coerce_map(self) elif embedding is not None: raise TypeError("embedding must be a parent or map") self._embedding._make_weak_references() @@ -1812,6 +1802,39 @@ cdef class Parent(category_object.CategoryObject): """ return copy(self._embedding) # It might be overkill to make a copy here + cpdef _generic_coerce_map(self, S): + r""" + Returns a default coercion map based on the data provided to + :meth:`_populate_coercion_lists_`. + + This method differs from :meth:`_generic_convert_map` only in setting + the category for the map to the meet of the category of this parent + and ``S``. + + EXAMPLES:: + + sage: QQ['x']._generic_coerce_map(ZZ) + Conversion map: + From: Integer Ring + To: Univariate Polynomial Ring in x over Rational Field + + + TESTS: + + We check that `trac`:23184 has been resolved:: + + sage: QQ['x', 'y']._generic_coerce_map(QQ).category_for() + Category of unique factorization domains + sage: QQ[['x']].coerce_map_from(QQ).category_for() + Category of euclidean domains + + """ + if isinstance(S, type): + category = None + else: + category = self.category()._meet_(S.category()) + return self._generic_convert_map(S, category=category) + cpdef _generic_convert_map(self, S, category=None): r""" Returns the default conversion map based on the data provided to @@ -1835,12 +1858,6 @@ cdef class Parent(category_object.CategoryObject): From: Finite Field of size 7 To: Finite Field of size 11 - TESTS: - - We check that `trac`:23184 has been resolved:: - - sage: QQ[['x']].coerce_map_from(QQ).category_for() - Category of euclidean domains """ import coerce_maps if self._convert_method_name is not None: @@ -1858,9 +1875,9 @@ cdef class Parent(category_object.CategoryObject): return coerce_maps.NamedConvertMap(S, self, self._convert_method_name) if self._element_init_pass_parent: - return coerce_maps.DefaultConvertMap(S, self, category) + return coerce_maps.DefaultConvertMap(S, self, category=category) else: - return coerce_maps.DefaultConvertMap_unique(S, self, category) + return coerce_maps.DefaultConvertMap_unique(S, self, category=category) def _coerce_map_via(self, v, S): """ @@ -2079,11 +2096,7 @@ cdef class Parent(category_object.CategoryObject): # non-unique parents if debug.unique_parent_warnings: print("Warning: non-unique parents %s" % (type(S))) - try: - category = S.category()._meet_(self.category()) - except Exception: - category = None - mor = self._generic_convert_map(S, category) + mor = self._generic_coerce_map(S) self._coerce_from_hash.set(S, mor) mor._make_weak_references() return mor @@ -2239,11 +2252,7 @@ cdef class Parent(category_object.CategoryObject): from coerce_maps import DefaultConvertMap, DefaultConvertMap_unique, NamedConvertMap, CallableConvertMap if user_provided_mor is True: - try: - category = S.category()._meet_(self.category()) - except Exception: - category = None - mor = self._generic_convert_map(S, category) + mor = self._generic_coerce_map(S) elif isinstance(user_provided_mor, Map): mor = user_provided_mor elif callable(user_provided_mor): diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index 892b85f3288..ed8a58b9a3c 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -381,6 +381,16 @@ cdef class Parent(parent.Parent): return parent.Parent._an_element_(self) cpdef _generic_convert_map(self, S, category=None): + r""" + Return a default conversion from ``S``. + + EXAMPLES:: + + sage: R.=QQ[] + sage: R._generic_convert_map(QQ).category_for() + Category of sets with partial maps + + """ if self._element_constructor is None: if hasattr(self, '_element_constructor_'): assert callable(self._element_constructor_)