本征不支持张量到本征矩阵
Eigen unsupported Tensor to Eigen matrix
在对具有更多维度的 Tensor 进行一些操作后,我得到了 Eigen::Tensor<std::complex, 2>
。有没有简单的方法从这个张量对象创建一个 Eigen::MatrixXcf
还是我必须手动复制这些值?
原始答案。进一步查看更新。
我目前使用的是 Eigen 版本 3.3.4,没有简单的 built-in 函数可以在 Eigen::Tensor 类型和更熟悉的 Matrix 或 Array 类型之间进行转换。拥有 .matrix()
或 .array()
方法之类的东西会很方便。
也没有简单的方法add such methods via the plugin mechanism,因为张量模块似乎不支持插件。如果有人知道如何请评论。
同时,可以使用 Map 函数制定相当有效的解决方法。以下在 C++14 中工作,用于将张量转换为矩阵
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
template<typename T>
using MatrixType = Eigen::Matrix<T,Eigen::Dynamic, Eigen::Dynamic>;
template<typename Scalar,int rank, typename sizeType>
auto Tensor_to_Matrix(const Eigen::Tensor<Scalar,rank> &tensor,const sizeType rows,const sizeType cols)
{
return Eigen::Map<const MatrixType<Scalar>> (tensor.data(), rows,cols);
}
template<typename Scalar, typename... Dims>
auto Matrix_to_Tensor(const MatrixType<Scalar> &matrix, Dims... dims)
{
constexpr int rank = sizeof... (Dims);
return Eigen::TensorMap<Eigen::Tensor<const Scalar, rank>>(matrix.data(), {dims...});
}
int main () {
Eigen::Tensor<double,4> my_rank4 (2,2,2,2);
my_rank4.setRandom();
Eigen::MatrixXd mymatrix = Tensor_to_Matrix(my_rank4, 4,4);
Eigen::Tensor<double,3> my_rank3 = Matrix_to_Tensor(mymatrix, 2,2,4);
std::cout << my_rank3 << std::endl;
return 0;
}
这同样适用于复杂类型。
不幸的是,这些函数只接受张量,而不是张量运算。例如,这不起作用:
Eigen::MatrixXd mymatrix = Tensor_to_Matrix(my_rank4.shuffle(Eigen::array<long,4>{1,0,3,2}), 4,4);
2021 年 8 月更新:
内存泄漏已修复,请参阅下面的代码。简而言之,必须记住在 Eigen::TensorEvaluator 对象上调用 .cleanup()
成员函数来释放内部临时缓冲区。
2021 年 10 月更新:
自从我在 2018 年提交上述答案以来,我已经学会了如何使用最少的临时变量在 Eigen::Tensor
和 Eigen::Matrix
(及其表达式)之间进行映射和转换。
自 Eigen 3.3.7 使用 C++17 以来,我一直在使用下面的辅助函数
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
template<typename T>
using MatrixType = Eigen::Matrix<T,Eigen::Dynamic, Eigen::Dynamic>;
template<typename T>
using VectorType = Eigen::Matrix<T,Eigen::Dynamic, 1>;
/*
*
* Convert Eigen::Tensor --> Eigen::Matrix
*
*/
template<typename Derived, typename Device = Eigen::DefaultDevice>
class selfCleaningEvaluator {
private:
using Evaluator = Eigen::TensorEvaluator<const Eigen::TensorForcedEvalOp<const Derived>, Device>;
Evaluator m_eval;
public:
selfCleaningEvaluator(const Evaluator &eval) : m_eval(eval) {}
selfCleaningEvaluator(const Eigen::TensorBase<Derived, Eigen::ReadOnlyAccessors> &expr, const Device &device = Device())
: m_eval(Evaluator(expr.eval(), device)) {
m_eval.evalSubExprsIfNeeded(nullptr);
}
~selfCleaningEvaluator() {
// This whole point of this object is to call cleanup automatically on destruct.
// If there are pending operations to evaluate, m_eval will allocate a buffer to hold a result,
// which needs to be deallocated.
m_eval.cleanup();
}
constexpr auto rank() {
using DimType = typename decltype(m_eval)::Dimensions::Base;
return DimType{}.size(); // Because Derived::Dimensions is sometimes wrong
}
const Evaluator *operator->() const { return &m_eval; }
Evaluator *operator->() { return &m_eval; }
constexpr auto map() {
// We inspect m_eval to get the type, rank and dimensions, because it has the resulting tensor,
// whereas Derived is the tensor type _before_ whatever operation is pending (if any).
using DimType = typename decltype(m_eval)::Dimensions::Base;
constexpr auto rank = DimType{}.size();
using Scalar = typename Eigen::internal::remove_const<typename decltype(m_eval)::Scalar>::type;
return Eigen::TensorMap<Eigen::Tensor<Scalar, rank>>(m_eval.data(), m_eval.dimensions());
}
};
// Evaluates expressions if needed
template<typename T, typename Device = Eigen::DefaultDevice>
auto asEval(const Eigen::TensorBase<T, Eigen::ReadOnlyAccessors> &expr, // An Eigen::TensorBase object (Tensor, TensorMap, TensorExpr... )
const Device &device = Device()) { // Override to evaluate on another device, e.g. thread pool or gpu.
return selfCleaningEvaluator(expr, device);
}
// Converts any Eigen::Tensor (or expression) to an Eigen::Matrix with shape rows/cols
template<typename T, typename sizeType, typename Device = Eigen::DefaultDevice>
auto MatrixCast(const Eigen::TensorBase<T, Eigen::ReadOnlyAccessors> &expr, const sizeType rows, const sizeType cols, const Device &device = Device()) {
auto tensor = asEval(expr, device);
auto tensorMap = tensor.map();
using Scalar = typename decltype(tensorMap)::Scalar;
return static_cast<MatrixType<Scalar>>(Eigen::Map<const MatrixType<Scalar>>(tensorMap.data(), rows, cols));
}
// Converts any Eigen::Tensor (or expression) to an Eigen::Matrix with shape rows/cols
template<typename T, typename Device = Eigen::DefaultDevice>
auto VectorCast(const Eigen::TensorBase<T, Eigen::ReadOnlyAccessors> &expr, const Device &device = Device()) {
auto tensor = asEval(expr, device);
auto tensorMap = tensor.map();
auto size = Eigen::internal::array_prod(tensorMap.dimensions());
using Scalar = typename decltype(tensorMap)::Scalar;
return static_cast<VectorType<Scalar>>(Eigen::Map<const VectorType<Scalar>>(tensorMap.data(), size));
}
// View an existing Eigen::Tensor as an Eigen::Map<Eigen::Matrix>
template<typename Scalar, auto rank, typename sizeType>
auto MatrixMap(const Eigen::Tensor<Scalar, rank> &tensor, const sizeType rows, const sizeType cols) {
return Eigen::Map<const MatrixType<Scalar>>(tensor.data(), rows, cols);
}
// View an existing Eigen::Tensor of rank 2 as an Eigen::Map<Eigen::Matrix>
// Rows/Cols are determined from the matrix
template<typename Scalar>
auto MatrixMap(const Eigen::Tensor<Scalar, 2> &tensor) {
return Eigen::Map<const MatrixType<Scalar>>(tensor.data(), tensor.dimension(0), tensor.dimension(1));
}
// View an existing Eigen::Tensor of rank 1 as an Eigen::Map<Eigen::Vector>
// Rows is the same as the size of the tensor.
template<typename Scalar, auto rank>
auto VectorMap(const Eigen::Tensor<Scalar, rank> &tensor) {
return Eigen::Map<const VectorType<Scalar>>(tensor.data(), tensor.size());
}
/*
*
* Convert Eigen::Matrix --> Eigen::Tensor
*
*/
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions specified in std::array
template<typename Derived, typename T, auto rank>
Eigen::Tensor<typename Derived::Scalar, rank>
TensorCast(const Eigen::EigenBase<Derived> &matrix, const std::array<T, rank> &dims) {
return Eigen::TensorMap<const Eigen::Tensor<const typename Derived::Scalar, rank>>
(matrix.derived().eval().data(), dims);
}
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions specified in Eigen::DSizes
template<typename Derived, typename T, auto rank>
Eigen::Tensor<typename Derived::Scalar, rank>
TensorCast(const Eigen::EigenBase<Derived> &matrix, const Eigen::DSizes<T, rank> &dims) {
return Eigen::TensorMap<const Eigen::Tensor<const typename Derived::Scalar, rank>>
(matrix.derived().eval().data(), dims);
}
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions as variadic arguments
template<typename Derived, typename... Dims>
auto TensorCast(const Eigen::EigenBase<Derived> &matrix, const Dims... dims) {
static_assert(sizeof...(Dims) > 0, "TensorCast: sizeof... (Dims) must be larger than 0");
return TensorCast(matrix, std::array<Eigen::Index, sizeof...(Dims)>{dims...});
}
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions directly as arguments in a variadic template
template<typename Derived>
auto TensorCast(const Eigen::EigenBase<Derived> &matrix) {
if constexpr(Derived::ColsAtCompileTime == 1 or Derived::RowsAtCompileTime == 1) {
return TensorCast(matrix, matrix.size());
} else {
return TensorCast(matrix, matrix.rows(), matrix.cols());
}
}
// View an existing Eigen::Matrix as Eigen::TensorMap
// with dimensions specified in std::array
template<typename Derived, auto rank>
auto TensorMap(const Eigen::PlainObjectBase<Derived> &matrix, const std::array<long, rank> &dims) {
return Eigen::TensorMap<const Eigen::Tensor<const typename Derived::Scalar, rank>>(matrix.derived().data(), dims);
}
// View an existing Eigen::Matrix as Eigen::TensorMap
// with dimensions as variadic arguments
template<typename Derived, typename... Dims>
auto TensorMap(const Eigen::PlainObjectBase<Derived> &matrix, const Dims... dims) {
return TensorMap(matrix, std::array<long, static_cast<int>(sizeof...(Dims))>{dims...});
}
// View an existing Eigen::Matrix as Eigen::TensorMap
// with dimensions determined automatically from the given matrix
template<typename Derived>
auto TensorMap(const Eigen::PlainObjectBase<Derived> &matrix) {
if constexpr(Derived::ColsAtCompileTime == 1 or Derived::RowsAtCompileTime == 1) {
return TensorMap(matrix, matrix.size());
} else {
return TensorMap(matrix, matrix.rows(), matrix.cols());
}
}
int main () {
Eigen::Tensor<double,4> my_rank4 (2,2,2,2);
my_rank4.setRandom();
Eigen::MatrixXd mymatrix = MatrixCast(my_rank4, 4,4); // Cast Eigen::Tensor --> Eigen::Matrix
Eigen::Tensor<double,3> my_rank3 = TensorCast(mymatrix, 2,2,4); // Cast Eigen::Matrix --> Eigen::Tensor
std::cout << my_rank3 << std::endl;
return 0;
}
在对具有更多维度的 Tensor 进行一些操作后,我得到了 Eigen::Tensor<std::complex, 2>
。有没有简单的方法从这个张量对象创建一个 Eigen::MatrixXcf
还是我必须手动复制这些值?
原始答案。进一步查看更新。
我目前使用的是 Eigen 版本 3.3.4,没有简单的 built-in 函数可以在 Eigen::Tensor 类型和更熟悉的 Matrix 或 Array 类型之间进行转换。拥有 .matrix()
或 .array()
方法之类的东西会很方便。
也没有简单的方法add such methods via the plugin mechanism,因为张量模块似乎不支持插件。如果有人知道如何请评论。
同时,可以使用 Map 函数制定相当有效的解决方法。以下在 C++14 中工作,用于将张量转换为矩阵
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
template<typename T>
using MatrixType = Eigen::Matrix<T,Eigen::Dynamic, Eigen::Dynamic>;
template<typename Scalar,int rank, typename sizeType>
auto Tensor_to_Matrix(const Eigen::Tensor<Scalar,rank> &tensor,const sizeType rows,const sizeType cols)
{
return Eigen::Map<const MatrixType<Scalar>> (tensor.data(), rows,cols);
}
template<typename Scalar, typename... Dims>
auto Matrix_to_Tensor(const MatrixType<Scalar> &matrix, Dims... dims)
{
constexpr int rank = sizeof... (Dims);
return Eigen::TensorMap<Eigen::Tensor<const Scalar, rank>>(matrix.data(), {dims...});
}
int main () {
Eigen::Tensor<double,4> my_rank4 (2,2,2,2);
my_rank4.setRandom();
Eigen::MatrixXd mymatrix = Tensor_to_Matrix(my_rank4, 4,4);
Eigen::Tensor<double,3> my_rank3 = Matrix_to_Tensor(mymatrix, 2,2,4);
std::cout << my_rank3 << std::endl;
return 0;
}
这同样适用于复杂类型。
不幸的是,这些函数只接受张量,而不是张量运算。例如,这不起作用:
Eigen::MatrixXd mymatrix = Tensor_to_Matrix(my_rank4.shuffle(Eigen::array<long,4>{1,0,3,2}), 4,4);
2021 年 8 月更新:
内存泄漏已修复,请参阅下面的代码。简而言之,必须记住在 Eigen::TensorEvaluator 对象上调用 .cleanup()
成员函数来释放内部临时缓冲区。
2021 年 10 月更新:
自从我在 2018 年提交上述答案以来,我已经学会了如何使用最少的临时变量在 Eigen::Tensor
和 Eigen::Matrix
(及其表达式)之间进行映射和转换。
自 Eigen 3.3.7 使用 C++17 以来,我一直在使用下面的辅助函数
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
template<typename T>
using MatrixType = Eigen::Matrix<T,Eigen::Dynamic, Eigen::Dynamic>;
template<typename T>
using VectorType = Eigen::Matrix<T,Eigen::Dynamic, 1>;
/*
*
* Convert Eigen::Tensor --> Eigen::Matrix
*
*/
template<typename Derived, typename Device = Eigen::DefaultDevice>
class selfCleaningEvaluator {
private:
using Evaluator = Eigen::TensorEvaluator<const Eigen::TensorForcedEvalOp<const Derived>, Device>;
Evaluator m_eval;
public:
selfCleaningEvaluator(const Evaluator &eval) : m_eval(eval) {}
selfCleaningEvaluator(const Eigen::TensorBase<Derived, Eigen::ReadOnlyAccessors> &expr, const Device &device = Device())
: m_eval(Evaluator(expr.eval(), device)) {
m_eval.evalSubExprsIfNeeded(nullptr);
}
~selfCleaningEvaluator() {
// This whole point of this object is to call cleanup automatically on destruct.
// If there are pending operations to evaluate, m_eval will allocate a buffer to hold a result,
// which needs to be deallocated.
m_eval.cleanup();
}
constexpr auto rank() {
using DimType = typename decltype(m_eval)::Dimensions::Base;
return DimType{}.size(); // Because Derived::Dimensions is sometimes wrong
}
const Evaluator *operator->() const { return &m_eval; }
Evaluator *operator->() { return &m_eval; }
constexpr auto map() {
// We inspect m_eval to get the type, rank and dimensions, because it has the resulting tensor,
// whereas Derived is the tensor type _before_ whatever operation is pending (if any).
using DimType = typename decltype(m_eval)::Dimensions::Base;
constexpr auto rank = DimType{}.size();
using Scalar = typename Eigen::internal::remove_const<typename decltype(m_eval)::Scalar>::type;
return Eigen::TensorMap<Eigen::Tensor<Scalar, rank>>(m_eval.data(), m_eval.dimensions());
}
};
// Evaluates expressions if needed
template<typename T, typename Device = Eigen::DefaultDevice>
auto asEval(const Eigen::TensorBase<T, Eigen::ReadOnlyAccessors> &expr, // An Eigen::TensorBase object (Tensor, TensorMap, TensorExpr... )
const Device &device = Device()) { // Override to evaluate on another device, e.g. thread pool or gpu.
return selfCleaningEvaluator(expr, device);
}
// Converts any Eigen::Tensor (or expression) to an Eigen::Matrix with shape rows/cols
template<typename T, typename sizeType, typename Device = Eigen::DefaultDevice>
auto MatrixCast(const Eigen::TensorBase<T, Eigen::ReadOnlyAccessors> &expr, const sizeType rows, const sizeType cols, const Device &device = Device()) {
auto tensor = asEval(expr, device);
auto tensorMap = tensor.map();
using Scalar = typename decltype(tensorMap)::Scalar;
return static_cast<MatrixType<Scalar>>(Eigen::Map<const MatrixType<Scalar>>(tensorMap.data(), rows, cols));
}
// Converts any Eigen::Tensor (or expression) to an Eigen::Matrix with shape rows/cols
template<typename T, typename Device = Eigen::DefaultDevice>
auto VectorCast(const Eigen::TensorBase<T, Eigen::ReadOnlyAccessors> &expr, const Device &device = Device()) {
auto tensor = asEval(expr, device);
auto tensorMap = tensor.map();
auto size = Eigen::internal::array_prod(tensorMap.dimensions());
using Scalar = typename decltype(tensorMap)::Scalar;
return static_cast<VectorType<Scalar>>(Eigen::Map<const VectorType<Scalar>>(tensorMap.data(), size));
}
// View an existing Eigen::Tensor as an Eigen::Map<Eigen::Matrix>
template<typename Scalar, auto rank, typename sizeType>
auto MatrixMap(const Eigen::Tensor<Scalar, rank> &tensor, const sizeType rows, const sizeType cols) {
return Eigen::Map<const MatrixType<Scalar>>(tensor.data(), rows, cols);
}
// View an existing Eigen::Tensor of rank 2 as an Eigen::Map<Eigen::Matrix>
// Rows/Cols are determined from the matrix
template<typename Scalar>
auto MatrixMap(const Eigen::Tensor<Scalar, 2> &tensor) {
return Eigen::Map<const MatrixType<Scalar>>(tensor.data(), tensor.dimension(0), tensor.dimension(1));
}
// View an existing Eigen::Tensor of rank 1 as an Eigen::Map<Eigen::Vector>
// Rows is the same as the size of the tensor.
template<typename Scalar, auto rank>
auto VectorMap(const Eigen::Tensor<Scalar, rank> &tensor) {
return Eigen::Map<const VectorType<Scalar>>(tensor.data(), tensor.size());
}
/*
*
* Convert Eigen::Matrix --> Eigen::Tensor
*
*/
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions specified in std::array
template<typename Derived, typename T, auto rank>
Eigen::Tensor<typename Derived::Scalar, rank>
TensorCast(const Eigen::EigenBase<Derived> &matrix, const std::array<T, rank> &dims) {
return Eigen::TensorMap<const Eigen::Tensor<const typename Derived::Scalar, rank>>
(matrix.derived().eval().data(), dims);
}
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions specified in Eigen::DSizes
template<typename Derived, typename T, auto rank>
Eigen::Tensor<typename Derived::Scalar, rank>
TensorCast(const Eigen::EigenBase<Derived> &matrix, const Eigen::DSizes<T, rank> &dims) {
return Eigen::TensorMap<const Eigen::Tensor<const typename Derived::Scalar, rank>>
(matrix.derived().eval().data(), dims);
}
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions as variadic arguments
template<typename Derived, typename... Dims>
auto TensorCast(const Eigen::EigenBase<Derived> &matrix, const Dims... dims) {
static_assert(sizeof...(Dims) > 0, "TensorCast: sizeof... (Dims) must be larger than 0");
return TensorCast(matrix, std::array<Eigen::Index, sizeof...(Dims)>{dims...});
}
// Converts an Eigen::Matrix (or expression) to Eigen::Tensor
// with dimensions directly as arguments in a variadic template
template<typename Derived>
auto TensorCast(const Eigen::EigenBase<Derived> &matrix) {
if constexpr(Derived::ColsAtCompileTime == 1 or Derived::RowsAtCompileTime == 1) {
return TensorCast(matrix, matrix.size());
} else {
return TensorCast(matrix, matrix.rows(), matrix.cols());
}
}
// View an existing Eigen::Matrix as Eigen::TensorMap
// with dimensions specified in std::array
template<typename Derived, auto rank>
auto TensorMap(const Eigen::PlainObjectBase<Derived> &matrix, const std::array<long, rank> &dims) {
return Eigen::TensorMap<const Eigen::Tensor<const typename Derived::Scalar, rank>>(matrix.derived().data(), dims);
}
// View an existing Eigen::Matrix as Eigen::TensorMap
// with dimensions as variadic arguments
template<typename Derived, typename... Dims>
auto TensorMap(const Eigen::PlainObjectBase<Derived> &matrix, const Dims... dims) {
return TensorMap(matrix, std::array<long, static_cast<int>(sizeof...(Dims))>{dims...});
}
// View an existing Eigen::Matrix as Eigen::TensorMap
// with dimensions determined automatically from the given matrix
template<typename Derived>
auto TensorMap(const Eigen::PlainObjectBase<Derived> &matrix) {
if constexpr(Derived::ColsAtCompileTime == 1 or Derived::RowsAtCompileTime == 1) {
return TensorMap(matrix, matrix.size());
} else {
return TensorMap(matrix, matrix.rows(), matrix.cols());
}
}
int main () {
Eigen::Tensor<double,4> my_rank4 (2,2,2,2);
my_rank4.setRandom();
Eigen::MatrixXd mymatrix = MatrixCast(my_rank4, 4,4); // Cast Eigen::Tensor --> Eigen::Matrix
Eigen::Tensor<double,3> my_rank3 = TensorCast(mymatrix, 2,2,4); // Cast Eigen::Matrix --> Eigen::Tensor
std::cout << my_rank3 << std::endl;
return 0;
}