Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
svd.h
Go to the documentation of this file.
1/*
2 * svdcomp - SVD decomposition routine.
3 * Takes an mxn matrix a and decomposes it into udv, where u,v are
4 * left and right orthogonal transformation matrices, and d is a
5 * diagonal matrix of singular values.
6 *
7 * This routine is adapted from svdecomp.c in XLISP-STAT 2.1 which is
8 * adapted by Luke Tierney and David Betz.
9 *
10 * the now dead xlisp-stat package seems to have been distributed
11 * under some sort of BSD license.
12 *
13 * Input to dsvd is as follows:
14 * a = mxn matrix to be decomposed, gets overwritten with u
15 * m = row dimension of a
16 * n = column dimension of a
17 * w = returns the vector of singular values of a
18 * v = returns the right orthogonal transformation matrix
19*/
20
21#pragma once
22
23#include <math.h>
24#include <stdio.h>
25#include <stdlib.h>
26
27
28static inline double SIGN(double a, double b)
29{
30 return copysign(a, b);
31}
32
33
34static inline double PYTHAG(double a, double b)
35{
36 const double at = fabs(a), bt = fabs(b);
37 if (at > bt)
38 {
39 const double ct = bt / at;
40 return at * sqrt(1.0 + ct * ct);
41 }
42 if (bt > 0.0)
43 {
44 const double ct = at / bt;
45 return bt * sqrt(1.0 + ct * ct);
46 }
47 return 0.0;
48}
49
50
51// decompose (m >= n)
52// n n n
53// | | | | n | |
54// m | a | = m | u | diag(w) | v^t | n
55// | | | | | |
56//
57// where the data layout of a (in) and u (out) is strided by str for every row
58static inline int dsvd(
59 double *a, // input matrix a[j*str + i] is j-th row and i-th column. will be overwritten by u
60 int m, // number of rows of a and u
61 int n, // number of cols of a and u
62 int str, // row stride of a and u
63 double *w, // output singular values w[n]
64 double *v) // output v matrix v[n*n]
65{
66 if (m < n)
67 {
68 fprintf(stderr, "[svd] #rows must be >= #cols \n");
69 return 0;
70 }
71
72 double c, f, h, s, x, y, z;
73 double anorm = 0.0, g = 0.0, scale = 0.0;
74 double *rv1 = malloc(n * sizeof(double));
75 int l = 0;
76
77 /* Householder reduction to bidiagonal form */
78 for (int i = 0; i < n; i++)
79 {
80 /* left-hand reduction */
81 l = i + 1;
82 rv1[i] = scale * g;
83 g = s = scale = 0.0;
84 if (i < m)
85 {
86 for (int k = i; k < m; k++)
87 scale += fabs(a[k*str+i]);
88 if (scale != 0.0)
89 {
90 for (int k = i; k < m; k++)
91 {
92 a[k*str+i] = a[k*str+i]/scale;
93 s += a[k*str+i] * a[k*str+i];
94 }
95 f = a[i*str+i];
96 g = -SIGN(sqrt(s), f);
97 h = f * g - s;
98 a[i*str+i] = f - g;
99 if (i != n - 1)
100 {
101 for (int j = l; j < n; j++)
102 {
103 s = 0.0;
104 for (int k = i; k < m; k++)
105 s += a[k*str+i] * a[k*str+j];
106 f = s / h;
107 for (int k = i; k < m; k++)
108 a[k*str+j] += f * a[k*str+i];
109 }
110 }
111 for (int k = i; k < m; k++)
112 a[k*str+i] = a[k*str+i]*scale;
113 }
114 }
115 w[i] = scale * g;
116
117 /* right-hand reduction */
118 g = s = scale = 0.0;
119 if (i < m && i != n - 1)
120 {
121 for (int k = l; k < n; k++)
122 scale += fabs(a[i*str+k]);
123 if (scale != 0.0)
124 {
125 for (int k = l; k < n; k++)
126 {
127 a[i*str+k] = a[i*str+k]/scale;
128 s += a[i*str+k] * a[i*str+k];
129 }
130 f = a[i*str+l];
131 g = -SIGN(sqrt(s), f);
132 h = f * g - s;
133 a[i*str+l] = f - g;
134 for (int k = l; k < n; k++)
135 rv1[k] = a[i*str+k] / h;
136 if (i != m - 1)
137 {
138 for (int j = l; j < m; j++)
139 {
140 s = 0.0;
141 for (int k = l; k < n; k++)
142 s += a[j*str+k] * a[i*str+k];
143 for (int k = l; k < n; k++)
144 a[j*str+k] += s * rv1[k];
145 }
146 }
147 for (int k = l; k < n; k++)
148 a[i*str+k] = a[i*str+k]*scale;
149 }
150 }
151 anorm = MAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
152 }
153
154 /* accumulate the right-hand transformation */
155 for (int i = n - 1; i >= 0; i--)
156 {
157 if (i < n - 1)
158 {
159 if (g != 0.0)
160 {
161 for (int j = l; j < n; j++)
162 v[j*n+i] = a[i*str+j] / a[i*str+l] / g;
163 /* double division to avoid underflow */
164 for (int j = l; j < n; j++)
165 {
166 s = 0.0;
167 for (int k = l; k < n; k++)
168 s += a[i*str+k] * v[k*n+j];
169 for (int k = l; k < n; k++)
170 v[k*n+j] += s * v[k*n+i];
171 }
172 }
173 for (int j = l; j < n; j++)
174 v[i*n+j] = v[j*n+i] = 0.0;
175 }
176 v[i*n+i] = 1.0;
177 g = rv1[i];
178 l = i;
179 }
180
181 /* accumulate the left-hand transformation */
182 for (int i = n - 1; i >= 0; i--)
183 {
184 l = i + 1;
185 g = w[i];
186 if (i < n - 1)
187 for (int j = l; j < n; j++)
188 a[i*str+j] = 0.0;
189 if (g != 0.0)
190 {
191 g = 1.0 / g;
192 if (i != n - 1)
193 {
194 for (int j = l; j < n; j++)
195 {
196 s = 0.0;
197 for (int k = l; k < m; k++)
198 s += a[k*str+i] * a[k*str+j];
199 f = (s / a[i*str+i]) * g;
200 for (int k = i; k < m; k++)
201 a[k*str+j] += f * a[k*str+i];
202 }
203 }
204 for (int j = i; j < m; j++)
205 a[j*str+i] = a[j*str+i]*g;
206 }
207 else
208 {
209 for (int j = i; j < m; j++)
210 a[j*str+i] = 0.0;
211 }
212 ++a[i*str+i];
213 }
214
215 /* diagonalize the bidiagonal form */
216 for (int k = n - 1; k >= 0; k--)
217 { /* loop over singular values */
218 const int max_its = 30;
219 for (int its = 0; its <= max_its; its++)
220 { /* loop over allowed iterations */
221 _Bool flag = 1;
222 int nm = 0;
223 for (l = k; l >= 0; l--)
224 { /* test for splitting */
225 nm = MAX(0, l - 1);
226 if (fabs(rv1[l]) + anorm == anorm)
227 {
228 flag = 0;
229 break;
230 }
231 if (l == 0 || fabs(w[nm]) + anorm == anorm)
232 break;
233 }
234 if (flag)
235 {
236 s = 1.0;
237 for (int i = l; i <= k; i++)
238 {
239 f = s * rv1[i];
240 if (fabs(f) + anorm != anorm)
241 {
242 g = w[i];
243 h = PYTHAG(f, g);
244 w[i] = h;
245 h = 1.0 / h;
246 c = g * h;
247 s = (- f * h);
248 for (int j = 0; j < m; j++)
249 {
250 y = a[j*str+nm];
251 z = a[j*str+i];
252 a[j*str+nm] = y * c + z * s;
253 a[j*str+i] = z * c - y * s;
254 }
255 }
256 }
257 }
258 z = w[k];
259 if (l == k)
260 { /* convergence */
261 if (z < 0.0)
262 { /* make singular value nonnegative */
263 w[k] = -z;
264 for (int j = 0; j < n; j++)
265 v[j*n+k] = -v[j*n+k];
266 }
267 break;
268 }
269 if (its >= max_its) {
270 fprintf(stderr, "[svd] no convergence after %d iterations\n", its);
271 free(rv1);
272 return 0;
273 }
274
275 /* shift from bottom 2 x 2 minor */
276 x = w[l];
277 nm = k - 1;
278 y = w[nm];
279 g = rv1[nm];
280 h = rv1[k];
281 f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
282 g = PYTHAG(f, 1.0);
283 f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
284
285 /* next QR transformation */
286 c = s = 1.0;
287 for (int j = l; j <= nm; j++)
288 {
289 const int i = j + 1;
290 g = rv1[i];
291 y = w[i];
292 h = s * g;
293 g = c * g;
294 z = PYTHAG(f, h);
295 rv1[j] = z;
296 c = f / z;
297 s = h / z;
298 f = x * c + g * s;
299 g = g * c - x * s;
300 h = y * s;
301 y = y * c;
302 for (int jj = 0; jj < n; jj++)
303 {
304 x = v[jj*n+j];
305 z = v[jj*n+i];
306 v[jj*n+j] = x * c + z * s;
307 v[jj*n+i] = z * c - x * s;
308 }
309 z = PYTHAG(f, h);
310 w[j] = z;
311 if (z != 0.0)
312 {
313 z = 1.0 / z;
314 c = f * z;
315 s = h * z;
316 }
317 f = (c * g) + (s * y);
318 x = (c * y) - (s * g);
319 for (int jj = 0; jj < m; jj++)
320 {
321 y = a[jj*str+j];
322 z = a[jj*str+i];
323 a[jj*str+j] = y * c + z * s;
324 a[jj*str+i] = z * c - y * s;
325 }
326 }
327 rv1[l] = 0.0;
328 rv1[k] = f;
329 w[k] = x;
330 }
331 }
332 free(rv1);
333 return 1;
334}
335
336// clang-format off
337// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
338// vim: shiftwidth=2 expandtab tabstop=2 cindent
339// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
340// clang-format on
341
#define m
Definition basecurve.c:231
const char flag
Definition common/image.h:164
static float f(const float t, const float c, const float x)
Definition graduatednd.c:173
static double PYTHAG(double a, double b)
Definition svd.h:34
static double SIGN(double a, double b)
Definition svd.h:28
static int dsvd(double *a, int m, int n, int str, double *w, double *v)
Definition svd.h:58
#define MAX(a, b)
Definition thinplate.c:20