Allow symbols to be used in compile-time expressions.

This commit is contained in:
Antonio Sánchez 2024-03-28 18:43:50 +00:00
parent d26e19714f
commit 77833f9320
10 changed files with 902 additions and 364 deletions

View File

@ -61,26 +61,28 @@ seqN(FirstType first, SizeType size, IncrType incr);
template <typename FirstType, typename SizeType, typename IncrType>
class ArithmeticSequence {
public:
ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {}
ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {}
constexpr ArithmeticSequence() = default;
constexpr ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {}
constexpr ArithmeticSequence(FirstType first, SizeType size, IncrType incr)
: m_first(first), m_size(size), m_incr(incr) {}
enum {
SizeAtCompileTime = internal::get_fixed_value<SizeType>::value,
// SizeAtCompileTime = internal::get_fixed_value<SizeType>::value,
IncrAtCompileTime = internal::get_fixed_value<IncrType, DynamicIndex>::value
};
/** \returns the size, i.e., number of elements, of the sequence */
Index size() const { return m_size; }
constexpr Index size() const { return m_size; }
/** \returns the first element \f$ a_0 \f$ in the sequence */
Index first() const { return m_first; }
constexpr Index first() const { return m_first; }
/** \returns the value \f$ a_i \f$ at index \a i in the sequence. */
Index operator[](Index i) const { return m_first + i * m_incr; }
constexpr Index operator[](Index i) const { return m_first + i * m_incr; }
const FirstType& firstObject() const { return m_first; }
const SizeType& sizeObject() const { return m_size; }
const IncrType& incrObject() const { return m_incr; }
constexpr const FirstType& firstObject() const { return m_first; }
constexpr const SizeType& sizeObject() const { return m_size; }
constexpr const IncrType& incrObject() const { return m_incr; }
protected:
FirstType m_first;
@ -88,7 +90,7 @@ class ArithmeticSequence {
IncrType m_incr;
public:
auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) {
constexpr auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) {
return seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr);
}
};
@ -201,38 +203,6 @@ auto lastN(SizeType size) -> decltype(seqN(Eigen::placeholders::last + fix<1>()
} // namespace placeholders
namespace internal {
// Convert a symbolic span into a usable one (i.e., remove last/end "keywords")
template <typename T>
struct make_size_type {
typedef std::conditional_t<symbolic::is_symbolic<T>::value, Index, T> type;
};
template <typename FirstType, typename SizeType, typename IncrType, int XprSize>
struct IndexedViewCompatibleType<ArithmeticSequence<FirstType, SizeType, IncrType>, XprSize> {
typedef ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType> type;
};
template <typename FirstType, typename SizeType, typename IncrType>
ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType> makeIndexedViewCompatible(
const ArithmeticSequence<FirstType, SizeType, IncrType>& ids, Index size, SpecializedType) {
return ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType>(
eval_expr_given_size(ids.firstObject(), size), eval_expr_given_size(ids.sizeObject(), size), ids.incrObject());
}
template <typename FirstType, typename SizeType, typename IncrType>
struct get_compile_time_incr<ArithmeticSequence<FirstType, SizeType, IncrType> > {
enum { value = get_fixed_value<IncrType, DynamicIndex>::value };
};
template <typename FirstType, typename SizeType, typename IncrType>
constexpr Index get_runtime_incr(const ArithmeticSequence<FirstType, SizeType, IncrType>& x) EIGEN_NOEXCEPT {
return static_cast<Index>(x.incrObject());
}
} // end namespace internal
/** \namespace Eigen::indexing
* \ingroup Core_Module
*

View File

@ -20,8 +20,8 @@ namespace internal {
template <typename XprType, typename RowIndices, typename ColIndices>
struct traits<IndexedView<XprType, RowIndices, ColIndices>> : traits<XprType> {
enum {
RowsAtCompileTime = int(array_size<RowIndices>::value),
ColsAtCompileTime = int(array_size<ColIndices>::value),
RowsAtCompileTime = int(IndexedViewHelper<RowIndices>::SizeAtCompileTime),
ColsAtCompileTime = int(IndexedViewHelper<ColIndices>::SizeAtCompileTime),
MaxRowsAtCompileTime = RowsAtCompileTime,
MaxColsAtCompileTime = ColsAtCompileTime,
@ -30,8 +30,8 @@ struct traits<IndexedView<XprType, RowIndices, ColIndices>> : traits<XprType> {
: (MaxColsAtCompileTime == 1 && MaxRowsAtCompileTime != 1) ? 0
: XprTypeIsRowMajor,
RowIncr = int(get_compile_time_incr<RowIndices>::value),
ColIncr = int(get_compile_time_incr<ColIndices>::value),
RowIncr = int(IndexedViewHelper<RowIndices>::IncrAtCompileTime),
ColIncr = int(IndexedViewHelper<ColIndices>::IncrAtCompileTime),
InnerIncr = IsRowMajor ? ColIncr : RowIncr,
OuterIncr = IsRowMajor ? RowIncr : ColIncr,
@ -47,24 +47,23 @@ struct traits<IndexedView<XprType, RowIndices, ColIndices>> : traits<XprType> {
is_same<AllRange<InnerSize>, std::conditional_t<XprTypeIsRowMajor, ColIndices, RowIndices>>::value,
InnerStrideAtCompileTime =
InnerIncr < 0 || InnerIncr == DynamicIndex || XprInnerStride == Dynamic || InnerIncr == UndefinedIncr
InnerIncr < 0 || InnerIncr == DynamicIndex || XprInnerStride == Dynamic || InnerIncr == Undefined
? Dynamic
: XprInnerStride * InnerIncr,
OuterStrideAtCompileTime =
OuterIncr < 0 || OuterIncr == DynamicIndex || XprOuterstride == Dynamic || OuterIncr == UndefinedIncr
OuterIncr < 0 || OuterIncr == DynamicIndex || XprOuterstride == Dynamic || OuterIncr == Undefined
? Dynamic
: XprOuterstride * OuterIncr,
ReturnAsScalar = is_same<RowIndices, SingleRange>::value && is_same<ColIndices, SingleRange>::value,
ReturnAsScalar = is_single_range<RowIndices>::value && is_single_range<ColIndices>::value,
ReturnAsBlock = (!ReturnAsScalar) && IsBlockAlike,
ReturnAsIndexedView = (!ReturnAsScalar) && (!ReturnAsBlock),
// FIXME we deal with compile-time strides if and only if we have DirectAccessBit flag,
// but this is too strict regarding negative strides...
DirectAccessMask =
(int(InnerIncr) != UndefinedIncr && int(OuterIncr) != UndefinedIncr && InnerIncr >= 0 && OuterIncr >= 0)
? DirectAccessBit
: 0,
DirectAccessMask = (int(InnerIncr) != Undefined && int(OuterIncr) != Undefined && InnerIncr >= 0 && OuterIncr >= 0)
? DirectAccessBit
: 0,
FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0,
FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0,
FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0,
@ -153,10 +152,10 @@ class IndexedViewImpl : public internal::generic_xpr_base<IndexedView<XprType, R
: m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) {}
/** \returns number of rows */
Index rows() const { return internal::index_list_size(m_rowIndices); }
Index rows() const { return IndexedViewHelper<RowIndices>::size(m_rowIndices); }
/** \returns number of columns */
Index cols() const { return internal::index_list_size(m_colIndices); }
Index cols() const { return IndexedViewHelper<ColIndices>::size(m_colIndices); }
/** \returns the nested expression */
const internal::remove_all_t<XprType>& nestedExpression() const { return m_xpr; }
@ -198,16 +197,16 @@ class IndexedViewImpl<XprType, RowIndices, ColIndices, StorageKind, true>
IndexedViewImpl(XprType& xpr, const T0& rowIndices, const T1& colIndices) : Base(xpr, rowIndices, colIndices) {}
Index rowIncrement() const {
if (traits<Derived>::RowIncr != DynamicIndex && traits<Derived>::RowIncr != UndefinedIncr) {
if (traits<Derived>::RowIncr != DynamicIndex && traits<Derived>::RowIncr != Undefined) {
return traits<Derived>::RowIncr;
}
return get_runtime_incr(this->rowIndices());
return IndexedViewHelper<RowIndices>::incr(this->rowIndices());
}
Index colIncrement() const {
if (traits<Derived>::ColIncr != DynamicIndex && traits<Derived>::ColIncr != UndefinedIncr) {
if (traits<Derived>::ColIncr != DynamicIndex && traits<Derived>::ColIncr != Undefined) {
return traits<Derived>::ColIncr;
}
return get_runtime_incr(this->colIndices());
return IndexedViewHelper<ColIndices>::incr(this->colIndices());
}
Index innerIncrement() const { return traits<Derived>::IsRowMajor ? colIncrement() : rowIncrement(); }

View File

@ -29,9 +29,9 @@ const int Dynamic = -1;
*/
const int DynamicIndex = 0xffffff;
/** This value means that the increment to go from one value to another in a sequence is not constant for each step.
/** This value means that the requested value is not defined.
*/
const int UndefinedIncr = 0xfffffe;
const int Undefined = 0xfffffe;
/** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>().
* The value Infinity there means the L-infinity norm.

View File

@ -91,6 +91,8 @@ template <typename XprType, typename RowIndices, typename ColIndices>
class IndexedView;
template <typename XprType, int Rows = Dynamic, int Cols = Dynamic, int Order = 0>
class Reshaped;
template <typename FirstType, typename SizeType, typename IncrType>
class ArithmeticSequence;
template <typename MatrixType, int Size = Dynamic>
class VectorBlock;

View File

@ -17,6 +17,9 @@ namespace Eigen {
namespace internal {
struct symbolic_last_tag {};
struct all_t {};
} // namespace internal
namespace placeholders {
@ -42,131 +45,7 @@ typedef symbolic::SymbolExpr<internal::symbolic_last_tag> last_t;
*
* \sa end
*/
static const last_t last;
} // namespace placeholders
namespace internal {
// Replace symbolic last/end "keywords" by their true runtime value
inline Index eval_expr_given_size(Index x, Index /* size */) { return x; }
template <int N>
FixedInt<N> eval_expr_given_size(FixedInt<N> x, Index /*size*/) {
return x;
}
template <typename Derived>
Index eval_expr_given_size(const symbolic::BaseExpr<Derived>& x, Index size) {
return x.derived().eval(Eigen::placeholders::last = size - 1);
}
// Extract increment/step at compile time
template <typename T, typename EnableIf = void>
struct get_compile_time_incr {
enum { value = UndefinedIncr };
};
template <typename T>
constexpr Index get_runtime_incr(const T&) EIGEN_NOEXCEPT {
return Index(1);
}
// Analogue of std::get<0>(x), but tailored for our needs.
template <typename T>
EIGEN_CONSTEXPR Index first(const T& x) EIGEN_NOEXCEPT {
return x.first();
}
// IndexedViewCompatibleType/makeIndexedViewCompatible turn an arbitrary object of type T into something usable by
// MatrixSlice The generic implementation is a no-op
template <typename T, int XprSize, typename EnableIf = void>
struct IndexedViewCompatibleType {
typedef T type;
};
template <typename T, typename Q>
const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) {
return x;
}
//--------------------------------------------------------------------------------
// Handling of a single Index
//--------------------------------------------------------------------------------
struct SingleRange {
enum { SizeAtCompileTime = 1 };
SingleRange(Index val) : m_value(val) {}
Index operator[](Index) const { return m_value; }
static EIGEN_CONSTEXPR Index size() EIGEN_NOEXCEPT { return 1; }
Index first() const EIGEN_NOEXCEPT { return m_value; }
Index m_value;
};
template <>
struct get_compile_time_incr<SingleRange> {
enum { value = 1 }; // 1 or 0 ??
};
// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operator[](int)
// methods)
template <typename T, int XprSize>
struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<internal::is_integral<T>::value>> {
// Here we could simply use Array, but maybe it's less work for the compiler to use
// a simpler wrapper as SingleRange
// typedef Eigen::Array<Index,1,1> type;
typedef SingleRange type;
};
template <typename T, int XprSize>
struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<symbolic::is_symbolic<T>::value>> {
typedef SingleRange type;
};
template <typename T>
std::enable_if_t<symbolic::is_symbolic<T>::value, SingleRange> makeIndexedViewCompatible(const T& id, Index size,
SpecializedType) {
return eval_expr_given_size(id, size);
}
//--------------------------------------------------------------------------------
// Handling of all
//--------------------------------------------------------------------------------
struct all_t {
all_t() {}
};
// Convert a symbolic 'all' into a usable range type
template <int XprSize>
struct AllRange {
enum { SizeAtCompileTime = XprSize };
AllRange(Index size = XprSize) : m_size(size) {}
EIGEN_CONSTEXPR Index operator[](Index i) const EIGEN_NOEXCEPT { return i; }
EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_size.value(); }
EIGEN_CONSTEXPR Index first() const EIGEN_NOEXCEPT { return 0; }
variable_if_dynamic<Index, XprSize> m_size;
};
template <int XprSize>
struct IndexedViewCompatibleType<all_t, XprSize> {
typedef AllRange<XprSize> type;
};
template <typename XprSizeType>
inline AllRange<get_fixed_value<XprSizeType>::value> makeIndexedViewCompatible(all_t, XprSizeType size,
SpecializedType) {
return AllRange<get_fixed_value<XprSizeType>::value>(size);
}
template <int Size>
struct get_compile_time_incr<AllRange<Size>> {
enum { value = 1 };
};
} // end namespace internal
namespace placeholders {
static constexpr const last_t last;
typedef symbolic::AddExpr<symbolic::SymbolExpr<internal::symbolic_last_tag>,
symbolic::ValueExpr<Eigen::internal::FixedInt<1>>>
@ -186,28 +65,251 @@ typedef Eigen::internal::all_t all_t;
* \sa last
*/
#ifdef EIGEN_PARSED_BY_DOXYGEN
static const auto lastp1 = last + fix<1>;
static constexpr auto lastp1 = last + fix<1>;
#else
// Using a FixedExpr<1> expression is important here to make sure the compiler
// can fully optimize the computation starting indices with zero overhead.
static const lastp1_t lastp1(last + fix<1>());
static constexpr lastp1_t lastp1(last + fix<1>());
#endif
/** \var end
* \ingroup Core_Module
* \sa lastp1
*/
static const lastp1_t end = lastp1;
static constexpr lastp1_t end = lastp1;
/** \var all
* \ingroup Core_Module
* Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or
* columns
*/
static const Eigen::internal::all_t all;
static constexpr Eigen::internal::all_t all;
} // namespace placeholders
namespace internal {
// Evaluate a symbolic expression or constant given the "size" of an object, allowing
// any symbols like `last` to be evaluated. The default here assumes a dynamic constant.
template <typename Expr, int SizeAtCompileTime, typename EnableIf = void>
struct SymbolicExpressionEvaluator {
static constexpr Index ValueAtCompileTime = Undefined;
static Index eval(const Expr& expr, Index /*size*/) { return static_cast<Index>(expr); }
};
// Symbolic expression with size known at compile-time.
template <typename Expr, int SizeAtCompileTime>
struct SymbolicExpressionEvaluator<Expr, SizeAtCompileTime, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> {
static constexpr Index ValueAtCompileTime =
Expr::Derived::eval_at_compile_time(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>);
static Index eval(const Expr& expr, Index /*size*/) {
return expr.eval(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>);
}
};
// Symbolic expression with dynamic size.
template <typename Expr>
struct SymbolicExpressionEvaluator<Expr, Dynamic, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> {
static constexpr Index ValueAtCompileTime = Undefined;
static Index eval(const Expr& expr, Index size) { return expr.eval(Eigen::placeholders::last = size - 1); }
};
// Fixed int.
template <int N, int SizeAtCompileTime>
struct SymbolicExpressionEvaluator<FixedInt<N>, SizeAtCompileTime, void> {
static constexpr Index ValueAtCompileTime = static_cast<Index>(N);
static Index eval(const FixedInt<N>& /*expr*/, Index /*size*/) { return ValueAtCompileTime; }
};
//--------------------------------------------------------------------------------
// Handling of generic indices (e.g. array)
//--------------------------------------------------------------------------------
// Potentially wrap indices in a type that is better-suited for IndexedView evaluation.
template <typename Indices, int NestedSizeAtCompileTime, typename EnableIf = void>
struct IndexedViewHelperIndicesWrapper {
using type = Indices;
static const type& CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices; }
};
// Extract compile-time and runtime first, size, increments.
template <typename Indices, typename EnableIf = void>
struct IndexedViewHelper {
static constexpr Index FirstAtCompileTime = Undefined;
static constexpr Index SizeAtCompileTime = array_size<Indices>::value;
static constexpr Index IncrAtCompileTime = Undefined;
static constexpr Index first(const Indices& indices) { return static_cast<Index>(indices[0]); }
static constexpr Index size(const Indices& indices) { return index_list_size(indices); }
static constexpr Index incr(const Indices& /*indices*/) { return Undefined; }
};
//--------------------------------------------------------------------------------
// Handling of ArithmeticSequence
//--------------------------------------------------------------------------------
template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_>
class ArithmeticSequenceRange {
public:
static constexpr Index FirstAtCompileTime = FirstAtCompileTime_;
static constexpr Index SizeAtCompileTime = SizeAtCompileTime_;
static constexpr Index IncrAtCompileTime = IncrAtCompileTime_;
constexpr ArithmeticSequenceRange(Index first, Index size, Index incr) : first_{first}, size_{size}, incr_{incr} {}
constexpr Index operator[](Index i) const { return first() + i * incr(); }
constexpr Index first() const noexcept { return first_.value(); }
constexpr Index size() const noexcept { return size_.value(); }
constexpr Index incr() const noexcept { return incr_.value(); }
private:
variable_if_dynamicindex<Index, int(FirstAtCompileTime)> first_;
variable_if_dynamic<Index, int(SizeAtCompileTime)> size_;
variable_if_dynamicindex<Index, int(IncrAtCompileTime)> incr_;
};
template <typename FirstType, typename SizeType, typename IncrType, int NestedSizeAtCompileTime>
struct IndexedViewHelperIndicesWrapper<ArithmeticSequence<FirstType, SizeType, IncrType>, NestedSizeAtCompileTime,
void> {
static constexpr Index EvalFirstAtCompileTime =
SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::ValueAtCompileTime;
static constexpr Index EvalSizeAtCompileTime =
SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::ValueAtCompileTime;
static constexpr Index EvalIncrAtCompileTime =
SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::ValueAtCompileTime;
static constexpr Index FirstAtCompileTime =
(int(EvalFirstAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalFirstAtCompileTime;
static constexpr Index SizeAtCompileTime =
(int(EvalSizeAtCompileTime) == Undefined) ? Index(Dynamic) : EvalSizeAtCompileTime;
static constexpr Index IncrAtCompileTime =
(int(EvalIncrAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalIncrAtCompileTime;
using Indices = ArithmeticSequence<FirstType, SizeType, IncrType>;
using type = ArithmeticSequenceRange<FirstAtCompileTime, SizeAtCompileTime, IncrAtCompileTime>;
static type CreateIndexSequence(const Indices& indices, Index nested_size) {
Index first =
SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::eval(indices.firstObject(), nested_size);
Index size =
SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::eval(indices.sizeObject(), nested_size);
Index incr =
SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::eval(indices.incrObject(), nested_size);
return type(first, size, incr);
}
};
template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_>
struct IndexedViewHelper<ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>, void> {
public:
using Indices = ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>;
static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
static Index first(const Indices& indices) { return indices.first(); }
static Index size(const Indices& indices) { return indices.size(); }
static Index incr(const Indices& indices) { return indices.incr(); }
};
//--------------------------------------------------------------------------------
// Handling of a single index.
//--------------------------------------------------------------------------------
template <Index ValueAtCompileTime>
class SingleRange {
public:
static constexpr Index FirstAtCompileTime = ValueAtCompileTime;
static constexpr Index SizeAtCompileTime = Index(1);
static constexpr Index IncrAtCompileTime = Index(1); // Needs to be 1 to be treated as block-like.
constexpr SingleRange(Index v) noexcept : value_(v) {}
constexpr Index operator[](Index) const noexcept { return first(); }
constexpr Index first() const noexcept { return value_.value(); }
constexpr Index size() const noexcept { return SizeAtCompileTime; }
constexpr Index incr() const noexcept { return IncrAtCompileTime; }
private:
variable_if_dynamicindex<Index, int(ValueAtCompileTime)> value_;
};
template <typename T>
struct is_single_range : public std::false_type {};
template <Index ValueAtCompileTime>
struct is_single_range<SingleRange<ValueAtCompileTime>> : public std::true_type {};
template <typename SingleIndex, int NestedSizeAtCompileTime>
struct IndexedViewHelperIndicesWrapper<
SingleIndex, NestedSizeAtCompileTime,
std::enable_if_t<std::is_integral<SingleIndex>::value || symbolic::is_symbolic<SingleIndex>::value>> {
static constexpr Index EvalValueAtCompileTime =
SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::ValueAtCompileTime;
static constexpr Index ValueAtCompileTime =
(int(EvalValueAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalValueAtCompileTime;
using type = SingleRange<ValueAtCompileTime>;
static type CreateIndexSequence(const SingleIndex& index, Index nested_size) {
return type(SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::eval(index, nested_size));
}
};
template <int N, int NestedSizeAtCompileTime>
struct IndexedViewHelperIndicesWrapper<FixedInt<N>, NestedSizeAtCompileTime, void> {
using type = SingleRange<Index(N)>;
static type CreateIndexSequence(const FixedInt<N>& /*index*/) { return type(Index(N)); }
};
template <Index ValueAtCompileTime>
struct IndexedViewHelper<SingleRange<ValueAtCompileTime>, void> {
using Indices = SingleRange<ValueAtCompileTime>;
static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
static constexpr Index first(const Indices& indices) { return indices.first(); }
static constexpr Index size(const Indices& /*indices*/) { return SizeAtCompileTime; }
static constexpr Index incr(const Indices& /*indices*/) { return IncrAtCompileTime; }
};
//--------------------------------------------------------------------------------
// Handling of all
//--------------------------------------------------------------------------------
// Convert a symbolic 'all' into a usable range type
template <Index SizeAtCompileTime_>
class AllRange {
public:
static constexpr Index FirstAtCompileTime = Index(0);
static constexpr Index SizeAtCompileTime = SizeAtCompileTime_;
static constexpr Index IncrAtCompileTime = Index(1);
constexpr AllRange(Index size) : size_(size) {}
constexpr Index operator[](Index i) const noexcept { return i; }
constexpr Index first() const noexcept { return FirstAtCompileTime; }
constexpr Index size() const noexcept { return size_.value(); }
constexpr Index incr() const noexcept { return IncrAtCompileTime; }
private:
variable_if_dynamic<Index, int(SizeAtCompileTime)> size_;
};
template <int NestedSizeAtCompileTime>
struct IndexedViewHelperIndicesWrapper<all_t, NestedSizeAtCompileTime, void> {
using type = AllRange<Index(NestedSizeAtCompileTime)>;
static type CreateIndexSequence(const all_t& /*indices*/, Index nested_size) { return type(nested_size); }
};
template <Index SizeAtCompileTime_>
struct IndexedViewHelper<AllRange<SizeAtCompileTime_>, void> {
using Indices = AllRange<SizeAtCompileTime_>;
static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
static Index first(const Indices& indices) { return indices.first(); }
static Index size(const Indices& indices) { return indices.size(); }
static Index incr(const Indices& indices) { return indices.incr(); }
};
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_INDEXED_VIEW_HELPER_H

View File

@ -54,65 +54,60 @@ class VariableAndFixedInt;
template <int N>
class FixedInt {
public:
static const int value = N;
EIGEN_CONSTEXPR operator int() const { return value; }
static constexpr int value = N;
constexpr operator int() const { return N; }
EIGEN_CONSTEXPR
FixedInt() = default;
constexpr FixedInt() = default;
constexpr FixedInt(std::integral_constant<int, N>) {}
EIGEN_CONSTEXPR
FixedInt(std::integral_constant<int, N>) {}
EIGEN_CONSTEXPR
FixedInt(VariableAndFixedInt<N> other) {
constexpr FixedInt(VariableAndFixedInt<N> other) {
#ifndef EIGEN_INTERNAL_DEBUGGING
EIGEN_UNUSED_VARIABLE(other);
#endif
eigen_internal_assert(int(other) == N);
}
EIGEN_CONSTEXPR
FixedInt<-N> operator-() const { return FixedInt<-N>(); }
constexpr FixedInt<-N> operator-() const { return FixedInt<-N>(); }
template <int M>
EIGEN_CONSTEXPR FixedInt<N + M> operator+(FixedInt<M>) const {
constexpr FixedInt<N + M> operator+(FixedInt<M>) const {
return FixedInt<N + M>();
}
template <int M>
EIGEN_CONSTEXPR FixedInt<N - M> operator-(FixedInt<M>) const {
constexpr FixedInt<N - M> operator-(FixedInt<M>) const {
return FixedInt<N - M>();
}
template <int M>
EIGEN_CONSTEXPR FixedInt<N * M> operator*(FixedInt<M>) const {
constexpr FixedInt<N * M> operator*(FixedInt<M>) const {
return FixedInt<N * M>();
}
template <int M>
EIGEN_CONSTEXPR FixedInt<N / M> operator/(FixedInt<M>) const {
constexpr FixedInt<N / M> operator/(FixedInt<M>) const {
return FixedInt<N / M>();
}
template <int M>
EIGEN_CONSTEXPR FixedInt<N % M> operator%(FixedInt<M>) const {
constexpr FixedInt<N % M> operator%(FixedInt<M>) const {
return FixedInt<N % M>();
}
template <int M>
EIGEN_CONSTEXPR FixedInt<N | M> operator|(FixedInt<M>) const {
constexpr FixedInt<N | M> operator|(FixedInt<M>) const {
return FixedInt<N | M>();
}
template <int M>
EIGEN_CONSTEXPR FixedInt<N & M> operator&(FixedInt<M>) const {
constexpr FixedInt<N & M> operator&(FixedInt<M>) const {
return FixedInt<N & M>();
}
// Needed in C++14 to allow fix<N>():
EIGEN_CONSTEXPR FixedInt operator()() const { return *this; }
constexpr FixedInt operator()() const { return *this; }
VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
constexpr VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
};
/** \internal

View File

@ -44,6 +44,8 @@ namespace symbolic {
template <typename Tag>
class Symbol;
template <typename Tag, typename Type>
class SymbolValue;
template <typename Arg0>
class NegateExpr;
template <typename Arg1, typename Arg2>
@ -52,136 +54,123 @@ template <typename Arg1, typename Arg2>
class ProductExpr;
template <typename Arg1, typename Arg2>
class QuotientExpr;
// A simple wrapper around an integral value to provide the eval method.
// We could also use a free-function symbolic_eval...
template <typename IndexType = Index>
class ValueExpr {
public:
ValueExpr(IndexType val) : m_value(val) {}
template <typename T>
IndexType eval_impl(const T&) const {
return m_value;
}
protected:
IndexType m_value;
};
// Specialization for compile-time value,
// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
template <int N>
class ValueExpr<internal::FixedInt<N> > {
public:
ValueExpr() {}
template <typename T>
EIGEN_CONSTEXPR Index eval_impl(const T&) const {
return N;
}
};
class ValueExpr;
/** \class BaseExpr
* \ingroup Core_Module
* Common base class of any symbolic expressions
*/
template <typename Derived>
template <typename Derived_>
class BaseExpr {
public:
const Derived& derived() const { return *static_cast<const Derived*>(this); }
using Derived = Derived_;
constexpr const Derived& derived() const { return *static_cast<const Derived*>(this); }
/** Evaluate the expression given the \a values of the symbols.
*
* \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue
* as constructed by SymbolExpr::operator= operator.
* \param values defines the values of the symbols, as constructed by SymbolExpr::operator= operator.
*
*/
template <typename T>
Index eval(const T& values) const {
return derived().eval_impl(values);
template <typename... Tags, typename... Types>
constexpr Index eval(const SymbolValue<Tags, Types>&... values) const {
return derived().eval_impl(values...);
}
template <typename... Types>
Index eval(Types&&... values) const {
return derived().eval_impl(std::make_tuple(values...));
/** Evaluate the expression at compile time given the \a values of the symbols.
*
* If a value is not known at compile-time, returns Eigen::Undefined.
*
*/
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time(const SymbolValue<Tags, Types>&...) {
return Derived::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
}
NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
constexpr NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
AddExpr<Derived, ValueExpr<> > operator+(Index b) const { return AddExpr<Derived, ValueExpr<> >(derived(), b); }
AddExpr<Derived, ValueExpr<> > operator-(Index a) const { return AddExpr<Derived, ValueExpr<> >(derived(), -a); }
ProductExpr<Derived, ValueExpr<> > operator*(Index a) const {
constexpr AddExpr<Derived, ValueExpr<>> operator+(Index b) const {
return AddExpr<Derived, ValueExpr<>>(derived(), b);
}
constexpr AddExpr<Derived, ValueExpr<>> operator-(Index a) const {
return AddExpr<Derived, ValueExpr<>>(derived(), -a);
}
constexpr ProductExpr<Derived, ValueExpr<>> operator*(Index a) const {
return ProductExpr<Derived, ValueExpr<> >(derived(), a);
}
QuotientExpr<Derived, ValueExpr<> > operator/(Index a) const {
constexpr QuotientExpr<Derived, ValueExpr<>> operator/(Index a) const {
return QuotientExpr<Derived, ValueExpr<> >(derived(), a);
}
friend AddExpr<Derived, ValueExpr<> > operator+(Index a, const BaseExpr& b) {
friend constexpr AddExpr<Derived, ValueExpr<>> operator+(Index a, const BaseExpr& b) {
return AddExpr<Derived, ValueExpr<> >(b.derived(), a);
}
friend AddExpr<NegateExpr<Derived>, ValueExpr<> > operator-(Index a, const BaseExpr& b) {
friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<>> operator-(Index a, const BaseExpr& b) {
return AddExpr<NegateExpr<Derived>, ValueExpr<> >(-b.derived(), a);
}
friend ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) {
friend constexpr ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) {
return ProductExpr<ValueExpr<>, Derived>(a, b.derived());
}
friend QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) {
friend constexpr QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) {
return QuotientExpr<ValueExpr<>, Derived>(a, b.derived());
}
template <int N>
AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>) const {
constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>) const {
return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
}
template <int N>
AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > > operator-(internal::FixedInt<N>) const {
constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<-N>>> operator-(internal::FixedInt<N>) const {
return AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > >(derived(), ValueExpr<internal::FixedInt<-N> >());
}
template <int N>
ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator*(internal::FixedInt<N>) const {
constexpr ProductExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator*(internal::FixedInt<N>) const {
return ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
}
template <int N>
QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator/(internal::FixedInt<N>) const {
constexpr QuotientExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator/(internal::FixedInt<N>) const {
return QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
}
template <int N>
friend AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>, const BaseExpr& b) {
friend constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>,
const BaseExpr& b) {
return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(b.derived(), ValueExpr<internal::FixedInt<N> >());
}
template <int N>
friend AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > > operator-(internal::FixedInt<N>,
const BaseExpr& b) {
friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N>>> operator-(internal::FixedInt<N>,
const BaseExpr& b) {
return AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > >(-b.derived(),
ValueExpr<internal::FixedInt<N> >());
}
template <int N>
friend ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator*(internal::FixedInt<N>, const BaseExpr& b) {
friend constexpr ProductExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator*(internal::FixedInt<N>,
const BaseExpr& b) {
return ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived());
}
template <int N>
friend QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator/(internal::FixedInt<N>, const BaseExpr& b) {
friend constexpr QuotientExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator/(internal::FixedInt<N>,
const BaseExpr& b) {
return QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived());
}
template <typename OtherDerived>
AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const {
constexpr AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const {
return AddExpr<Derived, OtherDerived>(derived(), b.derived());
}
template <typename OtherDerived>
AddExpr<Derived, NegateExpr<OtherDerived> > operator-(const BaseExpr<OtherDerived>& b) const {
constexpr AddExpr<Derived, NegateExpr<OtherDerived>> operator-(const BaseExpr<OtherDerived>& b) const {
return AddExpr<Derived, NegateExpr<OtherDerived> >(derived(), -b.derived());
}
template <typename OtherDerived>
ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const {
constexpr ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const {
return ProductExpr<Derived, OtherDerived>(derived(), b.derived());
}
template <typename OtherDerived>
QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const {
constexpr QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const {
return QuotientExpr<Derived, OtherDerived>(derived(), b.derived());
}
};
@ -193,21 +182,137 @@ struct is_symbolic {
enum { value = internal::is_convertible<T, BaseExpr<T> >::value };
};
// A simple wrapper around an integral value to provide the eval method.
// We could also use a free-function symbolic_eval...
template <typename IndexType>
class ValueExpr : BaseExpr<ValueExpr<IndexType>> {
public:
constexpr ValueExpr() = default;
constexpr ValueExpr(IndexType val) : value_(val) {}
template <typename... Tags, typename... Types>
constexpr IndexType eval_impl(const SymbolValue<Tags, Types>&...) const {
return value_;
}
template <typename... Tags, typename... Types>
static constexpr IndexType eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
return IndexType(Undefined);
}
protected:
IndexType value_;
};
// Specialization for compile-time value,
// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
template <int N>
class ValueExpr<internal::FixedInt<N>> : public BaseExpr<ValueExpr<internal::FixedInt<N>>> {
public:
constexpr ValueExpr() = default;
constexpr ValueExpr(internal::FixedInt<N>) {}
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
return Index(N);
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
return Index(N);
}
};
/** Represents the actual value of a symbol identified by its tag
*
* It is the return type of SymbolValue::operator=, and most of the time this is only way it is used.
*/
template <typename Tag, typename Type>
class SymbolValue : public BaseExpr<SymbolValue<Tag, Type>> {};
template <typename Tag>
class SymbolValue {
class SymbolValue<Tag, Index> : public BaseExpr<SymbolValue<Tag, Index>> {
public:
constexpr SymbolValue() = default;
/** Default constructor from the value \a val */
SymbolValue(Index val) : m_value(val) {}
constexpr SymbolValue(Index val) : value_(val) {}
/** \returns the stored value of the symbol */
Index value() const { return m_value; }
constexpr Index value() const { return value_; }
/** \returns the stored value of the symbol at compile time, or Undefined if not known. */
static constexpr Index value_at_compile_time() { return Index(Undefined); }
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
return value();
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
return value_at_compile_time();
}
protected:
Index m_value;
Index value_;
};
template <typename Tag, int N>
class SymbolValue<Tag, internal::FixedInt<N>> : public BaseExpr<SymbolValue<Tag, internal::FixedInt<N>>> {
public:
constexpr SymbolValue() = default;
/** Default constructor from the value \a val */
constexpr SymbolValue(internal::FixedInt<N>){};
/** \returns the stored value of the symbol */
constexpr Index value() const { return static_cast<Index>(N); }
/** \returns the stored value of the symbol at compile time, or Undefined if not known. */
static constexpr Index value_at_compile_time() { return static_cast<Index>(N); }
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
return value();
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
return value_at_compile_time();
}
};
// Find and return a symbol value based on the tag.
template <typename Tag, typename... Types>
struct EvalSymbolValueHelper;
// Empty base case, symbol not found.
template <typename Tag>
struct EvalSymbolValueHelper<Tag> {
static constexpr Index eval_impl() {
eigen_assert(false && "Symbol not found.");
return Index(Undefined);
}
static constexpr Index eval_at_compile_time_impl() { return Index(Undefined); }
};
// We found a symbol value matching the provided Tag!
template <typename Tag, typename Type, typename... OtherTypes>
struct EvalSymbolValueHelper<Tag, SymbolValue<Tag, Type>, OtherTypes...> {
static constexpr Index eval_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) {
return symbol.value();
}
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) {
return symbol.value_at_compile_time();
}
};
// No symbol value in first value, recursive search starting with next.
template <typename Tag, typename T1, typename... OtherTypes>
struct EvalSymbolValueHelper<Tag, T1, OtherTypes...> {
static constexpr Index eval_impl(const T1&, const OtherTypes&... values) {
return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_impl(values...);
}
static constexpr Index eval_at_compile_time_impl(const T1&, const OtherTypes&...) {
return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_at_compile_time_impl(OtherTypes{}...);
}
};
/** Expression of a symbol uniquely identified by the template parameter type \c tag */
@ -217,32 +322,47 @@ class SymbolExpr : public BaseExpr<SymbolExpr<tag> > {
/** Alias to the template parameter \c tag */
typedef tag Tag;
SymbolExpr() {}
constexpr SymbolExpr() = default;
/** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag.
*
* The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified
* runtime-time value.
*/
SymbolValue<Tag> operator=(Index val) const { return SymbolValue<Tag>(val); }
constexpr SymbolValue<Tag, Index> operator=(Index val) const { return SymbolValue<Tag, Index>(val); }
Index eval_impl(const SymbolValue<Tag>& values) const { return values.value(); }
template <int N>
constexpr SymbolValue<Tag, internal::FixedInt<N>> operator=(internal::FixedInt<N>) const {
return SymbolValue<Tag, internal::FixedInt<N>>{internal::FixedInt<N>{}};
}
// C++14 versions suitable for multiple symbols
template <typename... Types>
Index eval_impl(const std::tuple<Types...>& values) const {
return std::get<SymbolValue<Tag> >(values).value();
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_impl(values...);
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_at_compile_time_impl(
SymbolValue<Tags, Types>{}...);
}
};
template <typename Arg0>
class NegateExpr : public BaseExpr<NegateExpr<Arg0> > {
public:
NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
constexpr NegateExpr() = default;
constexpr NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
template <typename T>
Index eval_impl(const T& values) const {
return -m_arg0.eval_impl(values);
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
return -m_arg0.eval_impl(values...);
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
constexpr Index v = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
return (v == Undefined) ? Undefined : -v;
}
protected:
@ -252,11 +372,19 @@ class NegateExpr : public BaseExpr<NegateExpr<Arg0> > {
template <typename Arg0, typename Arg1>
class AddExpr : public BaseExpr<AddExpr<Arg0, Arg1> > {
public:
AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
constexpr AddExpr() = default;
constexpr AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
template <typename T>
Index eval_impl(const T& values) const {
return m_arg0.eval_impl(values) + m_arg1.eval_impl(values);
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
return m_arg0.eval_impl(values...) + m_arg1.eval_impl(values...);
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 + v1;
}
protected:
@ -267,11 +395,19 @@ class AddExpr : public BaseExpr<AddExpr<Arg0, Arg1> > {
template <typename Arg0, typename Arg1>
class ProductExpr : public BaseExpr<ProductExpr<Arg0, Arg1> > {
public:
ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
constexpr ProductExpr() = default;
constexpr ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
template <typename T>
Index eval_impl(const T& values) const {
return m_arg0.eval_impl(values) * m_arg1.eval_impl(values);
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
return m_arg0.eval_impl(values...) * m_arg1.eval_impl(values...);
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 * v1;
}
protected:
@ -282,11 +418,19 @@ class ProductExpr : public BaseExpr<ProductExpr<Arg0, Arg1> > {
template <typename Arg0, typename Arg1>
class QuotientExpr : public BaseExpr<QuotientExpr<Arg0, Arg1> > {
public:
QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
constexpr QuotientExpr() = default;
constexpr QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
template <typename T>
Index eval_impl(const T& values) const {
return m_arg0.eval_impl(values) / m_arg1.eval_impl(values);
template <typename... Tags, typename... Types>
constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
return m_arg0.eval_impl(values...) / m_arg1.eval_impl(values...);
}
template <typename... Tags, typename... Types>
static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 / v1;
}
protected:

View File

@ -9,51 +9,47 @@
#if !defined(EIGEN_PARSED_BY_DOXYGEN)
protected:
public:
// define some aliases to ease readability
template <typename Indices>
using IvcRowType = typename internal::IndexedViewCompatibleType<Indices, RowsAtCompileTime>::type;
using IvcRowType = typename internal::IndexedViewHelperIndicesWrapper<Indices, RowsAtCompileTime>::type;
template <typename Indices>
using IvcColType = typename internal::IndexedViewCompatibleType<Indices, ColsAtCompileTime>::type;
using IvcColType = typename internal::IndexedViewHelperIndicesWrapper<Indices, ColsAtCompileTime>::type;
template <typename Indices>
using IvcType = typename internal::IndexedViewCompatibleType<Indices, SizeAtCompileTime>::type;
typedef typename internal::IndexedViewCompatibleType<Index, 1>::type IvcIndex;
using IvcSizeType = typename internal::IndexedViewHelperIndicesWrapper<Indices, SizeAtCompileTime>::type;
template <typename Indices>
inline IvcRowType<Indices> ivcRow(const Indices& indices) const {
return internal::makeIndexedViewCompatible(
indices, internal::variable_if_dynamic<Index, RowsAtCompileTime>(derived().rows()), Specialized);
return internal::IndexedViewHelperIndicesWrapper<Indices, RowsAtCompileTime>::CreateIndexSequence(indices,
derived().rows());
}
template <typename Indices>
inline IvcColType<Indices> ivcCol(const Indices& indices) const {
return internal::makeIndexedViewCompatible(
indices, internal::variable_if_dynamic<Index, ColsAtCompileTime>(derived().cols()), Specialized);
return internal::IndexedViewHelperIndicesWrapper<Indices, ColsAtCompileTime>::CreateIndexSequence(indices,
derived().cols());
}
template <typename Indices>
inline IvcType<Indices> ivcSize(const Indices& indices) const {
return internal::makeIndexedViewCompatible(
indices, internal::variable_if_dynamic<Index, SizeAtCompileTime>(derived().size()), Specialized);
inline IvcSizeType<Indices> ivcSize(const Indices& indices) const {
return internal::IndexedViewHelperIndicesWrapper<Indices, SizeAtCompileTime>::CreateIndexSequence(indices,
derived().size());
;
}
// this helper class assumes internal::valid_indexed_view_overload<RowIndices, ColIndices>::value == true
template <typename RowIndices, typename ColIndices,
bool UseSymbolic =
internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsScalar,
bool UseBlock =
internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsBlock,
bool UseGeneric = internal::traits<
IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsIndexedView>
template <typename RowIndices, typename ColIndices, typename EnableIf = void>
struct IndexedViewSelector;
// Generic
template <typename RowIndices, typename ColIndices>
struct IndexedViewSelector<RowIndices, ColIndices, false, false, true> {
struct IndexedViewSelector<
RowIndices, ColIndices,
std::enable_if_t<
internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsIndexedView>> {
using ReturnType = IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
using ConstReturnType = IndexedView<const Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
@ -68,60 +64,73 @@ struct IndexedViewSelector<RowIndices, ColIndices, false, false, true> {
// Block
template <typename RowIndices, typename ColIndices>
struct IndexedViewSelector<RowIndices, ColIndices, false, true, false> {
using IndexedViewType = IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
using ConstIndexedViewType = IndexedView<const Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
struct IndexedViewSelector<RowIndices, ColIndices,
std::enable_if_t<internal::traits<
IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsBlock>> {
using ActualRowIndices = IvcRowType<RowIndices>;
using ActualColIndices = IvcColType<ColIndices>;
using IndexedViewType = IndexedView<Derived, ActualRowIndices, ActualColIndices>;
using ConstIndexedViewType = IndexedView<const Derived, ActualRowIndices, ActualColIndices>;
using ReturnType = typename internal::traits<IndexedViewType>::BlockType;
using ConstReturnType = typename internal::traits<ConstIndexedViewType>::BlockType;
using RowHelper = internal::IndexedViewHelper<ActualRowIndices>;
using ColHelper = internal::IndexedViewHelper<ActualColIndices>;
static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) {
IvcRowType<RowIndices> actualRowIndices = derived.ivcRow(rowIndices);
IvcColType<ColIndices> actualColIndices = derived.ivcCol(colIndices);
return ReturnType(derived, internal::first(actualRowIndices), internal::first(actualColIndices),
internal::index_list_size(actualRowIndices), internal::index_list_size(actualColIndices));
auto actualRowIndices = derived.ivcRow(rowIndices);
auto actualColIndices = derived.ivcCol(colIndices);
return ReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices),
RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices));
}
static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices,
const ColIndices& colIndices) {
IvcRowType<RowIndices> actualRowIndices = derived.ivcRow(rowIndices);
IvcColType<ColIndices> actualColIndices = derived.ivcCol(colIndices);
return ConstReturnType(derived, internal::first(actualRowIndices), internal::first(actualColIndices),
internal::index_list_size(actualRowIndices), internal::index_list_size(actualColIndices));
auto actualRowIndices = derived.ivcRow(rowIndices);
auto actualColIndices = derived.ivcCol(colIndices);
return ConstReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices),
RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices));
}
};
// Symbolic
// Scalar
template <typename RowIndices, typename ColIndices>
struct IndexedViewSelector<RowIndices, ColIndices, true, false, false> {
struct IndexedViewSelector<RowIndices, ColIndices,
std::enable_if_t<internal::traits<
IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsScalar>> {
using ReturnType = typename DenseBase<Derived>::Scalar&;
using ConstReturnType = typename DenseBase<Derived>::CoeffReturnType;
using ActualRowIndices = IvcRowType<RowIndices>;
using ActualColIndices = IvcColType<ColIndices>;
using RowHelper = internal::IndexedViewHelper<ActualRowIndices>;
using ColHelper = internal::IndexedViewHelper<ActualColIndices>;
static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) {
return derived(internal::eval_expr_given_size(rowIndices, derived.rows()),
internal::eval_expr_given_size(colIndices, derived.cols()));
auto actualRowIndices = derived.ivcRow(rowIndices);
auto actualColIndices = derived.ivcCol(colIndices);
return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices));
}
static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices,
const ColIndices& colIndices) {
return derived(internal::eval_expr_given_size(rowIndices, derived.rows()),
internal::eval_expr_given_size(colIndices, derived.cols()));
auto actualRowIndices = derived.ivcRow(rowIndices);
auto actualColIndices = derived.ivcCol(colIndices);
return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices));
}
};
// this helper class assumes internal::is_valid_index_type<Indices>::value == false
template <typename Indices, bool UseSymbolic = symbolic::is_symbolic<Indices>::value,
bool UseBlock = !UseSymbolic && internal::get_compile_time_incr<IvcType<Indices>>::value == 1,
bool UseGeneric = !UseSymbolic && !UseBlock>
template <typename Indices, typename EnableIf = void>
struct VectorIndexedViewSelector;
// Generic
template <typename Indices>
struct VectorIndexedViewSelector<Indices, false, false, true> {
struct VectorIndexedViewSelector<
Indices, std::enable_if_t<!internal::is_single_range<IvcSizeType<Indices>>::value &&
internal::IndexedViewHelper<IvcSizeType<Indices>>::IncrAtCompileTime != 1>> {
static constexpr bool IsRowMajor = DenseBase<Derived>::IsRowMajor;
using ZeroIndex = internal::SingleRange<Index(0)>;
using RowMajorReturnType = IndexedView<Derived, ZeroIndex, IvcSizeType<Indices>>;
using ConstRowMajorReturnType = IndexedView<const Derived, ZeroIndex, IvcSizeType<Indices>>;
using RowMajorReturnType = IndexedView<Derived, IvcIndex, IvcType<Indices>>;
using ConstRowMajorReturnType = IndexedView<const Derived, IvcIndex, IvcType<Indices>>;
using ColMajorReturnType = IndexedView<Derived, IvcType<Indices>, IvcIndex>;
using ConstColMajorReturnType = IndexedView<const Derived, IvcType<Indices>, IvcIndex>;
using ColMajorReturnType = IndexedView<Derived, IvcSizeType<Indices>, ZeroIndex>;
using ConstColMajorReturnType = IndexedView<const Derived, IvcSizeType<Indices>, ZeroIndex>;
using ReturnType = typename internal::conditional<IsRowMajor, RowMajorReturnType, ColMajorReturnType>::type;
using ConstReturnType =
@ -129,49 +138,53 @@ struct VectorIndexedViewSelector<Indices, false, false, true> {
template <bool UseRowMajor = IsRowMajor, std::enable_if_t<UseRowMajor, bool> = true>
static inline RowMajorReturnType run(Derived& derived, const Indices& indices) {
return RowMajorReturnType(derived, IvcIndex(0), derived.ivcCol(indices));
return RowMajorReturnType(derived, ZeroIndex(0), derived.ivcCol(indices));
}
template <bool UseRowMajor = IsRowMajor, std::enable_if_t<UseRowMajor, bool> = true>
static inline ConstRowMajorReturnType run(const Derived& derived, const Indices& indices) {
return ConstRowMajorReturnType(derived, IvcIndex(0), derived.ivcCol(indices));
return ConstRowMajorReturnType(derived, ZeroIndex(0), derived.ivcCol(indices));
}
template <bool UseRowMajor = IsRowMajor, std::enable_if_t<!UseRowMajor, bool> = true>
static inline ColMajorReturnType run(Derived& derived, const Indices& indices) {
return ColMajorReturnType(derived, derived.ivcRow(indices), IvcIndex(0));
return ColMajorReturnType(derived, derived.ivcRow(indices), ZeroIndex(0));
}
template <bool UseRowMajor = IsRowMajor, std::enable_if_t<!UseRowMajor, bool> = true>
static inline ConstColMajorReturnType run(const Derived& derived, const Indices& indices) {
return ConstColMajorReturnType(derived, derived.ivcRow(indices), IvcIndex(0));
return ConstColMajorReturnType(derived, derived.ivcRow(indices), ZeroIndex(0));
}
};
// Block
template <typename Indices>
struct VectorIndexedViewSelector<Indices, false, true, false> {
using ReturnType = VectorBlock<Derived, internal::array_size<Indices>::value>;
using ConstReturnType = VectorBlock<const Derived, internal::array_size<Indices>::value>;
struct VectorIndexedViewSelector<
Indices, std::enable_if_t<!internal::is_single_range<IvcSizeType<Indices>>::value &&
internal::IndexedViewHelper<IvcSizeType<Indices>>::IncrAtCompileTime == 1>> {
using Helper = internal::IndexedViewHelper<IvcSizeType<Indices>>;
using ReturnType = VectorBlock<Derived, Helper::SizeAtCompileTime>;
using ConstReturnType = VectorBlock<const Derived, Helper::SizeAtCompileTime>;
static inline ReturnType run(Derived& derived, const Indices& indices) {
IvcType<Indices> actualIndices = derived.ivcSize(indices);
return ReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices));
auto actualIndices = derived.ivcSize(indices);
return ReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices));
}
static inline ConstReturnType run(const Derived& derived, const Indices& indices) {
IvcType<Indices> actualIndices = derived.ivcSize(indices);
return ConstReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices));
auto actualIndices = derived.ivcSize(indices);
return ConstReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices));
}
};
// Symbolic
template <typename Indices>
struct VectorIndexedViewSelector<Indices, true, false, false> {
struct VectorIndexedViewSelector<Indices, std::enable_if_t<internal::is_single_range<IvcSizeType<Indices>>::value>> {
using ReturnType = typename DenseBase<Derived>::Scalar&;
using ConstReturnType = typename DenseBase<Derived>::CoeffReturnType;
static inline ReturnType run(Derived& derived, const Indices& id) {
return derived(internal::eval_expr_given_size(id, derived.size()));
using Helper = internal::IndexedViewHelper<IvcSizeType<Indices>>;
static inline ReturnType run(Derived& derived, const Indices& indices) {
auto actualIndices = derived.ivcSize(indices);
return derived(Helper::first(actualIndices));
}
static inline ConstReturnType run(const Derived& derived, const Indices& id) {
return derived(internal::eval_expr_given_size(id, derived.size()));
static inline ConstReturnType run(const Derived& derived, const Indices& indices) {
auto actualIndices = derived.ivcSize(indices);
return derived(Helper::first(actualIndices));
}
};

View File

@ -86,12 +86,12 @@ Here are some examples for a 2D array/matrix \c A and a 1D array/vector \c v.
<td></td>
</tr>
<tr>
<td>First \c n odd rows A</td>
<td>First \c n odd rows of A</td>
<td>\code A(seqN(1,n,2), all) \endcode</td>
<td></td>
</tr>
<tr>
<td>The last past one column</td>
<td>The second-last column</td>
<td>\code A(all, last-1) \endcode</td>
<td>\code A.col(A.cols()-2) \endcode</td>
</tr>
@ -158,7 +158,7 @@ It is equivalent to:
\endcode
We can revisit the <i>even columns of A</i> example as follows:
\code A(all, seq(0,last,fix<2>))
\code A(all, seq(fix<0>,last,fix<2>))
\endcode

View File

@ -527,10 +527,323 @@ void check_indexed_view() {
}
}
void check_tutorial_examples() {
constexpr int kRows = 11;
constexpr int kCols = 21;
Matrix<double, kRows, kCols> A = Matrix<double, kRows, kCols>::Random();
Vector<double, kRows> v = Vector<double, kRows>::Random();
{
auto slice = A(seqN(fix<0>, fix<5>, fix<2>), seqN(fix<2>, fix<7>, fix<1>));
EIGEN_UNUSED_VARIABLE(slice);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), 7);
}
{
auto slice = A(seqN(fix<0>, fix<5>, fix<2>), indexing::all);
EIGEN_UNUSED_VARIABLE(slice);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), kCols);
}
// Examples from slicing tutorial.
// Bottom-left corner.
{
Index i = 3;
Index n = 5;
auto slice = A(seq(i, indexing::last), seqN(0, n));
auto block = A.bottomLeftCorner(A.rows() - i, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), Dynamic);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), Dynamic);
VERIFY_IS_EQUAL(slice, block);
}
{
auto i = fix<3>;
auto n = fix<5>;
auto slice = A(seq(i, indexing::last), seqN(fix<0>, n));
auto block = A.bottomLeftCorner(fix<kRows> - i, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), A.RowsAtCompileTime - i);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), n);
VERIFY_IS_EQUAL(slice, block);
}
// Block starting at i,j of size m,n.
{
Index i = 4;
Index j = 2;
Index m = 3;
Index n = 5;
auto slice = A(seqN(i, m), seqN(j, n));
auto block = A.block(i, j, m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto i = fix<4>;
auto j = fix<2>;
auto m = fix<3>;
auto n = fix<5>;
auto slice = A(seqN(i, m), seqN(j, n));
auto block = A.block(i, j, m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Block starting at i0,j0 and ending at i1,j1.
{
Index i0 = 4;
Index i1 = 7;
Index j0 = 3;
Index j1 = 5;
auto slice = A(seq(i0, i1), seq(j0, j1));
auto block = A.block(i0, j0, i1 - i0 + 1, j1 - j0 + 1);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto i0 = fix<4>;
auto i1 = fix<7>;
auto j0 = fix<3>;
auto j1 = fix<5>;
auto slice = A(seq(i0, i1), seq(j0, j1));
auto block = A.block(i0, j0, i1 - i0 + fix<1>, j1 - j0 + fix<1>);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Even columns of A.
{
auto slice = A(all, seq(0, last, 2));
auto block =
Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<2 * kRows>>(A.data(), kRows, (kCols + 1) / 2);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto slice = A(all, seq(fix<0>, last, fix<2>));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, (kCols + 1) / 2>, 0, OuterStride<2 * kRows>>(A.data());
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// First n odd rows of A.
{
Index n = 3;
auto slice = A(seqN(1, n, 2), all);
auto block = Eigen::Map<Eigen::Matrix<double, Dynamic, kCols>, 0, Stride<kRows, 2>>(A.data() + 1, n, kCols);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto n = fix<3>;
auto slice = A(seqN(fix<1>, n, fix<2>), all);
auto block = Eigen::Map<Eigen::Matrix<double, 3, kCols>, 0, Stride<kRows, 2>>(A.data() + 1);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// The second-last column.
{
auto slice = A(all, last - 1);
auto block = A.col(A.cols() - 2);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto slice = A(all, last - fix<1>);
auto block = A.col(fix<kCols> - fix<2>);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// The middle row.
{
auto slice = A(last / 2, all);
auto block = A.row((A.rows() - 1) / 2);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto slice = A(last / fix<2>, all);
auto block = A.row(fix<(kRows - 1) / 2>);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last elements of v starting at i.
{
Index i = 7;
auto slice = v(seq(i, last));
auto block = v.tail(v.size() - i);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto i = fix<7>;
auto slice = v(seq(i, last));
auto block = v.tail(fix<kRows> - i);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last n elements of v.
{
Index n = 6;
auto slice = v(seq(last + 1 - n, last));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto n = fix<6>;
auto slice = v(seq(last + fix<1> - n, last));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last n elements of v.
{
Index n = 6;
auto slice = v(lastN(n));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto n = fix<6>;
auto slice = v(lastN(n));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Bottom-right corner of A of size m times n.
{
Index m = 3;
Index n = 6;
auto slice = A(lastN(m), lastN(n));
auto block = A.bottomRightCorner(m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto m = fix<3>;
auto n = fix<6>;
auto slice = A(lastN(m), lastN(n));
auto block = A.bottomRightCorner(m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last n columns with a stride of 3.
{
Index n = 4;
constexpr Index stride = 3;
auto slice = A(all, lastN(n, stride));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<stride * kRows>>(
A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
constexpr auto n = fix<4>;
constexpr auto stride = fix<3>;
auto slice = A(all, lastN(n, stride));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, n>, 0, OuterStride<stride * kRows>>(
A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Compile time size and increment.
{
auto slice1 = v(seq(last - fix<7>, last - fix<2>));
auto slice2 = v(seqN(last - 7, fix<6>));
VERIFY_IS_EQUAL(slice1, slice2);
VERIFY_IS_EQUAL(int(slice1.SizeAtCompileTime), 6);
VERIFY_IS_EQUAL(int(slice2.SizeAtCompileTime), 6);
auto slice3 = A(all, seq(fix<0>, last, fix<2>));
VERIFY_IS_EQUAL(int(slice3.RowsAtCompileTime), kRows);
VERIFY_IS_EQUAL(int(slice3.ColsAtCompileTime), (kCols + 1) / 2);
}
// Reverse order.
{
auto slice = A(all, seq(20, 10, fix<-2>));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<-2 * kRows>>(
A.data() + 20 * kRows, A.rows(), (20 - 10 + 2) / 2);
VERIFY_IS_EQUAL(slice, block);
}
{
Index n = 10;
auto slice1 = A(seqN(last, n, fix<-1>), all);
auto slice2 = A(lastN(n).reverse(), all);
VERIFY_IS_EQUAL(slice1, slice2);
}
// Array of indices.
{
std::vector<int> ind{4, 2, 5, 5, 3};
auto slice1 = A(all, ind);
for (int i = 0; i < ind.size(); ++i) {
VERIFY_IS_EQUAL(slice1.col(i), A.col(ind[i]));
}
auto slice2 = A(all, {4, 2, 5, 5, 3});
VERIFY_IS_EQUAL(slice1, slice2);
Eigen::ArrayXi indarray(5);
indarray << 4, 2, 5, 5, 3;
auto slice3 = A(all, indarray);
VERIFY_IS_EQUAL(slice1, slice3);
}
// Custom index list.
{
struct pad {
Index size() const { return out_size; }
Index operator[](Index i) const { return std::max<Index>(0, i - (out_size - in_size)); }
Index in_size, out_size;
};
auto slice = A(pad{3, 5}, pad{3, 5});
Eigen::MatrixXd B = slice;
VERIFY_IS_EQUAL(B.block(2, 2, 3, 3), A.block(0, 0, 3, 3));
}
}
EIGEN_DECLARE_TEST(indexed_view) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(check_indexed_view());
}
CALL_SUBTEST_1(check_tutorial_examples());
// static checks of some internals:
STATIC_CHECK((internal::is_valid_index_type<int>::value));