8 subroutine dsymv(uplo, n, alpha, a, lda, x, incx, beta, y, incy)
9 use iso_fortran_env,
only : int32, real64
10 character,
intent(in) :: uplo
11 integer(int32),
intent(in) :: n, lda, incx, incy
12 real(real64),
intent(in) :: alpha, beta, a(lda,*), x(*)
13 real(real64),
intent(inout) :: y(*)
18 module subroutine bfgs_solve(this, fcn, x, fout, ib, err)
20 class(bfgs),
intent(inout) :: this
21 class(fcnnvar_helper),
intent(in) :: fcn
22 real(real64),
intent(inout),
dimension(:) :: x
23 real(real64),
intent(out),
optional :: fout
24 type(iteration_behavior),
optional :: ib
25 class(errors),
intent(inout),
optional,
target :: err
28 real(real64),
parameter :: zero = 0.0d0
29 real(real64),
parameter :: one = 1.0d0
30 real(real64),
parameter :: negone = -1.0d0
31 real(real64),
parameter :: factor = 1.0d2
32 real(real64),
parameter :: small = 1.0d-10
35 logical :: xcnvrg, gcnvrg
36 integer(int32) :: i, n, maxeval, neval, ngrad, flag, iter
37 real(real64) :: xtol, gtol, fp, stpmax, fret, xtest, gtest, temp, ydx
38 real(real64),
allocatable,
dimension(:) :: g, dx, u, v, y, gold, xnew, bdx
39 real(real64),
allocatable,
dimension(:,:) :: b, r
40 class(errors),
pointer :: errmgr
41 type(errors),
target :: deferr
42 character(len = 256) :: errmsg
43 type(iteration_behavior) :: lib
44 class(line_search),
allocatable :: ls
47 n = fcn%get_variable_count()
48 maxeval = this%get_max_fcn_evals()
49 gtol = this%get_tolerance()
50 xtol = this%get_var_tolerance()
60 ib%gradient_count = ngrad
61 ib%converge_on_fcn = .false.
62 ib%converge_on_chng = xcnvrg
63 ib%converge_on_zero_diff = gcnvrg
65 if (
present(err))
then
70 if (this%get_use_line_search())
then
71 if (.not.this%is_line_search_defined()) &
72 call this%set_default_line_search()
73 call this%get_line_search(ls)
77 if (.not.fcn%is_fcn_defined())
then
79 call errmgr%report_error(
"bfgs_solve", &
80 "No function has been defined.", &
81 nl_invalid_operation_error)
84 if (
size(x) /= n)
then
86 "It was expected to receive a coordinate vector of length ", &
87 n,
" , but a vector of length ",
size(x),
" was received."
88 call errmgr%report_error(
"bfgs_solve", trim(errmsg), &
89 nl_invalid_input_error)
94 allocate(g(n), stat = flag)
95 if (flag == 0)
allocate(dx(n), stat = flag)
96 if (flag == 0)
allocate(u(n), stat = flag)
97 if (flag == 0)
allocate(v(n), stat = flag)
98 if (flag == 0)
allocate(y(n), stat = flag)
99 if (flag == 0)
allocate(bdx(n), stat = flag)
100 if (flag == 0)
allocate(gold(n), stat = flag)
101 if (flag == 0)
allocate(xnew(n), stat = flag)
102 if (flag == 0)
allocate(b(n,n), stat = flag)
103 if (flag == 0)
allocate(r(n,n), stat = flag)
106 call errmgr%report_error(
"bfgs_solve", &
107 "Insufficient memory available.", nl_out_of_memory_error)
113 call fcn%gradient(x, g, fp)
119 if (gtest < gtol)
then
125 if (.not.gcnvrg)
then
134 stpmax = factor * max(norm2(x), real(n, real64))
138 if (this%get_use_line_search())
then
139 call limit_search_vector(dx, stpmax)
140 call ls%search(fcn, x, g, dx, xnew, fp, fret, lib, errmgr)
141 neval = neval + lib%fcn_count
151 dx(i) = xnew(i) - x(i)
155 call fcn%gradient(x, g, fp)
161 temp = abs(dx(i)) / max(abs(x(i)), one)
162 xtest = max(temp, xtest)
164 if (xtest < xtol)
then
171 if (gtest < gtol)
then
178 ydx = dot_product(y, dx)
182 temp = sqrt(dot_product(y, y) / ydx)
183 call dlaset(
'A', n, n, zero, temp, r, n)
187 call tri_mtx_mult(.true., one, r, zero, b)
190 call dsymv(
'u', n, one, b, n, dx, 1, zero, bdx, 1)
193 if (ydx > small)
then
196 v = bdx / sqrt(dot_product(dx, bdx))
197 call cholesky_rank1_update(r, u)
198 call cholesky_rank1_downdate(r, v)
203 call solve_cholesky(.true., r, dx)
206 if (this%get_print_status())
then
208 print 101,
"Iteration: ", iter
209 print 101,
"Function Evaluations: ", neval
210 print 102,
"Function Value: ", fp
211 print 102,
"Change in Variable: ", xtest
212 print 102,
"Gradient: ", gtest
216 if (neval >= maxeval)
then
224 if (
present(ib))
then
227 ib%jacobian_count = 0
228 ib%gradient_count = ngrad
229 ib%converge_on_fcn = .false.
230 ib%converge_on_chng = xcnvrg
231 ib%converge_on_zero_diff = gcnvrg
235 if (
present(fout)) fout = fp
240 "The algorithm failed to converge." // new_line(
'c') // &
241 "Function evaluations performed: ", neval, new_line(
'c') // &
242 "Function Value: ", fp, new_line(
'c') // &
243 "Change in Variable: ", xtest, new_line(
'c') // &
245 call errmgr%report_error(
"bfgs_solve", trim(errmsg), &
246 nl_convergence_error)
250100
format(a, i0, a, i0, a)
253103
format(a, i0, a, e10.3, a, e10.3, a, e10.3)