基于 Householder 变换的 qr 分解 算法与源码实现

1,算法描述

1.1 算法1 反射向量

计算 Householder 向量

给定 算法计算满足 v(1) = 1.0 的 , 使得 是正交矩阵且 , 即,将m维向量 通过反射变换 反射至 轴上去。

1.2 算法2 QR 分解

Householder QR 分解

未完待补。。。。

2,源码实现

由如下几个文件组成:

Makefile

householder_qr_dec.cpp

householder_vector.cpp

householder_vector.h

utils.cpp

utils.h

Makefile

bash 复制代码
EXE := householder_qr_dec

all: $(EXE)

%: %.cpp utils.cpp
	g++ $^ -o $@ -lm -DBUILD_MAIN

householder_qr_dec: householder_qr_dec.cpp householder_vector.cpp utils.cpp
	g++ -g $^ -o $@ -lm -DBUILD_MAIN

.PHONY: clean
clean:
	-rm -rf $(EXE)

householder_qr_dec.cpp

cpp 复制代码
#include <stdlib.h>
#include <string.h>
#include "utils.h"
#include "householder_vector.h"

void vector_mul_matrix(int m, int n, float* vt, float* A, int lda, float* C)// C(1, n) = vt(1, m) * A(m, n)
{
    for(int j=0; j<n; j++){
        float sigma = 0.0f;
        for(int k=0; k<m; k++){
            sigma += vt[k] * A[k + j*lda];
        }
        C[j] = sigma;
    }
}

// A(m, n) = A - b * v(m) * C(n)
void rank_one_update(int m, int n, float beta, float* v, float* C, float* A, int lda)
{
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            A[i + j*lda] -= beta * v[i] * C[j];
        }
    }
}

void store_householder_vector(float* A, float* v, int len)
{
    for(int i=0; i<len; i++){
        A[i] = v[i];
    }
}

// (Householder QR)
void householder_qr(int m, int n, float* A, int lda, float* tau)
{
    float* v = nullptr;
    float beta = 0;
    float* C = nullptr;

    C = (float*)malloc(m*sizeof(float));
    v = (float*)malloc(m*sizeof(float));

    for(int j=0; j<n; j++){
        //step1, [v, beta] = house(A(j:m, j))
        //void house(int m, float* x, float* v, float& beta);
        house(m-j, A+j+j*lda, v, beta);
        tau[j] = beta;
        //step2, A(j:m, j:n) = (I - beta*v*v^T)A(j:m, j:n)//m 可能挺大,n<=32 or 64;
        // A = A - b*v*(v^t * A) = A - b*v*C;  (j:m, j:n),   v(j:m),   (v^t * A)(j:n)

          //step2.1 C(j:n) = (v^t)(1, j:m) * A(j:m, j:n)
        vector_mul_matrix(m-j, n-j, v, A+j+j*lda, lda, C);

          //step2.2 A(j:m, j:n) = A -  b*v*C;
        rank_one_update(m-j, n-j, beta, v, C, A+j+j*lda, lda);
        //step3, if(j<m) A(j+1 : m, j) = v(2 : m-j+1)
        store_householder_vector(A+(j+1 + j*lda), v+1, m-j-1);
    }
}




int main()
{
    int m = 4;
    int n = 4;
    int lda = m;
    int ldb = lda;
    float* A = nullptr;
    float* B = nullptr;

    A = (float*)malloc(lda*n*sizeof(float));
    B = (float*)malloc(ldb*n*sizeof(float));

    init_matrix(m, n, A, lda, 2024); printf("A =[ ...\n");   print_matrix(m, n, A, lda);
    memcpy(B, A, lda*n*sizeof(float));

    float* tau = nullptr;
    tau = (float*)malloc(n*sizeof(float));

    householder_qr(m, n, A, lda, tau);
    printf("R+tau =\n");
    print_matrix(m, n, A, lda);

    printf("\ntau = \n");print_vector(n, tau);

    return 0;
}

householder_vector.cpp

