ECOGEN 4.0
Evolutive, Compressible, Open, Genuine, Easy, N-phase
Loading...
Searching...
No Matches
svd.h
Go to the documentation of this file.
1/*
2 * HISTORY:
3 * This is an SVD library slightly modified by Kevin Schmidmayer.
4 * The original version was aquired from
5 * https://www.gb.nrao.edu/~rcreager/Zpectrometer/.
6*/
7
8/*
9 $Id: svd.c,v 1.4 2004/03/24 04:58:59 rauch Exp $
10
11 Routines related to singular value decomposition of matrices, based on
12 routines in Numerical Recipes which have been modified: to accept
13 standard 0-based, row-order C arrays as input; to return error codes if
14 memory could not be allocated; to use double precision instead of floats.
15 svsolve() and svinverse() functions have also been added.
16
17 Note that all matrix dimensions are specified as the number of rows
18 followed by the number of columns.
19*/
20#include <errno.h>
21#include <math.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "matrix.h"
26
27#define MAXIT 32
28#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
29
30/* Elements of static temporary storage to allocate. */
31#define NSTAT 16
32
33/* Default value for smallest meaningful singular value. */
34#define WMIN 1e-13
35
36inline int svdcmp(double u[/*m x n*/], double w[/*n*/], double v[/*n x n*/],
37 const double a[/*m x n*/], int m, int n)
38{
39/*
40 Compute the SVD A = U x W x V^T of the m (rows) by n (columns) matrix A;
41 on output, u[] holds the m by n matrix U, w[] holds the n diagonal
42 elements of the (diagonal) n by n matrix W, and v[] holds the transpose of
43 the n by n matrix V^T; note that u[] can be identical to a[].
44 Returns 0 on success, or a system error code otherwise
45 (ERANGE if MAXIT iterations are reached without converging).
46*/
47 static double srv1[NSTAT];
48 int flag, i, its, j, jj, k, l=0, nm=0;
49 double anorm, c, f, g, h, s, scale, x, y, z, *rv1;
50
51 if (n<=NSTAT) rv1=srv1; else rv1=(double *)malloc(n*sizeof(double));
52 if (!rv1) return(errno);
53
54 if (u!=a) memcpy(u, a, m*n*sizeof(double));
55 g=scale=anorm=0;
56
57 for (i=0; i<n; i++) {
58 l=i+1; rv1[i]=scale*g; g=s=scale=0;
59 if (i<m) {
60 double *uki=u+i*(n+1);
61
62 for (k=i; k<m; k++, uki+=n) scale+=fabs(*uki);
63 if (scale) {
64 for (uki=u+i*(n+1), k=i; k<m; k++, uki+=n) {
65 *uki/=scale; s+=(*uki)*(*uki);
66 }
67 f=u[i*n+i]; g=-SIGN(sqrt(s),f); h=f*g-s; u[i*n+i]=f-g;
68 for (j=l; j<n; j++) {
69 double *ukj;
70
71 for (s=0, uki=u+i*(n+1), ukj=u+i*n+j, k=i; k<m; k++, uki+=n, ukj+=n)
72 s+=(*uki)*(*ukj);
73 f=s/h;
74 for (uki=u+i*(n+1), ukj=u+i*n+j, k=i; k<m; k++, uki+=n, ukj+=n)
75 *ukj+=f*(*uki);
76 }
77 for (uki=u+i*(n+1), k=i; k<m; k++, uki+=n) (*uki)*=scale;
78 }
79 }
80 w[i]=scale*g; g=s=scale=0;
81 if (i<=m && i!=n) {
82 double *ui=u+i*n;
83
84 for (k=l; k<n; k++) scale+=fabs(ui[k]);
85 if (scale) {
86 for (ui=u+i*n+l, k=l; k<n; k++, ui++) { (*ui)/=scale; s+=(*ui)*(*ui); }
87 f=u[i*n+l]; g=-SIGN(sqrt(s),f); h=f*g-s; u[i*n+l]=f-g;
88 for (ui=u+i*n, k=l; k<n; k++) rv1[k]=ui[k]/h;
89 for (j=l; j<m; j++) {
90 double *uj=u+j*n;
91
92 for (s=0, k=l; k<n; k++) s+=uj[k]*ui[k];
93 for (uj=u+j*n, k=l; k<n; k++) uj[k]+=s*rv1[k];
94 }
95 for (ui=u+i*n, k=l; k<n; k++) ui[k]*=scale;
96 }
97 }
98 { double tmp=fabs(w[i])+fabs(rv1[i]); if (tmp>anorm) anorm=tmp; }
99 }
100
101 for (i=n-1; i>=0; i--) {
102 if (i<n-1) {
103 if (g) {
104 double *vji=v+l*n+i, *ui=u+i*n, g1=ui[l]*g;
105
106 if (g1) {
107 g1=1/g1; for (j=l; j<n; j++, vji+=n) *vji=g1*ui[j];
108 } else {
109 g1=1/ui[l]; for (j=l; j<n; j++, vji+=n) *vji=(ui[j]*g1)/g;
110 }
111 for (j=l; j<n; j++) {
112 double *vkj=v+l*n+j, *vki=v+l*n+i;
113
114 for (s=0, ui=u+i*n, k=l; k<n; k++, vkj+=n) s+=ui[k]*(*vkj);
115 for (vkj=v+l*n+j, k=l; k<n; k++, vkj+=n, vki+=n) (*vkj)+=s*(*vki);
116 }
117 }
118 {
119 double *vi=v+i*n, *vji=v+l*n+i;
120
121 for (j=l; j<n; j++, vji+=n) vi[j]=(*vji)=0;
122 }
123 }
124 v[i*n+i]=1; g=rv1[i]; l=i;
125 }
126
127 for (i=(m>n ? n : m)-1; i>=0; i--) {
128 l=i+1; g=w[i];
129 { double *ui=u+i*n; for (j=l; j<n; j++) ui[j]=0; }
130 if (g) {
131 g=1/g;
132 for (j=l; j<n; j++) {
133 double *uki=u+l*n+i, *ukj=u+l*n+j;
134
135 for (s=0, k=l; k<m; k++, uki+=n, ukj+=n) s+=(*uki)*(*ukj);
136 f=(s/u[i*n+i])*g;
137 for (uki=u+i*n+i, ukj=u+i*n+j, k=i; k<m; k++, uki+=n, ukj+=n)
138 (*ukj)+=f*(*uki);
139 }
140 { double *uji=u+i*n+i; for (j=i; j<m; j++, uji+=n) (*uji)*=g; }
141 } else {
142 double *uji=u+i*n+i;
143
144 for (j=i; j<m; j++, uji+=n) *uji=0;
145 }
146 ++u[i*n+i];
147 }
148
149 for (k=n-1; k>=0; k--) {
150 for (its=0; its<=MAXIT; its++) {
151 flag=1;
152 for (l=k; l>=0; l--) {
153 nm=l-1; if (fabs(rv1[l])+anorm==anorm) { flag=0; break; }
154 if (fabs(w[nm])+anorm==anorm) break;
155 }
156 if (flag) {
157 c=0; s=1;
158 for (i=l; i<=k; i++) {
159 f=s*rv1[i]; rv1[i]=c*rv1[i];
160 if (fabs(f)+anorm==anorm) break;
161 g=w[i]; h=hypot(f, g); w[i]=h; h=1/h; c=g*h; s=-f*h;
162 {
163 double *ujnm=u+nm, *uji=u+i;
164
165 for (j=0; j<m; j++, ujnm+=n, uji+=n) {
166 y=(*ujnm); z=(*uji); (*ujnm)=y*c+z*s; (*uji)=z*c-y*s;
167 }
168 }
169 }
170 }
171 z=w[k];
172 if (l==k) {
173 if (z<0) {
174 double *vjk=v+k;
175
176 w[k]= -z; for (j=0; j<n; j++, vjk+=n) (*vjk)= -(*vjk);
177 }
178 break;
179 }
180
181 if (its==MAXIT) { if (n>NSTAT) free(rv1); return(ERANGE); }
182
183 x=w[l]; nm=k-1; y=w[nm]; g=rv1[nm]; h=rv1[k];
184 f=((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
185 g=hypot(f, 1); f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; c=s=1;
186 for (j=l; j<=nm; j++) {
187 i=j+1; g=rv1[i]; y=w[i]; h=s*g; g=c*g; z=hypot(f,h);
188 rv1[j]=z;
189 { double z1=1/z; c=f*z1; s=h*z1; }
190 f=x*c+g*s; g=g*c-x*s; h=y*s; y*=c;
191 {
192 double *vjjj=v+j, *vjji=v+i;
193
194 for (jj=0; jj<n; jj++, vjjj+=n, vjji+=n) {
195 x=(*vjjj); z=(*vjji); (*vjjj)=x*c+z*s; (*vjji)=z*c-x*s;
196 }
197 }
198 z=hypot(f,h); w[j]=z;
199 if (z) { z=1/z; c=f*z; s=h*z; }
200 f=c*g+s*y; x=c*y-s*g;
201 {
202 double *ujjj=u+j, *ujji=u+i;
203
204 for (jj=0; jj<m; jj++, ujjj+=n, ujji+=n) {
205 y=(*ujjj); z=(*ujji); (*ujjj)=y*c+z*s; (*ujji)=z*c-y*s;
206 }
207 }
208 }
209 rv1[l]=0; rv1[k]=f; w[k]=x;
210 }
211 }
212
213 if (n>NSTAT) free(rv1);
214 return(0);
215}
216
217inline int svbksb(double x[/*n x p*/], const double u[/*m x n*/],
218 const double w[/*n*/], const double v[/*n x n*/],
219 const double b[/*m x p*/], int m, int n, int p)
220{
221/*
222 Solves A X = B for X, where A = U x W x V^T is the SVD of the m by n
223 matrix A, B is an m by p matrix, and X is an n by p matrix.
224 Returns 0 on success, or a system error code otherwise.
225*/
226 int jj, j, i, k;
227 static double stmp[NSTAT];
228 double s, *tmp=(n<=NSTAT ? stmp : (double *)malloc(n*sizeof(double))), *xjk;
229
230 if (!tmp) return(errno);
231
232 for (k=0; k<p; k++) {
233 for (j=0; j<n; j++) {
234 s=0;
235 if (w[j]) {
236 const double *uij=u+j, *bik=b+k;
237
238 for (i=0; i<m; i++, uij+=n, bik+=p) s+=(*uij)*(*bik);
239 s/=w[j];
240 }
241 tmp[j]=s;
242 }
243 for (xjk=x+k, j=0; j<n; j++, xjk+=p) {
244 const double *vj=v+j*n;
245
246 s=0; for (jj=0; jj<n; jj++) s+=vj[jj]*tmp[jj];
247 (*xjk)=s;
248 }
249 }
250
251 if (n>NSTAT) free(tmp);
252 return(0);
253}
254
255inline int svsolve(double x[/*n x p*/], double wmin, double a[/*m x n*/],
256 const double b[/*m x p*/], int m, int n, int p, int preserve)
257{
258/*
259 Solve a (least squares) system of linear equations A X = B by singular value
260 decomposition. Zero all singular values smaller than wmin*max(w[]), using
261 wmin=WMIN if wmin<0. If preserve is non-zero, A is copied before
262 decomposition; A is m x n, B is m x p, and X will be n x p.
263 Returns 0 on success, or a system error code otherwise.
264*/
265 double *utmp, *w, *v, wmax;
266 int i, status;
267
268 w=(double *)malloc(n*sizeof(double));
269 v=(double *)malloc(n*n*sizeof(double));
270 utmp=(preserve ? (double *)malloc(m*n*sizeof(double)) : a);
271 if (!w || !v || !utmp) {
272 if (w) free(w);
273 if (v) free(v);
274 if (utmp && preserve) free(utmp);
275 return(errno);
276 }
277
278 status=svdcmp(utmp, w, v, a, m, n);
279 if (status) {
280 free(w); free(v); if (preserve) free(utmp);
281 return(status);
282 }
283
284 for (wmax=0, i=0; i<n; i++) if (wmax<w[i]) wmax=w[i];
285 if (wmin<0) wmax*=WMIN; else wmax*=wmin;
286 for (i=0; i<n; i++) if (w[i]<wmax) w[i]=0;
287
288 status=svbksb(x, utmp, w, v, b, m, n, p);
289 if (status) {
290 free(w); free(v); if (preserve) free(utmp);
291 return(status);
292 }
293
294 free(w); free(v); if (preserve) free(utmp);
295 return(0);
296}
297
298inline int svinverse(double x[/*n x m*/], double wmin, const double a[/*m x n*/],
299 int m, int n)
300{
301/*
302 Find the pseudoinverse of the m x n matrix A, zeroing singular values below
303 wmin*max(w[]). X should have space for an n x m matrix and can be the
304 same as A. Returns 0 on success, or a system error code otherwise.
305*/
306 double *u=(double *)malloc(n*m*sizeof(double)),
307 *w=(double *)malloc(n*sizeof(double)),
308 *v=(double *)malloc(n*n*sizeof(double)), wmax;
309 int i, j, k, status;
310
311 if (!u || !w || !v) {
312 if (u) free(u);
313 if (w) free(w);
314 if (v) free(v);
315 return(errno);
316 }
317
318 status=svdcmp(u, w, v, a, m, n);
319 if (status) { free(u); free(w); free(v); return(status); }
320
321 for (wmax=0, i=0; i<n; i++) if (wmax<w[i]) wmax=w[i];
322 if (wmin<0) wmax*=WMIN; else wmax*=wmin;
323 for (i=0; i<n; i++) if (w[i]<wmax) w[i]=0; else w[i]=1/w[i];
324 {
325 double *vi=v, *uj;
326
327 for (i=0; i<n; i++, vi+=n)
328 for (uj=u, j=0; j<m; j++, uj+=n, x++)
329 for (*x=0, k=0; k<n; k++) (*x)+=vi[k]*w[k]*uj[k];
330 }
331
332 free(u); free(w); free(v);
333 return(0);
334}
@ p
Definition Tools.h:60
#define WMIN
Definition svd.h:34
int svdcmp(double u[], double w[], double v[], const double a[], int m, int n)
Definition svd.h:36
int svsolve(double x[], double wmin, double a[], const double b[], int m, int n, int p, int preserve)
Definition svd.h:255
#define NSTAT
Definition svd.h:31
#define SIGN(a, b)
Definition svd.h:28
int svbksb(double x[], const double u[], const double w[], const double v[], const double b[], int m, int n, int p)
Definition svd.h:217
#define MAXIT
Definition svd.h:27
int svinverse(double x[], double wmin, const double a[], int m, int n)
Definition svd.h:298