7 module subroutine nm_solve(this, fcn, x, fout, ib, err)
9 class(nelder_mead),
intent(inout) :: this
10 class(fcnnvar_helper),
intent(in) :: fcn
11 real(real64),
intent(inout),
dimension(:) :: x
12 real(real64),
intent(out),
optional :: fout
13 type(iteration_behavior),
optional :: ib
14 class(errors),
intent(inout),
optional,
target :: err
17 real(real64),
parameter :: zero = 0.0d0
18 real(real64),
parameter :: negone = -1.0d0
19 real(real64),
parameter :: half = 0.5d0
20 real(real64),
parameter :: two = 2.0d0
23 logical :: buildSimplex, fcnvrg
24 integer(int32) :: i, ihi, ilo, ihi2, ndim, npts, flag, neval, iter, &
26 real(real64) :: ftol, rtol, ftry, fsave, fval, swp
27 real(real64),
allocatable,
dimension(:) :: f, pcent, pmin, work
28 class(errors),
pointer :: errmgr
29 type(errors),
target :: deferr
30 character(len = 256) :: errmsg
33 ndim = fcn%get_variable_count()
36 maxeval = this%get_max_fcn_evals()
37 ftol = this%get_tolerance()
46 ib%converge_on_fcn = fcnvrg
47 ib%converge_on_chng = .false.
48 ib%converge_on_zero_diff = .false.
50 if (
present(err))
then
57 if (.not.fcn%is_fcn_defined())
then
59 call errmgr%report_error(
"nm_solve", &
60 "No function has been defined.", &
61 nl_invalid_operation_error)
64 if (
size(x) /= ndim)
then
66 "It was expected to receive a coordinate vector of length ", &
67 ndim,
" , but a vector of length ",
size(x),
" was received."
68 call errmgr%report_error(
"nm_solve", trim(errmsg), &
69 nl_invalid_input_error)
76 if (
allocated(this%m_simplex))
then
78 if (
size(this%m_simplex, 1) /= ndim .or. &
79 size(this%m_simplex, 2) /= npts)
then
80 deallocate(this%m_simplex)
84 buildsimplex = .false.
89 allocate(f(npts), stat = flag)
90 if (flag == 0)
allocate(pcent(ndim), stat = flag)
91 if (flag == 0)
allocate(pmin(ndim), stat = flag)
92 if (flag == 0)
allocate(work(ndim), stat = flag)
93 if (buildsimplex .and. flag == 0)
allocate(this%m_simplex(ndim, npts))
96 call errmgr%report_error(
"nm_solve", &
97 "Insufficient memory available.", nl_out_of_memory_error)
102 if (buildsimplex)
then
103 this%m_simplex(:,1) = x
105 this%m_simplex(:,i) = x
108 this%m_simplex(i,i+1) = this%m_simplex(i,i+1) + this%m_initSize
114 f(i) = fcn%fcn(this%m_simplex(:,i))
120 pcent(i) = sum(this%m_simplex(i,:))
131 if (f(1) > f(2))
then
139 if (f(i) <= f(ilo)) ilo = i
140 if (f(i) > f(ihi))
then
143 else if (f(i) > f(ihi2))
then
144 if (i /= ihi) ihi2 = i
153 rtol = abs(f(ihi) - f(ilo))
154 if (rtol < ftol)
then
159 swp = this%m_simplex(i,1)
160 this%m_simplex(i,1) = this%m_simplex(i,ilo)
161 this%m_simplex(i,ilo) = swp
162 x(i) = this%m_simplex(i,1)
171 ftry = this%extrapolate(fcn, f, pcent, ihi, negone, neval, work)
172 if (ftry <= f(ilo))
then
176 ftry = this%extrapolate(fcn, f, pcent, ihi, two, neval, work)
177 else if (ftry >= f(ihi2))
then
181 ftry = this%extrapolate(fcn, f, pcent, ihi, half, neval, work)
182 if (ftry >= fsave)
then
187 pcent = half * (this%m_simplex(:,i) + &
188 this%m_simplex(:,ilo))
189 this%m_simplex(:,i) = pcent
190 f(i) = fcn%fcn(pcent)
195 pcent(i) = sum(this%m_simplex(i,:))
201 if (this%get_print_status())
then
203 print 101,
"Iteration: ", iter
204 print 101,
"Function Evaluations: ", neval
205 print 102,
"Function Value: ", fval
206 print 102,
"Convergence Parameter: ", rtol
210 if (neval >= maxeval)
then
217 if (
present(ib))
then
220 ib%jacobian_count = 0
221 ib%gradient_count = 0
222 ib%converge_on_fcn = fcnvrg
223 ib%converge_on_chng = .false.
224 ib%converge_on_zero_diff = .false.
228 if (
present(fout)) fout = fval
233 "The algorithm failed to converge." // new_line(
'c') // &
234 "Function evaluations performed: ", neval, new_line(
'c') // &
235 "Convergence Parameter: ", rtol, new_line(
'c') // &
236 "Convergence Criteria: ", ftol
237 call errmgr%report_error(
"nm_solve", trim(errmsg), &
238 nl_convergence_error)
242100
format(a, i0, a, i0, a)
245103
format(a, i0, a, e10.3, a, e10.3)
249 module function nm_extrapolate(this, fcn, y, pcent, ihi, fac, neval, &
252 class(nelder_mead),
intent(inout) :: this
253 class(fcnnvar_helper),
intent(in) :: fcn
254 real(real64),
intent(inout),
dimension(:) :: y, pcent
255 integer(int32),
intent(in) :: ihi
256 real(real64),
intent(in) :: fac
257 integer(int32),
intent(inout) :: neval
258 real(real64),
intent(out),
dimension(:) :: work
262 real(real64),
parameter :: one = 1.0d0
265 integer(int32) :: i, ndim
266 real(real64) :: fac1, fac2
269 ndim =
size(this%m_simplex, 1)
272 fac1 = (one - fac) / ndim
275 work(i) = pcent(i) * fac1 - this%m_simplex(i,ihi) * fac2
282 if (ytry < y(ihi))
then
285 pcent(i) = pcent(i) + work(i) - this%m_simplex(i,ihi)
286 this%m_simplex(i,ihi) = work(i)
292 pure module function nm_get_simplex(this) result(p)
293 class(nelder_mead),
intent(in) :: this
294 real(real64),
allocatable,
dimension(:,:) :: p
295 integer(int32) :: m, n
296 if (
allocated(this%m_simplex))
then
297 m =
size(this%m_simplex, 1)
298 n =
size(this%m_simplex, 2)
305 module subroutine nm_set_simplex(this, x)
306 class(nelder_mead),
intent(inout) :: this
307 real(real64),
dimension(:,:) :: x
308 integer(int32) :: m, n
311 if (
allocated(this%m_simplex))
then
312 if (
size(this%m_simplex, 1) /= m .or. &
313 size(this%m_simplex, 2) /= n)
then
314 deallocate(this%m_simplex)
315 allocate(this%m_simplex(m, n))
318 allocate(this%m_simplex(m, n))
324 pure module function nm_get_size(this) result(x)
325 class(nelder_mead),
intent(in) :: this
331 module subroutine nm_set_size(this, x)
332 class(nelder_mead),
intent(inout) :: this
333 real(real64),
intent(in) :: x