Base class for parent objects¶
CLASS HIERARCHY:
SageObject
    CategoryObject
        Parent
A simple example of registering coercions:
sage: class A_class(Parent):
....:   def __init__(self, name):
....:       Parent.__init__(self)
....:       self._populate_coercion_lists_()
....:       self.rename(name)
....:
....:   def category(self):
....:       return Sets()
....:
....:   def _element_constructor_(self, i):
....:       assert(isinstance(i, (int, Integer)))
....:       return ElementWrapper(self, i)
sage: A = A_class("A")
sage: B = A_class("B")
sage: C = A_class("C")
sage: def f(a):
....:   return B(a.value+1)
sage: class MyMorphism(Morphism):
....:   def __init__(self, domain, codomain):
....:       Morphism.__init__(self, Hom(domain, codomain))
....:
....:   def _call_(self, x):
....:       return self.codomain()(x.value)
sage: f = MyMorphism(A,B)
sage: f
    Generic morphism:
      From: A
      To:   B
sage: B.register_coercion(f)
sage: C.register_coercion(MyMorphism(B,C))
sage: A(A(1)) == A(1)
True
sage: B(A(1)) == B(1)
True
sage: C(A(1)) == C(1)
True
sage: A(B(1))
Traceback (most recent call last):
...
AssertionError
>>> from sage.all import *
>>> class A_class(Parent):
...   def __init__(self, name):
...       Parent.__init__(self)
...       self._populate_coercion_lists_()
...       self.rename(name)
....:
>>>   def category(self):
...       return Sets()
....:
>>>   def _element_constructor_(self, i):
...       assert(isinstance(i, (int, Integer)))
...       return ElementWrapper(self, i)
>>> A = A_class("A")
>>> B = A_class("B")
>>> C = A_class("C")
>>> def f(a):
...   return B(a.value+Integer(1))
>>> class MyMorphism(Morphism):
...   def __init__(self, domain, codomain):
...       Morphism.__init__(self, Hom(domain, codomain))
....:
>>>   def _call_(self, x):
...       return self.codomain()(x.value)
>>> f = MyMorphism(A,B)
>>> f
    Generic morphism:
      From: A
      To:   B
>>> B.register_coercion(f)
>>> C.register_coercion(MyMorphism(B,C))
>>> A(A(Integer(1))) == A(Integer(1))
True
>>> B(A(Integer(1))) == B(Integer(1))
True
>>> C(A(Integer(1))) == C(Integer(1))
True
>>> A(B(Integer(1)))
Traceback (most recent call last):
...
AssertionError
When implementing an element of a ring, one would typically provide the
element class with _rmul_ and/or _lmul_ methods for the action of a
base ring, and with _mul_ for the ring multiplication. However, prior to
Issue #14249, it would have been necessary to additionally define a method
_an_element_() for the parent. But now, the following example works:
sage: from sage.structure.element import RingElement
sage: class MyElement(RingElement):
....:      def __init__(self, parent, x, y):
....:          RingElement.__init__(self, parent)
....:      def _mul_(self, other):
....:          return self
....:      def _rmul_(self, other):
....:          return self
....:      def _lmul_(self, other):
....:          return self
sage: class MyParent(Parent):
....:      Element = MyElement
>>> from sage.all import *
>>> from sage.structure.element import RingElement
>>> class MyElement(RingElement):
...      def __init__(self, parent, x, y):
...          RingElement.__init__(self, parent)
...      def _mul_(self, other):
...          return self
...      def _rmul_(self, other):
...          return self
...      def _lmul_(self, other):
...          return self
>>> class MyParent(Parent):
...      Element = MyElement
Now, we define
sage: P = MyParent(base=ZZ, category=Rings())
sage: a = P(1,2)
sage: a*a is a
True
sage: a*2 is a
True
sage: 2*a is a
True
>>> from sage.all import *
>>> P = MyParent(base=ZZ, category=Rings())
>>> a = P(Integer(1),Integer(2))
>>> a*a is a
True
>>> a*Integer(2) is a
True
>>> Integer(2)*a is a
True
- class sage.structure.parent.Parent[source]¶
- Bases: - CategoryObject- Base class for all parents. - Parents are the Sage/mathematical analogues of container objects in computer science. - INPUT: - base– an algebraic structure considered to be the “base” of this parent (e.g. the base field for a vector space)
- category– a category or list/tuple of categories. The category in which this parent lies (or list or tuple thereof). Since categories support more general super-categories, this should be the most specific category possible. If category is a list or tuple, a- JoinCategoryis created out of them. If category is not specified, the category will be guessed (see- CategoryObject), but will not be used to inherit parent’s or element’s code from this category.
- names– names of generators
- normalize– whether to standardize the names (remove punctuation, etc.)
- facade– a parent, or tuple thereof, or- True
 - If - facadeis specified, then- Sets().Facade()is added to the categories of the parent. Furthermore, if- facadeis not- True, the internal attribute- _facade_foris set accordingly for use by- Sets.Facade.ParentMethods.facade_for().- Internal invariants: - self._element_init_pass_parent == guess_pass_parent(self, self._element_constructor)Ensures that- __call__()passes down the parent properly to- _element_constructor(). See Issue #5979.
 - Todo - Eventually, category should be - Setsby default.- __call__(x=0, *args, **kwds)[source]¶
