.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht

   Distributed under the terms of the BSD 3-Clause License.

   The full license is in the file LICENSE, distributed with this software.

From numpy to xtensor
=====================

.. image:: numpy.svg
   :height: 100px
   :align: right

.. raw:: html

   <style>
   .rst-content table.docutils {
       width: 100%;
       table-layout: fixed;
       border: none;
   }

   table.docutils th {
       text-align: center;
   }

   table.docutils .line-block {
       margin-left: 0;
       margin-bottom: 0;
   }

   table.docutils code.literal {
       color: initial;
   }

   code.docutils {
       background: initial;
       border: none;
   }

   * {
       border: none;
   }

   .rst-content table.docutils thead {
       background-color: #d0e0e0;
   }

   .rst-content table.docutils td {
       border-bottom: none;
       border-left: none;
   }

   .rst-content table.docutils td > p {
       overflow: auto;
   }

   .rst-content table.docutils tr:hover {
       background-color: #d0e0e0;
   }

   .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1):hover td {
       background-color: initial;
   }

   #linear-algebra table.docutils thead .row-odd {
       background: #ffdddd;
   }

   #linear-algebra tr:nth-child(2n-1) td {
       background: #f9f3f3;
   }

   #linear-algebra tr:hover {
       background: #ffdddd;
   }

   #linear-algebra tr:nth-child(2n-1):hover td {
       background-color: initial;
   }
   </style>

Containers
----------

Two container types are provided. ``xarray`` (dynamic number of dimensions) and ``xtensor``
(static number of dimensions).

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|             Python 3 - numpy                                       |               C++ 14 - xtensor                                     |
+====================================================================+====================================================================+
| :any:`np.array([[3, 4], [5, 6]]) <numpy.array>`                    || ``xt::xarray<double>({{3, 4}, {5, 6}})``                          |
|                                                                    || ``xt::xtensor<double, 2>({{3, 4}, {5, 6}})``                      |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`arr.reshape([3, 4]) <numpy.ndarray.reshape>`                 | ``arr.reshape({3, 4})``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`arr.astype(np.float64) <numpy.ndarray.astype>`               | ``xt::cast<double>(arr)``                                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Initializers
------------

Lazy helper functions return tensor expressions. Return types don't hold any value and are
evaluated upon access or assignment. They can be assigned to a container or directly used in
expressions.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|             Python 3 - numpy                                       |               C++ 14 - xtensor                                     |
+====================================================================+====================================================================+
| :any:`np.linspace(1.0, 10.0, 100) <numpy.linspace>`                | ``xt::linspace<double>(1.0, 10.0, 100)``                           |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.logspace(2.0, 3.0, 4) <numpy.logspace>`                   | ``xt::logspace<double>(2.0, 3.0, 4)``                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.arange(3, 7) <numpy.arange>`                              | ``xt::arange(3, 7)``                                               |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.eye(4) <numpy.eye>`                                       | ``xt::eye(4)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.zeros([3, 4]) <numpy.zeros>`                              | ``xt::zeros<double>({3, 4})``                                      |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.ones([3, 4]) <numpy.ones>`                                | ``xt::ones<double>({3, 4})``                                       |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.empty([3, 4]) <numpy.empty>`                              | ``xt::empty<double>({3, 4})``                                      |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.meshgrid(x0, x1, x2, indexing='ij') <numpy.meshgrid>`     | ``xt::meshgrid(x0, x1, x2)``                                       |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

xtensor's ``meshgrid`` implementation corresponds to numpy's ``'ij'`` indexing order.

Slicing and indexing
--------------------

See :any:`numpy indexing <numpy:arrays.indexing>` page.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|             Python 3 - numpy                                       |                   C++ 14 - xtensor                                 |
+====================================================================+====================================================================+
| ``a[3, 2]``                                                        | ``a(3, 2)``                                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`a.flat[4] <numpy.ndarray.flat>`                              | ``a.flat(4)``                                                      |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[3]``                                                           || ``xt::view(a, 3, xt::all())``                                     |
|                                                                    || ``xt::row(a, 3)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[:, 2]``                                                        || ``xt::view(a, xt::all(), 2)``                                     |
|                                                                    || ``xt::col(a, 2)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[:5, 1:]``                                                      | ``xt::view(a, xt::range(_, 5), xt::range(1, _))``                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[5:1:-1, :]``                                                   | ``xt::view(a, xt::range(5, 1, -1), xt::all())``                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[..., 3]``                                                      | ``xt::strided_view(a, {xt::ellipsis, 3})``                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`a[:, np.newaxis] <numpy.newaxis>`                            | ``xt::view(a, xt::all(), xt::newaxis())``                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Broadcasting
------------

xtensor offers lazy numpy-style broadcasting, and universal functions. Unlike numpy, no copy
or temporary variables are created.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|             Python 3 - numpy                                       |                   C++ 14 - xtensor                                 |
+====================================================================+====================================================================+
| :any:`np.broadcast(a, [4, 5, 7]) <numpy.broadcast>`                | ``xt::broadcast(a, {4, 5, 7})``                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.vectorize(f) <numpy.vectorize>`                           | ``xt::vectorize(f)``                                               |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[a > 5]``                                                       | ``xt::filter(a, a > 5)``                                           |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| ``a[[0, 1], [0, 0]]``                                              | ``xt::index_view(a, {{0, 0}, {1, 0}})``                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Random
------

