Recocido Simulado: Algoritmo B´ asico
c M. Valenzuela 1996–2003 (19 de enero de 2004)
1. Idea b´ asica de recocido simulado
Cuando un material se somete a un calentamiento a temperatura muy alta, y despu´es se le deja enfriar lentamente, sus mol´eculas se acomandan de tal forma que la energ´ıa potencial de la configu- raci´on de las mol´eculas es m´ınima; a este proceso f´ısico le llamaremos recocido.1A cada temperatura del materal, el estado determinado por la configuraci´on de las mol´eculas sigue la distribuci´on de Boltzmann.
1.1. Algoritmo de Metropolis
La forma en que se visitan los estados posibles de configuraciones de las mol´eculas de un material a una temperatura fija puede simularse mediante el algoritmo de Metropolis definido de la siguiente manera. Se tiene un material en alg´un estado inicial u con energ´ıa Eu; se genera un nuevo estado v con energ´ıa Ev aplicando una perturbaci´on peque˜na (como el movimiento de una mol´ecula). Si el estado v tiene una energ´ıa menor, se acepta como el nuevo estado. Si no, se acepta con una probabilidad de
exp −Ev− Eu kBT
!
, (1)
donde kB es la constante de Boltzmann y T es la temperatura. El ciclo se repite. El algoritmo de Metropolis hace que los estados se visiten con la misma distribuci´on de probabilidad con la que en el proceso f´ısico se tienen las configuraciones de mol´eculas. La distribuci´on de probabilidad con la que se visitan los diferentes estados es la distribuci´on de Boltzmann.
1.2. Distribuci´ on de Boltzmann
En equilibrio t´ermico, es decir, despu´es que el material ha estado a una temperatura constante por un tiempo suficientemente largo, la probabilidad de que el material se encuentre en el estado u con energ´ıa Eu a la temperatura T est´a dada por
PT{X = u} =
exp − Eu kBT
!
X
v
exp − Ev kBT
! , (2)
donde la suma se extiende sobre todos los estados posibles. La figura ?? muestra la distribuci´on de probabilidad de Boltzmann.
1.3. Aplicaci´ on del algoritmo de Metropolis
Para utilizar el algoritmo de Metropolis para optimizaci´on combinatoria donde se desea minimizar una funci´on de costo f se hacen las siguientes substituciones. Se toma el estado u como una soluci´on posible del problema de optimizaci´on; f (u) como la energ´ıa del estado u; se define un par´ametro de control c = tBT que tiene la funci´on de la temperatura en el algoritmo de Metropolis. El criterio de aceptaci´on es ahora
P{Aceptar nueva soluci´on v} =
1, si f (v) ≤ f (u);
exp
−f (v) − f (u) c
, si f (v) > f (u). (3)
1En metalurgia se utiliza el t´ermino de revenido.
0 10 20 30 40 50 60 0
0.05 0.1 0.15 0.2 0.25
Energia
Probabilidad
Distribucion de Bolztmann
kBT = 512.00 kBT = 128.00 kBT = 32.00 kBT = 8.00 kBT = 2.00
Figura 1: Distribuci´on de probabilidad de Boltzmann.
2. Algoritmo b´ asico de recocido simulado
Sea ckel par´ametro de control y Lkel n´umero de transiciones generadas en el ciclo k del algoritmo de Metropolis. El algoritmo simple de recocido simulado puede ser descrito de la siguiente forma:
Recocido Simulado Inicializar (u0, c0, L0) k ← 0
u ← u0
repetir
para` ← hasta Lk hacer Generar vecino v de u sif (v) ≤ f (u)
entoncesu ← v sino
sialeatorio[0, 1) < exp
−f (v) − f (u) ck
entoncesu ← v
fin-si fin-si fin-para k ← k + 1
Calcular longitud L(k) Calcular control c(k)
hastaque se cumpla criterio de terminaci´on
3. Aplicaci´ on pr´ actica de recocido simulado
Para aplicar el algoritmo de recocido simulado es necesario especificar algunos puntos que no se describen en el algoritmo. A continuaci´on se da describen estos detalles de implementaci´on y una forma sencilla de decidirlos.
Valor incial del par´ametro de control c0
Se inicializa c con un valor peque˜no y se multiplica por una constante β mayor que 1 hasta que la raz´on de aceptaci´on sea cercana a 1.
Decremento del par´ametro de control
Es usual un decremento exponencial definido por la siguiente ecuaci´on:
ck+1= αck, (4)
donde α es una constante tal que 0 < α < 1.
Valor final del par´ametro de control
Se termina la ejecuci´on del algoritmo cuando el valor de la funci´on de costo de la soluci´on obtenida en el ´ultimo intento de una cadena de Markov permanece sin cambio por un n´umero determinado de cadenas consecutivas.
Longitud de cada cadena de Markov
Se termina cada cadena cuando se llega a un n´umero de transiciones aceptadas. Para evitar que se tengan cadenas excesivamente grandes al final de la corrida, se limita Lka no ser mayor que una constante dada L.
Funci´on de vecindad
La funci´on de vecindad es dependiente del problema y de la forma de los par´ametros de la funci´on objetivo. Por ejemplo, para par´ametros reales se obtiene un vecino sumando a cada par´ametro un n´umero aleatorio peque˜no con distribuci´on uniforme en el intervalo [−ν/2, ν/2], donde ν es la tama˜no de la vecindad.
4. Implementaci´ on del algoritmo b´ asico
A continuaci´on se lista la implementaci´on en MATLAB del algoritmo b´asico de recocido simula- do.2
function [intentos,mejorEv] = recocido(x0, varargin)
% [intentos,mejorEv] = recocido(x0)
% [intentos,mejorEv] = recocido(x0, semilla)
%
% Implementa el algoritmo basico de recocido simulado
%
% x0: punto inicial
% semilla: semilla del generador de numeros aleatorios
% M. Valenzuela (1 de septiembre de 2000)
% Revision 1: 31 de enero de 2001
% Errores varios
% Revision 2: 28 de abril de 2001
2En el URL http://www-cia.mty.itesm.mx/~mvalenzu/Software se encuentran varias implementaciones del algo- ritmo b´asico de recocido simulado en Python, MATLAB, Modula-3, Pascal, y C.
% Variables globales
global temp totalIntentos mejor salida
% Parametros del algoritmo
global pMax pMin longCadena maxIntentos minIntentos ...
minRazonAceptacion alfa beta maxCadenas frecImpresion ...
tamanoVecindad intentos mejorEv pMax = 10;
pMin = -10;
longCadena = 50;
maxIntentos = 100;
minIntentos = 20;
minRazonAceptacion = 0.8;
alfa = 0.5;
beta = 1.2;
maxCadenas = 3;
frecImpresion = 40;
tamanoVecindad = 0.1;
nomSalida = ’salida’;
if length(varargin)>=1 sem = varargin{1};
else
sem = sum(100*clock);
end
% Programa principal intentos = [];
mejorEv = [];
InicializarRand(sem);
salida = fopen(nomSalida, ’w’);
fprintf(’*** Inicio del programa ***\n’);
punto = InicializaPunto(x0);
[temp, punto] = Inicializar(punto);
punto = Recocido(punto, temp);
fprintf(1, ’Ultimo punto encontrado: ’);
ImprimePunto(1, punto);
fprintf(1, ’\n’)
fprintf(1, ’Mejor punto encontrado: ’);
ImprimePunto(1, mejor);
fprintf(1, ’\n’) fclose(salida);
% Fin del programa principal function ImprimePunto(archivo, u)
%*********************
% Imprime un punto u *
%*********************
fprintf(archivo, ’f(%5.2f,%5.2f) = %8.2f’, ...
u.x, u.y, u.evaluacion);
function f = FcnObjetivo(punto)
%*********************************
% Implementa la funcion objetivo *
% En este ejemplo implementa la *
% funcion f(x,y) = x^2 + y^2 *
%*********************************
f = punto.x^2 + punto.y^2;
%f = cos(sqrt(10*punto.x))*exp(-punto.x/100);
function uEvaluada = EvaluaPunto(u)
%*******************************************
% Evalua un punto u y guarda su evaluacion *
%*******************************************
global totalIntentos frecImpresion salida mejor intentos ...
mejorEv
u.evaluacion = FcnObjetivo(u);
if (u.evaluacion < mejor.evaluacion) mejor = u;
end
if ( mod(totalIntentos,frecImpresion)==0 )
fprintf(salida, ’Intentos =%6d ’, totalIntentos);
ImprimePunto(salida, mejor);
fprintf(salida, ’\n’);
intentos = [intentos totalIntentos];
mejorEv = [mejorEv mejor.evaluacion];
end
totalIntentos = totalIntentos + 1;
uEvaluada = u;
function u = InicializaPunto(x0)
%************************
% Inicializa el punto u *
%************************
global mejor totalIntentos u = x0;
totalIntentos = 0;
% Se evalua directamente para evitar comparacion
% con mejor que todavia no contiene nada u.evaluacion = FcnObjetivo(u);
mejor = u;
% Se llama a EvaluaPunto para permitir
% impresion del primer punto u = EvaluaPunto(u);
fprintf(1, ’punto inicial: ’);
ImprimePunto(1, u) fprintf(1, ’\n’)
function vecino = GeneraVecino(punto)
%*****************************
% Regresa un vecino de punto *
%*****************************
global tamanoVecindad pMax pMin aux = punto;
aux.x = aux.x + tamanoVecindad * (rand - 0.5);
aux.y = aux.y + tamanoVecindad * (rand - 0.5);
if (aux.x > pMax) aux.x = pMax;
else
if (aux.x < pMin) aux.x = pMin;
end end
if (aux.y > pMax) aux.y = pMax;
else
if (aux.y < pMin) aux.y = pMin;
end end
aux = EvaluaPunto(aux);
vecino = aux;
function b = AceptaIntento(u, v, c)
%*******************************************
% Regresa verdadero (1) si se debe aceptar *
% un punto nuevo v dado un punto viejo u *
%*******************************************
if (v.evaluacion <= u.evaluacion) b = 1;
return else
if ( rand < exp(-(v.evaluacion-u.evaluacion)/c) ) b = 1;
return else
b = 0;
return end end
function uFinal = CadenaMarkov(u, c)
%*******************************
% Ejecuta una cadena de Markov *
% a una temperatura fija c *
%*******************************
global maxIntentos longCadena intentos = 0;
intentosAceptados = 0;
while ( (intentosAceptados < longCadena) & ...
(intentos < maxIntentos) ) v = GeneraVecino(u);
intentos = intentos + 1;
if (AceptaIntento(u, v, c)) u = v;
intentosAceptados = intentosAceptados + 1;
end end
uFinal = u;
function uFinal = Recocido(u, c)
%**********************************************
% Implementa el algoritmo basico de recocido; *
% regresa el ultimo punto visitado *
%**********************************************
global totalIntentos maxCadenas alfa cadenasSinMejora = 0;
anterior = u;
fprintf(1, ’temp. =%4.1f ’, c);
fprintf(1, ’intentos =%5d ’, totalIntentos);
ImprimePunto(1, u);
fprintf(’\n’);
while (cadenasSinMejora < maxCadenas);
u = CadenaMarkov(u, c);
if ( (u.evaluacion) >= anterior.evaluacion ) cadenasSinMejora = cadenasSinMejora + 1;
else
cadenasSinMejora = 0;
end
fprintf(1, ’temperatura =%4.1f ’, c);
fprintf(1, ’intentos =%5d ’, totalIntentos);
ImprimePunto(1, u);
fprintf(1, ’ sin mejora =%3d\n’, cadenasSinMejora);
anterior = u;
c = c*alfa;
end
uFinal = u;
function [c, u0] = Inicializar(u)
%**********************************
% Regresa una temperatura inicial *
%**********************************
global beta minIntentos minRazonAceptacion intentos = 0;
intentosAceptados = 0;
c=1.0;
while ( (intentos <= minIntentos) | ...
((1.0*intentosAceptados)/intentos <= minRazonAceptacion) ) v = GeneraVecino(u);
intentos = intentos + 1;
if ( AceptaIntento(u, v, c) ) u = v;
intentosAceptados = intentosAceptados + 1;
end
c = c*beta;
end
fprintf(1, ’temp inicial =%4.1f’, c);
fprintf(1, ’ intentos =%5d’, intentos);
fprintf(1, ’ intentos aceptados =%5d\n’, intentosAceptados);
u0 = u;
function InicializarRand(semilla)
%***********************************************
% Inicializa el generador de numero aleatorios *
%***********************************************
rand(’seed’, semilla);
fprintf(1, ...
’Semilla del generador de numeros aleatorios: %d\n’, ...
semilla);
5. Mejoras al algoritmo b´ asico
Las siguientes son las modificaciones m´as sencillas al algoritmo b´asico de recocido simulado:
Enfriamiento de la funci´on de vecindad
La funci´on de vecindad toma como par´ametro la temperatura; a mayor temperatura m´as grande es la vecindad. De esta manera, el algoritmo tiende a buscar en regiones cercanas al punto donde se encuentra a medida que la temperatura tiende a cero.
Modificaciones de la temperatura dentro de la cadena de Markov
Al inicio de la i´esima cadena de Markov la temperatura se varia de acuerdo a
c(i) = αc(i − 1) (5)
donde c(i − 1) es la temperatura a la que se termin´o la cadena de Markov anterior. Adicional- mente, la temperatura dentro de cada cadena de Markov var´ıa de acuerdo a la evaluaci´on de la funci´on objetivo:
cnueva= fse acaba de aceptar
fanterior aceptada
canterior (6)
donde fse acaba de aceptar es la evaluaci´on que se acaba de aceptar, fanterior aceptada es la evalau- ci´on de la transici´on anterior que se haya aceptado, y canteriores la temperatura anterior.