- This is the generic call method for all parents. - When called, it will find a map based on the Parent (or type) of x. If a coercion exists, it will always be chosen. This map will then be called (with the arguments and keywords if any). - By default this will dispatch as quickly as possible to - _element_constructor_()though faster pathways are possible if so desired.
 - _populate_coercion_lists_(coerce_list=[], action_list=[], convert_list=[], embedding=None, convert_method_name=None, element_constructor=None, init_no_parent=None, unpickling=False)[source]¶
- This function allows one to specify coercions, actions, conversions and embeddings involving this parent. - IT SHOULD ONLY BE CALLED DURING THE __INIT__ method, often at the end. - INPUT: - coerce_list– list of coercion Morphisms to- selfand parents with canonical coercions to- self
- action_list– list of actions on and by- self
- convert_list– list of conversion Maps to- selfand parents with conversions to- self
- embedding– a single Morphism from- self
- convert_method_name– a name to look for that other elements can implement to create elements of- self(e.g.- _integer_)
- init_no_parent– if- Trueomit passing- selfin as the first argument of element_constructor for conversion. This is useful if parents are unique, or element_constructor is a bound method (this latter case can be detected automatically).
 
 - __mul__(x)[source]¶
- This is a multiplication method that more or less directly calls another attribute - _mul_(single underscore). This is because- __mul__cannot be implemented via inheritance from the parent methods of the category, but- _mul_can be inherited. This is, e.g., used when creating twosided ideals of matrix algebras. See Issue #7797.- EXAMPLES: - sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules - >>> from sage.all import * >>> MS = MatrixSpace(QQ, Integer(2), Integer(2)) # needs sage.modules - This matrix space is in fact an algebra, and in particular it is a ring, from the point of view of categories: - sage: MS.category() # needs sage.modules Category of infinite finite dimensional algebras with basis over (number fields and quotient fields and metric spaces) sage: MS in Rings() # needs sage.modules True - >>> from sage.all import * >>> MS.category() # needs sage.modules Category of infinite finite dimensional algebras with basis over (number fields and quotient fields and metric spaces) >>> MS in Rings() # needs sage.modules True - However, its class does not inherit from the base class - Ring:- sage: isinstance(MS, Ring) # needs sage.modules False - >>> from sage.all import * >>> isinstance(MS, Ring) # needs sage.modules False - Its - _mul_method is inherited from the category, and can be used to create a left or right ideal:- sage: # needs sage.modules sage: MS._mul_.__module__ 'sage.categories.rings' sage: MS * MS.1 # indirect doctest Left Ideal ( [0 1] [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: MS * [MS.1, 2] Left Ideal ( [0 1] [0 0], [2 0] [0 2] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: MS.1 * MS Right Ideal ( [0 1] [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: [MS.1, 2] * MS Right Ideal ( [0 1] [0 0], [2 0] [0 2] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - >>> from sage.all import * >>> # needs sage.modules >>> MS._mul_.__module__ 'sage.categories.rings' >>> MS * MS.gen(1) # indirect doctest Left Ideal ( [0 1] [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field >>> MS * [MS.gen(1), Integer(2)] Left Ideal ( [0 1] [0 0], <BLANKLINE> [2 0] [0 2] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field >>> MS.gen(1) * MS Right Ideal ( [0 1] [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field >>> [MS.gen(1), Integer(2)] * MS Right Ideal ( [0 1] [0 0], <BLANKLINE> [2 0] [0 2] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field 
 - __contains__(x)[source]¶
