| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 0d6a645 commit c452790
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -346,6 +346,9 @@ namespace xt | |||
| 346 | 346 | explicit pyarray(const shape_type& shape, const strides_type& strides, const_reference value); | |
| 347 | 347 | explicit pyarray(const shape_type& shape, const strides_type& strides); | |
| 348 | 348 | ||
| 349 | + template <class S = shape_type> | ||
| 350 | + static pyarray from_shape(S&& s); | ||
| 351 | + | ||
| 349 | 352 | pyarray(const self_type& rhs); | |
| 350 | 353 | self_type& operator=(const self_type& rhs); | |
| 351 | 354 | ||
@@ -605,6 +608,18 @@ namespace xt | |||
| 605 | 608 | { | |
| 606 | 609 | init_array(shape, strides); | |
| 607 | 610 | } | |
| 611 | + | ||
| 612 | + /** | ||
| 613 | + * Allocates and returns an pyarray with the specified shape. | ||
| 614 | + * @param shape the shape of the pyarray | ||
| 615 | + */ | ||
| 616 | + template <class T, layout_type L> | ||
| 617 | + template <class S> | ||
| 618 | + inline pyarray<T, L> pyarray<T, L>::from_shape(S&& shape) | ||
| 619 | + { | ||
| 620 | + auto shp = xtl::forward_sequence<shape_type>(shape); | ||
| 621 | + return self_type(shp); | ||
| 622 | + } | ||
| 608 | 623 | //@} | |
| 609 | 624 | ||
| 610 | 625 | /** | |
@@ -726,6 +741,12 @@ namespace xt | |||
| 726 | 741 | static_cast<size_type>(PyArray_NDIM(this->python_array()))); | |
| 727 | 742 | m_strides = inner_strides_type(reinterpret_cast<size_type*>(PyArray_STRIDES(this->python_array())), | |
| 728 | 743 | static_cast<size_type>(PyArray_NDIM(this->python_array()))); | |
| 744 | + | ||
| 745 | + if (L != layout_type::dynamic && !do_strides_match(m_shape, m_strides, L)) | ||
| 746 | + { | ||
| 747 | + throw std::runtime_error("NumPy: passing container with bad strides for layout (is it a view?)."); | ||
| 748 | + } | ||
| 749 | + | ||
| 729 | 750 | m_backstrides = backstrides_type(*this); | |
| 730 | 751 | m_storage = storage_type(reinterpret_cast<pointer>(PyArray_DATA(this->python_array())), | |
| 731 | 752 | this->get_min_stride() * static_cast<size_type>(PyArray_SIZE(this->python_array()))); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -226,8 +226,7 @@ namespace xt | |||
| 226 | 226 | bool check_array(const pybind11::handle& src) | |
| 227 | 227 | { | |
| 228 | 228 | using is_arithmetic_type = std::integral_constant<bool, bool(pybind11::detail::satisfies_any_of<T, std::is_arithmetic, xtl::is_complex>::value)>; | |
| 229 | - return PyArray_Check(src.ptr()) && | ||
| 230 | - check_array_type<T>(src, is_arithmetic_type{}); | ||
| 229 | + return PyArray_Check(src.ptr()) && check_array_type<T>(src, is_arithmetic_type{}); | ||
| 231 | 230 | } | |
| 232 | 231 | } | |
| 233 | 232 | ||
@@ -277,9 +276,7 @@ namespace xt | |||
| 277 | 276 | template <class D> | |
| 278 | 277 | inline bool pycontainer<D>::check_(pybind11::handle h) | |
| 279 | 278 | { | |
| 280 | - auto dtype = pybind11::detail::npy_format_descriptor<value_type>::dtype(); | ||
| 281 | - return PyArray_Check(h.ptr()) && | ||
| 282 | - PyArray_EquivTypes_(PyArray_TYPE(reinterpret_cast<PyArrayObject*>(h.ptr())), dtype.ptr()); | ||
| 279 | + return detail::check_array<typename D::value_type>(h); | ||
| 283 | 280 | } | |
| 284 | 281 | ||
| 285 | 282 | template <class D> | |
@@ -321,6 +318,30 @@ namespace xt | |||
| 321 | 318 | return *static_cast<const derived_type*>(this); | |
| 322 | 319 | } | |
| 323 | 320 | ||
| 321 | + namespace detail | ||
| 322 | + { | ||
| 323 | + template <class S> | ||
| 324 | + struct check_dims | ||
| 325 | + { | ||
| 326 | + static bool run(std::size_t) | ||
| 327 | + { | ||
| 328 | + return true; | ||
| 329 | + } | ||
| 330 | + }; | ||
| 331 | + | ||
| 332 | + template <class T, std::size_t N> | ||
| 333 | + struct check_dims<std::array<T, N>> | ||
| 334 | + { | ||
| 335 | + static bool run(std::size_t new_dim) | ||
| 336 | + { | ||
| 337 | + if(new_dim != N) | ||
| 338 | + { | ||
| 339 | + throw std::runtime_error("Dims not matching."); | ||
| 340 | + } | ||
| 341 | + return new_dim == N; | ||
| 342 | + } | ||
| 343 | + }; | ||
| 344 | + } | ||
| 324 | 345 | ||
| 325 | 346 | /** | |
| 326 | 347 | * resizes the container. | |
@@ -359,6 +380,7 @@ namespace xt | |||
| 359 | 380 | template <class S> | |
| 360 | 381 | inline void pycontainer<D>::resize(const S& shape, const strides_type& strides) | |
| 361 | 382 | { | |
| 383 | + detail::check_dims<shape_type>::run(shape.size()); | ||
| 362 | 384 | derived_type tmp(xtl::forward_sequence<shape_type>(shape), strides); | |
| 363 | 385 | *static_cast<derived_type*>(this) = std::move(tmp); | |
| 364 | 386 | } | |
@@ -369,9 +391,9 @@ namespace xt | |||
| 369 | 391 | { | |
| 370 | 392 | if (compute_size(shape) != this->size()) | |
| 371 | 393 | { | |
| 372 | - throw std::runtime_error("Cannot reshape with incorrect number of elements."); | ||
| 394 | + throw std::runtime_error("Cannot reshape with incorrect number of elements (" + std::to_string(this->size()) + " vs " + std::to_string(compute_size(shape)) + ")"); | ||
| 373 | 395 | } | |
| 374 | - | ||
| 396 | + detail::check_dims<shape_type>::run(shape.size()); | ||
| 375 | 397 | layout = default_assignable_layout(layout); | |
| 376 | 398 | ||
| 377 | 399 | NPY_ORDER npy_layout; | |
@@ -388,7 +410,8 @@ namespace xt | |||
| 388 | 410 | throw std::runtime_error("Cannot reshape with unknown layout_type."); | |
| 389 | 411 | } | |
| 390 | 412 | ||
| 391 | - PyArray_Dims dims = {reinterpret_cast<npy_intp*>(shape.data()), static_cast<int>(shape.size())}; | ||
| 413 | + using shape_ptr = typename std::decay_t<S>::pointer; | ||
| 414 | + PyArray_Dims dims = {reinterpret_cast<npy_intp*>(const_cast<shape_ptr>(shape.data())), static_cast<int>(shape.size())}; | ||
| 392 | 415 | auto new_ptr = PyArray_Newshape((PyArrayObject*) this->ptr(), &dims, npy_layout); | |
| 393 | 416 | auto old_ptr = this->ptr(); | |
| 394 | 417 | this->ptr() = new_ptr; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -163,6 +163,9 @@ namespace xt | |||
| 163 | 163 | explicit pytensor(const shape_type& shape, const strides_type& strides, const_reference value); | |
| 164 | 164 | explicit pytensor(const shape_type& shape, const strides_type& strides); | |
| 165 | 165 | ||
| 166 | + template <class S = shape_type> | ||
| 167 | + static pytensor from_shape(S&& shape); | ||
| 168 | + | ||
| 166 | 169 | pytensor(const self_type& rhs); | |
| 167 | 170 | self_type& operator=(const self_type& rhs); | |
| 168 | 171 | ||
@@ -315,6 +318,19 @@ namespace xt | |||
| 315 | 318 | { | |
| 316 | 319 | init_tensor(shape, strides); | |
| 317 | 320 | } | |
| 321 | + | ||
| 322 | + /** | ||
| 323 | + * Allocates and returns an pytensor with the specified shape. | ||
| 324 | + * @param shape the shape of the pytensor | ||
| 325 | + */ | ||
| 326 | + template <class T, std::size_t N, layout_type L> | ||
| 327 | + template <class S> | ||
| 328 | + inline pytensor<T, N, L> pytensor<T, N, L>::from_shape(S&& shape) | ||
| 329 | + { | ||
| 330 | + detail::check_dims<shape_type>::run(shape.size()); | ||
| 331 | + auto shp = xtl::forward_sequence<shape_type>(shape); | ||
| 332 | + return self_type(shp); | ||
| 333 | + } | ||
| 318 | 334 | //@} | |
| 319 | 335 | ||
| 320 | 336 | /** | |
@@ -429,6 +445,12 @@ namespace xt | |||
| 429 | 445 | std::transform(PyArray_STRIDES(this->python_array()), PyArray_STRIDES(this->python_array()) + N, m_strides.begin(), | |
| 430 | 446 | [](auto v) { return v / sizeof(T); }); | |
| 431 | 447 | adapt_strides(m_shape, m_strides, m_backstrides); | |
| 448 | + | ||
| 449 | + if (L != layout_type::dynamic && !do_strides_match(m_shape, m_strides, L)) | ||
| 450 | + { | ||
| 451 | + throw std::runtime_error("NumPy: passing container with bad strides for layout (is it a view?)."); | ||
| 452 | + } | ||
| 453 | + | ||
| 432 | 454 | m_storage = storage_type(reinterpret_cast<pointer>(PyArray_DATA(this->python_array())), | |
| 433 | 455 | this->get_min_stride() * static_cast<size_type>(PyArray_SIZE(this->python_array()))); | |
| 434 | 456 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -52,6 +52,15 @@ namespace xt | |||
| 52 | 52 | } | |
| 53 | 53 | } | |
| 54 | 54 | ||
| 55 | + TEST(pyarray, from_shape) | ||
| 56 | + { | ||
| 57 | + auto arr = pyarray<double>::from_shape({5, 2, 6}); | ||
| 58 | + auto exp_shape = std::vector<std::size_t>{5, 2, 6}; | ||
| 59 | + EXPECT_TRUE(std::equal(arr.shape().begin(), arr.shape().end(), exp_shape.begin())); | ||
| 60 | + EXPECT_EQ(arr.shape().size(), 3); | ||
| 61 | + EXPECT_EQ(arr.size(), 5 * 2 * 6); | ||
| 62 | + } | ||
| 63 | + | ||
| 55 | 64 | TEST(pyarray, strided_constructor) | |
| 56 | 65 | { | |
| 57 | 66 | central_major_result<> cmr; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -51,6 +51,18 @@ namespace xt | |||
| 51 | 51 | } | |
| 52 | 52 | } | |
| 53 | 53 | ||
| 54 | + TEST(pytensor, from_shape) | ||
| 55 | + { | ||
| 56 | + auto arr = pytensor<double, 3>::from_shape({5, 2, 6}); | ||
| 57 | + auto exp_shape = std::vector<std::size_t>{5, 2, 6}; | ||
| 58 | + EXPECT_TRUE(std::equal(arr.shape().begin(), arr.shape().end(), exp_shape.begin())); | ||
| 59 | + EXPECT_EQ(arr.shape().size(), 3); | ||
| 60 | + EXPECT_EQ(arr.size(), 5 * 2 * 6); | ||
| 61 | + using pyt3 = pytensor<double, 3>; | ||
| 62 | + std::vector<std::size_t> shp = std::vector<std::size_t>{5, 2}; | ||
| 63 | + EXPECT_THROW(pyt3::from_shape(shp), std::runtime_error); | ||
| 64 | + } | ||
| 65 | + | ||
| 54 | 66 | TEST(pytensor, strided_constructor) | |
| 55 | 67 | { | |
| 56 | 68 | central_major_result<container_type> cmr; | |
@@ -211,8 +223,12 @@ namespace xt | |||
| 211 | 223 | { | |
| 212 | 224 | pytensor<int, 2> a = {{1,2,3}, {4,5,6}}; | |
| 213 | 225 | auto ptr = a.data(); | |
| 226 | + a.reshape(a.shape()); // compilation check | ||
| 214 | 227 | a.reshape({1, 6}); | |
| 215 | 228 | EXPECT_EQ(ptr, a.data()); | |
| 216 | - EXPECT_THROW(a.reshape({6}), std::runtime_error); | ||
| 229 | + EXPECT_THROW(a.reshape(std::vector<std::size_t>{6}), std::runtime_error); | ||
| 230 | + // note this throws because std array has only 1 element initialized | ||
| 231 | + // and the second element is `0`. | ||
| 232 | + EXPECT_THROW(a.reshape({6, 5}), std::runtime_error); | ||
| 217 | 233 | } | |
| 218 | 234 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,6 +12,7 @@ | |||
| 12 | 12 | #include "xtensor/xarray.hpp" | |
| 13 | 13 | #define FORCE_IMPORT_ARRAY | |
| 14 | 14 | #include "xtensor-python/pyarray.hpp" | |
| 15 | + #include "xtensor-python/pytensor.hpp" | ||
| 15 | 16 | #include "xtensor-python/pyvectorize.hpp" | |
| 16 | 17 | ||
| 17 | 18 | namespace py = pybind11; | |
@@ -154,6 +155,22 @@ void char_array(xt::pyarray<char[20]>& carr) | |||
| 154 | 155 | carr(2)[3] = '\0'; | |
| 155 | 156 | } | |
| 156 | 157 | ||
| 158 | + void row_major_tensor(xt::pytensor<double, 3, xt::layout_type::row_major>& arg) | ||
| 159 | + { | ||
| 160 | + if (!std::is_same<decltype(arg.begin()), double*>::value) | ||
| 161 | + { | ||
| 162 | + throw std::runtime_error("TEST FAILED"); | ||
| 163 | + } | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + void col_major_array(xt::pyarray<double, xt::layout_type::column_major>& arg) | ||
| 167 | + { | ||
| 168 | + if (!std::is_same<decltype(arg.template begin<xt::layout_type::column_major>()), double*>::value) | ||
| 169 | + { | ||
| 170 | + throw std::runtime_error("TEST FAILED"); | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + | ||
| 157 | 174 | PYBIND11_MODULE(xtensor_python_test, m) | |
| 158 | 175 | { | |
| 159 | 176 | xt::import_numpy(); | |
@@ -197,4 +214,7 @@ PYBIND11_MODULE(xtensor_python_test, m) | |||
| 197 | 214 | m.def("dtype_to_python", dtype_to_python); | |
| 198 | 215 | m.def("dtype_from_python", dtype_from_python); | |
| 199 | 216 | m.def("char_array", char_array); | |
| 217 | + | ||
| 218 | + m.def("col_major_array", col_major_array); | ||
| 219 | + m.def("row_major_tensor", row_major_tensor); | ||
| 200 | 220 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -46,6 +46,7 @@ def __str__(self): | |||
| 46 | 46 | ['main.cpp'], | |
| 47 | 47 | include_dirs=[ | |
| 48 | 48 | # Path to pybind11 headers | |
| 49 | + '../include/', | ||
| 49 | 50 | get_pybind_include(), | |
| 50 | 51 | get_pybind_include(user=True), | |
| 51 | 52 | # Path to numpy headers | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -125,3 +125,24 @@ def test_char_array(self): | |||
| 125 | 125 | self.assertEqual(var[0], b'hello') | |
| 126 | 126 | self.assertEqual(var[1], b'from') | |
| 127 | 127 | self.assertEqual(var[2], b'c++') | |
| 128 | + | ||
| 129 | + def test_col_row_major(self): | ||
| 130 | + var = np.arange(50, dtype=float).reshape(2, 5, 5) | ||
| 131 | + | ||
| 132 | + with self.assertRaises(RuntimeError): | ||
| 133 | + xt.col_major_array(var) | ||
| 134 | + | ||
| 135 | + with self.assertRaises(RuntimeError): | ||
| 136 | + xt.row_major_tensor(var.T) | ||
| 137 | + | ||
| 138 | + with self.assertRaises(RuntimeError): | ||
| 139 | + xt.row_major_tensor(var[:, ::2, ::2]) | ||
| 140 | + | ||
| 141 | + with self.assertRaises(RuntimeError): | ||
| 142 | + # raise for wrong dimension | ||
| 143 | + xt.row_major_tensor(var[0, 0, :]) | ||
| 144 | + | ||
| 145 | + xt.row_major_tensor(var) | ||
| 146 | + varF = np.arange(50, dtype=float).reshape(2, 5, 5, order='F') | ||
| 147 | + xt.col_major_array(varF) | ||
| 148 | + xt.col_major_array(varF[:, :, 0]) # still col major! | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments