Ansel
0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
nelder_mead_simplex.h
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
#ifndef DT_MATH_NELDER_MEAD_SIMPLEX_H
84
#define DT_MATH_NELDER_MEAD_SIMPLEX_H
85
86
// Nelder-Mead reflection / contraction / expansion coefficients (the algorithm's standard
87
// constants). Guarded so a caller may override them before including this header.
88
#ifndef NMS_ALPHA
89
#define NMS_ALPHA 1.0
90
#endif
91
#ifndef NMS_BETA
92
#define NMS_BETA 0.5
93
#endif
94
#ifndef NMS_GAMMA
95
#define NMS_GAMMA 2.0
96
#endif
97
98
// Nelder-Mead simplex minimizer of objfunc over n parameters, starting from start[] (overwritten
99
// with the best point). EPSILON = convergence threshold, scale = initial simplex size, maxiter =
100
// iteration cap, constrain = optional projection of a trial point onto the feasible set (may be
101
// NULL), params = opaque pointer forwarded to objfunc/constrain. Returns the iteration count.
102
static
int
simplex
(
double
(*objfunc)(
double
[],
void
*params),
double
start[],
int
n
,
double
EPSILON
,
double
scale,
103
int
maxiter,
void
(*constrain)(
double
[],
int
n
),
void
*params)
104
{
105
106
int
vs;
/* vertex with smallest value */
107
int
vh;
/* vertex with next smallest value */
108
int
vg;
/* vertex with largest value */
109
110
int
i
= 0, j = 0,
m
,
row
;
111
int
itr;
/* track the number of iterations */
112
113
double
**
v
;
/* holds vertices of simplex */
114
double
pn, qn;
/* values used to create initial simplex */
115
double
*
f
;
/* value of function at each vertex */
116
double
fr;
/* value of function at reflection point */
117
double
fe;
/* value of function at expansion point */
118
double
fc
;
/* value of function at contraction point */
119
double
*vr;
/* reflection - coordinates */
120
double
*ve;
/* expansion - coordinates */
121
double
*vc;
/* contraction - coordinates */
122
double
*vm;
/* centroid - coordinates */
123
//double min;
124
125
double
fsum, favg, s, cent;
126
127
/* dynamically allocate arrays */
128
129
/* allocate the rows of the arrays */
130
v
= (
double
**)malloc(
sizeof
(
double
*) * (
n
+ 1));
131
f
= (
double
*)malloc(
sizeof
(
double
) * (
n
+ 1));
132
vr = (
double
*)malloc(
sizeof
(
double
) *
n
);
133
ve = (
double
*)malloc(
sizeof
(
double
) *
n
);
134
vc = (
double
*)malloc(
sizeof
(
double
) *
n
);
135
vm = (
double
*)malloc(
sizeof
(
double
) *
n
);
136
137
/* allocate the columns of the arrays */
138
for
(
i
= 0;
i
<=
n
;
i
++)
139
{
140
v
[
i
] = (
double
*)malloc(
sizeof
(
double
) *
n
);
141
}
142
143
/* create the initial simplex */
144
/* assume one of the vertices is 0,0 */
145
146
pn = scale * (sqrt(
n
+ 1) - 1 +
n
) / (
n
* sqrt(2));
147
qn = scale * (sqrt(
n
+ 1) - 1) / (
n
* sqrt(2));
148
149
for
(
i
= 0;
i
<
n
;
i
++)
150
{
151
v
[0][
i
] = start[
i
];
152
}
153
154
for
(
i
= 1;
i
<=
n
;
i
++)
155
{
156
for
(j = 0; j <
n
; j++)
157
{
158
if
(
i
- 1 == j)
159
{
160
v
[
i
][j] = pn + start[j];
161
}
162
else
163
{
164
v
[
i
][j] = qn + start[j];
165
}
166
}
167
}
168
169
if
(!
IS_NULL_PTR
(constrain))
170
{
171
constrain(
v
[j],
n
);
172
}
173
/* find the initial function values */
174
for
(j = 0; j <=
n
; j++)
175
{
176
f
[j] = objfunc(
v
[j], params);
177
}
178
179
#if 0
180
/* print out the initial values */
181
printf(
"Initial Values\n"
);
182
for
(j = 0; j <=
n
; j++)
183
{
184
for
(
i
= 0;
i
<
n
;
i
++)
185
{
186
printf(
"%f %f\n"
,
v
[j][
i
],
f
[j]);
187
}
188
}
189
#endif
190
191
/* begin the main loop of the minimization */
192
for
(itr = 1; itr <= maxiter; itr++)
193
{
194
/* find the index of the largest value */
195
vg = 0;
196
for
(j = 0; j <=
n
; j++)
197
{
198
if
(
f
[j] >
f
[vg])
199
{
200
vg = j;
201
}
202
}
203
204
/* find the index of the smallest value */
205
vs = 0;
206
for
(j = 0; j <=
n
; j++)
207
{
208
if
(
f
[j] <
f
[vs])
209
{
210
vs = j;
211
}
212
}
213
214
/* find the index of the second largest value */
215
vh = vs;
216
for
(j = 0; j <=
n
; j++)
217
{
218
if
(
f
[j] >
f
[vh] &&
f
[j] <
f
[vg])
219
{
220
vh = j;
221
}
222
}
223
224
/* calculate the centroid */
225
for
(j = 0; j <=
n
- 1; j++)
226
{
227
cent = 0.0;
228
for
(
m
= 0;
m
<=
n
;
m
++)
229
{
230
if
(
m
!= vg)
231
{
232
cent +=
v
[
m
][j];
233
}
234
}
235
vm[j] = cent /
n
;
236
}
237
238
/* reflect vg to new vertex vr */
239
for
(j = 0; j <=
n
- 1; j++)
240
{
241
/*vr[j] = (1+NMS_ALPHA)*vm[j] - NMS_ALPHA*v[vg][j];*/
242
vr[j] = vm[j] +
NMS_ALPHA
* (vm[j] -
v
[vg][j]);
243
}
244
if
(!
IS_NULL_PTR
(constrain))
245
{
246
constrain(vr,
n
);
247
}
248
fr = objfunc(vr, params);
249
250
if
(fr <
f
[vh] && fr >=
f
[vs])
251
{
252
for
(j = 0; j <=
n
- 1; j++)
253
{
254
v
[vg][j] = vr[j];
255
}
256
f
[vg] = fr;
257
}
258
259
/* investigate a step further in this direction */
260
if
(fr <
f
[vs])
261
{
262
for
(j = 0; j <=
n
- 1; j++)
263
{
264
/*ve[j] = NMS_GAMMA*vr[j] + (1-NMS_GAMMA)*vm[j];*/
265
ve[j] = vm[j] +
NMS_GAMMA
* (vr[j] - vm[j]);
266
}
267
if
(!
IS_NULL_PTR
(constrain))
268
{
269
constrain(ve,
n
);
270
}
271
fe = objfunc(ve, params);
272
273
/* by making fe < fr as opposed to fe < f[vs],
274
Rosenbrocks function takes 63 iterations as opposed
275
to 64 when using double variables. */
276
277
if
(fe < fr)
278
{
279
for
(j = 0; j <=
n
- 1; j++)
280
{
281
v
[vg][j] = ve[j];
282
}
283
f
[vg] = fe;
284
}
285
else
286
{
287
for
(j = 0; j <=
n
- 1; j++)
288
{
289
v
[vg][j] = vr[j];
290
}
291
f
[vg] = fr;
292
}
293
}
294
295
/* check to see if a contraction is necessary */
296
if
(fr >=
f
[vh])
297
{
298
if
(fr <
f
[vg] && fr >=
f
[vh])
299
{
300
/* perform outside contraction */
301
for
(j = 0; j <=
n
- 1; j++)
302
{
303
/*vc[j] = NMS_BETA*v[vg][j] + (1-NMS_BETA)*vm[j];*/
304
vc[j] = vm[j] +
NMS_BETA
* (vr[j] - vm[j]);
305
}
306
if
(!
IS_NULL_PTR
(constrain))
307
{
308
constrain(vc,
n
);
309
}
310
fc
= objfunc(vc, params);
311
}
312
else
313
{
314
/* perform inside contraction */
315
for
(j = 0; j <=
n
- 1; j++)
316
{
317
/*vc[j] = NMS_BETA*v[vg][j] + (1-NMS_BETA)*vm[j];*/
318
vc[j] = vm[j] -
NMS_BETA
* (vm[j] -
v
[vg][j]);
319
}
320
if
(!
IS_NULL_PTR
(constrain))
321
{
322
constrain(vc,
n
);
323
}
324
fc
= objfunc(vc, params);
325
}
326
327
328
if
(
fc
<
f
[vg])
329
{
330
for
(j = 0; j <=
n
- 1; j++)
331
{
332
v
[vg][j] = vc[j];
333
}
334
f
[vg] =
fc
;
335
}
336
/* at this point the contraction is not successful,
337
we must halve the distance from vs to all the
338
vertices of the simplex and then continue.
339
10/31/97 - modified to account for ALL vertices.
340
*/
341
else
342
{
343
for
(
row
= 0;
row
<=
n
;
row
++)
344
{
345
if
(
row
!= vs)
346
{
347
for
(j = 0; j <=
n
- 1; j++)
348
{
349
v
[
row
][j] =
v
[vs][j] + (
v
[
row
][j] -
v
[vs][j]) / 2.0;
350
}
351
}
352
}
353
if
(!
IS_NULL_PTR
(constrain))
354
{
355
constrain(
v
[vg],
n
);
356
}
357
f
[vg] = objfunc(
v
[vg], params);
358
if
(!
IS_NULL_PTR
(constrain))
359
{
360
constrain(
v
[vh],
n
);
361
}
362
f
[vh] = objfunc(
v
[vh], params);
363
}
364
}
365
#if 0
366
/* print out the value at each iteration */
367
printf(
"Iteration %d\n"
, itr);
368
for
(j = 0; j <=
n
; j++)
369
{
370
for
(
i
= 0;
i
<
n
;
i
++)
371
{
372
printf(
"%f %f\n"
,
v
[j][
i
],
f
[j]);
373
}
374
}
375
#endif
376
/* test for convergence */
377
fsum = 0.0;
378
for
(j = 0; j <=
n
; j++)
379
{
380
fsum +=
f
[j];
381
}
382
favg = fsum / (
n
+ 1);
383
s = 0.0;
384
for
(j = 0; j <=
n
; j++)
385
{
386
s += pow((
f
[j] - favg), 2.0) / (
n
);
387
}
388
s = sqrt(s);
389
if
(s <
EPSILON
)
break
;
390
}
391
/* end main loop of the minimization */
392
393
/* find the index of the smallest value */
394
vs = 0;
395
for
(j = 0; j <=
n
; j++)
396
{
397
if
(
f
[j] <
f
[vs])
398
{
399
vs = j;
400
}
401
}
402
#if 0
403
printf(
"The minimum was found at\n"
);
404
for
(j = 0; j <
n
; j++)
405
{
406
printf(
"%e\n"
,
v
[vs][j]);
407
start[j] =
v
[vs][j];
408
}
409
double
min
= objfunc(
v
[vs], params);
410
printf(
"The minimum value is %f\n"
,
min
);
411
printf(
"%d Iterations through program\n"
, itr);
412
#else
413
for
(j = 0; j <
n
; j++)
414
{
415
start[j] =
v
[vs][j];
416
}
417
#endif
418
dt_free
(
f
);
419
dt_free
(vr);
420
dt_free
(ve);
421
dt_free
(vc);
422
dt_free
(vm);
423
for
(
i
= 0;
i
<=
n
;
i
++)
424
{
425
dt_free
(
v
[
i
]);
426
}
427
dt_free
(
v
);
428
return
itr;
429
}
430
431
/*==================================================================================
432
* end of nmsimplex code
433
*==================================================================================*/
434
435
#endif
// DT_MATH_NELDER_MEAD_SIMPLEX_H
436
437
// clang-format off
438
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
439
// vim: shiftwidth=2 expandtab tabstop=2 cindent
440
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
441
// clang-format on
m
#define m
Definition
basecurve.c:283
f
const float f
Definition
colorprofiles/iop_profile.h:541
v
const float v
Definition
colorprofiles/iop_profile.h:536
i
const float i
Definition
colorspaces_inline_conversions.h:441
min
static const float const float const float min
Definition
colorspaces_inline_conversions.h:439
n
const float n
Definition
colorspaces_inline_conversions.h:679
row
static const int row
Definition
colorspaces_inline_conversions.h:36
fc
const float fc
Definition
colorspaces_inline_conversions.h:443
EPSILON
#define EPSILON
Definition
curve_tools.c:42
IS_NULL_PTR
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition
macros.h:96
dt_free
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition
mem_alloc.h:171
NMS_GAMMA
#define NMS_GAMMA
Definition
nelder_mead_simplex.h:95
NMS_BETA
#define NMS_BETA
Definition
nelder_mead_simplex.h:92
NMS_ALPHA
#define NMS_ALPHA
Definition
nelder_mead_simplex.h:89
simplex
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
nelder_mead_simplex.h:102
src
math
nelder_mead_simplex.h
Generated by
1.9.8