Eigen sparse solver resultados errados

Aug 26 2020

Estou tentando resolver um sistema linear esparso Ax=B com a biblioteca Eigen em C++, porém o seguinte exemplo trivial parece dar uma solução incorreta:

#include <Eigen/SparseCholesky>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <iostream>
#include <vector>

using namespace std;
using namespace Eigen;

int main(){

    SimplicialLDLT<SparseMatrix<double>> solver;
    SparseMatrix<double> A(9,9);
    typedef Triplet<double> T;
    vector<T> triplet;
    VectorXd B(9);

    for(int i=0; i<4; i++){
        triplet.push_back(T(i,i,1));
        triplet.push_back(T(i+5,i+5,1));
    }

    triplet.push_back(T(4,1,-1));
    triplet.push_back(T(4,3,-1));
    triplet.push_back(T(4,5,-1));
    triplet.push_back(T(4,7,-1));
    triplet.push_back(T(4,4,4));

    A.setFromTriplets(triplet.begin(),triplet.end());
    B << 0,0,0,0,0.387049,0,0,0,0;

    solver.compute(A);
    VectorXd x = solver.solve(B);

    cout << "A\n" << A << "\n";
    cout << "B\n" << B << "\n";
    cout << "x\n" << x << "\n";

    return 0;
}

Não vejo nenhum erro, o algoritmo retorna "0" que significa "Sucesso", porém a solução que recebo é

x = 0 0.193524 0 0.193524 0.193524 0 0 0 0

que obviamente não é a solução para este sistema, o correto é

x = 0 0 0 0 0.0967621 0 0 0 0

Respostas

4 Soonts Aug 26 2020 at 04:24

Aqui está a documentação para o SimplicialLDLTsolucionador:

Esta classe fornece fatorações LDL^T Cholesky sem raiz quadrada de matrizes esparsas que são autoadjuntas e definidas positivas .

Quando a matriz armazena números reais nos elementos, auto-adjunto == simétrico. Sua matriz claramente não é simétrica. Além disso, nem toda matriz simétrica é definida positiva, veja exemplos .

Resumindo, o solucionador que você escolheu só é aplicável a classes muito restritas de matrizes. Como você já descobriu, SparseLUo solver funciona para seus dados de entrada.

ConjugateGradientO solver também não funcionará, não requer que a matriz seja definida positiva, mas requer que seja auto-adjunta.