1 | #include "slalib.h"
|
---|
2 | #include "slamac.h"
|
---|
3 | void slaSvdsol ( int m, int n, int mp, int np, double *b, double *u,
|
---|
4 | double *w, double *v, double *work, double *x )
|
---|
5 | /*
|
---|
6 | ** - - - - - - - - - -
|
---|
7 | ** s l a S v d s o l
|
---|
8 | ** - - - - - - - - - -
|
---|
9 | **
|
---|
10 | ** From a given vector and the SVD of a matrix (as obtained from
|
---|
11 | ** the slaSvd routine), obtain the solution vector.
|
---|
12 | **
|
---|
13 | ** (double precision)
|
---|
14 | **
|
---|
15 | ** This routine solves the equation:
|
---|
16 | **
|
---|
17 | ** a . x = b
|
---|
18 | **
|
---|
19 | ** where:
|
---|
20 | **
|
---|
21 | ** a is a given m (rows) x n (columns) matrix, where m.ge.n
|
---|
22 | ** x is the n-vector we wish to find
|
---|
23 | ** b is a given m-vector
|
---|
24 | **
|
---|
25 | ** By means of the singular value decomposition method (SVD). In
|
---|
26 | ** this method, the matrix a is first factorized (for example by
|
---|
27 | ** the routine slaSvd) into the following components:
|
---|
28 | **
|
---|
29 | ** a = u x w x vt
|
---|
30 | **
|
---|
31 | ** where:
|
---|
32 | **
|
---|
33 | ** a is the m (rows) x n (columns) matrix
|
---|
34 | ** u is an m x n column-orthogonal matrix
|
---|
35 | ** w is an n x n diagonal matrix with w(i,i).ge.0
|
---|
36 | ** vt is the transpose of an nxn orthogonal matrix
|
---|
37 | **
|
---|
38 | ** Note that m and n, above, are the logical dimensions of the
|
---|
39 | ** matrices and vectors concerned, which can be located in
|
---|
40 | ** arrays of larger physical dimensions mp and np.
|
---|
41 | **
|
---|
42 | ** The solution is found from the expression:
|
---|
43 | **
|
---|
44 | ** x = v . [diag(1/wj)] . ( transpose(u) . b )
|
---|
45 | **
|
---|
46 | ** Notes:
|
---|
47 | **
|
---|
48 | ** 1) If matrix a is square, and if the diagonal matrix w is not
|
---|
49 | ** adjusted, the method is equivalent to conventional solution
|
---|
50 | ** of simultaneous equations.
|
---|
51 | **
|
---|
52 | ** 2) If m>n, the result is a least-squares fit.
|
---|
53 | **
|
---|
54 | ** 3) If the solution is poorly determined, this shows up in the
|
---|
55 | ** SVD factorization as very small or zero wj values. Where
|
---|
56 | ** a wj value is small but non-zero it can be set to zero to
|
---|
57 | ** avoid ill effects. The present routine detects such zero
|
---|
58 | ** wj values and produces a sensible solution, with highly
|
---|
59 | ** correlated terms kept under control rather than being allowed
|
---|
60 | ** to elope to infinity, and with meaningful values for the
|
---|
61 | ** other terms.
|
---|
62 | **
|
---|
63 | ** Given:
|
---|
64 | ** m,n int numbers of rows and columns in matrix a
|
---|
65 | ** mp,np int physical dimensions of array containing matrix a
|
---|
66 | ** *b double[m] known vector b
|
---|
67 | ** *u double[mp][np] array containing mxn matrix u
|
---|
68 | ** *w double[n] nxn diagonal matrix w (diagonal elements only)
|
---|
69 | ** *v double[np][np] array containing nxn orthogonal matrix v
|
---|
70 | **
|
---|
71 | ** Returned:
|
---|
72 | ** *work double[n] workspace
|
---|
73 | ** *x double[n] unknown vector x
|
---|
74 | **
|
---|
75 | ** Note: If the relative sizes of m, n, mp and np are inconsistent,
|
---|
76 | ** the vector x is returned unaltered. This condition should
|
---|
77 | ** have been detected when the SVD was performed using slaSvd.
|
---|
78 | **
|
---|
79 | ** Reference:
|
---|
80 | ** Numerical Recipes, Section 2.9.
|
---|
81 | **
|
---|
82 | ** Example call (note handling of "adjustable dimension" 2D arrays):
|
---|
83 | **
|
---|
84 | ** double a[MP][NP], w[NP], v[NP][NP], work[NP], b[MP], x[NP];
|
---|
85 | ** int m, n;
|
---|
86 | ** :
|
---|
87 | ** slaSvdsol ( m, n, MP, NP, b, (double *) a, w, (double *) v, work, x );
|
---|
88 | **
|
---|
89 | ** Last revision: 20 February 1995
|
---|
90 | **
|
---|
91 | ** Copyright P.T.Wallace. All rights reserved.
|
---|
92 | */
|
---|
93 | {
|
---|
94 | int j, i, jj;
|
---|
95 | double s;
|
---|
96 | double *ui;
|
---|
97 | double *vj;
|
---|
98 |
|
---|
99 | /* Check that the matrix is the right size and shape */
|
---|
100 | if ( m >= n && m <= mp && n <= np ) {
|
---|
101 |
|
---|
102 | /* Calculate [diag(1/wj)] . transpose(u) . b (or zero for zero wj) */
|
---|
103 | for ( j = 0; j < n; j++ ) {
|
---|
104 | s = 0.0;
|
---|
105 | if ( w[j] != 0.0 ) {
|
---|
106 | for ( i = 0, ui = u;
|
---|
107 | i < m;
|
---|
108 | i++, ui += np ) {
|
---|
109 | s += ui[j] * b[i];
|
---|
110 | }
|
---|
111 | s /= w[j];
|
---|
112 | }
|
---|
113 | work[j] = s;
|
---|
114 | }
|
---|
115 |
|
---|
116 | /* Multiply by matrix v to get result */
|
---|
117 | for ( j = 0, vj = v;
|
---|
118 | j < n;
|
---|
119 | j++, vj += np ) {
|
---|
120 | s = 0.0;
|
---|
121 | for ( jj = 0; jj < n; jj++ ) {
|
---|
122 | s += vj[jj] * work[jj];
|
---|
123 | }
|
---|
124 | x[j] = s;
|
---|
125 | }
|
---|
126 | }
|
---|
127 | }
|
---|