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