Tutorial IV: Coercion and category framework
system:sage


{{{id=374|
class Demo:
    def __init__(self, data):
        self._data = data
///
}}}

{{{id=375|
d = Demo('s'); d
///
<__main__.Demo instance at 0x517c200>
}}}

{{{id=397|
d._data
///
's'
}}}

{{{id=393|
type(d), d.__class__
///
(<type 'instance'>, <class __main__.Demo at 0x5041ef0>)
}}}

{{{id=383|
class Demo:
    def __init__(self, data):
        self._data = data
    def __repr__(self):
        return "This is %s"%self._data
///
}}}

{{{id=382|
d = Demo("it"); d
///
This is it
}}}

{{{id=381|
class Demo:
    def __init__(self, data):
        self._data = data
    def __repr__(self):
        return "This is %s"%self._data
    def __mul__(self, other):
        return self.__class__(self._data + other._data)
///
}}}

{{{id=380|
d = Demo("i"); e = Demo("t")
///
}}}

{{{id=379|
d*e
///
This is it
}}}

{{{id=378|
e*d
///
This is ti
}}}

{{{id=377|
class Demo:
    def __init__(self, data):
        self._data = data
    def __repr__(self):
        return "This is %s"%self._data
    def __mul__(self, other):
        return self.__class__(self._data + other._data)
    def __iter__(self):
        for x in self._data:
            yield self.__class__(x)
///
}}}

{{{id=376|
d = Demo("i"); e = Demo("t")
///
}}}

{{{id=384|
d*e
///
This is it
}}}

{{{id=385|
list(d*e)
///
[This is i, This is t]
}}}

