Sunteți pe pagina 1din 11

Universitatea Tehnic din Cluj-Napoca,

Centrul universitar Nord din Baia Mare


Masterat - Facultatea de Inginerie
Specializarea: Informatic i inginerie software - anul II

Algoritmi metaeuristici i aplicaii


Simulated Annealing

Prof. coord.: Pintea Camelia Mihaela


Masterand: Oan Raul Andrei

Simulated Annealing
"Simulated Annealing" a aprut la nceputul anilor 1980 n optimizarea combinatorial
(Kirkpatrick, Cerny), avnd ca surs de inspiraie procesul fizic de clire a solidelor.
Simulated annealing = tratament termic simulat = clire simulat;
Meta-euristica de tip traiectorie permite o mai bun explorare a spaiului i iesirea din
puncte de optim local, dnd posibilitatea vizitrii unor soluii de calitate mai slab dect cea
curent.
Numele de "Simulated Annealing" este derivat din nclzirea fizic a unui material
precum oelul, care este supus unor temperaturi mari, dup care este rcit gradual.
Algoritmi de cutare aleatoare
Introducerea unor elemente aleatoare ntr-un proces de cutare a soluiei unei probleme
de optimizare permite evitarea blocrii n optime locale i apropierea de optimul global.
"Simulated Annealing" este un algoritm de cutare aleatoare, deci acesta ncepe cu o
soluie care este total aleatoare. Acesta modific rezultatul pn cnd se ajunge la un rezultat
aproape de cel optim. Aceasta modific soluia precedent chiar dac noua soluie este mai rea
dect precedenta. Probabilitatea de a accepta o soluie mai rea scade cu timpul.
Mai jos este prezentat pseudocod-ul pentru cutarea "Simulated Annealing":
select an initial solution , intial as current
select the initial temperature T
select the temperature change counter k
select the minimum temperature M
repeat until T > M
next = generate successor(current)
if heuristics(next) < heauristics(current)
current = next
end if
else
delta = heuristics(next) = heuristics(current)
current = next only with prob = exp(delta/T)
Cool the temperature T by k

Algoritmul acesta se parcurge n 5 pai:


set initial temperature
repeat
for a predetermined number of times do
generate a perturbation
if energy decreased then
accept new state
else
accept new state with probability p(E)
end if
end for
decrease temperature
until frozen
Pasul 1. Iniializarea se ncepe cu p soluie iniial aleatoare. Se iniializeaz cu o temperatur
foarte mare;
Pasul 2. Mutarea Se face o mutare definit;
Pasul 3. Calcularea scorului Se calculeaz noul scor obinut dup mutarea fcut;
Pasul 4. Alegerea n funcie de schimbarea scorului se accept sau nu mutarea. Acceptarea
mutrii se face n funcie de temperatura curent;
Pasul 5. Actualizare i repatare Se actualizez valoarea temperaturii scznd-o. Ne ntoarcem
la Pasul 2.
Procesul este ncheiat atunci cnd este atins Pragul de nghe.
Algoritmul Simulated Annealing este prezentat mai jos:
Begin
temp = INIT-TEMP;
place = INIT-PLACEMENT;
while (temp > FINAL-TEMP) do
while (inner_loop_criterion = FALSE) do
new_place = PERTURB(place);
C = COST(new_place) - COST(place);
if (C < 0) then
place = new_place;
else if (RANDOM(0,1) > e-(C/temp)) then
place = new_place;
temp = SCHEDULE(temp);
End.

Ideea principal a acestui algoritm este c aproximaia curent este perturbat aleator, iar
dac prin perturbare se ajunge la o configuraie mai bun, aceasta se accept. Se accept, cu o
anumita probabilitate, i ajustari ale configuraiei curente care conduc la creterea funciei
obiectiv.
Procesul de reorganizare a structurii unui solid supus unui tratament termic:
Solidul este nclzit (topit): particulele sunt distribuite ntr-o manier aleatoare;
Solidul este rcit lent: particulele se reorganizeaz pentru a se ajunge la configuraii de
energie din ce n ce mai mic.

