Fortran:最小2D函数的梯度方法

时间:2014-12-12 19:52:53

标签: optimization fortran fortran90 genetic-algorithm

我制作了这个简单的程序,使用渐变方法计算目标函数的最小值。我测试它是为了一个简单的1D函数(http://en.wikipedia.org/wiki/Gradient_descent),并且它能很好地给我最小的确切位置。

我将它推广到2D函数:x ^ 4 + 2y ^ 4,其中只有(0,0)中的一个零如下:

real*8 function cubic(xvect_old,n)
   real(8), dimension(n) :: xvect_old

 cubic = 4.d0*(xvect_old(1)**3.d0)+8.d0*(xvect_old(2)**3.d0)     
!cubic = 4.d0*(xvect_old(1)**3.d0)-9.d0*(xvect_old(1)**2.d0)

end function cubic

program findmin
implicit none
   integer, parameter :: n=2
   integer :: i,j,m
   real(8) :: cubic
   real(8), dimension(n) :: xvect,xvect_old
   real(8) :: eps,max_prec
   m=30
   eps = 0.01d0 ! step size
   xvect_old =0.d0
   xvect(1) = 2.2d0 ! first guess
   xvect(2) = 3.1d0
   max_prec = 1e-16

  do while ( abs(xvect(1) - xvect_old(1)) > max_prec .and. &
              & abs(xvect(2) - xvect_old(2)) > max_prec)
   xvect_old(1:2) = xvect(1:2)
   xvect(1:2) = xvect_old(1:2) - eps*cubic(xvect_old,n)
  end do 

  print*, "Local minimum occurs at : ", xvect(1:2)

end program findmin

但它给了我,如果我非常接近正确的位置(让我们说,感谢第一次猜测(1.2,1.1))一些大的非正确的解决方案:

  

( - 0.5017; 0.3982)

方法是否实现错误或者我的理解缺乏方法的准确性?我知道有更先进的方法,比如遗传算法,它们可能更快但是它们也很容易实现吗?

非常感谢。

1 个答案:

答案 0 :(得分:1)

cubic应该返回渐变,因此必须是一个向量。

尝试以下方法:

module functions
implicit none
contains
function cubic(x,n) result(g)
integer, intent(in) :: n
real*8, dimension(n), intent(in) :: x
real*8, dimension(n) :: g
    g =(/ 4.d0*(x(1)**3.d0), 8.d0*(x(2)**3.d0) /)
end function cubic

end module

program SOGradient
use functions
implicit none
integer, parameter :: n=2
integer :: i,j,m
real(8), dimension(n) :: xvect,xvect_old
real(8) :: eps,max_prec
m=30
eps = 0.01d0 ! step size
xvect_old =(/ 0.d0, 0d0 /)
! first guess
xvect = (/ 2.2d0, 3.1d0 /)
max_prec = 1e-12

do while ( MAXVAL(ABS(xvect-xvect_old))>max_prec )
    xvect_old = xvect
    xvect = xvect_old - eps*cubic(xvect_old,n)
end do 

print*, "Local minimum occurs at : ", xvect

end program SOGradient

当然越接近最小值,步长越小,收敛速度就越慢。我建议使用牛顿拉夫森类型方法来找到梯度为零的位置。

所以要找到f(x,y)的最小值,找到渐变g(x,y)=[gx,gy]=[df/dx,df/dy]和渐变的渐变h(x,y) = [[ dgx/dx, dgx/dy],[dgy/dx, dgy/dy]]

现在你用

进行迭代
[x,y] -> [x,y] - h(x,y)^(-1)*g(x,y)

在您的情况下f(x,y) = x^4+2*y^2g=[4*x^3, 8*y^3]h=[[12*x^2,0],[0,24*y^2]]

[x,y] -> [x,y] - [x/3,y/3]

显然在(0,0)中有一个解,但收敛速度要快得多。