- Trueif there is an element of- selfthat is equal to- xunder- ==, or if- xis already an element of- self. Also,- Truein other cases involving the Symbolic Ring, which is handled specially.- For many structures we test this by using - __call__()and then testing equality between- xand the result.- The Symbolic Ring is treated differently because it is ultra-permissive about letting other rings coerce in, but ultra-strict about doing comparisons. - EXAMPLES: - sage: 2 in Integers(7) True sage: 2 in ZZ True sage: Integers(7)(3) in ZZ True sage: 3/1 in ZZ True sage: 5 in QQ True sage: I in RR # needs sage.rings.real_mpfr sage.symbolic False sage: RIF(1, 2) in RIF # needs sage.rings.real_interval_field True sage: # needs sage.symbolic sage: SR(2) in ZZ True sage: pi in RIF # there is no element of RIF equal to pi False sage: sqrt(2) in CC True sage: pi in RR True sage: pi in CC True sage: pi in RDF True sage: pi in CDF True - >>> from sage.all import * >>> Integer(2) in Integers(Integer(7)) True >>> Integer(2) in ZZ True >>> Integers(Integer(7))(Integer(3)) in ZZ True >>> Integer(3)/Integer(1) in ZZ True >>> Integer(5) in QQ True >>> I in RR # needs sage.rings.real_mpfr sage.symbolic False >>> RIF(Integer(1), Integer(2)) in RIF # needs sage.rings.real_interval_field True >>> # needs sage.symbolic >>> SR(Integer(2)) in ZZ True >>> pi in RIF # there is no element of RIF equal to pi False >>> sqrt(Integer(2)) in CC True >>> pi in RR True >>> pi in CC True >>> pi in RDF True >>> pi in CDF True - Note that we have - sage: 3/2 in RIF # needs sage.rings.real_interval_field True - >>> from sage.all import * >>> Integer(3)/Integer(2) in RIF # needs sage.rings.real_interval_field True - because - 3/2has an exact representation in- RIF(i.e. can be represented as an interval that contains exactly one value):- sage: RIF(3/2).is_exact() # needs sage.rings.real_interval_field True - >>> from sage.all import * >>> RIF(Integer(3)/Integer(2)).is_exact() # needs sage.rings.real_interval_field True - On the other hand, we have - sage: 2/3 in RIF # needs sage.rings.real_interval_field False - >>> from sage.all import * >>> Integer(2)/Integer(3) in RIF # needs sage.rings.real_interval_field False - because - 2/3has no exact representation in- RIF. Since- RIF(2/3)is a nontrivial interval, it cannot be equal to anything (not even itself):- sage: RIF(2/3).is_exact() # needs sage.rings.real_interval_field False sage: RIF(2/3).endpoints() # needs sage.rings.real_interval_field (0.666666666666666, 0.666666666666667) sage: RIF(2/3) == RIF(2/3) # needs sage.rings.real_interval_field False - >>> from sage.all import * >>> RIF(Integer(2)/Integer(3)).is_exact() # needs sage.rings.real_interval_field False >>> RIF(Integer(2)/Integer(3)).endpoints() # needs sage.rings.real_interval_field (0.666666666666666, 0.666666666666667) >>> RIF(Integer(2)/Integer(3)) == RIF(Integer(2)/Integer(3)) # needs sage.rings.real_interval_field False 
 - _coerce_map_from_(S)[source]¶
- Override this method to specify coercions beyond those specified in - coerce_list.- If no such coercion exists, return - Noneor- False. Otherwise, it may return either an actual Map to use for the coercion, a callable (in which case it will be wrapped in a Map), or- True(in which case a generic map will be provided).
 - _convert_map_from_(S)[source]¶
- Override this method to provide additional conversions beyond those given in - convert_list.- This function is called after coercions are attempted. If there is a coercion morphism in the opposite direction, one should consider adding a section method to that. - This MUST return a Map from - Sto- self, or- None. If- Noneis returned then a generic map will be provided.
 - _get_action_(S, op, self_on_left)[source]¶
- Override this method to provide an action of - selfon- Sor- Son- selfbeyond what was specified in- action_list.- This must return an action which accepts an element of - selfand an element of- S(in the order specified by- self_on_left).
 - _an_element_()[source]¶
- Return an element of - self.- Want it in sufficient generality that poorly-written functions will not work when they are not supposed to. This is cached so does not have to be super fast. - EXAMPLES: - sage: QQ._an_element_() 1/2 sage: ZZ['x,y,z']._an_element_() x - >>> from sage.all import * >>> QQ._an_element_() 1/2 >>> ZZ['x,y,z']._an_element_() x 
 - _repr_option(key)[source]¶
- Metadata about the - _repr_()output.- INPUT: - key– string; a key for different metadata informations that can be inquired about
 - Valid - keyarguments are:- 'ascii_art': The- _repr_()output is multi-line ascii art and each line must be printed starting at the same column, or the meaning is lost.
- 'element_ascii_art': same but for the output of the elements. Used in- sage.repl.display.formatter.
- 'element_is_atomic': the elements print atomically, that is, parenthesis are not required when printing out any of \(x - y\), \(x + y\), \(x^y\) and \(x/y\).
 - OUTPUT: boolean - EXAMPLES: - sage: ZZ._repr_option('ascii_art') False sage: MatrixSpace(ZZ, 2)._repr_option('element_ascii_art') # needs sage.modules True - >>> from sage.all import * >>> ZZ._repr_option('ascii_art') False >>> MatrixSpace(ZZ, Integer(2))._repr_option('element_ascii_art') # needs sage.modules True 
 - _init_category_(category)[source]¶
- Initialize the category framework. - Most parents initialize their category upon construction, and this is the recommended behavior. For example, this happens when the constructor calls - Parent.__init__()directly or indirectly. However, some parents defer this for performance reasons. For example,- sage.matrix.matrix_space.MatrixSpacedoes not.- EXAMPLES: - sage: P = Parent() sage: P.category() Category of sets sage: class MyParent(Parent): ....: def __init__(self): ....: self._init_category_(Groups()) sage: MyParent().category() Category of groups - >>> from sage.all import * >>> P = Parent() >>> P.category() Category of sets >>> class MyParent(Parent): ... def __init__(self): ... self._init_category_(Groups()) >>> MyParent().category() Category of groups 
 - _is_coercion_cached(domain)[source]¶