The random module provides simple ways to create random tensor expressions, lazily.
See :any:`numpy.random` and :ref:`xtensor random <random>` page.

+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
|            Python 3 - numpy                                                 |                C++ 14 - xtensor                                             |
+=============================================================================+=============================================================================+
| :any:`np.random.seed(0) <numpy.random.seed>`                                | ``xt::random::seed(0)``                                                     |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.random.randn(10, 10) <numpy.random.randn>`                         | ``xt::random::randn<double>({10, 10})``                                     |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.random.randint(10, 10) <numpy.random.randint>`                     | ``xt::random::randint<int>({10, 10})``                                      |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.random.rand(3, 4) <numpy.random.rand>`                             | ``xt::random::rand<double>({3, 4})``                                        |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.random.choice(arr, 5[, replace][, p]) <numpy.random.choice>`       | ``xt::random::choice(arr, 5[, weights][, replace])``                        |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.random.shuffle(arr) <numpy.random.shuffle>`                        | ``xt::random::shuffle(arr)``                                                |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.random.permutation(30) <numpy.random.permutation>`                 | ``xt::random::permutation(30)``                                             |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+

Concatenation, splitting, squeezing
-----------------------------------

Concatenating expressions does not allocate memory, it returns a tensor or view expression holding
closures on the specified arguments.

