Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
ashift_nmsimplex.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2016 Tobias Ellinghaus.
4 Copyright (C) 2016 Ulrich Pegelow.
5 Copyright (C) 2017 luzpaz.
6 Copyright (C) 2020 Hubert Kowalski.
7 Copyright (C) 2020 Pascal Obry.
8 Copyright (C) 2022 Martin Bařinka.
9 Copyright (C) 2023, 2025 Aurélien PIERRE.
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/* For parameter optimization we are using the Nelder-Mead simplex method
26 * implemented by Michael F. Hutt.
27 * Changes versus the original code:
28 * do not include "nmsimplex.h" (not needed)
29 * renamed configuration variables to NMS_*
30 * add additional argument to objfun for arbitrary parameters
31 * simplex() returns number of used iterations instead of min value
32 * maximum number of iterations as function parameter
33 * make interface function simplex() static * initialize i and j to avoid compiler warnings
34 * comment out printing of status inormation
35 * reformat according to darktable's clang standards
36 */
37
38/*==================================================================================
39 * begin nmsimplex code downloaded from http://www.mikehutt.com/neldermead.html
40 * on February 6, 2016
41 *==================================================================================*/
42/*
43 * Program: nmsimplex.c
44 * Author : Michael F. Hutt
45 * http://www.mikehutt.com
46 * 11/3/97
47 *
48 * An implementation of the Nelder-Mead simplex method.
49 *
50 * Copyright (c) 1997-2011 <Michael F. Hutt>
51 *
52 * Permission is hereby granted, free of charge, to any person obtaining
53 * a copy of this software and associated documentation files (the
54 * "Software"), to deal in the Software without restriction, including
55 * without limitation the rights to use, copy, modify, merge, publish,
56 * distribute, sublicense, and/or sell copies of the Software, and to
57 * permit persons to whom the Software is furnished to do so, subject to
58 * the following conditions:
59 *
60 * The above copyright notice and this permission notice shall be
61 * included in all copies or substantial portions of the Software.
62 *
63 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
64 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
65 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
66 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
67 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
68 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
69 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
70 *
71 *
72 * Jan. 6, 1999
73 * Modified to conform to the algorithm presented
74 * in Margaret H. Wright's paper on Direct Search Methods.
75 *
76 * Jul. 23, 2007
77 * Fixed memory leak.
78 *
79 * Mar. 1, 2011
80 * Added constraints.
81 */
82
83//#include "nmsimplex.h"
84
85static int simplex(double (*objfunc)(double[], void *params), double start[], int n, double EPSILON, double scale,
86 int maxiter, void (*constrain)(double[], int n), void *params)
87{
88
89 int vs; /* vertex with smallest value */
90 int vh; /* vertex with next smallest value */
91 int vg; /* vertex with largest value */
92
93 int i = 0, j = 0, m, row;
94 int itr; /* track the number of iterations */
95
96 double **v; /* holds vertices of simplex */
97 double pn, qn; /* values used to create initial simplex */
98 double *f; /* value of function at each vertex */
99 double fr; /* value of function at reflection point */
100 double fe; /* value of function at expansion point */
101 double fc; /* value of function at contraction point */
102 double *vr; /* reflection - coordinates */
103 double *ve; /* expansion - coordinates */
104 double *vc; /* contraction - coordinates */
105 double *vm; /* centroid - coordinates */
106 //double min;
107
108 double fsum, favg, s, cent;
109
110 /* dynamically allocate arrays */
111
112 /* allocate the rows of the arrays */
113 v = (double **)malloc(sizeof(double *) * (n + 1));
114 f = (double *)malloc(sizeof(double) * (n + 1));
115 vr = (double *)malloc(sizeof(double) * n);
116 ve = (double *)malloc(sizeof(double) * n);
117 vc = (double *)malloc(sizeof(double) * n);
118 vm = (double *)malloc(sizeof(double) * n);
119
120 /* allocate the columns of the arrays */
121 for(i = 0; i <= n; i++)
122 {
123 v[i] = (double *)malloc(sizeof(double) * n);
124 }
125
126 /* create the initial simplex */
127 /* assume one of the vertices is 0,0 */
128
129 pn = scale * (sqrt(n + 1) - 1 + n) / (n * sqrt(2));
130 qn = scale * (sqrt(n + 1) - 1) / (n * sqrt(2));
131
132 for(i = 0; i < n; i++)
133 {
134 v[0][i] = start[i];
135 }
136
137 for(i = 1; i <= n; i++)
138 {
139 for(j = 0; j < n; j++)
140 {
141 if(i - 1 == j)
142 {
143 v[i][j] = pn + start[j];
144 }
145 else
146 {
147 v[i][j] = qn + start[j];
148 }
149 }
150 }
151
152 if(constrain != NULL)
153 {
154 constrain(v[j], n);
155 }
156 /* find the initial function values */
157 for(j = 0; j <= n; j++)
158 {
159 f[j] = objfunc(v[j], params);
160 }
161
162#if 0
163 /* print out the initial values */
164 printf("Initial Values\n");
165 for(j = 0; j <= n; j++)
166 {
167 for(i = 0; i < n; i++)
168 {
169 printf("%f %f\n", v[j][i], f[j]);
170 }
171 }
172#endif
173
174 /* begin the main loop of the minimization */
175 for(itr = 1; itr <= maxiter; itr++)
176 {
177 /* find the index of the largest value */
178 vg = 0;
179 for(j = 0; j <= n; j++)
180 {
181 if(f[j] > f[vg])
182 {
183 vg = j;
184 }
185 }
186
187 /* find the index of the smallest value */
188 vs = 0;
189 for(j = 0; j <= n; j++)
190 {
191 if(f[j] < f[vs])
192 {
193 vs = j;
194 }
195 }
196
197 /* find the index of the second largest value */
198 vh = vs;
199 for(j = 0; j <= n; j++)
200 {
201 if(f[j] > f[vh] && f[j] < f[vg])
202 {
203 vh = j;
204 }
205 }
206
207 /* calculate the centroid */
208 for(j = 0; j <= n - 1; j++)
209 {
210 cent = 0.0;
211 for(m = 0; m <= n; m++)
212 {
213 if(m != vg)
214 {
215 cent += v[m][j];
216 }
217 }
218 vm[j] = cent / n;
219 }
220
221 /* reflect vg to new vertex vr */
222 for(j = 0; j <= n - 1; j++)
223 {
224 /*vr[j] = (1+NMS_ALPHA)*vm[j] - NMS_ALPHA*v[vg][j];*/
225 vr[j] = vm[j] + NMS_ALPHA * (vm[j] - v[vg][j]);
226 }
227 if(constrain != NULL)
228 {
229 constrain(vr, n);
230 }
231 fr = objfunc(vr, params);
232
233 if(fr < f[vh] && fr >= f[vs])
234 {
235 for(j = 0; j <= n - 1; j++)
236 {
237 v[vg][j] = vr[j];
238 }
239 f[vg] = fr;
240 }
241
242 /* investigate a step further in this direction */
243 if(fr < f[vs])
244 {
245 for(j = 0; j <= n - 1; j++)
246 {
247 /*ve[j] = NMS_GAMMA*vr[j] + (1-NMS_GAMMA)*vm[j];*/
248 ve[j] = vm[j] + NMS_GAMMA * (vr[j] - vm[j]);
249 }
250 if(constrain != NULL)
251 {
252 constrain(ve, n);
253 }
254 fe = objfunc(ve, params);
255
256 /* by making fe < fr as opposed to fe < f[vs],
257 Rosenbrocks function takes 63 iterations as opposed
258 to 64 when using double variables. */
259
260 if(fe < fr)
261 {
262 for(j = 0; j <= n - 1; j++)
263 {
264 v[vg][j] = ve[j];
265 }
266 f[vg] = fe;
267 }
268 else
269 {
270 for(j = 0; j <= n - 1; j++)
271 {
272 v[vg][j] = vr[j];
273 }
274 f[vg] = fr;
275 }
276 }
277
278 /* check to see if a contraction is necessary */
279 if(fr >= f[vh])
280 {
281 if(fr < f[vg] && fr >= f[vh])
282 {
283 /* perform outside contraction */
284 for(j = 0; j <= n - 1; j++)
285 {
286 /*vc[j] = NMS_BETA*v[vg][j] + (1-NMS_BETA)*vm[j];*/
287 vc[j] = vm[j] + NMS_BETA * (vr[j] - vm[j]);
288 }
289 if(constrain != NULL)
290 {
291 constrain(vc, n);
292 }
293 fc = objfunc(vc, params);
294 }
295 else
296 {
297 /* perform inside contraction */
298 for(j = 0; j <= n - 1; j++)
299 {
300 /*vc[j] = NMS_BETA*v[vg][j] + (1-NMS_BETA)*vm[j];*/
301 vc[j] = vm[j] - NMS_BETA * (vm[j] - v[vg][j]);
302 }
303 if(constrain != NULL)
304 {
305 constrain(vc, n);
306 }
307 fc = objfunc(vc, params);
308 }
309
310
311 if(fc < f[vg])
312 {
313 for(j = 0; j <= n - 1; j++)
314 {
315 v[vg][j] = vc[j];
316 }
317 f[vg] = fc;
318 }
319 /* at this point the contraction is not successful,
320 we must halve the distance from vs to all the
321 vertices of the simplex and then continue.
322 10/31/97 - modified to account for ALL vertices.
323 */
324 else
325 {
326 for(row = 0; row <= n; row++)
327 {
328 if(row != vs)
329 {
330 for(j = 0; j <= n - 1; j++)
331 {
332 v[row][j] = v[vs][j] + (v[row][j] - v[vs][j]) / 2.0;
333 }
334 }
335 }
336 if(constrain != NULL)
337 {
338 constrain(v[vg], n);
339 }
340 f[vg] = objfunc(v[vg], params);
341 if(constrain != NULL)
342 {
343 constrain(v[vh], n);
344 }
345 f[vh] = objfunc(v[vh], params);
346 }
347 }
348#if 0
349 /* print out the value at each iteration */
350 printf("Iteration %d\n", itr);
351 for(j = 0; j <= n; j++)
352 {
353 for(i = 0; i < n; i++)
354 {
355 printf("%f %f\n", v[j][i], f[j]);
356 }
357 }
358#endif
359 /* test for convergence */
360 fsum = 0.0;
361 for(j = 0; j <= n; j++)
362 {
363 fsum += f[j];
364 }
365 favg = fsum / (n + 1);
366 s = 0.0;
367 for(j = 0; j <= n; j++)
368 {
369 s += pow((f[j] - favg), 2.0) / (n);
370 }
371 s = sqrt(s);
372 if(s < EPSILON) break;
373 }
374 /* end main loop of the minimization */
375
376 /* find the index of the smallest value */
377 vs = 0;
378 for(j = 0; j <= n; j++)
379 {
380 if(f[j] < f[vs])
381 {
382 vs = j;
383 }
384 }
385#if 0
386 printf("The minimum was found at\n");
387 for(j = 0; j < n; j++)
388 {
389 printf("%e\n", v[vs][j]);
390 start[j] = v[vs][j];
391 }
392 double min = objfunc(v[vs], params);
393 printf("The minimum value is %f\n", min);
394 printf("%d Iterations through program\n", itr);
395#else
396 for(j = 0; j < n; j++)
397 {
398 start[j] = v[vs][j];
399 }
400#endif
401 dt_free(f);
402 dt_free(vr);
403 dt_free(ve);
404 dt_free(vc);
405 dt_free(vm);
406 for(i = 0; i <= n; i++)
407 {
408 dt_free(v[i]);
409 }
410 dt_free(v);
411 return itr;
412}
413
414/*==================================================================================
415 * end of nmsimplex code
416 *==================================================================================*/
417
418// clang-format off
419// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
420// vim: shiftwidth=2 expandtab tabstop=2 cindent
421// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
422// clang-format on
#define NMS_GAMMA
Definition ashift.c:121
#define NMS_BETA
Definition ashift.c:120
#define NMS_ALPHA
Definition ashift.c:119
static int simplex(double(*objfunc)(double[], void *params), double start[], int n, double EPSILON, double scale, int maxiter, void(*constrain)(double[], int n), void *params)
Definition ashift_nmsimplex.c:85
#define m
Definition basecurve.c:277
const float i
Definition colorspaces_inline_conversions.h:669
const dt_aligned_pixel_t f
Definition colorspaces_inline_conversions.h:256
static const float const float const float min
Definition colorspaces_inline_conversions.h:667
const float n
Definition colorspaces_inline_conversions.h:929
static const int row
Definition colorspaces_inline_conversions.h:175
const float fc
Definition colorspaces_inline_conversions.h:671
#define EPSILON
Definition curve_tools.c:41
#define dt_free(ptr)
Definition darktable.h:380
static const float v
Definition iop_profile.h:223