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