- Test whether the coercion from - domainis already cached.- EXAMPLES: - sage: R.<XX> = QQ sage: R._remove_from_coerce_cache(QQ) sage: R._is_coercion_cached(QQ) False sage: _ = R.coerce_map_from(QQ) sage: R._is_coercion_cached(QQ) True - >>> from sage.all import * >>> R = QQ; (XX,) = R._first_ngens(1) >>> R._remove_from_coerce_cache(QQ) >>> R._is_coercion_cached(QQ) False >>> _ = R.coerce_map_from(QQ) >>> R._is_coercion_cached(QQ) True 
 - _is_conversion_cached(domain)[source]¶
- Test whether the conversion from - domainis already set.- EXAMPLES: - sage: P = Parent() sage: P._is_conversion_cached(P) False sage: P.convert_map_from(P) Identity endomorphism of <sage.structure.parent.Parent object at ...> sage: P._is_conversion_cached(P) True - >>> from sage.all import * >>> P = Parent() >>> P._is_conversion_cached(P) False >>> P.convert_map_from(P) Identity endomorphism of <sage.structure.parent.Parent object at ...> >>> P._is_conversion_cached(P) True 
 - Hom(codomain, category=None)[source]¶
- Return the homspace - Hom(self, codomain, category).- INPUT: - codomain– a parent
- category– a category or- None(default:- None) If- None, the meet of the category of- selfand- codomainis used.
 - OUTPUT: - The homspace of all homomorphisms from - selfto- codomainin the category- category.- See also - EXAMPLES: - sage: R.<x,y> = PolynomialRing(QQ, 2) sage: R.Hom(QQ) Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field - >>> from sage.all import * >>> R = PolynomialRing(QQ, Integer(2), names=('x', 'y',)); (x, y,) = R._first_ngens(2) >>> R.Hom(QQ) Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field - Homspaces are defined for very general Sage objects, even elements of familiar rings: - sage: n = 5; Hom(n,7) Set of Morphisms from 5 to 7 in Category of elements of Integer Ring sage: z=(2/3); Hom(z,8/1) Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field - >>> from sage.all import * >>> n = Integer(5); Hom(n,Integer(7)) Set of Morphisms from 5 to 7 in Category of elements of Integer Ring >>> z=(Integer(2)/Integer(3)); Hom(z,Integer(8)/Integer(1)) Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field - This example illustrates the optional third argument: - sage: QQ.Hom(ZZ, Sets()) Set of Morphisms from Rational Field to Integer Ring in Category of sets - >>> from sage.all import * >>> QQ.Hom(ZZ, Sets()) Set of Morphisms from Rational Field to Integer Ring in Category of sets - A parent may specify how to construct certain homsets by implementing a method - _Hom_`(codomain, category). See :func:`~sage.categories.homset.Hom()for details.
 - an_element()[source]¶
- Return a (preferably typical) element of this parent. - This is used both for illustration and testing purposes. If the set - selfis empty,- an_element()raises the exception- EmptySetError.- This calls - _an_element_()(which see), and caches the result. Parent are thus encouraged to override- _an_element_().- EXAMPLES: - sage: CDF.an_element() # needs sage.rings.complex_double 1.0*I sage: ZZ[['t']].an_element() t - >>> from sage.all import * >>> CDF.an_element() # needs sage.rings.complex_double 1.0*I >>> ZZ[['t']].an_element() t - In case the set is empty, an - EmptySetErroris raised:- sage: Set([]).an_element() Traceback (most recent call last): ... EmptySetError - >>> from sage.all import * >>> Set([]).an_element() Traceback (most recent call last): ... EmptySetError 
 - category()[source]¶
- EXAMPLES: - sage: P = Parent() sage: P.category() Category of sets sage: class MyParent(Parent): ....: def __init__(self): pass sage: MyParent().category() Category of sets - >>> from sage.all import * >>> P = Parent() >>> P.category() Category of sets >>> class MyParent(Parent): ... def __init__(self): pass >>> MyParent().category() Category of sets 
 - coerce(x)[source]¶
- Return x as an element of - self, if and only if there is a canonical coercion from the parent of x to- self.- EXAMPLES: - sage: QQ.coerce(ZZ(2)) 2 sage: ZZ.coerce(QQ(2)) Traceback (most recent call last): ... TypeError: no canonical coercion from Rational Field to Integer Ring - >>> from sage.all import * >>> QQ.coerce(ZZ(Integer(2))) 2 >>> ZZ.coerce(QQ(Integer(2))) Traceback (most recent call last): ... TypeError: no canonical coercion from Rational Field to Integer Ring - We make an exception for zero: - sage: V = GF(7)^7 # needs sage.modules sage: V.coerce(0) # needs sage.modules (0, 0, 0, 0, 0, 0, 0) - >>> from sage.all import * >>> V = GF(Integer(7))**Integer(7) # needs sage.modules >>> V.coerce(Integer(0)) # needs sage.modules (0, 0, 0, 0, 0, 0, 0) 
 - coerce_embedding()[source]¶
