1. 矩阵SVD分解: 代码主要来自(http://cacs.usc.edu/education/phys516/src/TB/svdcmp.c),此外,自己增加矩阵的释放函数和更加方便的接口函数,如下:
(1) 头文件
#ifndef CTMSVD_H
#define CTMSVD_H
/*******************************************************************************
Singular value decomposition program, svdcmp, from "Numerical Recipes in C"
(Cambridge Univ. Press) by W.H. Press, S.A. Teukolsky, W.T. Vetterling,
and B.P. Flannery
*******************************************************************************/
#include
#include
#include
#define NR_END 1
#define FREE_ARG char*
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
static double dmaxarg1,dmaxarg2;
#define DMAX(a,b) (dmaxarg1=(a),dmaxarg2=(b),(dmaxarg1) > (dmaxarg2) ? (dmaxarg1) : (dmaxarg2))
static int iminarg1,iminarg2;
#define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ? (iminarg1) : (iminarg2))
/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
double **dmatrix(int nrl, int nrh, int ncl, int nch)
{
int i,nrow=nrh-nrl+1,ncol=nch-ncl+1;
double **m;
/* allocate pointers to rows */
m= (double **) malloc((size_t)((nrow+NR_END)*sizeof(double*)));
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(double *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(double)));
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* 初始化元素为0 */
for(int i = nrl; i <= nrh; ++i)
{
for(int j = ncl; j <= nch; ++j)
{
m[i][j] = 0;
}
}
/* return pointer to array of pointers to rows */
return m;
}
/* allocate a double vector with subscript range v[nl..nh] */
double *dvector(int nl, int nh)
{
int i;
double *v;
v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double)));
/* 初始化元素为0 */
for(i = nl; i <= nh; ++i)
{
v[i] = 0;
}
return v-nl+NR_END;
}
/* free a double vector allocated with dvector() */
void free_dvector(double *v, int nl, int nh)
{
free((FREE_ARG) (v+nl-NR_END));
}
/* free a double matrix allocated with dmatrix() */
void free_dmatrix(double** m, int nrl)
{
free((FREE_ARG) (m[nrl])); /* 释放元素部分 */
free((FREE_ARG) *m); /* 释放** */
}
/* compute (a2 + b2)^1/2 without destructive underflow or overflow */
double pythag(double a, double b)
{
double absa,absb;
absa=fabs(a);
absb=fabs(b);
if (absa > absb) return absa*sqrt(1.0+(absb/absa)*(absb/absa));
else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+(absa/absb)*(absa/absb)));
}
/******************************************************************************/
void svdcmp(double **a, int m, int n, double w[], double **v)
/*******************************************************************************
Given a matrix a[1..m][1..n], this routine computes its singular value
decomposition, A = U.W.VT. The matrix U replaces a on output. The diagonal
matrix of singular values W is output as a vector w[1..n]. The matrix V (not
the transpose VT) is output as v[1..n][1..n].
注意: (1) 要求a的矩阵元素必须满足: m = n
(2) 不满足要求的矩阵可以用零填充
*******************************************************************************/
{
int flag,i,its,j,jj,k,l,nm;
double anorm,c,f,g,h,s,scale,x,y,z,*rv1;
rv1=dvector(1,n);
g=scale=anorm=0.0; /* Householder reduction to bidiagonal form */
for (i=1;i<=n;i++) {
l=i+1;
rv1[i]=scale*g;
g=s=scale=0.0;
if (i <= m) {
for (k=i;k<=m;k++) scale += fabs(a[k][i]);
if (scale) {
for (k=i;k<=m;k++) {
a[k][i] /= scale;
s += a[k][i]*a[k][i];
}
f=a[i][i];
g = -SIGN(sqrt(s),f);
h=f*g-s;
a[i][i]=f-g;
for (j=l;j<=n;j++) {
for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
f=s/h;
for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
}
for (k=i;k<=m;k++) a[k][i] *= scale;
}
}
w[i]=scale *g;
g=s=scale=0.0;
if (i <= m && i != n) {
for (k=l;k<=n;k++) scale += fabs(a[i][k]);
if (scale) {
for (k=l;k<=n;k++) {
a[i][k] /= scale;
s += a[i][k]*a[i][k];
}
f=a[i][l];
g = -SIGN(sqrt(s),f);
h=f*g-s;
a[i][l]=f-g;
for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
for (j=l;j<=m;j++) {
for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
}
for (k=l;k<=n;k++) a[i][k] *= scale;
}
}
anorm = DMAX(anorm,(fabs(w[i])+fabs(rv1[i])));
}
for (i=n;i>=1;i--) { /* Accumulation of right-hand transformations. */
if (i < n) {
if (g) {
for (j=l;j<=n;j++) /* Double division to avoid possible underflow. */
v[j][i]=(a[i][j]/a[i][l])/g;
for (j=l;j<=n;j++) {
for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
}
}
for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
}
v[i][i]=1.0;
g=rv1[i];
l=i;
}
for (i=IMIN(m,n);i>=1;i--) { /* Accumulation of left-hand transformations. */
l=i+1;
g=w[i];
for (j=l;j<=n;j++) a[i][j]=0.0;
if (g) {
g=1.0/g;
for (j=l;j<=n;j++) {
for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
f=(s/a[i][i])*g;
for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
}
for (j=i;j<=m;j++) a[j][i] *= g;
} else for (j=i;j<=m;j++) a[j][i]=0.0;
++a[i][i];
}
for (k=n;k>=1;k--) { /* Diagonalization of the bidiagonal form. */
for (its=1;its<=30;its++) {
flag=1;
for (l=k;l>=1;l--) { /* Test for splitting. */
nm=l-1; /* Note that rv1[1] is always zero. */
if ((double)(fabs(rv1[l])+anorm) == anorm) {
flag=0;
break;
}
if ((double)(fabs(w[nm])+anorm) == anorm) break;
}
if (flag) {
c=0.0; /* Cancellation of rv1[l], if l > 1. */
s=1.0;
for (i=l;i<=k;i++) {
f=s*rv1[i];
rv1[i]=c*rv1[i];
if ((double)(fabs(f)+anorm) == anorm) break;
g=w[i];
h=pythag(f,g);
w[i]=h;
h=1.0/h;
c=g*h;
s = -f*h;
for (j=1;j<=m;j++) {
y=a[j][nm];
z=a[j][i];
a[j][nm]=y*c+z*s;
a[j][i]=z*c-y*s;
}
}
}
z=w[k];
if (l == k) { /* Convergence. */
if (z < 0.0) { /* Singular value is made nonnegative. */
w[k] = -z;
for (j=1;j<=n;j++) v[j][k] = -v[j][k];
}
break;
}
if (its == 30) printf("no convergence in 30 svdcmp iterations\n");
x=w[l]; /* Shift from bottom 2-by-2 minor. */
nm=k-1;
y=w[nm];
g=rv1[nm];
h=rv1[k];
f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
g=pythag(f,1.0);
f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
c=s=1.0; /* Next QR transformation: */
for (j=l;j<=nm;j++) {
i=j+1;
g=rv1[i];
y=w[i];
h=s*g;
g=c*g;
z=pythag(f,h);
rv1[j]=z;
c=f/z;
s=h/z;
f=x*c+g*s;
g = g*c-x*s;
h=y*s;
y *= c;
for (jj=1;jj<=n;jj++) {
x=v[jj][j];
z=v[jj][i];
v[jj][j]=x*c+z*s;
v[jj][i]=z*c-x*s;
}
z=pythag(f,h);
w[j]=z; /* Rotation can be arbitrary if z = 0. */
if (z) {
z=1.0/z;
c=f*z;
s=h*z;
}
f=c*g+s*y;
x=c*y-s*g;
for (jj=1;jj<=m;jj++) {
y=a[jj][j];
z=a[jj][i];
a[jj][j]=y*c+z*s;
a[jj][i]=z*c-y*s;
}
}
rv1[l]=0.0;
rv1[k]=f;
w[k]=x;
}
}
free_dvector(rv1,1,n);
}
#endif // CTMSVD_H
(2)函数接口:
int matrix_svd(double *matrix1, int M, int N, bool isSort, bool isT, double *matrixU, double *matrixD, double *matrixV)
{
int i,j, k;
double t;
int MN = M > N ? M : N;
double** u = dmatrix(1, MN, 1, MN);
double* w = dvector(1, MN);
double** v = dmatrix(1, MN, 1, MN);
double* t1 = dvector(1, MN);
double* t2 = dvector(1, MN);
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
u[i + 1][j + 1] = matrix1[i * N + j];
}
}
svdcmp(u, MN, MN, w, v);
/* Sort the singular values in descending order */
if(isSort)
{
for (i = 1; i <= N; i++)
{
for (j = i+1; j <= N; j++)
{
if (w[i] < w[j])
{ /* 对特异值排序 */
t = w[i];
w[i] = w[j];
w[j] = t;
/* 同时也要把矩阵U,V的列位置交换 */
/* 矩阵U */
for (k = 1; k <= M; k++)
{
t1[k] = u[k][i];
}
for (k = 1; k <= M; k++)
{
u[k][i] = u[k][j];
}
for (k = 1; k <= M; k++)
{
u[k][j] = t1[k];
}
/* 矩阵V */
for (k = 1; k <= N; k++)
{
t2[k] = v[k][i];
}
for (k = 1; k <= N; k++)
{
v[k][i] = v[k][j];
}
for (k = 1; k <= N; k++)
{
v[k][j] = t2[k];
}
}
}
}
}
/* 构造matrixD */
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
if(i == j)
{
matrixD[i * N + j] = w[i + 1];
}
else
{
matrixD[i * N + j] = 0.0;
}
cout << matrixD[i * N + j] << ", ";
}
cout << endl;
}
/* 构造matrixU */
for(i = 0; i < M; ++i)
{
for(j = 0; j < M; ++j)
{
matrixU[i * M + j] = u[i + 1][j + 1];
cout << matrixU[i * M + j] << ",";
}
cout << endl;
}
/* 构造matrixV: isT确定是否进行转置 */
if(isT)
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[j * N + i] = v[i + 1][j + 1]; /* 转置 */
cout << matrixV[i * N + j] << ",";
}
cout << endl;
}
}
else
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[i * N + j] = v[i + 1][j + 1];
cout << matrixV[i * N + j] << ",";
}
cout << endl;
}
}
free_dmatrix(u, 1);
free_dmatrix(v, 1);
free_dvector(w, 1, MN);
free_dvector(t1, 1, MN);
free_dvector(t2, 1, MN);
return 0;
}
2. 参考CSDN博主(http://blog.csdn.net/fengbingchun/article/details/72853757), 实现了另一个版本的SVD求解算法,同样包含一个头文件和接口函数,如下:
(1) 头文件
#ifndef CTMSVD2_H
#define CTMSVD2_H
#include
#include
#include
#include
#include
template
static inline _Tp hypot(_Tp a, _Tp b)
{/* sqrt(x^2 + y^2): 但是可以避免上溢或下溢 */
a = ABS(a);
b = ABS(b);
if (a > b)
{
b /= a;
return a*sqrt(1 + b*b);
}
if (b > 0)
{
a /= b;
return b*sqrt(1 + a*a);
}
return 0;
}
template
static void transpose(std::vector > src, std::vector >& dst)
{/* 转置 */
if(!src.empty())
{
int M = src.size(); // 行数
int N = src[0].size(); // 列数
int i,j;
for(i = 0; i < N; ++i)
{
std::vector<_Tp> rowData(M, 0); // dst: N x M
dst.push_back(rowData);
}
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
dst[j][i] = src[i][j];
}
}
}
}
template
static void JacobiSVD(std::vector>& At,
std::vector>& _W, std::vector>& Vt)
{
double minval = FLT_MIN;
_Tp eps = (_Tp)(FLT_EPSILON * 2);
const int m = At[0].size();
const int n = _W.size();
const int n1 = m; // urows
std::vector W(n, 0.);
for (int i = 0; i < n; i++) {
double sd{0.};
for (int k = 0; k < m; k++) {
_Tp t = At[i][k];
sd += (double)t*t;
}
W[i] = sd;
for (int k = 0; k < n; k++)
Vt[i][k] = 0;
Vt[i][i] = 1;
}
int max_iter = std::max(m, 30);
for (int iter = 0; iter < max_iter; iter++) {
bool changed = false;
_Tp c, s;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
_Tp *Ai = At[i].data(), *Aj = At[j].data();
double a = W[i], p = 0, b = W[j];
for (int k = 0; k < m; k++)
p += (double)Ai[k] * Aj[k];
if (std::abs(p) <= eps * std::sqrt((double)a*b))
continue;
p *= 2;
double beta = a - b, gamma = hypot((double)p, beta); // hypot_
if (beta < 0) {
double delta = (gamma - beta)*0.5;
s = (_Tp)std::sqrt(delta / gamma);
c = (_Tp)(p / (gamma*s * 2));
} else {
c = (_Tp)std::sqrt((gamma + beta) / (gamma * 2));
s = (_Tp)(p / (gamma*c * 2));
}
a = b = 0;
for (int k = 0; k < m; k++) {
_Tp t0 = c*Ai[k] + s*Aj[k];
_Tp t1 = -s*Ai[k] + c*Aj[k];
Ai[k] = t0; Aj[k] = t1;
a += (double)t0*t0; b += (double)t1*t1;
}
W[i] = a; W[j] = b;
changed = true;
_Tp *Vi = Vt[i].data(), *Vj = Vt[j].data();
for (int k = 0; k < n; k++) {
_Tp t0 = c*Vi[k] + s*Vj[k];
_Tp t1 = -s*Vi[k] + c*Vj[k];
Vi[k] = t0; Vj[k] = t1;
}
}
}
if (!changed)
break;
}
for (int i = 0; i < n; i++) {
double sd{ 0. };
for (int k = 0; k < m; k++) {
_Tp t = At[i][k];
sd += (double)t*t;
}
W[i] = std::sqrt(sd);
}
for (int i = 0; i < n - 1; i++) {
int j = i;
for (int k = i + 1; k < n; k++) {
if (W[j] < W[k])
j = k;
}
if (i != j) {
std::swap(W[i], W[j]);
for (int k = 0; k < m; k++)
std::swap(At[i][k], At[j][k]);
for (int k = 0; k < n; k++)
std::swap(Vt[i][k], Vt[j][k]);
}
}
for (int i = 0; i < n; i++)
_W[i][0] = (_Tp)W[i];
srand(time(nullptr));
for (int i = 0; i < n1; i++) {
double sd = i < n ? W[i] : 0;
for (int ii = 0; ii < 100 && sd <= minval; ii++) {
// if we got a zero singular value, then in order to get the corresponding left singular vector
// we generate a random vector, project it to the previously computed left singular vectors,
// subtract the projection and normalize the difference.
const _Tp val0 = (_Tp)(1. / m);
for (int k = 0; k < m; k++) {
unsigned int rng = rand() % 4294967295; // 2^32 - 1
_Tp val = (rng & 256) != 0 ? val0 : -val0;
At[i][k] = val;
}
for (int iter = 0; iter < 2; iter++) {
for (int j = 0; j < i; j++) {
sd = 0;
for (int k = 0; k < m; k++)
sd += At[i][k] * At[j][k];
_Tp asum = 0;
for (int k = 0; k < m; k++) {
_Tp t = (_Tp)(At[i][k] - sd*At[j][k]);
At[i][k] = t;
asum += std::abs(t);
}
asum = asum > eps * 100 ? 1 / asum : 0;
for (int k = 0; k < m; k++)
At[i][k] *= asum;
}
}
sd = 0;
for (int k = 0; k < m; k++) {
_Tp t = At[i][k];
sd += (double)t*t;
}
sd = std::sqrt(sd);
}
_Tp s = (_Tp)(sd > minval ? 1 / sd : 0.);
for (int k = 0; k < m; k++)
At[i][k] *= s;
}
}
// matSrc为原始矩阵,支持非方阵,
// matD存放奇异值
// matU存放左奇异向量
// matVt存放转置的右奇异向量
template
int svdcmp2(const std::vector>& matSrc,
std::vector>& matD, std::vector>& matU, std::vector>& matVt)
{
int m = matSrc.size();
int n = matSrc[0].size();
for (const auto& sz : matSrc) {
if (n != sz.size()) {
fprintf(stderr, "matrix dimension dismatch\n");
return -1;
}
}
bool at = false;
if (m < n) {
std::swap(m, n);
at = true;
}
matD.resize(n);
for (int i = 0; i < n; ++i) {
matD[i].resize(1, (_Tp)0);
}
matU.resize(m);
for (int i = 0; i < m; ++i) {
matU[i].resize(m, (_Tp)0);
}
matVt.resize(n);
for (int i = 0; i < n; ++i) {
matVt[i].resize(n, (_Tp)0);
}
std::vector> tmp_u = matU, tmp_v = matVt;
std::vector> tmp_a, tmp_a_;
if (!at)
transpose(matSrc, tmp_a);
else
tmp_a = matSrc;
if (m == n) {
tmp_a_ = tmp_a;
} else {
tmp_a_.resize(m);
for (int i = 0; i < m; ++i) {
tmp_a_[i].resize(m, (_Tp)0);
}
for (int i = 0; i < n; ++i) {
tmp_a_[i].assign(tmp_a[i].begin(), tmp_a[i].end());
}
}
JacobiSVD(tmp_a_, matD, tmp_v);
if (!at) {
transpose(tmp_a_, matU);
matVt = tmp_v;
} else {
transpose(tmp_v, matU);
matVt = tmp_a_;
}
return 0;
}
#endif // CTMSVD2_H
(2)接口函数
int matrix_svd2(double *matrix1, int M, int N, bool isSort, bool isT, double *matrixU, double *matrixD, double *matrixV)
{
vector< vector > A;
vector< vector > U; // M x M
vector< vector > Vt; // N x N
vector< vector > D; // M x N
int i, j;
for(i = 0; i < M; ++i)
{
vector rowData(N, 0);
double* pRow = rowData.data();
memcpy(pRow, matrix1 + i * N, sizeof(double) * N);
A.push_back(rowData);
}
svdcmp2(A, D, U, Vt);
int minMN = M > N ? N : M;
/* 构造matrixD */
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
if(i < minMN && j < minMN && i == j)
{
matrixD[i * N + j] = D[i][0];
}
else
{
matrixD[i * N + j] = 0;
}
// cout << matrixD[i * N + j] << ", ";
}
// cout << endl;
}
/* 构造matrixU */
for(i = 0; i < M; ++i)
{
for(j = 0; j < M; ++j)
{
matrixU[i * M + j] = U[i][j];
// cout << matrixU[i * M + j] << ", ";
}
// cout << endl;
}
/* 构造matrixV */
if(isT)
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[i * N + j] = Vt[i][j]; /* 返回Vt */
// cout << matrixV[i * N + j] << ", ";
}
// cout << endl;
}
}
else
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[j * N + i] = Vt[i][j]; /* 返回V */
// cout << matrixV[i * N + j] << ", ";
}
// cout << endl;
}
}
if(isSort)
{
for(i = 0; i < minMN; ++i)
{
double svdVal = matrixD[i];
int index = i;
for(j = 0; j < minMN; ++j)
{
if(svdVal < matrixD[i * minMN + i])
{
index = j;
}
}
if(i != j)
{
int k;
// matrixD 对角元素交换
std::swap(matrixD[i * M + i], matrixD[index * M + index]);
// matrixU 行交换
for(k = 0; k < M; ++k)
{
std::swap(matrixU[i * M + k], matrixU[index * M + k]);
}
// matrixV 列变换
for(k = 0; k < N; ++k)
{
std::swap(matrixV[k * N + i], matrixV[k * N + index]);
}
}
}
}
return 0;
}
3. 测试准确性
#include
#include
#include
#include
#include
#include
#include
// #include
#include
#include "ctmsvd.h"
#include "ctmsvd2.h"
using namespace std;
int vector_conv(double *vec1, int M, double *vec2, int N, double *vec3)
{
int nlen = M + N - 1;
double* xx = new double[nlen];
int i,j;
for(i = 0; i < nlen; ++i)
{
xx[i] = 0;
for(j = 0; j < M; ++j)
{
if(i - j >= 0 && (i - j) < N)
{
xx[i] += vec1[j] * vec2[i - j];
}
}
}
for(i = 0; i < nlen; ++i)
{
vec3[i] = xx[i];
}
return 0;
}
int matrix_svd(double *matrix1, int M, int N, bool isSort, bool isT, double *matrixU, double *matrixD, double *matrixV)
{
int i,j, k;
double t;
int MN = M > N ? M : N;
double** u = dmatrix(1, MN, 1, MN);
double* w = dvector(1, MN);
double** v = dmatrix(1, MN, 1, MN);
double* t1 = dvector(1, MN);
double* t2 = dvector(1, MN);
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
u[i + 1][j + 1] = matrix1[i * N + j];
}
}
svdcmp(u, MN, MN, w, v);
/* Sort the singular values in descending order */
if(isSort)
{
for (i = 1; i <= N; i++)
{
for (j = i+1; j <= N; j++)
{
if (w[i] < w[j])
{ /* 对特异值排序 */
t = w[i];
w[i] = w[j];
w[j] = t;
/* 同时也要把矩阵U,V的列位置交换 */
/* 矩阵U */
for (k = 1; k <= M; k++)
{
t1[k] = u[k][i];
}
for (k = 1; k <= M; k++)
{
u[k][i] = u[k][j];
}
for (k = 1; k <= M; k++)
{
u[k][j] = t1[k];
}
/* 矩阵V */
for (k = 1; k <= N; k++)
{
t2[k] = v[k][i];
}
for (k = 1; k <= N; k++)
{
v[k][i] = v[k][j];
}
for (k = 1; k <= N; k++)
{
v[k][j] = t2[k];
}
}
}
}
}
/* 构造matrixD */
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
if(i == j)
{
matrixD[i * N + j] = w[i + 1];
}
else
{
matrixD[i * N + j] = 0.0;
}
cout << matrixD[i * N + j] << ", ";
}
cout << endl;
}
/* 构造matrixU */
for(i = 0; i < M; ++i)
{
for(j = 0; j < M; ++j)
{
matrixU[i * M + j] = u[i + 1][j + 1];
cout << matrixU[i * M + j] << ",";
}
cout << endl;
}
/* 构造matrixV: isT确定是否进行转置 */
if(isT)
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[j * N + i] = v[i + 1][j + 1]; /* 转置 */
cout << matrixV[i * N + j] << ",";
}
cout << endl;
}
}
else
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[i * N + j] = v[i + 1][j + 1];
cout << matrixV[i * N + j] << ",";
}
cout << endl;
}
}
free_dmatrix(u, 1);
free_dmatrix(v, 1);
free_dvector(w, 1, MN);
free_dvector(t1, 1, MN);
free_dvector(t2, 1, MN);
return 0;
}
int matrix_svd2(double *matrix1, int M, int N, bool isSort, bool isT, double *matrixU, double *matrixD, double *matrixV)
{
vector< vector > A;
vector< vector > U; // M x M
vector< vector > Vt; // N x N
vector< vector > D; // M x N
int i, j;
for(i = 0; i < M; ++i)
{
vector rowData(N, 0);
double* pRow = rowData.data();
memcpy(pRow, matrix1 + i * N, sizeof(double) * N);
A.push_back(rowData);
}
svdcmp2(A, D, U, Vt);
int minMN = M > N ? N : M;
/* 构造matrixD */
for(i = 0; i < M; ++i)
{
for(j = 0; j < N; ++j)
{
if(i < minMN && j < minMN && i == j)
{
matrixD[i * N + j] = D[i][0];
}
else
{
matrixD[i * N + j] = 0;
}
// cout << matrixD[i * N + j] << ", ";
}
// cout << endl;
}
/* 构造matrixU */
for(i = 0; i < M; ++i)
{
for(j = 0; j < M; ++j)
{
matrixU[i * M + j] = U[i][j];
// cout << matrixU[i * M + j] << ", ";
}
// cout << endl;
}
/* 构造matrixV */
if(isT)
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[i * N + j] = Vt[i][j]; /* 返回Vt */
// cout << matrixV[i * N + j] << ", ";
}
// cout << endl;
}
}
else
{
for(i = 0; i < N; ++i)
{
for(j = 0; j < N; ++j)
{
matrixV[j * N + i] = Vt[i][j]; /* 返回V */
// cout << matrixV[i * N + j] << ", ";
}
// cout << endl;
}
}
if(isSort)
{
for(i = 0; i < minMN; ++i)
{
double svdVal = matrixD[i];
int index = i;
for(j = 0; j < minMN; ++j)
{
if(svdVal < matrixD[i * minMN + i])
{
index = j;
}
}
if(i != j)
{
int k;
// matrixD 对角元素交换
std::swap(matrixD[i * M + i], matrixD[index * M + index]);
// matrixU 行交换
for(k = 0; k < M; ++k)
{
std::swap(matrixU[i * M + k], matrixU[index * M + k]);
}
// matrixV 列变换
for(k = 0; k < N; ++k)
{
std::swap(matrixV[k * N + i], matrixV[k * N + index]);
}
}
}
}
return 0;
}
int main()
{
double vec1[5] = {1, 2, 3, 4, 5};
double vec2[6] = {1, 2, 3, 4, 5, 6};
double vec3[10] = {0};
vector_conv(vec1, 5, vec2, 6, vec3);
int i;
for(i = 0; i < 10; ++i)
{
cout << vec3[i] << ",";
}
cout << endl;
// 场景1: M > N
double matrix[12] = { 1.4090 , 0.7172 , 0.7269,
1.4172 , 1.6302, -0.3034,
0.6715 , 0.4889 , 0.2939,
-1.2075 , 1.0347 , -0.7873};
double matrixU1[16] = {0};
double matrixD1[12] = {0};
double matrixV1[9] = {0};
std::cout << "========== case 1: M > N ==========" << std::endl;
matrix_svd(matrix, 4, 3, true, false, matrixU1, matrixD1, matrixV1);
std::cout << "===================================" << std::endl;
matrix_svd2(matrix, 4, 3, true, false, matrixU1, matrixD1, matrixV1);
std::cout << "============= case 1 End =============" << std::endl;
// 场景2: M < N
double matrix2[12] = { 1.4090 , 0.7172 , 0.7269,
1.4172 , 1.6302, -0.3034,
0.6715 , 0.4889 , 0.2939,
-1.2075 , 1.0347 , -0.7873};
double matrixU2[16] = {0};
double matrixD2[12] = {0};
double matrixV2[9] = {0};
std::cout << "========== case 1: M < N ==========" << std::endl;
matrix_svd(matrix2, 3, 4, true, false, matrixU2, matrixD2, matrixV2);
std::cout << "===================================" << std::endl;
matrix_svd2(matrix2, 3, 4, true, false, matrixU1, matrixD1, matrixV1);
std::cout << "============= case 2 End =============" << std::endl;
return 0;
}
结果可以同matlab的svd函数进行对比: