From b6e8a13b6fecf4938e169f528c46b601dbf02a01 Mon Sep 17 00:00:00 2001 From: Marten van Kerkwijk Date: Thu, 30 Nov 2017 20:49:27 -0500 Subject: [PATCH] DOC: advise against use of matrix. --- doc/source/reference/arrays.classes.rst | 7 ++ doc/source/user/numpy-for-matlab-users.rst | 98 ++++++++-------------- doc/source/user/quickstart.rst | 10 +-- 3 files changed, 46 insertions(+), 69 deletions(-) diff --git a/doc/source/reference/arrays.classes.rst b/doc/source/reference/arrays.classes.rst index 2719f9239a53..f17cb932ae4b 100644 --- a/doc/source/reference/arrays.classes.rst +++ b/doc/source/reference/arrays.classes.rst @@ -215,6 +215,13 @@ Matrix objects .. index:: single: matrix +.. note:: + It is strongly advised *not* to use the matrix subclass. As described + below, it makes writing functions that deal consistently with matrices + and regular arrays very difficult. Currently, they are mainly used for + interacting with ``scipy.sparse``. We hope to provide an alternative + for this use, however, and eventually remove the ``matrix`` subclass. + :class:`matrix` objects inherit from the ndarray and therefore, they have the same attributes and methods of ndarrays. There are six important differences of matrix objects, however, that may lead to diff --git a/doc/source/user/numpy-for-matlab-users.rst b/doc/source/user/numpy-for-matlab-users.rst index ae379624e0e9..475c68c04aab 100644 --- a/doc/source/user/numpy-for-matlab-users.rst +++ b/doc/source/user/numpy-for-matlab-users.rst @@ -32,9 +32,9 @@ Some Key Differences in linear algebra. - In NumPy the basic type is a multidimensional ``array``. Operations on these arrays in all dimensionalities including 2D are element-wise - operations. However, there is a special ``matrix`` type for doing - linear algebra, which is just a subclass of the ``array`` class. - Operations on matrix-class arrays are linear algebra operations. + operations. One needs to use specific functions for linear algebra + (though for matrix multiplication, one can use the ``@`` operator + in python 3.5 and above). * - MATLABĀ® uses 1 (one) based indexing. The initial element of a sequence is found using a(1). @@ -50,8 +50,8 @@ Some Key Differences an excellent general-purpose programming language. While Matlab's syntax for some array manipulations is more compact than NumPy's, NumPy (by virtue of being an add-on to Python) can do many - things that Matlab just cannot, for instance subclassing the main - array type to do both array and matrix math cleanly. + things that Matlab just cannot, for instance dealing properly with + stacks of matrices. * - In MATLABĀ®, arrays have pass-by-value semantics, with a lazy copy-on-write scheme to prevent actually creating copies until they @@ -63,8 +63,10 @@ Some Key Differences 'array' or 'matrix'? Which should I use? ======================================== -NumPy provides, in addition to ``np.ndarray``, an additional matrix type -that you may see used in some existing code. Which one to use? +Historically, NumPy has provided a special matrix type, `np.matrix`, which +is a subclass of ndarray which makes binary operations linear algebra +operations. You may see it used in some existing code instead of `np.array`. +So, which one to use? Short answer ------------ @@ -82,6 +84,8 @@ had to use ``dot`` instead of ``*`` to multiply (reduce) two tensors (scalar product, matrix vector multiplication etc.). Since Python 3.5 you can use the matrix multiplication ``@`` operator. +Given the above, we intend to deprecate ``matrix`` eventually. + Long answer ----------- @@ -91,12 +95,14 @@ for many kinds of numerical computing, while ``matrix`` is intended to facilitate linear algebra computations specifically. In practice there are only a handful of key differences between the two. -- Operator ``*``, ``dot()``, and ``multiply()``: +- Operators ``*`` and ``@``, functions ``dot()``, and ``multiply()``: - - For ``array``, **'``*``\ ' means element-wise multiplication**, - and the ``dot()`` function is used for matrix multiplication. - - For ``matrix``, **'``*``\ ' means matrix multiplication**, and the - ``multiply()`` function is used for element-wise multiplication. + - For ``array``, **``*`` means element-wise multiplication**, while + **``@`` means matrix multiplication**; they have associated functions + ``multiply()`` and ``dot()``. (Before python 3.5, ``@`` did not exist + and one had to use ``dot()`` for matrix multiplication). + - For ``matrix``, **``*`` means matrix multiplication**, and for + element-wise multiplication one has to use the ``multiply()`` function. - Handling of vectors (one-dimensional arrays) @@ -132,15 +138,13 @@ There are pros and cons to using both: - ``array`` + - ``:)`` Element-wise multiplication is easy: ``A*B``. + - ``:(`` You have to remember that matrix multiplication has its own + operator, ``@``. - ``:)`` You can treat one-dimensional arrays as *either* row or column - vectors. ``dot(A,v)`` treats ``v`` as a column vector, while - ``dot(v,A)`` treats ``v`` as a row vector. This can save you having to + vectors. ``A @ v`` treats ``v`` as a column vector, while + ``v @ A`` treats ``v`` as a row vector. This can save you having to type a lot of transposes. - - ``<:(`` Having to use the ``dot()`` function for matrix-multiply is - messy -- ``dot(dot(A,B),C)`` vs. ``A*B*C``. This isn't an issue with - Python >= 3.5 because the ``@`` operator allows it to be written as - ``A @ B @ C``. - - ``:)`` Element-wise multiplication is easy: ``A*B``. - ``:)`` ``array`` is the "default" NumPy type, so it gets the most testing, and is the type most likely to be returned by 3rd party code that uses NumPy. @@ -149,6 +153,8 @@ There are pros and cons to using both: with that. - ``:)`` *All* operations (``*``, ``/``, ``+``, ``-`` etc.) are element-wise. + - ``:(`` Sparse matrices from ``scipy.sparse`` do not interact as well + with arrays. - ``matrix`` @@ -162,35 +168,17 @@ There are pros and cons to using both: argument. This shouldn't happen with NumPy functions (if it does it's a bug), but 3rd party code based on NumPy may not honor type preservation like NumPy does. - - ``:)`` ``A*B`` is matrix multiplication, so more convenient for - linear algebra (For Python >= 3.5 plain arrays have the same convenience - with the ``@`` operator). + - ``:)`` ``A*B`` is matrix multiplication, so it looks just like you write + it in linear algebra (For Python >= 3.5 plain arrays have the same + convenience with the ``@`` operator). - ``<:(`` Element-wise multiplication requires calling a function, ``multiply(A,B)``. - ``<:(`` The use of operator overloading is a bit illogical: ``*`` does not work element-wise but ``/`` does. + - Interaction with ``scipy.sparse`` is a bit cleaner. -The ``array`` is thus much more advisable to use. - -Facilities for Matrix Users -=========================== - -NumPy has some features that facilitate the use of the ``matrix`` type, -which hopefully make things easier for Matlab converts. - -- A ``matlib`` module has been added that contains matrix versions of - common array constructors like ``ones()``, ``zeros()``, ``empty()``, - ``eye()``, ``rand()``, ``repmat()``, etc. Normally these functions - return ``array``\ s, but the ``matlib`` versions return ``matrix`` - objects. -- ``mat`` has been changed to be a synonym for ``asmatrix``, rather - than ``matrix``, thus making it a concise way to convert an ``array`` - to a ``matrix`` without copying the data. -- Some top-level functions have been removed. For example - ``numpy.rand()`` now needs to be accessed as ``numpy.random.rand()``. - Or use the ``rand()`` from the ``matlib`` module. But the - "numpythonic" way is to use ``numpy.random.random()``, which takes a - tuple for the shape, like other numpy functions. +The ``array`` is thus much more advisable to use. Indeed, we intend to +deprecate ``matrix`` eventually. Table of Rough MATLAB-NumPy Equivalents ======================================= @@ -200,23 +188,6 @@ expressions. **These are not exact equivalents**, but rather should be taken as hints to get you going in the right direction. For more detail read the built-in documentation on the NumPy functions. -Some care is necessary when writing functions that take arrays or -matrices as arguments --- if you are expecting an ``array`` and are -given a ``matrix``, or vice versa, then '\*' (multiplication) will give -you unexpected results. You can convert back and forth between arrays -and matrices using - -- ``asarray``: always returns an object of type ``array`` -- ``asmatrix`` or ``mat``: always return an object of type - ``matrix`` -- ``asanyarray``: always returns an ``array`` object or a subclass - derived from it, depending on the input. For instance if you pass in - a ``matrix`` it returns a ``matrix``. - -These functions all accept both arrays and matrices (among other things -like Python lists), and thus are useful when writing functions that -should accept any array-like object. - In the table below, it is assumed that you have executed the following commands in Python: @@ -309,8 +280,7 @@ Linear Algebra Equivalents - 2x3 matrix literal * - ``[ a b; c d ]`` - - ``vstack([hstack([a,b]), hstack([c,d])])`` or - ``block([[a, b], [c, d])`` + - ``block([[a,b], [c,d]])`` - construct a matrix from blocks ``a``, ``b``, ``c``, and ``d`` * - ``a(end)`` @@ -369,7 +339,7 @@ Linear Algebra Equivalents - conjugate transpose of ``a`` * - ``a * b`` - - ``a.dot(b)`` or ``a@b`` (Python 3.5 or newer) + - ``a @ b`` - matrix multiply * - ``a .* b`` @@ -520,7 +490,7 @@ Linear Algebra Equivalents from each pair * - ``norm(v)`` - - ``sqrt(dot(v,v))`` or ``np.linalg.norm(v)`` + - ``sqrt(v @ v)`` or ``np.linalg.norm(v)`` - L2 norm of vector ``v`` * - ``a & b`` diff --git a/doc/source/user/quickstart.rst b/doc/source/user/quickstart.rst index de407908007d..57a7004cc547 100644 --- a/doc/source/user/quickstart.rst +++ b/doc/source/user/quickstart.rst @@ -297,19 +297,19 @@ created and filled with the result. Unlike in many matrix languages, the product operator ``*`` operates elementwise in NumPy arrays. The matrix product can be performed using -the ``dot`` function or method:: +the ``@`` operator (in python >=3.5) or the ``dot`` function or method:: >>> A = np.array( [[1,1], ... [0,1]] ) >>> B = np.array( [[2,0], ... [3,4]] ) - >>> A*B # elementwise product + >>> A * B # elementwise product array([[2, 0], [0, 4]]) - >>> A.dot(B) # matrix product + >>> A @ B # matrix product array([[5, 4], [3, 4]]) - >>> np.dot(A, B) # another matrix product + >>> A.dot(B) # another matrix product array([[5, 4], [3, 4]]) @@ -1357,7 +1357,7 @@ See linalg.py in numpy folder for more. [ 0., 1.]]) >>> j = np.array([[0.0, -1.0], [1.0, 0.0]]) - >>> np.dot (j, j) # matrix product + >>> j @ j # matrix product array([[-1., 0.], [ 0., -1.]])