+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
|            Python 3 - numpy                                                 |                C++ 14 - xtensor                                             |
+=============================================================================+=============================================================================+
| :any:`np.stack([a, b, c], axis=1) <numpy.stack>`                            | ``xt::stack(xtuple(a, b, c), 1)``                                           |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.hstack([a, b, c]) <numpy.hstack>`                                  | ``xt::hstack(xtuple(a, b, c))``                                             |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.vstack([a, b, c]) <numpy.vstack>`                                  | ``xt::vstack(xtuple(a, b, c))``                                             |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.concatenate([a, b, c], axis=1) <numpy.concatenate>`                | ``xt::concatenate(xtuple(a, b, c), 1)``                                     |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.tile(a, reps) <numpy.tile>`                                        | ``xt::tile(a, reps)``                                                       |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.squeeze(a) <numpy.squeeze>`                                        | ``xt::squeeze(a)``                                                          |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.expand_dims(a, 1) <numpy.expand_dims>`                             | ``xt::expand_dims(a ,1)``                                                   |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.atleast_3d(a) <numpy.atleast_3d>`                                  | ``xt::atleast_3d(a)``                                                       |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.split(a, 4, axis=0) <numpy.split>`                                 | ``xt::split(a, 4, 0)``                                                      |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.hsplit(a, 4) <numpy.hsplit>`                                       | ``xt::hsplit(a, 4)``                                                        |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.vsplit(a, 4) <numpy.vsplit>`                                       | ``xt::vsplit(a, 4)``                                                        |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.trim_zeros(a, trim='fb') <numpy.trim_zeros>`                       | ``xt::trim_zeros(a, "fb")``                                                 |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+
| :any:`np.pad(a, pad_width, mode='constant', constant_values=0) <numpy.pad>` | ``xt::pad(a, pad_width[, xt::pad_mode::constant][, 0])``                    |
+-----------------------------------------------------------------------------+-----------------------------------------------------------------------------+

Rearrange elements
------------------

In the same spirit as concatenation, the following operations do not allocate any memory and do
not modify the underlying xexpression.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.diag(a) <numpy.diag>`                                     | ``xt::diag(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.diagonal(a) <numpy.diagonal>`                             | ``xt::diagonal(a)``                                                |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.triu(a) <numpy.triu>`                                     | ``xt::triu(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.tril(a, k=1) <numpy.tril>`                                | ``xt::tril(a, 1)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.flip(a, axis=3) <numpy.flip>`                             | ``xt::flip(a, 3)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.flipud(a) <numpy.flipud>`                                 | ``xt::flip(a, 0)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.fliplr(a) <numpy.fliplr>`                                 | ``xt::flip(a, 1)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.transpose(a, (1, 0, 2)) <numpy.transpose>`                | ``xt::transpose(a, {1, 0, 2})``                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.ravel(a, order='F') <numpy.ravel>`                        | ``xt::ravel<layout_type::column_major>(a)``                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.rot90(a) <numpy.rot90>`                                   | ``xt::rot90(a)``                                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.rot90(a, 2, (1, 2)) <numpy.rot90>`                        | ``xt::rot90<2>(a, {1, 2})``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.roll(a, 2, axis=1) <numpy.roll>`                          | ``xt::roll(a, 2, 1)``                                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Iteration
---------

xtensor follows the idioms of the C++ STL providing iterator pairs to iterate on arrays in
different fashions.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`for x in np.nditer(a): <numpy.nditer>`                       |  ``for(auto it=a.begin(); it!=a.end(); ++it)``                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| Iterating over ``a`` with a prescribed broadcasting shape          | | ``a.begin({3, 4})``                                              |
|                                                                    | | ``a.end({3, 4})``                                                |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| Iterating over ``a`` in a row-major fashion                        | | ``a.begin<xt::layout_type::row_major>()``                        |
|                                                                    | | ``a.begin<xt::layout_type::row_major>()``                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| Iterating over ``a`` in a column-major fashion                     | | ``a.begin<xt::layout_type::column_major>()``                     |
|                                                                    | | ``a.end<xt::layout_type::column_major>()``                       |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Logical
-------

Logical universal functions are truly lazy. ``xt::where(condition, a, b)`` does not evaluate ``a``
where ``condition`` is falsy, and it does not evaluate ``b`` where ``condition`` is truthy.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.where(a > 5, a, b) <numpy.where>`                         | ``xt::where(a > 5, a, b)``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.where(a > 5) <numpy.where>`                               | ``xt::where(a > 5)``                                               |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.argwhere(a > 5) <numpy.argwhere>`                         | ``xt::argwhere(a > 5)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.any(a) <numpy.any>`                                       | ``xt::any(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.all(a) <numpy.all>`                                       | ``xt::all(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.isin(a, b) <numpy.isin>`                                  | ``xt::isin(a, b)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.in1d(a, b) <numpy.in1d>`                                  | ``xt::in1d(a, b)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.logical_and(a, b) <numpy.logical_and>`                    | ``a && b``                                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.logical_or(a, b) <numpy.logical_or>`                      | ``a || b``                                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.isclose(a, b) <numpy.isclose>`                            | ``xt::isclose(a, b)``                                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.allclose(a, b) <numpy.allclose>`                          | ``xt::allclose(a, b)``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`a = ~b <numpy.invert>`                                       | ``a = !b``                                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Indices
-------

+-------------------------------------------------------------------------+-------------------------------------------------------------------------+
|            Python 3 - numpy                                             |                C++ 14 - xtensor                                         |
+=========================================================================+=========================================================================+
| :any:`np.ravel_multi_index(indices, a.shape) <numpy.ravel_multi_index>` | ``xt::ravel_indices(indices, a.shape())``                               |
+-------------------------------------------------------------------------+-------------------------------------------------------------------------+

Comparisons
-----------

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.equal(a, b) <numpy.equal>`                                | ``xt::equal(a, b)``                                                |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.not_equal(a, b) <numpy.not_equal>`                        | ``xt::not_equal(a, b)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.less(a, b) <numpy.less>`                                  || ``xt::less(a, b)``                                                |
|                                                                    || ``a < b``                                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.less_equal(a, b) <numpy.less_equal>`                      || ``xt::less_equal(a, b)``                                          |
|                                                                    || ``a <= b``                                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.greater(a, b) <numpy.greater>`                            || ``xt::greater(a, b)``                                             |
|                                                                    || ``a > b``                                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.greater_equal(a, b) <numpy.greater_equal>`                || ``xt::greater_equal(a, b)``                                       |
|                                                                    || ``a >= b``                                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.nonzero(a) <numpy.nonzero>`                               | ``xt::nonzero(a)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.flatnonzero(a) <numpy.flatnonzero>`                       | ``xt::flatnonzero(a)``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Minimum, Maximum, Sorting
-------------------------

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.amin(a) <numpy.amin>`                                     | ``xt::amin(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.amax(a) <numpy.amax>`                                     | ``xt::amax(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.argmin(a) <numpy.argmin>`                                 | ``xt::argmin(a)``                                                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.argmax(a, axis=1) <numpy.argmax>`                         | ``xt::argmax(a, 1)``                                               |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.sort(a, axis=1) <numpy.sort>`                             | ``xt::sort(a, 1)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.argsort(a, axis=1) <numpy.argsort>`                       | ``xt::argsort(a, 1)``                                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.unique(a) <numpy.unique>`                                 | ``xt::unique(a)``                                                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.setdiff1d(ar1, ar2) <numpy.setdiff1d>`                    | ``xt::setdiff1d(ar1, ar2)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.diff(a[, n, axis]) <numpy.diff>`                          | ``xt::diff(a[, n, axis])``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.partition(a, kth) <numpy.partition>`                      | ``xt::partition(a, kth)``                                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.argpartition(a, kth) <numpy.argpartition>`                | ``xt::argpartition(a, kth)``                                       |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.median(a, axis) <numpy.median>`                           | ``xt::median(a, axis)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Complex numbers
---------------

Functions ``xt::real`` and ``xt::imag`` respectively return views on the real and imaginary part
of a complex expression. The returned value is an expression holding a closure on the passed
argument.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.real(a) <numpy.real>`                                     | ``xt::real(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.imag(a) <numpy.imag>`                                     | ``xt::imag(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.conj(a) <numpy.conj>`                                     | ``xt::conj(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

- The constness and value category (rvalue / lvalue) of ``real(a)`` is the same as that of ``a``.
  Hence, if ``a`` is a non-const lvalue, ``real(a)`` is an non-const lvalue reference, to which
  one can assign a real expression.
- If ``a`` has complex values, the same holds for ``imag(a)``. The constness and value category of
  ``imag(a)`` is the same as that of ``a``.
- If ``a`` has real values, ``imag(a)`` returns ``zeros(a.shape())``.

Reducers
--------

Reducers accumulate values of tensor expressions along specified axes. When no axis is specified,
values are accumulated along all axes. Reducers are lazy, meaning that returned expressions don't
hold any values and are computed upon access or assignment.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.sum(a, axis=[0, 1]) <numpy.sum>`                          | ``xt::sum(a, {0, 1})``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.sum(a, axis=1) <numpy.sum>`                               | ``xt::sum(a, 1)``                                                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.sum(a) <numpy.sum>`                                       | ``xt::sum(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.prod(a, axis=[0, 1]) <numpy.prod>`                        | ``xt::prod(a, {0, 1})``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.prod(a, axis=1) <numpy.prod>`                             | ``xt::prod(a, 1)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.prod(a) <numpy.prod>`                                     | ``xt::prod(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.mean(a, axis=[0, 1]) <numpy.mean>`                        | ``xt::mean(a, {0, 1})``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.mean(a, axis=1) <numpy.mean>`                             | ``xt::mean(a, 1)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.mean(a) <numpy.mean>`                                     | ``xt::mean(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.std(a, [axis]) <numpy.std>`                               | ``xt::stddev(a, [axis])``                                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.var(a, [axis]) <numpy.var>`                               | ``xt::variance(a, [axis])``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.trapz(a, dx=2.0, axis=-1) <numpy.trapz>`                  | ``xt::trapz(a, 2.0, -1)``                                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.trapz(a, x=b, axis=-1) <numpy.trapz>`                     | ``xt::trapz(a, b, -1)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.count_nonzero(a, axis=[0, 1]) <numpy.count_nonzero>`      | ``xt::count_nonzero(a, {0, 1})``                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.count_nonzero(a, axis=1) <numpy.count_nonzero>`           | ``xt::count_nonzero(a, 1)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.count_nonzero(a) <numpy.count_nonzero>`                   | ``xt::count_nonzero(a)``                                           |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

More generally, one can use the ``xt::reduce(function, input, axes)`` which allows the specification
of an arbitrary binary function for the reduction. The binary function must be commutative and
associative up to rounding errors.

I/O
---

**Print options**

These options determine the way floating point numbers, tensors and other xtensor expressions are displayed.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.set_printoptions(precision=4) <numpy.set_printoptions>`   | ``xt::print_options::set_precision(4)``                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.set_printoptions(threshold=5) <numpy.set_printoptions>`   | ``xt::print_options::set_threshold(5)``                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.set_printoptions(edgeitems=3) <numpy.set_printoptions>`   | ``xt::print_options::set_edgeitems(3)``                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.set_printoptions(linewidth=100) <numpy.set_printoptions>` | ``xt::print_options::set_line_width(100)``                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Reading npy, csv file formats**

Functions ``load_csv`` and ``dump_csv`` respectively take input and output streams as arguments.

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.load(filename) <numpy.load>`                              | ``xt::load_npy<double>(filename)``                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.save(filename, arr) <numpy.save>`                         | ``xt::dump_npy(filename, arr)``                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.loadtxt(filename, delimiter=',') <numpy.loadtxt>`         | ``xt::load_csv<double>(stream)``                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Mathematical functions
----------------------

xtensor universal functions are provided for a large set number of mathematical functions.

**Basic functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.absolute(a) <numpy.absolute>`                             | ``xt::abs(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.sign(a) <numpy.sign>`                                     | ``xt::sign(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.remainder(a, b) <numpy.remainder>`                        | ``xt::remainder(a, b)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.minimum(a, b) <numpy.minimum>`                            | ``xt::minimum(a, b)``                                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.maximum(a, b) <numpy.maximum>`                            | ``xt::maximum(a, b)``                                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.clip(a, min, max) <numpy.clip>`                           | ``xt::clip(a, min, max)``                                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
|                                                                    | ``xt::fma(a, b, c)``                                               |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.interp(x, xp, fp, [,left, right]) <numpy.interp>`         | ``xt::interp(x, xp, fp, [,left, right])``                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.rad2deg(a) <numpy.rad2deg>`                               | ``xt::rad2deg(a)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.degrees(a) <numpy.degrees>`                               | ``xt::degrees(a)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.deg2rad(a) <numpy.deg2rad>`                               | ``xt::deg2rad(a)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.radians(a) <numpy.radians>`                               | ``xt::radians(a)``                                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Exponential functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.exp(a) <numpy.exp>`                                       | ``xt::exp(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.expm1(a) <numpy.expm1>`                                   | ``xt::expm1(a)``                                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.log(a) <numpy.log>`                                       | ``xt::log(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.log1p(a) <numpy.log1p>`                                   | ``xt::log1p(a)``                                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Power functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.power(a, p) <numpy.power>`                                | ``xt::pow(a, b)``                                                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.sqrt(a) <numpy.sqrt>`                                     | ``xt::sqrt(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.square(a) <numpy.square>`                                 | ``xt::square(a)``                                                  |
|                                                                    | ``xt::cube(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.cbrt(a) <numpy.cbrt>`                                     | ``xt::cbrt(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Trigonometric functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.sin(a) <numpy.sin>`                                       | ``xt::sin(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.cos(a) <numpy.cos>`                                       | ``xt::cos(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.tan(a) <numpy.tan>`                                       | ``xt::tan(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Hyperbolic functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.sinh(a) <numpy.sinh>`                                     | ``xt::sinh(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.cosh(a) <numpy.cosh>`                                     | ``xt::cosh(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.tanh(a) <numpy.tanh>`                                     | ``xt::tanh(a)``                                                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Error and gamma functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`scipy.special.erf(a) <scipy.special.erf>`                    | ``xt::erf(a)``                                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`scipy.special.gamma(a) <scipy.special.gamma>`                | ``xt::tgamma(a)``                                                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`scipy.special.gammaln(a) <scipy.special.gammaln>`            | ``xt::lgamma(a)``                                                  |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Classification functions:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|            Python 3 - numpy                                        |                C++ 14 - xtensor                                    |
+====================================================================+====================================================================+
| :any:`np.isnan(a) <numpy.isnan>`                                   | ``xt::isnan(a)``                                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.isinf(a) <numpy.isinf>`                                   | ``xt::isinf(a)``                                                   |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.isfinite(a) <numpy.isfinite>`                             | ``xt::isfinite(a)``                                                |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.searchsorted(a, v[, side]) <numpy.searchsorted>`          | ``xt::searchsorted(a, v[, right])``                                |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Histogram:**

+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+
|                           Python 3 - numpy                                                                   |                           C++ 14 - xtensor                                                                   |
+==============================================================================================================+==============================================================================================================+
| :any:`np.histogram(a, bins[, weights][, density]) <numpy.histogram>`                                         | ``xt::histogram(a, bins[, weights][, density])``                                                             |
+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+
| :any:`np.histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode]) <numpy.histogram_bin_edges>` | ``xt::histogram_bin_edges(a, bins[, weights][, left, right][, bins][, mode])``                               |
+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+
| :any:`np.bincount(arr) <numpy.bincount>`                                                                     | ``xt::bincount(arr)``                                                                                        |
+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+
| :any:`np.digitize(data, bin_edges[, right]) <numpy.digitize>`                                                | ``xt::digitize(data, bin_edges[, right][, assume_sorted])``                                                  |
+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+

See :ref:`histogram`.

**Numerical constants:**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|                           Python 3 - numpy                         |                           C++ 14 - xtensor                         |
+====================================================================+====================================================================+
| :any:`numpy.pi`                                                    | ``xt::numeric_constants<double>::PI;``                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

Linear algebra
--------------

Many functions found in the :any:`numpy.linalg` module are implemented in `xtensor-blas`_, a separate package offering BLAS and LAPACK bindings,
as well as a convenient interface replicating the ``linalg`` module.

Please note, however, that while we're trying to be as close to NumPy as possible, some features are not
implemented yet. Most prominently that is broadcasting for all functions except for ``dot``.


**Matrix, vector and tensor products**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|              Python 3 - numpy                                      |               C++ 14 - xtensor                                     |
+====================================================================+====================================================================+
| :any:`np.dot(a, b) <numpy.dot>`                                    | ``xt::linalg::dot(a, b)``                                          |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.vdot(a, b) <numpy.vdot>`                                  | ``xt::linalg::vdot(a, b)``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.outer(a, b) <numpy.outer>`                                | ``xt::linalg::outer(a, b)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.matrix_power(a, 123) <numpy.linalg.matrix_power>`  | ``xt::linalg::matrix_power(a, 123)``                               |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.kron(a, b) <numpy.kron>`                                  | ``xt::linalg::kron(a, b)``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.tensordot(a, b, axes=3) <numpy.tensordot>`                | ``xt::linalg::tensordot(a, b, 3)``                                 |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.tensordot(a, b, axes=((0,2),(1,3)) <numpy.tensordot>`     | ``xt::linalg::tensordot(a, b, {0, 2}, {1, 3})``                    |
+--------------------------------------------------------------------+--------------------------------------------------------------------+


**Decompositions**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|       Python 3 - numpy                                             |       C++ 14 - xtensor                                             |
+====================================================================+====================================================================+
| :any:`np.linalg.cholesky(a) <numpy.linalg.cholesky>`               | ``xt::linalg::cholesky(a)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.qr(a) <numpy.linalg.qr>`                           | ``xt::linalg::qr(a)``                                              |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.svd(a) <numpy.linalg.svd>`                         | ``xt::linalg::svd(a)``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+


**Matrix eigenvalues**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|       Python 3 - numpy                                             |       C++ 14 - xtensor                                             |
+====================================================================+====================================================================+
| :any:`np.linalg.eig(a) <numpy.linalg.eig>`                         | ``xt::linalg::eig(a)``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.eigvals(a) <numpy.linalg.eigvals>`                 | ``xt::linalg::eigvals(a)``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.eigh(a) <numpy.linalg.eigh>`                       | ``xt::linalg::eigh(a)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.eigvalsh(a) <numpy.linalg.eigvalsh>`               | ``xt::linalg::eigvalsh(a)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Norms and other numbers**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|        Python 3 - numpy                                            |        C++ 14 - xtensor                                            |
+====================================================================+====================================================================+
| :any:`np.linalg.norm(a, order=2) <numpy.linalg.norm>`              | ``xt::linalg::norm(a, 2)``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.cond(a) <numpy.linalg.cond>`                       | ``xt::linalg::cond(a)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.det(a) <numpy.linalg.det>`                         | ``xt::linalg::det(a)``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.matrix_rank(a) <numpy.linalg.matrix_rank>`         | ``xt::linalg::matrix_rank(a)``                                     |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.slogdet(a) <numpy.linalg.slogdet>`                 | ``xt::linalg::slogdet(a)``                                         |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.trace(a) <numpy.trace>`                                   | ``xt::linalg::trace(a)``                                           |
+--------------------------------------------------------------------+--------------------------------------------------------------------+

**Solving equations and inverting matrices**

+--------------------------------------------------------------------+--------------------------------------------------------------------+
|        Python 3 - numpy                                            |        C++ 14 - xtensor                                            |
+====================================================================+====================================================================+
| :any:`np.linalg.inv(a) <numpy.linalg.inv>`                         | ``xt::linalg::inv(a)``                                             |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.pinv(a) <numpy.linalg.pinv>`                       | ``xt::linalg::pinv(a)``                                            |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.solve(A, b) <numpy.linalg.solve>`                  | ``xt::linalg::solve(A, b)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+
| :any:`np.linalg.lstsq(A, b) <numpy.linalg.lstsq>`                  | ``xt::linalg::lstsq(A, b)``                                        |
+--------------------------------------------------------------------+--------------------------------------------------------------------+


.. _`xtensor-blas`: https://github.com/xtensor-stack/xtensor-blas
