Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
gaussian_elimination.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2017 Heiko Bauke.
4 Copyright (C) 2018-2020, 2025-2026 Aurélien PIERRE.
5 Copyright (C) 2019 luzpaz.
6 Copyright (C) 2020 Pascal Obry.
7 Copyright (C) 2022 Martin Bařinka.
8 Copyright (C) 2022 Miloš Komarčević.
9 Copyright (C) 2023 Luca Zulberti.
10 Copyright (C) 2024 Alynx Zhou.
11
12 darktable is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 darktable is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with darktable. If not, see <http://www.gnu.org/licenses/>.
24*/
25
26/*
27 These routines can be used to solve full-rank linear systems of
28 equations by Gaussian elimination with partial pivoting. The
29 functions gauss_make_triangular and gauss_solve have been adopted
30 from Fortran routines as presented in the book "Numerik" by
31 Helmuth Späth, Vieweg Verlag, 1994, see also
32 http://dx.doi.org/10.1007/978-3-322-89220-1
33
34*/
35
36
37#pragma once
38
39#include <math.h>
40#include <stdlib.h>
41
42// Gaussian elimination with partial vivoting
43// after function call the square matrix A is triangular
44// vector p keeps track of row swaps
45// returns 0 if matrix A is singular
46// matrix elements are stored in row-major order
47static int gauss_make_triangular(double *A, int *p, int n)
48{
49 p[n - 1] = n - 1; // we never swap from the last row
50 for(int k = 0; k < n; ++k)
51 {
52 // find pivot element for row swap
53 int m = k;
54 for(int i = k + 1; i < n; ++i)
55 if(fabs(A[k + n * i]) > fabs(A[k + n * m])) m = i;
56 p[k] = m; // rows k and m are swapped
57 // eliminate elements and swap rows
58 double t1 = A[k + n * m];
59 A[k + n * m] = A[k + n * k];
60 A[k + n * k] = t1; // new diagonal elements are (implicitly) one, store scaling factors on diagonal
61 if(t1 != 0)
62 {
63 for(int i = k + 1; i < n; ++i) A[k + n * i] /= -t1;
64 // swap rows
65 if(k != m)
66 for(int i = k + 1; i < n; ++i)
67 {
68 double t2 = A[i + n * m];
69 A[i + n * m] = A[i + n * k];
70 A[i + n * k] = t2;
71 }
72 for(int j = k + 1; j < n; ++j)
73 for(int i = k + 1; i < n; ++i) A[i + n * j] += A[k + j * n] * A[i + k * n];
74 }
75 else
76 // the matrix is singular
77 return 0;
78 }
79 return 1;
80}
81
82// backward substritution after Gaussian elimination
83static void gauss_solve_triangular(const double *A, const int *p, double *b, int n)
84{
85 // permute and rescale elements of right-hand-side
86 for(int k = 0; k < n - 1; ++k)
87 {
88 int m = p[k];
89 double t = b[m];
90 b[m] = b[k];
91 b[k] = t;
92 for(int i = k + 1; i < n; ++i) b[i] += A[k + n * i] * t;
93 }
94 // perform backward substritution
95 for(int k = n - 1; k > 0; --k)
96 {
97 b[k] /= A[k + n * k];
98 double t = b[k];
99 for(int i = 0; i < k; ++i) b[i] -= A[k + n * i] * t;
100 }
101 b[0] /= A[0 + 0 * n];
102}
103
104static int gauss_solve(double *A, double *b, int n)
105{
106 int *p = malloc(n * sizeof(*p));
107 int err_code = 1;
108 if((err_code = gauss_make_triangular(A, p, n))) gauss_solve_triangular(A, p, b, n);
109 dt_free(p);
110 return err_code;
111}
112
113
114static inline int transpose_dot_matrix(double *const restrict A, // input
115 double *const restrict A_square, // output
116 const size_t m, const size_t n)
117{
118 // Construct the square symmetrical definite positive matrix A' A,
119
120 for(size_t i = 0; i < n; ++i)
121 for(size_t j = 0; j < n; ++j)
122 {
123 double sum = 0.0;
124 for(size_t k = 0; k < m; ++k)
125 sum += A[k * n + i] * A[k * n + j];
126
127 A_square[i * n + j] = sum;
128 }
129
130 return 0;
131}
132
133
134static inline int transpose_dot_vector(double *const restrict A, // input
135 double *const restrict y, // input
136 double *const restrict y_square, // output
137 const size_t m, const size_t n)
138{
139 // Construct the vector A' y
140 for(size_t i = 0; i < n; ++i)
141 {
142 double sum = 0.0;
143 for(size_t k = 0; k < m; ++k)
144 sum += A[k * n + i] * y[k];
145
146 y_square[i] = sum;
147 }
148
149 return 0;
150}
151
152
153static inline int pseudo_solve_gaussian(double *const restrict A,
154 double *const restrict y,
155 const size_t m, const size_t n, const int checks)
156{
157 // Solve the weighted linear problem w A'A x = w A' y with the over-constrained rectanguler matrix A
158 // of dimension m x n (m >= n) and w a vector of weights, by the least squares method
159 int err = 0;
160
161 if(m < n)
162 {
163 fprintf(stderr, "pseudo solve: cannot cast %zu \303\227 %zu matrix\n", m, n);
164 return 1;
165 }
166
167 double *const restrict A_square = dt_pixelpipe_cache_alloc_align_cache(n * n * sizeof(double), 0);
168 double *const restrict y_square = dt_pixelpipe_cache_alloc_align_cache(n * sizeof(double), 0);
169
170 if(y_square == NULL || A_square == NULL)
171 {
172 err = 1;
173 goto error;
174 }
175
176 #ifdef _OPENMP
177 #pragma omp parallel sections
178 #endif
179 {
180 #ifdef _OPENMP
181 #pragma omp section
182 #endif
183 {
184 // Prepare the least squares matrix = A' A
185 transpose_dot_matrix(A, A_square, m, n);
186 }
187
188 #ifdef _OPENMP
189 #pragma omp section
190 #endif
191 {
192 // Prepare the y square vector = A' y
193 transpose_dot_vector(A, y, y_square, m, n);
194 }
195 }
196
197 // Solve A' A x = A' y for x
198 if(gauss_solve(A_square, y_square, n) == 0)
199 {
200 err = 1;
201 goto error;
202 }
203 for(size_t k = 0; k < n; k++) y[k] = y_square[k];
204
205error:;
208
209 return err;
210}
211// clang-format off
212// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
213// vim: shiftwidth=2 expandtab tabstop=2 cindent
214// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
215// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define m
Definition basecurve.c:277
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
Definition chromatic_adaptation.h:315
#define A(y, x)
Definition colorspaces.c:186
const float i
Definition colorspaces_inline_conversions.h:669
const float b
Definition colorspaces_inline_conversions.h:1326
const float n
Definition colorspaces_inline_conversions.h:929
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:357
#define dt_free(ptr)
Definition darktable.h:380
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:377
static int pseudo_solve_gaussian(double *const restrict A, double *const restrict y, const size_t m, const size_t n, const int checks)
Definition gaussian_elimination.h:153
static int transpose_dot_matrix(double *const restrict A, double *const restrict A_square, const size_t m, const size_t n)
Definition gaussian_elimination.h:114
static int gauss_make_triangular(double *A, int *p, int n)
Definition gaussian_elimination.h:47
static void gauss_solve_triangular(const double *A, const int *p, double *b, int n)
Definition gaussian_elimination.h:83
static int gauss_solve(double *A, double *b, int n)
Definition gaussian_elimination.h:104
static int transpose_dot_vector(double *const restrict A, double *const restrict y, double *const restrict y_square, const size_t m, const size_t n)
Definition gaussian_elimination.h:134
const int t
Definition iop_profile.h:227