首页 > 其他分享 >SVD分解的并行实现

SVD分解的并行实现

时间:2023-05-31 15:03:00浏览次数:25  
标签:Matrix int double SVD 并行 ++ 分解 size matrix


在之前的文章中,我对SVD进行了大致的了解,它在互联网高端领域中有广泛的应用,至于它的一些详细应

用以后再进一步学习。现在主要的问题是如何有效地实现SVD分解,接下来我会先用两种方法来实现SVD分

解,即基于双边Jacobi旋转的SVD基于单边Jacobi旋转的SVD

 

这两种方法重点参考中国知网上的一篇论文:《并行JACOBI方法求解矩阵奇异值的研究》

 

代码:

#include <string.h>
#include <stdio.h>
#include <math.h>
#include <map>
 
#include "matrix.h"
 
using namespace std;
 
const double EPS = 1e-8;
const int ITER_NUM = 30;
 
int sign(double x)
{
    if(x < 0) return -1;
    return 1;
}
 
void rotate(Matrix<double> &matrix, int i, int j, bool &pass, Matrix<double> &J)
{
    double ele = matrix.get(i, j);
    if(fabs(ele) < EPS) return;
 
    pass = false;
    double ele1 = matrix.get(i, i);
    double ele2 = matrix.get(j, j);
    double tao = (ele1 - ele2) / (2 * ele);
    double tan = sign(tao) / (fabs(tao) + sqrt(1 + pow(tao, 2)));
    double cos = 1 / sqrt(1 + pow(tan, 2));
    double sin = cos * tan;
 
    int size = matrix.getRows();
    Matrix<double>G(IdentityMatrix<double>(size, size));
    G.put(i, i, cos);
    G.put(i, j, -1 * sin);
    G.put(j, i, sin);
    G.put(j, j, cos);
 
    matrix = G.getTranspose() * matrix * G;
    J *= G;
}
 
void jacobi(Matrix<double> &matrix, int size, vector<double> &E, Matrix<double> &J)
{
    int iter_num = ITER_NUM;
    while(iter_num-- > 0)
    {
        bool pass = true;
        for(int i = 0; i < size; i++)
        {
            for(int j = i + 1; j < size; j++)
                rotate(matrix, i, j, pass, J);
        }
        if(pass) break;
    }
    cout << "迭代次数:" << ITER_NUM - iter_num << endl;
 
    for(int i = 0; i < size; i++)
    {
        E[i] = matrix.get(i, i);
        if(E[i] < EPS)
            E[i] = 0.0;
    }
}
 
void svd(Matrix<double> &A, Matrix<double> &U, Matrix<double> &V, vector<double> &E)
{
    int rows = A.getRows();
    int columns = A.getColumns();
    assert(rows <= columns);
    assert(U.getRows() == rows);
    assert(U.getColumns() == rows);
    assert(V.getRows() == columns);
    assert(V.getColumns() == columns);
    assert(E.size() == columns);
 
    Matrix<double> B = A.getTranspose() * A;
    Matrix<double> J(IdentityMatrix<double>(columns, columns));
    vector<double> S(columns);
    jacobi(B, columns, S, J);
    for(int i = 0; i < S.size(); i++)
        S[i] = sqrt(S[i]);
 
    multimap<double, int> eigen;
    for(int i = 0; i < S.size(); i++)
        eigen.insert(make_pair(S[i], i));
    multimap<double, int>::const_iterator iter = --eigen.end();
    int num_eig = 0;
    for(int i = 0; i < columns; i++, iter--)
    {
        int index = iter->second;
        E[i] = S[index];
        if(E[i] > EPS)
            num_eig++;
        for(int row = 0; row < columns; row++)
            V.put(row, i, J.get(row, index));
    }
 
    assert(num_eig <= rows);
    for(int i = 0; i < num_eig; i++)
    {
        Matrix<double> vi = V.getColumn(i);
        double sigma = E[i];
        Matrix<double> ui(rows, 1);
        ui = A * vi;
        for(int j = 0; j < rows; j++)
            U.put(j, i, ui.get(j, 0) / sigma);
    }
}
 
