Skip to content

Commit d51374e

Browse files
committed
PEP 465: a dedicated infix operator for matrix multiplication (closes python#21176)
1 parent 2aad6ef commit d51374e

42 files changed

Lines changed: 800 additions & 439 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Doc/c-api/number.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ Number Protocol
3030
the equivalent of the Python expression ``o1 * o2``.
3131
3232
33+
.. c:function:: PyObject* PyNumber_MatrixMultiply(PyObject *o1, PyObject *o2)
34+
35+
Returns the result of matrix multiplication on *o1* and *o2*, or *NULL* on
36+
failure. This is the equivalent of the Python expression ``o1 @ o2``.
37+
38+
.. versionadded:: 3.5
39+
40+
3341
.. c:function:: PyObject* PyNumber_FloorDivide(PyObject *o1, PyObject *o2)
3442
3543
Return the floor of *o1* divided by *o2*, or *NULL* on failure. This is
@@ -146,6 +154,15 @@ Number Protocol
146154
the Python statement ``o1 *= o2``.
147155
148156
157+
.. c:function:: PyObject* PyNumber_InPlaceMatrixMultiply(PyObject *o1, PyObject *o2)
158+
159+
Returns the result of matrix multiplication on *o1* and *o2*, or *NULL* on
160+
failure. The operation is done *in-place* when *o1* supports it. This is
161+
the equivalent of the Python statement ``o1 @= o2``.
162+
163+
.. versionadded:: 3.5
164+
165+
149166
.. c:function:: PyObject* PyNumber_InPlaceFloorDivide(PyObject *o1, PyObject *o2)
150167
151168
Returns the mathematical floor of dividing *o1* by *o2*, or *NULL* on failure.

Doc/c-api/typeobj.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,9 @@ Number Object Structures
11211121
binaryfunc nb_inplace_true_divide;
11221122

11231123
unaryfunc nb_index;
1124+
1125+
binaryfunc nb_matrix_multiply;
1126+
binaryfunc nb_inplace_matrix_multiply;
11241127
} PyNumberMethods;
11251128

11261129
.. note::

Doc/library/dis.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,11 @@ result back on the stack.
364364
Implements ``TOS = TOS1 * TOS``.
365365

366366

367+
.. opcode:: BINARY_MATRIX_MULTIPLY
368+
369+
Implements ``TOS = TOS1 @ TOS``.
370+
371+
367372
.. opcode:: BINARY_FLOOR_DIVIDE
368373

369374
Implements ``TOS = TOS1 // TOS``.
@@ -436,6 +441,11 @@ the original TOS1.
436441
Implements in-place ``TOS = TOS1 * TOS``.
437442

438443

444+
.. opcode:: INPLACE_MATRIX_MULTIPLY
445+
446+
Implements in-place ``TOS = TOS1 @ TOS``.
447+
448+
439449
.. opcode:: INPLACE_FLOOR_DIVIDE
440450

441451
Implements in-place ``TOS = TOS1 // TOS``.

Doc/library/operator.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ The mathematical and bitwise operations are the most numerous:
138138
Return ``a * b``, for *a* and *b* numbers.
139139

140140

141+
.. function:: matmul(a, b)
142+
__matmul__(a, b)
143+
144+
Return ``a @ b``.
145+
146+
.. versionadded:: 3.5
147+
148+
141149
.. function:: neg(obj)
142150
__neg__(obj)
143151

@@ -400,6 +408,8 @@ Python syntax and the functions in the :mod:`operator` module.
400408
+-----------------------+-------------------------+---------------------------------------+
401409
| Multiplication | ``a * b`` | ``mul(a, b)`` |
402410
+-----------------------+-------------------------+---------------------------------------+
411+
| Matrix Multiplication | ``a @ b`` | ``matmul(a, b)`` |
412+
+-----------------------+-------------------------+---------------------------------------+
403413
| Negation (Arithmetic) | ``- a`` | ``neg(a)`` |
404414
+-----------------------+-------------------------+---------------------------------------+
405415
| Negation (Logical) | ``not a`` | ``not_(a)`` |
@@ -508,6 +518,14 @@ will perform the update, so no subsequent assignment is necessary:
508518
``a = imul(a, b)`` is equivalent to ``a *= b``.
509519

510520

521+
.. function:: imatmul(a, b)
522+
__imatmul__(a, b)
523+
524+
``a = imatmul(a, b)`` is equivalent to ``a @= b``.
525+
526+
.. versionadded:: 3.5
527+
528+
511529
.. function:: ior(a, b)
512530
__ior__(a, b)
513531

Doc/library/token.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ The token constants are:
9393
DOUBLESLASH
9494
DOUBLESLASHEQUAL
9595
AT
96+
ATEQUAL
9697
RARROW
9798
ELLIPSIS
9899
OP

Doc/reference/datamodel.rst

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,7 @@ left undefined.
19701970
.. method:: object.__add__(self, other)
19711971
object.__sub__(self, other)
19721972
object.__mul__(self, other)
1973+
object.__matmul__(self, other)
19731974
object.__truediv__(self, other)
19741975
object.__floordiv__(self, other)
19751976
object.__mod__(self, other)
@@ -1986,15 +1987,16 @@ left undefined.
19861987
builtin: pow
19871988
builtin: pow
19881989

