通过Householder转换实现QR分解的就地C ++实现

时间:2015-01-01 20:55:41

标签: c++ algorithm math matrix in-place

(结果:来自here的一些函数orhtonormalizeforward_transformation正在测试Householder方法的实现。

我是否尝试使用Householder算法进行矩形矩阵的QR分解? 就地意味着,输入在计算期间被修改,并且上三角矩阵 R 的对角线另外提供,如第12页的the article中所介绍的那样(或者某些东西)相似,但节省空间)。 tred2 函数的实现(在Internet中广泛呈现)并不十分清楚。我的目的是在纯 C ++ 中实现(或获得一些现成的)Householder转换实现。

这是我自己努力的结果。这是来自上述文章的MATLAB代码的简单直接重新实现,并且(因此)它主要提供了错误的输出:

#include <iostream>
#include <ostream>
#include <valarray>
#include <vector>
#include <deque>
#include <algorithm>
#include <numeric>
#include <utility>
#include <functional>
#include <limits>

#include <cstdlib>
#include <cassert>

using value_type = long double;
using vector = std::valarray< value_type >;
using matrix = std::valarray< vector >;

std::ostream &
operator << (std::ostream & out, matrix const & matrix)
{
    for (vector const & point : matrix) {
        for (value_type const & x : point) {
            out << x << ' ';
        }
        out << std::endl;
    }
    return out;
}

value_type const eps = std::numeric_limits< value_type >::epsilon();
value_type const zero = value_type(0);
value_type const one = value_type(1);

int
main()
{
    matrix qr{{12, 6, -4},
              {-51, 167, 24},
              {4, -68, -41}};
    std::cout << qr << std::endl;

    std::size_t const m = qr[0].size();
    std::size_t const n = qr.size();
    vector rtrace(zero, n);
    for (std::size_t j = 0; j < n; ++j) { // Householder itself
        value_type norm = zero;
        vector & qr_j = qr[j];
        for (std::size_t i = j; i < m; ++i) {
            value_type const & qrij = qr_j[i];
            norm += qrij * qrij;
        }
        using std::sqrt;
        norm = sqrt(norm);
        value_type & qrjj = qr_j[j];
        value_type & dj = rtrace[j];
        dj = (zero < qrjj) ? -norm : norm;
        using std::abs;
        value_type f = norm * (norm + abs(qrjj));
        assert(eps < f);
        f = one / sqrt(std::move(f));
        qrjj -= dj;
        for (std::size_t k = j; k < m; ++k) {
            qr_j[k] *= f;
        }
        for (std::size_t i = j + 1; i < n; ++i) {
            vector & qr_i = qr[i];
            value_type dot_product = zero;
            for (std::size_t k = j; k < m; ++k) {
                dot_product += qr_j[k] * qr_i[k];
            }
            for (std::size_t k = j; k < m; ++k) {
                qr_i[k] -= qr_j[k] * dot_product;
            }
        }
    }
    std::cout << "output:\n" << qr << std::endl;
    std::cout << "diagonal of R: " << std::endl;
    for (value_type const & rd : rtrace) {
        std::cout << rd << ' ';
    }
    std::cout << std::endl << std::endl;
    matrix q{{1, 0, 0},
             {0, 1, 0},
             {0, 0, 1}};
    for (std::size_t i = 0; i < n; ++i) {
        vector & qi = q[i];
        std::size_t j = n;
        while (0 < j) {
            --j;
            vector & qr_j = qr[j];
            value_type s_ = zero;
            for (std::size_t k = j; k < m; ++k) {
                s_ += qr_j[k] * qi[k];
            }
            for (std::size_t k = j; k < m; ++k) {
                qi[k] += qr_j[k] * s_;
            }
        }
    }
    std::cout << "Q:\n" << q << std::endl << std::endl;
    matrix r{{0, 0, 0},
             {0, 0, 0},
             {0, 0, 0}};
    for (std::size_t i = 0; i < n; ++i) {
        r[i][i] = rtrace[i];
        for (std::size_t j = i + 1; j < n; ++j) {
            r[j][i] = qr[j][i];
        }
    }
    std::cout << "R:\n" << r << std::endl << std::endl;
    matrix a{{0, 0, 0},
             {0, 0, 0},
             {0, 0, 0}};
    for (std::size_t i = 0; i < n; ++i) {
        for (std::size_t j = 0; j < n; ++j) {
            a[j][i] += q[i][j] * r[i][j];
        }
    }
    std::cout << "regenerated input:\n" << a << std::endl << std::endl;
    return EXIT_SUCCESS;
}

0 个答案:

没有答案