- Return the embedding of - selfinto some other parent, if such a parent exists.- This does not mean that there are no coercion maps from - selfinto other fields, this is simply a specific morphism specified out of- selfand usually denotes a special relationship (e.g. sub-objects, choice of completion, etc.)- EXAMPLES: - sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=1) sage: K.coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^3 + x^2 + 1 with a = -1.465571231876768? To: Real Lazy Field Defn: a -> -1.465571231876768? sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=CC.gen()) sage: K.coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^3 + x^2 + 1 with a = 0.2327856159383841? + 0.7925519925154479?*I To: Complex Lazy Field Defn: a -> 0.2327856159383841? + 0.7925519925154479?*I - >>> from sage.all import * >>> # needs sage.rings.number_field >>> x = polygen(ZZ, 'x') >>> K = NumberField(x**Integer(3) + x**Integer(2) + Integer(1), embedding=Integer(1), names=('a',)); (a,) = K._first_ngens(1) >>> K.coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^3 + x^2 + 1 with a = -1.465571231876768? To: Real Lazy Field Defn: a -> -1.465571231876768? >>> K = NumberField(x**Integer(3) + x**Integer(2) + Integer(1), embedding=CC.gen(), names=('a',)); (a,) = K._first_ngens(1) >>> K.coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^3 + x^2 + 1 with a = 0.2327856159383841? + 0.7925519925154479?*I To: Complex Lazy Field Defn: a -> 0.2327856159383841? + 0.7925519925154479?*I 
 - coerce_map_from(S)[source]¶
- Return a - Mapobject to coerce from- Sto- selfif one exists, or- Noneif no such coercion exists.- EXAMPLES: - By Issue #12313, a special kind of weak key dictionary is used to store coercion and conversion maps, namely - MonoDict. In that way, a memory leak was fixed that would occur in the following test:- sage: import gc sage: _ = gc.collect() sage: K = GF(1<<55,'t') # needs sage.rings.finite_rings sage: for i in range(50): # needs sage.rings.finite_rings sage.schemes ....: a = K.random_element() ....: E = EllipticCurve(j=a) ....: b = K.has_coerce_map_from(E) sage: _ = gc.collect() sage: len([x for x in gc.get_objects() if isinstance(x, type(E))]) # needs sage.rings.finite_rings sage.schemes 1 - >>> from sage.all import * >>> import gc >>> _ = gc.collect() >>> K = GF(Integer(1)<<Integer(55),'t') # needs sage.rings.finite_rings >>> for i in range(Integer(50)): # needs sage.rings.finite_rings sage.schemes ... a = K.random_element() ... E = EllipticCurve(j=a) ... b = K.has_coerce_map_from(E) >>> _ = gc.collect() >>> len([x for x in gc.get_objects() if isinstance(x, type(E))]) # needs sage.rings.finite_rings sage.schemes 1 
 - convert_map_from(S)[source]¶
- This function returns a - Mapfrom \(S\) to- self, which may or may not succeed on all inputs. If a coercion map from S to- selfexists, then the it will be returned. If a coercion from- selfto \(S\) exists, then it will attempt to return a section of that map.- Under the new coercion model, this is the fastest way to convert elements of \(S\) to elements of - self(short of manually constructing the elements) and is used by- __call__().- EXAMPLES: - sage: m = ZZ.convert_map_from(QQ) sage: m Generic map: From: Rational Field To: Integer Ring sage: m(-35/7) -5 sage: parent(m(-35/7)) Integer Ring - >>> from sage.all import * >>> m = ZZ.convert_map_from(QQ) >>> m Generic map: From: Rational Field To: Integer Ring >>> m(-Integer(35)/Integer(7)) -5 >>> parent(m(-Integer(35)/Integer(7))) Integer Ring 
 - element_class()[source]¶
- The (default) class for the elements of this parent. - FIXME’s and design issues: - If self.Element is “trivial enough”, should we optimize it away with: self.element_class = dynamic_class(“%s.element_class”%self.__class__.__name__, (category.element_class,), self.Element) 
- This should lookup for Element classes in all super classes 
 
 - get_action(S, op=None, self_on_left=True, self_el=None, S_el=None)[source]¶
- Return an action of - selfon- Sor- Son- self.- To provide additional actions, override - _get_action_().- Warning - This is not the method that you typically want to call. Instead, call - coercion_model.get_action(...)which caches results (this- Parent.get_actionmethod does not).
 - has_coerce_map_from(S)[source]¶
- Return - Trueif there is a natural map from- Sto- self. Otherwise, return- False.- EXAMPLES: - sage: RDF.has_coerce_map_from(QQ) True sage: RDF.has_coerce_map_from(QQ['x']) False sage: RDF['x'].has_coerce_map_from(QQ['x']) True sage: RDF['x,y'].has_coerce_map_from(QQ['x']) True - >>> from sage.all import * >>> RDF.has_coerce_map_from(QQ) True >>> RDF.has_coerce_map_from(QQ['x']) False >>> RDF['x'].has_coerce_map_from(QQ['x']) True >>> RDF['x,y'].has_coerce_map_from(QQ['x']) True 
 - hom(im_gens, codomain=None, check=None, base_map=None, category=None, **kwds)[source]¶
