Document

Anuncio
7. Optimización de funciones
Se describen aquí algunos algoritmos básicos de optimización de funciones.
7.1. Método Simplex
El procedimiento se debe a Nelder y Mead. Se trata de un algoritmo simple (de
ahí su nombre) que sólo requiere la evaluación de la función y no de sus
derivadas. Esto le confiere diversas características. En principio es un buen
método cuando la función a optimizar no es derivable (funciones de
argumentos enteros, por ejemplo) o cuando la derivada no es calculable (o de
cálculo muy costoso). Para una función analítica el método no es de los más
eficientes pero permite obtener una respuesta al problema planteado. El
procedimiento también se utiliza en el diseño de experimentos: cuando las
variables son parámetros experimentales, se va evaluando la función objetivo a
medida que el procedimiento va requiriendo la evaluación de la función en
diversos puntos.
Un simplex es una figura poliédrica de n+1 vértices inmersa en un espacio de
dimensión n. Así, por ejemplo, en el plano un triángulo es un simples y en el
espacio tridimensional lo es un tetraedro. Estas figuras, en general, no tienen
porque ser regulares. Los simplex que se deben considerar son los que tienen
área, volumen o hipervolumen no nulos.
Supondremos que queremos encontrar un máximo de la función. A
continuación se va a exponer el algoritmo de forma sucinta y simple. Más
información se puede encontrar en el libro de Press et al.
Algoritmo básico simplex para encontrar un punto óptimo (en este caso el
máximo) de una función f(x) de n variables:
1. Considerar n+1 puntos del espacio n dimensional. En todos ellos se evalúa
la función f. Estos puntos deben generar un hipervolumen no nulo. Ello se
puede comprobar viendo como el determinante de la matriz formada por los
n-1 vectores posición de cada punto respecto a uno de ellos que se toma
como origen no es nulo.
2. Del conjunto de puntos, se considera el punto asociado al valor mínimo de f:
Este peor punto se debe sustituir por otro nuevo. La forma habitual de
hacerlo es considerar el centro de masas de los restantes n puntos y hacer
una reflexión del peor punto a través de ese centro de masas. En esa
reflexión el punto ha “recorrido” una distancia 2d (siendo d la distancia inicial
entre el punto y el centro de masas). Se evalua la función en el nuevo punto
obtenido.
2.1. Si el valor de f es mayor que el del mejor punto, se prueba de
nuevo la reflexión pero avanzando un paso 3d (expansión). Se
elige la opción que nos de el mejor nuevo punto. Pasar a 3.
7-1
2.2. Si el nuevo punto tiene un valor peor (menor) que el del segundo
peor punto, se hace una reflexión con un paso igual a 1.5d
(contracción)
2.2.1. Si se continúa obteniendo un valor menor que el del
segundo peor punto se hace una contracción del
simplex (homotecia) con un factor de 0.5 manteniendo
el mejor punto. Se evalúa la función en los nuevos
puntos así obtenidos. Se pasa a 2.
2.2.2. Se pasa a 3.
2.3. Se acepta el nuevo punto calculado en 2.
3. Aplicar el criterio de convergencia: Si la distancia d recorrida es menor que
un cierto valor predeterminado (figura simplex muy diminuta), se acaba el
proceso. En caso contrario se pasa a 2.
7.2. Método de gradiente de Newton
El método de gradiente o de Newton-Raphson es un método analítico básico y
bastante eficiente. El método se basa en expandir una función de n variables
x=(x1,x2,...,xn), f(x), en un punto x0 en serie de Taylor truncada hasta los
términos de primer orden:
f (x ) ≈ f (x 0 ) + [∇f (x 0 )] (x − x 0 ) .
T
En esta notación, el vector gradiente evaluado en el punto x0 es
 ∂f (x ) 


 ∂x 1 
 ∂f (x ) 
∇f (x 0 ) =  ∂x 
.
1 

 M 
 ∂f (x ) 
 ∂x 
n  x =x0

Considerando que el punto x0 no es estacionario (máximo o mínimo) mientras
que el punto x sí que lo es y está lo suficientemente próximo a x0 (tanto como
para que la aproximación de hasta primer orden sea suficientemente precisa)
entonces podemos plantear que
∇f ( x ) = 0
y
{
}
0 = ∇f (x ) ≈ ∇ f (x 0 ) + [∇f (x 0 )] (x − x 0 ) ,
T
con lo cual
0 = ∇f (x 0 ) + ∇[∇f (x 0 )] (x − x 0 ) ,
T
7-2
El gradiente del vector gradiente es la matriz hesiana, la cual contiene todas las
segundas derivadas evaluadas en el punto x0:
 ∂ 2 f (x )

 ∂x 1∂x 1
 ∂ 2 f (x )
