fastglmm
Massively scalable generalized linear mixed models
Toggle main menu visibility
Loading...
Searching...
No Matches
inst
include
local_min.h
Go to the documentation of this file.
1
#ifndef LOCAL_MIN_H
2
#define LOCAL_MIN_H
3
4
5
# include <cfloat>
6
# include <cmath>
7
# include <cstdlib>
8
# include <iostream>
9
10
using namespace
std;
11
12
// Adapted from
13
// https://people.sc.fsu.edu/~jburkardt/cpp_src/local_min/local_min.cpp
14
15
// pass this object to local_min,
16
// so pass void * arguments too
17
struct
funcStruct
18
{
19
double (*
function
) (
double
x,
void
*
params
);
20
void
*
params
;
21
};
22
23
//****************************************************************************80
24
25
inline
double
local_min
(
double
a,
double
b,
double
t,
funcStruct
*f,
double
&x,
int
&calls )
26
27
//****************************************************************************80
28
//
29
// Purpose:
30
//
31
// local_min() seeks a local minimum of a function F(X) in an interval [A,B].
32
//
33
// Discussion:
34
//
35
// If the function F is defined on the interval (A,B), then local_min
36
// finds an approximation X to the point at which F attatains its minimum
37
// (or the appropriate limit point), and returns the value of F at X.
38
//
39
// T and EPS define a tolerance TOL = EPS * abs ( X ) + T.
40
// F is never evaluated at two points closer than TOL.
41
//
42
// If F is delta-unimodal for some delta less than TOL, the X approximates
43
// the global minimum of F with an error less than 3*TOL.
44
//
45
// If F is not delta-unimodal, then X may approximate a local, but
46
// perhaps non-global, minimum.
47
//
48
// The method used is a combination of golden section search and
49
// successive parabolic interpolation. Convergence is never much slower
50
// than that for a Fibonacci search. If F has a continuous second
51
// derivative which is positive at the minimum (which is not at A or
52
// B), then, ignoring rounding errors, convergence is superlinear, and
53
// usually of the order of about 1.3247.
54
//
55
// Licensing:
56
//
57
// This code is distributed under the MIT license.
58
//
59
// Modified:
60
//
61
// 30 May 2021
62
//
63
// Author:
64
//
65
// Original FORTRAN77 version by Richard Brent.
66
// C++ version by John Burkardt.
67
//
68
// Reference:
69
//
70
// Richard Brent,
71
// Algorithms for Minimization Without Derivatives,
72
// Dover, 2002,
73
// ISBN: 0-486-41998-3,
74
// LC: QA402.5.B74.
75
//
76
// Input:
77
//
78
// double A, B, the endpoints of the interval.
79
//
80
// double T, a positive absolute error tolerance.
81
//
82
// double F(double x), the name of a user-supplied function.
83
//
84
// Output:
85
//
86
// double &X, the estimated value of an abscissa
87
// for which F attains a local minimum value in [A,B].
88
//
89
// int &CALLS: the number of calls to F.
90
//
91
// double LOCAL_MIN, the value F(X).
92
//
93
{
94
double
c;
95
double
d;
96
double
e;
97
double
eps;
98
double
fu;
99
double
fv;
100
double
fw;
101
double
fx;
102
double
m;
103
double
p;
104
double
q;
105
double
r;
106
double
sa;
107
double
sb;
108
double
t2;
109
double
tol;
110
double
u;
111
double
v;
112
double
w;
113
114
calls = 0;
115
//
116
// C is the square of the inverse of the golden ratio.
117
//
118
c = 0.5 * ( 3.0 - sqrt ( 5.0 ) );
119
120
eps = sqrt ( DBL_EPSILON );
121
122
sa = a;
123
sb = b;
124
x = sa + c * ( b - a );
125
w = x;
126
v = w;
127
e = 0.0;
128
// fx = f ( x );
129
fx = f->
function
(x, f->
params
);
130
calls = calls + 1;
131
fw = fx;
132
fv = fw;
133
134
for
( ; ; )
135
{
136
m = 0.5 * ( sa + sb ) ;
137
tol = eps * fabs ( x ) + t;
138
t2 = 2.0 * tol;
139
//
140
// Check the stopping criterion.
141
//
142
if
( fabs ( x - m ) <= t2 - 0.5 * ( sb - sa ) )
143
{
144
break
;
145
}
146
//
147
// Fit a parabola.
148
//
149
r = 0.0;
150
q = r;
151
p = q;
152
153
if
( tol < fabs ( e ) )
154
{
155
r = ( x - w ) * ( fx - fv );
156
q = ( x - v ) * ( fx - fw );
157
p = ( x - v ) * q - ( x - w ) * r;
158
q = 2.0 * ( q - r );
159
if
( 0.0 < q )
160
{
161
p = - p;
162
}
163
q = fabs ( q );
164
r = e;
165
e = d;
166
}
167
168
if
( fabs ( p ) < fabs ( 0.5 * q * r ) &&
169
q * ( sa - x ) < p &&
170
p < q * ( sb - x ) )
171
{
172
//
173
// Take the parabolic interpolation step.
174
//
175
d = p / q;
176
u = x + d;
177
//
178
// F must not be evaluated too close to A or B.
179
//
180
if
( ( u - sa ) < t2 || ( sb - u ) < t2 )
181
{
182
if
( x < m )
183
{
184
d = tol;
185
}
186
else
187
{
188
d = - tol;
189
}
190
}
191
}
192
//
193
// A golden-section step.
194
//
195
else
196
{
197
if
( x < m )
198
{
199
e = sb - x;
200
}
201
else
202
{
203
e = sa - x;
204
}
205
d = c * e;
206
}
207
//
208
// F must not be evaluated too close to X.
209
//
210
if
( tol <= fabs ( d ) )
211
{
212
u = x + d;
213
}
214
else
if
( 0.0 < d )
215
{
216
u = x + tol;
217
}
218
else
219
{
220
u = x - tol;
221
}
222
223
// fu = f ( u );
224
fu = f->
function
(u, f->
params
);
225
calls = calls + 1;
226
//
227
// Update A, B, V, W, and X.
228
//
229
if
( fu <= fx )
230
{
231
if
( u < x )
232
{
233
sb = x;
234
}
235
else
236
{
237
sa = x;
238
}
239
v = w;
240
fv = fw;
241
w = x;
242
fw = fx;
243
x = u;
244
fx = fu;
245
}
246
else
247
{
248
if
( u < x )
249
{
250
sa = u;
251
}
252
else
253
{
254
sb = u;
255
}
256
257
if
( fu <= fw || w == x )
258
{
259
v = w;
260
fv = fw;
261
w = u;
262
fw = fu;
263
}
264
else
if
( fu <= fv || v == x || v == w )
265
{
266
v = u;
267
fv = fu;
268
}
269
}
270
}
271
return
fx;
272
}
273
#endif
274
local_min
double local_min(double a, double b, double t, funcStruct *f, double &x, int &calls)
Definition
local_min.h:25
funcStruct
Definition
local_min.h:18
funcStruct::function
double(* function)(double x, void *params)
Definition
local_min.h:19
funcStruct::params
void * params
Definition
local_min.h:20
Generated by
1.17.0