- Return the unique homomorphism from - selfto- codomainthat sends- self.gens()to the entries of- im_gens.- This raises a - TypeErrorif there is no such homomorphism.- INPUT: - im_gens– the images in the codomain of the generators of this object under the homomorphism
- codomain– the codomain of the homomorphism
- base_map– a map from the base ring to the codomain; if not given, coercion is used
- check– whether to verify that the images of generators extend to define a map (using only canonical coercions)
 - OUTPUT: a homomorphism - self --> codomain- Note - As a shortcut, one can also give an object X instead of - im_gens, in which case return the (if it exists) natural map to X.- EXAMPLES: - Polynomial Ring: We first illustrate construction of a few homomorphisms involving a polynomial ring: - sage: R.<x> = PolynomialRing(ZZ) sage: f = R.hom([5], QQ) sage: f(x^2 - 19) 6 sage: R.<x> = PolynomialRing(QQ) sage: f = R.hom([5], GF(7)) Traceback (most recent call last): ... ValueError: relations do not all (canonically) map to 0 under map determined by images of generators sage: # needs sage.rings.finite_rings sage: R.<x> = PolynomialRing(GF(7)) sage: f = R.hom([3], GF(49,'a')) sage: f Ring morphism: From: Univariate Polynomial Ring in x over Finite Field of size 7 To: Finite Field in a of size 7^2 Defn: x |--> 3 sage: f(x + 6) 2 sage: f(x^2 + 1) 3 - >>> from sage.all import * >>> R = PolynomialRing(ZZ, names=('x',)); (x,) = R._first_ngens(1) >>> f = R.hom([Integer(5)], QQ) >>> f(x**Integer(2) - Integer(19)) 6 >>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1) >>> f = R.hom([Integer(5)], GF(Integer(7))) Traceback (most recent call last): ... ValueError: relations do not all (canonically) map to 0 under map determined by images of generators >>> # needs sage.rings.finite_rings >>> R = PolynomialRing(GF(Integer(7)), names=('x',)); (x,) = R._first_ngens(1) >>> f = R.hom([Integer(3)], GF(Integer(49),'a')) >>> f Ring morphism: From: Univariate Polynomial Ring in x over Finite Field of size 7 To: Finite Field in a of size 7^2 Defn: x |--> 3 >>> f(x + Integer(6)) 2 >>> f(x**Integer(2) + Integer(1)) 3 - Natural morphism: - sage: f = ZZ.hom(GF(5)) sage: f(7) 2 sage: f Natural morphism: From: Integer Ring To: Finite Field of size 5 - >>> from sage.all import * >>> f = ZZ.hom(GF(Integer(5))) >>> f(Integer(7)) 2 >>> f Natural morphism: From: Integer Ring To: Finite Field of size 5 - There might not be a natural morphism, in which case a - TypeErroris raised:- sage: QQ.hom(ZZ) Traceback (most recent call last): ... TypeError: natural coercion morphism from Rational Field to Integer Ring not defined - >>> from sage.all import * >>> QQ.hom(ZZ) Traceback (most recent call last): ... TypeError: natural coercion morphism from Rational Field to Integer Ring not defined 
 - is_exact()[source]¶
- Test whether elements of this parent are represented exactly. - Note - This defaults to true, so even if it does return - Trueyou have no guarantee (unless the parent has properly overloaded this).- OUTPUT: - Return - Trueif elements of this parent are represented exactly, i.e., there is no precision loss when doing arithmetic.- EXAMPLES: - sage: QQ.is_exact() True sage: ZZ.is_exact() True sage: Qp(7).is_exact() # needs sage.rings.padics False sage: Zp(7, type='capped-abs').is_exact() # needs sage.rings.padics False - >>> from sage.all import * >>> QQ.is_exact() True >>> ZZ.is_exact() True >>> Qp(Integer(7)).is_exact() # needs sage.rings.padics False >>> Zp(Integer(7), type='capped-abs').is_exact() # needs sage.rings.padics False 
 - register_action(action)[source]¶
- Update the coercion model to use - actionto act on- self.- actionshould be of type- sage.categories.action.Action.- EXAMPLES: - sage: import sage.categories.action sage: import operator sage: class SymmetricGroupAction(sage.categories.action.Action): ....: "Act on a multivariate polynomial ring by permuting the generators." ....: def __init__(self, G, M, is_left=True): ....: sage.categories.action.Action.__init__(self, G, M, is_left, operator.mul) ....: ....: def _act_(self, g, a): ....: D = {} ....: for k, v in a.monomial_coefficients().items(): ....: nk = [0]*len(k) ....: for i in range(len(k)): ....: nk[g(i+1)-1] = k[i] ....: D[tuple(nk)] = v ....: return a.parent()(D) sage: # needs sage.groups sage: R.<x, y, z> = QQ['x, y, z'] sage: G = SymmetricGroup(3) sage: act = SymmetricGroupAction(G, R) sage: t = x + 2*y + 3*z sage: # needs sage.groups sage: act(G((1, 2)), t) 2*x + y + 3*z sage: act(G((2, 3)), t) x + 3*y + 2*z sage: act(G((1, 2, 3)), t) 3*x + y + 2*z - >>> from sage.all import * >>> import sage.categories.action >>> import operator >>> class SymmetricGroupAction(sage.categories.action.Action): ... "Act on a multivariate polynomial ring by permuting the generators." ... def __init__(self, G, M, is_left=True): ... sage.categories.action.Action.__init__(self, G, M, is_left, operator.mul) ....: >>> def _act_(self, g, a): ... D = {} ... for k, v in a.monomial_coefficients().items(): ... nk = [Integer(0)]*len(k) ... for i in range(len(k)): ... nk[g(i+Integer(1))-Integer(1)] = k[i] ... D[tuple(nk)] = v ... return a.parent()(D) >>> # needs sage.groups >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> G = SymmetricGroup(Integer(3)) >>> act = SymmetricGroupAction(G, R) >>> t = x + Integer(2)*y + Integer(3)*z >>> # needs sage.groups >>> act(G((Integer(1), Integer(2))), t) 2*x + y + 3*z >>> act(G((Integer(2), Integer(3))), t) x + 3*y + 2*z >>> act(G((Integer(1), Integer(2), Integer(3))), t) 3*x + y + 2*z - This should fail, since we have not registered the left action: - sage: G((1,2)) * t # needs sage.groups Traceback (most recent call last): ... TypeError: ... - >>> from sage.all import * >>> G((Integer(1),Integer(2))) * t # needs sage.groups Traceback (most recent call last): ... TypeError: ... - Now let’s make it work: - sage: # needs sage.groups sage: R._unset_coercions_used() sage: R.register_action(act) sage: G((1, 2)) * t 2*x + y + 3*z - >>> from sage.all import * >>> # needs sage.groups >>> R._unset_coercions_used() >>> R.register_action(act) >>> G((Integer(1), Integer(2))) * t 2*x + y + 3*z 
 - register_coercion(mor)[source]¶
