Extended support for Tensors:

* Added ability to map a region of the memory to a tensor
  * Added basic support for unary and binary coefficient wise expressions, such as addition or square root
  * Provided an emulation layer to make it possible to compile the code with compilers (such as nvcc) that don't support cxx11.
This commit is contained in:
Benoit Steiner
2014-04-28 10:32:27 -07:00
parent 450d0c3de0
commit c0f2cb016e
17 changed files with 1028 additions and 129 deletions

View File

@@ -57,28 +57,16 @@ namespace Eigen {
*
* \ref TopicStorageOrders
*/
template<typename Scalar_, std::size_t NumIndices_, int Options_ = 0>
class Tensor;
namespace internal {
template<typename Scalar_, std::size_t NumIndices_, int Options_>
struct traits<Tensor<Scalar_, NumIndices_, Options_>>
{
typedef Scalar_ Scalar;
typedef Dense StorageKind;
typedef DenseIndex Index;
enum {
Options = Options_
};
};
template<typename Index, std::size_t NumIndices, std::size_t n, bool RowMajor>
struct tensor_index_linearization_helper
{
constexpr static inline Index run(std::array<Index, NumIndices> const& indices, std::array<Index, NumIndices> const& dimensions)
static inline Index run(array<Index, NumIndices> const& indices, array<Index, NumIndices> const& dimensions)
{
return std_array_get<RowMajor ? n : (NumIndices - n - 1)>(indices) +
std_array_get<RowMajor ? n : (NumIndices - n - 1)>(dimensions) *
return array_get<RowMajor ? n : (NumIndices - n - 1)>(indices) +
array_get<RowMajor ? n : (NumIndices - n - 1)>(dimensions) *
tensor_index_linearization_helper<Index, NumIndices, n - 1, RowMajor>::run(indices, dimensions);
}
};
@@ -86,39 +74,40 @@ struct tensor_index_linearization_helper
template<typename Index, std::size_t NumIndices, bool RowMajor>
struct tensor_index_linearization_helper<Index, NumIndices, 0, RowMajor>
{
constexpr static inline Index run(std::array<Index, NumIndices> const& indices, std::array<Index, NumIndices> const&)
static inline Index run(array<Index, NumIndices> const& indices, array<Index, NumIndices> const&)
{
return std_array_get<RowMajor ? 0 : NumIndices - 1>(indices);
return array_get<RowMajor ? 0 : NumIndices - 1>(indices);
}
};
/* Forward-declaration required for the symmetry support. */
template<typename Tensor_, typename Symmetry_, int Flags = 0> class tensor_symmetry_value_setter;
} // end namespace internal
template<typename Scalar_, std::size_t NumIndices_, int Options_>
class Tensor
class Tensor : public TensorBase<Tensor<Scalar_, NumIndices_, Options_> >
{
static_assert(NumIndices_ >= 1, "A tensor must have at least one index.");
public:
typedef Tensor<Scalar_, NumIndices_, Options_> Self;
typedef TensorBase<Tensor<Scalar_, NumIndices_, Options_> > Base;
typedef typename Eigen::internal::nested<Self>::type Nested;
typedef typename internal::traits<Self>::StorageKind StorageKind;
typedef typename internal::traits<Self>::Index Index;
typedef typename internal::traits<Self>::Scalar Scalar;
typedef Scalar_ Scalar;
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Self DenseType;
typedef typename Base::CoeffReturnType CoeffReturnType;
constexpr static int Options = Options_;
constexpr static std::size_t NumIndices = NumIndices_;
static const int Options = Options_;
static const std::size_t NumIndices = NumIndices_;
protected:
TensorStorage<Scalar, NumIndices, Dynamic, Options> m_storage;
public:
EIGEN_STRONG_INLINE Index dimension(std::size_t n) const { return m_storage.dimensions()[n]; }
EIGEN_STRONG_INLINE std::array<Index, NumIndices> dimensions() const { return m_storage.dimensions(); }
EIGEN_STRONG_INLINE array<Index, NumIndices> dimensions() const { return m_storage.dimensions(); }
EIGEN_STRONG_INLINE Index size() const { return internal::array_prod(m_storage.dimensions()); }
EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); }
EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); }
@@ -129,29 +118,17 @@ class Tensor
inline Self& base() { return *this; }
inline const Self& base() const { return *this; }
void setZero()
{
// FIXME: until we have implemented packet access and the
// expression engine w.r.t. nullary ops, use this
// as a kludge. Only works with POD types, but for
// any standard usage, this shouldn't be a problem
memset((void *)data(), 0, size() * sizeof(Scalar));
}
inline Self& operator=(Self const& other)
{
m_storage = other.m_storage;
return *this;
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes>
inline const Scalar& coeff(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const
{
static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
return coeff(std::array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
// The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
return coeff(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
}
#endif
inline const Scalar& coeff(const std::array<Index, NumIndices>& indices) const
inline const Scalar& coeff(const array<Index, NumIndices>& indices) const
{
eigen_internal_assert(checkIndexRange(indices));
return m_storage.data()[linearizedIndex(indices)];
@@ -163,14 +140,17 @@ class Tensor
return m_storage.data()[index];
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes>
inline Scalar& coeffRef(Index firstIndex, Index secondIndex, IndexTypes... otherIndices)
{
static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
return coeffRef(std::array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
// The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
return coeffRef(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
}
#endif
inline Scalar& coeffRef(const std::array<Index, NumIndices>& indices)
inline Scalar& coeffRef(const array<Index, NumIndices>& indices)
{
eigen_internal_assert(checkIndexRange(indices));
return m_storage.data()[linearizedIndex(indices)];
@@ -182,14 +162,17 @@ class Tensor
return m_storage.data()[index];
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes>
inline const Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const
{
static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
return this->operator()(std::array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
// The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
return this->operator()(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
}
#endif
inline const Scalar& operator()(const std::array<Index, NumIndices>& indices) const
inline const Scalar& operator()(const array<Index, NumIndices>& indices) const
{
eigen_assert(checkIndexRange(indices));
return coeff(indices);
@@ -203,18 +186,22 @@ class Tensor
inline const Scalar& operator[](Index index) const
{
static_assert(NumIndices == 1, "The bracket operator is only for vectors, use the parenthesis operator instead.");
// The bracket operator is only for vectors, use the parenthesis operator instead.
EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE);
return coeff(index);
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes>
inline Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices)
{
static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
return operator()(std::array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
// The number of indices used to access a tensor coefficient must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
return operator()(array<Index, NumIndices>{{firstIndex, secondIndex, otherIndices...}});
}
#endif
inline Scalar& operator()(const std::array<Index, NumIndices>& indices)
inline Scalar& operator()(const array<Index, NumIndices>& indices)
{
eigen_assert(checkIndexRange(indices));
return coeffRef(indices);
@@ -228,47 +215,70 @@ class Tensor
inline Scalar& operator[](Index index)
{
static_assert(NumIndices == 1, "The bracket operator is only for vectors, use the parenthesis operator instead.");
// The bracket operator is only for vectors, use the parenthesis operator instead
EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
return coeffRef(index);
}
inline Tensor()
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Tensor()
: m_storage()
{
}
inline Tensor(const Self& other)
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Tensor(const Self& other)
: m_storage(other.m_storage)
{
}
inline Tensor(Self&& other)
: m_storage(other.m_storage)
{
}
#ifdef EIGEN_HAVE_RVALUE_REFERENCES
// inline Tensor(Self&& other)
// : m_storage(other.m_storage)
// {
// }
#endif
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes>
inline Tensor(Index firstDimension, IndexTypes... otherDimensions)
: m_storage()
{
static_assert(sizeof...(otherDimensions) + 1 == NumIndices, "Number of dimensions used to construct a tensor must be equal to the rank of the tensor.");
resize(std::array<Index, NumIndices>{{firstDimension, otherDimensions...}});
// The number of dimensions used to construct a tensor must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
resize(array<Index, NumIndices>{{firstDimension, otherDimensions...}});
}
#endif
inline Tensor(std::array<Index, NumIndices> dimensions)
inline Tensor(const array<Index, NumIndices>& dimensions)
: m_storage(internal::array_prod(dimensions), dimensions)
{
EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
}
template<typename OtherDerived>
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Tensor& operator=(const OtherDerived& other)
{
// FIXME: we need to resize the tensor to fix the dimensions of the other.
// Unfortunately this isn't possible yet when the rhs is an expression.
// resize(other.dimensions());
internal::TensorAssign<Tensor, const OtherDerived>::run(*this, other);
return *this;
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes>
void resize(Index firstDimension, IndexTypes... otherDimensions)
{
static_assert(sizeof...(otherDimensions) + 1 == NumIndices, "Number of dimensions used to resize a tensor must be equal to the rank of the tensor.");
resize(std::array<Index, NumIndices>{{firstDimension, otherDimensions...}});
// The number of dimensions used to resize a tensor must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
resize(array<Index, NumIndices>{{firstDimension, otherDimensions...}});
}
#endif
void resize(const std::array<Index, NumIndices>& dimensions)
void resize(const array<Index, NumIndices>& dimensions)
{
std::size_t i;
Index size = Index(1);
@@ -285,20 +295,22 @@ class Tensor
#endif
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename Symmetry_, typename... IndexTypes>
internal::tensor_symmetry_value_setter<Self, Symmetry_> symCoeff(const Symmetry_& symmetry, Index firstIndex, IndexTypes... otherIndices)
{
return symCoeff(symmetry, std::array<Index, NumIndices>{{firstIndex, otherIndices...}});
return symCoeff(symmetry, array<Index, NumIndices>{{firstIndex, otherIndices...}});
}
template<typename Symmetry_, typename... IndexTypes>
internal::tensor_symmetry_value_setter<Self, Symmetry_> symCoeff(const Symmetry_& symmetry, std::array<Index, NumIndices> const& indices)
internal::tensor_symmetry_value_setter<Self, Symmetry_> symCoeff(const Symmetry_& symmetry, array<Index, NumIndices> const& indices)
{
return internal::tensor_symmetry_value_setter<Self, Symmetry_>(*this, symmetry, indices);
}
#endif
protected:
bool checkIndexRange(const std::array<Index, NumIndices>& indices) const
bool checkIndexRange(const array<Index, NumIndices>& indices) const
{
using internal::array_apply_and_reduce;
using internal::array_zip_and_reduce;
@@ -313,7 +325,7 @@ class Tensor
array_zip_and_reduce<logical_and_op, lesser_op>(indices, m_storage.dimensions());
}
inline Index linearizedIndex(const std::array<Index, NumIndices>& indices) const
inline Index linearizedIndex(const array<Index, NumIndices>& indices) const
{
return internal::tensor_index_linearization_helper<Index, NumIndices, NumIndices - 1, Options&RowMajor>::run(indices, m_storage.dimensions());
}
@@ -322,7 +334,3 @@ class Tensor
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_H
/*
* kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
*/

View File

@@ -0,0 +1,52 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_ASSIGN_H
#define EIGEN_CXX11_TENSOR_TENSOR_ASSIGN_H
namespace Eigen {
/** \class TensorAssign
* \ingroup CXX11_Tensor_Module
*
* \brief The tensor assignment class.
*
* This class is responsible for triggering the evaluation of the expressions
* used on the lhs and rhs of an assignment operator and copy the result of
* the evaluation of the rhs expression at the address computed during the
* evaluation lhs expression.
*
* TODO: vectorization. For now the code only uses scalars
* TODO: parallelisation using multithreading on cpu, or kernels on gpu.
*/
namespace internal {
template<typename Derived1, typename Derived2>
struct TensorAssign
{
typedef typename Derived1::Index Index;
EIGEN_DEVICE_FUNC
static inline void run(Derived1& dst, const Derived2& src)
{
TensorEvaluator<Derived1> evalDst(dst);
TensorEvaluator<Derived2> evalSrc(src);
const Index size = dst.size();
for(Index i = 0; i < size; ++i) {
evalDst.coeffRef(i) = evalSrc.coeff(i);
}
}
};
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_ASSIGN_H

View File

@@ -0,0 +1,82 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_BASE_H
#define EIGEN_CXX11_TENSOR_TENSOR_BASE_H
namespace Eigen {
/** \class TensorBase
* \ingroup CXX11_Tensor_Module
*
* \brief The tensor base class.
*
* This class is the common parent of the Tensor and TensorMap class, thus
* making it possible to use either class interchangably in expressions.
*/
template<typename Derived>
class TensorBase
{
public:
typedef typename internal::traits<Derived>::Scalar Scalar;
typedef typename internal::traits<Derived>::Index Index;
typedef Scalar CoeffReturnType;
Derived& setZero() {
return setConstant(Scalar(0));
}
Derived& setConstant(const Scalar& val) {
Scalar* data = derived().data();
for (int i = 0; i < derived().size(); ++i) {
data[i] = val;
}
return derived();
}
Derived& setRandom() {
Scalar* data = derived().data();
for (int i = 0; i < derived().size(); ++i) {
data[i] = internal::random_default_impl<Scalar, false, false>::run();
}
return derived();
}
// Coefficient-wise unary operators
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const Derived>
operator-() const { return derived(); }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_sqrt_op<Scalar>, const Derived>
cwiseSqrt() const { return derived(); }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_abs_op<Scalar>, const Derived>
cwiseAbs() const { return derived(); }
// Coefficient-wise binary operators.
template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
const TensorCwiseBinaryOp<internal::scalar_sum_op<Scalar>, const Derived, const OtherDerived>
operator+(const OtherDerived& other) const {
return TensorCwiseBinaryOp<internal::scalar_sum_op<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
}
protected:
template <typename OtherDerived> friend class TensorBase;
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Derived& derived() { return *static_cast<Derived*>(this); }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const Derived& derived() const { return *static_cast<const Derived*>(this); }
};
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_BASE_H

View File

@@ -0,0 +1,127 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H
#define EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H
namespace Eigen {
/** \class TensorEvaluator
* \ingroup CXX11_Tensor_Module
*
* \brief The tensor evaluator classes.
*
* These classes are responsible for the evaluation of the tensor expression.
*
* TODO: add support for more types of expressions, in particular expressions
* leading to lvalues (slicing, reshaping, etc...)
* TODO: add support for vectorization
*/
template<typename Derived>
struct TensorEvaluator
{
typedef typename Derived::Index Index;
typedef typename Derived::Scalar Scalar;
typedef typename Derived::Scalar& CoeffReturnType;
//typedef typename Derived::PacketScalar PacketScalar;
typedef TensorEvaluator<Derived> nestedType;
TensorEvaluator(Derived& m)
: m_data(const_cast<Scalar*>(m.data()))
{ }
CoeffReturnType coeff(Index index) const {
return m_data[index];
}
Scalar& coeffRef(Index index) {
return m_data[index];
}
// to do: vectorized evaluation.
/* template<int LoadMode>
PacketReturnType packet(Index index) const
{
return ploadt<PacketScalar, LoadMode>(m_data + index);
}
template<int StoreMode>
void writePacket(Index index, const PacketScalar& x)
{
return pstoret<Scalar, PacketScalar, StoreMode>(const_cast<Scalar*>(m_data) + index, x);
}*/
protected:
Scalar* m_data;
};
// -------------------- CwiseUnaryOp --------------------
template<typename UnaryOp, typename ArgType>
struct TensorEvaluator<const TensorCwiseUnaryOp<UnaryOp, ArgType> >
{
typedef TensorCwiseUnaryOp<UnaryOp, ArgType> XprType;
typedef TensorEvaluator<ArgType> nestedType;
TensorEvaluator(const XprType& op)
: m_functor(op.functor()),
m_argImpl(op.nestedExpression())
{ }
typedef typename XprType::Index Index;
typedef typename XprType::CoeffReturnType CoeffReturnType;
CoeffReturnType coeff(Index index) const
{
return m_functor(m_argImpl.coeff(index));
}
private:
const UnaryOp m_functor;
typename TensorEvaluator<ArgType>::nestedType m_argImpl;
};
// -------------------- CwiseBinaryOp --------------------
template<typename BinaryOp, typename LeftArgType, typename RightArgType>
struct TensorEvaluator<const TensorCwiseBinaryOp<BinaryOp, LeftArgType, RightArgType> >
{
typedef TensorCwiseBinaryOp<BinaryOp, LeftArgType, RightArgType> XprType;
typedef TensorEvaluator<LeftArgType> leftType;
typedef TensorEvaluator<RightArgType> rightType;
TensorEvaluator(const XprType& op)
: m_functor(op.functor()),
m_leftImpl(op.lhsExpression()),
m_rightImpl(op.rhsExpression())
{ }
typedef typename XprType::Index Index;
typedef typename XprType::CoeffReturnType CoeffReturnType;
CoeffReturnType coeff(Index index) const
{
return m_functor(m_leftImpl.coeff(index), m_rightImpl.coeff(index));
}
private:
const BinaryOp m_functor;
typename TensorEvaluator<LeftArgType>::nestedType m_leftImpl;
typename TensorEvaluator<RightArgType>::nestedType m_rightImpl;
};
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H

View File

@@ -0,0 +1,161 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_EXPR_H
#define EIGEN_CXX11_TENSOR_TENSOR_EXPR_H
namespace Eigen {
/** \class TensorExpr
* \ingroup CXX11_Tensor_Module
*
* \brief Tensor expression classes.
*
* The TensorCwiseUnaryOp class represents an expression where a unary operator
* (e.g. cwiseSqrt) is applied to an expression.
*
* The TensorCwiseBinaryOp class represents an expression where a binary operator
* (e.g. addition) is applied to a lhs and a rhs expression.
*
*/
namespace internal {
template<typename UnaryOp, typename XprType>
struct traits<TensorCwiseUnaryOp<UnaryOp, XprType> >
: traits<XprType>
{
typedef typename result_of<
UnaryOp(typename XprType::Scalar)
>::type Scalar;
typedef typename XprType::Nested XprTypeNested;
typedef typename remove_reference<XprTypeNested>::type _XprTypeNested;
};
template<typename UnaryOp, typename XprType>
struct eval<TensorCwiseUnaryOp<UnaryOp, XprType>, Eigen::Dense>
{
typedef const TensorCwiseUnaryOp<UnaryOp, XprType>& type;
};
template<typename UnaryOp, typename XprType>
struct nested<TensorCwiseUnaryOp<UnaryOp, XprType>, 1, typename eval<TensorCwiseUnaryOp<UnaryOp, XprType> >::type>
{
typedef TensorCwiseUnaryOp<UnaryOp, XprType> type;
};
} // end namespace internal
template<typename UnaryOp, typename XprType>
class TensorCwiseUnaryOp
{
public:
typedef typename Eigen::internal::traits<TensorCwiseUnaryOp>::Scalar Scalar;
typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
typedef typename XprType::CoeffReturnType CoeffReturnType;
typedef typename Eigen::internal::nested<TensorCwiseUnaryOp>::type Nested;
typedef typename Eigen::internal::traits<TensorCwiseUnaryOp>::StorageKind StorageKind;
typedef typename Eigen::internal::traits<TensorCwiseUnaryOp>::Index Index;
inline TensorCwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp())
: m_xpr(xpr), m_functor(func) {}
EIGEN_DEVICE_FUNC
const UnaryOp& functor() const { return m_functor; }
/** \returns the nested expression */
EIGEN_DEVICE_FUNC
const typename internal::remove_all<typename XprType::Nested>::type&
nestedExpression() const { return m_xpr; }
/** \returns the nested expression */
EIGEN_DEVICE_FUNC
typename internal::remove_all<typename XprType::Nested>::type&
nestedExpression() { return m_xpr.const_cast_derived(); }
protected:
typename XprType::Nested m_xpr;
const UnaryOp m_functor;
};
namespace internal {
template<typename BinaryOp, typename LhsXprType, typename RhsXprType>
struct traits<TensorCwiseBinaryOp<BinaryOp, LhsXprType, RhsXprType> >
{
// Type promotion to handle the case where the types of the lhs and the rhs are different.
typedef typename result_of<
BinaryOp(
typename LhsXprType::Scalar,
typename RhsXprType::Scalar
)
>::type Scalar;
typedef typename promote_storage_type<typename traits<LhsXprType>::StorageKind,
typename traits<RhsXprType>::StorageKind>::ret StorageKind;
typedef typename promote_index_type<typename traits<LhsXprType>::Index,
typename traits<RhsXprType>::Index>::type Index;
typedef typename LhsXprType::Nested LhsNested;
typedef typename RhsXprType::Nested RhsNested;
typedef typename remove_reference<LhsNested>::type _LhsNested;
typedef typename remove_reference<RhsNested>::type _RhsNested;
};
template<typename BinaryOp, typename LhsXprType, typename RhsXprType>
struct eval<TensorCwiseBinaryOp<BinaryOp, LhsXprType, RhsXprType>, Eigen::Dense>
{
typedef const TensorCwiseBinaryOp<BinaryOp, LhsXprType, RhsXprType>& type;
};
template<typename BinaryOp, typename LhsXprType, typename RhsXprType>
struct nested<TensorCwiseBinaryOp<BinaryOp, LhsXprType, RhsXprType>, 1, typename eval<TensorCwiseBinaryOp<BinaryOp, LhsXprType, RhsXprType> >::type>
{
typedef TensorCwiseBinaryOp<BinaryOp, LhsXprType, RhsXprType> type;
};
} // end namespace internal
template<typename BinaryOp, typename LhsXprType, typename RhsXprType>
class TensorCwiseBinaryOp
{
public:
typedef typename Eigen::internal::traits<TensorCwiseBinaryOp>::Scalar Scalar;
typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
typedef typename internal::promote_storage_type<typename LhsXprType::CoeffReturnType,
typename RhsXprType::CoeffReturnType>::ret CoeffReturnType;
typedef typename Eigen::internal::nested<TensorCwiseBinaryOp>::type Nested;
typedef typename Eigen::internal::traits<TensorCwiseBinaryOp>::StorageKind StorageKind;
typedef typename Eigen::internal::traits<TensorCwiseBinaryOp>::Index Index;
inline TensorCwiseBinaryOp(const LhsXprType& lhs, const RhsXprType& rhs, const BinaryOp& func = BinaryOp())
: m_lhs_xpr(lhs), m_rhs_xpr(rhs), m_functor(func) {}
EIGEN_DEVICE_FUNC
const BinaryOp& functor() const { return m_functor; }
/** \returns the nested expressions */
EIGEN_DEVICE_FUNC
const typename internal::remove_all<typename LhsXprType::Nested>::type&
lhsExpression() const { return m_lhs_xpr; }
EIGEN_DEVICE_FUNC
const typename internal::remove_all<typename RhsXprType::Nested>::type&
rhsExpression() const { return m_rhs_xpr; }
protected:
typename LhsXprType::Nested m_lhs_xpr;
typename RhsXprType::Nested m_rhs_xpr;
const BinaryOp m_functor;
};
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_EXPR_H

View File

@@ -0,0 +1,27 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_FORWARD_DECLARATIONS_H
#define EIGEN_CXX11_TENSOR_TENSOR_FORWARD_DECLARATIONS_H
namespace Eigen {
template<typename Scalar_, std::size_t NumIndices_, int Options_ = 0> class Tensor;
template<typename PlainObjectType> class TensorMap;
template<typename Derived> class TensorBase;
template<typename UnaryOp, typename XprType> class TensorCwiseUnaryOp;
template<typename BinaryOp, typename LeftXprType, typename RightXprType> class TensorCwiseBinaryOp;
// Move to internal?
template<typename Derived> struct TensorEvaluator;
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_FORWARD_DECLARATIONS_H

View File

@@ -0,0 +1,101 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_MAP_H
#define EIGEN_CXX11_TENSOR_TENSOR_MAP_H
namespace Eigen {
template<int InnerStrideAtCompileTime, int OuterStrideAtCompileTime> class Stride;
/** \class TensorMap
* \ingroup CXX11_Tensor_Module
*
* \brief A tensor expression mapping an existing array of data.
*
*/
template<typename PlainObjectType> class TensorMap : public TensorBase<TensorMap<PlainObjectType> >
{
public:
typedef TensorMap<PlainObjectType> Self;
typedef typename PlainObjectType::Base Base;
typedef typename Eigen::internal::nested<Self>::type Nested;
typedef typename internal::traits<PlainObjectType>::StorageKind StorageKind;
typedef typename internal::traits<PlainObjectType>::Index Index;
typedef typename internal::traits<PlainObjectType>::Scalar Scalar;
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef typename Base::CoeffReturnType CoeffReturnType;
/* typedef typename internal::conditional<
bool(internal::is_lvalue<PlainObjectType>::value),
Scalar *,
const Scalar *>::type
PointerType;*/
typedef Scalar* PointerType;
typedef PointerType PointerArgType;
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index firstDimension) : m_data(dataPtr), m_dimensions({{firstDimension}}) {
// The number of dimensions used to construct a tensor must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(1 == PlainObjectType::NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes> EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index firstDimension, IndexTypes... otherDimensions) : m_data(dataPtr), m_dimensions({{firstDimension, otherDimensions...}}) {
// The number of dimensions used to construct a tensor must be equal to the rank of the tensor.
EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == PlainObjectType::NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE)
}
#endif
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Index dimension(Index n) const { return m_dimensions[n]; }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Index size() const { return internal::array_prod(m_dimensions); }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Scalar* data() { return m_data; }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const Scalar* data() const { return m_data; }
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const
{
eigen_internal_assert(index >= 0 && index < size());
return m_data[index];
}
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... IndexTypes> EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Scalar& operator()(Index firstIndex, IndexTypes... otherIndices)
{
static_assert(sizeof...(otherIndices) + 1 == PlainObjectType::NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
const Index index = internal::tensor_index_linearization_helper<Index, PlainObjectType::NumIndices, PlainObjectType::NumIndices - 1, PlainObjectType::Options&RowMajor>::run(array<Index, PlainObjectType::NumIndices>{{firstIndex, otherIndices...}}, m_dimensions);
return m_data[index];
}
#endif
template<typename OtherDerived>
EIGEN_DEVICE_FUNC
Self& operator=(const OtherDerived& other)
{
internal::TensorAssign<Self, const OtherDerived>::run(*this, other);
return *this;
}
private:
typename PlainObjectType::Scalar* m_data;
array<DenseIndex, PlainObjectType::NumIndices> m_dimensions;
};
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_MAP_H

View File

@@ -37,14 +37,19 @@ template<typename T, std::size_t NumIndices_, int Options_>
class TensorStorage<T, NumIndices_, Dynamic, Options_, void>
: public TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_numeric_list_repeated<DenseIndex, NumIndices_, Dynamic>::type>
{
typedef TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_numeric_list_repeated<DenseIndex, NumIndices_, Dynamic>::type> Base_;
typedef TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_numeric_list_repeated<DenseIndex, NumIndices_, Dynamic>::type> Base_;
public:
TensorStorage() = default;
TensorStorage(const TensorStorage<T, NumIndices_, Dynamic, Options_, void>&) = default;
TensorStorage(TensorStorage<T, NumIndices_, Dynamic, Options_, void>&&) = default;
TensorStorage() { }
TensorStorage(const TensorStorage<T, NumIndices_, Dynamic, Options_, void>& other) : Base_(other) { }
#ifdef EIGEN_HAVE_RVALUE_REFERENCES
// TensorStorage(TensorStorage<T, NumIndices_, Dynamic, Options_, void>&&) = default;
#endif
TensorStorage(internal::constructor_without_unaligned_array_assert) : Base_(internal::constructor_without_unaligned_array_assert()) {}
TensorStorage(DenseIndex size, const std::array<DenseIndex, NumIndices_>& dimensions) : Base_(size, dimensions) {}
TensorStorage<T, NumIndices_, Dynamic, Options_, void>& operator=(const TensorStorage<T, NumIndices_, Dynamic, Options_, void>&) = default;
TensorStorage(DenseIndex size, const array<DenseIndex, NumIndices_>& dimensions) : Base_(size, dimensions) {}
// TensorStorage<T, NumIndices_, Dynamic, Options_, void>& operator=(const TensorStorage<T, NumIndices_, Dynamic, Options_, void>&) = default;
};
// pure dynamic
@@ -52,17 +57,17 @@ template<typename T, std::size_t NumIndices_, int Options_>
class TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_numeric_list_repeated<DenseIndex, NumIndices_, Dynamic>::type>
{
T *m_data;
std::array<DenseIndex, NumIndices_> m_dimensions;
array<DenseIndex, NumIndices_> m_dimensions;
typedef TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_numeric_list_repeated<DenseIndex, NumIndices_, Dynamic>::type> Self_;
public:
TensorStorage() : m_data(0), m_dimensions(internal::template repeat<NumIndices_, DenseIndex>(0)) {}
TensorStorage() : m_data(0), m_dimensions() {}
TensorStorage(internal::constructor_without_unaligned_array_assert)
: m_data(0), m_dimensions(internal::template repeat<NumIndices_, DenseIndex>(0)) {}
TensorStorage(DenseIndex size, const std::array<DenseIndex, NumIndices_>& dimensions)
: m_data(internal::conditional_aligned_new_auto<T,(Options_&DontAlign)==0>(size)), m_dimensions(dimensions)
{ EIGEN_INTERNAL_TENSOR_STORAGE_CTOR_PLUGIN }
TensorStorage(const Self_& other)
TensorStorage(DenseIndex size, const array<DenseIndex, NumIndices_>& dimensions)
: m_data(internal::conditional_aligned_new_auto<T,(Options_&DontAlign)==0>(size)), m_dimensions(dimensions)
{ EIGEN_INTERNAL_TENSOR_STORAGE_CTOR_PLUGIN }
TensorStorage(const Self_& other)
: m_data(internal::conditional_aligned_new_auto<T,(Options_&DontAlign)==0>(internal::array_prod(other.m_dimensions)))
, m_dimensions(other.m_dimensions)
{
@@ -76,28 +81,34 @@ class TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_nu
}
return *this;
}
TensorStorage(Self_&& other)
#ifdef EIGEN_HAVE_RVALUE_REFERENCES
/* TensorStorage(Self_&& other)
: m_data(std::move(other.m_data)), m_dimensions(std::move(other.m_dimensions))
{
other.m_data = nullptr;
}
*/
Self_& operator=(Self_&& other)
{
using std::swap;
swap(m_data, other.m_data);
swap(m_dimensions, other.m_dimensions);
return *this;
}
}
#endif
~TensorStorage() { internal::conditional_aligned_delete_auto<T,(Options_&DontAlign)==0>(m_data, internal::array_prod(m_dimensions)); }
void swap(Self_& other)
{ std::swap(m_data,other.m_data); std::swap(m_dimensions,other.m_dimensions); }
std::array<DenseIndex, NumIndices_> dimensions(void) const {return m_dimensions;}
void conservativeResize(DenseIndex size, const std::array<DenseIndex, NumIndices_>& nbDimensions)
const array<DenseIndex, NumIndices_>& dimensions() const {return m_dimensions;}
void conservativeResize(DenseIndex size, const array<DenseIndex, NumIndices_>& nbDimensions)
{
m_data = internal::conditional_aligned_realloc_new_auto<T,(Options_&DontAlign)==0>(m_data, size, internal::array_prod(m_dimensions));
m_dimensions = nbDimensions;
}
void resize(DenseIndex size, const std::array<DenseIndex, NumIndices_>& nbDimensions)
void resize(DenseIndex size, const array<DenseIndex, NumIndices_>& nbDimensions)
{
if(size != internal::array_prod(m_dimensions))
{
@@ -110,8 +121,9 @@ class TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_nu
}
m_dimensions = nbDimensions;
}
const T *data() const { return m_data; }
T *data() { return m_data; }
const T *data() const { return m_data; }
};
// TODO: implement fixed-size stuff
@@ -119,7 +131,3 @@ class TensorStorage<T, NumIndices_, Dynamic, Options_, typename internal::gen_nu
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSORSTORAGE_H
/*
* kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
*/

View File

@@ -0,0 +1,122 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H
#define EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H
namespace Eigen {
namespace internal {
template<typename Scalar, int Options>
class compute_tensor_flags
{
enum {
is_dynamic_size_storage = 1,
aligned_bit =
(
((Options&DontAlign)==0) && (
#if EIGEN_ALIGN_STATICALLY
(!is_dynamic_size_storage)
#else
0
#endif
||
#if EIGEN_ALIGN
is_dynamic_size_storage
#else
0
#endif
)
) ? AlignedBit : 0,
packet_access_bit = packet_traits<Scalar>::Vectorizable && aligned_bit ? PacketAccessBit : 0
};
public:
enum { ret = packet_access_bit | aligned_bit};
};
template<typename Scalar_, std::size_t NumIndices_, int Options_>
struct traits<Tensor<Scalar_, NumIndices_, Options_> >
{
typedef Scalar_ Scalar;
typedef Dense StorageKind;
typedef DenseIndex Index;
enum {
Options = Options_,
Flags = compute_tensor_flags<Scalar_, Options_>::ret,
};
};
template<typename PlainObjectType>
struct traits<TensorMap<PlainObjectType> >
: public traits<PlainObjectType>
{
typedef traits<PlainObjectType> BaseTraits;
typedef typename BaseTraits::Scalar Scalar;
typedef typename BaseTraits::StorageKind StorageKind;
typedef typename BaseTraits::Index Index;
};
template<typename _Scalar, std::size_t NumIndices_, int Options_>
struct eval<Tensor<_Scalar, NumIndices_, Options_>, Eigen::Dense>
{
typedef const Tensor<_Scalar, NumIndices_, Options_>& type;
};
template<typename _Scalar, std::size_t NumIndices_, int Options_>
struct eval<const Tensor<_Scalar, NumIndices_, Options_>, Eigen::Dense>
{
typedef const Tensor<_Scalar, NumIndices_, Options_>& type;
};
template<typename PlainObjectType>
struct eval<TensorMap<PlainObjectType>, Eigen::Dense>
{
typedef const TensorMap<PlainObjectType>& type;
};
template<typename PlainObjectType>
struct eval<const TensorMap<PlainObjectType>, Eigen::Dense>
{
typedef const TensorMap<PlainObjectType>& type;
};
template <typename Scalar_, std::size_t NumIndices_, int Options_>
struct nested<Tensor<Scalar_, NumIndices_, Options_>, 1, typename eval<Tensor<Scalar_, NumIndices_, Options_> >::type>
{
typedef const Tensor<Scalar_, NumIndices_, Options_>& type;
};
template <typename Scalar_, std::size_t NumIndices_, int Options_>
struct nested<const Tensor<Scalar_, NumIndices_, Options_>, 1, typename eval<const Tensor<Scalar_, NumIndices_, Options_> >::type>
{
typedef const Tensor<Scalar_, NumIndices_, Options_>& type;
};
template <typename PlainObjectType>
struct nested<TensorMap<PlainObjectType>, 1, typename eval<TensorMap<PlainObjectType> >::type>
{
typedef const TensorMap<PlainObjectType>& type;
};
template <typename PlainObjectType>
struct nested<const TensorMap<PlainObjectType>, 1, typename eval<TensorMap<PlainObjectType> >::type>
{
typedef const TensorMap<PlainObjectType>& type;
};
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H