一般产品的特征自动扣除 [英] eigen auto type deduction in general product
问题描述
我有下面的代码(对于稍大的代码
snippet,我这样做是道歉的,这是我能够减少我的问题的最小示例):
I have the following piece of code (I apologize for the slightly larger code snippet, this is the minimal example I was able to reduce my problem to):
#include <Eigen/Dense>
#include <complex>
#include <iostream>
#include <typeinfo>
// Dynamic Matrix over Scalar field
template <typename Scalar>
using DynMat = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
// Dynamic column vector over Scalar field
template <typename Scalar>
using DynVect = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
// Returns the D x D Identity matrix over the field Derived::Scalar
// deduced from the expression Eigen::MatrixBase<Derived>& A
template<typename Derived>
DynMat<typename Derived::Scalar> Id(const Eigen::MatrixBase<Derived>& A, std::size_t D)
{
DynMat<typename Derived::Scalar> result =
DynMat<typename Derived::Scalar>::Identity(D, D);
return result;
}
int main()
{
//using ScalarField = std::complex<double>; // same issue even if I use complex numbers
using ScalarField = double; // we use doubles in this example
// A double dynamic matrix (i.e. MatrixXd)
DynMat<ScalarField> Foo; // used to deduce the type in Id<>()
// A double dynamic column vector (i.e. VectorXd)
DynVect<ScalarField> v(4);
v << 1., 0. , 0. ,0.; // plug in some values into it
// Make sure that Id(Foo, 4) correctly deduces the template parameters
std::cout << "Id(Foo, 4) is indeed the 4 x 4 identiy matrix over the ScalarField of "
<< "typeid().name(): " << typeid(ScalarField).name() << std::endl;
std::cout << Id(Foo, 4) << std::endl; // Indeed the 4 x 4 complex Identity matrix
// Use auto type deduction for GenMatProduct, junk is displayed. Why?!
std::cout << std::endl << "Use auto type deduction for GenMatProduct,\
sometimes junk is displayed. Why?!" << std::endl;
auto autoresult = Id(Foo, 4) * v; // evaluated result must be identically equal to v
for(int i=0; i<10; i++)
{
std::cout << autoresult.transpose(); // thought 1 0 0 0 is the result, but NO, junk
std::cout << " has norm: " << autoresult.norm() << std::endl; // junk
}
// Use implicit cast to Dynamic Matrix, works fine
std::cout << std::endl << "Use implicit cast to Dynamic Matrix, works fine" << std::endl;
DynMat<ScalarField> castresult = Id(Foo, 4) * v; // evaluated result must be identically equal to v
for(int i=0; i<10; i++)
{
std::cout << castresult.transpose(); // 1 0 0 0, works ok
std::cout << " has norm: " << castresult.norm() << std::endl; // ok
}
}
主要思想是模板函数 Id<>()
采用特征表达式 A
作为参数, code> D ,并且在表达式 A
的标量字段上产生单位矩阵
。这个函数本身工作正常。但是,当我在一个Eigen产品中使用 auto
推导类型时,如
auto autoresult = Id(Foo,4)* v
,我希望将向量 v
乘以单位矩阵,应该是一个表达式,
在计算时应该等于 v
。但是不是这样的,
每次显示结果并计算其范数时,看到第一个 for
循环,
我得到大多数时间垃圾。如果,另一方面,我隐式地转换
的特征产品 Id(Foo,4)* v
到动态矩阵,一切都很好,
结果被正确评估。
The main idea is that the template function Id<>()
takes an Eigen expression A
as a parameter, together with a size D
, and produces the identity matrix
over the scalar field of the expression A
. This function by itself works fine. However,
when I use it in an Eigen product with auto
deduced type, such as in the line
auto autoresult = Id(Foo, 4) * v
, I would expect to multiply the vector v
by the identity matrix, so the net result should be an expression which,
when evaluated, should be identically equal to v
. But this is not the case,
see the first for
loop, whenever I display the result and computes its norm,
I get most of the time junk. If, on the other hand, I implicitly cast
the Eigen product Id(Foo, 4) * v
to a dynamic matrix, everything works fine,
the result is properly evaluated.
我在OS X Yosemite上使用Eigen 3.2.2,并使用g ++ 4.9.1和
获得相同的奇怪的
行为Apple LLVM版本6.0(clang-600.0.54)(基于LLVM 3.5svn)
I use Eigen 3.2.2 on OS X Yosemite, and get the same weird behaviour both with g++4.9.1 and Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
QUESTION:
- 我不明白在
中的
循环中发生了什么,为什么
不是被评估的产品当我使用std :: cout
,或者甚至当I
使用norm
方法时?我缺少什么?这里没有别名
,我真的很困惑的是发生了什么。我知道
Eigen使用延迟评估,并评估
需要时的表达式,但这似乎不是这里的情况。这个问题是
对我非常重要,因为我有很多与$Id<>()
相同的
风格的函数,auto
推导出的表达式
可能会失败。
- I do not understand what is happening in the first
for
loop, why isn't the product evaluated when I usestd::cout
, or even when I use thenorm
method? Am I missing something? There is no aliasing involved here, and I am really puzzled by what is going on. I know that Eigen uses lazy evaluation, and evaluates the expression when needed, but this doesn't seem to be the case here. This problem is extremely important for me, as I have lots of functions of the same flavour asId<>()
, which when used inauto
deduced expressions may fail.
经常,但不总是。但是,如果你运行
程序3-4次,你肯定会看到它。
The problem occurs quite often, but not always. However, if you run the program 3-4 times, you will definitely see it.
我用来编译和运行它的命令是: p>
The command I use to compile and run it is:
clang++ (g++) -std=c++11 -isystem ./eigen_3.2.2/ testeigen.cpp -otesteigen; ./testeigen
我在真实运行中得到的典型输出是:
A typical output I got in a real run is:
Id(Foo, 4) is indeed the 4 x 4 identiy matrix over the ScalarField of typeid().name(): d
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
Use GenMatProduct, sometimes junk is displayed. Why?!
1 0 0 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
3.10504e+231 3.10504e+231 3.95253e-323 0 has norm: inf
Use implicit cast to Dynamic Matrix, works fine
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
1 0 0 0 has norm: 1
即使我在
std::cout << autoresult.eval().transpose(); // thought 1 0 0 0 is the result, but NO, junk
std::cout << " has norm: " << autoresult.eval().norm() << std::endl; // junk
我得到了相同的怪异行为。
I am getting the same weird behaviour.
推荐答案
问题是 Id()
返回一个临时通过引用存储在表示 Id(Foo,4)* v
的对象中。因此,在auto语句之后, autoresult
存储对死对象的引用。如果你不想要一个抽象表达式但实际结果,不要使用 auto
或调用 eval
来强制执行评估:
The problem is that Id()
returns a temporary which is stored by reference in the object representing the expression Id(Foo, 4) * v
. Thus after the auto statement, autoresult
stores a reference to a dead object. If you do not want an abstract expression but the actual result, do not use auto
or call eval
to enforce evaluation:
auto autoresult = (Id(Foo, 4) * v).eval();
第三个选项是使 Id code>可用于进一步的计算:
A third option is to make the object returned by Id()
available for further computations:
auto id4 = Id(Foo,4);
auto autoresult = id4 * v;
但在这种情况下,只要使用 autoresult
然后产品将被重新评估,并且以下将输出不同的结果:
but in this case, anytime you use autoresult
then the product will be re-evaluated and the following will output different results:
cout << autoresult;
v.setRandom();
cout << autoresult;
这篇关于一般产品的特征自动扣除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!