- Update the coercion model to use \(mor : P \to \text{self}\) to coerce from a parent - Pinto- self.- For safety, an error is raised if another coercion has already been registered or discovered between - Pand- self.- EXAMPLES: - sage: K.<a> = ZZ['a'] sage: L.<b> = ZZ['b'] sage: L_into_K = L.hom([-a]) # non-trivial automorphism sage: K.register_coercion(L_into_K) sage: K(0) + b -a sage: a + b 0 sage: K(b) # check that convert calls coerce first; normally this is just a -a sage: L(0) + a in K # this goes through the coercion mechanism of K True sage: L(a) in L # this still goes through the convert mechanism of L True sage: K.register_coercion(L_into_K) Traceback (most recent call last): ... AssertionError: coercion from Univariate Polynomial Ring in b over Integer Ring to Univariate Polynomial Ring in a over Integer Ring already registered or discovered - >>> from sage.all import * >>> K = ZZ['a']; (a,) = K._first_ngens(1) >>> L = ZZ['b']; (b,) = L._first_ngens(1) >>> L_into_K = L.hom([-a]) # non-trivial automorphism >>> K.register_coercion(L_into_K) >>> K(Integer(0)) + b -a >>> a + b 0 >>> K(b) # check that convert calls coerce first; normally this is just a -a >>> L(Integer(0)) + a in K # this goes through the coercion mechanism of K True >>> L(a) in L # this still goes through the convert mechanism of L True >>> K.register_coercion(L_into_K) Traceback (most recent call last): ... AssertionError: coercion from Univariate Polynomial Ring in b over Integer Ring to Univariate Polynomial Ring in a over Integer Ring already registered or discovered 
 - register_conversion(mor)[source]¶
- Update the coercion model to use \(\text{mor} : P \to \text{self}\) to convert from - Pinto- self.- EXAMPLES: - sage: K.<a> = ZZ['a'] sage: M.<c> = ZZ['c'] sage: M_into_K = M.hom([a]) # trivial automorphism sage: K._unset_coercions_used() sage: K.register_conversion(M_into_K) sage: K(c) a sage: K(0) + c Traceback (most recent call last): ... TypeError: ... - >>> from sage.all import * >>> K = ZZ['a']; (a,) = K._first_ngens(1) >>> M = ZZ['c']; (c,) = M._first_ngens(1) >>> M_into_K = M.hom([a]) # trivial automorphism >>> K._unset_coercions_used() >>> K.register_conversion(M_into_K) >>> K(c) a >>> K(Integer(0)) + c Traceback (most recent call last): ... TypeError: ... 
 - register_embedding(embedding)[source]¶
