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