{{{id=392|
len(d*e)
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_92.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("bGVuKGQqZSk="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmp8F5hfU/___code___.py", line 2, in <module>
    exec compile(u'len(d*e)' + '\n', '', 'single')
  File "", line 1, in <module>
    
AttributeError: Demo instance has no attribute '__len__'
}}}

{{{id=391|
class CardFromIter(object):
    def cardinality(self):
        return len(list(self))
///
}}}

{{{id=390|
class DemoLen(Demo, CardFromIter): pass
///
}}}

{{{id=389|
e = DemoLen('bla')
///
}}}

{{{id=387|
e
///
This is bla
}}}

{{{id=386|
e.cardinality()
///
3
}}}

{{{id=394|
e.__class__.mro()
///
[<class '__main__.DemoLen'>, <class __main__.Demo at 0x5041db8>, <class '__main__.CardFromIter'>, <type 'object'>]
}}}

{{{id=396|

///
}}}

{{{id=395|

///
}}}

<h1 style="text-align: center;">How to implement new algebraic structures in Sage</h1>
<p style="text-align: center;"><span style="font-size: x-large;">Sage's category and coercion framework</span></p>
<address style="text-align: right;"><span style="font-size: small;">Simon King</span></address><address style="text-align: right;"><span style="font-size: small;">Friedrich-Schiller-Universit&auml;t Jena</span></address><address style="text-align: right;"><span style="font-size: small;">E-mail: simon dot king at uni hyphen jena dot de</span></address><address style="text-align: right;"><span style="font-size: small;">&copy;&nbsp;2011/2013</span></address><address>&nbsp;</address>
<p>The aim of this tutorial is to explain how one can benefit from Sage's category framework and coercion model when implementing new algebraic structures. It is based on a worksheet created in 2011.</p>
<p>&nbsp;There is a thematic tutorial based on this worksheet, available from your notebook via</p>
<p style="margin-left: 30px;"><strong>Help -&gt; Thematic Tutorials</strong></p>
<p style="margin-left: 60px;"><strong>-&gt; Modeling Mathematics on a computer</strong></p>
<p style="margin-left: 60px;"><strong>-&gt; How to implement basic algebraic structures in Sage</strong></p>
<p>We illustrate the concepts of Sage&rsquo;s category framework and coercion model by means of a detailed example, namely a <span style="text-decoration: underline;"><strong>toy implementation of fraction fields</strong></span>. The code is developed step by step, so that the reader can focus on one detail in each part of this tutorial.</p>
<p>&nbsp;</p>
<p><span style="text-decoration: underline;"><strong>Practical work after this presentation:</strong></span></p>
<p style="margin-left: 30px;"><strong>Implement your favourite algebraic structure, e.g., implement (a toy implementation of) group algebras.</strong></p>
<p style="margin-left: 30px;">&nbsp;</p>
<p><span style="text-decoration: underline;"><strong><span style="font-size: x-large;">Outline - for the impatient<br /></span></strong></span></p>
<p><strong>Use existing base classes</strong></p>
<p style="padding-left: 30px;">For using Sage&rsquo;s coercion system, it is essential to work with sub&ndash;classes of <a class="reference external" title="(in Sage Reference Manual: Basic Structures v5.10.rc1)"><tt class="xref py py-class docutils literal"><span class="pre">sage.structure.parent.Parent</span></tt></a> or <a class="reference external" title="(in Sage Reference Manual: Basic Structures v5.10.rc1)"><tt class="xref py py-class docutils literal"><span class="pre">sage.structure.element.Element</span></tt></a>, respectively. They provide default implementations of many &ldquo;magical&rdquo; double-underscore Python methods, which must not be overridden. Instead, the actual implementation should be in <em>single underscore</em> methods, such as <tt class="docutils literal"><span class="pre">_add_</span></tt> or <tt class="docutils literal"><span class="pre">_mul_</span></tt>.</p>
<p><strong>Turn your parent structure into an object of a category</strong></p>
<p style="padding-left: 30px;">Declare the category during initialisation&mdash;Your parent structure will inherit further useful methods and consistency tests.</p>
<p><strong>Provide your parent structure with an element class</strong></p>
<p style="padding-left: 30px;">Assign to it an attribute called <tt class="docutils literal"><span class="pre">Element</span></tt>&mdash;The elements will inherit further useful methods from the category. In addition, some basic conversions will immediately work.</p>
<p><strong>Implement further conversions<br /></strong></p>
<p style="padding-left: 30px;">Never override a parent&rsquo;s <tt class="docutils literal"><span class="pre">__call__</span></tt> method! Provide the method <tt class="docutils literal"><span class="pre">_element_constructor_</span></tt> instead.</p>
<p><strong>Declare coercions</strong></p>
<p style="padding-left: 30px;">If a conversion happens to be a morphism, you may consider to turn it into a coercion. It will then <em>implicitly</em> be used in arithmetic operations.</p>
<p><strong><span style="text-decoration: underline;">Advanced coercion:</span> Define construction functors for your parent structure</strong></p>
<p style="padding-left: 30px;">Sage will automatically create new parents for you when needed, by the so&ndash;called <a class="reference external" title="(in Sage Reference Manual: Category Theory v5.10.rc1)"><tt class="xref py py-func docutils literal"><span class="pre">pushout</span></tt></a> construction.</p>
<p><strong>Run the automatic test suites</strong></p>
<p style="padding-left: 30px;">Each method should be documented and provide a doc test (we are not giving examples here). In addition, any method defined for a category should be supported by a test method that is executed when running the test suite.</p>
<h2>Base classes</h2>
<p>In Sage, a "Parent" is an object of a category and contains elements.</p>
<p>Parents should inherit from `<span style="font-family: arial,helvetica,sans-serif;">sage.structure.parent.Parent</span>` and their elements from `<span style="font-family: arial,helvetica,sans-serif;">sage.structure.element.Element</span>`.</p>
<p>Sage provides appropriate sub-classes of <span style="font-family: arial,helvetica,sans-serif;">Parent</span> and <span style="font-family: arial,helvetica,sans-serif;">Element</span> for a variety of more concrete algebraic structures, such as groups, rings, or fields, and of their elements.</p>
<p>But some old stuff in Sage doesn't use it:</p>
<p style="text-align: center;"><span style="text-decoration: underline;">Volunteers for refactoring are welcome!</span></p>
<p>&nbsp;</p>
<p><span style="font-size: large;"><strong>The parent</strong></span></p>
<p>We want to implement a special kind of fields, namely <em>fraction fields</em>, and we should thus start with the base class `<span style="font-family: arial,helvetica,sans-serif;">sage.rings.field.Field</span>`.</p>

{{{id=3|
from sage.rings.field import Field
///
}}}

<p>This base class provides a lot more methods than a general parent:</p>

{{{id=1|
[p for p in dir(Field) if p not in dir(Parent)]
///
['__div__', '__fraction_field', '__ideal_monoid', '__iter__', '__pow__', '__rdiv__', '__rpow__', '__rxor__', '__xor__', '_an_element', '_an_element_c', '_an_element_impl', '_coerce_', '_coerce_c', '_coerce_impl', '_coerce_self', '_coerce_try', '_default_category', '_gens', '_gens_dict', '_has_coerce_map_from', '_ideal_class_', '_latex_names', '_list', '_one_element', '_pseudo_fraction_field', '_random_nonzero_element', '_richcmp', '_unit_ideal', '_zero_element', '_zero_ideal', 'algebraic_closure', 'base_extend', 'cardinality', 'class_group', 'coerce_map_from_c', 'coerce_map_from_impl', 'content', 'divides', 'extension', 'fraction_field', 'gcd', 'gen', 'gens', 'get_action_c', 'get_action_impl', 'has_coerce_map_from_c', 'has_coerce_map_from_impl', 'ideal', 'ideal_monoid', 'integral_closure', 'is_commutative', 'is_field', 'is_finite', 'is_integral_domain', 'is_integrally_closed', 'is_noetherian', 'is_prime_field', 'is_ring', 'is_subring', 'is_zero', 'krull_dimension', 'list', 'ngens', 'one', 'one_element', 'order', 'prime_subfield', 'principal_ideal', 'quo', 'quotient', 'quotient_ring', 'random_element', 'unit_ideal', 'zero', 'zero_element', 'zero_ideal', 'zeta', 'zeta_order']
}}}

{{{id=372|
Field.is_finite??
///
<html><!--notruncate-->

<div class="docstring">
    
  <p><strong>File:</strong> /home/simon/SAGE/prerelease/sage-5.10.rc1/devel/sage/sage/rings/ring.pyx</p>
<p><strong>Source Code</strong> (starting at line 1027):</p>
<div class="highlight-python"><div class="highlight"><pre class="literal-block"><span class="k">def</span> <span class="nf">is_finite</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return ``True`` if this ring is finite.</span>

<span class="sd">    EXAMPLES::</span>

<span class="sd">        sage: QQ.is_finite()</span>
<span class="sd">        False</span>
<span class="sd">        sage: GF(2^10,&#39;a&#39;).is_finite()</span>
<span class="sd">        True</span>
<span class="sd">        sage: R.&lt;x&gt; = GF(7)[]</span>
<span class="sd">        sage: R.is_finite()</span>
<span class="sd">        False</span>
<span class="sd">        sage: S.&lt;y&gt; = R.quo(x^2+1)</span>
<span class="sd">        sage: S.is_finite()</span>
<span class="sd">        True</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_zero</span><span class="p">():</span>
        <span class="k">return</span> <span class="bp">True</span>
    <span class="k">raise</span> <span class="ne">NotImplementedError</span>
</pre></div>
</div>


</div>
</html>
}}}

{{{id=373|
Field.extension??
///
<html><!--notruncate-->

<div class="docstring">
    
  <p><strong>File:</strong> /home/simon/SAGE/prerelease/sage-5.10.rc1/devel/sage/sage/rings/ring.pyx</p>
<p><strong>Source Code</strong> (starting at line 1523):</p>
<div class="highlight-python"><div class="highlight"><pre class="literal-block"><span class="k">def</span> <span class="nf">extension</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">poly</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">names</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">embedding</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Algebraically extends self by taking the quotient ``self[x] / (f(x))``.</span>

<span class="sd">    INPUT:</span>

<span class="sd">    - ``poly`` -- A polynomial whose coefficients are coercible into</span>
<span class="sd">      ``self``</span>

<span class="sd">    - ``name`` -- (optional) name for the root of `f`</span>

<span class="sd">    .. NOTE::</span>

<span class="sd">        Using this method on an algebraically complete field does *not*</span>
<span class="sd">        return this field; the construction ``self[x] / (f(x))`` is done</span>
<span class="sd">        anyway.</span>

<span class="sd">    EXAMPLES::</span>

<span class="sd">        sage: R = QQ[&#39;x&#39;]</span>
<span class="sd">        sage: y = polygen(R)</span>
<span class="sd">        sage: R.extension(y^2 - 5, &#39;a&#39;)</span>
<span class="sd">        Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in x over Rational Field with modulus a^2 - 5</span>

<span class="sd">    ::</span>

<span class="sd">        sage: F.&lt;a&gt; = GF(5).extension(x^2 - 2)</span>
<span class="sd">        sage: P.&lt;t&gt; = F[]</span>
<span class="sd">        sage: R.&lt;b&gt; = F.extension(t^2 - a); R</span>
<span class="sd">        Univariate Quotient Polynomial Ring in b over Univariate Quotient Polynomial Ring in a over Finite Field of size 5 with modulus a^2 + 3 with modulus b^2 + 4*a</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="kn">from</span> <span class="nn">sage.rings.polynomial.polynomial_element</span> <span class="kn">import</span> <span class="n">Polynomial</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">poly</span><span class="p">,</span> <span class="n">Polynomial</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">poly</span> <span class="o">=</span> <span class="n">poly</span><span class="o">.</span><span class="n">polynomial</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="s">&quot;polynomial (=</span><span class="si">%s</span><span class="s">) must be a polynomial.&quot;</span><span class="o">%</span><span class="nb">repr</span><span class="p">(</span><span class="n">poly</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">names</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">names</span>
    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">name</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">poly</span><span class="o">.</span><span class="n">parent</span><span class="p">()</span><span class="o">.</span><span class="n">gen</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
    <span class="k">if</span> <span class="n">embedding</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">,</span> <span class="s">&quot;ring extension with prescripted embedding is not implemented&quot;</span>
    <span class="n">R</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
    <span class="n">I</span> <span class="o">=</span> <span class="n">R</span><span class="o">.</span><span class="n">ideal</span><span class="p">(</span><span class="n">R</span><span class="p">(</span><span class="n">poly</span><span class="o">.</span><span class="n">list</span><span class="p">()))</span>
    <span class="k">return</span> <span class="n">R</span><span class="o">.</span><span class="n">quotient</span><span class="p">(</span><span class="n">I</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
</pre></div>
</div>


</div>
</html>
}}}

<p>The following is a <strong>very basic implementation</strong> of fraction fields, that needs to be complemented later.</p>

{{{id=361|
class MyFrac(UniqueRepresentation, Field):
    # UniqueRepresentation provides a weak cache
    
    def __init__(self, base):
        # Fraction fields are only defined for integral domains
        if base not in IntegralDomains():
            raise ValueError, "%s is no integral domain"%base
        Field.__init__(self, base)
        
    def _repr_(self):
        # Single underscore method for string representation
        return "NewFrac(%s)"%repr(self.base())
        
    # These are implicitly used in the automated test suites below
    def base_ring(self):
        return self.base().base_ring()
    def characteristic(self):
        return self.base().characteristic()
///
}}}

<p><strong>In the following sections, we will successively add or change details of <tt class="docutils literal"><span class="pre">MyFrac</span></tt>. Rather than giving a full class definition in each step, we define new versions of <tt class="docutils literal"><span class="pre">MyFrac</span></tt> by inheriting from the previously defined version of <tt class="docutils literal"><span class="pre">MyFrac</span></tt>. In that way, we can focus on the single detail that is relevant in each section.</strong></p>
<p>Some words on this basic implementation:</p>

<p>Python uses double-underscore methods for arithemetic methods and string representations. Sage's base classes often have a default implementation.</p>
<p>Hence, <strong>implement SINGLE underscore methods _repr_, and similarly _add_, _mul_ etc.</strong></p>

{{{id=11|
MyFrac(ZZ['x'])
///
NewFrac(Univariate Polynomial Ring in x over Integer Ring)
}}}

<p>The test whether the given base is an integral domain is <strong>our first use of categories:</strong></p>

{{{id=357|
MyFrac(Integers(15))
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_106.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("TXlGcmFjKEludGVnZXJzKDE1KSk="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpJ2vdHc/___code___.py", line 3, in <module>
    exec compile(u'MyFrac(Integers(_sage_const_15 ))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "classcall_metaclass.pyx", line 330, in sage.misc.classcall_metaclass.ClasscallMetaclass.__call__ (build/cythonized/sage/misc/classcall_metaclass.c:1224)
  File "cachefunc.pyx", line 992, in sage.misc.cachefunc.WeakCachedFunction.__call__ (build/cythonized/sage/misc/cachefunc.c:5394)
  File "/home/simon/SAGE/prerelease/sage-5.10.rc1/local/lib/python2.7/site-packages/sage/structure/unique_representation.py", line 447, in __classcall__
    instance = typecall(cls, *args, **options)
  File "classcall_metaclass.pyx", line 518, in sage.misc.classcall_metaclass.typecall (build/cythonized/sage/misc/classcall_metaclass.c:1586)
  File "", line 7, in __init__
    
ValueError: Ring of integers modulo 15 is no integral domain
}}}

<p>Note that <span style="font-family: arial,helvetica,sans-serif;">UniqueRepresentation </span>automatically provides pickling, at least to some extent. And it provides a cache:</p>

{{{id=358|
loads(dumps(MyFrac(ZZ))) is MyFrac(ZZ)
///
True
}}}

<h3>The elements</h3>
<p>We use the base class :class:`sage.structure.element.FieldElement`.  Note that field elements do not require that their parent is a field:</p>

{{{id=330|
from sage.structure.element import FieldElement
FieldElement(ZZ)
///
Generic element of a structure
}}}

<p><strong><span style="text-decoration: underline;">Basic implementation of the fraction field <em>elements</em></span></strong></p>
<p style="padding-left: 30px;"><strong>Input: </strong>Numerator and denominator, which have to belong to the underlying integral domain (the "base").</p>
<p style="padding-left: 30px;">Denominator not zero, and wlog. not negative - by default, the denominator is one.</p>
<p style="padding-left: 30px;">String representation via <strong>_repr_</strong>.</p>
<p style="padding-left: 30px;">Arithmetic via _add_, _mul_. <strong>Do not override the default double underscore __add__, __mul__! </strong>Otherwise, you won't have coercion.</p>
<p>In the single underscore methods and in __cmp__, you can always assume that <strong>both arguments belong to the same parent</strong>.</p>
<p>Note the use of <span style="font-family: arial,helvetica,sans-serif;">self.__class__</span></p>

{{{id=332|
class MyElement(FieldElement):
    # Input: Numerator and denominator, that need to belong to the base of the given parent
    def __init__(self, n,d=None, parent=None):
        if parent is None:
            raise ValueError, "The parent must be provided"
        B = parent.base()
        # Default denominator is 1
        if d is None:
            d = B.one_element()
            
        # Numerator and denominator belong to the base
        if n not in B or d not in B:
            raise ValueError, "Numerator and denominator must be elements of %s"%B
        # Normalise the denominator
        if d==0:
            raise ZeroDivisionError, "The denominator must not be zero"
        if d<0:
            self.n = -n
            self.d = -d
        else:
            self.n = n
            self.d = d
        FieldElement.__init__(self,parent)
    
    # These methods are required! See below
    def numerator(self):
        return self.n
    def denominator(self):
        return self.d
        
    # Single underscore again
    def _repr_(self):
        return "(%s):(%s)"%(self.n,self.d)
        
    # FIRST USE OF COERCION MODEL:
    # We can assume that both to-be-compared elements live in the same parent.
    def __cmp__(self, other):
        return cmp(self.n*other.denominator(), other.numerator()*self.d)
        
    # Single underscore arithmetic methods
    # NOTE: Elements will later be sub-classes of MyElement. We make sure that the
    #       result will use the same sub-classes
    def _add_(self, other):
        C = self.__class__
        D = self.d*other.denominator()
        return C(self.n*other.denominator()+self.d*other.numerator(),D, self.parent())
    def _sub_(self, other):
        C = self.__class__
        D = self.d*other.denominator()
        return C(self.n*other.denominator()-self.d*other.numerator(),D, self.parent())
    def _mul_(self, other):
        C = self.__class__
        return C(self.n*other.numerator(), self.d*other.denominator(), self.parent())
    def _div_(self, other):
        C = self.__class__
        return C(self.n*other.denominator(), self.d*other.numerator(), self.parent())
///
}}}

<p>Thanks to the single underscore methods, some basic arithmetics works, <strong><span style="text-decoration: underline;">if</span></strong> we stay inside our parent structure:</p>

{{{id=339|
P = MyFrac(ZZ)
a = MyElement(3,4,P)
b = MyElement(1,2,P)
///
}}}

{{{id=340|
a+b; a-b; a*b; a/b
///
(10):(8)
(2):(8)
(3):(8)
(6):(4)
}}}

{{{id=343|
a-b == MyElement(1,4,P)
///
True
}}}

<p>We didn't implement exponentiation - but it just works:</p>

{{{id=342|
a^3
///
(27):(64)
}}}

<p>There is a default implementation of element tests. We can already do</p>

{{{id=350|
a in P
///
True
}}}

<p>since a is defined as an element of P.</p>
<p>But we can not  verify yet that the integers are contained in the fraction field of the  ring of integers:</p>

{{{id=352|
1 in P
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_115.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("MSBpbiBQ"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpNYO8Ii/___code___.py", line 3, in <module>
    exec compile(u'_sage_const_1  in P' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "parent.pyx", line 1121, in sage.structure.parent.Parent.__contains__ (build/cythonized/sage/structure/parent.c:8678)
  File "parent.pyx", line 942, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:7916)
NotImplementedError
}}}

<p>We will take care of that later.</p>
<h2>Chosing a category</h2>
<p>Sometimes the base classes do not reflect the mathematics:</p>
<p style="padding-left: 30px;">The set of <em>m</em> by <em>n</em>&nbsp; matrices over a field forms, in general, not more than a vector space. Hence, they are not implemented on top of&nbsp;<span style="font-family: arial,helvetica,sans-serif;"> sage.rings.ring.Ring</span>.</p>
<p style="padding-left: 30px;">However, if <em>m=n </em>then the matrix space is an algebra, thus, in particular is a ring.</p>
<p style="padding-left: 30px;">But their (Cython) classes coincide:</p>

{{{id=299|
MS1 = MatrixSpace(QQ,2,3)
isinstance(MS1, Ring)
///
False
}}}

{{{id=301|
MS2 = MatrixSpace(QQ,2)
isinstance(MS2, Ring)
///
False
}}}

{{{id=370|
MS1.__class__ is MS2.__class__
///
True
}}}

<p>Sage's category framework can differentiate the two cases:</p>

{{{id=313|
Rings()
///
Category of rings
}}}

{{{id=303|
MS1 in Rings()
///
False
}}}

{{{id=304|
MS2 in Rings()
///
True
}}}

<p>Surprisingly, MS2 has <em>more</em> methods than MS1, even though their classes coincide:</p>

{{{id=320|
import inspect
len([s for s in dir(MS1) if inspect.ismethod(getattr(MS1,s,None))])
///
55
}}}

{{{id=321|
len([s for s in dir(MS2) if inspect.ismethod(getattr(MS2,s,None))])
///
77
}}}

<p>Below, we will explain how this can be taken advantage of.</p>

<p>It is no surprise that our  parent P defined above knows that it belongs  to the category of fields,  as it is derived from the base class of  fields.</p>

{{{id=34|
P.category()
///
Category of fields
}}}

<p>However, we could choose a smaller category, namely the category of quotient fields.</p>
<h3>Why should one choose a category?</h3>
<p>One can provide default <strong>methods </strong><em><strong>for all objects</strong> of a category</em>, and <em><strong>for all elements</strong> of such objects</em>. Hence:</p>
<p style="padding-left: 30px;">It is an alternative way of inheriting useful stuff.</p>
<p style="padding-left: 30px;">It does not rely on implementation details, but on mathematical concepts.</p>
<p>In addition, the categories define <strong>test suites</strong> for their objects and elements. Hence, one also gets basic sanity tests for free.</p>
<p>&nbsp;</p>
<p><strong>How does this so-called <em>category framework </em>work?</strong></p>
<p style="padding-left: 30px;">Abstract base classes for the objects ("parent_class") and the elements of objects ("element_class") are provided by attributes of the category</p>
<p style="padding-left: 30px;">During initialisation of a parent, the class of the parent is <em>dynamically changed</em> into a sub-class of the category's parent class.</p>
<p style="padding-left: 30px;">Likewise, sub&ndash;classes of the category&rsquo;s element class are available for the creation of elements of the parent.</p>
<p>&nbsp;</p>
<p>Dynamic change of classes does not work in Cython. Nevertheless, method inheritance still works, by virtue of a __getattr__ method.</p>
<p style="padding-left: 30px;"><strong>=&gt;&nbsp; It is strongly recommended to use the category framework both in Python and in Cython.</strong></p>
<p>Let us see whether there is any gain in chosing the category of quotient fields instead of the category of fields:</p>

{{{id=33|
QuotientFields().parent_class, QuotientFields().element_class
///
(<class 'sage.categories.quotient_fields.QuotientFields.parent_class'>, <class 'sage.categories.quotient_fields.QuotientFields.element_class'>)
}}}

{{{id=37|
[p for p in dir(QuotientFields().parent_class) if p not in dir(Fields().parent_class)]
///
[]
}}}

{{{id=353|
[p for p in dir(QuotientFields().element_class) if p not in dir(Fields().element_class)]
///
['_derivative', 'denominator', 'derivative', 'factor', 'numerator', 'partial_fraction_decomposition']
}}}

<p>So, there is no immediate gain for the parent, but additional methods become available to our fraction field elements. Note that some of these methods are place-holders: There is no default implementation, but it is <em>required</em> (respectively is <em>optional</em>) to implement these methods:</p>

{{{id=366|
QuotientFields().element_class.denominator
///
<abstract method denominator at 0x1382a28>
}}}

{{{id=368|
from sage.misc.abstract_method import abstract_methods_of_class
abstract_methods_of_class(QuotientFields().element_class)['optional']
///
['_add_', '_mul_']
}}}

{{{id=369|
abstract_methods_of_class(QuotientFields().element_class)['required']
///
['__nonzero__', 'denominator', 'numerator']
}}}

<p>Hence, when implementing elements of a quotient field, it is <em>required</em> to implement methods returning the denominator and the numerator, and a method that tells whether the element is nonzero, and in addition, it is <em>optional</em> (but certainly recommended) to provide some arithmetic methods. If one forgets to implement the required methods, the test suites of the category framework will complain&mdash;see below.</p>
<h3>Implementing the category framework for the parent</h3>
<p>We simply need to declare the correct category by an optional argument of the field constructor, where we provide the possibility to override the default category:</p>

{{{id=39|
class MyFrac(MyFrac):
    def __init__(self, base, category=None):
        if base not in IntegralDomains():
            raise ValueError, "%s is no integral domain"%base
        Field.__init__(self, base, category=category or QuotientFields())
///
}}}

<p>When constructing instances of <span style="font-family: arial,helvetica,sans-serif;">MyFrac</span>, their class is dynamically changed into a new class <span style="font-family: arial,helvetica,sans-serif;">MyFrac_with_category</span>.</p>
<p>It is a common sub-class of <span style="font-family: arial,helvetica,sans-serif;">MyFrac</span> and of the category's parent class.</p>

{{{id=38|
P = MyFrac(ZZ)
type(P); isinstance(P,MyFrac); isinstance(P,QuotientFields().parent_class)
///
<class '__main__.MyFrac_with_category'>
True
True
}}}

<p>P inherits additional methods:</p>
<p style="padding-left: 30px;">The base class <span style="font-family: arial,helvetica,sans-serif;">&lt;Field&gt;</span> does not have a method `<span style="font-family: arial,helvetica,sans-serif;">sum</span>`. But P inherits such method from the category of commutative additive monoids</p>

{{{id=371|
hasattr(MyFrac, 'sum')
///
False
}}}

{{{id=48|
P.sum.__module__
///
'sage.categories.commutative_additive_monoids'
}}}

<p>We have seen above that we can add elements. Nevertheless, the <tt class="docutils literal"><span class="pre">sum</span></tt> method does not work, yet:</p>

{{{id=51|
a = MyElement(3,4,P)
b = MyElement(1,2,P)
c = MyElement(-1,2,P)
P.sum([a,b,c])
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_135.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("YSA9IE15RWxlbWVudCgzLDQsUCkKYiA9IE15RWxlbWVudCgxLDIsUCkKYyA9IE15RWxlbWVudCgtMSwyLFApClAuc3VtKFthLGIsY10p"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpXaSUsu/___code___.py", line 6, in <module>
    exec compile(u'P.sum([a,b,c])' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/home/simon/SAGE/prerelease/sage-5.10.rc1/local/lib/python2.7/site-packages/sage/categories/commutative_additive_monoids.py", line 141, in sum
    return sum(args, self.zero())
  File "ring.pyx", line 841, in sage.rings.ring.Ring.zero_element (build/cythonized/sage/rings/ring.c:7487)
  File "parent.pyx", line 942, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:7916)
NotImplementedError
}}}

{{{id=398|
P.sum??
///
<html><!--notruncate-->

<div class="docstring">
    
  <p><strong>File:</strong> /home/simon/SAGE/prerelease/sage-5.10.rc1/local/lib/python2.7/site-packages/sage/categories/commutative_additive_monoids.py</p>
<p><strong>Source Code</strong> (starting at line 120):</p>
<div class="highlight-python"><div class="highlight"><pre class="literal-block"><span class="k">def</span> <span class="nf">sum</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
    <span class="s">r&quot;&quot;&quot;</span>
<span class="s">    n-ary sum</span>

<span class="s">    INPUT:</span>

<span class="s">     - ``args`` -- a list (or iterable) of elements of ``self``</span>

<span class="s">    Returns the sum of the elements in `args`, as an element of `self`.</span>

<span class="s">    EXAMPLES::</span>

<span class="s">        sage: S = CommutativeAdditiveMonoids().example()</span>
<span class="s">        sage: (a,b,c,d) = S.additive_semigroup_generators()</span>
<span class="s">        sage: S.sum((a,b,a,c,a,b))</span>
<span class="s">        3*a + c + 2*b</span>
<span class="s">        sage: S.sum(())</span>
<span class="s">        0</span>
<span class="s">        sage: S.sum(()).parent() == S</span>
<span class="s">        True</span>
<span class="s">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">zero</span><span class="p">())</span>
</pre></div>
</div>


</div>
</html>
}}}

<p>The reason is that the <tt class="docutils literal"><span class="pre">sum</span></tt> method starts with the return value of <tt class="docutils literal"><span class="pre">P.zero_element()</span></tt>, which defaults to <tt class="docutils literal"><span class="pre">P(0)</span></tt>&mdash;but the conversion of integers into <tt class="docutils literal"><span class="pre">P</span></tt> is not implemented, yet.</p>
<p>&nbsp;</p>
<h3>Implementing the category framework for the elements</h3>
<p>Similar to what we have seen for parents, a new class is dynamically created that combines the element class of the parent&rsquo;s category with the class that we have implemented above. However, the category framework is implemented in a different way for elements than for parents:</p>
<ul>
<li>Provide the parent P (or its class) with an attribute called "<strong>Element</strong>", whose value is a <em>concrete</em> class.</li>
<li>The parent<em><strong> automatically</strong></em> obtains an attribute "<strong>P.element_class</strong>", that subclasses both <span style="font-family: arial,helvetica,sans-serif;">P.Element</span> and the <em>abstract </em>class <span style="font-family: arial,helvetica,sans-serif;">P.category().element_class</span>.</li>
</ul>
<p>&nbsp;Hence, for providing our fraction fields with their own element classes,<strong> we just need to add a single line to our class:</strong></p>

{{{id=54|
class MyFrac(MyFrac):
    Element = MyElement
///
}}}

<p>That little change has several benefits:</p>
<ul>
<li>We can now create elements by simply calling the parent:</li>
</ul>

{{{id=53|
P = MyFrac(ZZ)
P(1); P(2,3)
///
(1):(1)
(2):(3)
}}}

<ul>
<li>There is a method <tt class="docutils literal"><span class="pre">zero_element</span></tt> returning the expected result:</li>
</ul>

{{{id=63|
P.zero_element()
///
(0):(1)
}}}

<ul>
<li>The <tt class="docutils literal"><span class="pre">sum</span></tt> method mentioned above suddenly works:</li>
</ul>

{{{id=62|
a = MyElement(9,4,P)
b = MyElement(1,2,P)
c = MyElement(-1,2,P)
P.sum([a,b,c])
///
(36):(16)
}}}

<h3><strong>What did happen behind the scenes to make this work?</strong></h3>
<p style="padding-left: 30px;">We provided "<span style="font-family: arial,helvetica,sans-serif;">P.Element</span>", and get the class "<span style="font-family: arial,helvetica,sans-serif;">P.element_class</span>" (stored as a lazy attribute) as reward.</p>
<p style="padding-left: 30px;">It is another dynamic class, a simultaneous sub-class of MyElement and of `P.category().element_class`:</p>

{{{id=328|
P.__class__.element_class
///
<sage.misc.lazy_attribute.lazy_attribute object at 0x11e78d0>
}}}

{{{id=329|
P.element_class; type(P.element_class)
///
<class '__main__.MyFrac_with_category.element_class'>
<class 'sage.structure.dynamic_class.DynamicMetaclass'>
}}}

{{{id=64|
issubclass(P.element_class, MyElement); issubclass(P.element_class,P.category().element_class)
///
True
True
}}}

<p>The <strong>default __call__ method</strong> of P passes the arguments to <span style="font-family: arial,helvetica,sans-serif;">P.element_class</span>, adding the argument "<span style="font-family: arial,helvetica,sans-serif;">parent=P</span>".</p>
<p>This is why we are now able to create elements by calling the parent, yielding instances of the new dynamic class.</p>

{{{id=66|
type(P(2,3))
///
<class '__main__.MyFrac_with_category.element_class'>
}}}

<p><strong>Note:</strong> <em>All</em> elements of <em>P</em> should use the element class. In order to make sure that this also holds for the result of arithmetic operations, we created them as instances of <tt class="docutils literal"><span class="pre">self.__class__</span></tt> in the arithmetic methods of <tt class="docutils literal"><span class="pre">MyElement</span></tt>.</p>
<p><span style="font-family: arial,helvetica,sans-serif;">P.zero_element()</span> merely does <span style="font-family: arial,helvetica,sans-serif;">P(0) </span>and thus returns an instance of <span style="font-family: arial,helvetica,sans-serif;">P.element_class</span>. Since <span style="font-family: arial,helvetica,sans-serif;">P.sum([...])</span> starts with <span style="font-family: arial,helvetica,sans-serif;">P.zero_element()</span>, we have:</p>

{{{id=59|
type(a); isinstance(a,P.element_class); type(P.sum([a,b,c]))
///
<class '__main__.MyElement'>
False
<class '__main__.MyFrac_with_category.element_class'>
}}}

<p>The method <strong><span style="font-family: arial,helvetica,sans-serif;">factor()</span></strong> inherited from <span style="font-family: arial,helvetica,sans-serif;">P.category().element_class</span> (see above) simply works:</p>

{{{id=74|
a; a.factor(); P(6,4).factor()
///
(9):(4)
2^-2 * 3^2
2^-1 * 3
}}}

<p>But that's surprising: The element "a" is just an instance of&nbsp;<span style="font-family: arial,helvetica,sans-serif;"> MyElement</span>, not of <span style="font-family: arial,helvetica,sans-serif;">P.element_class</span>, and its class does not know about the factor method.</p>
<p>In fact, we see the above-mentioned __getattr__ at work.</p>

{{{id=85|
hasattr(type(a), 'factor'); hasattr(P.element_class, 'factor'); hasattr(a, 'factor')
///
False
True
True
}}}

<h3><strong>A first note on performance</strong></h3>
<p>The category framework is sometimes blamed for speed regressions (see trac tickets #9138 versus #11900).</p>
<p>But if the category framework is <em>used properly</em>, then it is fast. For illustration, we determine the time needed to access an attribute inherited from the element class. First, we consider an element that uses the class that we implemented above, but does not use the category framework properly:</p>

{{{id=80|
timeit('a.factor',number=1000); type(a)   # Here, the category is NOT properly used
///
1000 loops, best of 3: 1.54 µs per loop
<class '__main__.MyElement'>
}}}

<p>Now, we consider an element that is equal to <em>a</em>, but uses the category framework properly.</p>

{{{id=82|
a2 = P(9,4)          # Here, it IS properly used
a2 == a
///
True
}}}

{{{id=399|
type(a), type(a2)
///
(<class '__main__.MyElement'>, <class '__main__.MyFrac_with_category.element_class'>)
}}}

{{{id=83|
timeit('a2.factor',number=1000); type(a2)
///
1000 loops, best of 3: 378 ns per loop
<class '__main__.MyFrac_with_category.element_class'>
}}}

<p><span style="font-size: large;"><strong><span style="text-decoration: underline;">Recall</span></strong></span></p>

{{{id=402|
class MyElement(FieldElement):
    # Input: Numerator and denominator, that need to belong to the base of the given parent
    def __init__(self, n,d=None, parent=None):
        if parent is None:
            raise ValueError, "The parent must be provided"
        B = parent.base()
        # Default denominator is 1
        if d is None:
            d = B.one_element()
            
        # Numerator and denominator belong to the base
        if n not in B or d not in B:
            raise ValueError, "Numerator and denominator must be elements of %s"%B
        # Normalise the denominator
        if d==0:
            raise ZeroDivisionError, "The denominator must not be zero"
        if d<0:
            self.n = -n
            self.d = -d
        else:
            self.n = n
            self.d = d
        FieldElement.__init__(self,parent)
    
    # These methods are required! See below
    def numerator(self):
        return self.n
    def denominator(self):
        return self.d
        
    # Single underscore again
    def _repr_(self):
        return "(%s):(%s)"%(self.n,self.d)
        
    # FIRST USE OF COERCION MODEL:
    # We can assume that both to-be-compared elements live in the same parent.
    def __cmp__(self, other):
        return cmp(self.n*other.denominator(), other.numerator()*self.d)
        
    # Single underscore arithmetic methods
    # NOTE: Elements will later be sub-classes of MyElement. We make sure that the
    #       result will use the same sub-classes
    def _add_(self, other):
        C = self.__class__
        D = self.d*other.denominator()
        return C(self.n*other.denominator()+self.d*other.numerator(),D, self.parent())
    def _sub_(self, other):
        C = self.__class__
        D = self.d*other.denominator()
        return C(self.n*other.denominator()-self.d*other.numerator(),D, self.parent())
    def _mul_(self, other):
        C = self.__class__
        return C(self.n*other.numerator(), self.d*other.denominator(), self.parent())
    def _div_(self, other):
        C = self.__class__
        return C(self.n*other.denominator(), self.d*other.numerator(), self.parent())
///
}}}

{{{id=400|
class MyFrac(UniqueRepresentation, Field):
    # UniqueRepresentation provides a weak cache
    Element = MyElement
    def __init__(self, base, category=None):
        if base not in IntegralDomains():
            raise ValueError, "%s is no integral domain"%base
        Field.__init__(self, base, category=category or QuotientFields())
                
    def _repr_(self):
        # Single underscore method for string representation
        return "NewFrac(%s)"%repr(self.base())
        
    # These are implicitly used in the automated test suites below
    def base_ring(self):
        return self.base().base_ring()
    def characteristic(self):
        return self.base().characteristic()
///
}}}

{{{id=403|
P = MyFrac(ZZ); P
///
NewFrac(Integer Ring)
}}}

{{{id=404|
P(1), P.zero(), P.sum([P(1,2), P(3,4)])
///
((1):(1), (0):(1), (10):(8))
}}}

{{{id=408|
P(1)/P(1,2)
///
(2):(1)
}}}

<h3>Creating a sub-category</h3>
<p>We aim at implementing a generic `latex` method for fraction field elements, and a method for faction fields that turns a list defining a continued fraction into the corresponding fraction. For this purpoe, we create a sub-category of the category of fraction fields. Admittedly, it doesn't make much sense, mathematically; this is to show how to implement generic code in the category.</p>
<p>When we want to create a sub-category, we <strong>need to provide a method `super_categories`</strong>, that returns a list of all immediate super categories (here: category of quotient fields). The parent and element methods of a category are provided as methods of a class `ParentMethods` and `Element Methods`, as follows:</p>

{{{id=405|
latex(P(1))
///
\verb|(1):(1)|
}}}

{{{id=407|
class QuotientFieldsWithLatex(Category):
    # DO NOT create a sub-class of QuotientFields!!!!!
    # Instead, declare that QuotientFields() is a super-category.
    def super_categories(self):
        return [QuotientFields()]
    class ParentMethods:
        def continued_fraction(self, L):
            p1 = self.one()
            p2 = self.zero()
            q1 = self.zero()
            q2 = self.one()
            for a in L:
                P = self(a)*p1 + p2
                Q = self(a)*q1 + q2
                p2 = p1
                q2 = q1
                p1 = P
                q1 = Q
            return P/Q
    class ElementMethods:
        def _latex_(self):
            return r"\frac{%s}{%s}"%(self.numerator(), self.denominator())
///
}}}

{{{id=417|
P = MyFrac(ZZ, category=QuotientFieldsWithLatex())
///
}}}

{{{id=433|
latex(P(1,2))
///
\frac{1}{2}
}}}

{{{id=416|
show(latex(P(1,2)))
///
<html><script type="math/tex; mode=display">\newcommand{\Bold}[1]{\mathbf{#1}}\frac{1}{2}</script></html>
}}}

{{{id=415|
P.continued_fraction([3,7,15,1,292])
///
(103993):(33102)
}}}

{{{id=414|
RR(103993/33102)
///
3.14159265301190
}}}

<div id="cell_text_99" class="text_cell">
<h2>The Test Suites</h2>
<p>The category framework does not only provide functionality but&nbsp; also a test framework.</p>
<p><strong>"Abstract" methods</strong></p>
<p>A category can require/suggest certain parent or element methods, that the user must/should implement. This is in order to smoothly blend with the methods that already exist in Sage.</p>
<p>The methods that ought to be provided are called "abstract methods". Let us see what methods are needed for quotient fields and their elements:</p>
</div>
<div id="cell_outer_243" class="cell_visible">&nbsp;</div>

{{{id=413|
from sage.misc.abstract_method import abstract_methods_of_class
///
}}}

{{{id=412|
abstract_methods_of_class(QuotientFields().element_class)
///
{'required': ['__nonzero__', 'denominator', 'numerator'], 'optional': ['_add_', '_mul_']}
}}}

<p>Hence, the elements must provide denominator() and numerator() methods, may provide Sage's single underscore arithmetic methods (actually any ring element <em>should</em> provide them).</p>
<p><strong>_test_... methods</strong></p>
<p>If a parent or element method's name start with "_test_", it gives rise to a test in the automatic test suite.</p>
<p>For example, it is tested</p>
<ul>
<li>whether a parent P actually is an instance of the parent class of the category of P,</li>
<li>whether the user hase implemented the required abstract methods,</li>
<li>whether some defining structural properties (e.g., commutativity) hold.</li>
</ul>
<p>Here are the tests that form the test suite of quotient fields:</p>

{{{id=411|
TestSuite(P).run(verbose=True)
///
running ._test_additive_associativity() . . . pass
running ._test_an_element() . . . pass
running ._test_associativity() . . . pass
running ._test_category() . . . pass
running ._test_characteristic() . . . pass
running ._test_characteristic_fields() . . . pass
running ._test_distributivity() . . . pass
running ._test_elements() . . .
  Running the test suite of self.an_element()
  running ._test_category() . . . pass
  running ._test_eq() . . . pass
  running ._test_nonzero_equal() . . . pass
  running ._test_not_implemented_methods() . . . pass
  running ._test_pickling() . . . pass
  pass
running ._test_elements_eq_reflexive() . . . pass
running ._test_elements_eq_symmetric() . . . pass
running ._test_elements_eq_transitive() . . . pass
running ._test_elements_neq() . . . pass
running ._test_eq() . . . pass
running ._test_not_implemented_methods() . . . pass
running ._test_one() . . . pass
running ._test_pickling() . . . pass
running ._test_prod() . . . pass
running ._test_some_elements() . . . pass
running ._test_zero() . . . pass
}}}

<p>As one can see, tests are also performed on elements. There are methods that return one element or a list of some elements, relying on "typical" elements that can be found in most algebraic structures.</p>

{{{id=410|
P.an_element(); P.some_elements()
///
(2):(1)
[(2):(1)]
}}}

<p>Unfortunately, the list of elements that is returned by the default method is of length one, and that single element could also be a bit more interesting.</p>
<p>The method an_element relies on a method _an_element_, so, we implement that. We also override the some_elements method.</p>

{{{id=424|
class MyFrac(MyFrac):
    def _an_element_(self):
        a = self.base().an_element()
        b = self.base_ring().an_element()
        if (a+b)!=0:
            return self(a)**2/(self(a+b)**3)
        if b != 0:
            return self(a)/self(b)**2
        return self(a)**2*self(b)**3
    def some_elements(self):
        return [self.an_element(),self(self.base().an_element()),self(self.base_ring().an_element())]
///
}}}

{{{id=423|
P = MyFrac(ZZ['x'])
P.an_element(); P.some_elements()
///
(x^2):(x^3 + 3*x^2 + 3*x + 1)
[(x^2):(x^3 + 3*x^2 + 3*x + 1), (x):(1), (1):(1)]
}}}

{{{id=436|
TestSuite(P).run()
///
}}}

<p>We would now like to add a method that tests the `factor` method. But for this, it is needed to make the following work:</p>

{{{id=431|
P(2)^-1
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_39.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("UCgyKV4tMQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpgUpv1j/___code___.py", line 3, in <module>
    exec compile(u'P(_sage_const_2 )**-_sage_const_1 ' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "element.pyx", line 1790, in sage.structure.element.RingElement.__pow__ (sage/structure/element.c:14919)
  File "element.pyx", line 3385, in sage.structure.element.generic_power_c (sage/structure/element.c:26367)
  File "element.pyx", line 1847, in sage.structure.element.RingElement.__invert__ (sage/structure/element.c:15744)
  File "element.pyx", line 1813, in sage.structure.element.RingElement.__div__ (sage/structure/element.c:15142)
  File "coerce.pyx", line 856, in sage.structure.coerce.CoercionModel_cache_maps.bin_op (sage/structure/coerce.c:8115)
TypeError: unsupported operand parent(s) for '/': '<type 'int'>' and 'NewFrac(Univariate Polynomial Ring in x over Integer Ring)'
}}}

<p>In other words, we need that the integer 1 is <em><span style="text-decoration: underline;">automatically</span></em> converted into an element of our fraction field</p>

<h1>Coercion - the basics</h1>
<p><em>Coercion is involved if one wants to be able to do arithmetic, comparisons, etc. between elements of distinct parents.</em></p>
<h3>Theoretical background</h3>
<h4>Dissociation from <em>type conversion</em></h4>
<p style="padding-left: 30px;">In C: "coercion" means "automatic type conversion".</p>
<p style="padding-left: 30px;">In Sage<strong>: Coercion is not about a change of types, but about a change of parents.</strong></p>
<p><strong></strong>Elements of the same type may have very different parents, such as here:</p>

{{{id=77|
P1 = QQ['v,w']; P2 = ZZ['w,v']
type(P1.gen()) == type(P2.gen()); P1==P2
///
True
False
}}}

<p>P2 naturally is a sub-ring of P1. So, it makes sense to be able to add elements of the two rings - the result should then live in P1:</p>

{{{id=73|
(P1.gen()+P2.gen()).parent() is P1
///
True
}}}

<p>It would be rather inconvenient if one needed to <em>explicitly </em>convert an element of P2 into P1 before adding. The coercion system does that conversion automatically.</p>
<h4>Coercion versus conversion</h4>
<p>A coercion happens implicitly, without being explicitly requested by the user.</p>
<p>Hence, coercion must be based on mathematical rigour.</p>
<h5 style="padding-left: 30px;"><span style="font-size: large;">1. A coercion is a map, a conversion may be a <em>partial</em> map</span></h5>
<p>For example, a polynomial of degree zero over the integers can be interpreted as an integer - but there is no general conversion of a polynomial into an integer. So, that must not be a coercion.</p>
<p>Hence, coercion maps are defined on the level of parents, and they can be obtained from the following methods:</p>

{{{id=71|
P1.has_coerce_map_from(P2)
///
True
}}}

{{{id=70|
P1.coerce_map_from(P2)
///
Call morphism:
  From: Multivariate Polynomial Ring in w, v over Integer Ring
  To:   Multivariate Polynomial Ring in v, w over Rational Field
}}}

{{{id=68|
P2.has_coerce_map_from(P1)
///
False
}}}

{{{id=81|
P2.coerce_map_from(P1) is None
///
True
}}}

<h5 style="padding-left: 30px;"><span style="font-size: large;">2. A coercion is a morphism, i.e., structure preserving</span></h5>
<p>Any real number can be converted to an integer, namely by rounding. However, such a conversion is not useful in arithmetic operations:</p>

{{{id=94|
int(1.6)+int(2.7) == int(1.6+2.7)
///
False
}}}

<p>It depends on the parents which structure is to be preserved. For example, the coercion from the integers into the rational field is a homomorphism of euclidean domains:</p>

{{{id=93|
QQ.coerce_map_from(ZZ).category_for()
///
Category of euclidean domains
}}}

<p>Hence, categories show up in coercion, too.<span style="font-size: large;"><br /></span></p>
<h5 style="padding-left: 30px;"><span style="font-size: large;">3. If a coercion exists, it has to be unique, and must coincide with conversion<br /></span></h5>
<h5 style="margin-left: 30px;"><span style="font-size: large;">4. Coercions can be composed</span></h5>
<p>If there is a coercion &phi; from P1 to P2 and another coercion &psi; from P2 to P3, then the composition of &phi; followed by &psi; must yield a (the) coercion from P1 to P3.</p>
<h5 style="padding-left: 30px;"><span style="font-size: large;">5. The identity is a coercion</span></h5>
<p>Together with the two preceding requirements, it follows: If there are conversions from P1 to P2 and from P2 to P1, then they are mutually inverse.</p>
<p>&nbsp;</p>
<h3>Implementing conversion</h3>
<p>We implement some conversions into our fraction fields by simply providing the attribute "Element".</p>
<p>However, we can not convert elements of a fraction field into elements of another fraction field, yet:</p>
<p>&nbsp;</p>

{{{id=218|
P(2/3)
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_48.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("UCgyLzMp"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpmkunMP/___code___.py", line 3, in <module>
    exec compile(u'P(_sage_const_2 /_sage_const_3 )' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "parent.pyx", line 961, in sage.structure.parent.Parent.__call__ (sage/structure/parent.c:8070)
  File "coerce_maps.pyx", line 82, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (sage/structure/coerce_maps.c:3821)
  File "coerce_maps.pyx", line 77, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (sage/structure/coerce_maps.c:3723)
  File "/home/simon/SAGE/prerelease/sage-5.9.rc0/local/lib/python2.7/site-packages/sage/categories/sets_cat.py", line 339, in _element_constructor_from_element_class
    return self.element_class(parent = self, *args, **keywords)
  File "", line 13, in __init__
    
ValueError: Numerator and denominator must be elements of Univariate Polynomial Ring in x over Integer Ring
}}}

<p>For implementing a conversion, <strong>the default<span style="font-family: arial,helvetica,sans-serif;"> __call__</span> method should (almost) never be overridden. </strong>Again, some old parents violate that rule - please help to refactor them!</p>
<p>Instead,<strong> implement the method <span style="font-family: arial,helvetica,sans-serif;">_element_constructor_</span></strong>,  that should return an instance of the parent's element class.</p>

{{{id=111|
class MyFrac(MyFrac):
    def _element_constructor_(self, *args,**kwds):
        # If numerator and denominator are given, then
        # no preprocessing is needed
        if len(args)!=1:
            return self.element_class(*args,parent=self,**kwds)
            
        # Only one argument is given---analyse it!
        x = args[0]
        try:
            # Does it have a parent?
            P = x.parent()
        except AttributeError:
            # If not, fall back to the default
            return self.element_class(x,parent=self,**kwds)
            
        # If x belongs to a "friendly" quotient field, then use its numerator/denominator
        if P in QuotientFields() and P != self.base():
            return self.element_class(x.numerator(),x.denominator(),parent=self,**kwds)
        return self.element_class(x,parent=self,**kwds)
///
}}}

<p>In addition to the conversion from the base ring and from pairs of base ring elements, we now also have a conversion from the rationals to our fraction field of ZZ:</p>

{{{id=242|
P = MyFrac(ZZ)
P(2); P(2,3); P(3/4)
///
(2):(1)
(2):(3)
(3):(4)
}}}

<p>Recall that above, the test "1 in P" failed with an error. Since we can now convert the integer 1 into P, the error has vanished. But there is still a negative outcome:</p>

{{{id=292|
1 in P
///
False
}}}

<p>The technical reason: We have a conversion P(1) of 1 into P, but this is not a coercion.</p>

{{{id=129|
P.has_coerce_map_from(ZZ), P.has_coerce_map_from(QQ)
///
(False, False)
}}}

<h3>How to turn a conversion into a coercion</h3>
<ul>
<li><em>Could</em> use <span style="font-family: arial,helvetica,sans-serif;">P.register_coercion</span> during initialisation (see documentation of that method).</li>
<li>More flexible: Provide a method <span style="font-family: arial,helvetica,sans-serif;">_coerce_map_from_</span>&nbsp;</li>
</ul>
<p><span style="font-family: arial,helvetica,sans-serif;">_coerce_map_from_</span> accepts a parent as argument. If it returns "True", then conversion is used for coercion (but it may return an actual map).</p>
<p>Note that we need a special case for the rational field, since QQ.base() is not the ring of integers.</p>

{{{id=136|
class MyFrac(MyFrac):
    def _coerce_map_from_(self, S):
        # Coercion from the base ring:
        if self.base().has_coerce_map_from(S):
            return True
            
        # Coercion from the fraction field of a "good" ring
        if S in QuotientFields():
            if self.base().has_coerce_map_from(S.base()):
                return True
            # QQ is special
            if hasattr(S,'ring_of_integers') and self.base().has_coerce_map_from(S.ring_of_integers()):
                return True
///
}}}

<p>By the method above, a parent coercing into the base ring will also coerce into the fraction field, and a fraction field coerces into another fraction field if there is a coercion of the corresponding base rings. Now, we have:</p>

{{{id=126|
P = MyFrac(QQ['x'])
P.has_coerce_map_from(ZZ['x']), P.has_coerce_map_from(Frac(ZZ['x'])), P.has_coerce_map_from(QQ)
///
(True, True, True)
}}}

<p>We can now use coercion from ZZ['x'] and from QQ into P for arithmetic operations between the two rings:</p>

{{{id=125|
3/4+P(2)+ZZ['x'].gen(); (P(2)+ZZ['x'].gen()).parent() is P
///
(4*x + 11):(4)
True
}}}

<h3>Equality and element containment</h3>
<p>Recall that above, the test "1 in P" had a negative outcome. Let us repeat the test now:</p>

{{{id=124|
1 in P
///
True
}}}

<p>Why is that?</p>
<p>The default element containment test "x in P" is based on the interplay of three building blocks: conversion, coercion and equality test.</p>
<ol>
<li>Clearly, if the conversion P(x) raises an error, then x can not be seen as an element of P. On the other hand, a conversion P(x) can in general do very nasty things. So, the fact that P(x) works does not mean that x is in P.</li>
<li>If x is in P, then the conversion P(x) should not change x (at least, that's the default). Hence, we will have x==P(x).</li>
<li>Sage uses coercion not only for arithmetic operations, but also for comparison. Hence, if there is a coercion between the parent of x and P, then it will be applied. <em>If</em> there is a coercion from x.parent() to P then x==P(x) reduces to P(x)==P(x). Otherwise, x==P(x) will evaluate as false.</li>
</ol>
<p>That leads to the following default implementation of element containment testing:</p>
<p style="padding-left: 30px;"><strong>"x in P" holds if and only if "x==P(x)" does not raise an error and evaluates as true</strong></p>
<p>If the user is not happy with that behaviour, the "magical" Python method __contains__ can be overridden.</p>
<h2>Coercion - the advanced parts</h2>
<p>So far, we are able to add integers and rational numbers to elements of our new implementation of the fraction field of ZZ.</p>

{{{id=123|
P = MyFrac(ZZ)
///
}}}

{{{id=122|
1/2+P(2,3)+1
///
(13):(6)
}}}

<p>Surprisingly, we can even add a polynomial over the integers to an element of P, even though the <strong>result lives in a new parent</strong>, namely in a polynomial ring over P:</p>

{{{id=121|
P(1/2) + ZZ['x'].gen(), (P(1/2) + ZZ['x'].gen()).parent() is P['x']
///
((1):(1)*x + (1):(2), True)
}}}

<p>In the next, seemingly more easy example, there "obviously" is a coercion from the fraction field of ZZ to the fraction field of ZZ['x'].</p>
<p>However, Sage does not know enough about our new implementation of fraction fields. Hence, it does not recognise the coercion:</p>

{{{id=120|
Frac(ZZ['x']).has_coerce_map_from(P)
///
False
}}}

<p><strong>How / why has the new ring been constructed above?</strong></p>
<p><strong>How can we establish a coercion from<span style="font-family: arial,helvetica,sans-serif;"> P</span> to <span style="font-family: arial,helvetica,sans-serif;">Frac(ZZ['x'])</span>?</strong></p>
<p style="padding-left: 30px;">Most parents can be constructed from simpler pieces.</p>
<p style="padding-left: 30px;">If we are lucky, a parent can tell how it has been constructed:</p>

{{{id=119|
Poly,R = QQ[x].construction()
Poly,R
///
(Poly[x], Rational Field)
}}}

{{{id=118|
Poly(R) is QQ['x']; Poly(ZZ) is ZZ['x']; Poly(P) is P['x']
///
True
True
True
}}}

{{{id=117|
Fract,R = QQ.construction()
Fract,R
///
(FractionField, Integer Ring)
}}}

<p>These constructions are functorial:</p>
<p style="padding-left: 30px;">Frac: IntegralDomains() --&gt; Fields()</p>
<p style="padding-left: 30px;">Poly[x]: Rings() --&gt; Rings()</p>
<p>In particular, the construction functors can be composed:</p>

{{{id=116|
Poly*Fract
///
Poly[x](FractionField(...))
}}}

{{{id=115|
(Poly*Fract)(ZZ) is QQ[x]
///
True
}}}

<p>In addition, it is assumed that we have a coercion from input to output of the construction functor:</p>

{{{id=356|
((Poly*Fract)(ZZ))._coerce_map_from_(ZZ)
///
Composite map:
  From: Integer Ring
  To:   Univariate Polynomial Ring in x over Rational Field
  Defn:   Natural morphism:
          From: Integer Ring
          To:   Rational Field
        then
          Polynomial base injection morphism:
          From: Rational Field
          To:   Univariate Polynomial Ring in x over Rational Field
}}}

<p>Construction functors do not necessarily commute:</p>

{{{id=164|
(Fract*Poly)(ZZ)
///
Fraction Field of Univariate Polynomial Ring in x over Integer Ring
}}}

<p><strong>Given:</strong></p>
<p>We have parents P1, P2, R and construction functors F1, F2, such that</p>
<p style="padding-left: 30px;">P1 = F1(R) and P2 = F2(R)</p>
<p><strong>Wanted:</strong></p>
<p>Find new construction functor F3, such that both P1 and P2 coerce into P3=F3(R).</p>
<p>In analogy to a notion of category theory, P3 is called the <em>pushout</em> of P1 and P2; and similarly F3 is called the pushout of F1 and F2.</p>

{{{id=110|
from sage.categories.pushout import pushout
pushout(Fract(ZZ),Poly(ZZ))
///
Univariate Polynomial Ring in x over Rational Field
}}}

<p>F1*F2 and F2*F1 are natural candidates for the pushout of F1 and F2. However, the result must not depend on the order</p>
<p style="padding-left: 30px;">=&gt; We need a consistent choice of order: "indecomposable" construction functors have a <strong>rank</strong>.</p>
<p style="padding-left: 30px;">If <span style="font-family: arial,helvetica,sans-serif;">F1.rank</span> is smaller than<span style="font-family: arial,helvetica,sans-serif;"> F2.rank</span>, then the pushout is F2*F1 (hence, F1 is applied first).</p>
<p>We have</p>

{{{id=137|
Fract.rank, Poly.rank
///
(5, 9)
}}}

<p>and thus the pushout is</p>

{{{id=152|
Fract.pushout(Poly), Poly.pushout(Fract)
///
(Poly[x](FractionField(...)), Poly[x](FractionField(...)))
}}}

<p>This is why the example above has worked.</p>
<p>However, only "elementary" construction functors have a rank:</p>

{{{id=170|
(Fract*Poly).rank
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_71.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("KEZyYWN0KlBvbHkpLnJhbms="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpUZ2aqs/___code___.py", line 2, in <module>
    exec compile(u'(Fract*Poly).rank' + '\n', '', 'single')
  File "", line 1, in <module>
    
AttributeError: 'CompositeConstructionFunctor' object has no attribute 'rank'
}}}

<p><strong>What do we do with two <em>chains </em>of construction functors?</strong></p>
<p>Shuffle the functors from the two chains (F1,F2,...) and (G1,G2,...):</p>
<p style="padding-left: 30px;">If <span style="font-family: arial,helvetica,sans-serif;">F1.rank &lt; G1.rank</span>: Apply F1, and proceed with (F2,F3,...) and (G1,G2,...).</p>
<p style="padding-left: 30px;">If <span style="font-family: arial,helvetica,sans-serif;">F1.rank &gt; G1.rank</span>: Apply G1, and proceed with (F1,F2,...) and (G2,G3,...).</p>
<p style="padding-left: 30px;">If F1.rank == G1.rank, then we need other techniques (see below).</p>
<p>As an illustration, we first get us some functors and then see how chains of functors are shuffled.</p>

{{{id=169|
AlgClos, R = CC.construction(); AlgClos
///
AlgebraicClosureFunctor
}}}

{{{id=168|
Compl, R = RR.construction(); Compl
///
Completion[+Infinity]
}}}

{{{id=167|
Matr, R = (MatrixSpace(ZZ,3)).construction(); Matr
///
MatrixFunctor
}}}

{{{id=166|
AlgClos.rank, Compl.rank, Fract.rank, Poly.rank, Matr.rank
///
(3, 4, 5, 9, 10)
}}}

<p>When we apply Fract, AlgClos, Poly and Fract to the ring of integers, we obtain</p>

{{{id=194|
(Fract*Poly*AlgClos*Fract)(ZZ)
///
Fraction Field of Univariate Polynomial Ring in x over Algebraic Field
}}}

<p>When we apply Compl, Matr and Poly to the ring of integers, we obtain</p>

{{{id=205|
(Poly*Matr*Compl)(ZZ)
///
Univariate Polynomial Ring in x over Full MatrixSpace of 3 by 3 dense matrices over Real Field with 53 bits of precision
}}}

<p>Applying the shuffling procedure yields</p>

{{{id=204|
(Poly*Matr*Fract*Poly*AlgClos*Fract*Compl)(ZZ)
///
Univariate Polynomial Ring in x over Full MatrixSpace of 3 by 3 dense matrices over Fraction Field of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
}}}

<p>and this is indeed equal to the pushout found by Sage:</p>

{{{id=202|
pushout((Fract*Poly*AlgClos*Fract)(ZZ), (Poly*Matr*Compl)(ZZ))
///
Univariate Polynomial Ring in x over Full MatrixSpace of 3 by 3 dense matrices over Fraction Field of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
}}}

<p><strong>The case <span style="font-family: arial,helvetica,sans-serif;">F1.rank==G1.rank</span></strong></p>
<p>Sage's pushout constructions offers two ways to proceed:</p>
<ol>
<li>Construction functors have a method `<span style="font-family: arial,helvetica,sans-serif;"><strong>merge()</strong></span>` that either returns None or returns a construction functor. If either F1.merge(G1) or <span style="font-family: arial,helvetica,sans-serif;">G1.merge(F1)</span> return a functor H1, then apply H1 and proceed with (F2,F3,...) and (G2,G3,...).</li>
<li>Construction functors have a method `<span style="font-family: arial,helvetica,sans-serif;"><strong>commutes()</strong></span>`. If F1.commutes(G1) or G1.commutes(F1) returns True, then apply both F1 and G1 in any order, and proceed with (F2,F3,...) and (G2,G3,...).</li>
</ol>
<p>By default, <span style="font-family: arial,helvetica,sans-serif;">F1.merge(G1)</span> returns <span style="font-family: arial,helvetica,sans-serif;">F1</span> if <span style="font-family: arial,helvetica,sans-serif;">F1==G1</span>, and returns <span style="font-family: arial,helvetica,sans-serif;">None</span> otherwise.</p>
<p>The `<span style="font-family: arial,helvetica,sans-serif;">commutes</span><span style="font-family: arial,helvetica,sans-serif;">()</span>` method exists, but it seems that so far nobody has implemented two functors of the same rank that commute.</p>
<p><strong>The typical application of `<span style="font-family: arial,helvetica,sans-serif;">merge()</span>` is:</strong></p>
<p style="padding-left: 30px;"><strong>Provide coercion between different implementations of the same algebraic structure</strong></p>
<p>If F1(P) and F2(P) are different implementations of the same thing, then <span style="font-family: arial,helvetica,sans-serif;">F1.merge(F2)(P)</span> should be the default implementation of that thing.</p>
<p>Here:</p>
<ul>
<li>Implement an alternative to the "usual" fraction field functor, having the same rank, but returning our new implementation.</li>
<li>Make our new implementation the default, by providing a merge method.</li>
</ul>
<p>Remark:</p>
<ul>
<li><strong>Do not override the default __call__ method </strong>-- implement `_apply_functor` instead.</li>
<li>Declare <strong>domain</strong> and <strong>codomain</strong> of the functor.</li>
</ul>

{{{id=200|
from sage.categories.pushout import ConstructionFunctor
class MyFracFunctor(ConstructionFunctor):
    rank = 5
    def __init__(self):
        ConstructionFunctor.__init__(self, IntegralDomains(), Fields())
    def _apply_functor(self, R):
        return MyFrac(R)
    def merge(self, other):
        if isinstance(other, (type(self), sage.categories.pushout.FractionField)):
            return self
///
}}}

{{{id=312|
MyFracFunctor()
///
MyFracFunctor
}}}

<p>We verify that our functor can really be used to construct our implementation of fraction fields, and that it can be merged with either itself or the usual fraction field constructor:</p>

{{{id=198|
MyFracFunctor()(ZZ)
///
NewFrac(Integer Ring)
}}}

{{{id=197|
MyFracFunctor().merge(MyFracFunctor())
///
MyFracFunctor
}}}

{{{id=196|
MyFracFunctor().merge(Fract)
///
MyFracFunctor
}}}

<p>There remains to let our new fraction fields know about the new construction functor:</p>

{{{id=229|
class MyFrac(MyFrac):
    def construction(self):
        return MyFracFunctor(), self.base()
///
}}}

{{{id=235|
MyFrac(ZZ['x']).construction()
///
(MyFracFunctor, Univariate Polynomial Ring in x over Integer Ring)
}}}

<p>Due to merging, we have:</p>

{{{id=195|
pushout(MyFrac(ZZ['x']), Frac(QQ['x']))
///
NewFrac(Univariate Polynomial Ring in x over Rational Field)
}}}

<h5><span style="font-size: large;">Adding a new test<br /></span></h5>
<p>Now, as we have more&nbsp; interesting elements, we may also add a test for the "factor" method. Recall that the method was inherited from the category, but it appears that it is not tested.</p>
<p>Normally, a test for a method defined by a category should be provided by the same category. Hence, since `factor()` is defined in the category of quotient fields, a test should be added there. But we won't change source code here and will instead create another sub-category.</p>
<p>Apparently, the product of the factors returned be `e.factor()` should be equal to `e`. For forming the product, we use the `prod()` method, that, no surprise, is inherited from another category.</p>

{{{id=271|
P.prod.__module__
///
'sage.categories.monoids'
}}}

<p>We provide an instance of our quotient field implementation with that new category. Note that categories have a default _repr_ method, that guesses a good string representation from the name of the class: QuotientFieldsWithTest becomes "quotient fields with test".</p>

{{{id=438|
from sage.categories.category import Category
class QuotientFieldsWithTest(Category): # do *not* inherit from QuotientFields, but ...
    def super_categories(self):
        return [QuotientFields()]       # ... declare QuotientFields as a super category!
    class ParentMethods:
        # Simply keep the stuff inherited from the super category
        pass
    class ElementMethods:
        # Add the new test
        def _test_factorisation(self, **options):
            P = self.parent()
            assert self == P.prod([P(b)**e for b,e in self.factor()])
///
}}}

{{{id=278|
P = MyFrac(ZZ['x'], category=QuotientFieldsWithTest())
P.category()
///
Category of quotient fields with test
}}}

<p>The new test is inherited from the category. Since an_element() is returning a complicated element, _test_factorisation is a serious test.</p>

{{{id=279|
P.an_element()._test_factorisation
///
<bound method MyFrac_with_category.element_class._test_factorisation of (x^2):(x^3 + 3*x^2 + 3*x + 1)>
}}}

{{{id=272|
P.an_element().factor()
///
(x + 1)^-3 * x^2
}}}

<p>Last, we observe that the new test has automatically become part of the test suite. We remark that the existing test became more serious as well, by an_element() returning something more interesting.</p>

{{{id=273|
TestSuite(P).run(verbose=True)
///
running ._test_additive_associativity() . . . pass
running ._test_an_element() . . . pass
running ._test_associativity() . . . pass
running ._test_category() . . . pass
running ._test_characteristic() . . . pass
running ._test_characteristic_fields() . . . pass
running ._test_distributivity() . . . pass
running ._test_elements() . . .
  Running the test suite of self.an_element()
  running ._test_category() . . . pass
  running ._test_eq() . . . pass
  running ._test_factorisation() . . . pass
  running ._test_nonzero_equal() . . . pass
  running ._test_not_implemented_methods() . . . pass
  running ._test_pickling() . . . pass
  pass
running ._test_elements_eq_reflexive() . . . pass
running ._test_elements_eq_symmetric() . . . pass
running ._test_elements_eq_transitive() . . . pass
running ._test_elements_neq() . . . pass
running ._test_eq() . . . pass
running ._test_not_implemented_methods() . . . pass
running ._test_one() . . . pass
running ._test_pickling() . . . pass
running ._test_prod() . . . pass
running ._test_some_elements() . . . pass
running ._test_zero() . . . pass
}}}

{{{id=443|

///
}}}