1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #include "test_common_macros.hpp"
11 
12 #include "xtensor/xarray.hpp"
13 #include "xtensor/xio.hpp"
14 #include "xtensor/xoptional_assembly.hpp"
15 
16 #include "test_common.hpp"
17 
18 namespace xt
19 {
20     using array_type = xarray<int, layout_type::dynamic>;
21     using flag_array_type = xarray<bool, layout_type::dynamic>;
22     using adaptor_type = xoptional_assembly_adaptor<array_type&, flag_array_type&>;
23 
TEST(xoptional_assembly_adaptor,constructor)24     TEST(xoptional_assembly_adaptor, constructor)
25     {
26         array_type v = {{1, 2, 3}, {4, 5, 6}};
27         flag_array_type hv = {{true, false, true}, {false, true, false}};
28         adaptor_type a(v, hv);
29         compare_shape(a, v);
30     }
31 
TEST(xoptional_assembly_adaptor,copy_semantic)32     TEST(xoptional_assembly_adaptor, copy_semantic)
33     {
34         array_type v = {{1, 2, 3}, {4, 5, 6}};
35         flag_array_type hv = {{true, false, true}, {false, true, false}};
36         adaptor_type a(v, hv);
37 
38         SUBCASE("copy constructor")
39         {
40             adaptor_type b(a);
41             compare_shape(a, b);
42             EXPECT_EQ(a.value().storage(), b.value().storage());
43             EXPECT_EQ(a.has_value().storage(), b.has_value().storage());
44         }
45 
46         SUBCASE("assignment operator")
47         {
48             array_type v2 = {{1, 2, 13}, {14, 15, 16}};
49             flag_array_type hv2 = {{false, true, true}, {false, true, false}};
50             adaptor_type c(v2, hv2);
51             EXPECT_NE(a.value().storage(), c.value().storage());
52             EXPECT_NE(a.has_value().storage(), c.has_value().storage());
53             c = a;
54             compare_shape(a, c);
55             EXPECT_EQ(a.value().storage(), c.value().storage());
56             EXPECT_EQ(a.has_value().storage(), c.has_value().storage());
57         }
58     }
59 
TEST(xoptional_assembly_adaptor,move_semantic)60     TEST(xoptional_assembly_adaptor, move_semantic)
61     {
62         array_type v = {{1, 2, 3}, {4, 5, 6}};
63         flag_array_type hv = {{true, false, true}, {false, true, false}};
64         adaptor_type a(v, hv);
65 
66         SUBCASE("copy constructor")
67         {
68             adaptor_type tmp(a);
69             adaptor_type b(std::move(tmp));
70             compare_shape(a, b);
71             EXPECT_EQ(a.value().storage(), b.value().storage());
72             EXPECT_EQ(a.has_value().storage(), b.has_value().storage());
73         }
74 
75         SUBCASE("assignment operator")
76         {
77             array_type v2 = {{1, 2, 13}, {14, 15, 16}};
78             flag_array_type hv2 = {{false, true, true}, {false, true, false}};
79             adaptor_type c(v2, hv2);
80             EXPECT_NE(a.value().storage(), c.value().storage());
81             EXPECT_NE(a.has_value().storage(), c.has_value().storage());
82             adaptor_type tmp(a);
83             c = std::move(tmp);
84             compare_shape(a, c);
85             EXPECT_EQ(a.value().storage(), c.value().storage());
86             EXPECT_EQ(a.has_value().storage(), c.has_value().storage());
87         }
88     }
89 
TEST(xoptional_assembly_adaptor,resize)90     TEST(xoptional_assembly_adaptor, resize)
91     {
92         array_type v = {{1, 2, 3}, {4, 5, 6}};
93         flag_array_type hv = {{true, false, true}, {false, true, false}};
94         adaptor_type a(v, hv);
95         test_resize(a);
96         compare_shape(a.value(), a.has_value());
97     }
98 
TEST(xoptional_assembly_adaptor,reshape)99     TEST(xoptional_assembly_adaptor, reshape)
100     {
101         array_type v = {{1, 2, 3}, {4, 5, 6}};
102         flag_array_type hv = {{true, false, true}, {false, true, false}};
103         adaptor_type a(v, hv);
104         test_reshape(a);
105         compare_shape(a.value(), a.has_value());
106     }
107 
TEST(xoptional_assembly_adaptor,access)108     TEST(xoptional_assembly_adaptor, access)
109     {
110         using opt = xtl::xoptional<int>;
111         array_type v = {{1, 2, 3}, {4, 5, 6}};
112         flag_array_type hv = {{true, false, true}, {false, true, false}};
113         adaptor_type a(v, hv);
114         EXPECT_EQ(a(0, 0), opt(1, true));
115         EXPECT_EQ(a(0, 1), opt(2, false));
116         EXPECT_EQ(a(0, 2), opt(3, true));
117         EXPECT_EQ(a(1, 0), opt(4, false));
118         EXPECT_EQ(a(1, 1), opt(5, true));
119         EXPECT_EQ(a(1, 2), opt(6, false));
120     }
121 
TEST(xoptional_assembly_adaptor,at)122     TEST(xoptional_assembly_adaptor, at)
123     {
124         using opt = xtl::xoptional<int>;
125         array_type v = {{1, 2, 3}, {4, 5, 6}};
126         flag_array_type hv = {{true, false, true}, {false, true, false}};
127         adaptor_type a(v, hv);
128         EXPECT_EQ(a.at(0, 0), opt(1, true));
129         EXPECT_EQ(a.at(0, 1), opt(2, false));
130         EXPECT_EQ(a.at(0, 2), opt(3, true));
131         EXPECT_EQ(a.at(1, 0), opt(4, false));
132         EXPECT_EQ(a.at(1, 1), opt(5, true));
133         EXPECT_EQ(a.at(1, 2), opt(6, false));
134     }
135 
TEST(xoptional_assembly_adaptor,element)136     TEST(xoptional_assembly_adaptor, element)
137     {
138         using opt = xtl::xoptional<int>;
139         array_type v = {{1, 2, 3}, {4, 5, 6}};
140         flag_array_type hv = {{true, false, true}, {false, true, false}};
141         adaptor_type a(v, hv);
142         std::vector<std::size_t> v00({0, 0}), v01({0, 1}), v02({0, 2}),
143             v10({1, 0}), v11({1, 1}), v12({1, 2});
144 
145         EXPECT_EQ(a.element(v00.begin(), v00.end()), opt(1, true));
146         EXPECT_EQ(a.element(v01.begin(), v01.end()), opt(2, false));
147         EXPECT_EQ(a.element(v02.begin(), v02.end()), opt(3, true));
148         EXPECT_EQ(a.element(v10.begin(), v10.end()), opt(4, false));
149         EXPECT_EQ(a.element(v11.begin(), v11.end()), opt(5, true));
150         EXPECT_EQ(a.element(v12.begin(), v12.end()), opt(6, false));
151     }
152 
TEST(xoptional_assembly_adaptor,indexed_access)153     TEST(xoptional_assembly_adaptor, indexed_access)
154     {
155         using opt = xtl::xoptional<int>;
156         array_type v = {{1, 2, 3}, {4, 5, 6}};
157         flag_array_type hv = {{true, false, true}, {false, true, false}};
158         adaptor_type a(v, hv);
159         xindex i00({0, 0}), i01({0, 1}), i02({0, 2}),
160             i10({1, 0}), i11({1, 1}), i12({1, 2});
161 
162         EXPECT_EQ(a[i00], opt(1, true));
163         EXPECT_EQ((a[{0, 0}]), opt(1, true));
164         EXPECT_EQ(a[i01], opt(2, false));
165         EXPECT_EQ((a[{0, 1}]), opt(2, false));
166         EXPECT_EQ(a[i02], opt(3, true));
167         EXPECT_EQ((a[{0, 2}]), opt(3, true));
168         EXPECT_EQ(a[i10], opt(4, false));
169         EXPECT_EQ((a[{1, 0}]), opt(4, false));
170         EXPECT_EQ(a[i11], opt(5, true));
171         EXPECT_EQ((a[{1, 1}]), opt(5, true));
172         EXPECT_EQ(a[i12], opt(6, false));
173         EXPECT_EQ((a[{1, 2}]), opt(6, false));
174     }
175 
TEST(xoptional_assembly_adaptor,broadcast_shape)176     TEST(xoptional_assembly_adaptor, broadcast_shape)
177     {
178         using shape_type = adaptor_type::shape_type;
179         shape_type s = {3, 1, 4, 2};
180         array_type v(s);
181         flag_array_type hv(s);
182         adaptor_type a(v, hv);
183 
184         SUBCASE("same shape")
185         {
186             shape_type s1 = s;
187             bool res = a.broadcast_shape(s1);
188             EXPECT_EQ(s1, s);
189             EXPECT_TRUE(res);
190         }
191 
192         SUBCASE("different shape")
193         {
194             shape_type s2 = {3, 5, 1, 2};
195             shape_type s2r = {3, 5, 4, 2};
196             bool res = a.broadcast_shape(s2);
197             EXPECT_EQ(s2, s2r);
198             EXPECT_FALSE(res);
199         }
200 
201         SUBCASE("incompatible shapes")
202         {
203             shape_type s4 = {2, 1, 3, 2};
204             XT_EXPECT_THROW(a.broadcast_shape(s4), broadcast_error);
205         }
206 
207         {
208             shape_type s2 = {3, 1, 4, 2};
209         SUBCASE("different dimensions")
210             a.resize(s2);
211             shape_type s3 = {5, 3, 1, 4, 2};
212             shape_type s3r = s3;
213             bool res = a.broadcast_shape(s3);
214             EXPECT_EQ(s3, s3r);
215             EXPECT_FALSE(res);
216         }
217     }
218 
TEST(xoptional_assembly_adaptor,iterator)219     TEST(xoptional_assembly_adaptor, iterator)
220     {
221         using opt = xtl::xoptional<int>;
222         std::vector<opt> vec = {opt(1), opt(2, false), opt(3, false), opt(4)};
223 
224         SUBCASE("row_major storage iterator")
225         {
226             xarray<int, layout_type::row_major> v;
227             xarray<bool, layout_type::row_major> hv;
228             xoptional_assembly_adaptor<decltype(v)&, decltype(hv)&> rma(v, hv);
229             rma.resize({2, 2});
230             std::copy(vec.cbegin(), vec.cend(), rma.begin<layout_type::row_major>());
231             EXPECT_EQ(vec[0], rma(0, 0));
232             EXPECT_EQ(vec[1], rma(0, 1));
233             EXPECT_EQ(vec[2], rma(1, 0));
234             EXPECT_EQ(vec[3], rma(1, 1));
235             EXPECT_EQ(vec.size(), std::size_t(std::distance(rma.begin<layout_type::row_major>(), rma.end<layout_type::row_major>())));
236         }
237 
238         SUBCASE("column_major storage iterator")
239         {
240             xarray<int, layout_type::row_major> v;
241             xarray<bool, layout_type::row_major> hv;
242             xoptional_assembly_adaptor<decltype(v)&, decltype(hv)&> cma(v, hv);
243             cma.resize({2, 2});
244             std::copy(vec.cbegin(), vec.cend(), cma.begin<layout_type::column_major>());
245             EXPECT_EQ(vec[0], cma(0, 0));
246             EXPECT_EQ(vec[1], cma(1, 0));
247             EXPECT_EQ(vec[2], cma(0, 1));
248             EXPECT_EQ(vec[3], cma(1, 1));
249             EXPECT_EQ(vec.size(), std::size_t(std::distance(cma.begin<layout_type::column_major>(), cma.end<layout_type::column_major>())));
250         }
251     }
252 
TEST(xoptional_assembly_adaptor,xiterator)253     TEST(xoptional_assembly_adaptor, xiterator)
254     {
255         row_major_result<> rm;
256         array_type a;
257         a.resize(rm.m_shape, layout_type::row_major);
258         a.fill(0);
259         a(1, 1, 0) = rm.m_assigner[1][1][0];
260         a[0] = 4;
261         flag_array_type fa(rm.m_shape, true);
262         size_t nb_iter = a.size() / 2;
263         using shape_type = std::vector<size_t>;
264         adaptor_type vec(a, fa);
265 
266         // broadcast_iterator
267         {
268             auto iter = vec.begin<layout_type::row_major>();
269             auto iter_end = vec.end<layout_type::row_major>();
270             for (size_t i = 0; i < nb_iter; ++i)
271             {
272                 ++iter;
273             }
274             EXPECT_EQ(vec.value().storage()[nb_iter], *iter);
275             for (size_t i = 0; i < nb_iter; ++i)
276             {
277                 ++iter;
278             }
279             EXPECT_EQ(iter, iter_end);
280         }
281 
282         // shaped_xiterator
283         {
284             shape_type shape(rm.m_shape.size() + 1);
285             std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1);
286             shape[0] = 2;
287             auto iter = vec.begin<layout_type::row_major>(shape);
288             auto iter_end = vec.end<layout_type::row_major>(shape);
289             for (size_t i = 0; i < 2 * nb_iter; ++i)
290             {
291                 ++iter;
292             }
293             EXPECT_EQ(vec(0, 0), *iter);
294             for (size_t i = 0; i < 2 * nb_iter; ++i)
295             {
296                 ++iter;
297             }
298             EXPECT_EQ(iter, iter_end);
299         }
300 
301         // column broadcast_iterator
302         {
303             auto iter = vec.begin<layout_type::column_major>();
304             auto iter_end = vec.end<layout_type::column_major>();
305             for (size_t i = 0; i < nb_iter; ++i)
306             {
307                 ++iter;
308             }
309             EXPECT_EQ(vec(0, 0, 2), *iter);
310             for (size_t i = 0; i < nb_iter; ++i)
311             {
312                 ++iter;
313             }
314             EXPECT_EQ(iter, iter_end);
315         }
316 
317         // column shaped_xiterator
318         {
319             shape_type shape(rm.m_shape.size() + 1);
320             std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1);
321             shape[0] = 2;
322             auto iter = vec.begin<layout_type::column_major>(shape);
323             auto iter_end = vec.end<layout_type::column_major>(shape);
324             for (size_t i = 0; i < 2 * nb_iter; ++i)
325             {
326                 ++iter;
327             }
328             EXPECT_EQ(vec(0, 0, 2), *iter);
329             for (size_t i = 0; i < 2 * nb_iter; ++i)
330             {
331                 ++iter;
332             }
333             EXPECT_EQ(iter, iter_end);
334         }
335     }
336 
TEST(xoptional_assembly_adaptor,reverse_xiterator)337     TEST(xoptional_assembly_adaptor, reverse_xiterator)
338     {
339         row_major_result<> rm;
340         array_type a;
341         a.resize(rm.m_shape, layout_type::row_major);
342         a(1, 0, 3) = rm.m_assigner[1][0][3];
343         a(2, 1, 3) = 2;
344         flag_array_type fa(rm.m_shape, true);
345         size_t nb_iter = a.size() / 2;
346         using shape_type = std::vector<size_t>;
347         adaptor_type vec(a, fa);
348 
349         // broadcast_iterator
350         {
351             auto iter = vec.rbegin<layout_type::row_major>();
352             auto iter_end = vec.rend<layout_type::row_major>();
353             for (size_t i = 0; i < nb_iter; ++i)
354             {
355                 ++iter;
356             }
357             EXPECT_EQ(vec.value().storage()[nb_iter - 1], *iter);
358             for (size_t i = 0; i < nb_iter; ++i)
359             {
360                 ++iter;
361             }
362             EXPECT_EQ(iter, iter_end);
363         }
364 
365         // shaped_xiterator
366         {
367             shape_type shape(rm.m_shape.size() + 1);
368             std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1);
369             shape[0] = 2;
370             auto iter = vec.rbegin<layout_type::row_major>(shape);
371             auto iter_end = vec.rend<layout_type::row_major>(shape);
372             for (size_t i = 0; i < 2 * nb_iter; ++i)
373             {
374                 ++iter;
375             }
376             EXPECT_EQ(vec.value().storage()[2 * nb_iter - 1], *iter);
377             for (size_t i = 0; i < 2 * nb_iter; ++i)
378             {
379                 ++iter;
380             }
381             EXPECT_EQ(iter, iter_end);
382         }
383     }
384 
TEST(xoptional_assembly_adaptor,semantic)385     TEST(xoptional_assembly_adaptor, semantic)
386     {
387         array_type v = {{1, 2}, {3, 4}};
388         flag_array_type hv = {{true, false}, {false, true}};
389 
390         adaptor_type a(v, hv);
391         adaptor_type b(a);
392 
393         array_type vres;
394         flag_array_type hvres;
395         adaptor_type res(vres, hvres);
396 
397         res = a + b;
398         EXPECT_EQ(res(0, 0), a(0, 0) + b(0, 0));
399         EXPECT_EQ(res(0, 1), a(0, 1) + b(0, 1));
400         EXPECT_EQ(res(1, 0), a(1, 0) + b(1, 0));
401         EXPECT_EQ(res(1, 1), a(1, 1) + b(1, 1));
402 
403         res = a;
404         res += b;
405         EXPECT_EQ(res(0, 0), a(0, 0) + b(0, 0));
406         EXPECT_EQ(res(0, 1), a(0, 1) + b(0, 1));
407         EXPECT_EQ(res(1, 0), a(1, 0) + b(1, 0));
408         EXPECT_EQ(res(1, 1), a(1, 1) + b(1, 1));
409     }
410 }
411