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
34#pragma once
35
36#include <math.h>
37#include <stdio.h>
38#include <stdlib.h>
39
40
41static inline double SIGN(double a, double b)
42{
43 return copysign(a, b);
44}
45
46
47static inline double PYTHAG(double a, double b)
48{
49 const double at = fabs(a), bt = fabs(b);
50 if (at > bt)
51 {
52 const double ct = bt / at;
53 return at * sqrt(1.0 + ct * ct);
54 }
55 if (bt > 0.0)
56 {
57 const double ct = at / bt;
58 return bt * sqrt(1.0 + ct * ct);
59 }
60 return 0.0;
61}
62
63
80static inline int dsvd(
81 double *a, // input matrix a[j*str + i] is j-th row and i-th column. will be overwritten by u
82 int m, // number of rows of a and u
83 int n, // number of cols of a and u
84 int str, // row stride of a and u
85 double *w, // output singular values w[n]
86 double *v) // output v matrix v[n*n]
87{
88 if (m < n)
89 {
90 fprintf(stderr, "[svd] #rows must be >= #cols \n");
91 return 0;
92 }
93
94 double c, f, h, s, x, y, z;
95 double anorm = 0.0, g = 0.0, scale = 0.0;
96 double *rv1 = malloc(n * sizeof(double));
97 int l = 0;
98
99 /* Householder reduction to bidiagonal form */
100 for (int i = 0; i < n; i++)
101 {
102 /* left-hand reduction */
103 l = i + 1;
104 rv1[i] = scale * g;
105 g = s = scale = 0.0;
106 if (i < m)
107 {
108 for (int k = i; k < m; k++)
109 scale += fabs(a[k*str+i]);
110 if (scale != 0.0)
111 {
112 for (int k = i; k < m; k++)
113 {
114 a[k*str+i] = a[k*str+i]/scale;
115 s += a[k*str+i] * a[k*str+i];
116 }
117 f = a[i*str+i];
118 g = -SIGN(sqrt(s), f);
119 h = f * g - s;
120 a[i*str+i] = f - g;
121 if (i != n - 1)
122 {
123 for (int j = l; j < n; j++)
124 {
125 s = 0.0;
126 for (int k = i; k < m; k++)
127 s += a[k*str+i] * a[k*str+j];
128 f = s / h;
129 for (int k = i; k < m; k++)
130 a[k*str+j] += f * a[k*str+i];
131 }
132 }
133 for (int k = i; k < m; k++)
134 a[k*str+i] = a[k*str+i]*scale;
135 }
136 }
137 w[i] = scale * g;
138
139 /* right-hand reduction */
140 g = s = scale = 0.0;
141 if (i < m && i != n - 1)
142 {
143 for (int k = l; k < n; k++)
144 scale += fabs(a[i*str+k]);
145 if (scale != 0.0)
146 {
147 for (int k = l; k < n; k++)
148 {
149 a[i*str+k] = a[i*str+k]/scale;
150 s += a[i*str+k] * a[i*str+k];
151 }
152 f = a[i*str+l];
153 g = -SIGN(sqrt(s), f);
154 h = f * g - s;
155 a[i*str+l] = f - g;
156 for (int k = l; k < n; k++)
157 rv1[k] = a[i*str+k] / h;
158 if (i != m - 1)
159 {
160 for (int j = l; j < m; j++)
161 {
162 s = 0.0;
163 for (int k = l; k < n; k++)
164 s += a[j*str+k] * a[i*str+k];
165 for (int k = l; k < n; k++)
166 a[j*str+k] += s * rv1[k];
167 }
168 }
169 for (int k = l; k < n; k++)
170 a[i*str+k] = a[i*str+k]*scale;
171 }
172 }
173 anorm = MAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
174 }
175
176 /* accumulate the right-hand transformation */
177 for (int i = n - 1; i >= 0; i--)
178 {
179 if (i < n - 1)
180 {
181 if (g != 0.0)
182 {
183 for (int j = l; j < n; j++)
184 v[j*n+i] = a[i*str+j] / a[i*str+l] / g;
185 /* double division to avoid underflow */
186 for (int j = l; j < n; j++)
187 {
188 s = 0.0;
189 for (int k = l; k < n; k++)
190 s += a[i*str+k] * v[k*n+j];
191 for (int k = l; k < n; k++)
192 v[k*n+j] += s * v[k*n+i];
193 }
194 }
195 for (int j = l; j < n; j++)
196 v[i*n+j] = v[j*n+i] = 0.0;
197 }
198 v[i*n+i] = 1.0;
199 g = rv1[i];
200 l = i;
201 }
202
203 /* accumulate the left-hand transformation */
204 for (int i = n - 1; i >= 0; i--)
205 {
206 l = i + 1;
207 g = w[i];
208 if (i < n - 1)
209 for (int j = l; j < n; j++)
210 a[i*str+j] = 0.0;
211 if (g != 0.0)
212 {
213 g = 1.0 / g;
214 if (i != n - 1)
215 {
216 for (int j = l; j < n; j++)
217 {
218 s = 0.0;
219 for (int k = l; k < m; k++)
220 s += a[k*str+i] * a[k*str+j];
221 f = (s / a[i*str+i]) * g;
222 for (int k = i; k < m; k++)
223 a[k*str+j] += f * a[k*str+i];
224 }
225 }
226 for (int j = i; j < m; j++)
227 a[j*str+i] = a[j*str+i]*g;
228 }
229 else
230 {
231 for (int j = i; j < m; j++)
232 a[j*str+i] = 0.0;
233 }
234 ++a[i*str+i];
235 }
236
237 /* diagonalize the bidiagonal form */
238 for (int k = n - 1; k >= 0; k--)
239 { /* loop over singular values */
240 const int max_its = 30;
241 for (int its = 0; its <= max_its; its++)
242 { /* loop over allowed iterations */
243 _Bool flag = 1;
244 int nm = 0;
245 for (l = k; l >= 0; l--)
246 { /* test for splitting */
247 nm = MAX(0, l - 1);
248 if (fabs(rv1[l]) + anorm == anorm)
249 {
250 flag = 0;
251 break;
252 }
253 if (l == 0 || fabs(w[nm]) + anorm == anorm)
254 break;
255 }
256 if (flag)
257 {
258 s = 1.0;
259 for (int i = l; i <= k; i++)
260 {
261 f = s * rv1[i];
262 if (fabs(f) + anorm != anorm)
263 {
264 g = w[i];
265 h = PYTHAG(f, g);
266 w[i] = h;
267 h = 1.0 / h;
268 c = g * h;
269 s = (- f * h);
270 for (int j = 0; j < m; j++)
271 {
272 y = a[j*str+nm];
273 z = a[j*str+i];
274 a[j*str+nm] = y * c + z * s;
275 a[j*str+i] = z * c - y * s;
276 }
277 }
278 }
279 }
280 z = w[k];
281 if (l == k)
282 { /* convergence */
283 if (z < 0.0)
284 { /* make singular value nonnegative */
285 w[k] = -z;
286 for (int j = 0; j < n; j++)
287 v[j*n+k] = -v[j*n+k];
288 }
289 break;
290 }
291 if (its >= max_its) {
292 fprintf(stderr, "[svd] no convergence after %d iterations\n", its);
293 dt_free(rv1);
294 return 0;
295 }
296
297 /* shift from bottom 2 x 2 minor */
298 x = w[l];
299 nm = k - 1;
300 y = w[nm];
301 g = rv1[nm];
302 h = rv1[k];
303 f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
304 g = PYTHAG(f, 1.0);
305 f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
306
307 /* next QR transformation */
308 c = s = 1.0;
309 for (int j = l; j <= nm; j++)
310 {
311 const int i = j + 1;
312 g = rv1[i];
313 y = w[i];
314 h = s * g;
315 g = c * g;
316 z = PYTHAG(f, h);
317 rv1[j] = z;
318 c = f / z;
319 s = h / z;
320 f = x * c + g * s;
321 g = g * c - x * s;
322 h = y * s;
323 y = y * c;
324 for (int jj = 0; jj < n; jj++)
325 {
326 x = v[jj*n+j];
327 z = v[jj*n+i];
328 v[jj*n+j] = x * c + z * s;
329 v[jj*n+i] = z * c - x * s;
330 }
331 z = PYTHAG(f, h);
332 w[j] = z;
333 if (z != 0.0)
334 {
335 z = 1.0 / z;
336 c = f * z;
337 s = h * z;
338 }
339 f = (c * g) + (s * y);
340 x = (c * y) - (s * g);
341 for (int jj = 0; jj < m; jj++)
342 {
343 y = a[jj*str+j];
344 z = a[jj*str+i];
345 a[jj*str+j] = y * c + z * s;
346 a[jj*str+i] = z * c - y * s;
347 }
348 }
349 rv1[l] = 0.0;
350 rv1[k] = f;
351 w[k] = x;
352 }
353 }
354 dt_free(rv1);
355 return 1;
356}
357
358// clang-format off
359// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
360// vim: shiftwidth=2 expandtab tabstop=2 cindent
361// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
362// clang-format on
#define m
Definition basecurve.c:277
const float i
Definition colorspaces_inline_conversions.h:440
const float g
Definition colorspaces_inline_conversions.h:674
const dt_aligned_pixel_t f
Definition colorspaces_inline_conversions.h:102
const float n
Definition colorspaces_inline_conversions.h:678
#define dt_free(ptr)
Definition darktable.h:456
const char flag
Definition image.h:218
static const float x
Definition iop_profile.h:235
const float v
Definition iop_profile.h:221
float *const restrict const size_t k
Definition luminance_mask.h:78
static double PYTHAG(double a, double b)
Definition svd.h:47
static double SIGN(double a, double b)
Definition svd.h:41
static int dsvd(double *a, int m, int n, int str, double *w, double *v)
Compute the singular value decomposition of a dense matrix.
Definition svd.h:80
#define MAX(a, b)
Definition thinplate.c:29