∇[∇f (x 0 )] = H (x 0 ) =  ∂x ∂x
 2 1
 M
 ∂ 2 f (x )

 ∂x n ∂x 1
∂ 2 f (x )
∂x 1∂x 2
∂ 2 f (x )
∂x 2 ∂x 2
M
∂ 2 f (x )
∂x n ∂x 2
∂ 2 f (x ) 

∂x 1∂x n 
∂ 2 f (x ) 
L

.
∂x 2 ∂x n 
O
M

∂ 2 f (x ) 
L

∂x n ∂x n  x = x
0
L
Para una función analítica que se comporte bien, la matriz hesiana es
simétrica:
∂ 2 f (x ) ∂ 2 f (x )
=
∀ i, j.
∂x i ∂x j
∂x j ∂x i
Continuando, escribimos 0 = ∇f (x 0 ) + H (x 0 )(x − x 0 ) y podemos despejar cual
es el punto x:
x = x 0 − [H (x 0 )] ∇f (x 0 ) .
−1
Hemos de suponer que el punto x así calculado, si no es ya un punto
estacionario, nos da una mejor aproximación al punto óptimo de la función de lo
que era el punto x0. El método requiere la inversión de una matriz. En algunas
ocasiones esta matriz se puede simplificar considerando sólo los elementos
diagonales. De esta manera su inversión es inmediata.
Así pues, el algoritmo iterativo consiste en lo siguiente:
1. Considerar la tolerancia del proceso 0<ε→0.
2. Considerar un punto inicial x0.
3. Evaluar el vector gradiente g= ∇f (x 0 ) .
4.
5.
6.
7.
Si | g |<ε, el punto óptimo es x0. Terminar.
−1
Evaluar x = x 0 − [H (x 0 )] ∇f (x 0 ) .
Redefinir x0=x.
Ir al paso 3.
7-3
Ejercicios
1. Considerar la función f(x,y)=x2+xy+y2. Partiendo del punto (1,1), aplicar
numéricamente el algoritmo de Newton. Comprobar que se llega al punto del
máximo (0,0) en un solo paso. ¿Por qué?
2. Confeccionar programas que codifiquen los algoritmos aquí descritos.
3. Utilizando los algoritmos descritos aquí y partiendo de un punto (o puntos)
2
2
arbitrario(s), buscar el máximo de las funciones z = x 2 + y 2 y z = e − (x + y ) , los
cuales se encuentran en el punto (0,0). ¿Por qué para la primera función el
método de Newton encuentra la solución en un único paso?
4. ¿Qué cambios cabe efectuar en los algoritmos anteriores para poder
localizar mínimos de funciones? ¿Se te ocurre alguna otra estrategia para
mantener los algoritmos sin modificar y aún así poder localizar máximos o
mínimos de las funciones?
7-4
Programas
!-------------------------------------------------------------------! Busqueda de un maximo de una funcion segun el metodo basico simplex
! Ejemplo para la funcion f=exp[-(x**2+y**2)] de dos variables (n=2):
! el simplex es de dimension n+1=3
!-------------------------------------------------------------------implicit double precision (a-h,o-z)
! Dimensionalidad
parameter (n=2,n1=n+1)
dimension x(n,n1),z(n1),cdm(n),v(n),xnew(n),xnew2(n)
common /counter/ nveces
! Tolerancia para el critero de terminacion
toler=1.0d-3
nveces=0 ! Veces que se evalua la funcion
! Puntos iniciales
x(1,1)=-5.0; x(2,1)=-5.0
x(1,2)=-1.0; x(2,2)=-1.0
x(1,3)= 5.0; x(2,3)=-1.0
! Evalua la funcion en cada punto
do i=1,n1
z(i)=f(x(1,i),x(2,i))
end do
DO ! Proceso iterativo
mi=1 ! Indicaran los puntos minimo y maximo
ma=1 ! (peor y mejor) de los n+1 que se consideran
zmi=z(mi); zma=z(ma)
do i=2,n1
if (z(i)>zma) then
zma=z(i)
ma=i
end if
if (z(i)<zmi) then
zmi=z(i)
mi=i
end if
end do
! Centro de masas
cdm(:)=0.0d0
do i=1,n1
if (i/=mi) then ! excluye el punto del minimo
do j=1,n
cdm(j)=cdm(j)+x(j,i)
end do
end if
end do
cdm(:)=cdm(:)/n
! Calcula vector desplazamiento (de modulo d)
d=0.0d0
do i=1,n
v(i)=cdm(i)-x(i,mi)
d=d+v(i)**2
7-5
end do
d=dsqrt(d)
! Nuevo punto (desplazamiento 2d) y valor de la funcion en el
do i=1,n
xnew(i)=x(i,mi)+2*v(i)
end do
znew=f(xnew(1),xnew(2))
if (znew>z(ma)) then ! Se ha mejorado lo mejor. Prueba 3d
do i=1,n
xnew2(i)=xnew(i)+v(i)
end do
znew2=f(xnew2(1),xnew2(2))
if (znew2>znew) then ! Este nuevo punto es el elegido
znew=znew2
xnew(:)=xnew2(:)
end if
x(:,mi)=xnew(:)
z(mi)=znew
else ! Necesita buscar el segundo peor punto
! mi2 indica el segundo peor punto
do i=1,n1
if (i/=mi .and. i/=ma) then ! Descarta mi y ma
mi2=i
zmi2=z(mi2)
exit
end if
end do
do i=1,n1
if (i/=mi .and. i/=ma) then ! Descarta mi y ma
if (z(i)<zmi2) then
zmi2=z(i)
mi2=i
end if
end if
end do
if (znew<zmi2) then ! Peor que el segundo peor punto
do i=1,n
xnew2(i)=xnew(i)+1.5*v(i) ! Contraccion
end do
znew2=f(xnew2(1),xnew2(2))
if (znew2<zmi2) then ! Continua siendo malo: homotecia
do i=1,n1
! Recorre los puntos
if (i/=ma) then ! Descarta el mejor
do j=1,n
dist=x(j,i)-x(j,ma)
x(j,i)=x(j,ma)+dist/2 ! Homotecia
end do
z(i)=f(x(1,i),x(2,i))
end if
end do
CYCLE
end if
x(:,mi)=xnew2(:)
z(mi)=znew2
7-6
else
x(:,mi)=xnew(:)
z(mi)=znew
end if
end if
! Criterio de convergencia
if (d<toler) exit ! Final
END DO
write(*,*) " Mejor punto encontrado:"
write(*,*) xnew(:)
write(*,'(" Valor de la funcion:",g14.6)') znew
write(*,'(" La funcion se ha evaluado",i5," veces.")') nveces
END
!-------------------------------------------------------------------double precision function f(x,y)
implicit double precision (a-h,o-z)
common /counter/ nveces
f=exp(-(x**2+y**2))
nveces=nveces+1
END
!--------------------------------------------------------------------
7-7
!----------------------------------------------------------------! Busqueda el punto optimo segun el metodo de Newton
! Solucion particular del problema 1: f=x**2+x*y*y**2
!----------------------------------------------------------------implicit double precision (a-h,o-z)
dimension x0(2),x(2),g(2),H(2,2)
dimension Ht(2,2),S(2,2),T(2,2),Ti(2,2),Tit(2,2),Hi(2,2),Si(2,2)
! Punto inicial
x0(1)=1.0d0; x0(2)=1.0d0
DO
! Calcula el gradiente
call gradfun(x0,g)
! Criterio de convergencia
gmod=SUM(g(:)**2)
if (gmod<1.0d-10) then ! Se acaba aqui
write(*,'("
Punto optimo:",2g14.6)') x0(:)
write(*,'(" Modulo del gradiente:",g14.6)') gmod
stop "Programa acabado normalmente."
end if
! Obtiene la matriz Hessiana
call Hess(x0,H)
! INVIERTE HESSIANA. Esta matriz es simetrica
! Se utilizan mas matrices de lo necesario para que
! el codigo sea mas legible
! Matriz simetrica S=HtH definida no negativa
call producto_de_matrices(H,H,S,2,2,2)
! Efectua la descomposicion de Cholesky de S
call Cholesky(S,2,T)
! Inversa de la matriz triangular T: Ti
call inversa_T(T,2,Ti)
! Genera la matriz transpuesta de Ti: Tit
call transpone(Ti,2,2,Tit)
! Calcula la inversa de S: Si=Ti*Tit
call producto_de_matrices(Ti,Tit,Si,2,2,2)
! Calcula la inversa de H: H(-1)=Si*H
call producto_de_matrices(Si,H,Hi,2,2,2)
! Calcula en nuevo punto
call producto_de_matriz_vector(Hi,g,x,2,2) ! El vector Hg
x0(:)=x0(:)-x(:) ! Nuevo punto
END DO
END
!-----------------------------------------------------------------
7-8
!----------------------------------------------------------------subroutine gradfun(x,g)
implicit double precision (a-h,o-z)
dimension x(2),g(2)
g(1)= 2*x(1)+x(2) ! df/dx = 2x+y
g(2)= x(1)+2*x(2) ! df/dy = x+2y
END
!----------------------------------------------------------------!----------------------------------------------------------------subroutine Hess(x,H)
implicit double precision (a-h,o-z)
dimension x(2),H(2,2)
H(1,1)=
H(1,2)=
H(2,1)=
H(2,2)=
2.0d0
1.0d0
1.0d0
2.0d0
!
!
!
!
d2f/dxdx
d2f/dxdy
d2f/dydx
d2f/dydy
=
=
=
=
2.
1.
1.
2.
! En general, estos terminos
! deberian ser funciones
!
!
END
!----------------------------------------------------------------!-------------------------------------------------------------------SUBROUTINE transpone(A,n,m,B)
implicit double precision (A-H,O-Z)
dimension A(n,m),B(m,n)
do i=1,m
do j=1,n
B(i,j)=A(j,i)
end do
end do
END
!-------------------------------------------------------------------!-------------------------------------------------------------------SUBROUTINE producto_de_matrices(A,B,C,ma,na,mb)
implicit double precision (A-H,O-Z)
dimension A(ma,na),B(na,mb),C(ma,mb)
do i=1,ma
do j=1,mb
C(i,j)=0.0
do k=1,na
C(i,j)=C(i,j)+A(i,k)*B(k,j)
end do
end do
end do
END
!-------------------------------------------------------------------!-------------------------------------------------------------------SUBROUTINE producto_de_matriz_vector(A,u,v,n,m)
implicit double precision (A-H,O-Z)
dimension A(n,m),u(n),v(n)
do i=1,n
v(i)=0.0
do j=1,m
v(i)=v(i)+A(i,j)*u(j)
end do
end do
END
!--------------------------------------------------------------------
7-9
!-------------------------------------------------------------------subroutine Cholesky(S,n,T)
implicit double precision (a-h,o-z)
dimension S(n,n),T(n,n)
! Define el triangulo inferior con ceros
do i=1,n
do j=1,i-1
T(i,j)=0.0
end do
end do
! Descomposicion de Cholesky
do i=1,n
sum=0.0
do k=1,i-1
sum=sum+t(k,i)**2
end do
t(i,i)=dsqrt(s(i,i)-sum)
do j=i+1,n
sum=0.0
do k=1,i-1
sum=sum+t(k,i)*t(k,j)
end do
t(i,j)=(s(i,j)-sum)/t(i,i)
end do
end do
END
!-------------------------------------------------------------------!-------------------------------------------------------------------subroutine inversa_T(T,n,Ti)
implicit double precision (a-h,o-z)
dimension T(n,n),Ti(n,n)
! Define el triangulo inferior con ceros
do i=1,n
do j=1,i-1
Ti(i,j)=0.0
end do
end do
! Inversa de la matriz triangular superior
do L=0,n-1
do i=1,n-L
if (L.eq.0) then
Ti(i,i)=1.0d0/t(i,i)
else
iL=i+L
sum=0.0d0
do k=i+1,iL
sum=sum+t(i,k)*ti(k,iL)
end do
ti(i,iL)=-sum/t(i,i)
end if
end do
end do
END
!--------------------------------------------------------------
7-10
Código que debe cambiarse para buscar el punto óptimo de la función
2
2
z = e − (x + y ) . Se trata de las funciones de cálculo del gradiente y la hessiana:
gradfun() y Hess().
!----------------------------------------------------------------! Busqueda el punto optimo segun el metodo de Newton
! Solucion particular para la funcion f=exp[-(x**2+y**2)]
!----------------------------------------------------------------!----------------------------------------------------------------subroutine gradfun(x,g)
implicit double precision (a-h,o-z)
dimension x(2),g(2)
expo=dexp(-(x(1)**2+x(2)**2))
g(1)= -2*x(1)*expo ! df/dx = -2*x*expo
g(2)= -2*x(2)*expo ! df/dy = -2*y*expo
END
!----------------------------------------------------------------!----------------------------------------------------------------subroutine Hess(x,H)
implicit double precision (a-h,o-z)
dimension x(2),H(2,2)
expo=dexp(-(x(1)**2+x(2)**2))
H(1,1)=
H(1,2)=
H(2,1)=
H(2,2)=
2*expo*(2*x(1)**2-1.0d0)
-4*x(1)*x(2)*expo
H(1,2)
2*expo*(2*x(2)**2-1.0d0)
!
!
!
!
d2f/dxdx = 2*expo*(2x**2-1)
d2f/dxdy = -4xy*expo
Simetrica
d2f/dydy = 2*expo*(2y**2-1)
END
!-----------------------------------------------------------------
7-11
Descargar