Aplicaii ale algoritmului Simulated Annealing:


Partiionarea unui circuit i distribuirea prilor acestuia;
Programarea strategiei pentru produse de capital cu o structur complex;
Repartizarea arbitrilor la turneul de tenis US Open;
Situaii de nvare bazate pe evenimente.

Rezolvarea problemei 8 puzzle utiliznd Simulated Annealing Search


Enun. 8 puzzle este o matrice de 3X3 elemente, unde acestea sunt numerotate de la 1 la
8. O poziie este inut goal tot timpul. Pot fi mutate elemente adiacente pe poziia goal. Se
cere ordonarea elementelor de la 1 la 8 prin mutarea elementelor adiacente pe poziia goal.

Fig.1 8 puzzle
Privind poziia iniial a elementelor ne dm seama c putem muta doar plcile: 2 i 5.
Transformm problema 8 puzzle ntr-o matrice de 3X3 cu elementul gol pe poziia [0, 2].
Care sunt elementele care pot fi mutate pe poziia [0,2]? n mod evident elementele de pe
poziiile [0,1] i [1,2]. Cu alte cuvinte poziia goal poate fi mutat dintr-o poziie n alta prin
mutri n sus, n jos, n stnga sau n dreapta. S spunem c mutnd poziia goal facem schimb
de poziii.
ntr-o problem de inteligen artificial avem nevoie de informaii despre costul drumului,
adncime i cost estimat. Acestea ar trebui s fie incluse n problema noastr. Clasa noastr va
conine variabile definite:
Variabila $pos pentru a pstra poziia iniial;
Variabila $sequence pentru a pstra calea de la nodul rdcin la nodul curent;
Variabila $val pentru a ine costul estimat al soluiei finale;
Variabila $goal_position pentru a ine soluia final.
n definiia problemei am transformat matricea de 3X3 ntr-un ntreg.
4

Poziia iniial din figura de mai sus este 120345678 i soluia final este data de poziia
012345678. Astfel reducem consumul de memorie.
Avem nevoie de o funcie care returneaz succesorii fiecrui nod.
Avem nevoie de o funcie euristic, care returneaz costul de parcurgere a drmului ctre
nodul int de la nodul curent.
Fiecare poziie din starea iniial este potrivit cu poziia din starea final. n poziia
iniial elementul cu numrul 2 este localizat pe poziia [0,1], iar n starea final pe poziia [0,2].
n concluzie este nevoie ca acesta s fie mutat o poziie la dreapta pentru a ajunge n poziia
final.
Costul estimat este calculat dup formula urmtoare:
Presupunem c [i,j] este locaia elementului n starea curent i locaia final ar fi [x,y].
Generaliznd, descoperim c numrul de mutri ale plcii pentru a ajunge n poziia final este
dat de formula: |i-x| + |j-y|.
Mai jos avem implementarea funciilor problemei 8 puzzle n limbajul de programare PHP:
<?php
/**Descrierea problemei*/
class Puzzle {
var $pos;
var $sequence;
var $depth;
var $val;
var $path_cost;
var $goalpos;
function setInitial($current_pos) {
$this->pos = $this->arrayToNumber($current_pos);
$this->depth = 1;
$this->sequence[] = $this->pos;
}
function setGoalpos($goal_pos) {
$this->goalpos = $this->arrayToNumber($goal_pos);
$this->evaluate($goal_pos);
}
function goalTest() {
if ($this->pos == $this->goalpos) {
return True;
} else {
return False;
}
}
function possibleMoves() {
$Moves = array();
$current_pos = $this->numberToArray($this->pos);
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
if ($current_pos[$i][$j] == 0) {
break 2;
}
}
}
$this->checkMove($i, $j, $i - 1, $j, $current_pos,
$this->checkMove($i, $j, $i + 1, $j, $current_pos,
$this->checkMove($i, $j, $i, $j - 1, $current_pos,
$this->checkMove($i, $j, $i, $j + 1, $current_pos,
return $Moves;
}

$Moves);
$Moves);
$Moves);
$Moves);

