Подтвердить что ты не робот

С++-собственное значение/векторное разложение, нужны только первые n векторов

У меня есть ковариационная матрица размером ~ 3000x3000, на которой я вычисляю разложение по собственному значению-собственному вектору (это матрица OpenCV, и я использую cv::eigen() для выполнения задания).

Однако мне действительно нужны только, скажем, первые 30 собственных значений/векторов, мне все равно, что остальное. Теоретически это должно позволить значительно ускорить вычисление, не так ли? Я имею в виду, это означает, что у него меньше 2970 собственных векторов, которые нужно вычислить.

Какая библиотека С++ позволит мне это сделать? Обратите внимание, что для этого метода OpenCV eigen() есть параметры, но в документации указано, что они игнорируются, и я сам его тестировал, они действительно игнорируются: D

UPDATE: Мне удалось это сделать с ARPACK. Мне удалось скомпилировать его для окон и даже использовать его. Результаты выглядят многообещающе, в этом примере игрушек можно увидеть иллюстрацию:

#include "ardsmat.h"
#include "ardssym.h"
int     n = 3;           // Dimension of the problem.
    double* EigVal = NULL;  // Eigenvalues.
    double* EigVec = NULL; // Eigenvectors stored sequentially.


    int lowerHalfElementCount = (n*n+n) / 2;
    //whole matrix:
    /*
    2  3  8
    3  9  -7
    8  -7 19
    */
    double* lower = new double[lowerHalfElementCount]; //lower half of the matrix
    //to be filled with COLUMN major (i.e. one column after the other, always starting from the diagonal element)
    lower[0] = 2; lower[1] = 3; lower[2] = 8; lower[3] = 9; lower[4] = -7; lower[5] = 19;
    //params: dimensions (i.e. width/height), array with values of the lower or upper half (sequentially, row major), 'L' or 'U' for upper or lower
    ARdsSymMatrix<double> mat(n, lower, 'L');

    // Defining the eigenvalue problem.
    int noOfEigVecValues = 2;
    //int maxIterations = 50000000;
    //ARluSymStdEig<double> dprob(noOfEigVecValues, mat, "LM", 0, 0.5, maxIterations);
    ARluSymStdEig<double> dprob(noOfEigVecValues, mat);

    // Finding eigenvalues and eigenvectors.

    int converged = dprob.EigenValVectors(EigVec, EigVal);
    for (int eigValIdx = 0; eigValIdx < noOfEigVecValues; eigValIdx++) {
        std::cout << "Eigenvalue: " << EigVal[eigValIdx] << "\nEigenvector: ";

        for (int i = 0; i < n; i++) {
            int idx = n*eigValIdx+i;
            std::cout << EigVec[idx] << " ";
        }
        std::cout << std::endl;
    }

Результаты:

9.4298, 24.24059

для собственных значений, а

-0.523207, -0.83446237, -0.17299346
0.273269, -0.356554, 0.893416

для 2 собственных векторов соответственно (один собственный вектор на строку) Код не может найти 3 собственных вектора (он может найти только 1-2 в этом случае, assert() делает это, но это не проблема).

4b9b3361

Ответ 1

В этой статье Саймон Фанк показывает простой и эффективный способ оценки разложения сингулярных значений (SVD) очень большой матрицы. В его случае матрица является редкой, с размерами: 17 000 х 500 000.

Теперь, глядя здесь, описывается, как разложение собственных значений тесно связано с SVD. Таким образом, вам может быть полезно рассмотреть модифицированную версию подхода Саймона Фанка, особенно если ваша матрица разрежена. Кроме того, ваша матрица не только квадратная, но и симметричная (если это то, что вы подразумеваете под ковариантным), что, вероятно, приводит к дополнительному упрощению.

... Просто идея:)