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