首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >一般产品中的特征自动类型推导

一般产品中的特征自动类型推导
EN

Stack Overflow用户
提问于 2014-11-02 22:57:25
回答 2查看 1.4K关注 0票数 4

我有下面的代码(为稍微大一点的代码片段道歉,这是我能够将问题降到最低限度的例子):

代码语言:javascript
复制
#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与大小D一起作为参数,并在表达式A的标量字段上生成标识矩阵。这一功能本身运作良好。然而,当我把它用在auto推导型的特征乘积中时,例如在直线auto autoresult = Id(Foo, 4) * v中,我期望将向量v乘以恒等式矩阵,因此最终结果应该是一个表达式,在求值时,应该与v完全相等。但情况并非如此,请参见第一个for循环,每当我显示结果并计算其规范时,我就会得到大部分时间的垃圾。另一方面,如果我将本征乘积Id(Foo, 4) * v隐式地转换为一个动态矩阵,那么一切都很好,结果就会得到适当的评估。

我在上使用了特征3.2.2,并在g++4.9.1和Apple版本6.0 (clang-600.0.54) (基于LLVM 3.5svn)中得到了相同的奇怪行为。

问题:

  • 我不明白在第一个for循环中发生了什么,为什么当我使用std::cout,甚至当我使用norm方法时,产品没有被评估?我是不是遗漏了什么?这里不涉及别名问题,我对发生了什么事感到非常困惑。我知道特征使用懒惰的计算,并在需要时对表达式进行评估,但这里的情况似乎并非如此。这个问题对我来说是非常重要的,因为我有许多和Id<>()一样味道的函数,当在auto中使用时,推导出的表达式可能会失败。

这个问题经常发生,但并不总是发生。然而,如果你运行程序3-4次,你肯定会看到它。

我用来编译和运行它的命令是:

代码语言:javascript
复制
clang++ (g++) -std=c++11 -isystem ./eigen_3.2.2/ testeigen.cpp -otesteigen; ./testeigen

我在实际运行中得到的一个典型输出是:

代码语言:javascript
复制
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

即使我在

代码语言:javascript
复制
  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

我也有同样奇怪的行为。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-14 07:50:09

问题是Id()返回一个临时的,它通过引用存储在表示表达式Id(Foo, 4) * v的对象中。因此,在auto语句之后,autoresult存储对死对象的引用。如果不需要抽象表达式,但需要实际结果,则不要使用auto或调用eval来强制计算:

代码语言:javascript
复制
auto autoresult = (Id(Foo, 4) * v).eval();

第三种选择是使Id()返回的对象可供进一步计算:

代码语言:javascript
复制
auto id4 = Id(Foo,4);
auto autoresult = id4 * v;

但在这种情况下,无论何时使用autoresult,产品都会被重新评估,下面的结果会有所不同:

代码语言:javascript
复制
cout << autoresult;
v.setRandom();
cout << autoresult;
票数 3
EN

Stack Overflow用户

发布于 2014-11-02 23:02:44

它可能有一个只对计算一次安全的惰性计算类型。你可以用以下方法捕捉到它:

代码语言:javascript
复制
auto autoresultmatrix = autoresult.eval()
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26705446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档