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
4 changes: 4 additions & 0 deletions include/xtensor/core/xmath.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,10 @@ namespace xt
auto ax = normalize_axis(e, axes);
if (weights.dimension() == 1)
{
if (ax.size() != 1)
{
XTENSOR_THROW(std::runtime_error, "1-D weights need exactly one axis.");
}
if (weights.size() != e.shape()[ax[0]])
{
XTENSOR_THROW(std::runtime_error, "Weights need to have the same shape as expression at axes.");
Expand Down
3 changes: 3 additions & 0 deletions include/xtensor/generators/xbuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ namespace xt
shape_type new_shape = xtl::forward_sequence<shape_type, source_shape_type>(
std::get<0>(t).shape()
);
axis = normalize_axis(new_shape.size(), axis);

auto check_shape = [&axis, &new_shape](auto& arr)
{
Expand Down Expand Up @@ -884,6 +885,8 @@ namespace xt
{
using shape_type = promote_shape_t<typename std::decay_t<CT>::shape_type...>;
using source_shape_type = decltype(std::get<0>(t).shape());
// The stacking axis is a new one, it can be inserted up to and including dimension().
axis = normalize_axis(std::get<0>(t).dimension() + 1, axis);
auto new_shape = detail::add_axis(
xtl::forward_sequence<shape_type, source_shape_type>(std::get<0>(t).shape()),
axis,
Expand Down
66 changes: 39 additions & 27 deletions include/xtensor/misc/xmanipulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,18 +547,37 @@ namespace xt

namespace detail
{
// Each squeezed axis removes one dimension from the result, so the axes
// must be valid and distinct for the result shape to be filled exactly.
template <class S>
inline dynamic_shape<std::size_t> normalize_squeeze_axes(std::size_t dim, const S& axis)
{
dynamic_shape<std::size_t> res;
for (auto ax : axis)
{
const std::size_t nax = normalize_axis(dim, ax);
if (std::find(res.cbegin(), res.cend(), nax) != res.cend())
{
XTENSOR_THROW(std::runtime_error, "Axis " + std::to_string(nax) + " is repeated in squeeze.");
}
res.push_back(nax);
}
return res;
}

template <class E, class S>
inline auto squeeze_impl(E&& e, S&& axis, check_policy::none)
{
std::size_t new_dim = e.dimension() - axis.size();
const auto axes = normalize_squeeze_axes(e.dimension(), axis);
std::size_t new_dim = e.dimension() - axes.size();
dynamic_shape<std::size_t> new_shape(new_dim);
dynamic_shape<std::ptrdiff_t> new_strides(new_dim);

decltype(auto) old_strides = detail::get_strides<XTENSOR_DEFAULT_LAYOUT>(e);

for (std::size_t i = 0, ix = 0; i < e.dimension(); ++i)
{
if (axis.cend() == std::find(axis.cbegin(), axis.cend(), i))
if (axes.cend() == std::find(axes.cbegin(), axes.cend(), i))
{
new_shape[ix] = e.shape()[i];
new_strides[ix++] = old_strides[i];
Expand All @@ -577,18 +596,15 @@ namespace xt
template <class E, class S>
inline auto squeeze_impl(E&& e, S&& axis, check_policy::full)
{
for (auto ix : axis)
auto axes = normalize_squeeze_axes(e.dimension(), axis);
for (auto ix : axes)
{
if (static_cast<std::size_t>(ix) > e.dimension())
{
XTENSOR_THROW(std::runtime_error, "Axis argument to squeeze > dimension of expression");
}
if (e.shape()[static_cast<std::size_t>(ix)] != 1)
if (e.shape()[ix] != 1)
{
XTENSOR_THROW(std::runtime_error, "Trying to squeeze axis != 1");
}
}
return squeeze_impl(std::forward<E>(e), std::forward<S>(axis), check_policy::none());
return squeeze_impl(std::forward<E>(e), std::move(axes), check_policy::none());
}
}

Expand Down Expand Up @@ -646,8 +662,10 @@ namespace xt
template <class E>
inline auto expand_dims(E&& e, std::size_t axis)
{
xstrided_slice_vector sv(e.dimension() + 1, all());
sv[axis] = newaxis();
// The new axis can be inserted at any position up to and including dimension().
const std::size_t new_dim = e.dimension() + 1;
xstrided_slice_vector sv(new_dim, all());
sv[normalize_axis(new_dim, axis)] = newaxis();
return strided_view(std::forward<E>(e), std::move(sv));
}

Expand Down Expand Up @@ -734,8 +752,9 @@ namespace xt
*
* This splits an xexpression along the axis in `n` equal parts and
* returns a vector of ``strided_view``.
* Calling split with axis > dimension of e or a `n` that does not result in
* an equal division of the xexpression will throw a runtime_error.
* Calling split with an axis that is not smaller than the dimension of e or
* a `n` that does not result in an equal division of the xexpression will
* throw a runtime_error.
*
* @ingroup xt_xmanipulation
* @param e input xexpression
Expand All @@ -745,11 +764,7 @@ namespace xt
template <class E>
inline auto split(E& e, std::size_t n, std::size_t axis)
{
if (axis >= e.dimension())
{
XTENSOR_THROW(std::runtime_error, "Split along axis > dimension.");
}

axis = normalize_axis(e.dimension(), axis);
std::size_t ax_sz = e.shape()[axis];
xstrided_slice_vector sv(e.dimension(), all());
std::size_t step = ax_sz / n;
Expand Down Expand Up @@ -838,6 +853,7 @@ namespace xt
{
using shape_type = xindex_type_t<typename std::decay_t<E>::shape_type>;

axis = normalize_axis(e.dimension(), axis);
shape_type shape;
resize_container(shape, e.shape().size());
std::copy(e.shape().cbegin(), e.shape().cend(), shape.begin());
Expand Down Expand Up @@ -1067,17 +1083,13 @@ namespace xt
const auto& shape = cpy.shape();
const auto dim = cpy.dimension();

if (axis < -static_cast<std::ptrdiff_t>(dim) || axis >= static_cast<std::ptrdiff_t>(dim))
{
XTENSOR_THROW(std::runtime_error, "axis is not within shape dimension.");
}
const std::size_t saxis = normalize_axis(dim, axis);

if (cpy.size() == 0)
{
return cpy;
}

std::size_t saxis = normalize_axis(dim, axis);
const auto axis_dim = static_cast<std::ptrdiff_t>(shape[saxis]);

while (shift < 0)
Expand All @@ -1098,8 +1110,8 @@ namespace xt
template <class E, class R>
inline auto make_xrepeat(E&& e, R&& r, typename std::decay_t<E>::size_type axis)
{
const auto casted_axis = static_cast<typename std::decay_t<E>::size_type>(axis);
if (r.size() != e.shape(casted_axis))
axis = normalize_axis(e.dimension(), axis);
if (r.size() != e.shape(axis))
{
XTENSOR_THROW(std::invalid_argument, "repeats must have the same size as the specified axis");
}
Expand All @@ -1120,8 +1132,8 @@ namespace xt
template <class E>
inline auto repeat(E&& e, std::size_t repeats, std::size_t axis)
{
const auto casted_axis = static_cast<typename std::decay_t<E>::size_type>(axis);
std::vector<std::size_t> broadcasted_repeats(e.shape(casted_axis));
axis = normalize_axis(e.dimension(), axis);
std::vector<std::size_t> broadcasted_repeats(e.shape(axis));
std::fill(broadcasted_repeats.begin(), broadcasted_repeats.end(), repeats);
return repeat(std::forward<E>(e), std::move(broadcasted_repeats), axis);
}
Expand Down
30 changes: 16 additions & 14 deletions include/xtensor/misc/xsort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ namespace xt
template <class R, class E, class F>
inline R map_axis(const E& e, std::ptrdiff_t axis, F&& lambda)
{
const std::size_t ax = normalize_axis(e.dimension(), axis);
if (e.dimension() == 1)
{
R res = e;
lambda(res.begin(), res.end());
return res;
}

const std::size_t ax = normalize_axis(e.dimension(), axis);
if (ax == detail::leading_axis(e))
{
R res = e;
Expand Down Expand Up @@ -706,6 +706,7 @@ namespace xt
using result_type = typename detail::argsort_result_type<eval_type>::type;

const auto& de = e.derived_cast();
const std::size_t ax = normalize_axis(de.dimension(), axis);

if (de.dimension() == 1)
{
Expand All @@ -729,7 +730,6 @@ namespace xt
);
};

const std::size_t ax = normalize_axis(de.dimension(), axis);
if (ax == detail::leading_axis(de))
{
result_type res = result_type::from_shape(de.shape());
Expand Down Expand Up @@ -1157,13 +1157,16 @@ namespace xt
};

template <layout_type L, class E, class F>
inline typename argfunc_result_type<E>::type arg_func_impl(const E& e, std::size_t axis, F&& cmp)
inline typename argfunc_result_type<E>::type arg_func_impl(const E& e, std::ptrdiff_t ax, F&& cmp)
{
using eval_type = typename detail::sort_eval_type<E>::type;
using value_type = typename E::value_type;
using result_type = typename argfunc_result_type<E>::type;
using result_shape_type = typename result_type::shape_type;

// Checked here because the result shape below relies on axis < dimension().
const std::size_t axis = normalize_axis(e.dimension(), ax);

if (e.dimension() == 1)
{
auto begin = e.template begin<L>();
Expand All @@ -1184,13 +1187,14 @@ namespace xt
result_shape_type alt_shape;
xt::resize_container(alt_shape, e.dimension() - 1);

// Excluding copy, copy all of shape except for axis
std::copy(e.shape().cbegin(), e.shape().cbegin() + std::ptrdiff_t(axis), alt_shape.begin());
std::copy(
e.shape().cbegin() + std::ptrdiff_t(axis) + 1,
e.shape().cend(),
alt_shape.begin() + std::ptrdiff_t(axis)
);
// Copy all of shape except for axis
for (std::size_t i = 0, j = 0; i < e.dimension(); ++i)
{
if (i != axis)
{
alt_shape[j++] = e.shape()[i];
}
}

result_type result = result_type::from_shape(std::move(alt_shape));
auto result_iter = result.template begin<L>();
Expand Down Expand Up @@ -1260,8 +1264,7 @@ namespace xt
{
using value_type = typename E::value_type;
auto&& ed = eval(e.derived_cast());
std::size_t ax = normalize_axis(ed.dimension(), axis);
return detail::arg_func_impl<L>(ed, ax, std::less<value_type>());
return detail::arg_func_impl<L>(ed, axis, std::less<value_type>());
}

template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class E>
Expand Down Expand Up @@ -1291,8 +1294,7 @@ namespace xt
{
using value_type = typename E::value_type;
auto&& ed = eval(e.derived_cast());
std::size_t ax = normalize_axis(ed.dimension(), axis);
return detail::arg_func_impl<L>(ed, ax, std::greater<value_type>());
return detail::arg_func_impl<L>(ed, axis, std::greater<value_type>());
}

/**
Expand Down
15 changes: 13 additions & 2 deletions include/xtensor/reducers/xblockwise_reducer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,23 @@ namespace xt
{
using functor_type = std::decay_t<FF>;
using closure_type = xtl::const_closure_type_t<E>;
using axes_type = std::decay_t<A>;

// The result shape is computed from the axes before any block is reduced,
// so they have to be valid and distinct here already.
decltype(auto) normalized_axes = normalize_axis(e, std::forward<A>(axes));
using axes_type = std::decay_t<decltype(normalized_axes)>;
for (auto it = normalized_axes.begin(); it != normalized_axes.end(); ++it)
{
if (std::find(normalized_axes.begin(), it, *it) != it)
{
XTENSOR_THROW(std::runtime_error, "Reducing axes should not contain duplicates.");
}
}

return xblockwise_reducer<closure_type, functor_type, axes_type, O>(
std::forward<E>(e),
std::forward<CS>(chunk_shape),
std::forward<A>(axes),
std::forward<decltype(normalized_axes)>(normalized_axes),
std::forward<O>(raw_options),
std::forward<FF>(functor)
);
Expand Down
Loading
Loading