.. 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
Containers
----------
Two container types are provided. :cpp:type:`xt::xarray` (dynamic number of dimensions)
and :cpp:type:`xt::xtensor` (static number of dimensions).
.. table::
:widths: 50 50
+------------------------------------------------------+------------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+======================================================+========================================================================+
| :any:`np.array([[3, 4], [5, 6]]) ` || :cpp:type:`xt::xarray\({{3, 4}, {5, 6}}) ` |
| || :cpp:type:`xt::xtensor\({{3, 4}, {5, 6}}) ` |
+------------------------------------------------------+------------------------------------------------------------------------+
| :any:`arr.reshape([3, 4]) ` | :cpp:func:`arr.reshape({3, 4}) ` |
+------------------------------------------------------+------------------------------------------------------------------------+
| :any:`arr.astype(np.float64) ` | :cpp:func:`xt::cast\(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.
.. table::
:widths: 50 50
+----------------------------------------------------------------+-------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+================================================================+===================================================================+
| :any:`np.linspace(1.0, 10.0, 100) ` | :cpp:func:`xt::linspace\(1.0, 10.0, 100) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.logspace(2.0, 3.0, 4) ` | :cpp:func:`xt::logspace\(2.0, 3.0, 4) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.arange(3, 7) ` | :cpp:func:`xt::arange(3, 7) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.eye(4) ` | :cpp:func:`xt::eye(4) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.zeros([3, 4]) ` | :cpp:func:`xt::zeros\({3, 4}) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.ones([3, 4]) ` | :cpp:func:`xt::ones\({3, 4}) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.empty([3, 4]) ` | :cpp:func:`xt::empty\({3, 4}) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
| :any:`np.meshgrid(x0, x1, x2, indexing='ij') ` | :cpp:func:`xt::meshgrid(x0, x1, x2) ` |
+----------------------------------------------------------------+-------------------------------------------------------------------+
xtensor's :cpp:func:`meshgrid ` implementation corresponds to numpy's ``'ij'`` indexing order.
Slicing and indexing
--------------------
See :any:`numpy indexing ` page.
.. table::
:widths: 50 50
+-----------------------------------------+---------------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=========================================+===========================================================================+
| ``a[3, 2]`` | :cpp:func:`a(3, 2) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| :any:`a.flat[4] ` | :cpp:func:`a.flat(4) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| ``a[3]`` || :cpp:func:`xt::view(a, 3, xt::all()) ` |
| || :cpp:func:`xt::row(a, 3) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| ``a[:, 2]`` || :cpp:func:`xt::view(a, xt::all(), 2) ` |
| || :cpp:func:`xt::col(a, 2) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| ``a[:5, 1:]`` | :cpp:func:`xt::view(a, xt::range(_, 5), xt::range(1, _)) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| ``a[5:1:-1, :]`` | :cpp:func:`xt::view(a, xt::range(5, 1, -1), xt::all()) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| ``a[..., 3]`` | :cpp:func:`xt::strided_view(a, {xt::ellipsis(), 3}) ` |
+-----------------------------------------+---------------------------------------------------------------------------+
| :any:`a[:, np.newaxis] ` | :cpp:func:`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.
.. table::
:widths: 50 50
+-----------------------------------------------------+------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=====================================================+==================================================================+
| :any:`np.broadcast(a, [4, 5, 7]) ` | :cpp:func:`xt::broadcast(a, {4, 5, 7}) ` |
+-----------------------------------------------------+------------------------------------------------------------------+
| :any:`np.vectorize(f) ` | :cpp:func:`xt::vectorize(f) ` |
+-----------------------------------------------------+------------------------------------------------------------------+
| ``a[a > 5]`` | :cpp:func:`xt::filter(a, a > 5) ` |
+-----------------------------------------------------+------------------------------------------------------------------+
| ``a[[0, 1], [0, 0]]`` | :cpp:func:`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 ` page.
.. table::
:widths: 50 50
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=======================================================================+===================================================================================+
| :any:`np.random.seed(0) ` | :cpp:func:`xt::random::seed(0) ` |
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| :any:`np.random.randn(10, 10) ` | :cpp:func:`xt::random::randn\({10, 10}) ` |
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| :any:`np.random.randint(10, 10) ` | :cpp:func:`xt::random::randint\({10, 10}) ` |
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| :any:`np.random.rand(3, 4) ` | :cpp:func:`xt::random::rand\({3, 4}) ` |
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| :any:`np.random.choice(arr, 5[, replace][, p]) ` | :cpp:func:`xt::random::choice(arr, 5[, weights][, replace]) ` |
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| :any:`np.random.shuffle(arr) ` | :cpp:func:`xt::random::shuffle(arr) ` |
+-----------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| :any:`np.random.permutation(30) ` | :cpp:func:`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.
.. table::
:widths: 50 50
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=============================================================================+============================================================================+
| :any:`np.stack([a, b, c], axis=1) ` | :cpp:func:`xt::stack(xtuple(a, b, c), 1) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.hstack([a, b, c]) ` | :cpp:func:`xt::hstack(xtuple(a, b, c)) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.vstack([a, b, c]) ` | :cpp:func:`xt::vstack(xtuple(a, b, c)) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.concatenate([a, b, c], axis=1) ` | :cpp:func:`xt::concatenate(xtuple(a, b, c), 1) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.tile(a, reps) ` | :cpp:func:`xt::tile(a, reps) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.squeeze(a) ` | :cpp:func:`xt::squeeze(a) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.expand_dims(a, 1) ` | :cpp:func:`xt::expand_dims(a ,1) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.atleast_3d(a) ` | :cpp:func:`xt::atleast_3d(a) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.split(a, 4, axis=0) ` | :cpp:func:`xt::split(a, 4, 0) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.hsplit(a, 4) ` | :cpp:func:`xt::hsplit(a, 4) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.vsplit(a, 4) ` | :cpp:func:`xt::vsplit(a, 4) ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.trim_zeros(a, trim='fb') ` | :cpp:func:`xt::trim_zeros(a, "fb") ` |
+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+
| :any:`np.pad(a, pad_width, mode='constant', constant_values=0) ` | :cpp:func:`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.
.. list-table::
:widths: 50 50
:header-rows: 1
* - Python3 - NumPy
- C++14 - xtensor
* - :any:`np.nan_to_num(a) `
- :cpp:func:`xt::nan_to_num(a) `
* - :any:`np.diag(a) `
- :cpp:func:`xt::diag(a) `
* - :any:`np.diagonal(a) `
- :cpp:func:`xt::diagonal(a) `
* - :any:`np.triu(a) `
- :cpp:func:`xt::triu(a) `
* - :any:`np.tril(a, k=1) `
- :cpp:func:`xt::tril(a, 1) `
* - :any:`np.flip(a, axis=3) `
- :cpp:func:`xt::flip(a, 3) `
* - :any:`np.flipud(a) `
- :cpp:func:`xt::flip(a, 0) `
* - :any:`np.fliplr(a) `
- :cpp:func:`xt::flip(a, 1) `
* - :any:`np.transpose(a, (1, 0, 2)) `
- :cpp:func:`xt::transpose(a, {1, 0, 2}) `
* - :any:`np.swapaxes(a, 0, -1) `
- :cpp:func:`xt::swapaxes(a, 0, -1) `
* - :any:`np.moveaxis(a, 0, -1) `
- :cpp:func:`xt::moveaxis(a, 0, -1) `
* - :any:`np.ravel(a, order='F') `
- :cpp:func:`xt::ravel\(a) `
* - :any:`np.rot90(a) `
- :cpp:func:`xt::rot90(a) `
* - :any:`np.rot90(a, 2, (1, 2)) `
- :cpp:func:`xt::rot90\<2\>(a, {1, 2}) `
* - :any:`np.roll(a, 2, axis=1) `
- :cpp:func:`xt::roll(a, 2, 1) `
Iteration
---------
xtensor follows the idioms of the C++ STL providing iterator pairs to iterate on arrays in
different fashions.
.. table::
:widths: 50 50
+-----------------------------------------------------------+------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+===========================================================+================================================+
| :any:`for x in np.nditer(a): ` | ``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()`` |
| | | ``a.begin()`` |
+-----------------------------------------------------------+------------------------------------------------+
| Iterating over ``a`` in a column-major fashion | | ``a.begin()`` |
| | | ``a.end()`` |
+-----------------------------------------------------------+------------------------------------------------+
Logical
-------
Logical universal functions are truly lazy.
:cpp:func:`xt::where(condition, a, b) ` does not evaluate ``a`` where ``condition``
is falsy, and it does not evaluate ``b`` where ``condition`` is truthy.
.. table::
:widths: 50 50
+-------------------------------------------------+------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=================================================+================================================+
| :any:`np.where(a > 5, a, b) ` | :cpp:func:`xt::where(a > 5, a, b) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.where(a > 5) ` | :cpp:func:`xt::where(a > 5) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.argwhere(a > 5) ` | :cpp:func:`xt::argwhere(a > 5) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.any(a) ` | :cpp:func:`xt::any(a) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.all(a) ` | :cpp:func:`xt::all(a) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.isin(a, b) ` | :cpp:func:`xt::isin(a, b) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.in1d(a, b) ` | :cpp:func:`xt::in1d(a, b) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.logical_and(a, b) ` | ``a && b`` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.logical_or(a, b) ` | ``a || b`` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.isclose(a, b) ` | :cpp:func:`xt::isclose(a, b) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`np.allclose(a, b) ` | :cpp:func:`xt::allclose(a, b) ` |
+-------------------------------------------------+------------------------------------------------+
| :any:`a = ~b ` | ``a = !b`` |
+-------------------------------------------------+------------------------------------------------+
Indices
-------
.. table::
:widths: 50 50
+-------------------------------------------------------------------------+-----------------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=========================================================================+=======================================================================+
| :any:`np.ravel_multi_index(indices, a.shape) ` | :cpp:func:`xt::ravel_indices(indices, a.shape()) ` |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------+
Comparisons
-----------
.. table::
:widths: 50 50
+-----------------------------------------------------+----------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+=====================================================+==========================================================+
| :any:`np.equal(a, b) ` | :cpp:func:`xt::equal(a, b) ` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.not_equal(a, b) ` | :cpp:func:`xt::not_equal(a, b) ` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.less(a, b) ` || :cpp:func:`xt::less(a, b) ` |
| || ``a < b`` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.less_equal(a, b) ` || :cpp:func:`xt::less_equal(a, b) ` |
| || ``a <= b`` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.greater(a, b) ` || :cpp:func:`xt::greater(a, b) ` |
| || ``a > b`` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.greater_equal(a, b) ` || :cpp:func:`xt::greater_equal(a, b) ` |
| || ``a >= b`` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.nonzero(a) ` | :cpp:func:`xt::nonzero(a) ` |
+-----------------------------------------------------+----------------------------------------------------------+
| :any:`np.flatnonzero(a) ` | :cpp:func:`xt::flatnonzero(a) ` |
+-----------------------------------------------------+----------------------------------------------------------+
Minimum, Maximum, Sorting
-------------------------
.. list-table::
:widths: 50 50
:header-rows: 1
* - Python3 - NumPy
- C++14 - xtensor
* - :any:`np.amin(a) `
- :cpp:func:`xt::amin(a) `
* - :any:`np.amax(a) `
- :cpp:func:`xt::amax(a) `
* - :any:`np.argmin(a) `
- :cpp:func:`xt::argmin(a) `
* - :any:`np.argmax(a, axis=1) `
- :cpp:func:`xt::argmax(a, 1) `
* - :any:`np.sort(a, axis=1) `
- :cpp:func:`xt::sort(a, 1) `
* - :any:`np.argsort(a, axis=1) `
- :cpp:func:`xt::argsort(a, 1) `
* - :any:`np.unique(a) `
- :cpp:func:`xt::unique(a) `
* - :any:`np.setdiff1d(ar1, ar2) `
- :cpp:func:`xt::setdiff1d(ar1, ar2) `
* - :any:`np.partition(a, kth) `
- :cpp:func:`xt::partition(a, kth) `
* - :any:`np.argpartition(a, kth) `
- :cpp:func:`xt::argpartition(a, kth) `
* - :any:`np.quantile(a, [.1 .3], method="linear") `
- :cpp:func:`xt::quantile(a, {.1, .3}, xt::quantile_method::linear) `
* - :any:`np.quantile(a, [.1, .3], axis=1 method="linear") `
- :cpp:func:`xt::quantile(a, {.1, .3}, 1, xt::quantile_method::linear) `
* -
- :cpp:func:`xt::quantile(a, {.1, .3}, 1, 1.0, 1.0) `
* - :any:`np.median(a, axis=1) `
- :cpp:func:`xt::median(a, 1) `
Complex numbers
---------------
Functions :cpp:func:`xt::real` and :cpp:func:`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.
.. table::
:widths: 50 50
+--------------------------------+------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+================================+====================================+
| :any:`np.real(a) ` | :cpp:func:`xt::real(a) ` |
+--------------------------------+------------------------------------+
| :any:`np.imag(a) ` | :cpp:func:`xt::imag(a) ` |
+--------------------------------+------------------------------------+
| :any:`np.conj(a) ` | :cpp:func:`xt::conj(a) ` |
+--------------------------------+------------------------------------+
- The constness and value category (rvalue / lvalue) of :cpp:func:`xt::real(a) ` is the same as that of ``a``.
Hence, if ``a`` is a non-const lvalue, :cpp:func:`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 :cpp:func:`xt::imag(a) `. The constness and value category of
:cpp:func:`xt::imag(a) ` is the same as that of ``a``.
- If ``a`` has real values, :cpp:func:`xt::imag(a) ` returns :cpp:func:`xt::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.
.. table::
:widths: 50 50
+---------------------------------------------------------------+--------------------------------------------------------------+
| Python 3 - NumPy | C++ 14 - xtensor |
+===============================================================+==============================================================+
| :any:`np.sum(a, axis=(0, 1)) ` | :cpp:func:`xt::sum(a, {0, 1}) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.sum(a, axis=1) ` | :cpp:func:`xt::sum(a, 1) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.sum(a) ` | :cpp:func:`xt::sum(a) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.prod(a, axis=(0, 1)) ` | :cpp:func:`xt::prod(a, {0, 1}) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.prod(a, axis=1) ` | :cpp:func:`xt::prod(a, 1) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.prod(a) ` | :cpp:func:`xt::prod(a) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.mean(a, axis=(0, 1)) ` | :cpp:func:`xt::mean(a, {0, 1}) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.mean(a, axis=1) ` | :cpp:func:`xt::mean(a, 1) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.mean(a) ` | :cpp:func:`xt::mean(a) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.std(a, [axis]) ` | :cpp:func:`xt::stddev(a, [axis]) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.var(a, [axis]) ` | :cpp:func:`xt::variance(a, [axis]) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.diff(a[, n, axis]) ` | :cpp:func:`xt::diff(a[, n, axis]) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.trapz(a, dx=2.0, axis=-1) ` | :cpp:func:`xt::trapz(a, 2.0, -1) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.trapz(a, x=b, axis=-1) ` | :cpp:func:`xt::trapz(a, b, -1) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.count_nonzero(a, axis=(0, 1)) ` | :cpp:func:`xt::count_nonzero(a, {0, 1}) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.count_nonzero(a, axis=1) ` | :cpp:func:`xt::count_nonzero(a, 1) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
| :any:`np.count_nonzero(a) ` | :cpp:func:`xt::count_nonzero(a) ` |
+---------------------------------------------------------------+--------------------------------------------------------------+
More generally, one can use the :cpp:func:`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.
NaN functions
-------------
NaN functions allow disregarding NaNs during computation, changing the effective number of elements
considered in reductions.
.. list-table::
:widths: 50 50
:header-rows: 1
* - Python3 - NumPy
- C++14 - xtensor
* - :any:`np.nan_to_num(a) `
- :cpp:func:`xt::nan_to_num(a) `
* - :any:`np.nanmin(a) `
- :cpp:func:`xt::nanmin(a) `
* - :any:`np.nanmin(a, axis=(0, 1)) `
- :cpp:func:`xt::nanmin(a, {0, 1}) `
* - :any:`np.nanmax(a) `
- :cpp:func:`xt::nanmax(a) `
* - :any:`np.nanmax(a, axis=(0, 1)) `
- :cpp:func:`xt::nanmax(a, {0, 1})