- Add embedding to coercion model. - This method updates the coercion model to use \(\text{embedding} : \text{self} \to P\) to embed - selfinto the parent- P.- There can only be one embedding registered; it can only be registered once; and it must be registered before using this parent in the coercion model. - EXAMPLES: - sage: S3 = AlternatingGroup(3) # needs sage.groups sage: G = SL(3, QQ) # needs sage.groups sage: p = S3[2]; p.matrix() # needs sage.groups [0 0 1] [1 0 0] [0 1 0] - >>> from sage.all import * >>> S3 = AlternatingGroup(Integer(3)) # needs sage.groups >>> G = SL(Integer(3), QQ) # needs sage.groups >>> p = S3[Integer(2)]; p.matrix() # needs sage.groups [0 0 1] [1 0 0] [0 1 0] - In general one cannot mix matrices and permutations: - sage: # needs sage.groups sage: G(p) Traceback (most recent call last): ... TypeError: unable to convert (1,3,2) to a rational sage: phi = S3.hom(lambda p: G(p.matrix()), codomain=G) sage: phi(p) [0 0 1] [1 0 0] [0 1 0] sage: S3._unset_coercions_used() sage: S3.register_embedding(phi) - >>> from sage.all import * >>> # needs sage.groups >>> G(p) Traceback (most recent call last): ... TypeError: unable to convert (1,3,2) to a rational >>> phi = S3.hom(lambda p: G(p.matrix()), codomain=G) >>> phi(p) [0 0 1] [1 0 0] [0 1 0] >>> S3._unset_coercions_used() >>> S3.register_embedding(phi) - By Issue #14711, coerce maps should be copied when using outside of the coercion system: - sage: phi = copy(S3.coerce_embedding()); phi # needs sage.groups Generic morphism: From: Alternating group of order 3!/2 as a permutation group To: Special Linear Group of degree 3 over Rational Field sage: phi(p) # needs sage.groups [0 0 1] [1 0 0] [0 1 0] - >>> from sage.all import * >>> phi = copy(S3.coerce_embedding()); phi # needs sage.groups Generic morphism: From: Alternating group of order 3!/2 as a permutation group To: Special Linear Group of degree 3 over Rational Field >>> phi(p) # needs sage.groups [0 0 1] [1 0 0] [0 1 0] - This does not work since matrix groups are still old-style parents (see Issue #14014): - sage: G(p) # not implemented # needs sage.groups - >>> from sage.all import * >>> G(p) # not implemented # needs sage.groups - Though one can have a permutation act on the rows of a matrix: - sage: G(1) * p # needs sage.groups [0 0 1] [1 0 0] [0 1 0] - >>> from sage.all import * >>> G(Integer(1)) * p # needs sage.groups [0 0 1] [1 0 0] [0 1 0] - Some more advanced examples: - sage: # needs sage.rings.number_field sage: x = QQ['x'].0 sage: t = abs(ZZ.random_element(10^6)) sage: K = NumberField(x^2 + 2*3*7*11, "a"+str(t)) sage: a = K.gen() sage: K_into_MS = K.hom([a.matrix()]) sage: K._unset_coercions_used() sage: K.register_embedding(K_into_MS) sage: # needs sage.rings.number_field sage: L = NumberField(x^2 + 2*3*7*11*19*31, ....: "b" + str(abs(ZZ.random_element(10^6)))) sage: b = L.gen() sage: L_into_MS = L.hom([b.matrix()]) sage: L._unset_coercions_used() sage: L.register_embedding(L_into_MS) sage: K.coerce_embedding()(a) # needs sage.rings.number_field [ 0 1] [-462 0] sage: L.coerce_embedding()(b) # needs sage.rings.number_field [ 0 1] [-272118 0] sage: a.matrix() * b.matrix() # needs sage.rings.number_field [-272118 0] [ 0 -462] sage: a.matrix() * b.matrix() # needs sage.rings.number_field [-272118 0] [ 0 -462] - >>> from sage.all import * >>> # needs sage.rings.number_field >>> x = QQ['x'].gen(0) >>> t = abs(ZZ.random_element(Integer(10)**Integer(6))) >>> K = NumberField(x**Integer(2) + Integer(2)*Integer(3)*Integer(7)*Integer(11), "a"+str(t)) >>> a = K.gen() >>> K_into_MS = K.hom([a.matrix()]) >>> K._unset_coercions_used() >>> K.register_embedding(K_into_MS) >>> # needs sage.rings.number_field >>> L = NumberField(x**Integer(2) + Integer(2)*Integer(3)*Integer(7)*Integer(11)*Integer(19)*Integer(31), ... "b" + str(abs(ZZ.random_element(Integer(10)**Integer(6))))) >>> b = L.gen() >>> L_into_MS = L.hom([b.matrix()]) >>> L._unset_coercions_used() >>> L.register_embedding(L_into_MS) >>> K.coerce_embedding()(a) # needs sage.rings.number_field [ 0 1] [-462 0] >>> L.coerce_embedding()(b) # needs sage.rings.number_field [ 0 1] [-272118 0] >>> a.matrix() * b.matrix() # needs sage.rings.number_field [-272118 0] [ 0 -462] >>> a.matrix() * b.matrix() # needs sage.rings.number_field [-272118 0] [ 0 -462] 
 
- sage.structure.parent.is_Parent(x)[source]¶
- Return - Trueif x is a parent object, i.e., derives from sage.structure.parent.Parent and- Falseotherwise.- EXAMPLES: - sage: from sage.structure.parent import is_Parent sage: is_Parent(2/3) doctest:warning... DeprecationWarning: the function is_Parent is deprecated; use 'isinstance(..., Parent)' instead See https://github.com/sagemath/sage/issues/37922 for details. False sage: is_Parent(ZZ) True sage: is_Parent(Primes()) True - >>> from sage.all import * >>> from sage.structure.parent import is_Parent >>> is_Parent(Integer(2)/Integer(3)) doctest:warning... DeprecationWarning: the function is_Parent is deprecated; use 'isinstance(..., Parent)' instead See https://github.com/sagemath/sage/issues/37922 for details. False >>> is_Parent(ZZ) True >>> is_Parent(Primes()) True