int main()
{
    const int ROW = 4;
    const int COL = 5;
    assert(ROW <= COL);
    double arr[ROW * COL] =
    {1, 0, 0, 0, 2,
     0, 0, 3, 0, 0,
     0, 0, 0, 0, 0,
     0, 4, 0, 0, 0
     };
    Matrix<double> A(ROW, COL);
    A = arr;
 
    Matrix<double> U(ROW, ROW);
    Matrix<double> V(COL, COL);
    vector<double> E(COL);
 
    svd(A, U, V, E);
    Matrix<double> Sigma(ROW, COL);
    for(int i = 0; i < ROW; i++)
        Sigma.put(i, i, E[i]);
 
    cout << "U = " << endl << U;
    cout << "Sigma = " << endl << Sigma;
    cout << "V^T = " << endl << V.getTranspose();
 
    Matrix<double> AA = U * Sigma * V.getTranspose();
    cout << "Result AA = " << endl << AA;
 
    return 0;
}

 


标签:Matrix,int,double,SVD,并行,++,分解,size,matrix
From: https://blog.51cto.com/u_16146153/6386936

相关文章

  • 并行编程解决什么问题?
    多线程爬虫是指通过多个线程并发地请求网页和解析响应,以提高爬虫的效率和速度。在Python中可以使用threading、Queue和requests等模块来实现。并行编程是一种利用多个处理器/内核/线程来同时执行代码的编程方式。它可以解决以下几个问题:提升程序的性能在多任务或多进程场......
  • 基于压缩感知和KSVD的图像去噪算法matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:2.算法涉及理论知识概要K-SVD可以看做K-means的一种泛化形式,K-means算法总每个信号量只能用一个原子来近似表示,而K-SVD中每个信号是用多个原子的线性组合来表示的。K-SVD通过构建字典来对数据进行稀疏表示,经常用于图像压缩、编码、分类等......
  • python推荐系统实现(矩阵分解来协同过滤)|附代码数据
    原文链接:http://tecdat.cn/?p=10911最近我们被客户要求撰写关于推荐系统的研究报告,包括一些图形和统计输出。用户和产品的潜在特征编写推荐系统矩阵分解工作原理使用潜在表征来找到类似的产品 1.用户和产品的潜在特征我们可以通过为每个用户和每部电影分配属性,然后将它们相......
  • 分解质因数--试除法
     #include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;voiddivide(intn){for(inti=2;i<=n;i++)//这个地方是枚举到n{if(n%i==0){ints=0;while(n%i==0)......
  • 2.3Tucker分解HOSVD、HOOI算法推导和python实现
    HOSVD参考论文:AMULTILINEARSINGULARVALUEDECOMPOSITIONHOSVD虽然不能保证给Tucker分解给出最优拟合,但是可以提供一个好的初始化的解这些矩阵都是正交的。之所以求前R最大特征值,可以在下文的HOOI看到,目的是最大化目标函数UWHOSVD的最后一行证明如下:HOOI:黄色之所以可以化过去,......
  • 将真分数分解为埃及分数
    现输入一个真分数,请将该分数分解为埃及分数。#include<iostream>usingnamespacestd;intmain(){ inta,b,c; cout<<"请分别输入一个真分数的分母和分子:"<<endl; cin>>a>>b; cout<<"分解成埃及分数为:"; while(1) { if(b%a) { c=b/a+1; } else { c=b......
  • 将真分数分解为埃及分数
    自然语言解决问题:真分数(aproperfraction):分子比分母小的分数,叫做真分数。真分数的分数值小于1。如1/2,3/5,8/9等。分子是1的分数,叫单位分数。古代埃及人在进行分数运算时,只使用分子是1的分数。因此这种分数也叫做埃及分数,或者叫单分子分数。如8/11=1/2+1/5+1/55+1/110。我......
  • 并发与并行
    一、并发并发:轮流执行  交替执行有多个任务在等待cpu的执行cpu只能同时执行一个任务cpu在多个任务之间做高速切换来轮流执行每一个任务效率低 二、并行并行:同时执行cpu可以同时执行多个任务效率高 ......
  • DolohinScheduler 分布式任务调度框架 代码流程分解
    一、DS-API模块-执行工作流 -定时任务执行 更新schedule参数 -/schedule新增schedule参数做了什么事? 将schedule参数用ScheduleParam类进行解析 有效性校验,而后解析保存到t_ds_schedules表内,更新t_ds_process_definition表 -/onlin......
  • rt下降40%?程序并行优化六步法
    1背景性能优化是我们日常工作中很重要的一部分,主要有以下原因:降低服务器和带宽等硬件成本:用更少的资源处理更多的请求提高现实世界的运行效率:人机处理效率存在数量级的偏差,同样机器世界的效率提升能带来现实世界效率提升的方法效果提高用户的体验:解决响应缓慢、宕机等问题......