2014-11-02 2 views
3

я следующий кусок кода (Извиняюсь за несколько больший код сниппета, это минимальный пример, который я смог уменьшить мою проблему к):собственный автоматический тип вычет в общем продукте

#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<>() принимает значение Eigen A в качестве параметра вместе с размером D и создает идентификационную матрицу над скалярным полем выражения A. Эта функция сама по себе отлично работает. Тем не менее, , когда я использую его в качестве продукта Эйгена с auto выведенного типа, например, в линии auto autoresult = Id(Foo, 4) * v, я ожидал бы умножать вектор v единичной матрицы, так что чистый результат должен быть выражением, которое, когда оценивается, должно быть тождественно равным v. Но это не так, см. Первый цикл for, всякий раз, когда я показываю результат и вычисляет его норму, Я получаю большую часть времени мусор. Если, с другой стороны, я неявно отбрасываю собственный продукт Id(Foo, 4) * v в динамическую матрицу, все работает нормально, результат правильно оценивается.

Я использую Эйгена 3.2.2 на OS X Yosemite, и получить такое же странное поведение как с г ++ 4.9.1 и компании Apple LLVM версии 6,0 (Звон-600.0.54) (на основе LLVM 3.5svn)

ВОПРОС:

  • Я не понимаю, что происходит в первом цикле for, почему не продукт оценивали при использовании std::cout, или даже когда я использовать norm встретились корыто? Я что-то упускаю? Здесь нет никакого псевдонима , и я действительно озадачен тем, что происходит. Я знаю , что Eigen использует ленивую оценку и вычисляет выражение, когда требуется , но это, похоже, не так. Эта проблема чрезвычайно важна для меня, так как у меня есть множество функций того же аромата, как Id<>(), который при использовании в auto выведенных выражениях может не работать.

Проблема возникает довольно часто, но не всегда. Однако, если вы запустите программу 3-4 раза, вы обязательно ее увидите.

Команда Я использую для компиляции и запуска это:

clang++ (g++) -std=c++11 -isystem ./eigen_3.2.2/ testeigen.cpp -otesteigen; ./testeigen 

Типичный выход я в реальной перспективе является:

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 

Даже если я использую eval() в

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 

У меня такое же странное поведение.

ответ

2

Проблема заключается в том, что Id() возвращает временный, который хранится в виде ссылки в объект, представляющий выражение Id(Foo, 4) * v. Таким образом, после автоматического объявления autoresult хранит ссылку на мертвый объект. Если вы не хотите, абстрактное выражение, но фактический результат, не используйте auto или позвоните eval для обеспечения оценки:

auto autoresult = (Id(Foo, 4) * v).eval(); 

Третий вариант, чтобы сделать объект, возвращаемый Id() можно использовать для дальнейших вычислений:

auto id4 = Id(Foo,4); 
auto autoresult = id4 * v; 

, но в этом случае, в любое время вы используете autoresult тогда продукт будет повторно оценивать и следующие выходные будут разные результаты:

cout << autoresult; 
v.setRandom(); 
cout << autoresult; 
+0

Спасибо большое! Один последний вопрос: не временный объект, хранящийся через привязку ссылки const к временному, поэтому время жизни временного объекта совпадает с временем жизни выражения? – vsoftco

+0

Да, временная информация хранится с помощью ссылки на константу, но это не продлевает срок ее службы, поскольку существует одно косвенное направление. Этот механизм расширения продолжительности жизни не является транзитивным. – ggael

+0

спасибо, получилось. – vsoftco

1

У этого, вероятно, есть ленивый тип оценки, который можно только оценить один раз.Вы могли бы захватить его:

auto autoresultmatrix = autoresult.eval() 
+0

Спасибо, я знаю, что если я принудительно оцениваю, он работает (при выполнении броска оценка принудительно), однако это делает код намного более уродливым вообще, особенно при работе со сложными выражениями. Мне хотелось бы написать что-то вроде 'myfunc (A * A + BC)', где 'myfunc' - некоторая функция, которая принимает выражение Eigen и выплескивает результат вычисления как динамическую матрицу, и я, хотя это отлично использовать его позже в выражениях типа myfunc (A * A + BC) * D', без необходимости 'eval'. Особенно при вызове таких методов, как 'norm', которые ДОЛЖНЫ принудительно оценивать. – vsoftco

+0

@vsoftco Печать транспонирования + печать оценивает и потребляет результат. Если бы вы сначала выполнили эту норму, это сработало бы. Я предложил eval, потому что я думал, что ваша проблема неспособна использовать авто. –

+0

И даже если я сначала делаю 'std :: cout << result.norm()', все равно получаю то же поведение, то есть отображается мусор. – vsoftco