From ea74b6ffc5d7d50e62bb95065c41da4ffe73888c Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 5 Apr 2017 12:05:43 +0200 Subject: [PATCH 1/2] Add support for __matmul__ in the coercion model --- src/sage/structure/element.pxd | 1 + src/sage/structure/element.pyx | 102 +++++++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index a6838d8c6b1..0cf62031091 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -165,6 +165,7 @@ cdef class Element(SageObject): cdef _mul_(self, other) cdef _mul_long(self, long n) + cdef _matmul_(self, other) cdef _div_(self, other) cdef _floordiv_(self, other) cdef _mod_(self, other) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 86ce7e9c730..516c9608224 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -294,14 +294,14 @@ from cpython.ref cimport PyObject from sage.ext.stdsage cimport * import types -cdef add, sub, mul, truediv, floordiv, mod, pow +cdef add, sub, mul, truediv, floordiv, mod, matmul, pow cdef iadd, isub, imul, itruediv, ifloordiv, imod, ipow -from operator import (add, sub, mul, truediv, floordiv, mod, pow, - iadd, isub, imul, itruediv, ifloordiv, imod, ipow) +from operator import (add, sub, mul, truediv, floordiv, mod, matmul, pow, + iadd, isub, imul, itruediv, ifloordiv, imod, imatmul, ipow) cdef dict _coerce_op_symbols = dict( - add='+', sub='-', mul='*', truediv='/', floordiv='//', mod='%', pow='^', - iadd='+', isub='-', imul='*', itruediv='/', ifloordiv='//', imod='%', ipow='^') + add='+', sub='-', mul='*', truediv='/', floordiv='//', mod='%', matmul='@', pow='^', + iadd='+', isub='-', imul='*', itruediv='/', ifloordiv='//', imod='%', imatmul='@', ipow='^') from sage.structure.richcmp cimport rich_to_bool from sage.structure.coerce cimport py_scalar_to_element, coercion_model @@ -1578,6 +1578,98 @@ cdef class Element(SageObject): """ return coercion_model.bin_op(self, n, mul) + def __matmul__(left, right): + """ + Top-level matrix multiplication operator for :class:`Element` + invoking the coercion model. + + See :ref:`element_arithmetic`. + + EXAMPLES:: + + sage: from sage.structure.element import Element + sage: class MyElement(Element): + ....: def _matmul_(self, other): + ....: return 42 + sage: e = MyElement(Parent()) + sage: from operator import matmul + sage: matmul(e, e) + 42 + + TESTS:: + + sage: e = Element(Parent()) + sage: matmul(e, e) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for @: '' and '' + sage: matmul(1, e) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for @: 'Integer Ring' and '' + sage: matmul(e, 1) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for @: '' and 'Integer Ring' + sage: matmul(int(1), e) + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for @: 'int' and 'sage.structure.element.Element' + sage: matmul(e, int(1)) + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for @: 'sage.structure.element.Element' and 'int' + sage: matmul(None, e) + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for @: 'NoneType' and 'sage.structure.element.Element' + sage: matmul(e, None) + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for @: 'sage.structure.element.Element' and 'NoneType' + """ + cdef int cl = classify_elements(left, right) + if HAVE_SAME_PARENT(cl): + return (left)._matmul_(right) + if BOTH_ARE_ELEMENT(cl): + return coercion_model.bin_op(left, right, matmul) + + try: + return coercion_model.bin_op(left, right, matmul) + except TypeError: + return NotImplemented + + cdef _matmul_(self, other): + """ + Virtual matrix multiplication method for elements with + identical parents. + + This default Cython implementation of ``_matmul_`` calls the + Python method ``self._matmul_`` if it exists. This method may + be defined in the ``ElementMethods`` of the category of the + parent. If the method is not found, a ``TypeError`` is raised + indicating that the operation is not supported. + + See :ref:`element_arithmetic`. + + EXAMPLES: + + This method is not visible from Python:: + + sage: from sage.structure.element import Element + sage: e = Element(Parent()) + sage: e._matmul_(e) + Traceback (most recent call last): + ... + AttributeError: 'sage.structure.element.Element' object has no attribute '_matmul_' + """ + try: + python_op = (self)._matmul_ + except AttributeError: + raise bin_op_exception('@', self, other) + else: + return python_op(other) + def __truediv__(left, right): """ Top-level true division operator for :class:`Element` invoking From d939b2cee7f1992745c11cb3440729b519833e19 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Jul 2020 04:29:39 -0700 Subject: [PATCH 2/2] Update doctests for py3 --- src/sage/structure/element.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 516c9608224..31ba8342bdd 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -1602,15 +1602,15 @@ cdef class Element(SageObject): sage: matmul(e, e) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for @: '' and '' + TypeError: unsupported operand parent(s) for @: '' and '' sage: matmul(1, e) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for @: 'Integer Ring' and '' + TypeError: unsupported operand parent(s) for @: 'Integer Ring' and '' sage: matmul(e, 1) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for @: '' and 'Integer Ring' + TypeError: unsupported operand parent(s) for @: '' and 'Integer Ring' sage: matmul(int(1), e) Traceback (most recent call last): ...