num_minimum.F90 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. !
  2. ! type(TMinimumInfo) :: mini
  3. ! real :: x, y
  4. !
  5. ! call Init( mini, x0, dx, maxiter=10, atol=0.01, verbose=.true. )
  6. ! do
  7. ! call InitIter( mini, x )
  8. !
  9. ! ...
  10. ! y = ... func( x )
  11. ! ...
  12. !
  13. ! call DoneInter( mini, y, status )
  14. ! if ( status == 0 ) exit ! ok, converged
  15. ! if ( status == -1 ) cycle ! try next iteration
  16. ! if ( status == 1 ) stop 'exceeded maximum number of iterations'
  17. ! if ( status == 2 ) stop 'no clear minimum'
  18. ! stop 'error in iteration'
  19. ! end do
  20. ! call Done( mini )
  21. !
  22. !
  23. module num_minimum
  24. implicit none
  25. ! --- in/out ----------------------------
  26. private
  27. public :: TMinimumInfo
  28. public :: Init, Done
  29. public :: InitIter, DoneIter
  30. ! --- types ----------------------------
  31. type TMinimumInfo
  32. integer :: iter
  33. real :: dx
  34. real :: x1, x2, x3
  35. real :: y1, y2, y3
  36. real, pointer :: x(:)
  37. real, pointer :: y(:)
  38. !
  39. integer :: maxiter
  40. real :: atol
  41. !
  42. logical :: verbose
  43. end type TMinimumInfo
  44. ! --- interfaces --------------------------
  45. interface Init
  46. module procedure mini_Init
  47. end interface
  48. interface Done
  49. module procedure mini_Done
  50. end interface
  51. interface InitIter
  52. module procedure mini_InitIter
  53. end interface
  54. interface DoneIter
  55. module procedure mini_DoneIter
  56. end interface
  57. contains
  58. ! ===========================================================
  59. subroutine mini_Init( mini, x0, dx, maxiter, atol, verbose )
  60. ! --- in/out ----------------------------
  61. type(TMinimumInfo), intent(out) :: mini
  62. real, intent(in) :: x0, dx
  63. integer, intent(in) :: maxiter
  64. real, intent(in) :: atol
  65. logical, intent(in) :: verbose
  66. ! --- begin -------------------------------
  67. mini%maxiter = maxiter
  68. mini%atol = atol
  69. mini%iter = 0
  70. mini%dx = dx
  71. allocate( mini%x(mini%maxiter) )
  72. mini%x = 0.0
  73. mini%x(1) = x0
  74. mini%x(2) = x0 + dx
  75. allocate( mini%y(mini%maxiter) )
  76. mini%y = 0.0
  77. mini%verbose = verbose
  78. end subroutine mini_Init
  79. ! ***
  80. subroutine mini_Done( mini )
  81. ! --- in/out ----------------------------
  82. type(TMinimumInfo), intent(inout) :: mini
  83. ! --- begin -------------------------------
  84. deallocate( mini%x )
  85. deallocate( mini%y )
  86. end subroutine mini_Done
  87. ! ===================================================
  88. subroutine mini_InitIter( mini, x )
  89. ! --- in/out ----------------------------
  90. type(TMinimumInfo), intent(inout) :: mini
  91. real, intent(out) :: x
  92. ! --- local -----------------------------
  93. integer :: i1, i2, i3
  94. ! --- begin -------------------------------
  95. ! next interation step:
  96. mini%iter = mini%iter + 1
  97. ! leave if this is initialisation:
  98. if ( mini%iter <= 2 ) then
  99. x = mini%x(mini%iter)
  100. return
  101. end if
  102. ! previous and prev-previous:
  103. i1 = mini%iter-2
  104. i2 = mini%iter-1
  105. i3 = mini%iter
  106. mini%x1 = mini%x(i1)
  107. mini%x2 = mini%x(i2)
  108. mini%y1 = mini%y(i1)
  109. mini%y2 = mini%y(i2)
  110. do
  111. if ( mini%y2 <= mini%y1 ) then
  112. !
  113. ! o
  114. ! o
  115. ! ?
  116. ! -------+---+---+------- x
  117. ! 1 2 3
  118. !
  119. ! take same step ...
  120. else if ( mini%y2 > mini%y1 ) then
  121. !
  122. ! o
  123. ! o
  124. ! ?
  125. ! ---+---+---+----------- x
  126. ! 1 3 2
  127. !
  128. ! reverse search direction, decrase step:
  129. mini%dx = - mini%dx/2.0
  130. end if
  131. ! next point:
  132. mini%x3 = mini%x2 + mini%dx
  133. ! already processed ? take x and y and try again:
  134. if ( any( mini%x(1:i2) == mini%x3 ) ) then
  135. do i3 = 1, i2
  136. if ( mini%x(i3) == mini%x3 ) then
  137. mini%y3 = mini%y(i3)
  138. exit
  139. end if
  140. end do
  141. mini%x1 = mini%x2 ; mini%y1 = mini%y2
  142. mini%x2 = mini%x3 ; mini%y2 = mini%y3
  143. else
  144. exit
  145. end if
  146. end do
  147. ! store next point:
  148. mini%x(mini%iter) = mini%x3
  149. ! set output:
  150. x = mini%x3
  151. end subroutine mini_InitIter
  152. ! ***
  153. !
  154. ! status description
  155. ! -1 try next iter
  156. ! 0 converged
  157. ! 1 reached max iter
  158. ! 2 error; no minium in interval ?
  159. !
  160. subroutine mini_DoneIter( mini, y, status )
  161. ! --- in/out ----------------------------
  162. type(TMinimumInfo), intent(inout) :: mini
  163. real, intent(in) :: y
  164. integer, intent(out) :: status
  165. ! --- local -----------------------------
  166. integer :: i1, i2, i3
  167. ! --- begin -------------------------------
  168. ! previous and prev-previous:
  169. i1 = mini%iter-2
  170. i2 = mini%iter-1
  171. i3 = mini%iter
  172. ! store evaluation:
  173. mini%y(i3) = y
  174. if ( mini%verbose ) then
  175. print *, ' iter:', mini%iter, mini%x(i3), mini%y(i3)
  176. !
  177. !print *, 'iter', mini%iter
  178. !print *, ' x=', mini%x
  179. !print *, ' y=', mini%y
  180. !print *, ' '
  181. end if
  182. if ( mini%iter <= 2 ) then
  183. ! next iter
  184. status = -1
  185. return
  186. end if
  187. !print *, ' --->', mini%x(i3), mini%x(i2), abs(mini%x(i3)-mini%x(i2)), mini%atol
  188. if ( abs(mini%x(i3)-mini%x(i2)) <= mini%atol ) then
  189. !if ( mini%verbose ) then
  190. ! print *, 'iter: minimal difference :', mdif
  191. ! print *, ' atol * y :', mini%atol * abs(mini%y(2))
  192. !end if
  193. status = 0
  194. return
  195. end if
  196. if ( mini%iter == mini%maxiter ) then
  197. if ( mini%verbose ) then
  198. print *, 'iter: reached maximum number of iterations'
  199. end if
  200. status = 1
  201. return
  202. end if
  203. ! by default next iter:
  204. status = -1
  205. end subroutine mini_DoneIter
  206. end module num_minimum