function moveBlank($srcRow, $srcCol, $destRow, $destCol, $newpos) {


$tmp = $newpos[$destRow][$destCol];
$newpos[$destRow][$destCol] = $newpos[$srcRow][$srcCol];
$newpos[$srcRow][$srcCol] = $tmp;
return $newpos;
}
function InSequence($pos) {
foreach ($this->sequence as $seqpos) {
if ($seqpos === $pos) {
return TRUE;
}
}
return FALSE;
}
function canMove($srcRow, $srcCol, $destRow, $destCol) {
if ($srcRow < 0 or $srcCol < 0 or $destRow < 0 or $destCol < 0) {
return FALSE;}
if ($srcRow > 2 or $srcCol > 2 or $destRow > 2 or $destCol > 2) {
return FALSE;
}
return TRUE;
}
function checkMove($srcRow, $srcCol, $destRow, $destCol, $current_pos, & $Moves) {
if ($this->canMove($srcRow, $srcCol, $destRow, $destCol)) {
$newpos = $this->moveBlank($srcRow, $srcCol, $destRow, $destCol, $current_pos);
$posnum = $this->arrayToNumber($newpos);
if ($this->InSequence($posnum) == FALSE) {
//$newMove = new Puzzle();
$newMove = clone $this;
$newMove->pos = $posnum;
//$newMove->sequence = array_merge($this->sequence);
$newMove->sequence[] = $posnum;
//$newMove->goalpos = $this->goalpos;
$newMove->depth++;
$newMove->evaluate($newpos);
$Moves[] = $newMove;
}
}
}
function printSequence() {
for ($i = 0; $i < count($this->sequence); $i++) {
print ("Pasul $i -------<br>
");
$pos = $this->numberToarray($this->sequence[$i]);
$this->printPos($pos);
print("<br>");
}
}
function printPos($pos) {
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
print(" " . $pos[$i][$j] . " ");
}
print("<br>");
}
}
function printReverse() {
for ($i = ($this->depth - 1); $i >= 0; $i--) {
print ("Pasul $i -------<br>
");
$pos = $this->numberToArray($this->sequence[$i]);
$this->printPos($pos);
print("<br>");
}
}

function evaluate($pos) {
//$pos = $this->numberToarray($this->pos);
$this->heuristics($pos);
$this->pathCost();
}
function heuristics($pos) {
$goalpos = $this->numberToarray($this->goalpos);
$this->val = 0;
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
$blockrow = 0;
$blockcol = 0;
$this->findBlock($goalpos[$i][$j], $blockrow, $blockcol, $pos);
$blockval = abs($blockrow - $i) + abs($blockcol - $j);
$this->val = $this->val + $blockval;
}
}
}
function pathCost() {
$this->path_cost = $this->depth;
}
function findBlock($val, &$i, &$j, $pos) {
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
if ($pos[$i][$j] == $val) {
break 2;
}
}
}
}
function arrayToString($posarray) {
$posstr = "";
for ($i = 0; $i < 3; $i++) {
$s = implode(",", $posarray[$i]);
$posstr = $posstr . "|" . $s;
}
return $posstr;
}
function stringToarray($posstr) {
$posarray = array();
$iterarray = explode("|", $posstr);
for ($i = 1; $i < count($iterarray); $i++) {
$posarray[] = explode(",", $iterarray[$i]);
}
return $posarray;
}
function arrayToNumber($posarray) {
$posnum = 0;
$multiplier = 100000000;
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
//$pw = (2 - $j) + (2 - $i) * 3;
$posnum = $posnum + $posarray[$i][$j] * $multiplier;
$multiplier = $multiplier / 10;
}
}
return $posnum;
}
function numberToArray($posnum) {
$posarray = array();
$divider = 100000000;
for ($i = 0; $i < 3; $i++) {

//pow(10, $pw);

for ($j = 0; $j < 3; $j++) {


//$pw = (2 - $j) + (2 - $i) * 3;
//$divider = pow(10, $pw);
$posarray[$i][$j] = (int) ($posnum / $divider);
$posnum = $posnum % $divider;
$divider = $divider / 10;
}
}
return $posarray;
}
}

