Remove slow index check in Tensor::resize from release mode.

This commit is contained in:
Rasmus Munk Larsen 2024-03-18 23:43:25 +00:00
parent 386e2079e4
commit d3cd312652
6 changed files with 25 additions and 149 deletions

View File

@ -31,6 +31,7 @@ namespace Eigen {
namespace internal { namespace internal {
#ifndef EIGEN_NO_DEBUG
template <int MaxSizeAtCompileTime, int MaxRowsAtCompileTime, int MaxColsAtCompileTime> template <int MaxSizeAtCompileTime, int MaxRowsAtCompileTime, int MaxColsAtCompileTime>
struct check_rows_cols_for_overflow { struct check_rows_cols_for_overflow {
EIGEN_STATIC_ASSERT(MaxRowsAtCompileTime* MaxColsAtCompileTime == MaxSizeAtCompileTime, EIGEN_STATIC_ASSERT(MaxRowsAtCompileTime* MaxColsAtCompileTime == MaxSizeAtCompileTime,
@ -44,7 +45,7 @@ struct check_rows_cols_for_overflow<Dynamic, MaxRowsAtCompileTime, Dynamic> {
template <typename Index> template <typename Index>
EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE constexpr void run(Index, Index cols) { EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE constexpr void run(Index, Index cols) {
constexpr Index MaxIndex = NumTraits<Index>::highest(); constexpr Index MaxIndex = NumTraits<Index>::highest();
bool error = cols > MaxIndex / MaxRowsAtCompileTime; bool error = cols > (MaxIndex / MaxRowsAtCompileTime);
if (error) throw_std_bad_alloc(); if (error) throw_std_bad_alloc();
} }
}; };
@ -54,7 +55,7 @@ struct check_rows_cols_for_overflow<Dynamic, Dynamic, MaxColsAtCompileTime> {
template <typename Index> template <typename Index>
EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE constexpr void run(Index rows, Index) { EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE constexpr void run(Index rows, Index) {
constexpr Index MaxIndex = NumTraits<Index>::highest(); constexpr Index MaxIndex = NumTraits<Index>::highest();
bool error = rows > MaxIndex / MaxColsAtCompileTime; bool error = rows > (MaxIndex / MaxColsAtCompileTime);
if (error) throw_std_bad_alloc(); if (error) throw_std_bad_alloc();
} }
}; };
@ -64,10 +65,11 @@ struct check_rows_cols_for_overflow<Dynamic, Dynamic, Dynamic> {
template <typename Index> template <typename Index>
EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE constexpr void run(Index rows, Index cols) { EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE constexpr void run(Index rows, Index cols) {
constexpr Index MaxIndex = NumTraits<Index>::highest(); constexpr Index MaxIndex = NumTraits<Index>::highest();
bool error = cols == 0 ? false : (rows > MaxIndex / cols); bool error = cols == 0 ? false : (rows > (MaxIndex / cols));
if (error) throw_std_bad_alloc(); if (error) throw_std_bad_alloc();
} }
}; };
#endif
template <typename Derived, typename OtherDerived = Derived, template <typename Derived, typename OtherDerived = Derived,
bool IsVector = bool(Derived::IsVectorAtCompileTime) && bool(OtherDerived::IsVectorAtCompileTime)> bool IsVector = bool(Derived::IsVectorAtCompileTime) && bool(OtherDerived::IsVectorAtCompileTime)>
@ -297,8 +299,10 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
internal::check_implication(ColsAtCompileTime == Dynamic && MaxColsAtCompileTime != Dynamic, internal::check_implication(ColsAtCompileTime == Dynamic && MaxColsAtCompileTime != Dynamic,
cols <= MaxColsAtCompileTime) && cols <= MaxColsAtCompileTime) &&
rows >= 0 && cols >= 0 && "Invalid sizes when resizing a matrix or array."); rows >= 0 && cols >= 0 && "Invalid sizes when resizing a matrix or array.");
#ifndef EIGEN_NO_DEBUG
internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime>::run(rows, internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime>::run(rows,
cols); cols);
#endif
#ifdef EIGEN_INITIALIZE_COEFFS #ifdef EIGEN_INITIALIZE_COEFFS
Index size = rows * cols; Index size = rows * cols;
bool size_changed = size != this->size(); bool size_changed = size != this->size();
@ -367,8 +371,10 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
template <typename OtherDerived> template <typename OtherDerived>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resizeLike(const EigenBase<OtherDerived>& _other) { EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resizeLike(const EigenBase<OtherDerived>& _other) {
const OtherDerived& other = _other.derived(); const OtherDerived& other = _other.derived();
#ifndef EIGEN_NO_DEBUG
internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime>::run( internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime>::run(
other.rows(), other.cols()); other.rows(), other.cols());
#endif
const Index othersize = other.rows() * other.cols(); const Index othersize = other.rows() * other.cols();
if (RowsAtCompileTime == 1) { if (RowsAtCompileTime == 1) {
eigen_assert(other.rows() == 1 || other.cols() == 1); eigen_assert(other.rows() == 1 || other.cols() == 1);
@ -941,8 +947,10 @@ struct conservative_resize_like_impl {
((Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows ((Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows
(!Derived::IsRowMajor && _this.rows() == rows))) // column-major and we change only the number of columns (!Derived::IsRowMajor && _this.rows() == rows))) // column-major and we change only the number of columns
{ {
#ifndef EIGEN_NO_DEBUG
internal::check_rows_cols_for_overflow<Derived::MaxSizeAtCompileTime, Derived::MaxRowsAtCompileTime, internal::check_rows_cols_for_overflow<Derived::MaxSizeAtCompileTime, Derived::MaxRowsAtCompileTime,
Derived::MaxColsAtCompileTime>::run(rows, cols); Derived::MaxColsAtCompileTime>::run(rows, cols);
#endif
_this.derived().m_storage.conservativeResize(rows * cols, rows, cols); _this.derived().m_storage.conservativeResize(rows * cols, rows, cols);
} else { } else {
// The storage order does not allow us to use reallocation. // The storage order does not allow us to use reallocation.

View File

@ -303,12 +303,16 @@ class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexTyp
/** Normal Dimension */ /** Normal Dimension */
EIGEN_DEVICE_FUNC void resize(const array<Index, NumIndices>& dimensions) { EIGEN_DEVICE_FUNC void resize(const array<Index, NumIndices>& dimensions) {
int i; #ifndef EIGEN_NO_DEBUG
Index size = Index(1); Index size = Index(1);
for (i = 0; i < NumIndices; i++) { for (int i = 0; i < NumIndices; i++) {
internal::check_rows_cols_for_overflow<Dynamic, Dynamic, Dynamic>::run(size, dimensions[i]); internal::check_rows_cols_for_overflow<Dynamic, Dynamic, Dynamic>::run(size, dimensions[i]);
size *= dimensions[i]; size *= dimensions[i];
} }
#else
Index size = internal::array_prod(dimensions);
#endif
#ifdef EIGEN_INITIALIZE_COEFFS #ifdef EIGEN_INITIALIZE_COEFFS
bool size_changed = size != this->size(); bool size_changed = size != this->size();
m_storage.resize(size, dimensions); m_storage.resize(size, dimensions);
@ -318,15 +322,6 @@ class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexTyp
#endif #endif
} }
// Why this overload, DSizes is derived from array ??? //
EIGEN_DEVICE_FUNC void resize(const DSizes<Index, NumIndices>& dimensions) {
array<Index, NumIndices> dims;
for (int i = 0; i < NumIndices; ++i) {
dims[i] = dimensions[i];
}
resize(dims);
}
EIGEN_DEVICE_FUNC void resize() { EIGEN_DEVICE_FUNC void resize() {
EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE);
// Nothing to do: rank 0 tensors have fixed size // Nothing to do: rank 0 tensors have fixed size
@ -347,7 +342,6 @@ class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexTyp
resize(internal::customIndices2Array<Index, NumIndices>(dimensions)); resize(internal::customIndices2Array<Index, NumIndices>(dimensions));
} }
#ifndef EIGEN_EMULATE_CXX11_META_H
template <typename std::ptrdiff_t... Indices> template <typename std::ptrdiff_t... Indices>
EIGEN_DEVICE_FUNC void resize(const Sizes<Indices...>& dimensions) { EIGEN_DEVICE_FUNC void resize(const Sizes<Indices...>& dimensions) {
array<Index, NumIndices> dims; array<Index, NumIndices> dims;
@ -356,16 +350,6 @@ class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_, IndexTyp
} }
resize(dims); resize(dims);
} }
#else
template <std::size_t V1, std::size_t V2, std::size_t V3, std::size_t V4, std::size_t V5>
EIGEN_DEVICE_FUNC void resize(const Sizes<V1, V2, V3, V4, V5>& dimensions) {
array<Index, NumIndices> dims;
for (int i = 0; i < NumIndices; ++i) {
dims[i] = static_cast<Index>(dimensions[i]);
}
resize(dims);
}
#endif
#ifdef EIGEN_TENSOR_PLUGIN #ifdef EIGEN_TENSOR_PLUGIN
#include EIGEN_TENSOR_PLUGIN #include EIGEN_TENSOR_PLUGIN

View File

@ -55,12 +55,10 @@ template <>
struct is_input_scalar<Sizes<>> { struct is_input_scalar<Sizes<>> {
static const bool value = true; static const bool value = true;
}; };
#ifndef EIGEN_EMULATE_CXX11_META_H
template <typename std::ptrdiff_t... Indices> template <typename std::ptrdiff_t... Indices>
struct is_input_scalar<Sizes<Indices...>> { struct is_input_scalar<Sizes<Indices...>> {
static const bool value = (Sizes<Indices...>::total_size == 1); static constexpr bool value = (Sizes<Indices...>::total_size == 1);
}; };
#endif
} // end namespace internal } // end namespace internal

View File

@ -81,7 +81,6 @@ struct fixed_size_tensor_index_extraction_helper<Index, 0> {
} // end namespace internal } // end namespace internal
// Fixed size // Fixed size
#ifndef EIGEN_EMULATE_CXX11_META_H
template <typename std::ptrdiff_t... Indices> template <typename std::ptrdiff_t... Indices>
struct Sizes { struct Sizes {
typedef internal::numeric_list<std::ptrdiff_t, Indices...> Base; typedef internal::numeric_list<std::ptrdiff_t, Indices...> Base;
@ -133,87 +132,6 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_prod(const Sizes<Indi
} }
} // namespace internal } // namespace internal
#else
template <std::ptrdiff_t n>
struct non_zero_size {
typedef internal::type2val<std::ptrdiff_t, n> type;
};
template <>
struct non_zero_size<0> {
typedef internal::null_type type;
};
template <std::ptrdiff_t V1 = 0, std::ptrdiff_t V2 = 0, std::ptrdiff_t V3 = 0, std::ptrdiff_t V4 = 0,
std::ptrdiff_t V5 = 0>
struct Sizes {
typedef typename internal::make_type_list<typename non_zero_size<V1>::type, typename non_zero_size<V2>::type,
typename non_zero_size<V3>::type, typename non_zero_size<V4>::type,
typename non_zero_size<V5>::type>::type Base;
static const std::ptrdiff_t count = Base::count;
static const std::ptrdiff_t total_size = internal::arg_prod<Base>::value;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ptrdiff_t rank() const { return count; }
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ptrdiff_t TotalSize() { return internal::arg_prod<Base>::value; }
Sizes() {}
template <typename DenseIndex>
explicit Sizes(const array<DenseIndex, Base::count>& /*indices*/) {
// todo: add assertion
}
template <typename T>
Sizes& operator=(const T& /*other*/) {
// add assertion failure if the size of other is different
return *this;
}
template <typename... DenseIndex>
Sizes(DenseIndex... /*indices*/) {}
explicit Sizes(std::initializer_list<std::ptrdiff_t>) {
// todo: add assertion
}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index operator[](const Index index) const {
switch (index) {
case 0:
return internal::get<0, Base>::value;
case 1:
return internal::get<1, Base>::value;
case 2:
return internal::get<2, Base>::value;
case 3:
return internal::get<3, Base>::value;
case 4:
return internal::get<4, Base>::value;
default:
eigen_assert(false && "index overflow");
return static_cast<Index>(-1);
}
}
template <typename DenseIndex>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ptrdiff_t IndexOfColMajor(const array<DenseIndex, Base::count>& indices) const {
return internal::fixed_size_tensor_index_linearization_helper<DenseIndex, Base::count, Base::count, false>::run(
indices, *reinterpret_cast<const Base*>(this));
}
template <typename DenseIndex>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ptrdiff_t IndexOfRowMajor(const array<DenseIndex, Base::count>& indices) const {
return internal::fixed_size_tensor_index_linearization_helper<DenseIndex, Base::count, Base::count, true>::run(
indices, *reinterpret_cast<const Base*>(this));
}
};
namespace internal {
template <std::ptrdiff_t V1, std::ptrdiff_t V2, std::ptrdiff_t V3, std::ptrdiff_t V4, std::ptrdiff_t V5>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_prod(const Sizes<V1, V2, V3, V4, V5>&) {
return Sizes<V1, V2, V3, V4, V5>::total_size;
}
} // namespace internal
#endif
// Boilerplate // Boilerplate
namespace internal { namespace internal {
template <typename Index, std::ptrdiff_t NumIndices, std::ptrdiff_t n, bool RowMajor> template <typename Index, std::ptrdiff_t NumIndices, std::ptrdiff_t n, bool RowMajor>
@ -289,21 +207,12 @@ struct DSizes : array<DenseIndex, NumDims> {
} }
} }
#ifndef EIGEN_EMULATE_CXX11_META_H
template <typename std::ptrdiff_t... Indices> template <typename std::ptrdiff_t... Indices>
EIGEN_DEVICE_FUNC DSizes(const Sizes<Indices...>& a) { EIGEN_DEVICE_FUNC DSizes(const Sizes<Indices...>& a) {
for (int i = 0; i < NumDims; ++i) { for (int i = 0; i < NumDims; ++i) {
(*this)[i] = a[i]; (*this)[i] = a[i];
} }
} }
#else
template <std::ptrdiff_t V1, std::ptrdiff_t V2, std::ptrdiff_t V3, std::ptrdiff_t V4, std::ptrdiff_t V5>
EIGEN_DEVICE_FUNC DSizes(const Sizes<V1, V2, V3, V4, V5>& a) {
for (int i = 0; i < NumDims; ++i) {
(*this)[i] = a[i];
}
}
#endif
template <typename... IndexTypes> template <typename... IndexTypes>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit DSizes(DenseIndex firstDimension, DenseIndex secondDimension, EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit DSizes(DenseIndex firstDimension, DenseIndex secondDimension,
@ -374,7 +283,6 @@ template <typename DenseIndex, int NumDims>
struct array_size<DSizes<DenseIndex, NumDims> > { struct array_size<DSizes<DenseIndex, NumDims> > {
static const ptrdiff_t value = NumDims; static const ptrdiff_t value = NumDims;
}; };
#ifndef EIGEN_EMULATE_CXX11_META_H
template <typename std::ptrdiff_t... Indices> template <typename std::ptrdiff_t... Indices>
struct array_size<const Sizes<Indices...> > { struct array_size<const Sizes<Indices...> > {
static const std::ptrdiff_t value = Sizes<Indices...>::count; static const std::ptrdiff_t value = Sizes<Indices...>::count;
@ -392,22 +300,6 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_get(const Sizes<>&) {
eigen_assert(false && "should never be called"); eigen_assert(false && "should never be called");
return -1; return -1;
} }
#else
template <std::ptrdiff_t V1, std::ptrdiff_t V2, std::ptrdiff_t V3, std::ptrdiff_t V4, std::ptrdiff_t V5>
struct array_size<const Sizes<V1, V2, V3, V4, V5> > {
static const ptrdiff_t value = Sizes<V1, V2, V3, V4, V5>::count;
};
template <std::ptrdiff_t V1, std::ptrdiff_t V2, std::ptrdiff_t V3, std::ptrdiff_t V4, std::ptrdiff_t V5>
struct array_size<Sizes<V1, V2, V3, V4, V5> > {
static const ptrdiff_t value = Sizes<V1, V2, V3, V4, V5>::count;
};
template <std::ptrdiff_t n, std::ptrdiff_t V1, std::ptrdiff_t V2, std::ptrdiff_t V3, std::ptrdiff_t V4,
std::ptrdiff_t V5>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_get(const Sizes<V1, V2, V3, V4, V5>&) {
return get<n, typename Sizes<V1, V2, V3, V4, V5>::Base>::value;
}
#endif
template <typename Dims1, typename Dims2, ptrdiff_t n, ptrdiff_t m> template <typename Dims1, typename Dims2, ptrdiff_t n, ptrdiff_t m>
struct sizes_match_below_dim { struct sizes_match_below_dim {

View File

@ -37,7 +37,7 @@ namespace Eigen {
template <Index n> template <Index n>
struct type2index { struct type2index {
static const Index value = n; static constexpr Index value = n;
EIGEN_DEVICE_FUNC constexpr operator Index() const { return n; } EIGEN_DEVICE_FUNC constexpr operator Index() const { return n; }
EIGEN_DEVICE_FUNC void set(Index val) { eigen_assert(val == n); } EIGEN_DEVICE_FUNC void set(Index val) { eigen_assert(val == n); }
}; };
@ -46,8 +46,8 @@ struct type2index {
// such as IndexPairList<type2indexpair<1,2>, type2indexpair<3,4>>(). // such as IndexPairList<type2indexpair<1,2>, type2indexpair<3,4>>().
template <Index f, Index s> template <Index f, Index s>
struct type2indexpair { struct type2indexpair {
static const Index first = f; static constexpr Index first = f;
static const Index second = s; static constexpr Index second = s;
constexpr EIGEN_DEVICE_FUNC operator IndexPair<Index>() const { return IndexPair<Index>(f, s); } constexpr EIGEN_DEVICE_FUNC operator IndexPair<Index>() const { return IndexPair<Index>(f, s); }
@ -134,7 +134,7 @@ struct IndexTuple<T, O...> {
EIGEN_DEVICE_FUNC constexpr IndexTuple() : head(), others() {} EIGEN_DEVICE_FUNC constexpr IndexTuple() : head(), others() {}
EIGEN_DEVICE_FUNC constexpr IndexTuple(const T& v, const O... o) : head(v), others(o...) {} EIGEN_DEVICE_FUNC constexpr IndexTuple(const T& v, const O... o) : head(v), others(o...) {}
constexpr static int count = 1 + sizeof...(O); static constexpr int count = 1 + sizeof...(O);
T head; T head;
IndexTuple<O...> others; IndexTuple<O...> others;
typedef T Head; typedef T Head;
@ -194,11 +194,11 @@ EIGEN_DEVICE_FUNC constexpr const typename IndexTupleExtractor<N, T, O...>::ValT
} }
template <typename T, typename... O> template <typename T, typename... O>
struct array_size<IndexTuple<T, O...>> { struct array_size<IndexTuple<T, O...>> {
static const size_t value = IndexTuple<T, O...>::count; static constexpr size_t value = IndexTuple<T, O...>::count;
}; };
template <typename T, typename... O> template <typename T, typename... O>
struct array_size<const IndexTuple<T, O...>> { struct array_size<const IndexTuple<T, O...>> {
static const size_t value = IndexTuple<T, O...>::count; static constexpr size_t value = IndexTuple<T, O...>::count;
}; };
template <Index Idx, typename ValueT> template <Index Idx, typename ValueT>

View File

@ -47,13 +47,7 @@ static void test_static_dimension_failure() {
// This can be worked around in this case. // This can be worked around in this case.
Tensor<int, 3, DataLayout> concatenation = left.reshape(Tensor<int, 3>::Dimensions(2, 3, 1)).concatenate(right, 0); Tensor<int, 3, DataLayout> concatenation = left.reshape(Tensor<int, 3>::Dimensions(2, 3, 1)).concatenate(right, 0);
Tensor<int, 2, DataLayout> alternative = left Tensor<int, 2, DataLayout> alternative = left.concatenate(right.reshape(Tensor<int, 2>::Dimensions(2, 3)), 0);
// Clang compiler break with {{{}}} with an ambiguous error on copy
// constructor the variadic DSize constructor added for #ifndef
// EIGEN_EMULATE_CXX11_META_H. Solution: either the code should change to
// Tensor<int, 2>::Dimensions{{2, 3}}
// or Tensor<int, 2>::Dimensions{Tensor<int, 2>::Dimensions{{2, 3}}}
.concatenate(right.reshape(Tensor<int, 2>::Dimensions(2, 3)), 0);
} }
template <int DataLayout> template <int DataLayout>