(结果:来自here的一些函数orhtonormalize
和forward_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;
}