eigen Auto-Typ-Abzug im Allgemeinen Produkt

Ich habe den folgenden Code (ich entschuldige mich für das etwas größere Code-Snippet, dies ist das minimale Beispiel, auf das ich mein Problem reduzieren konnte):

#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
    }
}

Die Hauptidee ist, dass die Template-FunktionId<>() nimmt einen Eigen-Ausdruck anA als Parameter, zusammen mit einer GrößeD und erzeugt die Identitätsmatrix über dem Skalarfeld des AusdrucksA. Diese Funktion selbst funktioniert gut. Wenn ich es jedoch in einem Eigen-Produkt mit @ verwenauto Abgeleiteter Typ, z. B. in der Zeileauto autoresult = Id(Foo, 4) * v, Ich würde erwarten, den Vektor zu multiplizierenv durch die Identitätsmatrix, also sollte das Nettoergebnis ein Ausdruck sein, der bei der Auswertung identisch mit @ sein sollv. Dies ist aber nicht der Fall, siehe das erstefor loop, wenn ich das Ergebnis anzeige und seine Norm berechne, bekomme ich die meiste Zeit Müll. Wenn ich dagegen implizit das EigenproduktId(Foo, 4) * v zu einer dynamischen Matrix, alles funktioniert gut, das Ergebnis wird richtig ausgewertet.

Ich verwende Eigen 3.2.2 unter OS X Yosemite und erhalte dasselbe seltsame Verhalten sowohl mit g ++ 4.9.1 als auch mit Apple LLVM Version 6.0 (clang-600.0.54) (basierend auf LLVM 3.5svn).

FRAGE

Ich verstehe nicht, was im ersten @ passiefor loop, warum wird das Produkt nicht bewertet, wenn ich @ verwenstd::cout, oder auch wenn ich das @ benutnorm Methode? Vermisse ich etwas? Hier gibt es kein Aliasing, und ich bin wirklich verwirrt darüber, was los ist. Ich weiß, dass Eigen eine faule Auswertung verwendet und den Ausdruck bei Bedarf auswertet, aber dies scheint hier nicht der Fall zu sein. Dieses Problem ist für mich extrem wichtig, da ich viele Funktionen mit dem gleichen Geschmack wie @ habId<>(), welches bei Verwendung inauto Abgeleitete Ausdrücke können fehlschlagen.

Das Problem tritt ziemlich oft auf, aber nicht immer. Wenn Sie das Programm jedoch 3-4 Mal ausführen, wird es auf jeden Fall angezeigt.

Der Befehl, den ich zum Kompilieren und Ausführen verwende, lautet:

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

Eine typische Ausgabe, die ich in einem echten Lauf bekam, ist:

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

Auch wenn ich @ benuteval() i

  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

Ich bekomme das selbe seltsame Verhalten.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage