From 1b6b7dbddd747cf45d2e633fcdc041549e110700 Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Tue, 6 Jan 2026 16:36:59 +0100 Subject: [PATCH 01/25] Removed deprecated osx 13 runner (#2879) --- .github/workflows/osx.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index c278216b0..5dbce477e 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -18,7 +18,6 @@ jobs: fail-fast: false matrix: os: - - 13 - 14 - 15 From 0c4ca0de4707d966633e41d4d9ad5b36d1432e44 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Fri, 9 Jan 2026 04:14:19 -0800 Subject: [PATCH 02/25] Add support of 1D expression in xcsv (#2870) --- include/xtensor/io/xcsv.hpp | 41 ++++++++++++++++++++++--------------- test/test_xcsv.cpp | 25 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/include/xtensor/io/xcsv.hpp b/include/xtensor/io/xcsv.hpp index 2b758bd9e..080ccaf54 100644 --- a/include/xtensor/io/xcsv.hpp +++ b/include/xtensor/io/xcsv.hpp @@ -10,7 +10,6 @@ #ifndef XTENSOR_CSV_HPP #define XTENSOR_CSV_HPP -#include #include #include #include @@ -211,30 +210,40 @@ namespace xt { using size_type = typename E::size_type; const E& ex = e.derived_cast(); - if (ex.dimension() != 2) + if (ex.dimension() == 1) { - XTENSOR_THROW(std::runtime_error, "Only 2-D expressions can be serialized to CSV"); - } - size_type nbrows = ex.shape()[0], nbcols = ex.shape()[1]; - auto st = ex.stepper_begin(ex.shape()); - for (size_type r = 0; r != nbrows; ++r) - { - for (size_type c = 0; c != nbcols; ++c) + const size_type n = ex.shape()[0]; + for (size_type i = 0; i != n; ++i) { - stream << *st; - if (c != nbcols - 1) + stream << ex(i); + if (i != n - 1) { - st.step(1); stream << ','; } - else + } + stream << std::endl; + } + else if (ex.dimension() == 2) + { + const size_type nbrows = ex.shape()[0]; + const size_type nbcols = ex.shape()[1]; + for (size_type r = 0; r != nbrows; ++r) + { + for (size_type c = 0; c != nbcols; ++c) { - st.reset(1); - st.step(0); - stream << std::endl; + stream << ex(r, c); + if (c != nbcols - 1) + { + stream << ','; + } } + stream << std::endl; } } + else + { + XTENSOR_THROW(std::runtime_error, "Only 1-D and 2-D expressions can be serialized to CSV"); + } } struct xcsv_config diff --git a/test/test_xcsv.cpp b/test/test_xcsv.cpp index 584d17345..767718fe1 100644 --- a/test/test_xcsv.cpp +++ b/test/test_xcsv.cpp @@ -7,10 +7,8 @@ * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ -#include #include -#include "xtensor/core/xmath.hpp" #include "xtensor/io/xcsv.hpp" #include "xtensor/io/xio.hpp" @@ -18,6 +16,19 @@ namespace xt { + TEST(xcsv, load_1D) + { + const std::string source = "1, 2, 3, 4"; + + std::stringstream source_stream(source); + + const xtensor res = load_csv(source_stream); + + const xtensor exp{{1, 2, 3, 4}}; + + ASSERT_TRUE(all(equal(res, exp))); + } + TEST(xcsv, load_double) { std::string source = "1.0, 2.0, 3.0, 4.0\n" @@ -49,6 +60,16 @@ namespace xt ASSERT_TRUE(all(equal(res, exp))); } + TEST(xcsv, dump_1D) + { + xtensor data{{1.0, 2.0, 3.0, 4.0}}; + + std::stringstream res; + + dump_csv(res, data); + ASSERT_EQ("1,2,3,4\n", res.str()); + } + TEST(xcsv, dump_double) { xtensor data{{1.0, 2.0, 3.0, 4.0}, {10.0, 12.0, 15.0, 18.0}}; From 18f6524829d8ac6399374f9ecbd21b959f75424d Mon Sep 17 00:00:00 2001 From: Alexandre Hoffmann Date: Thu, 29 Jan 2026 14:05:59 +0100 Subject: [PATCH 03/25] added a mapper that maps the indexes of a view to the indices of a container (#2880) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description The `index_mapper` class provides functionality to convert indices from a view's coordinate system to the corresponding indices in the underlying container. This is particularly useful for views that contain integral slices (fixed indices), as these slices reduce the dimensionality of the view. Example: ```cpp xt::xarray a = xt::arange(24).reshape({2, 3, 4}); auto view1 = xt::view(a, 1, xt::all(), xt::all()); // Fixed first dimension index_mapper mapper; // Map view indices (i,j) to container indices (1,i,j) double val = mapper.map(a, view1, 0, 0); // Returns a(1, 0, 0) double val2 = mapper.map(a, view1, 1, 2); // Returns a(1, 1, 2) ``` --------- Co-authored-by: Alexandre Hoffmann --- include/xtensor/views/index_mapper.hpp | 538 +++++++++++++++++++++++++ include/xtensor/views/xview_utils.hpp | 3 + test/test_xview.cpp | 129 ++++++ 3 files changed, 670 insertions(+) create mode 100644 include/xtensor/views/index_mapper.hpp diff --git a/include/xtensor/views/index_mapper.hpp b/include/xtensor/views/index_mapper.hpp new file mode 100644 index 000000000..672cb2207 --- /dev/null +++ b/include/xtensor/views/index_mapper.hpp @@ -0,0 +1,538 @@ +/*************************************************************************** + * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * + * Copyright (c) QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +#ifndef XTENSOR_INDEX_MAPPER_HPP +#define XTENSOR_INDEX_MAPPER_HPP + +#include "xview.hpp" + +namespace xt +{ + + template + struct index_mapper; + + /** + * @enum access_t + * @brief Defines the access policy for the underlying container. + */ + enum class access_t + { + SAFE, ///< Use .at() accessor (bounds checked). + UNSAFE ///< Use operator() accessor (no bounds checking). + }; + + /** + * @class index_mapper + * @brief A helper class for mapping indices between views and their underlying containers. + * + * The `index_mapper` class provides functionality to convert indices from a view's coordinate system + * to the corresponding indices in the underlying container. This is particularly useful for views + * that contain integral slices (fixed indices), as these slices reduce the dimensionality of the view. + * + * @tparam UndefinedView The primary template parameter, specialized for `xt::xview` types. + * + * @note This class is specialized for `xt::xview` types only. + * Other view types will trigger a compilation error. + * + * @example + * @code + * xt::xarray a = xt::arange(24).reshape({2, 3, 4}); + * auto view1 = xt::view(a, 1, xt::all(), xt::all()); // Fixed first dimension + * index_mapper mapper; + * + * // Map view indices (i,j) to container indices (1,i,j) + * double val = mapper.map(a, view1, 0, 0); // Returns a(1, 0, 0) + * double val2 = mapper.map(a, view1, 1, 2); // Returns a(1, 1, 2) + * @endcode + */ + template + class index_mapper> + { + public: + + /// @brief The view type this mapper works with + using view_type = xt::xview; + + /// @brief Reference type of the underlying view. + using reference = typename xt::xview::reference; + + /// @brief Const reference type of the underlying view. + using const_reference = typename xt::xview::const_reference; + + /// @brief Total number of explicitly passed slices in the view + static constexpr size_t n_slices = sizeof...(Slices); + + /// @brief Number of slices that are integral constants (fixed indices) + static constexpr size_t nb_integral_slices = (std::is_integral_v + ...); + + /// @brief Number of slices that are xt::newaxis (insert a dimension) + static constexpr size_t nb_new_axis_slices = (xt::detail::is_newaxis_v + ...); + + /** + * Compute how many indices are needed to address the underlying container + * when given N indices in the view. + */ + template + static constexpr size_t n_indices_full_v = size_t(sizeof...(Indices) + nb_integral_slices); + + /** + * @brief Map view indices to container reference using UNSAFE access. + * @param container The source container. + * @param view The view defining the mapping. + * @param indices The indices in view-space. + * @return Reference to the element in the container. + */ + template + reference map(UnderlyingContainer& container, const view_type& view, const Indices... indices) const; + + /** + * @brief Map view indices to container const_reference using UNSAFE access. + * @param container The source container. + * @param view The view defining the mapping. + * @param indices The indices in view-space. + * @return Reference to the element in the container. + */ + template + const_reference + cmap(const UnderlyingContainer& container, const view_type& view, const Indices... indices) const; + + /** + * @brief Map view indices to container reference using SAFE access. + * @param container The source container. + * @param view The view defining the mapping. + * @param indices The indices in view-space. + * @return Reference to the element in the container. + */ + template + reference map_at(UnderlyingContainer& container, const view_type& view, const Indices... indices) const; + + /** + * @brief Map view indices to container const_reference using SAFE access. + * @param container The source container. + * @param view The view defining the mapping. + * @param indices The indices in view-space. + * @return Reference to the element in the container. + */ + template + const_reference + cmap_at(const UnderlyingContainer& container, const view_type& view, const Indices... indices) const; + + /// @brief Return the dimensionality of the view + size_t dimension(const UnderlyingContainer& container) const; + + private: + + /// @brief Alias for selecting reference type based on const-correctness. + template + using conditional_reference = std::conditional_t; + + /// @brief Helper type alias for the I-th slice type + template + using slice_type = std::tuple_element_t>; + + /// @brief True if the I-th slice is an integral slice (fixed index) + template + static consteval bool is_slice_integral(); + + /// @brief True if the I-th slice is a newaxis slice + template + static consteval bool is_slice_new_axis(); + + /** + * Helper metafunction to build an index_sequence that skips + * newaxis slices. + * + * The resulting sequence contains only the indices that + * correspond to real container dimensions. + */ + template + struct indices_sequence_helper + { + // we add the current axis + using not_new_axis_type = typename indices_sequence_helper::type; + + // we skip the current axis + using new_axis_type = typename indices_sequence_helper::type; + + // NOTE: is_slice_new_axis works even if first >= sizeof...(Slices) + using type = std::conditional_t(), new_axis_type, not_new_axis_type>; + }; + + /// @brief Base case: recursion termination + template + struct indices_sequence_helper + { + using type = std::index_sequence; + }; + + ///< @brief Index sequence of non-newaxis slices + template + using indices_sequence = indices_sequence_helper<0, bound>::type; + + /** + * @brief Maps an index for a specific slice to the corresponding index in the underlying container. + * + * For integral slices (fixed indices), returns the fixed index value. + * For non-integral slices (like `xt::all()`), applies the slice transformation to the index. + * + * @tparam I The slice index to map. + * @tparam Index Type of the index (must be integral). + * @param view The view object containing slice information. + * @param i The index within the slice to map. + * @return size_t The mapped index in the underlying container. + * + * @throws Assertion failure if `i != 0` for integral slices. + * @throws Assertion failure if `i >= slice.size()` for non-integral slices. + */ + template + size_t map_ith_index(const view_type& view, const Index i) const; + + /** + * @brief Main recursion/logic handler for mapping operations. + * Handles dimension dropping if the provided index count exceeds view dimensionality. + * + * @tparam IS_CONST Boolean flag; true if the operation is on a const container. + * @tparam ACCESS The access policy (SAFE for .at(), UNSAFE for operator()). + * @param is_const Tag used for compile-time dispatching of const-correctness. + * @param container The underlying container (xarray, xtensor, etc.) being accessed. + * @param access Tag used for compile-time dispatching of the access method. + * @param view The xview instance that defines the coordinate transformation. + * @param firstIndice The current leading index in the coordinate pack. + * @param otherIndices The remaining indices in the coordinate pack. + */ + template + conditional_reference map_main( + std::bool_constant /* is_const */, + std::conditional_t container, + std::integral_constant /* access */, + const view_type& view, + const FirstIndice firstIndice, + const OtherIndices... otherIndices + ) const; + + /** + * @brief Base case for map_main recursion, where no indices is supplied and assumes (0, 0, ...). + * + * @tparam IS_CONST Boolean flag; true if the operation is on a const container. + * @tparam ACCESS The access policy (SAFE for .at(), UNSAFE for operator()). + * @param is_const Tag used for compile-time dispatching of const-correctness. + * @param container The underlying container (xarray, xtensor, etc.) being accessed. + * @param access Tag used for compile-time dispatching of the access method. + * @param view The xview instance that defines the coordinate transformation. + */ + template + conditional_reference map_main( + std::bool_constant /* is_const */, + std::conditional_t container, + std::integral_constant /* access */, + const view_type& view + ) const; + + /** + * @brief Maps all indices and accesses the container. + * + * @tparam IS_CONST Boolean flag for const-correctness. + * @tparam ACCESS The access policy (SAFE or UNSAFE). + * @tparam n_indices The size of the index array (calculated from view/container info). + * @tparam Is A pack of indices `0, 1, ..., n-1` used to unroll the mapping loop. + * @param is_const Tag for const-correctness dispatch. + * @param container The underlying container being accessed. + * @param access Tag for access method dispatch. + * @param view The xview instance providing the slice transformations. + * @param is_seq An index sequence used to drive the parameter pack expansion. + * @param indices An array containing the view-space indices to be mapped. + */ + template + conditional_reference map_all_indices( + std::bool_constant /* is_const */, + std::conditional_t container, + std::integral_constant /* access */, + const view_type& view, + std::index_sequence /* is_seq */, + const std::array& indices + ) const; + + /// @brief Expand view indices into a full index array, inserting dummy indices for integral slices + template + std::array> get_indices_full(const Indices... indices) const; + }; + + /******************************* + * index_mapper implementation * + *******************************/ + + template + template + consteval bool index_mapper>::is_slice_integral() + { + if constexpr (I < sizeof...(Slices)) + { + return std::is_integral_v>; + } + else + { + return false; + } + } + + template + template + consteval bool index_mapper>::is_slice_new_axis() + { + if constexpr (I < sizeof...(Slices)) + { + return xt::detail::is_newaxis_v>; + } + else + { + return false; + } + } + + template + template + auto + index_mapper>::get_indices_full(const Indices... indices) const + -> std::array> + { + constexpr size_t n_indices_full = n_indices_full_v; + + std::array args{size_t(indices)...}; + std::array args_full; + + const auto fill_args_full = [&args_full, &args](std::index_sequence) + { + auto it = std::cbegin(args); + + ((args_full[Is] = (is_slice_integral()) ? size_t(0) : *it++), ...); + }; + + fill_args_full(std::make_index_sequence{}); + + return args_full; + } + + template + template + auto index_mapper>::map( + UnderlyingContainer& container, + const view_type& view, + const Indices... indices + ) const -> reference + { + return map_main( + std::false_type{}, + container, + std::integral_constant{}, + view, + indices... + ); + } + + template + template + auto index_mapper>::cmap( + const UnderlyingContainer& container, + const view_type& view, + const Indices... indices + ) const -> const_reference + { + return map_main( + std::true_type{}, + container, + std::integral_constant{}, + view, + indices... + ); + } + + template + template + auto index_mapper>::map_at( + UnderlyingContainer& container, + const view_type& view, + const Indices... indices + ) const -> reference + { + return map_main( + std::false_type{}, + container, + std::integral_constant{}, + view, + indices... + ); + } + + template + template + auto index_mapper>::cmap_at( + const UnderlyingContainer& container, + const view_type& view, + const Indices... indices + ) const -> const_reference + { + return map_main( + std::true_type{}, + container, + std::integral_constant{}, + view, + indices... + ); + } + + template + template + auto index_mapper>::map_main( + std::bool_constant is_const, + std::conditional_t container, + std::integral_constant access, + const view_type& view, + const FirstIndice firstIndice, + const OtherIndices... otherIndices + ) const -> conditional_reference + { + constexpr size_t n_indices_full = n_indices_full_v; + + constexpr size_t underlying_n_dimensions = xt::static_dimension< + typename std::decay_t::shape_type>::value; + + // If there is too many indices, we need to drop the first ones. + // If the number of dimensions of the underlying container is known at compile time we can drop them + // at compile time Else a runtime-test is requires, which, breaks vectorization. + // I don't know if we can do it in another way. + + if constexpr (underlying_n_dimensions != size_t(-1)) + { + // the number of dimensions of the underlying container is known at compile time. + constexpr size_t n_dimensions = underlying_n_dimensions - nb_integral_slices + nb_new_axis_slices; + + // we can perform compile time checks + if constexpr (1 + sizeof...(OtherIndices) > n_dimensions) + { + return map_main(is_const, container, access, view, otherIndices...); + } + else + { + return map_all_indices( + is_const, + container, + access, + view, + indices_sequence{}, + get_indices_full(firstIndice, otherIndices...) + ); + } + } + else + { + // we need execution time checks + if (1 + sizeof...(OtherIndices) > dimension(container)) + { + return map_main(is_const, container, access, view, otherIndices...); + } + else + { + return map_all_indices( + is_const, + container, + access, + view, + indices_sequence{}, + get_indices_full(firstIndice, otherIndices...) + ); + } + } + } + + template + template + auto index_mapper>::map_main( + std::bool_constant is_const, + std::conditional_t container, + std::integral_constant access, + const view_type& view + ) const -> conditional_reference + { + constexpr size_t n_indices_full = n_indices_full_v<>; + + return map_all_indices( + is_const, + container, + access, + view, + indices_sequence{}, + get_indices_full() + ); + } + + template + template + auto index_mapper>::map_all_indices( + std::bool_constant /* is_const */, + std::conditional_t container, + std::integral_constant /* access */, + const view_type& view, + std::index_sequence /* is_seq */, + const std::array& indices + ) const -> conditional_reference + { + if constexpr (ACCESS == access_t::SAFE) + { + return container.at(map_ith_index(view, indices[Is])...); + } + else + { + return container(map_ith_index(view, indices[Is])...); + } + } + + template + template + auto + index_mapper>::map_ith_index(const view_type& view, const Index i) const + -> size_t + { + if constexpr (I < sizeof...(Slices)) + { + // if the slice is explicitly specified, use it + using current_slice = std::tuple_element_t>; + + static_assert(not xt::detail::is_newaxis_v); + + const auto& slice = std::get(view.slices()); + + if constexpr (std::is_integral_v) + { + assert(i == 0); + return size_t(slice); + } + else + { + assert(i < slice.size()); + return size_t(slice(i)); + } + } + else + { + // else assume xt::all + return i; + } + } + + template + auto index_mapper>::dimension(const UnderlyingContainer& container + ) const -> size_t + { + return container.dimension() - nb_integral_slices + nb_new_axis_slices; + } + +} // namespace xt + +#endif // XTENSOR_INDEX_MAPPER_HPP diff --git a/include/xtensor/views/xview_utils.hpp b/include/xtensor/views/xview_utils.hpp index f74eb07e2..696fa8762 100644 --- a/include/xtensor/views/xview_utils.hpp +++ b/include/xtensor/views/xview_utils.hpp @@ -149,6 +149,9 @@ namespace xt { }; + template + constexpr bool is_newaxis_v = is_newaxis::value; + template struct newaxis_count_impl { diff --git a/test/test_xview.cpp b/test/test_xview.cpp index b2afa3c56..5f81047b2 100644 --- a/test/test_xview.cpp +++ b/test/test_xview.cpp @@ -28,6 +28,7 @@ #include "xtensor/generators/xbuilder.hpp" #include "xtensor/generators/xrandom.hpp" #include "xtensor/misc/xmanipulation.hpp" +#include "xtensor/views/index_mapper.hpp" #include "xtensor/views/xstrided_view.hpp" #include "xtensor/views/xview.hpp" @@ -143,6 +144,76 @@ namespace xt } } + TEST(xview_mapping, simple) + { + view_shape_type shape = {3, 4}; + xarray a(shape); + std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::copy(data.cbegin(), data.cend(), a.template begin()); + + auto view1 = view(a, 1, range(1, 4)); + + index_mapper mapper1; + + EXPECT_EQ(a(1, 1), mapper1.map(a, view1, 0)); + EXPECT_EQ(a(1, 2), mapper1.map(a, view1, 1)); + EXPECT_EQ(size_t(1), mapper1.dimension(a)); + XT_EXPECT_ANY_THROW(mapper1.map_at(a, view1, 10)); + + auto view0 = view(a, 0, range(0, 3)); + index_mapper mapper0; + + EXPECT_EQ(a(0, 0), mapper0.map(a, view0, 0)); + EXPECT_EQ(a(0, 1), mapper0.map(a, view0, 1)); + EXPECT_EQ(size_t(1), mapper0.dimension(a)); + + auto view2 = view(a, range(0, 2), 2); + index_mapper mapper2; + EXPECT_EQ(a(0, 2), mapper2.map(a, view2, 0)); + EXPECT_EQ(a(1, 2), mapper2.map(a, view2, 1)); + EXPECT_EQ(size_t(1), mapper2.dimension(a)); + + auto view4 = view(a, 1); + index_mapper mapper4; + EXPECT_EQ(size_t(1), mapper4.dimension(a)); + + auto view5 = view(view4, 1); + index_mapper mapper5; + EXPECT_EQ(size_t(0), mapper5.dimension(view4)); + + auto view6 = view(a, 1, all()); + index_mapper mapper6; + EXPECT_EQ(a(1, 0), mapper6.map(a, view6, 0)); + EXPECT_EQ(a(1, 1), mapper6.map(a, view6, 1)); + EXPECT_EQ(a(1, 2), mapper6.map(a, view6, 2)); + EXPECT_EQ(a(1, 3), mapper6.map(a, view6, 3)); + + auto view7 = view(a, all(), 2); + index_mapper mapper7; + EXPECT_EQ(a(0, 2), mapper7.map(a, view7, 0)); + EXPECT_EQ(a(1, 2), mapper7.map(a, view7, 1)); + EXPECT_EQ(a(2, 2), mapper7.map(a, view7, 2)); + } + + TEST(xview_mapping, indices) + { + xarray a = {{1., 2., 3.}, {4., 5., 6.}}; + + auto view1 = view(a, all(), all()); + index_mapper mapper1; + + EXPECT_EQ(a(0, 2), mapper1.map(a, view1, 0, 2)); + EXPECT_EQ(a(0, 2), mapper1.map(a, view1, 2)); + EXPECT_EQ(a(1, 2), mapper1.map(a, view1, 1, 1, 2)); + + auto view2 = view(a, all()); + index_mapper mapper2; + + EXPECT_EQ(a(0, 2), mapper2.map(a, view2, 0, 2)); + EXPECT_EQ(a(0, 2), mapper2.map(a, view2, 2)); + EXPECT_EQ(a(1, 2), mapper2.map(a, view2, 1, 1, 2)); + } + TEST(xview, negative_index) { view_shape_type shape = {3, 4}; @@ -269,6 +340,38 @@ namespace xt EXPECT_EQ(a(1, 1, 1), view1.element(idx.cbegin(), idx.cend())); } + TEST(xview_mapping, three_dimensional) + { + view_shape_type shape = {3, 4, 2}; + std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, + + 9, 10, 11, 12, 21, 22, 23, 24, + + 25, 26, 27, 28, 29, 210, 211, 212}; + xarray a(shape); + std::copy(data.cbegin(), data.cend(), a.template begin()); + + auto view1 = view(a, 1, all(), all()); + index_mapper mapper1; + + EXPECT_EQ(size_t(2), mapper1.dimension(a)); + EXPECT_EQ(a(1, 0, 0), mapper1.map(a, view1, 0, 0)); + EXPECT_EQ(a(1, 0, 1), mapper1.map(a, view1, 0, 1)); + EXPECT_EQ(a(1, 1, 0), mapper1.map(a, view1, 1, 0)); + EXPECT_EQ(a(1, 1, 1), mapper1.map(a, view1, 1, 1)); + XT_EXPECT_ANY_THROW(mapper1.map_at(a, view1, 10, 10)); + + auto view2 = view(a, 1); + index_mapper mapper2; + + EXPECT_EQ(size_t(2), mapper2.dimension(a)); + EXPECT_EQ(a(1, 0, 0), mapper2.map(a, view2, 0, 0)); + EXPECT_EQ(a(1, 0, 1), mapper2.map(a, view2, 0, 1)); + EXPECT_EQ(a(1, 1, 0), mapper2.map(a, view2, 1, 0)); + EXPECT_EQ(a(1, 1, 1), mapper2.map(a, view2, 1, 1)); + XT_EXPECT_ANY_THROW(mapper2.map_at(a, view2, 10, 10)); + } + TEST(xview, integral_count) { size_t squeeze1 = integral_count>(); @@ -333,6 +436,32 @@ namespace xt EXPECT_EQ(v3(2, 3, 1, 1), arr(1, 2)); } + TEST(xview_mapping, access) + { + xt::xarray arr{{1.0, 2.0, 3.0}, {2.0, 5.0, 7.0}, {2.0, 5.0, 7.0}}; + + auto v1 = xt::view(arr, 1, xt::range(1, 3)); + index_mapper mapper1; + + EXPECT_EQ(mapper1.map(arr, v1), arr(0, 1)); + EXPECT_EQ(mapper1.map(arr, v1, 1), arr(1, 2)); + EXPECT_EQ(mapper1.map(arr, v1, 1, 1), arr(1, 2)); + + auto v2 = xt::view(arr, all(), newaxis(), all()); + index_mapper mapper2; + + // EXPECT_EQ(v2(1), arr(0, 1)); + EXPECT_EQ(mapper2.map(arr, v2, 1, 0, 2), arr(1, 2)); + EXPECT_EQ(mapper2.map(arr, v2, 2, 1, 0, 2), arr(1, 2)); + + auto v3 = xt::view(arr, xt::range(0, 2), xt::range(1, 3)); + index_mapper mapper3; + + // EXPECT_EQ(v3(1), arr(0, 2)); + EXPECT_EQ(mapper3.map(arr, v3, 1, 1), arr(1, 2)); + EXPECT_EQ(mapper3.map(arr, v3, 2, 3, 1, 1), arr(1, 2)); + } + TEST(xview, unchecked) { xt::xarray arr{{1.0, 2.0, 3.0}, {2.0, 5.0, 7.0}, {2.0, 5.0, 7.0}}; From 5988352ee6aec2e2ee957187df51fabd9123c824 Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Tue, 7 Apr 2026 10:09:34 +0200 Subject: [PATCH 04/25] =?UTF-8?q?Updated=20language=C3=A8formatters-pre-co?= =?UTF-8?q?mmit-hooks=20(#2890)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Checklist - [ ] The title and commit message(s) are descriptive. - [ ] Small commits made to fix your PR have been squashed to avoid history pollution. - [ ] Tests have been added for new features or bug fixes. - [ ] API of new functions and classes are documented. # Description --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d67461681..6e33ed170 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: - id: remove-tabs args: [--whitespaces-count, '4'] - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks - rev: v2.11.0 + rev: v2.16.0 hooks: - id: pretty-format-yaml args: [--autofix, --indent, '2'] From f21347a93c77218528521bdce9524e76bb801e31 Mon Sep 17 00:00:00 2001 From: Kwonunn Date: Tue, 7 Apr 2026 11:36:02 +0200 Subject: [PATCH 05/25] Fix NPY header length error due to signed->unsigned conversion (#2889) # Checklist - [x] The title and commit message(s) are descriptive. - [ ] Small commits made to fix your PR have been squashed to avoid history pollution. - [ ] Tests have been added for new features or bug fixes. - [ ] ~~API of new functions and classes are documented.~~ # Description This PR fixes an error pertaining to reading the length of the header of an npy file. The header is read as two `char`s and then combined into a `uint16_t`. Previously due to `char` being a signed value, any value with the MSB set would get converted as if it were a negative number and thus misinterpreted. For example, the bytes `F6 00` which means a header of 246 bytes would be interpreted as a header of 65526 bytes. I think the code could be shortened a little, but I think when messing with bits like this it's best to be explicit. Also, the compiler will likely optimize it anyway. --- include/xtensor/io/xnpy.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/xtensor/io/xnpy.hpp b/include/xtensor/io/xnpy.hpp index 369d68c9d..61739cfe0 100644 --- a/include/xtensor/io/xnpy.hpp +++ b/include/xtensor/io/xnpy.hpp @@ -482,7 +482,9 @@ namespace xt char header_len_le16[2]; istream.read(header_len_le16, 2); - uint16_t header_length = uint16_t(header_len_le16[0] << 0) | uint16_t(header_len_le16[1] << 8); + uint16_t header_b0 = static_cast(static_cast(header_len_le16[0])); + uint16_t header_b1 = static_cast(static_cast(header_len_le16[1])) << 8; + uint16_t header_length = header_b0 | header_b1; if ((magic_string_length + 2 + 2 + header_length) % 16 != 0) { @@ -502,8 +504,11 @@ namespace xt char header_len_le32[4]; istream.read(header_len_le32, 4); - uint32_t header_length = uint32_t(header_len_le32[0] << 0) | uint32_t(header_len_le32[1] << 8) - | uint32_t(header_len_le32[2] << 16) | uint32_t(header_len_le32[3] << 24); + uint32_t header_b0 = static_cast(static_cast(header_len_le32[0])); + uint32_t header_b1 = static_cast(static_cast(header_len_le32[1])) << 8; + uint32_t header_b2 = static_cast(static_cast(header_len_le32[2])) << 16; + uint32_t header_b3 = static_cast(static_cast(header_len_le32[3])) << 24; + uint32_t header_length = header_b0 | header_b1 | header_b2 | header_b3; if ((magic_string_length + 2 + 4 + header_length) % 16 != 0) { From d67005490c9722c9fc348df8c61b61e87c21fcf9 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Wed, 15 Apr 2026 17:09:36 +0200 Subject: [PATCH 06/25] Fix errors and warnings in the documentation generation (#2891) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description The goal of this pullrequest is to fix thee error and warning during the documentation generation. --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> --- docs/source/api/accumulating_functions.rst | 9 +-- docs/source/api/basic_functions.rst | 25 +------ docs/source/api/classif_functions.rst | 11 +-- docs/source/api/error_functions.rst | 9 +-- docs/source/api/exponential_functions.rst | 15 +--- docs/source/api/hyperbolic_functions.rst | 19 +---- docs/source/api/index_related.rst | 9 +-- docs/source/api/nan_functions.rst | 25 +------ docs/source/api/nearint_operations.rst | 13 +--- docs/source/api/operators.rst | 71 +++---------------- docs/source/api/power_functions.rst | 15 +--- docs/source/api/reducing_functions.rst | 61 +--------------- docs/source/api/trigonometric_functions.rst | 15 +--- docs/source/api/xaccessible.rst | 16 +++++ docs/source/api/xbuilder.rst | 2 +- docs/source/api/xfft.rst | 16 +++++ docs/source/api/xhistogram.rst | 29 ++------ docs/source/api/xjson.rst | 8 ++- docs/source/api/xreducer.rst | 7 +- docs/source/api/xset_operation.rst | 22 +++--- docs/source/api/xview.rst | 1 - docs/source/build-options.rst | 2 +- docs/source/dev-build-options.rst | 2 +- docs/source/expression.rst | 2 +- docs/source/external-structures.rst | 2 +- docs/source/index.rst | 2 +- docs/source/quickref/chunked_arrays.rst | 4 +- docs/source/random.rst | 6 +- docs/source/related.rst | 10 +-- docs/source/view.rst | 6 +- include/xtensor/chunk/xchunked_array.hpp | 2 +- include/xtensor/core/xeval.hpp | 2 +- include/xtensor/core/xshape.hpp | 6 +- include/xtensor/core/xstrides.hpp | 10 ++- include/xtensor/generators/xbuilder.hpp | 2 +- include/xtensor/generators/xrandom.hpp | 9 +-- include/xtensor/misc/xcomplex.hpp | 2 +- include/xtensor/misc/xhistogram.hpp | 10 +++ include/xtensor/misc/xmanipulation.hpp | 8 +-- include/xtensor/misc/xset_operation.hpp | 5 ++ include/xtensor/misc/xsort.hpp | 4 +- .../optional/xoptional_assembly_base.hpp | 4 +- include/xtensor/reducers/xreducer.hpp | 1 + include/xtensor/views/xaxis_iterator.hpp | 2 +- include/xtensor/views/xfunctor_view.hpp | 2 +- include/xtensor/views/xindex_view.hpp | 6 +- 46 files changed, 160 insertions(+), 349 deletions(-) create mode 100644 docs/source/api/xaccessible.rst create mode 100644 docs/source/api/xfft.rst diff --git a/docs/source/api/accumulating_functions.rst b/docs/source/api/accumulating_functions.rst index edcc26909..1842912e1 100644 --- a/docs/source/api/accumulating_functions.rst +++ b/docs/source/api/accumulating_functions.rst @@ -11,10 +11,5 @@ Accumulating functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: cumsum(E&&) - -.. doxygenfunction:: cumsum(E&&, std::ptrdiff_t) - -.. doxygenfunction:: cumprod(E&&) - -.. doxygenfunction:: cumprod(E&&, std::ptrdiff_t) +.. doxygengroup:: acc_functions + :members: diff --git a/docs/source/api/basic_functions.rst b/docs/source/api/basic_functions.rst index c96e34d66..c6e8020b8 100644 --- a/docs/source/api/basic_functions.rst +++ b/docs/source/api/basic_functions.rst @@ -11,26 +11,5 @@ Basic functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: abs(E&&) - -.. doxygenfunction:: fabs(E&&) - -.. doxygenfunction:: fmod(E1&&, E2&&) - -.. doxygenfunction:: remainder(E1&&, E2&&) - -.. doxygenfunction:: fma(E1&&, E2&&, E3&&) - -.. doxygenfunction:: maximum(E1&&, E2&&) - -.. doxygenfunction:: minimum(E1&&, E2&&) - -.. doxygenfunction:: fmax(E1&&, E2&&) - -.. doxygenfunction:: fmin(E1&&, E2&&) - -.. doxygenfunction:: fdim(E1&&, E2&&) - -.. doxygenfunction:: clip(E1&&, E2&&, E3&&) - -.. doxygenfunction:: sign(E&&) +.. doxygengroup:: basic_functions + :members: diff --git a/docs/source/api/classif_functions.rst b/docs/source/api/classif_functions.rst index d170f737b..f39602b2b 100644 --- a/docs/source/api/classif_functions.rst +++ b/docs/source/api/classif_functions.rst @@ -11,12 +11,5 @@ Classification functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: isfinite(E&&) - -.. doxygenfunction:: isinf(E&&) - -.. doxygenfunction:: isnan(E&&) - -.. doxygenfunction:: isclose(E1&&, E2&&, double, double, bool) - -.. doxygenfunction:: allclose(E1&&, E2&, double, double) +.. doxygengroup:: classif_functions + :members: diff --git a/docs/source/api/error_functions.rst b/docs/source/api/error_functions.rst index 7b335e4cc..be2312f08 100644 --- a/docs/source/api/error_functions.rst +++ b/docs/source/api/error_functions.rst @@ -11,10 +11,5 @@ Error and gamma functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: erf(E&&) - -.. doxygenfunction:: erfc(E&&) - -.. doxygenfunction:: tgamma(E&&) - -.. doxygenfunction:: lgamma(E&&) +.. doxygengroup:: err_functions + :members: diff --git a/docs/source/api/exponential_functions.rst b/docs/source/api/exponential_functions.rst index e2202dd67..65caeed74 100644 --- a/docs/source/api/exponential_functions.rst +++ b/docs/source/api/exponential_functions.rst @@ -11,16 +11,5 @@ Exponential functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: exp(E&&) - -.. doxygenfunction:: exp2(E&&) - -.. doxygenfunction:: expm1(E&&) - -.. doxygenfunction:: log(E&&) - -.. doxygenfunction:: log2(E&&) - -.. doxygenfunction:: log10(E&&) - -.. doxygenfunction:: log1p(E&&) +.. doxygengroup:: exp_functions + :members: diff --git a/docs/source/api/hyperbolic_functions.rst b/docs/source/api/hyperbolic_functions.rst index e7e835104..757c77409 100644 --- a/docs/source/api/hyperbolic_functions.rst +++ b/docs/source/api/hyperbolic_functions.rst @@ -11,20 +11,5 @@ Hyperbolic functions Defined in ``xtensor/core/xmath.hpp`` -.. _sinh-function-reference: -.. doxygenfunction:: sinh(E&&) - -.. _cosh-function-reference: -.. doxygenfunction:: cosh(E&&) - -.. _tanh-function-reference: -.. doxygenfunction:: tanh(E&&) - -.. _asinh-func-ref: -.. doxygenfunction:: asinh(E&&) - -.. _acosh-func-ref: -.. doxygenfunction:: acosh(E&&) - -.. _atanh-func-ref: -.. doxygenfunction:: atanh(E&&) +.. doxygengroup:: hyper_functions + :members: diff --git a/docs/source/api/index_related.rst b/docs/source/api/index_related.rst index 7f74c758e..f7de8fdc2 100644 --- a/docs/source/api/index_related.rst +++ b/docs/source/api/index_related.rst @@ -9,10 +9,7 @@ Index related functions Defined in ``xtensor/core/xoperation.hpp`` -.. doxygenfunction:: where(const T&) +The logical operator group documents the index-producing overloads of +``xt::where``, ``xt::nonzero`` and ``xt::argwhere``. -.. doxygenfunction:: nonzero(const T&) - -.. doxygenfunction:: argwhere - -.. doxygenfunction:: from_indices +``xt::from_indices`` is documented on the ``xtensor`` API page. diff --git a/docs/source/api/nan_functions.rst b/docs/source/api/nan_functions.rst index 5b35e5c0f..918039bce 100644 --- a/docs/source/api/nan_functions.rst +++ b/docs/source/api/nan_functions.rst @@ -11,26 +11,5 @@ NaN functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: nan_to_num(E&&) - -.. doxygenfunction:: nanmin(E&&, X&&, EVS) - -.. doxygenfunction:: nanmax(E&&, X&&, EVS) - -.. doxygenfunction:: nansum(E&&, X&&, EVS) - -.. doxygenfunction:: nanmean(E&&, X&&, EVS) - -.. doxygenfunction:: nanvar(E&&, X&&, EVS) - -.. doxygenfunction:: nanstd(E&&, X&&, EVS) - -.. doxygenfunction:: nanprod(E&&, X&&, EVS) - -.. doxygenfunction:: nancumsum(E&&) - -.. doxygenfunction:: nancumsum(E&&, std::ptrdiff_t) - -.. doxygenfunction:: nancumprod(E&&) - -.. doxygenfunction:: nancumprod(E&&, std::ptrdiff_t) +.. doxygengroup:: nan_functions + :members: diff --git a/docs/source/api/nearint_operations.rst b/docs/source/api/nearint_operations.rst index c4ba6832c..59dd61d19 100644 --- a/docs/source/api/nearint_operations.rst +++ b/docs/source/api/nearint_operations.rst @@ -11,14 +11,5 @@ Nearest integer floating point operations Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: ceil(E&&) - -.. doxygenfunction:: floor(E&&) - -.. doxygenfunction:: trunc(E&&) - -.. doxygenfunction:: round(E&&) - -.. doxygenfunction:: nearbyint(E&&) - -.. doxygenfunction:: rint(E&&) +.. doxygengroup:: nearint_functions + :members: diff --git a/docs/source/api/operators.rst b/docs/source/api/operators.rst index 32a474221..00df9458d 100644 --- a/docs/source/api/operators.rst +++ b/docs/source/api/operators.rst @@ -9,68 +9,17 @@ Operators and related functions Defined in ``xtensor/core/xmath.hpp`` and ``xtensor/core/xoperation.hpp`` -.. doxygenfunction:: operator+(E&&) +.. doxygengroup:: arithmetic_operators + :members: -.. doxygenfunction:: operator-(E&&) +.. doxygengroup:: logical_operators + :members: -.. doxygenfunction:: operator+(E1&&, E2&&) +.. doxygengroup:: comparison_operators + :members: -.. doxygenfunction:: operator-(E1&&, E2&&) +.. doxygengroup:: bitwise_operators + :members: -.. doxygenfunction:: operator*(E1&&, E2&&) - -.. doxygenfunction:: operator/(E1&&, E2&&) - -.. doxygenfunction:: operator||(E1&&, E2&&) - -.. doxygenfunction:: operator&&(E1&&, E2&&) - -.. doxygenfunction:: operator!(E&&) - -.. doxygenfunction:: where(E1&&, E2&&, E3&&) - -.. doxygenfunction:: any(E&&) - -.. doxygenfunction:: all(E&&) - -.. doxygenfunction:: operator<(E1&&, E2&&) - -.. doxygenfunction:: operator<=(E1&&, E2&&) - -.. doxygenfunction:: operator>(E1&&, E2&&) - -.. doxygenfunction:: operator>=(E1&&, E2&&) - -.. doxygenfunction:: operator==(const xexpression&, const xexpression&) - -.. doxygenfunction:: operator!=(const xexpression&, const xexpression&) - -.. doxygenfunction:: equal(E1&&, E2&&) - -.. doxygenfunction:: not_equal(E1&&, E2&&) - -.. doxygenfunction:: less(E1&& e1, E2&& e2) - -.. doxygenfunction:: less_equal(E1&& e1, E2&& e2) - -.. doxygenfunction:: greater(E1&& e1, E2&& e2) - -.. doxygenfunction:: greater_equal(E1&& e1, E2&& e2) - -.. doxygenfunction:: operator&(E1&&, E2&&) - -.. doxygenfunction:: operator|(E1&&, E2&&) - -.. doxygenfunction:: operator^(E1&&, E2&&) - -.. doxygenfunction:: operator~(E&&) - -.. doxygenfunction:: left_shift(E1&&, E2&&) - -.. doxygenfunction:: right_shift(E1&&, E2&&) - -.. doxygenfunction:: operator<<(E1&&, E2&&) - -.. doxygenfunction:: operator>>(E1&&, E2&&) - -.. doxygenfunction:: cast(E&&) +.. doxygengroup:: casting_operators + :members: diff --git a/docs/source/api/power_functions.rst b/docs/source/api/power_functions.rst index a11b5ba27..5ac5a1546 100644 --- a/docs/source/api/power_functions.rst +++ b/docs/source/api/power_functions.rst @@ -12,16 +12,5 @@ Power functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: pow(E1&&, E2&&) - -.. doxygenfunction:: pow(E&&) - -.. doxygenfunction:: square(E1&&) - -.. doxygenfunction:: cube(E1&&) - -.. doxygenfunction:: sqrt(E&&) - -.. doxygenfunction:: cbrt(E&&) - -.. doxygenfunction:: hypot(E1&&, E2&&) +.. doxygengroup:: pow_functions + :members: diff --git a/docs/source/api/reducing_functions.rst b/docs/source/api/reducing_functions.rst index 223e57a92..89c0baff5 100644 --- a/docs/source/api/reducing_functions.rst +++ b/docs/source/api/reducing_functions.rst @@ -9,62 +9,7 @@ Reducing functions **xtensor** provides the following reducing functions for xexpressions: -Defined in ``xtensor/core/xmath.hpp`` +Defined in ``xtensor/core/xmath.hpp`` and ``xtensor/reducers/xnorm.hpp``. -.. doxygenfunction:: sum(E&&, EVS) - -.. doxygenfunction:: sum(E&&, X&&, EVS) - -.. doxygenfunction:: prod(E&&, EVS) - -.. doxygenfunction:: prod(E&&, X&&, EVS) - -.. doxygenfunction:: mean(E&&, EVS) - -.. doxygenfunction:: mean(E&&, X&&, EVS) - -.. doxygenfunction:: average(E&&, EVS) - -.. doxygenfunction:: variance(E&&, EVS) - -.. doxygenfunction:: variance(E&&, X&&, EVS) - -.. doxygenfunction:: variance(E&&, X&&, const D&, EVS) - -.. doxygenfunction:: stddev(E&&, EVS) - -.. doxygenfunction:: stddev(E&&, X&&, EVS) - -.. doxygenfunction:: diff(const xexpression&, unsigned int, std::ptrdiff_t) - -.. doxygenfunction:: amax(E&&, EVS) - -.. doxygenfunction:: amax(E&&, X&&, EVS) - -.. doxygenfunction:: amin(E&&, EVS) - -.. doxygenfunction:: amin(E&&, X&&, EVS) - -.. doxygenfunction:: trapz(const xexpression&, double, std::ptrdiff_t) - -.. doxygenfunction:: trapz(const xexpression&, const xexpression&, std::ptrdiff_t) - -Defined in ``xtensor/reducers/xnorm.hpp`` - -.. doxygenfunction:: norm_l0(E&&, X&&, EVS) - -.. doxygenfunction:: norm_l1(E&&, X&&, EVS) - -.. doxygenfunction:: norm_sq(E&&, X&&, EVS) - -.. doxygenfunction:: norm_l2(E&&, X&&, EVS) - -.. doxygenfunction:: norm_linf(E&&, X&&, EVS) - -.. doxygenfunction:: norm_lp_to_p(E&&, double, X&&, EVS) - -.. doxygenfunction:: norm_lp(E&&, double, X&&, EVS) - -.. doxygenfunction:: norm_induced_l1(E&&, EVS) - -.. doxygenfunction:: norm_induced_linf(E&&, EVS) +.. doxygengroup:: red_functions + :members: diff --git a/docs/source/api/trigonometric_functions.rst b/docs/source/api/trigonometric_functions.rst index 6234470d0..e76d151b5 100644 --- a/docs/source/api/trigonometric_functions.rst +++ b/docs/source/api/trigonometric_functions.rst @@ -11,16 +11,5 @@ Trigonometric functions Defined in ``xtensor/core/xmath.hpp`` -.. doxygenfunction:: sin(E&&) - -.. doxygenfunction:: cos(E&&) - -.. doxygenfunction:: tan(E&&) - -.. doxygenfunction:: asin(E&&) - -.. doxygenfunction:: acos(E&&) - -.. doxygenfunction:: atan(E&&) - -.. doxygenfunction:: atan2(E1&&, E2&&) +.. doxygengroup:: trigo_functions + :members: diff --git a/docs/source/api/xaccessible.rst b/docs/source/api/xaccessible.rst new file mode 100644 index 000000000..237fc029d --- /dev/null +++ b/docs/source/api/xaccessible.rst @@ -0,0 +1,16 @@ +.. 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. + +xaccessible +=========== + +Defined in ``xtensor/core/xaccessible.hpp`` + +.. doxygenclass:: xt::xconst_accessible + :members: + +.. doxygenclass:: xt::xaccessible + :members: diff --git a/docs/source/api/xbuilder.rst b/docs/source/api/xbuilder.rst index db358f88e..b315c3730 100644 --- a/docs/source/api/xbuilder.rst +++ b/docs/source/api/xbuilder.rst @@ -19,7 +19,7 @@ Defined in ``xtensor/generators/xbuilder.hpp`` .. doxygenfunction:: xt::empty(const S&) -.. doxygenfunction:: xt::full_like(const xexpression&) +.. doxygenfunction:: xt::full_like(const xexpression&, typename E::value_type) .. doxygenfunction:: xt::empty_like(const xexpression&) diff --git a/docs/source/api/xfft.rst b/docs/source/api/xfft.rst new file mode 100644 index 000000000..a05766ff7 --- /dev/null +++ b/docs/source/api/xfft.rst @@ -0,0 +1,16 @@ +.. 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. + +xfft +==== + +Defined in ``xtensor/misc/xfft.hpp`` + +.. doxygenfunction:: xt::fft::fft(E&&, std::ptrdiff_t) + +.. doxygenfunction:: xt::fft::ifft(E&&, std::ptrdiff_t) + +.. doxygenfunction:: xt::fft::convolve(E1&&, E2&&, std::ptrdiff_t) diff --git a/docs/source/api/xhistogram.rst b/docs/source/api/xhistogram.rst index 71b05c89b..4d1e3e639 100644 --- a/docs/source/api/xhistogram.rst +++ b/docs/source/api/xhistogram.rst @@ -9,35 +9,14 @@ xhistogram Defined in ``xtensor/misc/xhistogram.hpp`` -.. doxygenenum:: xt::histogram_algorithm +.. doxygengroup:: digitize + :members: -.. doxygenfunction:: xt::histogram(E1&&, E2&&, E3&&, bool) +.. doxygengroup:: histogram + :members: .. doxygenfunction:: xt::bincount(E1&&, E2&&, std::size_t) -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, E2&&, E3, E3, std::size_t, histogram_algorithm) - -.. doxygenfunction:: xt::digitize(E1&&, E2&&, E3&&, bool, bool) - .. doxygenfunction:: xt::bin_items(size_t, E&&) -Further overloads ------------------ - -.. doxygenfunction:: xt::histogram(E1&&, E2&&, bool) - -.. doxygenfunction:: xt::histogram(E1&&, std::size_t, bool) - -.. doxygenfunction:: xt::histogram(E1&&, std::size_t, E2, E2, bool) - -.. doxygenfunction:: xt::histogram(E1&&, std::size_t, E2&&, bool) - -.. doxygenfunction:: xt::histogram(E1&&, std::size_t, E2&&, E3, E3, bool) - -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, E2, E2, std::size_t, histogram_algorithm) - -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, E2&&, std::size_t, histogram_algorithm) - -.. doxygenfunction:: xt::histogram_bin_edges(E1&&, std::size_t, histogram_algorithm) - .. doxygenfunction:: xt::bin_items(size_t, size_t) diff --git a/docs/source/api/xjson.rst b/docs/source/api/xjson.rst index 7a11957a5..138c5b9de 100644 --- a/docs/source/api/xjson.rst +++ b/docs/source/api/xjson.rst @@ -9,6 +9,10 @@ xjson: serialize to/from JSON Defined in ``xtensor/io/xjson.hpp`` -.. doxygenfunction:: xt::to_json(nlohmann::json&, const E&); +Available overload families +--------------------------- -.. doxygenfunction:: xt::from_json(const nlohmann::json&, E&); +- ``xt::to_json(nlohmann::basic_json&, const E&)`` +- ``xt::from_json(const nlohmann::basic_json&, E&)`` + +``xt::from_json`` is provided for both container and view semantics. diff --git a/docs/source/api/xreducer.rst b/docs/source/api/xreducer.rst index 85ee2a09a..4e896e099 100644 --- a/docs/source/api/xreducer.rst +++ b/docs/source/api/xreducer.rst @@ -12,4 +12,9 @@ Defined in ``xtensor/reducers/xreducer.hpp`` .. doxygenclass:: xt::xreducer :members: -.. doxygenfunction:: xt::reduce(F&&, E&&, X&&, EVS&&) +Available overload families +--------------------------- + +- ``xt::reduce(f, e, axes, options)`` +- ``xt::reduce(f, e, options)`` +- ``xt::reduce(f, e, const I (&axes)[N], options)`` diff --git a/docs/source/api/xset_operation.rst b/docs/source/api/xset_operation.rst index 31b25126c..14ea65cda 100644 --- a/docs/source/api/xset_operation.rst +++ b/docs/source/api/xset_operation.rst @@ -9,19 +9,13 @@ xset_operation Defined in ``xtensor/misc/xset_operation.hpp`` -.. doxygenenum:: xt::isin(E&&, F&&) +``xt::searchsorted(a, v, right)`` returns insertion indices for values ``v`` +in the sorted array ``a``. -.. doxygenenum:: xt::in1d(E&&, F&&) +Available functions +------------------- -.. doxygenenum:: xt::searchsorted(E1&&, E2&&, bool) - -Further overloads ------------------ - -.. doxygenenum:: xt::isin(E&&, std::initializer_list) - -.. doxygenenum:: xt::isin(E&&, I&&, I&&) - -.. doxygenenum:: xt::in1d(E&&, std::initializer_list) - -.. doxygenenum:: xt::in1d(E&&, I&&, I&&) +- ``xt::isin(element, test_elements)`` +- ``xt::in1d(element, test_elements)`` +- ``xt::isin(element, begin, end)`` +- ``xt::in1d(element, begin, end)`` diff --git a/docs/source/api/xview.rst b/docs/source/api/xview.rst index 9652ea26a..d9e72ad72 100644 --- a/docs/source/api/xview.rst +++ b/docs/source/api/xview.rst @@ -10,7 +10,6 @@ xview Defined in ``xtensor/views/xview.hpp`` .. doxygenclass:: xt::xview - :members: .. doxygenfunction:: xt::view diff --git a/docs/source/build-options.rst b/docs/source/build-options.rst index b076c422b..25e32ceb9 100644 --- a/docs/source/build-options.rst +++ b/docs/source/build-options.rst @@ -120,4 +120,4 @@ Notice that this option prevents building on a machine and distributing the resu a different architecture (i.e. not supporting the same instruction set). .. _xsimd: https://github.com/xtensor-stack/xsimd -.. _tbb: https://www.threadingbuildingblocks.org +.. _tbb: https://github.com/uxlfoundation/oneTBB diff --git a/docs/source/dev-build-options.rst b/docs/source/dev-build-options.rst index 67fbab9a6..c4b12a8fe 100644 --- a/docs/source/dev-build-options.rst +++ b/docs/source/dev-build-options.rst @@ -100,4 +100,4 @@ You can then build the documentation: Type ``make help`` to see the list of available documentation targets. .. _xsimd: https://github.com/xtensor-stack/xsimd -.. _tbb: https://www.threadingbuildingblocks.org +.. _tbb: https://github.com/uxlfoundation/oneTBB diff --git a/docs/source/expression.rst b/docs/source/expression.rst index 0fec517f7..8aa5d7324 100644 --- a/docs/source/expression.rst +++ b/docs/source/expression.rst @@ -232,5 +232,5 @@ Iterators :cpp:func:`begin(shape) ` and :cpp:func:`end(shape) `. -.. _NumPy: http://www.numpy.org +.. _NumPy: https://numpy.org/ .. _libdynd: http://libdynd.org diff --git a/docs/source/external-structures.rst b/docs/source/external-structures.rst index 1eb048138..4d82738f2 100644 --- a/docs/source/external-structures.rst +++ b/docs/source/external-structures.rst @@ -47,7 +47,7 @@ Adapting a pointer ------------------ Suppose that you want to use the *xtensor* machinery on a small contiguous subset of a large tensor. -You can, of course, use :ref:`Views`, but for efficiency you can also use pointers to the right bit of memory. +You can, of course, use :ref:`view-description`, but for efficiency you can also use pointers to the right bit of memory. Consider an example of an ``[M, 2, 2]`` tensor ``A``, for which you want to operate on ``A[i, :, :]`` for different ``i``. In this case the most efficient *xtensor* has to offer is: diff --git a/docs/source/index.rst b/docs/source/index.rst index 2aea4cb71..d28e135ea 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -119,7 +119,7 @@ for details. related bindings -.. _NumPy: http://www.numpy.org +.. _NumPy: https://numpy.org/ .. _Buffer Protocol: https://docs.python.org/3/c-api/buffer.html .. _libdynd: http://libdynd.org .. _xtensor-python: https://github.com/xtensor-stack/xtensor-python diff --git a/docs/source/quickref/chunked_arrays.rst b/docs/source/quickref/chunked_arrays.rst index 2f25c9f3f..e645cea73 100644 --- a/docs/source/quickref/chunked_arrays.rst +++ b/docs/source/quickref/chunked_arrays.rst @@ -17,7 +17,7 @@ the chunks fit comfortably in memory, but this also allows to process them in parallel, including in a distributed environment (although this is not supported yet). -Formats for the storage of arrays such as `Zarr `_ +Formats for the storage of arrays such as `Zarr `_ specifically target chunked arrays. Such formats are becoming increasingly popular in the field of big data, since the chunks can be stored in the cloud. @@ -66,4 +66,4 @@ persistence of data. In particular, they are used as a building block for the `xtensor-zarr `_ library. For further details, please refer to the documentation -of `xtensor-io `_. +of `xtensor-io `_. diff --git a/docs/source/random.rst b/docs/source/random.rst index 69e51384a..c0f555664 100644 --- a/docs/source/random.rst +++ b/docs/source/random.rst @@ -67,8 +67,8 @@ where :math:`\alpha` is the shape (also known as :math:`k`) and :math:`\beta` th .. seealso:: * :any:`numpy.random.gamma` - * `std::gamma_distribution `_ - * `Weisstein, Eric W. "Gamma Distribution." From MathWorld – A Wolfram Web Resource. `_ + * `std::gamma_distribution `_ + * `Weisstein, Eric W. "Gamma Distribution." From MathWorld – A Wolfram Web Resource. `_ * `Wikipedia, "Gamma distribution". `_ :cpp:func:`xt::random::weibull` @@ -100,7 +100,7 @@ Note that you can specify only :math:`a` while choosing the default for :math:`b .. seealso:: * :any:`numpy.random.weibull` - * `std::weibull_distribution `_ + * `std::weibull_distribution `_ * `Wikipedia, "Weibull distribution". `_ :cpp:func:`xt::random::extreme_value` diff --git a/docs/source/related.rst b/docs/source/related.rst index 97fa5ab30..60c640272 100644 --- a/docs/source/related.rst +++ b/docs/source/related.rst @@ -453,12 +453,12 @@ and also provides a python wrapper based on ``xtensor-python``. .. _xtensor-r: https://github.com/xtensor-stack/xtensor-r .. _xtensor-blas: https://github.com/xtensor-stack/xtensor-blas .. _xtensor-io: https://github.com/xtensor-stack/xtensor-io -.. _xtensor-fftw: https://github.com/egpbos/xtensor-fftw -.. _xtensor-ros: https://github.com/wolfv/xtensor_ros +.. _xtensor-fftw: https://github.com/xtensor-stack/xtensor-fftw +.. _xtensor-ros: https://github.com/RoboStack/xtensor-ros .. _xsimd: https://github.com/xtensor-stack/xsimd .. _xtl: https://github.com/xtensor-stack/xtl .. _xframe: https://github.com/xtensor-stack/xframe .. _z5: https://github.com/constantinpape/z5 -.. _zarr: https://github.com/zarr-developers/zarr -.. _n5: https://github.com/saalfeldlab/n5i -.. _xarray: http://xarray.pydata.org +.. _zarr: https://github.com/zarr-developers/zarr-python +.. _n5: https://github.com/saalfeldlab/n5 +.. _xarray: https://docs.xarray.dev/en/stable/ diff --git a/docs/source/view.rst b/docs/source/view.rst index 5348860b6..95b6365b8 100644 --- a/docs/source/view.rst +++ b/docs/source/view.rst @@ -159,9 +159,9 @@ Since ``xtensor 0.16.3``, a new range syntax can be used with strided views: // The previous line is equivalent to auto v2 = xt::strided_view(a, {xt::range(0, 1), 1, xt::range(_, 2), xt::range(_, _, -1)}); -The :cpp:type:`xt::xstrided_view` is very efficient on contigous memory -(e.g. :cpp:type:`xt::xtensor` or :cpp:type:`xt::xarray`) but less efficient on\ -:cpp:type:`xt::xexpression`s. +The :cpp:type:`xt::xstrided_view` type is very efficient on contigous memory +(e.g. :cpp:type:`xt::xtensor` or :cpp:type:`xt::xarray`) but less efficient on +generic :cpp:type:`xt::xexpression` objects. Transposed views ---------------- diff --git a/include/xtensor/chunk/xchunked_array.hpp b/include/xtensor/chunk/xchunked_array.hpp index 53a53aba1..dc0c16355 100644 --- a/include/xtensor/chunk/xchunked_array.hpp +++ b/include/xtensor/chunk/xchunked_array.hpp @@ -19,7 +19,7 @@ namespace xt { /** - * @defgroup xt_xchunked_array + * @defgroup xt_xchunked_array Chunked array * * Chunked array container. * Defined in ``xtensor/xchunked_array.hpp``. diff --git a/include/xtensor/core/xeval.hpp b/include/xtensor/core/xeval.hpp index 231f47312..5ccbc1db9 100644 --- a/include/xtensor/core/xeval.hpp +++ b/include/xtensor/core/xeval.hpp @@ -18,7 +18,7 @@ namespace xt { /** - * @defgroup xt_xeval + * @defgroup xt_xeval Evaluation * * Evaluation functions. * Defined in ``xtensor/xeval.hpp`` diff --git a/include/xtensor/core/xshape.hpp b/include/xtensor/core/xshape.hpp index 28fbe43cc..61650bb87 100644 --- a/include/xtensor/core/xshape.hpp +++ b/include/xtensor/core/xshape.hpp @@ -122,7 +122,7 @@ namespace xt * Check if an object has a certain shape. * * @ingroup xt_xshape - * @param a an array + * @param e an array-like object * @param shape the shape to test * @return bool */ @@ -136,8 +136,8 @@ namespace xt /** * Check if an object has a certain shape. * - * @ingroup has_shape - * @param a an array + * @ingroup xt_xshape + * @param e an array-like object * @param shape the shape to test * @return bool */ diff --git a/include/xtensor/core/xstrides.hpp b/include/xtensor/core/xstrides.hpp index f8735f7e3..d413fcd26 100644 --- a/include/xtensor/core/xstrides.hpp +++ b/include/xtensor/core/xstrides.hpp @@ -59,7 +59,8 @@ namespace xt * * @ingroup xt_xstrides * @param strides Strides of the array. - * @param args Array index. + * @param arg First array index. + * @param args Remaining array indices. * @return The flat index. */ template @@ -241,7 +242,8 @@ namespace xt * @brief Get strides of an object. * * @ingroup xt_xstrides - * @param a an array + * @param e an array + * @param type output stride convention * @return array */ template @@ -285,7 +287,9 @@ namespace xt * @brief Get stride of an object along an axis. * * @ingroup xt_xstrides - * @param a an array + * @param e an array + * @param axis axis along which to query the stride + * @param type output stride convention * @return integer */ template diff --git a/include/xtensor/generators/xbuilder.hpp b/include/xtensor/generators/xbuilder.hpp index 8a2f61147..5ba9f7a36 100644 --- a/include/xtensor/generators/xbuilder.hpp +++ b/include/xtensor/generators/xbuilder.hpp @@ -146,7 +146,7 @@ namespace xt * the same shape, value type and layout as the input xexpression *e*. * * Note: contrary to zeros(shape), this function returns a non-lazy, allocated container! - * Use ``xt::zeros(e.shape());` for a lazy version. + * Use ``xt::zeros(e.shape());`` for a lazy version. * * @param e the xexpression from which to extract shape, value type and layout. */ diff --git a/include/xtensor/generators/xrandom.hpp b/include/xtensor/generators/xrandom.hpp index 5e365f667..d43a69876 100644 --- a/include/xtensor/generators/xrandom.hpp +++ b/include/xtensor/generators/xrandom.hpp @@ -914,15 +914,16 @@ namespace xt * * For weighted random sampling with replacement, binary search with cumulative weights alogrithm is * used. For weighted random sampling without replacement, the algorithm used is the exponential sort - * from [Efraimidis and Spirakis](https://doi.org/10.1016/j.ipl.2005.11.003) (2006) with the ``weight - * / randexp(1)`` [trick](https://web.archive.org/web/20201021162211/https://krlmlr.github.io/wrswoR/) - * from Kirill Müller. + * from [Efraimidis and Spirakis](https://linkinghub.elsevier.com/retrieve/pii/S002001900500298X) + * (2006) with the ``weight / randexp(1)`` + * [trick](https://web.archive.org/web/20201021162211/https://krlmlr.github.io/wrswoR/) from Kirill + * Müller. * * Note: this function makes a copy of your data, and only 1D data is accepted. * * @param e expression to sample from * @param n number of elements to sample - * @param w expression for the weight distribution. + * @param weights expression for the weight distribution. * Weights must be positive and real-valued but need not sum to 1. * @param replace set true to sample with replacement * @param engine random number engine diff --git a/include/xtensor/misc/xcomplex.hpp b/include/xtensor/misc/xcomplex.hpp index 308218f60..c803bb77c 100644 --- a/include/xtensor/misc/xcomplex.hpp +++ b/include/xtensor/misc/xcomplex.hpp @@ -23,7 +23,7 @@ namespace xt { /** - * @defgroup xt_xcomplex + * @defgroup xt_xcomplex Complex numbers * * Defined in ``xtensor/xcomplex.hpp`` */ diff --git a/include/xtensor/misc/xhistogram.hpp b/include/xtensor/misc/xhistogram.hpp index b8fdd9da1..a389c4fb9 100644 --- a/include/xtensor/misc/xhistogram.hpp +++ b/include/xtensor/misc/xhistogram.hpp @@ -23,6 +23,11 @@ using namespace xt::placeholders; namespace xt { + /** + * @defgroup digitize Digitize helpers + * @brief Helpers for assigning values to histogram bins. + */ + /** * @ingroup digitize * @brief Return the indices of the bins to which each value in input array belongs. @@ -128,6 +133,11 @@ namespace xt } // detail + /** + * @defgroup histogram Histogram functions + * @brief Helpers for computing histograms and histogram bin edges. + */ + /** * @ingroup histogram * @brief Compute the histogram of a set of data. diff --git a/include/xtensor/misc/xmanipulation.hpp b/include/xtensor/misc/xmanipulation.hpp index f100744ac..2d540539b 100644 --- a/include/xtensor/misc/xmanipulation.hpp +++ b/include/xtensor/misc/xmanipulation.hpp @@ -27,7 +27,7 @@ namespace xt { /** - * @defgroup xt_xmanipulation + * @defgroup xt_xmanipulation Array manipulation */ namespace check_policy @@ -1099,7 +1099,7 @@ namespace xt * @param repeats The number of repetition of each elements. * @p repeats is broadcasted to fit the shape of the given @p axis. * @param axis the axis along which to repeat the value - * @return an expression which as the same shape as \ref e, except along the given \ref axis + * @return an expression with the same shape as ``e``, except along the given ``axis`` */ template inline auto repeat(E&& e, std::size_t repeats, std::size_t axis) @@ -1119,7 +1119,7 @@ namespace xt * The size of @p repeats must match the shape of the given @p axis. * @param axis the axis along which to repeat the value * - * @return an expression which as the same shape as \ref e, except along the given \ref axis + * @return an expression with the same shape as ``e``, except along the given ``axis`` */ template inline auto repeat(E&& e, const std::vector& repeats, std::size_t axis) @@ -1135,7 +1135,7 @@ namespace xt * @param repeats The number of repetition of each elements. * The size of @p repeats must match the shape of the given @p axis. * @param axis the axis along which to repeat the value - * @return an expression which as the same shape as \ref e, except along the given \ref axis + * @return an expression with the same shape as ``e``, except along the given ``axis`` */ template inline auto repeat(E&& e, std::vector&& repeats, std::size_t axis) diff --git a/include/xtensor/misc/xset_operation.hpp b/include/xtensor/misc/xset_operation.hpp index 94b7e23a7..35c564a37 100644 --- a/include/xtensor/misc/xset_operation.hpp +++ b/include/xtensor/misc/xset_operation.hpp @@ -25,6 +25,11 @@ namespace xt { + /** + * @defgroup searchsorted Searchsorted helpers + * @brief Helpers for locating insertion indices in sorted arrays. + */ + namespace detail { diff --git a/include/xtensor/misc/xsort.hpp b/include/xtensor/misc/xsort.hpp index aa9ea4cfa..196ec45cd 100644 --- a/include/xtensor/misc/xsort.hpp +++ b/include/xtensor/misc/xsort.hpp @@ -556,7 +556,7 @@ namespace xt * @ingroup xt_xsort * @param e input xexpression * @param kth_container a container of ``indices`` that should contain the correctly sorted value - * @param axis either integer (default = -1) to sort along last axis or ``xnone()`` to flatten before + * @param ax placeholder indicating that the input is flattened before sorting * sorting * * @return partially sorted xcontainer @@ -647,7 +647,7 @@ namespace xt * @ingroup xt_xsort * @param e input xexpression * @param kth_container a container of ``indices`` that should contain the correctly sorted value - * @param axis either integer (default = -1) to sort along last axis or ``xnone()`` to flatten before + * @param axis placeholder indicating that the input is flattened before sorting * sorting * * @return xcontainer with indices of partial sort of input diff --git a/include/xtensor/optional/xoptional_assembly_base.hpp b/include/xtensor/optional/xoptional_assembly_base.hpp index 3f60cc359..5df618f0b 100644 --- a/include/xtensor/optional/xoptional_assembly_base.hpp +++ b/include/xtensor/optional/xoptional_assembly_base.hpp @@ -700,7 +700,7 @@ namespace xt /** * Returns a reference to the element at the specified position * of the underlying storage in the optional assembly. - * @param index index to underlying flat storage. + * @param i index to underlying flat storage. */ template inline auto xoptional_assembly_base::flat(size_type i) -> reference @@ -711,7 +711,7 @@ namespace xt /** * Returns a constant reference to the element at the specified position * of the underlying storage in the optional assembly. - * @param index index to underlying flat storage. + * @param i index to underlying flat storage. */ template inline auto xoptional_assembly_base::flat(size_type i) const -> const_reference diff --git a/include/xtensor/reducers/xreducer.hpp b/include/xtensor/reducers/xreducer.hpp index 3cf8ec76f..0e5ef9992 100644 --- a/include/xtensor/reducers/xreducer.hpp +++ b/include/xtensor/reducers/xreducer.hpp @@ -1400,6 +1400,7 @@ namespace xt * @param func the function to apply * @param e the expression to reduce * @param axes the axes along which the reduction is performed + * @param options reducer options controlling evaluation strategy and related settings */ template template diff --git a/include/xtensor/views/xaxis_iterator.hpp b/include/xtensor/views/xaxis_iterator.hpp index 41da6822f..2b54748d4 100644 --- a/include/xtensor/views/xaxis_iterator.hpp +++ b/include/xtensor/views/xaxis_iterator.hpp @@ -235,7 +235,7 @@ namespace xt /** * Checks equality of the xaxis_slice_iterator and \c rhs. * - * @param + * @param rhs iterator to compare with * @return true if the iterators are equivalent, false otherwise */ template diff --git a/include/xtensor/views/xfunctor_view.hpp b/include/xtensor/views/xfunctor_view.hpp index 9f2daf712..1c76a91b5 100644 --- a/include/xtensor/views/xfunctor_view.hpp +++ b/include/xtensor/views/xfunctor_view.hpp @@ -29,7 +29,7 @@ namespace xt { /** - * @defgroup xt_xfunctor_view + * @defgroup xt_xfunctor_view Functor view * * Chunked array container. * Defined in ``xtensor/xfunctor_view.hpp`` diff --git a/include/xtensor/views/xindex_view.hpp b/include/xtensor/views/xindex_view.hpp index 8b911afb8..e41add4cb 100644 --- a/include/xtensor/views/xindex_view.hpp +++ b/include/xtensor/views/xindex_view.hpp @@ -505,7 +505,8 @@ namespace xt /** * Returns a reference to the element at the specified position in the xindex_view. * @param first iterator starting the sequence of indices - * The number of indices in the sequence should be equal to or greater 1. + * @param last iterator ending the sequence of indices (not used, only for compatibility with xexpression + * operator()) The number of indices in the sequence should be equal to or greater 1. */ template template @@ -517,7 +518,8 @@ namespace xt /** * Returns a reference to the element at the specified position in the xindex_view. * @param first iterator starting the sequence of indices - * The number of indices in the sequence should be equal to or greater 1. + * @param last iterator ending the sequence of indices (not used, only for compatibility with xexpression + * operator()) The number of indices in the sequence should be equal to or greater 1. */ template template From 4a213a6d0ae269ddde13b6dc74442cc461c45ed9 Mon Sep 17 00:00:00 2001 From: SamareshSingh <97642706+ssam18@users.noreply.github.com> Date: Wed, 15 Apr 2026 10:45:54 -0500 Subject: [PATCH 07/25] docs: Add warning about dangling references with lazy reducers (fixes #2871) (#2882) This PR addresses GitHub issue #2871 where using auto with xtensor reducer functions (like amax, sum with keep_dims) causes crashes or incorrect results in optimized builds, particularly on Android ARM64. **Root Cause:** Lazy expressions hold references to local variables. When intermediate results are stored with auto, these references become dangling when the function returns, leading to undefined behavior. **Changes:** - docs/source/pitfall.rst: Added detailed warning section explaining the issue and providing three solutions: 1. Use explicit container types (xt::xtensor) 2. Use xt::eval() to force immediate evaluation 3. Use evaluation_strategy::immediate with reducers - test/test_xmath.cpp: Added test demonstrating correct patterns **Testing:** - All 83 xmath tests pass - All 64 xreducer tests pass Fixes #2871 --- .pre-commit-config.yaml | 1 + docs/source/pitfall.rst | 39 ++++++++++++++++++++++++++++++++++ test/test_xmath.cpp | 47 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6e33ed170..bfc98b9cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,6 +30,7 @@ repos: args: [--autofix, --indent, '2'] types: [file] files: \.(yaml|yml|clang-format) + additional_dependencies: [setuptools] - repo: https://github.com/tdegeus/cpp_comment_format rev: v0.2.1 hooks: diff --git a/docs/source/pitfall.rst b/docs/source/pitfall.rst index 0c404007f..b9e40a2a3 100644 --- a/docs/source/pitfall.rst +++ b/docs/source/pitfall.rst @@ -70,6 +70,45 @@ in the returned expression. Replacing ``auto tmp`` with ``xt::xarray tmp`` does not change anything, ``tmp`` is still an lvalue and thus captured by reference. +.. warning:: + + This issue is particularly subtle with reducer functions like :cpp:func:`xt::amax`, + :cpp:func:`xt::sum`, etc. Consider the following function: + + .. code:: + + template + xt::xtensor logSoftmax(const xt::xtensor &matrix) + { + xt::xtensor maxVals = xt::amax(matrix, {1}, xt::keep_dims); + auto shifted = matrix - maxVals; + auto expVals = xt::exp(shifted); + auto sumExp = xt::sum(expVals, {1}, xt::keep_dims); + return shifted - xt::log(sumExp); + } + + This function may produce incorrect results or crash, especially in optimized builds. + The issue is that ``shifted``, ``expVals``, and ``sumExp`` are all lazy expressions + that hold references to local variables. When the function returns, these local + variables are destroyed, and the returned expression contains dangling references. + + The fix is to evaluate reducer results and the returned expression explicitly. + Element-wise lazy expressions (like ``shifted`` and ``expVals``) are safe to + leave as ``auto``, but reducer results (like ``sumExp``) must be materialized + before being used in a subsequent element-wise expression: + + .. code:: + + template + xt::xtensor logSoftmax(const xt::xtensor &matrix) + { + xt::xtensor maxVals = xt::amax(matrix, {1}, xt::keep_dims); + auto shifted = matrix - maxVals; + auto expVals = xt::exp(shifted); + xt::xtensor sumExp = xt::sum(expVals, {1}, xt::keep_dims); + return xt::xtensor(shifted - xt::log(sumExp)); + } + Random numbers not consistent ----------------------------- diff --git a/test/test_xmath.cpp b/test/test_xmath.cpp index 17bc57895..8f56e93b9 100644 --- a/test/test_xmath.cpp +++ b/test/test_xmath.cpp @@ -969,4 +969,51 @@ namespace xt EXPECT_TRUE(xt::allclose(expected, unwrapped)); } } + + // Test for GitHub issue #2871: Proper handling of intermediate results + // This test documents the correct way to use reducers with keep_dims + // when intermediate expressions are needed. + TEST(xmath, issue_2871_intermediate_result_handling) + { + // This test verifies the correct pattern for using reducers with + // intermediate results. Returning a lazy expression from a function can lead + // to dangling references — only the returned expression must be evaluated. + + // The CORRECT way: reducer results must be evaluated; element-wise lazy + // expressions are safe to leave as auto + auto logSoftmax_correct = [](const xt::xtensor& matrix) + { + xt::xtensor maxVals = xt::amax(matrix, {1}, xt::keep_dims); + auto shifted = matrix - maxVals; + auto expVals = xt::exp(shifted); + xt::xtensor sumExp = xt::sum(expVals, {1}, xt::keep_dims); + return xt::xtensor(shifted - xt::log(sumExp)); + }; + + // Alternative CORRECT way: use xt::eval for reducer results + auto logSoftmax_eval = [](const xt::xtensor& matrix) + { + auto maxVals = xt::eval(xt::amax(matrix, {1}, xt::keep_dims)); + auto shifted = matrix - maxVals; + auto expVals = xt::exp(shifted); + auto sumExp = xt::eval(xt::sum(expVals, {1}, xt::keep_dims)); + return xt::xtensor(shifted - xt::log(sumExp)); + }; + + // Test data + xt::xtensor input = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}}; + + // Both implementations should produce the same result + auto result1 = logSoftmax_correct(input); + auto result2 = logSoftmax_eval(input); + + EXPECT_TRUE(xt::allclose(result1, result2)); + + // Verify the result is a valid log-softmax (rows sum to 0 in log space) + // exp(log_softmax).sum(axis=1) should equal 1 + auto exp_result = xt::exp(result1); + auto row_sums = xt::sum(exp_result, {1}); + xt::xtensor expected_sums = {1.0, 1.0}; + EXPECT_TRUE(xt::allclose(row_sums, expected_sums)); + } } From 92c873e1d369564656c250305bffaa05605806ba Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Wed, 22 Apr 2026 17:11:45 +0000 Subject: [PATCH 08/25] Remove unused standard includes (#2894) Commit generated through diskarzhan. With ci added to prevent regression. --- .github/workflows/static-analysis.yml | 8 ++++++++ include/xtensor/containers/xarray.hpp | 1 - include/xtensor/containers/xcontainer.hpp | 2 -- include/xtensor/containers/xfixed.hpp | 1 - include/xtensor/containers/xscalar.hpp | 1 - include/xtensor/core/xexpression.hpp | 2 -- include/xtensor/core/xfunction.hpp | 1 - include/xtensor/core/xiterator.hpp | 1 - include/xtensor/core/xoperation.hpp | 1 - include/xtensor/core/xshape.hpp | 3 --- include/xtensor/generators/xgenerator.hpp | 2 -- include/xtensor/io/xio.hpp | 1 - include/xtensor/io/xnpy.hpp | 3 --- include/xtensor/misc/xset_operation.hpp | 1 - include/xtensor/reducers/xblockwise_reducer_functors.hpp | 3 --- include/xtensor/reducers/xreducer.hpp | 1 - include/xtensor/utils/xexception.hpp | 1 - include/xtensor/utils/xutils.hpp | 2 -- include/xtensor/views/index_mapper.hpp | 2 ++ include/xtensor/views/xbroadcast.hpp | 2 -- include/xtensor/views/xindex_view.hpp | 1 - include/xtensor/views/xstrided_view.hpp | 1 - 22 files changed, 10 insertions(+), 31 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 5441a3371..e3204614b 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -12,3 +12,11 @@ jobs: steps: - uses: actions/checkout@v3 - uses: pre-commit/action@v3.0.0 + + include-check: + runs-on: ubuntu-latest + name: Check unused standard includes + steps: + - uses: actions/checkout@v6 + - run: pip install diskarzhan + - run: diskarzhan `find include -name '*.hpp'` diff --git a/include/xtensor/containers/xarray.hpp b/include/xtensor/containers/xarray.hpp index 7455b8854..7f27bd296 100644 --- a/include/xtensor/containers/xarray.hpp +++ b/include/xtensor/containers/xarray.hpp @@ -11,7 +11,6 @@ #define XTENSOR_ARRAY_HPP #include -#include #include #include diff --git a/include/xtensor/containers/xcontainer.hpp b/include/xtensor/containers/xcontainer.hpp index 70ebaa798..bfaf54b5a 100644 --- a/include/xtensor/containers/xcontainer.hpp +++ b/include/xtensor/containers/xcontainer.hpp @@ -11,9 +11,7 @@ #define XTENSOR_CONTAINER_HPP #include -#include #include -#include #include #include diff --git a/include/xtensor/containers/xfixed.hpp b/include/xtensor/containers/xfixed.hpp index 6ac029881..25c9c747d 100644 --- a/include/xtensor/containers/xfixed.hpp +++ b/include/xtensor/containers/xfixed.hpp @@ -14,7 +14,6 @@ #include #include #include -#include #include diff --git a/include/xtensor/containers/xscalar.hpp b/include/xtensor/containers/xscalar.hpp index 9464f4721..4a9c01081 100644 --- a/include/xtensor/containers/xscalar.hpp +++ b/include/xtensor/containers/xscalar.hpp @@ -12,7 +12,6 @@ #include #include -#include #include diff --git a/include/xtensor/core/xexpression.hpp b/include/xtensor/core/xexpression.hpp index 1f8c98194..9b133315d 100644 --- a/include/xtensor/core/xexpression.hpp +++ b/include/xtensor/core/xexpression.hpp @@ -10,9 +10,7 @@ #ifndef XTENSOR_EXPRESSION_HPP #define XTENSOR_EXPRESSION_HPP -#include #include -#include #include #include diff --git a/include/xtensor/core/xfunction.hpp b/include/xtensor/core/xfunction.hpp index 200a35d47..ffc411a15 100644 --- a/include/xtensor/core/xfunction.hpp +++ b/include/xtensor/core/xfunction.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/include/xtensor/core/xiterator.hpp b/include/xtensor/core/xiterator.hpp index ca3faef21..6dcb9c9e1 100644 --- a/include/xtensor/core/xiterator.hpp +++ b/include/xtensor/core/xiterator.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/include/xtensor/core/xoperation.hpp b/include/xtensor/core/xoperation.hpp index 533ad6513..76bfc7c50 100644 --- a/include/xtensor/core/xoperation.hpp +++ b/include/xtensor/core/xoperation.hpp @@ -11,7 +11,6 @@ #define XTENSOR_OPERATION_HPP #include -#include #include #include diff --git a/include/xtensor/core/xshape.hpp b/include/xtensor/core/xshape.hpp index 61650bb87..6988e69f3 100644 --- a/include/xtensor/core/xshape.hpp +++ b/include/xtensor/core/xshape.hpp @@ -11,13 +11,10 @@ #define XTENSOR_XSHAPE_HPP #include -#include #include #include -#include #include #include -#include #include "../containers/xstorage.hpp" #include "../core/xlayout.hpp" diff --git a/include/xtensor/generators/xgenerator.hpp b/include/xtensor/generators/xgenerator.hpp index f4dfc191f..66922c5be 100644 --- a/include/xtensor/generators/xgenerator.hpp +++ b/include/xtensor/generators/xgenerator.hpp @@ -12,8 +12,6 @@ #include #include -#include -#include #include #include diff --git a/include/xtensor/io/xio.hpp b/include/xtensor/io/xio.hpp index 345edc4d4..fbc0cd3a0 100644 --- a/include/xtensor/io/xio.hpp +++ b/include/xtensor/io/xio.hpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/include/xtensor/io/xnpy.hpp b/include/xtensor/io/xnpy.hpp index 61739cfe0..ef517f068 100644 --- a/include/xtensor/io/xnpy.hpp +++ b/include/xtensor/io/xnpy.hpp @@ -17,15 +17,12 @@ #include #include #include -#include #include -#include #include #include #include #include #include -#include #include #include diff --git a/include/xtensor/misc/xset_operation.hpp b/include/xtensor/misc/xset_operation.hpp index 35c564a37..2a29a6b12 100644 --- a/include/xtensor/misc/xset_operation.hpp +++ b/include/xtensor/misc/xset_operation.hpp @@ -11,7 +11,6 @@ #define XTENSOR_XSET_OPERATION_HPP #include -#include #include #include diff --git a/include/xtensor/reducers/xblockwise_reducer_functors.hpp b/include/xtensor/reducers/xblockwise_reducer_functors.hpp index 4ac9e649d..d6216b2da 100644 --- a/include/xtensor/reducers/xblockwise_reducer_functors.hpp +++ b/include/xtensor/reducers/xblockwise_reducer_functors.hpp @@ -2,10 +2,7 @@ #define XTENSOR_XBLOCKWISE_REDUCER_FUNCTORS_HPP -#include -#include #include -#include #include "../chunk/xchunked_array.hpp" #include "../chunk/xchunked_assign.hpp" diff --git a/include/xtensor/reducers/xreducer.hpp b/include/xtensor/reducers/xreducer.hpp index 0e5ef9992..e99522b5e 100644 --- a/include/xtensor/reducers/xreducer.hpp +++ b/include/xtensor/reducers/xreducer.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/include/xtensor/utils/xexception.hpp b/include/xtensor/utils/xexception.hpp index 10a75d190..025836ce2 100644 --- a/include/xtensor/utils/xexception.hpp +++ b/include/xtensor/utils/xexception.hpp @@ -10,7 +10,6 @@ #ifndef XTENSOR_EXCEPTION_HPP #define XTENSOR_EXCEPTION_HPP -#include #include #include #include diff --git a/include/xtensor/utils/xutils.hpp b/include/xtensor/utils/xutils.hpp index 2e97f67db..5a3e2af14 100644 --- a/include/xtensor/utils/xutils.hpp +++ b/include/xtensor/utils/xutils.hpp @@ -12,8 +12,6 @@ #include #include -#include -#include #include #include #include diff --git a/include/xtensor/views/index_mapper.hpp b/include/xtensor/views/index_mapper.hpp index 672cb2207..84685f28a 100644 --- a/include/xtensor/views/index_mapper.hpp +++ b/include/xtensor/views/index_mapper.hpp @@ -10,6 +10,8 @@ #ifndef XTENSOR_INDEX_MAPPER_HPP #define XTENSOR_INDEX_MAPPER_HPP +#include + #include "xview.hpp" namespace xt diff --git a/include/xtensor/views/xbroadcast.hpp b/include/xtensor/views/xbroadcast.hpp index 1626faaa3..d3034222f 100644 --- a/include/xtensor/views/xbroadcast.hpp +++ b/include/xtensor/views/xbroadcast.hpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include diff --git a/include/xtensor/views/xindex_view.hpp b/include/xtensor/views/xindex_view.hpp index e41add4cb..6701d3bf3 100644 --- a/include/xtensor/views/xindex_view.hpp +++ b/include/xtensor/views/xindex_view.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/include/xtensor/views/xstrided_view.hpp b/include/xtensor/views/xstrided_view.hpp index f0fda4214..aa84b20a7 100644 --- a/include/xtensor/views/xstrided_view.hpp +++ b/include/xtensor/views/xstrided_view.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include From 8e747494cf9ca118a763e315875c00b55b13e35f Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Tue, 28 Apr 2026 17:28:35 +0200 Subject: [PATCH 09/25] Removed constexpr workarounds (#2895) This workaround is for old compilers not supported anymore. Edit: `XTENSOR_CONSTEXPR_ENHANCED_STATIC` is still required on Windows. --- include/xtensor/containers/xcontainer.hpp | 16 ++++----- include/xtensor/containers/xfixed.hpp | 26 +++++++------- include/xtensor/containers/xscalar.hpp | 8 ++--- include/xtensor/containers/xstorage.hpp | 22 ++++-------- include/xtensor/core/xiterator.hpp | 8 ++--- include/xtensor/core/xtensor_config.hpp | 5 --- include/xtensor/views/xbroadcast.hpp | 8 ++--- include/xtensor/views/xslice.hpp | 44 +++++++++-------------- 8 files changed, 55 insertions(+), 82 deletions(-) diff --git a/include/xtensor/containers/xcontainer.hpp b/include/xtensor/containers/xcontainer.hpp index bfaf54b5a..a2ab4fd0d 100644 --- a/include/xtensor/containers/xcontainer.hpp +++ b/include/xtensor/containers/xcontainer.hpp @@ -114,11 +114,11 @@ namespace xt size_type size() const noexcept; - XTENSOR_CONSTEXPR_RETURN size_type dimension() const noexcept; + constexpr size_type dimension() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides() const noexcept; + constexpr const inner_shape_type& shape() const noexcept; + constexpr const inner_strides_type& strides() const noexcept; + constexpr const inner_backstrides_type& backstrides() const noexcept; template void fill(const T& value); @@ -373,7 +373,7 @@ namespace xt * Returns the number of dimensions of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::dimension() const noexcept -> size_type + constexpr auto xcontainer::dimension() const noexcept -> size_type { return shape().size(); } @@ -382,7 +382,7 @@ namespace xt * Returns the shape of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::shape() const noexcept -> const inner_shape_type& + constexpr auto xcontainer::shape() const noexcept -> const inner_shape_type& { return derived_cast().shape_impl(); } @@ -391,7 +391,7 @@ namespace xt * Returns the strides of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::strides() const noexcept -> const inner_strides_type& + constexpr auto xcontainer::strides() const noexcept -> const inner_strides_type& { return derived_cast().strides_impl(); } @@ -400,7 +400,7 @@ namespace xt * Returns the backstrides of the container. */ template - XTENSOR_CONSTEXPR_RETURN auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + constexpr auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& { return derived_cast().backstrides_impl(); } diff --git a/include/xtensor/containers/xfixed.hpp b/include/xtensor/containers/xfixed.hpp index 25c9c747d..54270caa7 100644 --- a/include/xtensor/containers/xfixed.hpp +++ b/include/xtensor/containers/xfixed.hpp @@ -373,9 +373,9 @@ namespace xt storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; + constexpr const inner_shape_type& shape_impl() const noexcept; + constexpr const inner_strides_type& strides_impl() const noexcept; + constexpr const inner_backstrides_type& backstrides_impl() const noexcept; friend class xcontainer>; }; @@ -495,9 +495,9 @@ namespace xt storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; - XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; + constexpr const inner_shape_type& shape_impl() const noexcept; + constexpr const inner_strides_type& strides_impl() const noexcept; + constexpr const inner_backstrides_type& backstrides_impl() const noexcept; friend class xcontainer>; }; @@ -740,21 +740,20 @@ namespace xt } template - XTENSOR_CONSTEXPR_RETURN auto xfixed_container::shape_impl() const noexcept - -> const inner_shape_type& + constexpr auto xfixed_container::shape_impl() const noexcept -> const inner_shape_type& { return m_shape; } template - XTENSOR_CONSTEXPR_RETURN auto xfixed_container::strides_impl() const noexcept + constexpr auto xfixed_container::strides_impl() const noexcept -> const inner_strides_type& { return m_strides; } template - XTENSOR_CONSTEXPR_RETURN auto xfixed_container::backstrides_impl() const noexcept + constexpr auto xfixed_container::backstrides_impl() const noexcept -> const inner_backstrides_type& { return m_backstrides; @@ -937,21 +936,20 @@ namespace xt } template - XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::shape_impl() const noexcept - -> const inner_shape_type& + constexpr auto xfixed_adaptor::shape_impl() const noexcept -> const inner_shape_type& { return m_shape; } template - XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::strides_impl() const noexcept + constexpr auto xfixed_adaptor::strides_impl() const noexcept -> const inner_strides_type& { return m_strides; } template - XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::backstrides_impl() const noexcept + constexpr auto xfixed_adaptor::backstrides_impl() const noexcept -> const inner_backstrides_type& { return m_backstrides; diff --git a/include/xtensor/containers/xscalar.hpp b/include/xtensor/containers/xscalar.hpp index 4a9c01081..106a65923 100644 --- a/include/xtensor/containers/xscalar.hpp +++ b/include/xtensor/containers/xscalar.hpp @@ -466,25 +466,25 @@ namespace xt *****************************/ template - XTENSOR_CONSTEXPR_RETURN auto linear_begin(xscalar& c) noexcept -> decltype(c.dummy_begin()) + constexpr auto linear_begin(xscalar& c) noexcept -> decltype(c.dummy_begin()) { return c.dummy_begin(); } template - XTENSOR_CONSTEXPR_RETURN auto linear_end(xscalar& c) noexcept -> decltype(c.dummy_end()) + constexpr auto linear_end(xscalar& c) noexcept -> decltype(c.dummy_end()) { return c.dummy_end(); } template - XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xscalar& c) noexcept -> decltype(c.dummy_begin()) + constexpr auto linear_begin(const xscalar& c) noexcept -> decltype(c.dummy_begin()) { return c.dummy_begin(); } template - XTENSOR_CONSTEXPR_RETURN auto linear_end(const xscalar& c) noexcept -> decltype(c.dummy_end()) + constexpr auto linear_end(const xscalar& c) noexcept -> decltype(c.dummy_end()) { return c.dummy_end(); } diff --git a/include/xtensor/containers/xstorage.hpp b/include/xtensor/containers/xstorage.hpp index 811ab80b7..426480805 100644 --- a/include/xtensor/containers/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -1658,13 +1658,7 @@ namespace xt { public: -#if defined(_MSC_VER) - using cast_type = std::array; -#define XTENSOR_FIXED_SHAPE_CONSTEXPR inline -#else using cast_type = const_array; -#define XTENSOR_FIXED_SHAPE_CONSTEXPR constexpr -#endif using value_type = std::size_t; using size_type = std::size_t; using const_iterator = typename cast_type::const_iterator; @@ -1681,17 +1675,17 @@ namespace xt return std::get(tmp_cast_type{X...}); } - XTENSOR_FIXED_SHAPE_CONSTEXPR operator cast_type() const + constexpr operator cast_type() const { return cast_type({X...}); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto begin() const + constexpr auto begin() const { return m_array.begin(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto end() const + constexpr auto end() const { return m_array.end(); } @@ -1706,22 +1700,22 @@ namespace xt return m_array.rend(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto cbegin() const + constexpr auto cbegin() const { return m_array.cbegin(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR auto cend() const + constexpr auto cend() const { return m_array.cend(); } - XTENSOR_FIXED_SHAPE_CONSTEXPR std::size_t operator[](std::size_t idx) const + constexpr std::size_t operator[](std::size_t idx) const { return m_array[idx]; } - XTENSOR_FIXED_SHAPE_CONSTEXPR bool empty() const + constexpr bool empty() const { return sizeof...(X) == 0; } @@ -1731,8 +1725,6 @@ namespace xt XTENSOR_CONSTEXPR_ENHANCED_STATIC cast_type m_array = cast_type({X...}); }; -#undef XTENSOR_FIXED_SHAPE_CONSTEXPR - template class sequence_view { diff --git a/include/xtensor/core/xiterator.hpp b/include/xtensor/core/xiterator.hpp index 6dcb9c9e1..448f6093d 100644 --- a/include/xtensor/core/xiterator.hpp +++ b/include/xtensor/core/xiterator.hpp @@ -417,7 +417,7 @@ namespace xt } template - XTENSOR_CONSTEXPR_RETURN auto linear_begin(C& c) noexcept + constexpr auto linear_begin(C& c) noexcept { if constexpr (detail::has_linear_iterator::value) { @@ -430,7 +430,7 @@ namespace xt } template - XTENSOR_CONSTEXPR_RETURN auto linear_end(C& c) noexcept + constexpr auto linear_end(C& c) noexcept { if constexpr (detail::has_linear_iterator::value) { @@ -443,7 +443,7 @@ namespace xt } template - XTENSOR_CONSTEXPR_RETURN auto linear_begin(const C& c) noexcept + constexpr auto linear_begin(const C& c) noexcept { if constexpr (detail::has_linear_iterator::value) { @@ -456,7 +456,7 @@ namespace xt } template - XTENSOR_CONSTEXPR_RETURN auto linear_end(const C& c) noexcept + constexpr auto linear_end(const C& c) noexcept { if constexpr (detail::has_linear_iterator::value) { diff --git a/include/xtensor/core/xtensor_config.hpp b/include/xtensor/core/xtensor_config.hpp index 6a74112df..959a3b2a4 100644 --- a/include/xtensor/core/xtensor_config.hpp +++ b/include/xtensor/core/xtensor_config.hpp @@ -35,17 +35,12 @@ // Workaround for some missing constexpr functionality in MSVC 2015 and MSVC 2017 x86 #if defined(_MSC_VER) -#define XTENSOR_CONSTEXPR_ENHANCED const // The following must not be defined to const, otherwise // it prevents generation of copy operators of classes // containing XTENSOR_CONSTEXPR_ENHANCED_STATIC members #define XTENSOR_CONSTEXPR_ENHANCED_STATIC -#define XTENSOR_CONSTEXPR_RETURN inline #else -#define XTENSOR_CONSTEXPR_ENHANCED constexpr -#define XTENSOR_CONSTEXPR_RETURN constexpr #define XTENSOR_CONSTEXPR_ENHANCED_STATIC constexpr static -#define XTENSOR_HAS_CONSTEXPR_ENHANCED #endif #ifndef XTENSOR_DEFAULT_DATA_CONTAINER diff --git a/include/xtensor/views/xbroadcast.hpp b/include/xtensor/views/xbroadcast.hpp index d3034222f..68b11d443 100644 --- a/include/xtensor/views/xbroadcast.hpp +++ b/include/xtensor/views/xbroadcast.hpp @@ -96,25 +96,25 @@ namespace xt *****************************/ template - XTENSOR_CONSTEXPR_RETURN auto linear_begin(xbroadcast& c) noexcept + constexpr auto linear_begin(xbroadcast& c) noexcept { return linear_begin(c.expression()); } template - XTENSOR_CONSTEXPR_RETURN auto linear_end(xbroadcast& c) noexcept + constexpr auto linear_end(xbroadcast& c) noexcept { return linear_end(c.expression()); } template - XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xbroadcast& c) noexcept + constexpr auto linear_begin(const xbroadcast& c) noexcept { return linear_begin(c.expression()); } template - XTENSOR_CONSTEXPR_RETURN auto linear_end(const xbroadcast& c) noexcept + constexpr auto linear_end(const xbroadcast& c) noexcept { return linear_end(c.expression()); } diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index a7a4dae6e..7b6856415 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -21,16 +21,6 @@ #include "../core/xtensor_config.hpp" #include "../utils/xutils.hpp" -#ifndef XTENSOR_CONSTEXPR -#if (defined(_MSC_VER) || __GNUC__ < 8) -#define XTENSOR_CONSTEXPR inline -#define XTENSOR_GLOBAL_CONSTEXPR static const -#else -#define XTENSOR_CONSTEXPR constexpr -#define XTENSOR_GLOBAL_CONSTEXPR constexpr -#endif -#endif - namespace xt { @@ -70,11 +60,11 @@ namespace xt * slice tags * **************/ -#define DEFINE_TAG_CONVERSION(NAME) \ - template \ - XTENSOR_CONSTEXPR NAME convert() const noexcept \ - { \ - return NAME(); \ +#define DEFINE_TAG_CONVERSION(NAME) \ + template \ + constexpr NAME convert() const noexcept \ + { \ + return NAME(); \ } struct xall_tag @@ -642,12 +632,12 @@ namespace xt std::ptrdiff_t rng[3]; // = { 0, 0, 0 }; }; - XTENSOR_CONSTEXPR xtuph get_tuph_or_val(std::ptrdiff_t /*val*/, std::true_type) + constexpr xtuph get_tuph_or_val(std::ptrdiff_t /*val*/, std::true_type) { return xtuph(); } - XTENSOR_CONSTEXPR std::ptrdiff_t get_tuph_or_val(std::ptrdiff_t val, std::false_type) + constexpr std::ptrdiff_t get_tuph_or_val(std::ptrdiff_t val, std::false_type) { return val; } @@ -655,7 +645,7 @@ namespace xt template struct rangemaker { - XTENSOR_CONSTEXPR operator xrange_adaptor() + constexpr operator xrange_adaptor() { return xrange_adaptor( {get_tuph_or_val(rng[0], std::is_same()), @@ -670,7 +660,7 @@ namespace xt template struct rangemaker { - XTENSOR_CONSTEXPR operator xrange_adaptor() + constexpr operator xrange_adaptor() { return xrange_adaptor( {get_tuph_or_val(rng[0], std::is_same()), @@ -683,7 +673,7 @@ namespace xt }; template - XTENSOR_CONSTEXPR auto operator|(const rangemaker& rng, const std::ptrdiff_t& t) + constexpr auto operator|(const rangemaker& rng, const std::ptrdiff_t& t) { auto nrng = rangemaker({rng.rng[0], rng.rng[1], rng.rng[2]}); nrng.rng[sizeof...(OA)] = t; @@ -691,17 +681,17 @@ namespace xt } template - XTENSOR_CONSTEXPR auto operator|(const rangemaker& rng, const xt::placeholders::xtuph& /*t*/) + constexpr auto operator|(const rangemaker& rng, const xt::placeholders::xtuph& /*t*/) { auto nrng = rangemaker({rng.rng[0], rng.rng[1], rng.rng[2]}); return nrng; } - XTENSOR_GLOBAL_CONSTEXPR xtuph _{}; - XTENSOR_GLOBAL_CONSTEXPR rangemaker<> _r = rangemaker<>({{0, 0, 0}}); - XTENSOR_GLOBAL_CONSTEXPR xall_tag _a{}; - XTENSOR_GLOBAL_CONSTEXPR xnewaxis_tag _n{}; - XTENSOR_GLOBAL_CONSTEXPR xellipsis_tag _e{}; + constexpr xtuph _{}; + constexpr rangemaker<> _r = rangemaker<>({{0, 0, 0}}); + constexpr xall_tag _a{}; + constexpr xnewaxis_tag _n{}; + constexpr xellipsis_tag _e{}; } inline auto xnone() @@ -1598,6 +1588,4 @@ namespace xt } } -#undef XTENSOR_CONSTEXPR - #endif From ff10a8504f990537597e8f5ba834fbfedd5ef65a Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Wed, 29 Apr 2026 10:19:01 +0200 Subject: [PATCH 10/25] Removed workaround for GCC4 (#2898) --- include/xtensor/containers/xstorage.hpp | 66 ------------------------- 1 file changed, 66 deletions(-) diff --git a/include/xtensor/containers/xstorage.hpp b/include/xtensor/containers/xstorage.hpp index 426480805..af96f002b 100644 --- a/include/xtensor/containers/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -1437,49 +1437,6 @@ namespace xt #define XTENSOR_CONST const #endif -#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) -#define GCC4_FALLBACK - - namespace const_array_detail - { - template - struct array_traits - { - using storage_type = T[N]; - - static constexpr T& ref(const storage_type& t, std::size_t n) noexcept - { - return const_cast(t[n]); - } - - static constexpr T* ptr(const storage_type& t) noexcept - { - return const_cast(t); - } - }; - - template - struct array_traits - { - struct empty - { - }; - - using storage_type = empty; - - static constexpr T& ref(const storage_type& /*t*/, std::size_t /*n*/) noexcept - { - return *static_cast(nullptr); - } - - static constexpr T* ptr(const storage_type& /*t*/) noexcept - { - return nullptr; - } - }; - } -#endif - /** * A std::array like class with all member function (except reverse iterators) * as constexpr. The data is immutable once set. @@ -1502,11 +1459,7 @@ namespace xt constexpr const_reference operator[](std::size_t idx) const { -#ifdef GCC4_FALLBACK - return const_array_detail::array_traits::ref(m_data, idx); -#else return m_data[idx]; -#endif } constexpr const_iterator begin() const noexcept @@ -1552,30 +1505,17 @@ namespace xt constexpr const_pointer data() const noexcept { -#ifdef GCC4_FALLBACK - return const_array_detail::array_traits::ptr(m_data); -#else return m_data; -#endif } constexpr const_reference front() const noexcept { -#ifdef GCC4_FALLBACK - return const_array_detail::array_traits::ref(m_data, 0); -#else return m_data[0]; -#endif } constexpr const_reference back() const noexcept { -#ifdef GCC4_FALLBACK - return N ? const_array_detail::array_traits::ref(m_data, N - 1) - : const_array_detail::array_traits::ref(m_data, 0); -#else return m_data[size() - 1]; -#endif } constexpr bool empty() const noexcept @@ -1588,15 +1528,9 @@ namespace xt return N; } -#ifdef GCC4_FALLBACK - XTENSOR_CONST typename const_array_detail::array_traits::storage_type m_data; -#else XTENSOR_CONST T m_data[N > 0 ? N : 1]; -#endif }; -#undef GCC4_FALLBACK - template inline bool operator==(const const_array& lhs, const const_array& rhs) { From 61cebfe682cd0bf22eb92fc7553f079449cf7db5 Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Wed, 29 Apr 2026 17:55:49 +0200 Subject: [PATCH 11/25] Removed workaround for old compilers and old C++ standards (#2902) --- include/xtensor/containers/xfixed.hpp | 5 --- include/xtensor/containers/xstorage.hpp | 4 --- include/xtensor/core/xiterable.hpp | 16 --------- include/xtensor/core/xmath.hpp | 35 ------------------- include/xtensor/core/xvectorize.hpp | 5 --- include/xtensor/generators/xbuilder.hpp | 7 ---- include/xtensor/io/xinfo.hpp | 46 ++++--------------------- include/xtensor/utils/xutils.hpp | 14 +++----- test/test_xdatesupport.cpp | 3 -- test/test_xfunction.cpp | 9 ----- test/test_xutils.cpp | 4 --- 11 files changed, 11 insertions(+), 137 deletions(-) diff --git a/include/xtensor/containers/xfixed.hpp b/include/xtensor/containers/xfixed.hpp index 54270caa7..e1b02867d 100644 --- a/include/xtensor/containers/xfixed.hpp +++ b/include/xtensor/containers/xfixed.hpp @@ -256,12 +256,7 @@ namespace xt using inner_backstrides_type = backstrides_type; // NOTE: 0D (S::size() == 0) results in storage for 1 element (scalar) -#if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(_WIN64) - // WORKAROUND FOR MSVC 2015 32 bit, fallback to unaligned container for 0D scalar case - using storage_type = std::array::value>; -#else using storage_type = aligned_array::value>; -#endif using reference = typename storage_type::reference; using const_reference = typename storage_type::const_reference; diff --git a/include/xtensor/containers/xstorage.hpp b/include/xtensor/containers/xstorage.hpp index af96f002b..62b2e4a35 100644 --- a/include/xtensor/containers/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -649,13 +649,9 @@ namespace xt using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; -#if defined(_MSC_VER) && _MSC_VER < 1910 - static constexpr std::size_t alignment = detail::allocator_alignment::value; -#else static constexpr std::size_t alignment = detail::allocator_alignment::value != 0 ? detail::allocator_alignment::value : alignof(T); -#endif svector() noexcept; ~svector(); diff --git a/include/xtensor/core/xiterable.hpp b/include/xtensor/core/xiterable.hpp index d0caf9d6f..14d386207 100644 --- a/include/xtensor/core/xiterable.hpp +++ b/include/xtensor/core/xiterable.hpp @@ -322,21 +322,6 @@ namespace xt static constexpr layout_type static_layout = inner_types::layout; -#if defined(_MSC_VER) && _MSC_VER >= 1910 - // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type - // parameters. - template - using layout_iterator = xiterator; - template - using const_layout_iterator = xiterator< - typename iterable_base::const_stepper, - typename iterable_base::inner_shape_type*, - L>; - template - using reverse_layout_iterator = std::reverse_iterator>; - template - using const_reverse_layout_iterator = std::reverse_iterator>; -#else template using layout_iterator = typename iterable_base::template layout_iterator; template @@ -345,7 +330,6 @@ namespace xt using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; template using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; -#endif template using broadcast_iterator = typename iterable_base::template broadcast_iterator; diff --git a/include/xtensor/core/xmath.hpp b/include/xtensor/core/xmath.hpp index 77f864929..315e13a82 100644 --- a/include/xtensor/core/xmath.hpp +++ b/include/xtensor/core/xmath.hpp @@ -1088,31 +1088,6 @@ namespace xt return xfunction_type(detail::lambda_adapt(std::forward(lambda)), std::forward(args)...); } -// Workaround for MSVC 2015 & GCC 4.9 -#if (defined(_MSC_VER) && _MSC_VER < 1910) || (defined(__GNUC__) && __GNUC__ < 5) -#define XTENSOR_DISABLE_LAMBDA_FCT -#endif - -#ifdef XTENSOR_DISABLE_LAMBDA_FCT - struct square_fct - { - template - auto operator()(T x) const -> decltype(x * x) - { - return x * x; - } - }; - - struct cube_fct - { - template - auto operator()(T x) const -> decltype(x * x * x) - { - return x * x * x; - } - }; -#endif - /** * @ingroup pow_functions * @brief Square power function, equivalent to e1 * e1. @@ -1125,15 +1100,11 @@ namespace xt template inline auto square(E1&& e1) noexcept { -#ifdef XTENSOR_DISABLE_LAMBDA_FCT - return make_lambda_xfunction(square_fct{}, std::forward(e1)); -#else auto fnct = [](auto x) -> decltype(x * x) { return x * x; }; return make_lambda_xfunction(std::move(fnct), std::forward(e1)); -#endif } /** @@ -1148,19 +1119,13 @@ namespace xt template inline auto cube(E1&& e1) noexcept { -#ifdef XTENSOR_DISABLE_LAMBDA_FCT - return make_lambda_xfunction(cube_fct{}, std::forward(e1)); -#else auto fnct = [](auto x) -> decltype(x * x * x) { return x * x * x; }; return make_lambda_xfunction(std::move(fnct), std::forward(e1)); -#endif } -#undef XTENSOR_DISABLE_LAMBDA_FCT - namespace detail { // Thanks to Matt Pharr in http://pbrt.org/hair.pdf diff --git a/include/xtensor/core/xvectorize.hpp b/include/xtensor/core/xvectorize.hpp index 053d7c92b..edd199021 100644 --- a/include/xtensor/core/xvectorize.hpp +++ b/include/xtensor/core/xvectorize.hpp @@ -54,14 +54,9 @@ namespace xt template xvectorizer vectorize(F&& f, R (*)(Args...)); -// Workaround for Visual Studio 15.7.1. -// Error C2668 (ambiguous call to overloaded function) mistaking a declarations -// for the definition of another overload. -#ifndef _MSC_VER template auto vectorize(F&& f) -> decltype(vectorize(std::forward(f), std::declval*>())); -#endif /****************************** * xvectorizer implementation * diff --git a/include/xtensor/generators/xbuilder.hpp b/include/xtensor/generators/xbuilder.hpp index 5ba9f7a36..d6bb27d31 100644 --- a/include/xtensor/generators/xbuilder.hpp +++ b/include/xtensor/generators/xbuilder.hpp @@ -954,17 +954,10 @@ namespace xt template inline auto meshgrid_impl(std::index_sequence, E&&... e) noexcept { -#if defined _MSC_VER - const std::array shape = {e.shape()[0]...}; - return std::make_tuple( - detail::make_xgenerator(detail::repeat_impl>(std::forward(e), I), shape)... - ); -#else return std::make_tuple(detail::make_xgenerator( detail::repeat_impl>(std::forward(e), I), {e.shape()[0]...} )...); -#endif } } diff --git a/include/xtensor/io/xinfo.hpp b/include/xtensor/io/xinfo.hpp index f78cc3c76..478569cc7 100644 --- a/include/xtensor/io/xinfo.hpp +++ b/include/xtensor/io/xinfo.hpp @@ -14,49 +14,21 @@ #include "../core/xlayout.hpp" -#ifndef _MSC_VER -#if __cplusplus < 201103 -#define CONSTEXPR11_TN -#define CONSTEXPR14_TN -#define NOEXCEPT_TN -#elif __cplusplus < 201402 -#define CONSTEXPR11_TN constexpr -#define CONSTEXPR14_TN -#define NOEXCEPT_TN noexcept -#else -#define CONSTEXPR11_TN constexpr -#define CONSTEXPR14_TN constexpr -#define NOEXCEPT_TN noexcept -#endif -#else // _MSC_VER -#if _MSC_VER < 1900 -#define CONSTEXPR11_TN -#define CONSTEXPR14_TN -#define NOEXCEPT_TN -#elif _MSC_VER < 2000 -#define CONSTEXPR11_TN constexpr -#define CONSTEXPR14_TN -#define NOEXCEPT_TN noexcept -#else -#define CONSTEXPR11_TN constexpr -#define CONSTEXPR14_TN constexpr -#define NOEXCEPT_TN noexcept -#endif -#endif - namespace xt { // see http://stackoverflow.com/a/20170989 struct static_string { template - explicit CONSTEXPR11_TN static_string(const char (&a)[N]) NOEXCEPT_TN : data(a), - size(N - 1) + explicit constexpr static_string(const char (&a)[N]) noexcept + : data(a) + , size(N - 1) { } - CONSTEXPR11_TN static_string(const char* a, const std::size_t sz) NOEXCEPT_TN : data(a), - size(sz) + constexpr static_string(const char* a, const std::size_t sz) noexcept + : data(a) + , size(sz) { } @@ -65,18 +37,14 @@ namespace xt }; template - CONSTEXPR14_TN static_string type_name() + constexpr static_string type_name() { #ifdef __clang__ static_string p(__PRETTY_FUNCTION__); return static_string(p.data + 39, p.size - 39 - 1); #elif defined(__GNUC__) static_string p(__PRETTY_FUNCTION__); -#if __cplusplus < 201402 - return static_string(p.data + 36, p.size - 36 - 1); -#else return static_string(p.data + 54, p.size - 54 - 1); -#endif #elif defined(_MSC_VER) static const static_string p(__FUNCSIG__); return static_string(p.data + 47, p.size - 47 - 7); diff --git a/include/xtensor/utils/xutils.hpp b/include/xtensor/utils/xutils.hpp index 5a3e2af14..ca9fb0942 100644 --- a/include/xtensor/utils/xutils.hpp +++ b/include/xtensor/utils/xutils.hpp @@ -28,12 +28,6 @@ #include "../core/xtensor_config.hpp" -#if (defined(_MSC_VER) && _MSC_VER >= 1910) -#define NOEXCEPT(T) -#else -#define NOEXCEPT(T) noexcept(T) -#endif - namespace xt { /**************** @@ -53,7 +47,7 @@ namespace xt constexpr decltype(auto) argument(Args&&... args) noexcept; template - R apply(std::size_t index, F&& func, const std::tuple& s) NOEXCEPT(noexcept(func(std::get<0>(s)))); + R apply(std::size_t index, F&& func, const std::tuple& s) noexcept(noexcept(func(std::get<0>(s)))); template void nested_copy(T&& iter, const S& s); @@ -198,7 +192,7 @@ namespace xt * accumulate implementation * *****************************/ - /// @cond DOXYGEN_INCLUDE_NOEXCEPT + /// @cond DOXYGEN_INCLUDE_noexcept namespace detail { @@ -266,8 +260,8 @@ namespace xt ************************/ template - inline R apply(std::size_t index, F&& func, const std::tuple& s) - NOEXCEPT(noexcept(func(std::get<0>(s)))) + inline R + apply(std::size_t index, F&& func, const std::tuple& s) noexcept(noexcept(func(std::get<0>(s)))) { XTENSOR_ASSERT(sizeof...(S) > index); return std::apply( diff --git a/test/test_xdatesupport.cpp b/test/test_xdatesupport.cpp index 6c5894be7..33cd7ee46 100644 --- a/test/test_xdatesupport.cpp +++ b/test/test_xdatesupport.cpp @@ -55,8 +55,6 @@ namespace xt EXPECT_EQ((result < result2), expected); } -// need to wait until the system clock on Windows catches up with Linux -#ifndef _MSC_VER TEST(xdate, date_arange) { xarray tarr = xt::arange( @@ -66,7 +64,6 @@ namespace xt ); EXPECT_TRUE(tarr.storage().back() > tarr.storage().front()); } -#endif TEST(xdate, xfunction) { diff --git a/test/test_xfunction.cpp b/test/test_xfunction.cpp index 05c869517..69426d22d 100644 --- a/test/test_xfunction.cpp +++ b/test/test_xfunction.cpp @@ -480,21 +480,13 @@ namespace xt auto f1 = 2.0 * x; auto f2 = x * 2.0 * x; iterator_tester(f1); -// For an unknown reason, MSVC cannot correctly generate -// linear_cbegin() for a function of function. Moreover, -// a simple SFINAE deduction like has_linear_iterator -// harcoded and tested here fails (while it builds fine in any -// empty project) -#ifndef _MSC_VER iterator_tester(f2); iterator_tester(x * y * 3.0); iterator_tester(5.0 + x * y * 3.0); iterator_tester(x * y * z); iterator_tester(x / y / z); -#endif } -#ifndef _MSC_VER TEST(xfunction, xfunction_in_xfunction) { using Point3 = xt::xtensor_fixed>; @@ -507,5 +499,4 @@ namespace xt xtensor res{r1, r2, r3}; EXPECT_EQ(c, res); } -#endif } diff --git a/test/test_xutils.cpp b/test/test_xutils.cpp index 62df3144e..e46a883c8 100644 --- a/test/test_xutils.cpp +++ b/test/test_xutils.cpp @@ -113,11 +113,7 @@ namespace xt return i; }; auto t = std::make_tuple(1, 2, 3); -#if (_MSC_VER >= 1910) - static_assert(!noexcept(apply(1, func_ne, t))); -#else static_assert(noexcept(apply(1, func_ne, t))); -#endif } TEST(utils, conditional_cast) From c88d087fe3396642de01b86d4f58400c98de557a Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Thu, 30 Apr 2026 07:16:17 +0200 Subject: [PATCH 12/25] Removed xtrivially_default_constructible (#2903) --- .../xtensor/containers/xbuffer_adaptor.hpp | 2 +- include/xtensor/containers/xstorage.hpp | 8 +++--- include/xtensor/utils/xutils.hpp | 28 ------------------- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/include/xtensor/containers/xbuffer_adaptor.hpp b/include/xtensor/containers/xbuffer_adaptor.hpp index f9ac409a1..e59503f3a 100644 --- a/include/xtensor/containers/xbuffer_adaptor.hpp +++ b/include/xtensor/containers/xbuffer_adaptor.hpp @@ -709,7 +709,7 @@ namespace xt rhs.get_allocator() ); pointer tmp = safe_init_allocate(al, rhs.m_size); - if (xtrivially_default_constructible::value) + if (std::is_trivially_default_constructible::value) { std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); } diff --git a/include/xtensor/containers/xstorage.hpp b/include/xtensor/containers/xstorage.hpp index 62b2e4a35..efeb6571e 100644 --- a/include/xtensor/containers/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -167,7 +167,7 @@ namespace xt using pointer = typename traits::pointer; using value_type = typename traits::value_type; pointer res = alloc.allocate(size); - if (!xtrivially_default_constructible::value) + if (!std::is_trivially_default_constructible::value) { for (pointer p = res; p != res + size; ++p) { @@ -189,7 +189,7 @@ namespace xt using value_type = typename traits::value_type; if (ptr != nullptr) { - if (!xtrivially_default_constructible::value) + if (!std::is_trivially_default_constructible::value) { for (pointer p = ptr; p != ptr + size; ++p) { @@ -325,7 +325,7 @@ namespace xt rhs.get_allocator() ); resize_impl(rhs.size()); - if (xtrivially_default_constructible::value) + if (std::is_trivially_default_constructible::value) { std::uninitialized_copy(rhs.p_begin, rhs.p_end, p_begin); } @@ -1255,7 +1255,7 @@ namespace xt template inline void svector::destroy_range(T* begin, T* end) { - if (!xtrivially_default_constructible::value) + if (!std::is_trivially_default_constructible::value) { while (begin != end) { diff --git a/include/xtensor/utils/xutils.hpp b/include/xtensor/utils/xutils.hpp index ca9fb0942..e93d8e688 100644 --- a/include/xtensor/utils/xutils.hpp +++ b/include/xtensor/utils/xutils.hpp @@ -609,34 +609,6 @@ namespace xt template concept iterator_concept = is_iterator::value; - /******************************************** - * xtrivial_default_construct implemenation * - ********************************************/ - -#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7 -// has_trivial_default_constructor has not been available since libstdc++-7. -#define XTENSOR_GLIBCXX_USE_CXX11_ABI 1 -#else -#if defined(_GLIBCXX_USE_CXX11_ABI) -#if _GLIBCXX_USE_CXX11_ABI || (defined(_GLIBCXX_USE_DUAL_ABI) && !_GLIBCXX_USE_DUAL_ABI) -#define XTENSOR_GLIBCXX_USE_CXX11_ABI 1 -#endif -#endif -#endif - -#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(XTENSOR_GLIBCXX_USE_CXX11_ABI) - - template - using xtrivially_default_constructible = std::is_trivially_default_constructible; - -#else - - template - using xtrivially_default_constructible = std::has_trivial_default_constructor; - -#endif -#undef XTENSOR_GLIBCXX_USE_CXX11_ABI - /************************* * conditional type cast * *************************/ From 68f9a7742e17be1776d810d5653bb20924216320 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Thu, 30 Apr 2026 11:36:22 +0200 Subject: [PATCH 13/25] Fix CSV reader to handle 8-bit integers (#2904) --- include/xtensor/io/xcsv.hpp | 14 ++++++- test/test_xcsv.cpp | 83 +++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/include/xtensor/io/xcsv.hpp b/include/xtensor/io/xcsv.hpp index 080ccaf54..2fd347745 100644 --- a/include/xtensor/io/xcsv.hpp +++ b/include/xtensor/io/xcsv.hpp @@ -66,7 +66,7 @@ namespace xt } size_t last = cell.find_last_not_of(' '); - return cell.substr(first, last == std::string::npos ? cell.size() : last + 1); + return cell.substr(first, last == std::string::npos ? cell.size() : last - first + 1); } template <> @@ -93,6 +93,18 @@ namespace xt return std::stoi(cell); } + template <> + inline signed char lexical_cast(const std::string& cell) + { + return static_cast(std::stoi(cell)); + } + + template <> + inline unsigned char lexical_cast(const std::string& cell) + { + return static_cast(std::stoul(cell)); + } + template <> inline long lexical_cast(const std::string& cell) { diff --git a/test/test_xcsv.cpp b/test/test_xcsv.cpp index 767718fe1..148b40cd3 100644 --- a/test/test_xcsv.cpp +++ b/test/test_xcsv.cpp @@ -43,6 +43,20 @@ namespace xt ASSERT_TRUE(all(equal(res, exp))); } + TEST(xcsv, load_binary_matrix) + { + const std::string source = "1,0,1\n" + "0,1,1"; + + std::stringstream source_stream(source); + + const xtensor res = load_csv(source_stream); + + const xtensor exp{{1, 0, 1}, {0, 1, 1}}; + + ASSERT_TRUE(all(equal(res, exp))); + } + TEST(xcsv, load_double_with_options) { std::string source = "A B C D\n" @@ -60,6 +74,56 @@ namespace xt ASSERT_TRUE(all(equal(res, exp))); } + TEST(xcsv, load_string_trims_cells) + { + const std::string source = " alpha , beta,gamma \n delta, epsilon , zeta "; + + std::stringstream source_stream(source); + + const xtensor res = load_csv(source_stream); + + ASSERT_EQ(res.shape()[0], std::size_t(2)); + ASSERT_EQ(res.shape()[1], std::size_t(3)); + ASSERT_EQ(res(0, 0), "alpha"); + ASSERT_EQ(res(0, 1), "beta"); + ASSERT_EQ(res(0, 2), "gamma"); + ASSERT_EQ(res(1, 0), "delta"); + ASSERT_EQ(res(1, 1), "epsilon"); + ASSERT_EQ(res(1, 2), "zeta"); + } + + TEST(xcsv, load_file_uses_config) + { + const std::string source = "metadata\n" + "//ignore this row\n" + "1;2;3\n" + "4;5;6\n" + "7;8;9"; + + std::stringstream source_stream(source); + xcsv_config config; + config.delimiter = ';'; + config.skip_rows = 1; + config.max_rows = 2; + config.comments = "//"; + + xtensor res = {{0, 0, 0}}; + load_file(source_stream, res, config); + + const xtensor exp{{1, 2, 3}, {4, 5, 6}}; + + ASSERT_TRUE(all(equal(res, exp))); + } + + TEST(xcsv, load_inconsistent_rows_throws) + { + const std::string source = "1,2,3\n4,5"; + + std::stringstream source_stream(source); + + XT_EXPECT_THROW(load_csv(source_stream), std::runtime_error); + } + TEST(xcsv, dump_1D) { xtensor data{{1.0, 2.0, 3.0, 4.0}}; @@ -79,4 +143,23 @@ namespace xt dump_csv(res, data); ASSERT_EQ("1,2,3,4\n10,12,15,18\n", res.str()); } + + TEST(xcsv, dump_file_matches_dump_csv) + { + xtensor data{{1, 2}, {3, 4}}; + std::stringstream res; + xcsv_config config; + + dump_file(res, data, config); + + ASSERT_EQ("1,2\n3,4\n", res.str()); + } + + TEST(xcsv, dump_higher_dimension_throws) + { + xtensor data{{{1.0, 2.0}, {3.0, 4.0}}}; + std::stringstream res; + + XT_EXPECT_THROW(dump_csv(res, data), std::runtime_error); + } } From 42d124c54fd28f8724d202c893550baca770dc03 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Mon, 4 May 2026 00:40:34 +0200 Subject: [PATCH 14/25] Fix xview assignment through leading newaxis slices (#2896) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description This PR fixes incorrect index mapping in xview assignments when a view starts with one or more newaxis() slices. The change updates the index computation to use a newaxis-aware slice index before applying integral-slice adjustments. That keeps writes through views with multiple leading newaxis() entries aligned with the correct element in the underlying tensor. Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> --- include/xtensor/views/xview.hpp | 5 +++-- test/test_xview.cpp | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index ea546d4ff..025df0ae4 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -1645,8 +1645,9 @@ namespace xt { if constexpr (lesser_condition::value) { - return sliced_access(I) + newaxis_count_before(I + 1)>( - std::get(I + 1)>(m_slices), + constexpr size_type slice_index = newaxis_skip(I); + return sliced_access(slice_index)>( + std::get(m_slices), args... ); } diff --git a/test/test_xview.cpp b/test/test_xview.cpp index 5f81047b2..c98993bf9 100644 --- a/test/test_xview.cpp +++ b/test/test_xview.cpp @@ -1591,6 +1591,45 @@ namespace xt EXPECT_EQ(a, b); } + TEST(xview, assign_through_multiple_leading_newaxis) + { + SUBCASE("updates the underlying tensor for every element") + { + xt::xtensor tensor = xt::zeros({4, 3}); + auto view = xt::view(tensor, xt::newaxis(), xt::newaxis(), xt::newaxis(), xt::all(), xt::all()); + + uint8_t value = 0; + for (std::size_t row = 0; row < 4; ++row) + { + for (std::size_t col = 0; col < 3; ++col) + { + view(std::size_t{0}, std::size_t{0}, std::size_t{0}, row, col) = value; + EXPECT_EQ(tensor(row, col), value); + ++value; + } + } + + EXPECT_EQ(tensor, xt::arange(12).reshape({4, 3})); + } + + SUBCASE("preserves bool assignment semantics") + { + xt::xtensor tensor = xt::zeros({4, 3}); + auto view = xt::view(tensor, xt::newaxis(), xt::newaxis(), xt::newaxis(), xt::all(), xt::all()); + + for (std::size_t row = 0; row < 4; ++row) + { + for (std::size_t col = 0; col < 3; ++col) + { + view(std::size_t{0}, std::size_t{0}, std::size_t{0}, row, col) = true; + EXPECT_TRUE(tensor(row, col)); + } + } + + EXPECT_EQ(tensor, xt::ones({4, 3})); + } + } + TEST(xview, in_bounds) { xt::xtensor a = {{0, 1, 2}, {3, 4, 5}}; From 5caa64dbd14c43057008cca17753e40a0efcfe1b Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Tue, 5 May 2026 13:57:35 +0200 Subject: [PATCH 15/25] Update CI: Add clang 22 (#2905) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Add clang 22 and gcc 15 in the CI --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Co-authored-by: Copilot --- .github/workflows/linux.yml | 12 ++++++++++-- .github/workflows/static-analysis.yml | 4 ++-- include/xtensor/generators/xbuilder.hpp | 10 +++++----- include/xtensor/views/index_mapper.hpp | 12 ++++++++---- include/xtensor/views/xslice.hpp | 10 +++++----- include/xtensor/views/xstrided_view.hpp | 2 +- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index a4de87fb8..876a37135 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -23,6 +23,9 @@ jobs: - {compiler: clang, version: '19', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} - {compiler: clang, version: '20', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} - {compiler: clang, version: '21', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} + - {compiler: clang, version: '21', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} + - {compiler: clang, version: '22', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} + - {compiler: clang, version: '22', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} - {compiler: gcc, version: '11', name: openmp, flags: -DXTENSOR_USE_OPENMP=ON} - {compiler: gcc, version: '11', name: noexcept, flags: -DXTENSOR_DISABLE_EXCEPTIONS=ON} - {compiler: gcc, version: '12', name: xsimd, flags: -DXTENSOR_USE_XSIMD=ON} @@ -30,10 +33,15 @@ jobs: - {compiler: gcc, version: '13', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} - {compiler: gcc, version: '14', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} - {compiler: gcc, version: '14', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + # TODO: Activate following gcc versions when switching github runner to ubuntu 26.04 + # - {compiler: gcc, version: '15', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + # - {compiler: gcc, version: '15', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + # - {compiler: gcc, version: '16', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} + # - {compiler: gcc, version: '16', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} steps: - name: Install GCC if: matrix.sys.compiler == 'gcc' - uses: egor-tensin/setup-gcc@v1 + uses: egor-tensin/setup-gcc@v2 with: version: ${{matrix.sys.version}} platform: x64 @@ -53,7 +61,7 @@ jobs: sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set conda environment uses: mamba-org/setup-micromamba@main diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index e3204614b..64fe21244 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -10,8 +10,8 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: pre-commit/action@v3.0.0 + - uses: actions/checkout@v6 + - uses: pre-commit/action@v3.0.1 include-check: runs-on: ubuntu-latest diff --git a/include/xtensor/generators/xbuilder.hpp b/include/xtensor/generators/xbuilder.hpp index d6bb27d31..7474357b6 100644 --- a/include/xtensor/generators/xbuilder.hpp +++ b/include/xtensor/generators/xbuilder.hpp @@ -574,18 +574,18 @@ namespace xt } const auto& shape = arr.shape(); const size_t stride = std::accumulate( - shape.begin() + i + 1, + shape.begin() + static_cast(i) + 1, shape.end(), - 1, + size_t(1), std::multiplies() ); - const auto len = (*(first + i + after_axis)); + const auto len = (*(first + static_cast(i + after_axis))); offset += len * stride; } - const auto element = arr.begin() + offset; + const auto element = arr.begin() + static_cast(offset); return *element; }; - size_type i = *(first + axis); + size_type i = *(first + static_cast(axis)); return apply(i, get_item, t); } }; diff --git a/include/xtensor/views/index_mapper.hpp b/include/xtensor/views/index_mapper.hpp index 84685f28a..574bcb476 100644 --- a/include/xtensor/views/index_mapper.hpp +++ b/include/xtensor/views/index_mapper.hpp @@ -402,8 +402,9 @@ namespace xt { constexpr size_t n_indices_full = n_indices_full_v; - constexpr size_t underlying_n_dimensions = xt::static_dimension< - typename std::decay_t::shape_type>::value; + constexpr size_t underlying_n_dimensions = static_cast( + xt::static_dimension::shape_type>::value + ); // If there is too many indices, we need to drop the first ones. // If the number of dimensions of the underlying container is known at compile time we can drop them @@ -462,7 +463,9 @@ namespace xt const view_type& view ) const -> conditional_reference { - constexpr size_t n_indices_full = n_indices_full_v<>; + // Work around compilers failing to deduce nb_integral_slices as a non-type template argument inline + // (error: use of variable template 'n_indices_full_v' requires template arguments) + constexpr size_t n_indices_full = nb_integral_slices; return map_all_indices( is_const, @@ -517,8 +520,9 @@ namespace xt } else { + using slice_size_type = typename current_slice::size_type; assert(i < slice.size()); - return size_t(slice(i)); + return size_t(slice(static_cast(i))); } } else diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index 7b6856415..3b4d3a6fb 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -708,7 +708,7 @@ namespace xt type operator()(T t) { - return (xtl::is_integral::value) ? static_cast(t) : t; + return static_cast(t); } }; @@ -770,7 +770,7 @@ namespace xt { if constexpr (is_xslice::value) { - return slice.size(); + return static_cast(slice.size()); } else { @@ -787,7 +787,7 @@ namespace xt { if constexpr (is_xslice::value) { - return slice.step_size(idx); + return static_cast(slice.step_size(idx)); } else { @@ -800,7 +800,7 @@ namespace xt { if constexpr (is_xslice::value) { - return slice.step_size(idx, n); + return static_cast(slice.step_size(idx, n)); } else { @@ -818,7 +818,7 @@ namespace xt if constexpr (is_xslice::value) { using ST = typename S::size_type; - return slice(static_cast(i)); + return static_cast(slice(static_cast(i))); } else { diff --git a/include/xtensor/views/xstrided_view.hpp b/include/xtensor/views/xstrided_view.hpp index aa84b20a7..3faff70c8 100644 --- a/include/xtensor/views/xstrided_view.hpp +++ b/include/xtensor/views/xstrided_view.hpp @@ -833,7 +833,7 @@ namespace xt if (iter != std::end(shape)) { const auto total = std::accumulate(shape.cbegin(), shape.cend(), -1, std::multiplies{}); - const auto missing_dimension = size / total; + const auto missing_dimension = size / static_cast(total); (*iter) = static_cast(missing_dimension); } } From 3b8e0c4112c957410a93432b22b74971bc06f8f8 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Wed, 6 May 2026 15:12:17 +0200 Subject: [PATCH 16/25] Fix clip function behavior when a_min is greater than a_max (#2909) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Address #2860 Now `clips` follow the rule: When a_min is greater than a_max, clip returns an array in which all values are equal to a_max --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Co-authored-by: Copilot --- include/xtensor/core/xmath.hpp | 4 ++-- test/test_xmath.cpp | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/xtensor/core/xmath.hpp b/include/xtensor/core/xmath.hpp index 315e13a82..827e84219 100644 --- a/include/xtensor/core/xmath.hpp +++ b/include/xtensor/core/xmath.hpp @@ -606,13 +606,13 @@ namespace xt template constexpr auto operator()(const A1& v, const A2& lo, const A3& hi) const { - return xtl::select(v < lo, lo, xtl::select(hi < v, hi, v)); + return xtl::select(lo < hi, xtl::select(v < lo, lo, xtl::select(hi < v, hi, v)), hi); } template constexpr auto simd_apply(const A1& v, const A2& lo, const A3& hi) const { - return xt_simd::select(v < lo, lo, xt_simd::select(hi < v, hi, v)); + return xt_simd::select(lo < hi, xt_simd::select(v < lo, lo, xt_simd::select(hi < v, hi, v)), hi); } }; diff --git a/test/test_xmath.cpp b/test/test_xmath.cpp index 8f56e93b9..57771859b 100644 --- a/test/test_xmath.cpp +++ b/test/test_xmath.cpp @@ -222,6 +222,15 @@ namespace xt EXPECT_EQ(res1, clip(opt_a, 2.0, 4.0)); } + TEST(xmath, clip_amin_greater_than_amax) + { + // NumPy-compatible behavior: when a_min > a_max, all values + // are set to a_max (the hi bound). + const xarray arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const xarray expected = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + EXPECT_EQ(expected, clip(arr, 8, 1)); + } + TEST(xmath, sign) { shape_type shape = {3, 2}; From 6c2e51bd1fe5915922a6ef31d919043c673f3539 Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Mon, 11 May 2026 22:20:27 +0200 Subject: [PATCH 17/25] Fixed lambda return type used in xfunxtion (#2913) Fixes #2911 --- include/xtensor/core/xfunction.hpp | 14 +++++++------- test/test_xfunction.cpp | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/include/xtensor/core/xfunction.hpp b/include/xtensor/core/xfunction.hpp index ffc411a15..6459e998d 100644 --- a/include/xtensor/core/xfunction.hpp +++ b/include/xtensor/core/xfunction.hpp @@ -608,7 +608,7 @@ namespace xt // leading to warning about signed/unsigned conversions in the deeper layers of the access methods return std::apply( - [&](auto&... e) + [&](auto&... e) -> const_reference { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); @@ -631,7 +631,7 @@ namespace xt inline auto xfunction::flat(size_type index) const -> const_reference { return std::apply( - [&](auto&... e) + [&](auto&... e) -> const_reference { return m_f(e.data_element(index)...); }, @@ -665,7 +665,7 @@ namespace xt // The static cast prevents the compiler from instantiating the template methods with signed integers, // leading to warning about signed/unsigned conversions in the deeper layers of the access methods return std::apply( - [&](const auto&... e) + [&](const auto&... e) -> const_reference { return m_f(e.unchecked(static_cast(args)...)...); }, @@ -685,7 +685,7 @@ namespace xt inline auto xfunction::element(It first, It last) const -> const_reference { return std::apply( - [&](auto&... e) + [&](auto&... e) -> const_reference { XTENSOR_TRY(check_element_index(shape(), first, last)); return m_f(e.element(first, last)...); @@ -826,7 +826,7 @@ namespace xt inline auto xfunction::data_element(size_type i) const -> const_reference { return std::apply( - [&](auto&... e) + [&](auto&... e) -> const_reference { return m_f(e.data_element(i)...); }, @@ -957,7 +957,7 @@ namespace xt inline auto xfunction_iterator::operator*() const -> reference { return std::apply( - [&](auto&... it) + [&](auto&... it) -> reference { return (p_f->m_f)(*it...); }, @@ -1109,7 +1109,7 @@ namespace xt inline auto xfunction_stepper::operator*() const -> reference { return std::apply( - [&](auto&... e) + [&](auto&... e) -> reference { return (p_f->m_f)(*e...); }, diff --git a/test/test_xfunction.cpp b/test/test_xfunction.cpp index 69426d22d..ddf08758c 100644 --- a/test/test_xfunction.cpp +++ b/test/test_xfunction.cpp @@ -10,6 +10,7 @@ #include "xtensor/containers/xarray.hpp" #include "xtensor/containers/xfixed.hpp" #include "xtensor/containers/xtensor.hpp" +#include "xtensor/core/xvectorize.hpp" #include "xtensor/generators/xrandom.hpp" #include "xtensor/views/xview.hpp" @@ -193,6 +194,21 @@ namespace xt } } + TEST(xfunction, access_dangling_reference) + { + auto values_original = xt::xtensor{1., 2., 3.}; + auto indexes = xt::arange(values_original.size()); + auto map = [&](const size_t& index) -> auto& + { + return values_original[index]; + }; + auto values_mapped = xt::vectorize(map)(indexes); + for (size_t i = 0; i < values_original.size(); ++i) + { + EXPECT_TRUE(&(values_mapped[i]) == &(values_original[i])); + } + } + TEST(xfunction, unchecked) { xfunction_features f; From ebeb3c6958819ac7bca392a9f2898957ff452122 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Mon, 11 May 2026 22:33:12 +0200 Subject: [PATCH 18/25] Add Linux ARM builds (#2910) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Add Linux ARM build on the CI --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> --- .github/workflows/linux.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 876a37135..1a66aa273 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -12,11 +12,12 @@ defaults: shell: bash -e -l {0} jobs: build: - runs-on: ubuntu-24.04 - name: ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} - ${{ matrix.sys.name }} + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }} ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} - ${{ matrix.sys.name }} strategy: fail-fast: false matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm] sys: - {compiler: clang, version: '17', name: assert, flags: -DXTENSOR_ENABLE_ASSERT=ON} - {compiler: clang, version: '18', name: column-major, flags: -DDEFAULT_COLUMN_MAJOR=ON} @@ -38,6 +39,16 @@ jobs: # - {compiler: gcc, version: '15', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} # - {compiler: gcc, version: '16', name: xsimd-tbb, flags: -DXTENSOR_USE_XSIMD=ON -DXTENSOR_USE_TBB=ON} # - {compiler: gcc, version: '16', name: tbb, flags: -DXTENSOR_USE_TBB=ON -DTBB_INCLUDE_DIR=$CONDA_PREFIX/include -DTBB_LIBRARY=$CONDA_PREFIX/lib} + exclude: + - os: ubuntu-24.04-arm + sys: + compiler: gcc + version: '12' + - os: ubuntu-24.04-arm + sys: + compiler: gcc + version: '11' + steps: - name: Install GCC if: matrix.sys.compiler == 'gcc' From 2b01100feae099fe3f9476c62e2f1edebeed9aa5 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Mon, 11 May 2026 22:37:49 +0200 Subject: [PATCH 19/25] Xcsv dump config (#2906) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description xcsv_config is now used to configure dump csv function --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Co-authored-by: Copilot --- include/xtensor/io/xcsv.hpp | 45 +++++++++++++++++++++++++++++++++++-- test/test_xcsv.cpp | 24 ++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/include/xtensor/io/xcsv.hpp b/include/xtensor/io/xcsv.hpp index 2fd347745..70472625e 100644 --- a/include/xtensor/io/xcsv.hpp +++ b/include/xtensor/io/xcsv.hpp @@ -274,6 +274,47 @@ namespace xt } }; + template + void dump_csv(std::ostream& stream, const xexpression& e, const xcsv_config& config) + { + using size_type = typename E::size_type; + const E& ex = e.derived_cast(); + if (ex.dimension() == 1) + { + const size_type n = ex.shape()[0]; + for (size_type i = 0; i != n; ++i) + { + stream << ex(i); + if (i != n - 1) + { + stream << config.delimiter; + } + } + stream << std::endl; + } + else if (ex.dimension() == 2) + { + const size_type nbrows = ex.shape()[0]; + const size_type nbcols = ex.shape()[1]; + for (size_type r = 0; r != nbrows; ++r) + { + for (size_type c = 0; c != nbcols; ++c) + { + stream << ex(r, c); + if (c != nbcols - 1) + { + stream << config.delimiter; + } + } + stream << std::endl; + } + } + else + { + XTENSOR_THROW(std::runtime_error, "Only 1-D and 2-D expressions can be serialized to CSV"); + } + } + template void load_file(std::istream& stream, xexpression& e, const xcsv_config& config) { @@ -287,9 +328,9 @@ namespace xt } template - void dump_file(std::ostream& stream, const xexpression& e, const xcsv_config&) + void dump_file(std::ostream& stream, const xexpression& e, const xcsv_config& config) { - dump_csv(stream, e); + dump_csv(stream, e, config); } } diff --git a/test/test_xcsv.cpp b/test/test_xcsv.cpp index 148b40cd3..00fcd4519 100644 --- a/test/test_xcsv.cpp +++ b/test/test_xcsv.cpp @@ -162,4 +162,28 @@ namespace xt XT_EXPECT_THROW(dump_csv(res, data), std::runtime_error); } + + TEST(xcsv, dump_with_config) + { + xtensor data{{1.0, 2.0, 3.0, 4.0}, {10.0, 12.0, 15.0, 18.0}}; + + std::stringstream res; + + xcsv_config config; + config.delimiter = ' '; + dump_csv(res, data, config); + ASSERT_EQ("1 2 3 4\n10 12 15 18\n", res.str()); + } + + TEST(xcsv, dump_file_with_config) + { + xtensor data{{1.0, 2.0, 3.0, 4.0}, {10.0, 12.0, 15.0, 18.0}}; + + std::stringstream res; + + xcsv_config config; + config.delimiter = ';'; + dump_file(res, data, config); + ASSERT_EQ("1;2;3;4\n10;12;15;18\n", res.str()); + } } From 8adbd1c774f45e7b317b73d6ca191751248f4a0e Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Mon, 11 May 2026 22:53:11 +0200 Subject: [PATCH 20/25] Prevent buffer overflow when assigning to fixed-dimension xtensor with mismatched rank (#2907) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Addressing https://github.com/xtensor-stack/xtensor/issues/2792 Assigning a higher-dimensional expression to a fixed-rank [xtensor] caused a buffer overflow (stack smashing) in release builds: ```c++ auto a = xt::xtensor::from_shape({2}); a = xt::expand_dims(a, 0); // expand_dims returns 2D view, shape {1, 2} // buffer overflow: resize truncates shape {1,2} -> {1}, then copies 2 elements into 1 element buffer ``` --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> --- include/xtensor/containers/xcontainer.hpp | 4 ++-- test/test_xassign.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/xtensor/containers/xcontainer.hpp b/include/xtensor/containers/xcontainer.hpp index a2ab4fd0d..7f17ffe01 100644 --- a/include/xtensor/containers/xcontainer.hpp +++ b/include/xtensor/containers/xcontainer.hpp @@ -997,10 +997,10 @@ namespace xt template inline void xstrided_container::resize(S&& shape, bool force) { - XTENSOR_ASSERT_MSG( + XTENSOR_PRECONDITION( detail::check_resize_dimension(m_shape, shape), "cannot change the number of dimensions of xtensor" - ) + ); std::size_t dim = shape.size(); if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) diff --git a/test/test_xassign.cpp b/test/test_xassign.cpp index c6ca46305..3535b4886 100644 --- a/test/test_xassign.cpp +++ b/test/test_xassign.cpp @@ -15,6 +15,7 @@ #include "xtensor/containers/xtensor.hpp" #include "xtensor/core/xassign.hpp" #include "xtensor/core/xnoalias.hpp" +#include "xtensor/misc/xmanipulation.hpp" #include "test_common.hpp" #include "test_common_macros.hpp" @@ -167,4 +168,10 @@ namespace xt EXPECT_EQ(a.shape(1), 3); } } + + TEST(xassign, fixed_dimension_mismatch) + { + auto a = xt::xtensor::from_shape({2}); + XT_ASSERT_THROW(a = xt::expand_dims(a, 0), std::runtime_error); + } } From 961722d2fce9222d9be4e5ab38e7384e32395381 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Mon, 11 May 2026 23:10:04 +0200 Subject: [PATCH 21/25] Enhance xmasked_view support for output streaming (#2899) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Fix `xt::masked_view` pretty-printing when the underlying data is non-optional. Related to: #2495 The generic non-fundamental printer was streaming masked proxy values directly, which could lose the correct masked/value state during formatting. This change keeps the existing generic printer path but handles `xtl::xmasked_value` with a compile-time branch and streams a stabilized value via unary `+`. ## Changes - include `xtl/xmasked_value_meta.hpp` in `xio.hpp` - update the generic non-fundamental printer to use `if constexpr` - stream masked values with `buf << +val` - add a regression test for `masked_view` stream output on plain `xarray` data --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> --- include/xtensor/io/xio.hpp | 10 +++++++++- test/test_xmasked_view.cpp | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/xtensor/io/xio.hpp b/include/xtensor/io/xio.hpp index fbc0cd3a0..09ee4da58 100644 --- a/include/xtensor/io/xio.hpp +++ b/include/xtensor/io/xio.hpp @@ -20,6 +20,7 @@ #include "../core/xexpression.hpp" #include "../core/xmath.hpp" #include "../views/xstrided_view.hpp" +#include "xtl/xmasked_value_meta.hpp" namespace xt { @@ -646,7 +647,14 @@ namespace xt void update(const_reference val) { std::stringstream buf; - buf << val; + if constexpr (xtl::is_xmasked_value::value) + { + buf << +val; + } + else + { + buf << val; + } std::string s = buf.str(); if (int(s.size()) > m_width) { diff --git a/test/test_xmasked_view.cpp b/test/test_xmasked_view.cpp index 14613d169..1c7f9cb4d 100644 --- a/test/test_xmasked_view.cpp +++ b/test/test_xmasked_view.cpp @@ -7,6 +7,8 @@ * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ +#include + #include "xtensor/io/xio.hpp" #include "xtensor/optional/xoptional_assembly.hpp" #include "xtensor/views/xmasked_view.hpp" @@ -210,6 +212,21 @@ namespace xt EXPECT_EQ(data, expected2); } + TEST(xmasked_view, non_optional_data_stream) + { + const xarray data = {{1., 5., 3.}, {4., 5., 6.}}; + const xarray mask = {{true, false, false}, {false, true, false}}; + + const auto masked_data = masked_view(data, mask); + + std::stringstream out; + out << masked_data; + + const std::string expected = "{{ 1, masked, masked},\n" + " {masked, 5, masked}}"; + EXPECT_EQ(out.str(), expected); + } + TEST(xmasked_view, assign) { xarray data = {{1., -2., 3.}, {4., 5., -6.}, {7., 8., -9.}}; From a49724325e46237e3b422104ad0c767c79c422c0 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Tue, 12 May 2026 17:37:05 +0200 Subject: [PATCH 22/25] Fix xt::drop with variables (#2912) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Address #2867 Changed `xtl::is_integral::value` to `xtl::is_integral>::value` in the `drop()` function template. When passing a variable like `size_t index = 1`, `T` deduces to `unsigned long&`, a reference type, which `is_integral` rejects. Decaying strips the reference so the integral branch is correctly taken. --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Co-authored-by: Johan Mabille --- include/xtensor/views/xslice.hpp | 2 +- test/test_xoperation.cpp | 23 +++++++++++++++++++++++ test/test_xview.cpp | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index 3b4d3a6fb..d2142fb82 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -484,7 +484,7 @@ namespace xt template inline auto drop(T&& indices) { - if constexpr (xtl::is_integral::value) + if constexpr (xtl::is_integral>::value) { using slice_type = xdrop_slice; using container_type = typename slice_type::container_type; diff --git a/test/test_xoperation.cpp b/test/test_xoperation.cpp index fa97a0946..21a9c77bd 100644 --- a/test/test_xoperation.cpp +++ b/test/test_xoperation.cpp @@ -858,6 +858,29 @@ namespace xt EXPECT_EQ(expected1, res3); EXPECT_EQ(expected2, res4); } + + TEST_CASE("divide_4d") + { + using T4 = xt::xtensor; + using shape_type = typename T4::shape_type; + + shape_type shape = {2, 3, 2, 2}; + T4 a(shape, 4.5f); + T4 b(shape, 1.3f); + + EXPECT_EQ((a / b)(0, 0, 0, 0), a(0, 0, 0, 0) / b(0, 0, 0, 0)); + + float sb = 1.2f; + EXPECT_EQ((a / sb)(0, 0, 0, 0), a(0, 0, 0, 0) / sb); + + float sa = 4.6f; + EXPECT_EQ((sa / b)(0, 0, 0, 0), sa / b(0, 0, 0, 0)); + + // self-divide assignment: a = a / b (no zeros in b) + auto a_before = a(1, 2, 1, 1); + a = a / b; + EXPECT_EQ(a(1, 2, 1, 1), a_before / b(1, 2, 1, 1)); + } } #undef XOPERATION_TEST_TYPES diff --git a/test/test_xview.cpp b/test/test_xview.cpp index c98993bf9..18449b742 100644 --- a/test/test_xview.cpp +++ b/test/test_xview.cpp @@ -1861,4 +1861,23 @@ namespace xt XT_ASSERT_THROW(const auto col = xt::col(arr, 0), std::invalid_argument); } + + TEST(xview, drop_on_1dim_array) + { + auto my_array = xt::xtensor({1, 2, 3}); + + // drop(1) creates a view excluding index 1 + auto v1 = xt::view(my_array, xt::drop(1)); + EXPECT_EQ(v1, (xt::xtensor{1, 3})); + + // Assign through the drop view + xt::view(my_array, xt::drop(1)) = 0.; + EXPECT_EQ(my_array, (xt::xtensor{0, 2, 0})); + + // Reset, then test drop with a variable (the original compilation issue) + my_array = xt::xtensor({1, 2, 3}); + const size_t index = 1; + auto v2 = xt::view(my_array, xt::drop(index)); + EXPECT_EQ(v2, (xt::xtensor{1, 3})); + } } From 0f06096b40a613ce8ef4c2017a872685f871a0b5 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Tue, 12 May 2026 23:51:30 +0200 Subject: [PATCH 23/25] Fix reverse iterators xstorage (#2908) # Checklist - [ ] The title and commit message(s) are descriptive. - [ ] Small commits made to fix your PR have been squashed to avoid history pollution. - [ ] Tests have been added for new features or bug fixes. - [ ] API of new functions and classes are documented. # Description --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> --- include/xtensor/containers/xstorage.hpp | 10 ++++++++++ test/test_xfixed.cpp | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/include/xtensor/containers/xstorage.hpp b/include/xtensor/containers/xstorage.hpp index efeb6571e..26d4a8ccd 100644 --- a/include/xtensor/containers/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -1640,6 +1640,16 @@ namespace xt return m_array.cend(); } + auto crbegin() const + { + return m_array.crbegin(); + } + + auto crend() const + { + return m_array.crend(); + } + constexpr std::size_t operator[](std::size_t idx) const { return m_array[idx]; diff --git a/test/test_xfixed.cpp b/test/test_xfixed.cpp index b4af22af2..3a6e8181b 100644 --- a/test/test_xfixed.cpp +++ b/test/test_xfixed.cpp @@ -22,6 +22,7 @@ #include "xtensor/core/xnoalias.hpp" #include "xtensor/io/xio.hpp" #include "xtensor/misc/xmanipulation.hpp" +#include "xtensor/views/xview.hpp" #include "test_common_macros.hpp" @@ -306,6 +307,13 @@ namespace xt using tiny_tensor = xtensor_fixed, layout_type::row_major, false>; EXPECT_GT(sizeof(fixed_tensor), sizeof(tiny_tensor)); } + + TEST(xtensor_fixed, iterators) + { + auto arr = xt::xtensor({5, 5, 5, 5, 5}); + auto fixed_arr = xt::xtensor_fixed>{1, 2, 3}; + xt::view(arr, xt::range(0, 3)) = fixed_arr + 1; + } } #endif From 849665a23f118aad05a5490c58748009fd946a05 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Wed, 13 May 2026 10:39:41 +0200 Subject: [PATCH 24/25] Fix vstack for mixed fixed-shape inputs (#2897) # Checklist - [x] The title and commit message(s) are descriptive. - [x] Small commits made to fix your PR have been squashed to avoid history pollution. - [x] Tests have been added for new features or bug fixes. - [x] API of new functions and classes are documented. # Description Fix xt::vstack so it works with xtensor_fixed inputs when stacking a mix of 1-D and 2-D fixed-shape expressions. Before this change, vstack could try to build a runtime shape for fixed-shape inputs, which fails for cases like stacking xshape<1, 2> with xshape<2, 2>. The fixed-shape path now computes the stacked result shape at compile time instead. --------- Co-authored-by: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Co-authored-by: Copilot --- include/xtensor/generators/xbuilder.hpp | 41 +++++++++++++++++++++++++ include/xtensor/views/index_mapper.hpp | 17 +++++++--- test/test_xbuilder.cpp | 15 +++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/include/xtensor/generators/xbuilder.hpp b/include/xtensor/generators/xbuilder.hpp index 7474357b6..4b9bed942 100644 --- a/include/xtensor/generators/xbuilder.hpp +++ b/include/xtensor/generators/xbuilder.hpp @@ -910,6 +910,32 @@ namespace xt namespace detail { + template + struct vstack_fixed_shape_impl; + + template + struct vstack_fixed_shape_impl> + { + using type = fixed_shape<1, N>; + }; + + template + struct vstack_fixed_shape_impl> + { + using type = fixed_shape; + }; + + template + struct vstack_fixed_shape + { + using type = concat_fixed_shape_t< + 0, + typename vstack_fixed_shape_impl::shape_type>::type...>; + }; + + template + using vstack_fixed_shape_t = typename vstack_fixed_shape::type; + template inline auto vstack_shape(std::tuple& t, const S& shape) { @@ -948,6 +974,21 @@ namespace xt return detail::make_xgenerator(detail::vstack_impl(std::move(t), size_t(0)), new_shape); } + /** + * @brief Stack fixed-shape xexpressions in sequence vertically (row wise). + * This overload preserves the result shape at compile time by treating + * 1-D fixed shapes as ``(1, N)`` row vectors before concatenation. + * + * @param t \ref xtuple of fixed-shape xexpressions to stack + * @return xgenerator evaluating to stacked elements with a fixed compile-time shape + */ + template + inline auto vstack(std::tuple&& t) + { + using shape_type = detail::vstack_fixed_shape_t; + return detail::make_xgenerator(detail::vstack_impl(std::move(t), size_t(0)), shape_type{}); + } + namespace detail { diff --git a/include/xtensor/views/index_mapper.hpp b/include/xtensor/views/index_mapper.hpp index 574bcb476..d445ac1ec 100644 --- a/include/xtensor/views/index_mapper.hpp +++ b/include/xtensor/views/index_mapper.hpp @@ -193,7 +193,7 @@ namespace xt * @throws Assertion failure if `i != 0` for integral slices. * @throws Assertion failure if `i >= slice.size()` for non-integral slices. */ - template + template size_t map_ith_index(const view_type& view, const Index i) const; /** @@ -490,16 +490,16 @@ namespace xt { if constexpr (ACCESS == access_t::SAFE) { - return container.at(map_ith_index(view, indices[Is])...); + return container.at(map_ith_index(view, indices[Is])...); } else { - return container(map_ith_index(view, indices[Is])...); + return container(map_ith_index(view, indices[Is])...); } } template - template + template auto index_mapper>::map_ith_index(const view_type& view, const Index i) const -> size_t @@ -518,10 +518,17 @@ namespace xt assert(i == 0); return size_t(slice); } + else if constexpr (xt::detail::is_xall_slice>::value) + { + return size_t(i); + } else { using slice_size_type = typename current_slice::size_type; - assert(i < slice.size()); + if constexpr (ACCESS == access_t::UNSAFE) + { + assert(static_cast(i) < slice.size()); + } return size_t(slice(static_cast(i))); } } diff --git a/test/test_xbuilder.cpp b/test/test_xbuilder.cpp index 73d952b6f..d35847a8e 100644 --- a/test/test_xbuilder.cpp +++ b/test/test_xbuilder.cpp @@ -424,6 +424,21 @@ namespace xt ASSERT_TRUE(arange(8) == w1); ASSERT_TRUE(w1 == w2); } + + TEST(xbuilder, vstack_fixed) + { + xtensor_fixed> a = {{1.f, 2.f}}; + xtensor_fixed> b = {{3.f, 4.f}, {5.f, 6.f}}; + + auto c = vstack(xtuple(a, b)); + + using expected_shape_t = fixed_shape<3, 2>; + ASSERT_EQ(expected_shape_t{}, c.shape()); + EXPECT_EQ(1.f, c(0, 0)); + EXPECT_EQ(2.f, c(0, 1)); + EXPECT_EQ(3.f, c(1, 0)); + EXPECT_EQ(6.f, c(2, 1)); + } #endif TEST(xbuilder, access) From fe2d7accd5d4143d848d74de1fd9d4348c3cf68c Mon Sep 17 00:00:00 2001 From: Samaresh Kumar Singh Date: Fri, 17 Apr 2026 20:43:30 -0500 Subject: [PATCH 25/25] Fix poisson and geometric missing default for template parameter T --- include/xtensor/generators/xrandom.hpp | 8 ++++---- test/test_xrandom.cpp | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/xtensor/generators/xrandom.hpp b/include/xtensor/generators/xrandom.hpp index d43a69876..73b1763ae 100644 --- a/include/xtensor/generators/xrandom.hpp +++ b/include/xtensor/generators/xrandom.hpp @@ -63,14 +63,14 @@ namespace xt auto binomial(const S& shape, T trials = 1, D prob = 0.5, E& engine = random::get_default_random_engine()); - template + template auto geometric(const S& shape, D prob = 0.5, E& engine = random::get_default_random_engine()); template auto negative_binomial(const S& shape, T k = 1, D prob = 0.5, E& engine = random::get_default_random_engine()); - template + template auto poisson(const S& shape, D rate = 1.0, E& engine = random::get_default_random_engine()); template @@ -123,7 +123,7 @@ namespace xt auto binomial(const I (&shape)[L], T trials = 1, D prob = 0.5, E& engine = random::get_default_random_engine()); - template + template auto geometric(const I (&shape)[L], D prob = 0.5, E& engine = random::get_default_random_engine()); template @@ -134,7 +134,7 @@ namespace xt E& engine = random::get_default_random_engine() ); - template + template auto poisson(const I (&shape)[L], D rate = 1.0, E& engine = random::get_default_random_engine()); template diff --git a/test/test_xrandom.cpp b/test/test_xrandom.cpp index c732e2ab4..0d824a794 100644 --- a/test/test_xrandom.cpp +++ b/test/test_xrandom.cpp @@ -237,6 +237,20 @@ namespace xt #endif } + TEST(xrandom, poisson_geometric_default_type) + { + // poisson and geometric have no parameter from which T can be deduced, + // so they require a default T (= int) to be callable without explicit template arg. + auto p = random::poisson({3, 3}, 1.0); + static_assert(std::is_same::value, "poisson default T must be int"); + + auto g = random::geometric({3, 3}, 0.5); + static_assert(std::is_same::value, "geometric default T must be int"); + + auto p2 = random::poisson({3, 3}); + static_assert(std::is_same::value, "poisson default T must be int"); + } + TEST(xrandom, permutation) { xt::random::seed(123);