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