Как получить Q из результатов QR-факторизации?

DGEQRF и SGEQRF из LAPACK возвращают часть Q факторизации QR в упакованном формате. Распаковка вроде требует O(k^3) шаги (k продуктов низкого ранга), и, кажется, не очень просто. Плюс числовая стабильность ведения k Последовательное умножение мне неясно.

Включает ли LAPACK подпрограмму для распаковки Q, и если нет, то как мне это сделать?

2 ответа

Решение

Да, LAPACK действительно предлагает процедуру для извлечения Q из элементарных отражателей (то есть части данных, возвращаемых DGEQRF), она называется DORGQR. Из описания:

*  DORGQR generates an M-by-N real matrix Q with orthonormal columns,
*  which is defined as the first N columns of a product of K elementary
*  reflectors of order M
*
*        Q  =  H(1) H(2) . . . H(k)
*  as returned by DGEQRF.

Полный расчет Q а также R от A с использованием C-wrapper LAPACKE может выглядеть так (адаптация Fortran должна быть прямой):

void qr( double* const _Q, double* const _R, double* const _A, const size_t _m, const size_t _n) {
    // Maximal rank is used by Lapacke
    const size_t rank = std::min(_m, _n); 

    // Tmp Array for Lapacke
    const std::unique_ptr<double[]> tau(new double[rank]);

    // Calculate QR factorisations
    LAPACKE_dgeqrf(LAPACK_ROW_MAJOR, (int) _m, (int) _n, _A, (int) _n, tau.get());

    // Copy the upper triangular Matrix R (rank x _n) into position
    for(size_t row =0; row < rank; ++row) {
        memset(_R+row*_n, 0, row*sizeof(double)); // Set starting zeros
        memcpy(_R+row*_n+row, _A+row*_n+row, (_n-row)*sizeof(double)); // Copy upper triangular part from Lapack result.
    }

    // Create orthogonal matrix Q (in tmpA)
    LAPACKE_dorgqr(LAPACK_ROW_MAJOR, (int) _m, (int) rank, (int) rank, _A, (int) _n, tau.get());

    //Copy Q (_m x rank) into position
    if(_m == _n) {
        memcpy(_Q, _A, sizeof(double)*(_m*_n));
    } else {
        for(size_t row =0; row < _m; ++row) {
            memcpy(_Q+row*rank, _A+row*_n, sizeof(double)*(rank));
        }
    }
}

Это часть моего собственного кода, где я удалил все проверки, чтобы улучшить читаемость. Для продуктивного использования вы хотите проверить правильность ввода, а также учитывать возвращаемые значения вызовов LAPACK. Обратите внимание, что вход A уничтожен

Ты ищешь

DORMQR(SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, LWORK, INFO)

Вычисляет Q * C где Q = H(1) H(2) . . . H(k) как вернулся из DGEQRF, Просто используйте C = I,

Для получения дополнительной информации смотрите здесь.

Другие вопросы по тегам