C++ 用armadillo创建的Pardiso求解稀疏矩阵方程

C++ 用armadillo创建的Pardiso求解稀疏矩阵方程,c++,matrix,sparse-matrix,armadillo,pardiso,C++,Matrix,Sparse Matrix,Armadillo,Pardiso,我想使用MKL中的Pardiso解算器,而不是内置稀疏矩阵解算器。为此,我首先在犰狳中创建矩阵,然后将其转换为CSC矩阵,并将其放入Pardiso解算器中。我的代码是 int main() { /* Matrix data. */ MKL_INT n = 8; arma::sp_mat single_mat = arma::sp_mat(n, n); single_mat.diag(-2).fill(1); single_mat.diag(-1).fill

我想使用MKL中的Pardiso解算器,而不是内置稀疏矩阵解算器。为此,我首先在犰狳中创建矩阵,然后将其转换为CSC矩阵,并将其放入Pardiso解算器中。我的代码是

int main()
{
    /* Matrix data. */
    MKL_INT n = 8;
    arma::sp_mat single_mat = arma::sp_mat(n, n);
    single_mat.diag(-2).fill(1);
    single_mat.diag(-1).fill(-8);
    single_mat.diag(0).fill(0);
    single_mat.diag(1).fill(8);
    single_mat.diag(2).fill(-1);
    single_mat = single_mat / 0.0012;
    std::cout << "Number of nonzeros: " << single_mat.n_nonzero << '\n';
    std::cout << "Number of n_cols: " << single_mat.n_cols << '\n';
    MKL_INT *ia = new MKL_INT[single_mat.n_cols+1];
    MKL_INT *ja = new MKL_INT[single_mat.n_nonzero];
    double *a = new double[single_mat.n_nonzero];
    for (size_t i = 0; i < single_mat.n_nonzero; i++)
        ja[i] = single_mat.row_indices[i];
    for (size_t i = 0; i < single_mat.n_nonzero; i++)
        a[i] = single_mat.values[i];
    for (size_t i = 0; i < single_mat.n_cols+1; i++)
        ia[i] = single_mat.col_ptrs[i];


    std::cout << "\n" << arma::mat(single_mat) << "\n";

    MKL_INT mtype = 11;       /* Real symmetric matrix */
                              /* RHS and solution vectors. */
    double *b = new double[n], *x = new double[n], *bs = new double[n], res, res0;
    bs[0] = 0;
    bs[1] = 0;
    MKL_INT nrhs = 1;     /* Number of right hand sides. */
                          /* Internal solver memory pointer pt, */
                          /* 32-bit: int pt[64]; 64-bit: long int pt[64] */
                          /* or void *pt[64] should be OK on both architectures */
    void *pt[64];
    /* Pardiso control parameters. */
    MKL_INT iparm[64];
    MKL_INT maxfct, mnum, phase, error, msglvl;
    /* Auxiliary variables. */
    MKL_INT i;
    double ddum;          /* Double dummy */
    MKL_INT idum;         /* Integer dummy. */
                          /* -------------------------------------*/
                          /* .. Setup Pardiso control parameters. */
                          /* -------------------------------------*/
    for (i = 0; i < 64; i++)
    {
        iparm[i] = 0;
    }
    iparm[0] = 1;         /* No solver default */
    iparm[1] = 2;         /* Fill-in reordering from METIS */
    iparm[3] = 0;         /* No iterative-direct algorithm */
    iparm[4] = 0;         /* No user fill-in reducing permutation */
    iparm[5] = 0;         /* Write solution into x */
    iparm[7] = 2;         /* Max numbers of iterative refinement steps */
    iparm[9] = 13;        /* Perturb the pivot elements with 1E-13 */
    iparm[10] = 1;        /* Use nonsymmetric permutation and scaling MPS */
    iparm[12] = 0;        /* Maximum weighted matching algorithm is switched-off (default for symmetric). Try iparm[12] = 1 in case of inappropriate accuracy */
    iparm[13] = 0;        /* Output: Number of perturbed pivots */
    iparm[17] = -1;       /* Output: Number of nonzeros in the factor LU */
    iparm[18] = -1;       /* Output: Mflops for LU factorization */
    iparm[19] = 0;        /* Output: Numbers of CG Iterations */
    iparm[26] = 1;        /* Checks if matrix is correct*/
    iparm[34] = 1;        /* PARDISO use C-style indexing for ia and ja arrays */
    maxfct = 1;           /* Maximum number of numerical factorizations. */
    mnum = 1;         /* Which factorization to use. */
    msglvl = 0;           /* Print statistical information in file */
    error = 0;            /* Initialize error flag */
                          /* ----------------------------------------------------------------*/
                          /* .. Initialize the internal solver memory pointer. This is only  */
                          /*   necessary for the FIRST call of the PARDISO solver.           */
                          /* ----------------------------------------------------------------*/
    for (i = 0; i < 64; i++)
    {
        pt[i] = 0;
    }
    /* --------------------------------------------------------------------*/
    /* .. Reordering and Symbolic Factorization. This step also allocates  */
    /*    all memory that is necessary for the factorization.              */
    /* --------------------------------------------------------------------*/
    phase = 11;
    PARDISO(pt, &maxfct, &mnum, &mtype, &phase,
        &n, a, ia, ja, &idum, &nrhs, iparm, &msglvl, &ddum, &ddum, &error);
    if (error != 0)
    {
        printf("\nERROR during symbolic factorization: %d", error);
        exit(1);
    }
    printf("\nReordering completed ... ");
    printf("\nNumber of nonzeros in factors = %d", iparm[17]);
    printf("\nNumber of factorization MFLOPS = %d", iparm[18]);
    /* ----------------------------*/
    /* .. Numerical factorization. */
    /* ----------------------------*/
    phase = 22;
    PARDISO(pt, &maxfct, &mnum, &mtype, &phase,
        &n, a, ia, ja, &idum, &nrhs, iparm, &msglvl, &ddum, &ddum, &error);
    if (error != 0)
    {
        printf("\nERROR during numerical factorization: %d", error);
        exit(2);
    }
    printf("\nFactorization completed ... ");
    /* -----------------------------------------------*/
    /* .. Back substitution and iterative refinement. */
    /* -----------------------------------------------*/
    phase = 33;
    iparm[7] = 2;         /* Max numbers of iterative refinement steps. */
                          /* Set right hand side to one. */
    for (i = 0; i < n; i++)
    {
        b[i] = 1;
    }
    PARDISO(pt, &maxfct, &mnum, &mtype, &phase,
        &n, a, ia, ja, &idum, &nrhs, iparm, &msglvl, b, x, &error);
    if (error != 0)
    {
        printf("\nERROR during solution: %d", error);
        exit(3);
    }
    printf("\nSolve completed ... ");
    printf("\nThe solution of the system is: ");
    for (i = 0; i < n; i++)
    {
        printf("\n x [%d] = % f", i, x[i]);
    }
    printf("\n");
    //Check with Lapack solve
    arma::colvec b_vec = arma::colvec(n);
    b_vec.fill(1);
    arma::colvec x_vec = arma::zeros(n);
    arma::spsolve(x_vec, single_mat, b_vec, "lapack");


    //End Lapack
    printf("\nx_vec is: ");
    for (i = 0; i < n; i++)
    {
        printf("\n x [%d] = % f", i, x_vec[i]);
    }
    printf("\n");
    //Check resolutions
    arma::colvec x_pardiso = arma::colvec(n);
    for (size_t i = 0; i < n; i++)
        x_pardiso[i] = x[i];

    std::cout << "\n" << single_mat*x_pardiso << '\n' << single_mat*x_vec << '\n';

    /* --------------------------------------*/
    /* .. Termination and release of memory. */
    /* --------------------------------------*/
    phase = -1;           /* Release internal memory. */
    PARDISO(pt, &maxfct, &mnum, &mtype, &phase,
        &n, &ddum, ia, ja, &idum, &nrhs,
        iparm, &msglvl, &ddum, &ddum, &error);
    std::cout << "\nPardiso freed memory\n";
    delete[]a;
    delete[]ja;
    delete[]ia;
    delete[]x;
    delete[]b;
    delete[]bs;
    return 0;
}

x_vec的值正确,x的值不正确。为什么?

您是否想知道倒符号(x=-x_vec,近似值)或舍入差异?舍入误差可能是由不同的舍入/截断规则引起的,但最后一个规则(x[7])看起来很奇怪。我想知道这两个规则,特别是在之后测试
Ax=b
时,
x
的正确值会给我
b
的原始值,但不正确的值不会。嗯,符号错误时有发生。可能是由于算法的不同实现、矩阵的不同实现(例如,意外转置)或类似的原因。也许更改为CSR/CRS格式会有所帮助?我这里没有MKL,因此无法帮助测试。当增加
n
的值时,即使调整了符号,差异也会变得更大,因此误差会更大。此外,我目前正在使用CSC格式,因为armadillo和mkl都支持它,因此我认为应该没有问题。
The solution of the system is:
 x [0] =  0.000674
 x [1] = -0.000089
 x [2] =  0.000488
 x [3] = -0.000287
 x [4] =  0.000288
 x [5] = -0.000487
 x [6] =  0.000089
 x [7] = -0.000677

x_vec is:
 x [0] = -0.000673
 x [1] =  0.000089
 x [2] = -0.000487
 x [3] =  0.000287
 x [4] = -0.000287
 x [5] =  0.000487
 x [6] = -0.000089
 x [7] =  0.000673