Mai jos avem codul surs pentru rezolvarea problemei 8 puzzle cu Simulated Annealing:
<!DOCTYPE html>
<!-To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
/*
* Rezolvarea problemei 8 puzzle folosind simulated annealing
*/
include("puzzle.php");
$start_time = microtime(true);
$initial_pos
array(1,
array(3,
array(6,
);

= array(
2, 0),
4, 5),
7, 8)

$goal_pos = array(
array(0, 1, 2),
array(3, 4, 5),
array(6, 7, 8)
);
$initial_state = new Puzzle();
$initial_state->setInitial($initial_pos);
$initial_state->setGoalpos($goal_pos);
$temp = 10;
$epsi = 0.999;
$steps = 1;
$current_state = clone $initial_state;
while ($temp > 1) {
$steps++;
if ($current_state->goalTest() == TRUE) {
print("Soluie gsit n urma evalurii a $steps noduri; <br>");
break;
}
$moves = $current_state->possibleMoves();
$cnt = count($moves);
if ($cnt == 0) {
break;

}
$index = rand(0, $cnt - 1);
if ($moves[$index]->val <= $current_state->val) {
$current_state = $moves[$index];
} else {
$delta = $current_state->val - $moves[$index]->val;
$rand = rand(1, 10000) / 10000;
$prob = exp($delta / $temp);
if ($prob > $rand) {
$current_state = $moves[$index];
}
if ($steps % 2 == 0) {
print "Dup $steps iteraii probabilitatea = $prob; <br>";
}
$temp = $temp * $epsi;
}
}
print $current_state->printSequence();
print ("<br>Memorie maxim folosit: " . memory_get_peak_usage().";");
print ("<br>Memorie curent folosit: " . memory_get_usage().";");
$end_time = microtime(true);
$time_exec = $end_time - $start_time;
print("<br>Timp de execuie = " . $time_exec.".");
?>
</body>
</html>

Dup rularea codului surs n browser, vom obine urmtorul rezultat(optim):

Fig. 2 Soluie problem 8 puzzle

Concluzii
Algoritmii Simulated Annealing sunt de obicei mai buni dect algoritmii greedy, cnd este
vorba de probleme care au un numr mare de soluii optime.
S-a dovedit c folosirea acestui algoritm poate conduce spre cea mai bun soluie. Problema
este c rezolvarea poate dura mai mult dect ar dura folosind o cutare exhaustiv. Dei nu este
potrivit pentru gsirea celei mai bune soluii, simulated annealing are aceast proprietate
important care este folosit ca baz pentru cercetrile viitoare.
Simulated Annealing nu este cea mai bun soluie pentru partiionarea unui circuit i
plasarea acestuia. Aceste probleme sunt rezolvate mult mai repede cu abordarea fluxurilor de
reea.
Simulated Annealing garanteaz o convergen n timpul rulrii unui numr destul de mare
de iteraii.

10

Bibliografie

http://web.info.uvt.ro/~dzaharie/cne2013/curs/cne2013_slides6.pdf;

http://en.wikipedia.org/wiki/Simulated_annealing;

http://webcache.googleusercontent.com/search?q=cache:d8DDMkKdbT0J:www.ecs.uma
ss.edu/ece/labs/vlsicad/ece665/slides/SimulatedAnnealing.ppt+&cd=4&hl=en&ct=clnk&
gl=ro"gl=ro;

http://ai-php.com/searching/solving-8-puzzle-problem-using-simulated-annealing-search/

http://www.google.ro/url?sa=t&rct=j&q=&esrc=s&source=web&cd=8&ved=0CFMQFj
AH&url=http%3A%2F%2Fwww.cs.nott.ac.uk%2F~gxk%2Faim%2Fnotes%2Fsimulated
annealing.doc&ei=xG62VJqDGYnrUvqcg_gG&usg=AFQjCNEe__7whMG2xeQZVWV
EYI13E_j5Lg&sig2=3rqdzgIwVejajxJoMAjMhA&bvm=bv.83640239,d.d24;

11