如何在不指定维数的情况下用 Eigen 声明张量?
How to declare a tensor with Eigen without specifying the dimension?
我有一个函数将 n 维张量作为输入,我必须存储这个张量以便以后重用。
但是,我事先并不知道我的张量的维度。
我想这样做:
//in class.h
Eigen::Tensor<double, N> mytensor;
//in class.cpp
mytensor = input;
有办法吗?
由于参数N
是非类型模板参数,它必须是编译时已知的值。这意味着您不能真正在变量中存储未指定 N
的 Eigen::Tensor
,因为每个具有不同大小的实例都是不同的类型。
您可以使用 std::variant
和 std::any
等容器解决此问题。它们使得可以分别存储来自封闭类型集或任何类型的类型的对象。例如,您可以使用 std::any
创建一个助手 tensor_holder
class,如下所示:
template <typename T>
class tensor_holder
{
private:
std::any _held;
size_t _size;
public:
template <int N>
constexpr tensor_holder(Eigen::Tensor<T, N> tensor) :
_held{std::move(tensor)},
_size{N}
{
}
constexpr tensor_holder(const tensor_holder&) = default;
constexpr tensor_holder(tensor_holder&&) = default;
template <size_t N>
Eigen::Tensor<T, N>& get()
{
return std::any_cast<Eigen::Tensor<T, N>&>(_held);
}
template <size_t N>
const Eigen::Tensor<T, N>& get() const
{
return std::any_cast<Eigen::Tensor<T, N>&>(_held);
}
constexpr int size() const noexcept
{
return _size;
}
};
它将任意大小的 Eigen::Tensor
存储在 std::any
中。如果提供的大小不匹配,成员函数 get
将抛出 std::bad_any_cast
实际张量大小(请注意,作为编译时值的大小限制不会消失)。
假设您有一小组可能的张量大小,您可以 运行 函数内的不同分支,如下所示:
void use_tensor(const tensor_holder<double>& in)
{
static tensor_holder held = in; // it can be stored for later
if (held.size() == 4)
{
auto& tensor = held.get<4>();
tensor(0, 1, 2, 3) = 115.5;
}
else if (held.size() == 3)
{
// some other logic
}
}
在这种情况下,您也可以使用 switch
而不是 if
。仅当您必须支持的不同张量大小的数量很少时,此解决方案才实用。我不知道你打算如何使用你的张量,所以我很难说这个解决方案是否足够。
多亏了 class tensor_holder
的转换构造函数,您可以通过简单地为它提供任意大小的 Eigen::Tensor
来调用该函数:
use_tensor(Eigen::Tensor<double, 3>{});
(godbolt)
我有一个函数将 n 维张量作为输入,我必须存储这个张量以便以后重用。 但是,我事先并不知道我的张量的维度。 我想这样做:
//in class.h
Eigen::Tensor<double, N> mytensor;
//in class.cpp
mytensor = input;
有办法吗?
由于参数N
是非类型模板参数,它必须是编译时已知的值。这意味着您不能真正在变量中存储未指定 N
的 Eigen::Tensor
,因为每个具有不同大小的实例都是不同的类型。
您可以使用 std::variant
和 std::any
等容器解决此问题。它们使得可以分别存储来自封闭类型集或任何类型的类型的对象。例如,您可以使用 std::any
创建一个助手 tensor_holder
class,如下所示:
template <typename T>
class tensor_holder
{
private:
std::any _held;
size_t _size;
public:
template <int N>
constexpr tensor_holder(Eigen::Tensor<T, N> tensor) :
_held{std::move(tensor)},
_size{N}
{
}
constexpr tensor_holder(const tensor_holder&) = default;
constexpr tensor_holder(tensor_holder&&) = default;
template <size_t N>
Eigen::Tensor<T, N>& get()
{
return std::any_cast<Eigen::Tensor<T, N>&>(_held);
}
template <size_t N>
const Eigen::Tensor<T, N>& get() const
{
return std::any_cast<Eigen::Tensor<T, N>&>(_held);
}
constexpr int size() const noexcept
{
return _size;
}
};
它将任意大小的 Eigen::Tensor
存储在 std::any
中。如果提供的大小不匹配,成员函数 get
将抛出 std::bad_any_cast
实际张量大小(请注意,作为编译时值的大小限制不会消失)。
假设您有一小组可能的张量大小,您可以 运行 函数内的不同分支,如下所示:
void use_tensor(const tensor_holder<double>& in)
{
static tensor_holder held = in; // it can be stored for later
if (held.size() == 4)
{
auto& tensor = held.get<4>();
tensor(0, 1, 2, 3) = 115.5;
}
else if (held.size() == 3)
{
// some other logic
}
}
在这种情况下,您也可以使用 switch
而不是 if
。仅当您必须支持的不同张量大小的数量很少时,此解决方案才实用。我不知道你打算如何使用你的张量,所以我很难说这个解决方案是否足够。
多亏了 class tensor_holder
的转换构造函数,您可以通过简单地为它提供任意大小的 Eigen::Tensor
来调用该函数:
use_tensor(Eigen::Tensor<double, 3>{});
(godbolt)