用豪斯霍尔德(Householder)变换进行矩阵的QR分解,及其Matlab和OpenCV实现

1、豪斯霍尔德变换
一般地,对给定的 m m m维向量 a a a,考虑分块 a = [ a 1 a 2 ] a=\left[ \begin{matrix} {{a}_{1}} \\ {{a}_{2}} \\ \end{matrix} \right] a=[a1a2],其中 a 1 {{a}_{1}} a1 ( k − 1 ) (k-1) (k1)维向量, 1 ≤ k < m 1\le k1k<m。如果豪斯霍尔德向量为 v = [ 0 a 2 ] − α e k v=\left[ \begin{matrix} 0 \\ {{a}_{2}} \\ \end{matrix} \right]-\alpha {{e}_{k}} v=[0a2]αek,其中 α = − s i g n ( a k ) ∣ ∣ a 2 ∣ ∣ 2 \alpha =-sign({{a}_{k}})||{{a}_{2}}|{{|}_{2}} α=sign(ak)a22 e k {{e}_{k}} ek是单位矩阵的第 k {k} k列,则由此形成的豪斯霍尔德变换可消去 a a a的后 m − k m-k mk个分量。对 k = 1 , 2 , ⋯   , n k=1,2,\cdots ,n k=1,2,,n用这种方法可定义一系列豪斯霍尔德变换,以消去 m × n m\times n m×n阶矩阵 A A A的副对角线及以下的元素,对 A A A的列按从左到右的顺序依次作上述变换,就可将矩阵约化为上三角阵。每个豪斯霍尔德变换只对 A A A的未被约化的部分起作用,并不影响前面已约化好的部分,因而在依次变换过程中,已得到的零元素能得以保持。对任意向量 u u u,经过豪斯霍尔德变换 H H H后,为 H u = ( I − 2 v v T v T v ) u = u − ( 2 v T u v T v ) v Hu=\left( I-2\frac{v{{v}^{T}}}{{{v}^{T}}v} \right)u=u-\left( 2\frac{{{v}^{T}}u}{{{v}^{T}}v} \right)v Hu=(I2vTvvvT)u=u(2vTvvTu)v,这个变换的计算量比通常的矩阵向量相乘要少得多,且只要知道向量 v v v即可,不必具体算出矩阵 H H H
2、伪代码
用豪斯霍尔德(Householder)变换进行矩阵的QR分解,及其Matlab和OpenCV实现_第1张图片
3、Matlab实现

%% Matlab 2018b——用豪斯霍尔德变换进行矩阵的QR分解:A→R(上三角阵)
A=[1,0,0;0,1,0;0,0,1;-1,1,0;-1,0,1;0,-1,1];
% b=[1237,1941,2417,711,1177,475];
% A=[A,b'];
[m,n]=size(A);
alpha=zeros(1,n);
beta=alpha;
gama=alpha;
v=zeros(m,n);
E=eye(m,n);
for i=1:n
   alpha(i)=-1*sign(A(i,i))*sqrt(sum(A(i:m,i).*A(i:m,i)));
   v(:,i)=[zeros(i-1,1);A(i:m,i)]-alpha(i).*E(:,i);
   beta(i)=v(:,i)'*v(:,i);
   if beta(i)==0
      continue; 
   end
   for j=i:n
      gama(j)=v(:,i)'*A(:,j);
      A(:,j)=A(:,j)-(2*gama(j)/beta(i)).*v(:,i);  
   end
end
R=A;

4、OpenCV实现

// OpenCV 4.5.0——用豪斯霍尔德变换进行矩阵的QR分解:A→R(上三角阵)
#include 
#include 

using namespace std;
using namespace cv;

int main()
{
	Mat A = (Mat_<float>(6, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 1, 0, -1, 0, 1, 0, -1, 1);
	Size n = A.size();
	Mat alpha = Mat::zeros(1, n.width, CV_32FC1);
	Mat V = Mat::zeros(n, CV_32FC1);
	Mat E = Mat::eye(n, CV_32FC1);
	Mat beta = alpha.clone(), gama = alpha.clone();
	Mat temp, temp1;	// 过程暂存变量
	for (int i = 0; i < n.width; i++)
	{		
		temp = A(Range(i, n.height), Range(i, i + 1)).clone();
		temp1 = temp.mul(temp);		// 各项求平方
		reduce(temp1, temp1, 0, REDUCE_SUM);	// 平方和
		alpha.at<float>(i) = -1 * A.at<float>(i, i) / fabsf(A.at<float>(i, i)) * sqrt(temp1.at<float>(0));
		vconcat(Mat::zeros(i, 1, CV_32FC1), temp, temp);
		V.col(i) = temp - alpha.at<float>(i)*E.col(i);
		temp1 = V.col(i).t()*V.col(i);
		beta.at<float>(i) = temp1.at<float>(0);
		if (beta.at<float>(i) == 0)
			continue;
		for (int j = i; j < n.width; j++)
		{
			temp = V.col(i).t()*A.col(j);
			gama.at<float>(j) = temp.at<float>(0);
			A.col(j) = A.col(j) - (2 * gama.at<float>(j) / beta.at<float>(i))*V.col(i);
		}
	}
	cout << A << endl;
	getchar();
	return 0;
}

参考文献:《科学计算导论》(第2版)——Michael T. Health 著 张威等 译

你可能感兴趣的:(OpenCV,MATLAB)