SDDSlib
Loading...
Searching...
No Matches
gridopt.c
Go to the documentation of this file.
1/**
2 * @file gridopt.c
3 * @brief Functions for performing grid search and random search minimization on an N-dimensional function.
4 *
5 * This file provides several methods for locating the minimum of a function that may be
6 * expensive or complicated to evaluate. The methods include:
7 * - grid_search_min(): Systematically samples the parameter space at fixed intervals.
8 * - grid_sample_min(): Randomly samples a grid of points in the parameter space.
9 * - randomSampleMin(): Selects random points in the parameter space to find a suitable starting point.
10 * - randomWalkMin(): Performs a random walk starting from a given point, potentially refining a solution.
11 * Additionally, optimAbort() can signal an external abort condition to halt the search processes.
12 *
13 * @copyright
14 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
15 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
16 *
17 * @license
18 * This file is distributed under the terms of the Software License Agreement
19 * found in the file LICENSE included with this distribution.
20 *
21 * @author M. Borland, R. Soliday, Y. Wang
22 */
23
24#include "mdb.h"
25
26#define OPTIM_ABORT 0x0001UL
27static unsigned long optimFlags = 0;
28
29/**
30 * @brief Set or query the abort condition for optimization routines.
31 *
32 * When called with a non-zero parameter, this function sets an internal flag that
33 * signals the optimization routines to abort their search. When called with zero,
34 * it returns the current state of the abort flag.
35 *
36 * @param abort If non-zero, sets the abort condition. If zero, simply queries it.
37 * @return Returns 1 if the abort flag is set, otherwise 0.
38 */
39long optimAbort(long abort) {
40 if (abort) {
41 /* if zero, then operation is a query */
42 optimFlags |= OPTIM_ABORT;
43 }
44 return optimFlags & OPTIM_ABORT ? 1 : 0;
45}
46
47/**
48 * @brief Perform a grid search to find the minimum of a given function.
49 *
50 * Given ranges and steps for each dimension, this function systematically evaluates
51 * the target function over a grid of points. It returns the best found minimum and
52 * updates xReturn with the coordinates of that minimum.
53 *
54 * @param best_result Pointer to a double that will store the best function value found.
55 * @param xReturn Pointer to an array that will be updated with the coordinates of the minimum.
56 * @param lower Array specifying the lower bounds of each dimension.
57 * @param upper Array specifying the upper bounds of each dimension.
58 * @param step Array specifying the step sizes for each dimension.
59 * @param n_dimen The number of dimensions in the parameter space.
60 * @param target The target function value to achieve or surpass.
61 * @param func A pointer to the function to minimize, taking coordinates and returning a value and validity flag.
62 * @return Returns 1 if a minimum was found, otherwise 0.
63 */
65 double *best_result,
66 double *xReturn,
67 double *lower,
68 double *upper,
69 double *step,
70 long n_dimen,
71 double target,
72 double (*func)(double *x, long *invalid)) {
73 static double *x = NULL, *best_x = NULL;
74 static long last_n_dimen = 0;
75 static long *index, *counter, *maxcount;
76 double result;
77 long flag, i, best_found;
78
79 optimFlags = 0;
80
81 if (last_n_dimen < n_dimen) {
82 if (x)
83 tfree(x);
84 if (index)
85 tfree(index);
86 if (counter)
87 tfree(counter);
88 if (maxcount)
89 tfree(maxcount);
90 x = tmalloc(sizeof(*x) * n_dimen);
91 best_x = tmalloc(sizeof(*best_x) * n_dimen);
92 index = tmalloc(sizeof(*index) * n_dimen);
93 counter = tmalloc(sizeof(*counter) * n_dimen);
94 maxcount = tmalloc(sizeof(*maxcount) * n_dimen);
95 last_n_dimen = n_dimen;
96 }
97
98 *best_result = DBL_MAX;
99 for (i = 0; i < n_dimen; i++) {
100 index[i] = i;
101 counter[i] = 0;
102 x[i] = lower[i];
103 if (lower[i] >= upper[i]) {
104 step[i] = 0;
105 maxcount[i] = 0;
106 } else {
107 maxcount[i] = (upper[i] - lower[i]) / step[i] + 1.5;
108 if (maxcount[i] <= 1)
109 maxcount[i] = 2;
110 step[i] = (upper[i] - lower[i]) / (maxcount[i] - 1);
111 }
112 }
113
114 best_found = 0;
115 do {
116 if ((result = (*func)(x, &flag)) < *best_result && flag == 0) {
117 *best_result = result;
118 for (i = 0; i < n_dimen; i++)
119 best_x[i] = x[i];
120 best_found = 1;
121 if (result < target)
122 break;
123 }
124 if (optimFlags & OPTIM_ABORT)
125 break;
126 } while (advance_values(x, index, lower, step, n_dimen, counter, maxcount, n_dimen) >= 0);
127
128 if (best_found)
129 for (i = 0; i < n_dimen; i++)
130 xReturn[i] = best_x[i];
131
132 return (best_found);
133}
134
135/**
136 * @brief Perform a partial (sampled) grid search to find the minimum of a function.
137 *
138 * This routine performs a grid-based search similar to grid_search_min(), but only evaluates
139 * a fraction of the points, chosen randomly. It returns the best found minimum and updates
140 * xReturn with the coordinates of that minimum.
141 *
142 * @param best_result Pointer to a double that will store the best function value found.
143 * @param xReturn Pointer to an array that will be updated with the coordinates of the minimum.
144 * @param lower Array specifying the lower bounds of each dimension.
145 * @param upper Array specifying the upper bounds of each dimension.
146 * @param step Array specifying the step sizes for each dimension.
147 * @param n_dimen The number of dimensions.
148 * @param target The target function value to achieve or surpass.
149 * @param func The function to minimize.
150 * @param sample_fraction The fraction or number of points to sample from the grid.
151 * @param random_f Optional random function for generating samples (default random_1).
152 * @return Returns 1 if a minimum was found, otherwise 0.
153 */
155 double *best_result,
156 double *xReturn,
157 double *lower,
158 double *upper,
159 double *step,
160 long n_dimen,
161 double target,
162 double (*func)(double *x, long *invalid),
163 double sample_fraction,
164 double (*random_f)(long iseed)) {
165 static double *x = NULL, *best_x = NULL;
166 static long last_n_dimen = 0;
167 static long *index, *counter, *maxcount;
168 double result;
169 long flag, i, best_found;
170
171 optimFlags = 0;
172
173 if (random_f == NULL)
174 random_f = random_1;
175
176 if (last_n_dimen < n_dimen) {
177 if (x)
178 tfree(x);
179 if (index)
180 tfree(index);
181 if (counter)
182 tfree(counter);
183 if (maxcount)
184 tfree(maxcount);
185 x = tmalloc(sizeof(*x) * n_dimen);
186 best_x = tmalloc(sizeof(*best_x) * n_dimen);
187 index = tmalloc(sizeof(*index) * n_dimen);
188 counter = tmalloc(sizeof(*counter) * n_dimen);
189 maxcount = tmalloc(sizeof(*maxcount) * n_dimen);
190 last_n_dimen = n_dimen;
191 }
192
193 *best_result = DBL_MAX;
194 for (i = 0; i < n_dimen; i++) {
195 index[i] = i;
196 counter[i] = 0;
197 x[i] = lower[i];
198 if (lower[i] >= upper[i]) {
199 step[i] = 0;
200 maxcount[i] = 0;
201 } else {
202 maxcount[i] = (upper[i] - lower[i]) / step[i] + 1.5;
203 if (maxcount[i] <= 1)
204 maxcount[i] = 2;
205 step[i] = (upper[i] - lower[i]) / (maxcount[i] - 1);
206 }
207 }
208
209 if (sample_fraction >= 1) {
210 double npoints = 1;
211 for (i = 0; i < n_dimen; i++)
212 npoints *= maxcount[i];
213 sample_fraction /= npoints;
214 }
215
216 best_found = 0;
217 do {
218 if (sample_fraction < (*random_f)(1))
219 continue;
220 if ((result = (*func)(x, &flag)) < *best_result && flag == 0) {
221 *best_result = result;
222 for (i = 0; i < n_dimen; i++)
223 best_x[i] = x[i];
224 best_found = 1;
225 if (result < target)
226 break;
227 }
228 if (optimFlags & OPTIM_ABORT)
229 break;
230 } while (advance_values(x, index, lower, step, n_dimen, counter, maxcount, n_dimen) >= 0);
231
232 if (best_found)
233 for (i = 0; i < n_dimen; i++)
234 xReturn[i] = best_x[i];
235
236 return (best_found);
237}
238
239/**
240 * @brief Randomly sample the parameter space to find a minimum.
241 *
242 * This routine randomly samples points in the given parameter space (defined by lower and upper bounds)
243 * for a specified number of samples. It returns the best found minimum and updates xReturn with its coordinates.
244 *
245 * @param best_result Pointer to a double that will store the best function value found.
246 * @param xReturn Pointer to an array that will be updated with the coordinates of the minimum.
247 * @param lower Array specifying the lower bounds of each dimension.
248 * @param upper Array specifying the upper bounds of each dimension.
249 * @param n_dimen The number of dimensions.
250 * @param target The target function value.
251 * @param func The function to minimize.
252 * @param nSamples The number of random samples to try.
253 * @param random_f Optional random function for sampling (default random_1).
254 * @return Returns 1 if a minimum was found, otherwise 0.
255 */
257 double *best_result,
258 double *xReturn,
259 double *lower,
260 double *upper,
261 long n_dimen,
262 double target,
263 double (*func)(double *x, long *invalid),
264 long nSamples,
265 double (*random_f)(long iseed)) {
266 double *x, *xBest;
267 double result;
268 long flag, i, best_found = 0;
269
270 optimFlags = 0;
271 if (random_f == NULL)
272 random_f = random_1;
273
274 x = tmalloc(sizeof(*x) * n_dimen);
275 xBest = tmalloc(sizeof(*xBest) * n_dimen);
276 for (i = 0; i < n_dimen; i++)
277 xBest[i] = xReturn[i];
278 *best_result = DBL_MAX;
279 while (nSamples--) {
280 for (i = 0; i < n_dimen; i++)
281 x[i] = lower[i] + (upper[i] - lower[i]) * (*random_f)(0);
282 if ((result = (*func)(x, &flag)) < *best_result && flag == 0) {
283 *best_result = result;
284 for (i = 0; i < n_dimen; i++)
285 xBest[i] = x[i];
286 best_found = 1;
287 if (result < target)
288 break;
289 }
290 if (optimFlags & OPTIM_ABORT)
291 break;
292 }
293 if (best_found) {
294 for (i = 0; i < n_dimen; i++)
295 xReturn[i] = xBest[i];
296 }
297 free(x);
298 free(xBest);
299 return (best_found);
300}
301
302/**
303 * @brief Perform a random walk starting from a given point to find a function minimum.
304 *
305 * This function starts at a user-supplied point and randomly perturbs it within given bounds
306 * and step sizes. It evaluates the function at each new point, seeking improvements.
307 * If a better minimum is found, xReturn is updated.
308 *
309 * @param best_result Pointer to a double that will store the best found function value.
310 * @param xReturn Pointer to an array with the starting coordinates, updated on success.
311 * @param lower Array specifying the lower bounds for each dimension.
312 * @param upper Array specifying the upper bounds for each dimension.
313 * @param stepSize Array specifying the maximum step size for random perturbations in each dimension.
314 * @param n_dimen The number of dimensions.
315 * @param target The target function value.
316 * @param func The function to minimize.
317 * @param nSamples The number of random steps to take.
318 * @param random_f Optional random function (default random_1).
319 * @return Returns 1 if a minimum was found, otherwise 0.
320 */
322 double *best_result,
323 double *xReturn,
324 double *lower,
325 double *upper,
326 double *stepSize,
327 long n_dimen,
328 double target,
329 double (*func)(double *x, long *invalid),
330 long nSamples,
331 double (*random_f)(long iseed)) {
332 double *x, *xBest;
333 double result;
334 long flag, i, best_found = 0;
335
336 optimFlags = 0;
337
338 if (random_f == NULL)
339 random_f = random_1;
340
341 x = tmalloc(sizeof(*x) * n_dimen);
342 xBest = tmalloc(sizeof(*xBest) * n_dimen);
343 for (i = 0; i < n_dimen; i++)
344 xBest[i] = xReturn[i];
345 *best_result = DBL_MAX;
346 while (nSamples--) {
347 for (i = 0; i < n_dimen; i++) {
348 x[i] = xBest[i] + 2 * stepSize[i] * (0.5 - random_f(0));
349 if (lower && x[i] < lower[i])
350 x[i] = lower[i];
351 if (upper && x[i] > upper[i])
352 x[i] = upper[i];
353 }
354 result = (*func)(x, &flag);
355 if (flag == 0 && result < *best_result) {
356 *best_result = result;
357 for (i = 0; i < n_dimen; i++)
358 xBest[i] = x[i];
359 best_found = 1;
360 if (result < target)
361 break;
362 }
363 if (optimFlags & OPTIM_ABORT)
364 break;
365 }
366 if (best_found) {
367 for (i = 0; i < n_dimen; i++)
368 xReturn[i] = xBest[i];
369 }
370 free(x);
371 free(xBest);
372 return (best_found);
373}
int tfree(void *ptr)
Frees a memory block and records the deallocation if tracking is enabled.
Definition array.c:230
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
long advance_values(double *value, long *value_index, double *initial, double *step, long n_values, long *counter, long *max_count, long n_indices)
Sequences an array of values systematically to cover an n-dimensional grid.
Definition counter.c:31
double random_1(long iseed)
Generate a uniform random double in [0,1] using a custom seed initialization.
Definition drand.c:175
long randomWalkMin(double *best_result, double *xReturn, double *lower, double *upper, double *stepSize, long n_dimen, double target, double(*func)(double *x, long *invalid), long nSamples, double(*random_f)(long iseed))
Perform a random walk starting from a given point to find a function minimum.
Definition gridopt.c:321
long grid_sample_min(double *best_result, double *xReturn, double *lower, double *upper, double *step, long n_dimen, double target, double(*func)(double *x, long *invalid), double sample_fraction, double(*random_f)(long iseed))
Perform a partial (sampled) grid search to find the minimum of a function.
Definition gridopt.c:154
long optimAbort(long abort)
Set or query the abort condition for optimization routines.
Definition gridopt.c:39
long grid_search_min(double *best_result, double *xReturn, double *lower, double *upper, double *step, long n_dimen, double target, double(*func)(double *x, long *invalid))
Perform a grid search to find the minimum of a given function.
Definition gridopt.c:64
long randomSampleMin(double *best_result, double *xReturn, double *lower, double *upper, long n_dimen, double target, double(*func)(double *x, long *invalid), long nSamples, double(*random_f)(long iseed))
Randomly sample the parameter space to find a minimum.
Definition gridopt.c:256