Skip to content

Commit

Permalink
Trac #20767: Move coercion to Element
Browse files Browse the repository at this point in the history
This ticket has 2 main changes:

1. Move all coercion logic from `RingElement`, `ModuleElement` and the
like to `Element`.

Because of this, it matters a lot less whether a class inherits from
`Element` or from `ModuleElement`/`RingElement`/`FieldElement`...

One difference remains: the more specialized classes have some default
implementations for arithmetic. For example, `ModuleElement` implements
unary negation as multiplication by -1. The base class `Element` has no
such default implementations.

This patch also affects lookup in categories: with this patch, double-
underscore methods like `__add__` are never taken from the category. The
`Element` classes take precedence over the category, so the default
implementations of arithmetic operations will override whatever is in
the category (this is existing behaviour, not affected by this patch).
For the base class `Element`, this is not an issue since there are no
default implementations.

2. Change the implementation of double-underscore methods like `__add__`
to return `NotImplemented` (rather than raise an error) if one argument
is not a Sage `Element` and coercion fails.

This will cause Python to try the reversed operation (`__radd__` or
`__add__` in Cython). This way, Sage has improved support for operations
with non-Sage types.

URL: https://trac.sagemath.org/20767
Reported by: jdemeyer
Ticket author(s): Jeroen Demeyer
Reviewer(s): Nicolas M. Thiéry
  • Loading branch information
Release Manager authored and vbraun committed Oct 3, 2016
2 parents b711d97 + 25c9d7d commit be7c0f8
Show file tree
Hide file tree
Showing 18 changed files with 1,410 additions and 1,108 deletions.
32 changes: 1 addition & 31 deletions src/sage/categories/additive_magmas.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
from sage.categories.cartesian_product import CartesianProductsCategory
from sage.categories.homsets import HomsetsCategory
from sage.categories.with_realizations import WithRealizationsCategory
import sage.categories.coercion_methods
from sage.categories.sets_cat import Sets
from sage.structure.element import have_same_parent

class AdditiveMagmas(Category_singleton):
"""
Expand Down Expand Up @@ -390,9 +388,6 @@ def addition_table(self, names='letters', elements=None):

class ElementMethods:

__add__ = sage.categories.coercion_methods.__add__
__radd__ = sage.categories.coercion_methods.__radd__

@abstract_method(optional = True)
def _add_(self, right):
"""
Expand Down Expand Up @@ -805,27 +800,6 @@ def _test_nonzero_equal(self, **options):
tester.assertEqual(bool(self), self != self.parent().zero())
tester.assertEqual(not self, self == self.parent().zero())

def __sub__(left, right):
"""
Return the difference between ``left`` and ``right``, if it exists.
This top-level implementation delegates the work to
the ``_sub_`` method or to coercion. See the extensive
documentation at the top of :ref:`sage.structure.element`.
EXAMPLES::
sage: F = CombinatorialFreeModule(QQ, ['a','b'])
sage: a,b = F.basis()
sage: a - b
B['a'] - B['b']
"""
if have_same_parent(left, right):
return left._sub_(right)
from sage.structure.element import get_coercion_model
import operator
return get_coercion_model().bin_op(left, right, operator.sub)

def _sub_(left, right):
r"""
Default implementation of difference.
Expand Down Expand Up @@ -865,10 +839,6 @@ def __neg__(self):
TESTS::
sage: b.__neg__.__module__
'sage.categories.additive_magmas'
sage: b._neg_.__module__
'sage.combinat.free_module'
sage: F = CombinatorialFreeModule(ZZ, ['a','b'])
sage: a,b = F.gens()
sage: FF = cartesian_product((F,F))
Expand Down Expand Up @@ -940,7 +910,7 @@ def extra_super_categories(self):
return [AdditiveMagmas().AdditiveUnital().AdditiveInverse()]

class ElementMethods:
def __neg__(self):
def _neg_(self):
"""
Return the negation of ``self``.
Expand Down
27 changes: 0 additions & 27 deletions src/sage/categories/associative_algebras.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,31 +43,4 @@ class AssociativeAlgebras(CategoryWithAxiom_over_base_ring):
"""
_base_category_class_and_axiom = (MagmaticAlgebras, "Associative")

class ElementMethods:
"""
An abstract class for elements of an associative algebra.
.. NOTE::
``Magmas.Element.__mul__`` is preferable to
``Modules.Element.__mul__`` since the later does not
handle products of two elements of ``self``.
TESTS::
sage: A = AlgebrasWithBasis(QQ).example(); A
An example of an algebra with basis: the free algebra
on the generators ('a', 'b', 'c') over Rational Field
sage: x = A.an_element()
sage: x
B[word: ] + 2*B[word: a] + 3*B[word: b] + B[word: bab]
sage: x.__mul__(x)
B[word: ] + 4*B[word: a] + 4*B[word: aa] + 6*B[word: ab]
+ 2*B[word: abab] + 6*B[word: b] + 6*B[word: ba]
+ 2*B[word: bab] + 2*B[word: baba] + 3*B[word: babb]
+ B[word: babbab] + 9*B[word: bb] + 3*B[word: bbab]
"""
__mul__ = Magmas.ElementMethods.__mul__.__func__


Unital = LazyImport('sage.categories.algebras', 'Algebras', at_startup=True)
Loading

0 comments on commit be7c0f8

Please sign in to comment.