1989-
These methods are called to implement the binary arithmetic operations (``+``,
1990-
``-``, ``*``, ``/``, ``//``, ``%``, :func:`divmod`, :func:`pow`, ``**``, ``<<``,
1991-
``>>``, ``&``, ``^``, ``|``). For instance, to evaluate the expression
1992-
``x + y``, where *x* is an instance of a class that has an :meth:`__add__`
1993-
method, ``x.__add__(y)`` is called. The :meth:`__divmod__` method should be the
1994-
equivalent to using :meth:`__floordiv__` and :meth:`__mod__`; it should not be
1995-
related to :meth:`__truediv__`. Note that :meth:`__pow__` should be defined
1996-
to accept an optional third argument if the ternary version of the built-in
1997-
:func:`pow` function is to be supported.
1990+
These methods are called to implement the binary arithmetic operations
1991+
(``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`,
1992+
:func:`pow`, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``). For instance, to
1993+
evaluate the expression ``x + y``, where *x* is an instance of a class that
1994+
has an :meth:`__add__` method, ``x.__add__(y)`` is called. The
1995+
:meth:`__divmod__` method should be the equivalent to using
1996+
:meth:`__floordiv__` and :meth:`__mod__`; it should not be related to
1997+
:meth:`__truediv__`. Note that :meth:`__pow__` should be defined to accept
1998+
an optional third argument if the ternary version of the built-in :func:`pow`
1999+
function is to be supported.
19982000

19992001
If one of those methods does not support the operation with the supplied
20002002
arguments, it should return ``NotImplemented``.
@@ -2003,6 +2005,7 @@ left undefined.
20032005
.. method:: object.__radd__(self, other)
20042006
object.__rsub__(self, other)
20052007
object.__rmul__(self, other)
2008+
object.__rmatmul__(self, other)
20062009
object.__rtruediv__(self, other)
20072010
object.__rfloordiv__(self, other)
20082011
object.__rmod__(self, other)
@@ -2018,14 +2021,14 @@ left undefined.
20182021
builtin: divmod
20192022
builtin: pow
20202023

2021-
These methods are called to implement the binary arithmetic operations (``+``,
2022-
``-``, ``*``, ``/``, ``//``, ``%``, :func:`divmod`, :func:`pow`, ``**``,
2023-
``<<``, ``>>``, ``&``, ``^``, ``|``) with reflected (swapped) operands.
2024-
These functions are only called if the left operand does not support the
2025-
corresponding operation and the operands are of different types. [#]_ For
2026-
instance, to evaluate the expression ``x - y``, where *y* is an instance of
2027-
a class that has an :meth:`__rsub__` method, ``y.__rsub__(x)`` is called if
2028-
``x.__sub__(y)`` returns *NotImplemented*.
2024+
These methods are called to implement the binary arithmetic operations
2025+
(``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`,
2026+
:func:`pow`, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``) with reflected
2027+
(swapped) operands. These functions are only called if the left operand does
2028+
not support the corresponding operation and the operands are of different
2029+
types. [#]_ For instance, to evaluate the expression ``x - y``, where *y* is
2030+
an instance of a class that has an :meth:`__rsub__` method, ``y.__rsub__(x)``
2031+
is called if ``x.__sub__(y)`` returns *NotImplemented*.
20292032

20302033
.. index:: builtin: pow
20312034

@@ -2043,6 +2046,7 @@ left undefined.
20432046
.. method:: object.__iadd__(self, other)
20442047
object.__isub__(self, other)
20452048
object.__imul__(self, other)
2049+
object.__imatmul__(self, other)
20462050
object.__itruediv__(self, other)
20472051
object.__ifloordiv__(self, other)
20482052
object.__imod__(self, other)
@@ -2054,17 +2058,17 @@ left undefined.
20542058
object.__ior__(self, other)
20552059

20562060
These methods are called to implement the augmented arithmetic assignments
2057-
(``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``, ``**=``, ``<<=``, ``>>=``,
2058-
``&=``, ``^=``, ``|=``). These methods should attempt to do the operation
2059-
in-place (modifying *self*) and return the result (which could be, but does
2060-
not have to be, *self*). If a specific method is not defined, the augmented
2061-
assignment falls back to the normal methods. For instance, if *x* is an
2062-
instance of a class with an :meth:`__iadd__` method, ``x += y`` is equivalent
2063-
to ``x = x.__iadd__(y)`` . Otherwise, ``x.__add__(y)`` and ``y.__radd__(x)``
2064-
are considered, as with the evaluation of ``x + y``. In certain situations,
2065-
augmented assignment can result in unexpected errors (see
2066-
:ref:`faq-augmented-assignment-tuple-error`), but this behavior is in
2067-
fact part of the data model.
2061+
(``+=``, ``-=``, ``*=``, ``@=``, ``/=``, ``//=``, ``%=``, ``**=``, ``<<=``,
2062+
``>>=``, ``&=``, ``^=``, ``|=``). These methods should attempt to do the
2063+
operation in-place (modifying *self*) and return the result (which could be,
2064+
but does not have to be, *self*). If a specific method is not defined, the
2065+
augmented assignment falls back to the normal methods. For instance, if *x*
2066+
is an instance of a class with an :meth:`__iadd__` method, ``x += y`` is
2067+
equivalent to ``x = x.__iadd__(y)`` . Otherwise, ``x.__add__(y)`` and
2068+
``y.__radd__(x)`` are considered, as with the evaluation of ``x + y``. In
2069+
certain situations, augmented assignment can result in unexpected errors (see
2070+
:ref:`faq-augmented-assignment-tuple-error`), but this behavior is in fact
2071+
part of the data model.
20682072

20692073

20702074
.. method:: object.__neg__(self)

Doc/reference/expressions.rst

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,9 @@ from the power operator, there are only two levels, one for multiplicative
892892
operators and one for additive operators:
893893

894894
.. productionlist::
895-
m_expr: `u_expr` | `m_expr` "*" `u_expr` | `m_expr` "//" `u_expr` | `m_expr` "/" `u_expr`
896-
: | `m_expr` "%" `u_expr`
895+
m_expr: `u_expr` | `m_expr` "*" `u_expr` | `m_expr` "@" `m_expr` |
896+
: `m_expr` "//" `u_expr`| `m_expr` "/" `u_expr` |
897+
: `m_expr` "%" `u_expr`
897898
a_expr: `m_expr` | `a_expr` "+" `m_expr` | `a_expr` "-" `m_expr`
898899

899900
.. index:: single: multiplication
@@ -904,6 +905,13 @@ the other must be a sequence. In the former case, the numbers are converted to a
904905
common type and then multiplied together. In the latter case, sequence
905906
repetition is performed; a negative repetition factor yields an empty sequence.
906907

908+
.. index:: single: matrix multiplication
909+
910+
The ``@`` (at) operator is intended to be used for matrix multiplication. No
911+
builtin Python types implement this operator.
912+
913+
.. versionadded:: 3.5
914+
907915
.. index::
908916
exception: ZeroDivisionError
909917
single: division
@@ -1346,8 +1354,9 @@ groups from right to left).
13461354
+-----------------------------------------------+-------------------------------------+
13471355
| ``+``, ``-`` | Addition and subtraction |
13481356
+-----------------------------------------------+-------------------------------------+
1349-
| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |
1350-
| | [#]_ |
1357+
| ``*``, ``@``, ``/``, ``//``, ``%`` | Multiplication, matrix |
1358+
| | multiplication division, |
1359+
| | remainder [#]_ |
13511360
+-----------------------------------------------+-------------------------------------+
13521361
| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |
13531362
+-----------------------------------------------+-------------------------------------+

Doc/reference/simple_stmts.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ operation and an assignment statement:
267267
.. productionlist::
268268
augmented_assignment_stmt: `augtarget` `augop` (`expression_list` | `yield_expression`)
269269
augtarget: `identifier` | `attributeref` | `subscription` | `slicing`
270-
augop: "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="
270+
augop: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="
271271
: | ">>=" | "<<=" | "&=" | "^=" | "|="
272272
273273
(See section :ref:`primaries` for the syntax definitions for the last three

Grammar/Grammar

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
4040
expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) |
4141
('=' (yield_expr|testlist_star_expr))*)
4242
testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
43-
augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
43+
augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
4444
'<<=' | '>>=' | '**=' | '//=')
4545
# For normal assignments, additional restrictions enforced by the interpreter
4646
del_stmt: 'del' exprlist
@@ -97,7 +97,7 @@ xor_expr: and_expr ('^' and_expr)*
9797
and_expr: shift_expr ('&' shift_expr)*
9898
shift_expr: arith_expr (('<<'|'>>') arith_expr)*
9999
arith_expr: term (('+'|'-') term)*
100-
term: factor (('*'|'/'|'%'|'//') factor)*
100+
term: factor (('*'|'@'|'/'|'%'|'//') factor)*
101101
factor: ('+'|'-'|'~') factor | power
102102
power: atom trailer* ['**' factor]
103103
atom: ('(' [yield_expr|testlist_comp] ')' |

Include/Python-ast.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ typedef struct _slice *slice_ty;
1515

1616
typedef enum _boolop { And=1, Or=2 } boolop_ty;
1717

18-
typedef enum _operator { Add=1, Sub=2, Mult=3, Div=4, Mod=5, Pow=6, LShift=7,
19-
RShift=8, BitOr=9, BitXor=10, BitAnd=11, FloorDiv=12 }
20-
operator_ty;
18+
typedef enum _operator { Add=1, Sub=2, Mult=3, MatMult=4, Div=5, Mod=6, Pow=7,
19+
LShift=8, RShift=9, BitOr=10, BitXor=11, BitAnd=12,
20+
FloorDiv=13 } operator_ty;
2121

2222
typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty;
2323

0 commit comments

Comments
 (0)