Blame external/pybind11/docs/advanced/cast/eigen.rst

Packit 534379
Eigen
Packit 534379
#####
Packit 534379
Packit 534379
`Eigen <http://eigen.tuxfamily.org>`_ is C++ header-based library for dense and
Packit 534379
sparse linear algebra. Due to its popularity and widespread adoption, pybind11
Packit 534379
provides transparent conversion and limited mapping support between Eigen and
Packit 534379
Scientific Python linear algebra data types.
Packit 534379
Packit 534379
To enable the built-in Eigen support you must include the optional header file
Packit 534379
:file:`pybind11/eigen.h`.
Packit 534379
Packit 534379
Pass-by-value
Packit 534379
=============
Packit 534379
Packit 534379
When binding a function with ordinary Eigen dense object arguments (for
Packit 534379
example, ``Eigen::MatrixXd``), pybind11 will accept any input value that is
Packit 534379
already (or convertible to) a ``numpy.ndarray`` with dimensions compatible with
Packit 534379
the Eigen type, copy its values into a temporary Eigen variable of the
Packit 534379
appropriate type, then call the function with this temporary variable.
Packit 534379
Packit 534379
Sparse matrices are similarly copied to or from
Packit 534379
``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` objects.
Packit 534379
Packit 534379
Pass-by-reference
Packit 534379
=================
Packit 534379
Packit 534379
One major limitation of the above is that every data conversion implicitly
Packit 534379
involves a copy, which can be both expensive (for large matrices) and disallows
Packit 534379
binding functions that change their (Matrix) arguments.  Pybind11 allows you to
Packit 534379
work around this by using Eigen's ``Eigen::Ref<MatrixType>`` class much as you
Packit 534379
would when writing a function taking a generic type in Eigen itself (subject to
Packit 534379
some limitations discussed below).
Packit 534379
Packit 534379
When calling a bound function accepting a ``Eigen::Ref<const MatrixType>``
Packit 534379
type, pybind11 will attempt to avoid copying by using an ``Eigen::Map`` object
Packit 534379
that maps into the source ``numpy.ndarray`` data: this requires both that the
Packit 534379
data types are the same (e.g. ``dtype='float64'`` and ``MatrixType::Scalar`` is
Packit 534379
``double``); and that the storage is layout compatible.  The latter limitation
Packit 534379
is discussed in detail in the section below, and requires careful
Packit 534379
consideration: by default, numpy matrices and Eigen matrices are *not* storage
Packit 534379
compatible.
Packit 534379
Packit 534379
If the numpy matrix cannot be used as is (either because its types differ, e.g.
Packit 534379
passing an array of integers to an Eigen parameter requiring doubles, or
Packit 534379
because the storage is incompatible), pybind11 makes a temporary copy and
Packit 534379
passes the copy instead.
Packit 534379
Packit 534379
When a bound function parameter is instead ``Eigen::Ref<MatrixType>`` (note the
Packit 534379
lack of ``const``), pybind11 will only allow the function to be called if it
Packit 534379
can be mapped *and* if the numpy array is writeable (that is
Packit 534379
``a.flags.writeable`` is true).  Any access (including modification) made to
Packit 534379
the passed variable will be transparently carried out directly on the
Packit 534379
``numpy.ndarray``.
Packit 534379
Packit 534379
This means you can can write code such as the following and have it work as
Packit 534379
expected:
Packit 534379
Packit 534379
.. code-block:: cpp
Packit 534379
Packit 534379
    void scale_by_2(Eigen::Ref<Eigen::VectorXd> v) {
Packit 534379
        v *= 2;
Packit 534379
    }
Packit 534379
Packit 534379
Note, however, that you will likely run into limitations due to numpy and
Packit 534379
Eigen's difference default storage order for data; see the below section on
Packit 534379
:ref:`storage_orders` for details on how to bind code that won't run into such
Packit 534379
limitations.
Packit 534379
Packit 534379
.. note::
Packit 534379
Packit 534379
    Passing by reference is not supported for sparse types.
Packit 534379
Packit 534379
Returning values to Python
Packit 534379
==========================
Packit 534379
Packit 534379
When returning an ordinary dense Eigen matrix type to numpy (e.g.
Packit 534379
``Eigen::MatrixXd`` or ``Eigen::RowVectorXf``) pybind11 keeps the matrix and
Packit 534379
returns a numpy array that directly references the Eigen matrix: no copy of the
Packit 534379
data is performed.  The numpy array will have ``array.flags.owndata`` set to
Packit 534379
``False`` to indicate that it does not own the data, and the lifetime of the
Packit 534379
stored Eigen matrix will be tied to the returned ``array``.
Packit 534379
Packit 534379
If you bind a function with a non-reference, ``const`` return type (e.g.
Packit 534379
``const Eigen::MatrixXd``), the same thing happens except that pybind11 also
Packit 534379
sets the numpy array's ``writeable`` flag to false.
Packit 534379
Packit 534379
If you return an lvalue reference or pointer, the usual pybind11 rules apply,
Packit 534379
as dictated by the binding function's return value policy (see the
Packit 534379
documentation on :ref:`return_value_policies` for full details).  That means,
Packit 534379
without an explicit return value policy, lvalue references will be copied and
Packit 534379
pointers will be managed by pybind11.  In order to avoid copying, you should
Packit 534379
explicitly specify an appropriate return value policy, as in the following
Packit 534379
example:
Packit 534379
Packit 534379
.. code-block:: cpp
Packit 534379
Packit 534379
    class MyClass {
Packit 534379
        Eigen::MatrixXd big_mat = Eigen::MatrixXd::Zero(10000, 10000);
Packit 534379
    public:
Packit 534379
        Eigen::MatrixXd &getMatrix() { return big_mat; }
Packit 534379
        const Eigen::MatrixXd &viewMatrix() { return big_mat; }
Packit 534379
    };
Packit 534379
Packit 534379
    // Later, in binding code:
Packit 534379
    py::class_<MyClass>(m, "MyClass")
Packit 534379
        .def(py::init<>())
Packit 534379
        .def("copy_matrix", &MyClass::getMatrix) // Makes a copy!
Packit 534379
        .def("get_matrix", &MyClass::getMatrix, py::return_value_policy::reference_internal)
Packit 534379
        .def("view_matrix", &MyClass::viewMatrix, py::return_value_policy::reference_internal)
Packit 534379
        ;
Packit 534379
Packit 534379
.. code-block:: python
Packit 534379
Packit 534379
    a = MyClass()
Packit 534379
    m = a.get_matrix()   # flags.writeable = True,  flags.owndata = False
Packit 534379
    v = a.view_matrix()  # flags.writeable = False, flags.owndata = False
Packit 534379
    c = a.copy_matrix()  # flags.writeable = True,  flags.owndata = True
Packit 534379
    # m[5,6] and v[5,6] refer to the same element, c[5,6] does not.
Packit 534379
Packit 534379
Note in this example that ``py::return_value_policy::reference_internal`` is
Packit 534379
used to tie the life of the MyClass object to the life of the returned arrays.
Packit 534379
Packit 534379
You may also return an ``Eigen::Ref``, ``Eigen::Map`` or other map-like Eigen
Packit 534379
object (for example, the return value of ``matrix.block()`` and related
Packit 534379
methods) that map into a dense Eigen type.  When doing so, the default
Packit 534379
behaviour of pybind11 is to simply reference the returned data: you must take
Packit 534379
care to ensure that this data remains valid!  You may ask pybind11 to
Packit 534379
explicitly *copy* such a return value by using the
Packit 534379
``py::return_value_policy::copy`` policy when binding the function.  You may
Packit 534379
also use ``py::return_value_policy::reference_internal`` or a
Packit 534379
``py::keep_alive`` to ensure the data stays valid as long as the returned numpy
Packit 534379
array does.
Packit 534379
Packit 534379
When returning such a reference of map, pybind11 additionally respects the
Packit 534379
readonly-status of the returned value, marking the numpy array as non-writeable
Packit 534379
if the reference or map was itself read-only.
Packit 534379
Packit 534379
.. note::
Packit 534379
Packit 534379
    Sparse types are always copied when returned.
Packit 534379
Packit 534379
.. _storage_orders:
Packit 534379
Packit 534379
Storage orders
Packit 534379
==============
Packit 534379
Packit 534379
Passing arguments via ``Eigen::Ref`` has some limitations that you must be
Packit 534379
aware of in order to effectively pass matrices by reference.  First and
Packit 534379
foremost is that the default ``Eigen::Ref<MatrixType>`` class requires
Packit 534379
contiguous storage along columns (for column-major types, the default in Eigen)
Packit 534379
or rows if ``MatrixType`` is specifically an ``Eigen::RowMajor`` storage type.
Packit 534379
The former, Eigen's default, is incompatible with ``numpy``'s default row-major
Packit 534379
storage, and so you will not be able to pass numpy arrays to Eigen by reference
Packit 534379
without making one of two changes.
Packit 534379
Packit 534379
(Note that this does not apply to vectors (or column or row matrices): for such
Packit 534379
types the "row-major" and "column-major" distinction is meaningless).
Packit 534379
Packit 534379
The first approach is to change the use of ``Eigen::Ref<MatrixType>`` to the
Packit 534379
more general ``Eigen::Ref
Packit 534379
Eigen::Dynamic>>`` (or similar type with a fully dynamic stride type in the
Packit 534379
third template argument).  Since this is a rather cumbersome type, pybind11
Packit 534379
provides a ``py::EigenDRef<MatrixType>`` type alias for your convenience (along
Packit 534379
with EigenDMap for the equivalent Map, and EigenDStride for just the stride
Packit 534379
type).
Packit 534379
Packit 534379
This type allows Eigen to map into any arbitrary storage order.  This is not
Packit 534379
the default in Eigen for performance reasons: contiguous storage allows
Packit 534379
vectorization that cannot be done when storage is not known to be contiguous at
Packit 534379
compile time.  The default ``Eigen::Ref`` stride type allows non-contiguous
Packit 534379
storage along the outer dimension (that is, the rows of a column-major matrix
Packit 534379
or columns of a row-major matrix), but not along the inner dimension.
Packit 534379
Packit 534379
This type, however, has the added benefit of also being able to map numpy array
Packit 534379
slices.  For example, the following (contrived) example uses Eigen with a numpy
Packit 534379
slice to multiply by 2 all coefficients that are both on even rows (0, 2, 4,
Packit 534379
...) and in columns 2, 5, or 8:
Packit 534379
Packit 534379
.. code-block:: cpp
Packit 534379
Packit 534379
    m.def("scale", [](py::EigenDRef<Eigen::MatrixXd> m, double c) { m *= c; });
Packit 534379
Packit 534379
.. code-block:: python
Packit 534379
Packit 534379
    # a = np.array(...)
Packit 534379
    scale_by_2(myarray[0::2, 2:9:3])
Packit 534379
Packit 534379
The second approach to avoid copying is more intrusive: rearranging the
Packit 534379
underlying data types to not run into the non-contiguous storage problem in the
Packit 534379
first place.  In particular, that means using matrices with ``Eigen::RowMajor``
Packit 534379
storage, where appropriate, such as:
Packit 534379
Packit 534379
.. code-block:: cpp
Packit 534379
Packit 534379
    using RowMatrixXd = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
Packit 534379
    // Use RowMatrixXd instead of MatrixXd
Packit 534379
Packit 534379
Now bound functions accepting ``Eigen::Ref<RowMatrixXd>`` arguments will be
Packit 534379
callable with numpy's (default) arrays without involving a copying.
Packit 534379
Packit 534379
You can, alternatively, change the storage order that numpy arrays use by
Packit 534379
adding the ``order='F'`` option when creating an array:
Packit 534379
Packit 534379
.. code-block:: python
Packit 534379
Packit 534379
    myarray = np.array(source, order='F')
Packit 534379
Packit 534379
Such an object will be passable to a bound function accepting an
Packit 534379
``Eigen::Ref<MatrixXd>`` (or similar column-major Eigen type).
Packit 534379
Packit 534379
One major caveat with this approach, however, is that it is not entirely as
Packit 534379
easy as simply flipping all Eigen or numpy usage from one to the other: some
Packit 534379
operations may alter the storage order of a numpy array.  For example, ``a2 =
Packit 534379
array.transpose()`` results in ``a2`` being a view of ``array`` that references
Packit 534379
the same data, but in the opposite storage order!
Packit 534379
Packit 534379
While this approach allows fully optimized vectorized calculations in Eigen, it
Packit 534379
cannot be used with array slices, unlike the first approach.
Packit 534379
Packit 534379
When *returning* a matrix to Python (either a regular matrix, a reference via
Packit 534379
``Eigen::Ref<>``, or a map/block into a matrix), no special storage
Packit 534379
consideration is required: the created numpy array will have the required
Packit 534379
stride that allows numpy to properly interpret the array, whatever its storage
Packit 534379
order.
Packit 534379
Packit 534379
Failing rather than copying
Packit 534379
===========================
Packit 534379
Packit 534379
The default behaviour when binding ``Eigen::Ref<const MatrixType>`` Eigen
Packit 534379
references is to copy matrix values when passed a numpy array that does not
Packit 534379
conform to the element type of ``MatrixType`` or does not have a compatible
Packit 534379
stride layout.  If you want to explicitly avoid copying in such a case, you
Packit 534379
should bind arguments using the ``py::arg().noconvert()`` annotation (as
Packit 534379
described in the :ref:`nonconverting_arguments` documentation).
Packit 534379
Packit 534379
The following example shows an example of arguments that don't allow data
Packit 534379
copying to take place:
Packit 534379
Packit 534379
.. code-block:: cpp
Packit 534379
Packit 534379
    // The method and function to be bound:
Packit 534379
    class MyClass {
Packit 534379
        // ...
Packit 534379
        double some_method(const Eigen::Ref<const MatrixXd> &matrix) { /* ... */ }
Packit 534379
    };
Packit 534379
    float some_function(const Eigen::Ref<const MatrixXf> &big,
Packit 534379
                        const Eigen::Ref<const MatrixXf> &small) {
Packit 534379
        // ...
Packit 534379
    }
Packit 534379
Packit 534379
    // The associated binding code:
Packit 534379
    using namespace pybind11::literals; // for "arg"_a
Packit 534379
    py::class_<MyClass>(m, "MyClass")
Packit 534379
        // ... other class definitions
Packit 534379
        .def("some_method", &MyClass::some_method, py::arg().noconvert());
Packit 534379
Packit 534379
    m.def("some_function", &some_function,
Packit 534379
        "big"_a.noconvert(), // <- Don't allow copying for this arg
Packit 534379
        "small"_a            // <- This one can be copied if needed
Packit 534379
    );
Packit 534379
Packit 534379
With the above binding code, attempting to call the the ``some_method(m)``
Packit 534379
method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)``
Packit 534379
will raise a ``RuntimeError`` rather than making a temporary copy of the array.
Packit 534379
It will, however, allow the ``m2`` argument to be copied into a temporary if
Packit 534379
necessary.
Packit 534379
Packit 534379
Note that explicitly specifying ``.noconvert()`` is not required for *mutable*
Packit 534379
Eigen references (e.g. ``Eigen::Ref<MatrixXd>`` without ``const`` on the
Packit 534379
``MatrixXd``): mutable references will never be called with a temporary copy.
Packit 534379
Packit 534379
Vectors versus column/row matrices
Packit 534379
==================================
Packit 534379
Packit 534379
Eigen and numpy have fundamentally different notions of a vector.  In Eigen, a
Packit 534379
vector is simply a matrix with the number of columns or rows set to 1 at
Packit 534379
compile time (for a column vector or row vector, respectively).  Numpy, in
Packit 534379
contrast, has comparable 2-dimensional 1xN and Nx1 arrays, but *also* has
Packit 534379
1-dimensional arrays of size N.
Packit 534379
Packit 534379
When passing a 2-dimensional 1xN or Nx1 array to Eigen, the Eigen type must
Packit 534379
have matching dimensions: That is, you cannot pass a 2-dimensional Nx1 numpy
Packit 534379
array to an Eigen value expecting a row vector, or a 1xN numpy array as a
Packit 534379
column vector argument.
Packit 534379
Packit 534379
On the other hand, pybind11 allows you to pass 1-dimensional arrays of length N
Packit 534379
as Eigen parameters.  If the Eigen type can hold a column vector of length N it
Packit 534379
will be passed as such a column vector.  If not, but the Eigen type constraints
Packit 534379
will accept a row vector, it will be passed as a row vector.  (The column
Packit 534379
vector takes precedence when both are supported, for example, when passing a
Packit 534379
1D numpy array to a MatrixXd argument).  Note that the type need not be
Packit 534379
explicitly a vector: it is permitted to pass a 1D numpy array of size 5 to an
Packit 534379
Eigen ``Matrix<double, Dynamic, 5>``: you would end up with a 1x5 Eigen matrix.
Packit 534379
Passing the same to an ``Eigen::MatrixXd`` would result in a 5x1 Eigen matrix.
Packit 534379
Packit 534379
When returning an Eigen vector to numpy, the conversion is ambiguous: a row
Packit 534379
vector of length 4 could be returned as either a 1D array of length 4, or as a
Packit 534379
2D array of size 1x4.  When encountering such a situation, pybind11 compromises
Packit 534379
by considering the returned Eigen type: if it is a compile-time vector--that
Packit 534379
is, the type has either the number of rows or columns set to 1 at compile
Packit 534379
time--pybind11 converts to a 1D numpy array when returning the value.  For
Packit 534379
instances that are a vector only at run-time (e.g. ``MatrixXd``,
Packit 534379
``Matrix<float, Dynamic, 4>``), pybind11 returns the vector as a 2D array to
Packit 534379
numpy.  If this isn't want you want, you can use ``array.reshape(...)`` to get
Packit 534379
a view of the same data in the desired dimensions.
Packit 534379
Packit 534379
.. seealso::
Packit 534379
Packit 534379
    The file :file:`tests/test_eigen.cpp` contains a complete example that
Packit 534379
    shows how to pass Eigen sparse and dense data types in more detail.