Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/xtensor/containers/xcontainer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,10 @@ namespace xt
template <class S>
inline auto& xstrided_container<D>::reshape(S&& shape, layout_type layout) &
{
XTENSOR_PRECONDITION(
detail::check_resize_dimension(m_shape, shape),
"cannot change the number of dimensions of xtensor"
);
reshape_impl(
std::forward<S>(shape),
xtl::is_signed<std::decay_t<typename std::decay_t<S>::value_type>>(),
Expand All @@ -1103,6 +1107,10 @@ namespace xt
template <class T>
inline auto& xstrided_container<D>::reshape(std::initializer_list<T> shape, layout_type layout) &
{
XTENSOR_PRECONDITION(
detail::check_resize_dimension(m_shape, shape),
"cannot change the number of dimensions of xtensor"
);
using sh_type = rebind_container_t<T, shape_type>;
sh_type sh = xtl::make_sequence<sh_type>(shape.size());
std::copy(shape.begin(), shape.end(), sh.begin());
Expand Down
2 changes: 1 addition & 1 deletion include/xtensor/containers/xtensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ namespace xt
template <class S>
inline xtensor_container<EC, N, L, Tag> xtensor_container<EC, N, L, Tag>::from_shape(S&& s)
{
XTENSOR_ASSERT_MSG(s.size() == N, "Cannot change dimension of xtensor.");
XTENSOR_PRECONDITION(s.size() == N, "cannot change the number of dimensions of xtensor");
shape_type shape = xtl::forward_sequence<shape_type, S>(s);
return self_type(shape);
}
Expand Down
24 changes: 23 additions & 1 deletion include/xtensor/core/xmath.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2966,6 +2966,27 @@ namespace xt
return eval(sum(trap, {saxis}));
}

namespace detail
{
// The result is a one-dimensional xtensor built from the shape of x, and
// xp and fp are read at the indices found in xp.
template <class E1, class E2, class E3>
inline void check_interp_arguments(const E1& x, const E2& xp, const E3& fp)
{
if (x.dimension() != 1 || xp.dimension() != 1 || fp.dimension() != 1)
{
XTENSOR_THROW(std::runtime_error, "interp: x, xp and fp must be one-dimensional.");
}
if (xp.size() == 0 || fp.size() != xp.size())
{
XTENSOR_THROW(
std::runtime_error,
"interp: xp must not be empty and fp must have the length of xp."
);
}
}
}

/**
* @ingroup basic_functions
* @brief Returns the one-dimensional piecewise linear interpolant to a function with given discrete data
Expand All @@ -2985,7 +3006,7 @@ namespace xt
using value_type = typename E3::value_type;

// basic checks
XTENSOR_ASSERT(xp.dimension() == 1);
detail::check_interp_arguments(x, xp, fp);
XTENSOR_ASSERT(std::is_sorted(x.cbegin(), x.cend()));
XTENSOR_ASSERT(std::is_sorted(xp.cbegin(), xp.cend()));

Expand Down Expand Up @@ -3146,6 +3167,7 @@ namespace xt
template <class E1, class E2, class E3>
inline auto interp(const E1& x, const E2& xp, const E3& fp)
{
detail::check_interp_arguments(x, xp, fp);
return interp(x, xp, fp, fp[0], fp[fp.size() - 1]);
}

Expand Down
21 changes: 21 additions & 0 deletions test/test_xmath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,27 @@ namespace xt
}
}

TEST(xmath, interp_invalid_arguments)
{
xt::xarray<double> xp = {0.0, 1.0, 3.0};
xt::xarray<double> fp = {0.0, 1.0, 3.0};
xt::xarray<double> x = {0.5, 2.0};
xt::xarray<double> x2 = {{0.5, 1.5}, {2.0, 2.5}};
xt::xarray<double> empty = xt::xarray<double>::from_shape({0});
xt::xarray<double> fp_short = {0.0, 1.0};

XT_EXPECT_THROW(xt::interp(x2, xp, fp), std::runtime_error);
XT_EXPECT_THROW(xt::interp(x, x2, fp), std::runtime_error);
XT_EXPECT_THROW(xt::interp(x, xp, x2), std::runtime_error);
XT_EXPECT_THROW(xt::interp(x, empty, empty), std::runtime_error);
XT_EXPECT_THROW(xt::interp(x, xp, fp_short), std::runtime_error);
XT_EXPECT_THROW(xt::interp(x, xp, fp_short, 0.0, 1.0), std::runtime_error);

auto f = xt::interp(x, xp, fp);
EXPECT_EQ(f(0), 0.5);
EXPECT_EQ(f(1), 2.0);
}

TEST(xmath, cov)
{
xt::xarray<double> x = {0.0, 1.0, 2.0};
Expand Down
17 changes: 17 additions & 0 deletions test/test_xtensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,23 @@ namespace xt
test_throwing_reshape(b);
}

TEST(xtensor, change_dimension)
{
// The shape of an xtensor holds exactly N values.
xtensor<int, 1> a = xt::arange(6);
XT_EXPECT_THROW(a.reshape({2, 3}), std::runtime_error);
XT_EXPECT_THROW(a.reshape(std::vector<std::size_t>{2, 3}), std::runtime_error);
XT_EXPECT_THROW(a.reshape(std::vector<int>{2, -1}), std::runtime_error);
XT_EXPECT_THROW(a.resize(std::vector<std::size_t>{2, 3}), std::runtime_error);
EXPECT_EQ(a.shape()[0], 6u);

using shape = std::vector<std::size_t>;
XT_EXPECT_THROW((xtensor<int, 1>::from_shape(shape{2, 3})), std::runtime_error);
XT_EXPECT_THROW((xtensor<int, 2>::from_shape(shape{6})), std::runtime_error);
XT_EXPECT_THROW((xtensor<int, 2>::from_shape(shape{})), std::runtime_error);
EXPECT_EQ((xtensor<int, 2>::from_shape(shape{2, 3}).size()), 6u);
}

TEST(xtensor, transpose)
{
xtensor_dynamic a;
Expand Down
Loading