1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
.. 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.
Common pitfalls
===============
xarray initialization
---------------------
.. code::
xt::xarray<double> a({1, 3, 4, 2});
does not initialize a 4D-array, but a 1D-array containing the values ``1``, ``3``,
``4``, and ``2``.
It is strictly equivalent to
.. code::
xt::xarray<double> a = {1, 3, 4, 2};
To initialize a 4D-array with the given shape, use the :cpp:func:`xt::xarray::from_shape` static method:
.. code::
auto a = xt::xarray<double>::from_shape({1, 3, 4, 2});
The confusion often comes from the way :cpp:type:`xt::xtensor` can be initialized:
.. code::
xt::xtensor<double, 4> a = {1, 3, 4, 2};
In this case, a 4D-tensor with shape ``(1, 3, 4, 2)`` is initialized.
Intermediate result
-------------------
Consider the following function:
.. code::
template <class C>
auto func(const C& c)
{
return (1 - func_tmp(c)) / (1 + func_tmp(c));
}
where ``func_tmp`` is another unary function accepting an xtensor expression. You may
be tempted to simplify it a bit:
.. code::
template <class C>
auto func(const C& c)
{
auto tmp = func_tmp(c);
return (1 - tmp) / (1 + tmp);
}
Unfortunately, you introduced a bug; indeed, expressions in *xtensor* are not evaluated
immediately, they capture their arguments by reference or copy depending on their nature,
for future evaluation. Since ``tmp`` is an lvalue, it is captured by reference in the last
statement; when the function returns, ``tmp`` is destroyed, leading to a dangling reference
in the returned expression.
Replacing ``auto tmp`` with ``xt::xarray<double> tmp`` does not change anything, ``tmp``
is still an lvalue and thus captured by reference.
Random numbers not consistent
-----------------------------
Using a random number function from xtensor actually returns a lazy
generator. That means, accessing the same element of a random number
generator does not give the same random number if called twice.
.. code::
auto gen = xt::random::rand<double>({10, 10});
auto a0 = gen(0, 0);
auto a1 = gen(0, 0);
// a0 != a1 !!!
You need to explicitly assign or eval a random number generator, like so:
.. code::
xt::xarray<double> xr = xt::random::rand<double>({10, 10});
auto xr2 = xt::eval(xt::random::rand<double>({10, 10}));
// now xr(0, 0) == xr(0, 0) is true.
variance arguments
------------------
When :cpp:func:`xt::variance` is passed an expression and an integer parameter, this latter
is not the axis along which the variance must be computed, but the degree of freedom:
.. code::
xt::xtensor<double, 2> a = {{1., 2., 3.}, {4., 5., 6.}};
std::cout << xt::variance(a, 1) << std::endl;
// Outputs 3.5
If you want to specify an axis, you need to pass an initializer list:
.. code::
xt::xtensor<double, 2> a = {{1., 2., 3.}, {4., 5., 6.}};
std::cout << xt::variance(a, {1}) << std::endl;
.. Outputs { 0.666667, 0.666667 }
fixed_shape on Windows
----------------------
Builder functions such as :cpp:func:`xt::empty` or :cpp:func:`xt::ones` accept an initializer list
as argument. If the elements of this list do not have the same type, a
curious compilation error may occur on Windows:
.. code::
size_t N = 10ull;
xt::xarray<int> ages = xt::empty<int>({N, 4ul});
// error: cannot convert argument 1 from 'initializer list'
// to 'const xt::fixed_shape<> &'
To avoid this compiler bug (for which we don't have a workaround), ensure
all the elements in the initializer list have the same type.
Alignment of fixed-size members
-------------------------------
.. note::
If you are using ``C++ >= 17`` you should not have to worry about this.
When building with *xsimd* (see :ref:`external-dependencies`), if you define a structure
having members of fixed-size xtensor types, you must ensure that the buffers properly
aligned. For this you can use the macro ``XTENSOR_FIXED_ALIGN`` available in
``xtensor/xtensor_config.hpp``.
Consider the following example:
.. code-block:: cpp
template <typename T>
class alignas(XTENSOR_FIXED_ALIGN) Foo
{
public:
using allocator_type = std::conditional_t<XTENSOR_FIXED_ALIGN != 0,
xt_simd::aligned_allocator<T, XTENSOR_FIXED_ALIGN>,
std::allocator<T>>;
Foo(T fac) : m_fac(fac)
{
m_bar.fill(fac);
}
auto get() const
{
return m_bar;
}
private:
xt::xtensor_fixed<T, xt::xshape<10, 10>> m_bar;
T m_fac;
};
Whereby it is important to store the fixed-sized xtensor type (in this case ``xt::xtensor_fixed<T, xt::xshape<10, 10>>``) as first member.
|