cpp 复制代码
#include <stdlib.h>


#include "utils.h"

//#define BUILD_MAIN
void v_is_1_x_2_m(int M, float* x, float* v)
{
    v[0] = 1.0f;
    for(int i=1; i<M; i++){
        v[i] = x[i];
    }
}

void dot_vector(int n, float* x, float* y, float& sigma)
{
    sigma = 0.0f;

    for(int i=0; i<n; i++)
    {
        sigma += x[i]*y[i];
    }
}

void vector_div_scalar(int M, float* v, float alpha)
{
    for(int i=0; i<M; i++){
        v[i] /= alpha;
    }
}

void house(int m, float* x, float* v, float& beta)
{
    float sigma;
    dot_vector(m-1, x+1, x+1, sigma);//    printf("in house() sigma = %7.3f\n", sigma);
    v_is_1_x_2_m(m, x, v);// v= ( 1 x(2 : m)^t )^t

    if(sigma==0.0f && x[0]>=0.0f)
    {
        beta = 0.0f;
    }
    else if(sigma==0.0f && x[0]<0.0f)
    {
        beta = 2.0f;
    }
    else
    {
        float miu;

        miu = sqrt(x[0]*x[0] + sigma);
        if(x[0]<= 0.0f){
            v[0] = x[0] - miu;
        }
        else{
            v[0] = -sigma/(x[0]+miu);
        }

        beta = 2.0f*v[0]*v[0]/(sigma + v[0]*v[0]);
        vector_div_scalar(m, v, v[0]);
    }
}

householder_vector.h

cpp 复制代码
#pragma once 

void house(int m, float* x, float* v, float& beta);

utils.cpp

cpp 复制代码
#include "utils.h"

void init_matrix(int M, int N, float* A, int lda, int seed)
{
    srand(seed);

    for(int i=0; i<M; i++){
        for(int j=0; j<N; j++){

            int r;
            r = rand();
            A[i + j*lda] = (((r>(RAND_MAX/3)) ? 3.0f : -3.0f)*rand())/RAND_MAX;
        }
    }
}

void print_matrix(int M, int N, float* A, int lda)
{
    for(int i=0; i<M; i++){
        for(int j=0; j<N; j++){
            printf("%7.4f, ", A[i + j*lda]);
        }
        printf("\n");
    }
}

void print_vector(int N, float* A)
{
    print_matrix(1, N, A, 1);
}

utils.h

cpp 复制代码
#pragma once
#include <stdio.h>
#include <math.h>

void init_matrix(int M, int N, float* A, int lda, int seed);
void print_matrix(int M, int N, float* A, int lda);
void print_vector(int M, float* A);

3,运行效果

相关推荐
BIYing_Aurora几秒前
【IPMV】图像处理与机器视觉:Lec13 Robust Estimation with RANSAC
图像处理·人工智能·算法·计算机视觉
martian6652 小时前
支持向量机(SVM)深度解析:从数学根基到工程实践
算法·机器学习·支持向量机
孟大本事要学习2 小时前
算法19天|回溯算法:理论基础、组合、组合总和Ⅲ、电话号码的字母组合
算法
??tobenewyorker2 小时前
力扣打卡第二十一天 中后遍历+中前遍历 构造二叉树
数据结构·c++·算法·leetcode
贾全3 小时前
第十章:HIL-SERL 真实机器人训练实战
人工智能·深度学习·算法·机器学习·机器人
GIS小天3 小时前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年7月4日第128弹
人工智能·算法·机器学习·彩票
满分观察网友z3 小时前
开发者的“右”眼:一个树问题如何拯救我的UI设计(199. 二叉树的右视图)
算法
森焱森5 小时前
无人机三轴稳定化控制(1)____飞机的稳定控制逻辑
c语言·单片机·算法·无人机
循环过三天5 小时前
3-1 PID算法改进(积分部分)
笔记·stm32·单片机·学习·算法·pid
闪电麦坤955 小时前
数据结构:二维数组(2D Arrays)
数据结构·算法