一般产品的特征自动扣除 [英] eigen auto type deduction in general product

查看:121
本文介绍了一般产品的特征自动扣除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的代码(对于稍大的代码
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 use std::cout, or even when I use the norm 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 as Id<>(), which when used in auto 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