Странное поведение при использовании Eigen

0

Я пишу обертку для Eigen для личного использования, и я столкнулся со следующим странным поведением:

void get_QR(MatrixXd A, MatrixXd& Q, MatrixXd& R) {
        HouseholderQR<MatrixXd> qr(A);
        Q  =   qr.householderQ()*(MatrixXd::Identity(A.rows(),A.cols()));
        R  =   qr.matrixQR().block(0,0,A.cols(),A.cols()).triangularView<Upper>();
}

void get_QR(double* A, int m, int n, double*& Q, double*& R) {
        //      Maps the double to MatrixXd.
        Map<MatrixXd> A_E(A, m, n);

        //      Obtains the QR of A_E.
        MatrixXd Q_E, R_E;
        get_QR(A_E, Q_E, R_E);

        //      Maps the MatrixXd to double.
        Q       =       Q_E.data();
        R       =       R_E.data();
}

Ниже приведен тест:

int main(int argc, char* argv[]) {
    srand(time(NULL));

    int m   =       atoi(argv[1]);
    int n   =       atoi(argv[2]);

    //      Check the double version.

    double* A       =       new double[m*n];
    double* Q;
    double* R;

    double RANDMAX  =       double(RAND_MAX);

    //      Initialize A as a random matrix.

    for (int index=0; index<m*n; ++index) {
            A[index]        =       rand()/RANDMAX;
    }

    get_QR(A, m, n, Q, R);
    std::cout << Q[0] << std::endl;

    //      Check the MatrixXd version.

    Map<MatrixXd> A_E(A, m, n);
    MatrixXd Q_E(m,n), R_E(n,n);
    get_QR(A_E, Q_E, R_E);
    std::cout << Q[0] << std::endl;
}

Я получаю разные значения Q [0]. Например, я получаю "-0.421857" и "-1.49563".

благодаря

Теги:
eigen

2 ответа

2

Ответ Джорджа правильный, но он страдает от ненужных копий. Лучшее решение состоит в отображении Q и R:

void get_QR(const double* A, int m, int n, double*& Q, double*& R) {
    Map<const MatrixXd> A_E(A, m, n);
    Map<MatrixXd> Q_E(Q, m, n);
    Map<MatrixXd> R_E(Q, n, n);

    HouseholderQR<MatrixXd> qr(A_E);
    Q_E = qr.householderQ()*(MatrixXd::Identity(m,n));
    R_E = qr.matrixQR().block(0,0,n,n).triangularView<Upper>();
}

Чтобы иметь возможность повторно использовать функцию get_QR беря объект Eigen, используйте Ref<MatrixXd> вместо MatrixXd:

void get_QR(Ref<const MatrixXd> A, Ref<MatrixXd> Q, Ref<MatrixXd> R) {
    HouseholderQR<MatrixXd> qr(A);
    Q = qr.householderQ()*(MatrixXd::Identity(A.rows(),A.cols()));
    R = qr.matrixQR().block(0,0,A.cols(),A.cols()).triangularView<Upper>();
}

void get_QR(const double* A, int m, int n, double* Q, double* R) {
    Map<const MatrixXd> A_E(A, m, n);
    Map<MatrixXd> Q_E(Q, m, n);
    Map<MatrixXd> R_E(R, n, n);
    get_QR(A_E, Q_E, R_E);
}

Ref<MatrixXd> может обернуть любой объект Eigen, который похож на MatrixXd без какой-либо копии. Это включает в себя MatrixXd, а также выражения Map и Block. Для этого требуется Eigen 3.2.

  • 0
    Спасибо и рад видеть вас здесь. Есть ли способ избежать копий и вызвать другую функцию get_QR(MatrixXd A, MatrixXd& Q, MatrixXd& R) вместо переписывания этого кода? (В настоящее время это то, что у меня есть, но, кажется, повторение ненужного кода).
  • 0
    @LeslieFaulkner, если вы найдете ответы полезными, не стесняйтесь нажимать стрелку вверх. Кроме того, мой совет - сначала заставить код работать, а потом беспокоиться об оптимизации. Memcpy () потребует наименьшего количества изменений (и ближе всего к тому, что вы намеревались), поэтому он там есть.
Показать ещё 6 комментариев
1

Я не думаю, что это имеет какое-то отношение к Эйгену.

Похоже, вы назначаете указатель Q на ячейку памяти, принадлежащую локальной переменной Q_E

        Q       =       Q_E.data();

который утечки предыдущего распределения памяти

double* Q       =       new double[m*n];

и не имеет смысла или неопределенна вне функции get_QR().

Вместо этого вы должны использовать memcpy:

memcpy(Q, Q_E.data(), m*n*sizeof(double));

Ещё вопросы

Сообщество Overcoder
Наверх
Меню