You are on page 1of 7

31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

Μετα-ευριστικοί Αλγόριθμοι για Πρόβλημα


Ελαχιστοποίησης Μαθηματικών Συναρτήσεων ¶
In [1]:

import numpy as np
import matplotlib.pyplot as plt
#from mpl_toolkits.mplot3d import Axes3D
from tqdm import tqdm

Στο 7ο μάθημα είδαμε τον Γενετικό Αλγόριθμο, που είναι (με διαφορά) ο πιο δημοφιλής μετα-ευριστικός
αλγόριθμος βελτιστοποίησης. Στα μαθήματα 8 και 9 θα δούμε τους τέσσερις αμέσως δημοφιλέστερους μετα-
ευριστικούς αλγόριθμους, από δύο σε κάθε μάθημα.

Σήμερα θα δούμε δύο αλγόριθμους για αριθμητική βελτιστοποίηση, και συγκεκριμένα, για ελαχιστοποίηση της
συνάρτησης rastrigin.

Η συνάρτηση ορίζεται ως:


𝑛
𝑓(𝑥) = 10𝑛 + ∑[𝑥2𝑖 − 10𝑐𝑜𝑠(2π𝑥𝑖 )]
𝑖=1

http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 1/7
31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

Αυτή η συνάρτηση έχει σαν ελάχιστη πιθανή τιμή το 0, δηλαδή 𝑓𝑚𝑖𝑛 (𝑥) = 0, που προκύπτει για
𝑥 = [0,0,...,0].

Επίσης έχει τον περιορισμό


−5.12 ≤ 𝑥 ≤ 5.12
δηλαδή το x παίρνει τιμές από -5.12 έως 5.12

Ας την ορίσουμε

In [2]:

def rastrigin(x):
f = 0
for i in np.arange(x.shape[0]):
f += x[i]*x[i]-(10*np.cos(2*np.pi*x[i]))+10
return f

Simulated Annealing
Ο αλγόριθμος Simulated Annealing ξεκινάει από κάποιο αρχικό, τυχαίο σημείο, και σε κάθε επανάληψη
αποφασίζει, με κάποια τυχαιότητα, αν θα μεταβεί σε κάποιο άλλο σημείο. Οι πιθανότητα για το αν θα μεταβεί σε
άλλο σημείο ή όχι εξαρτώνται από το αν το άλλο σημείο αποτελεί καλύτερη λύση. Όσο προχωρούν οι
επαναλήψεις, οι πιθανότητες μειώνονται, οδηγώντας σε ένα ενεργειακά σταθερό σύστημα και εξομοιώνοντας
την κίνηση των ατόμων σε μεγάλες θερμοκρασίες, που μειώνεται όσο οι θερμοκρασία πέφτει.

Αυτή η φυσική διεργασία ονομάζεται annealing. Αυτό εξομοιώνεται με μια παράμετρο Τ που συμβολίζει την
"θερμοκρασία" του συστήματος. Όσο προχωρούν οι επαναλήψεις τόσο μειώνεται η θερμοκρασία, και τόσο
μικραίνουν οι πιθανότητες να αλλάξουμε την λύση.

1. Τυχαία αρχικοποίηση μιας λύσης.


2. Δημιουργία παραλλαγής, υποψήφιας να αντικαταστήσει την λύση.
3. Υπολογισμός των πιθανοτήτων να ανταλλάξουμε λύση, με βάση το 1) ποια λύση έχει καλύτερα
αποτελέσματα στην συνάρτηση προς βελτιστοποίηση, και 2) την παράμετρο θερμοκρασίας.
4. Με βάση τις πιθανότητες επιλέγουμε αν θα αλλάξουμε την λύση.
5. Μείωση του συντελεστή θερμοκρασίας.
6. Επιστροφή στο βήμα 2. Επανάληψη για προκαθορισμένο αριθό επαναλήψεων.
7. Επιστροφή τρέχουσας λύσης.

Παρακάτω γράφουμε τον αλγόριθμο σε μορφή συνάρτησης και τον τρέχουμε. Η συνάρτηση παίρνει τα εξής
ορίσματα:

func: συνάρτηση προς βελτιστοποίησης


dim: πόσες διαστάσεις θέλουμε να έχει το πρόβλημα, δηλαδή πόσα στοιχεία θα έχει το διάνυσμα x με την
λύση
minx: ο κάτω περιορισμός του x
maxx: ο πάνω περιορισμός του x
T: αρχική θερμοκρασία
a: συντελεστής από 0 έως 1 που καθορίζει πόσο γρήγορα ή αργά θα μειώνεται η θερμοκρασία σε κάθε
επανάληψη. Όσο μεγαλύτερος, τόσο αργότερα.
n_iter: αριθμός επαναλήψεων

http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 2/7
31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

In [228]:

def sa(func,dim,minx,maxx,T=100,a=0.95,n_iter=100):

from tqdm import tqdm


x = np.random.uniform(minx,maxx,dim) #initial solution
fx = func(x)
monitor = []

for i in tqdm(range(n_iter)):

step = np.random.uniform(-1,1,size=2)
candidate = x + step

#make sure constrains aren't violated


for k in range(dim):
if candidate[k] < minx: candidate[k] = x[k] - 2*step[k]
if candidate[k] > maxx: candidate[k] = x[k] - 2*step[k]

fc = func(candidate)
df = fx - fc
p = np.exp(df/T)

if np.random.uniform(0,1) <= p:
x = candidate.copy()
fx = fc.copy()

T *= a
monitor.append(fx)
return x, monitor

In [226]:

x, monitor = sa(func = rastrigin,


dim = 2,
minx = -5.12,
maxx = 5.12,
T = 100,
a = 0.95,
n_iter = 500)

x, monitor[-1]

100%|██████████| 500/500 [00:00<00:00, 4622.73it/s]

Out[226]:

(array([ 0.01062067, -0.04865889]), 0.48847141964103)

http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 3/7
31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

In [227]:

plt.plot(np.arange(len(monitor)),monitor);

In [163]:

x = np.random.uniform(-5.12,5.21,2)
c = np.random.uniform(-5.12,5.21,2)
fx, fc = func(x), func(c)
print('fx:',fx)
print('fc:',fc)
print('probability to switch:',np.round(np.exp(fx-fc),5))

fx: 58.64128401521241
fc: 56.64608951387444
probability to switch: 7.35363

Particle Swarm Optimization


Σε αυτόν τον αλγόριθμο, ένα σμήνος σωματιδίων διαχέεται τυχαία στο χώρο των πιθανών λύσεων.
Υπολογίζεται ποιό από αυτά κατέχει την καλύτερη λύση. Σε κάθε επανάληψη:

Τα σωματίδια κάνουν ένα βήμα προς μια κατεύθυνση που υπολογίζει ο αλγόριθμος. Η κατεύθυνση αυτή
εξαρτάται: 1) από την προηγούμενη κατεύθυνση του σωματιδίου, 2) από την καλύτερη λύση που βρέθηκε
ποτέ από όλα τα σωματίδια, και 3) από την καλύτερη λύση που έχει βρει το συγκεκριμένο σωματίδιο.
Υπολογίζεται η καλύτερη λύση από όλα τα σωματίδια και αποθηκεύεται.

Πριν δούμε τον αλγόριθμο πιο αναλυτικά, ας ορίσουμε μια κλάση Particle, όπου κάθε σωματίδιο θα έχει τα εξής
χαρακτηριστικά:

position: Η θέση του σωματιδίου στον χώρο


velocity: Η κατεύθυνση προς την οπία θα πάει όταν κάνει το επόμενο βήμα
fitness: Η τιμή της f(x) για το x στο οποίο βρίσκεται τώρα
best_position: Η καλύτερη θέση που έχει βρει το συγκεκριμένο σωματίδιο ως τώρα
best_fitness: Η τιμή της f(x) για καλύτερη θέση που έχει βρει το συγκεκριμένο σωματίδιο ως τώρα

http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 4/7
31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

In [254]:

class Particle:
def __init__(self,mini,maxi,n):
self.position = np.random.uniform(mini,maxi,n)
self.velocity = np.random.rand(n)
self.fitness = rastrigin(self.position)

self.best_position = np.copy(self.position)
self.best_fitness = self.fitness

Όπως είπαμε, η κατεύθυνση που θα πάρει το σωματίδιο καθορίζεται από τρεις παράγοντες. Η βαρύτητα που θα
έχει κάθε παράγοντας επιλέγεται από εμάς με τις εξής παραμέτρους:

w1: Αδράνεια: όσο μεγαλύτερη, τόσο τείνει το σωματίδιο να πάει προς την κατεύθυνση που ήδη έχει
w2: Αυτονομία: όσο μεγαλύτερη, τόσο τείνει το σωματίδιο να πάει προς την καλύτερη λύση που έχει βρει το
ίδιο
w3: Κοινωνικότητα: όσο μεγαλύτερη, τόσο τείνει το σωματίδιο να πάει προς την καλύτερη ολική λύση από
όλα τα σωματίδια

Ο αλγόριθμος έχει ως εξής:

1. Αρχικοποίηση σωματιδίων, τριών παραμέτρων W, λαλύτερες θέσεις είναι οι τωρινές τυχαίες, η καλύτερη
ολική λύση είναι τυχαία, η καλύτερη ολική fitness είναι μια πολύ υψηλή τιμή. (Επειδή έχουμε
ελαχιστοποίηση συνάρτησης, θα ελαχιστοποιήσουμε και την fitness)
2. Ξεκινάμε τις επαναλήψεις, αριθμός επαναλήψεων = n_iter.
3. Ανανέωσε την θέση των σωματιδίων.
4. Συγκρινε τις θέσεις τους με τις καλύτερές τους, ανανέωσε τις καταχωρήσεις των καλύτερων αν χρειαστεί.
5. Για όποιες καταχωρήσεις ανανεώθηκαν, σύγκρινε με ολική καλύτερη, ανανέωσε καταχώρηση ολικής
καλύτερης αν χρειαστεί.
6. Επιστροφή στο βήμα 3.

Όταν οι επαναλήψεις τελειώσουν, η λύση που βρέθηκε είναι αποθηκευμένη στην μεταβλητή της καλύτερης
ολικής λύσης.

http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 5/7
31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

In [255]:

# initializations
mini, maxi = -5.12,5.12
n = 3

best_g_position = np.zeros((n))#np.random.uniform(mini,maxi,n)
best_g_fitness = sys.float_info.max#rastrigin(best_g_position)

swarm_size = 100
swarm = [ Particle(mini,maxi,n) for i in range(swarm_size) ]

w1 = 0.1
w2 = 1.494
w3 = 1

for particle in swarm:


if particle.fitness < best_g_fitness:
best_g_fitness = particle.fitness.copy()
best_g_position = particle.position.copy()

monitor_fitness = []

#----------------------------------

n_iter = 500

for i in tqdm(range(n_iter)):

for i in range(swarm_size):

for k in range(n):

#update position, velocity, and fitness of particles


swarm[i].velocity[k] = w1*swarm[i].velocity[k] + \
w2*np.random.randn()*(swarm[i].best_position[k]-swarm[i].positi
w3*np.random.randn()*(best_g_position[k]-swarm[i].position[k])

swarm[i].position += swarm[i].velocity

#ensure constraints aren't violated


for k in range(n):
if swarm[i].position[k] < mini:
swarm[i].position[k] = mini
swarm[i].velocity[k] = 0
elif swarm[i].position[k] > maxi:
swarm[i].position[k] = maxi
swarm[i].velocity[k] = 0

swarm[i].fitness = rastrigin(swarm[i].position)

#if position better than self best


#update self-best and consider updating global best
if swarm[i].fitness < swarm[i].best_fitness:
swarm[i].best_fitness = swarm[i].fitness.copy()
swarm[i].best_position = swarm[i].position.copy()
if swarm[i].best_fitness < best_g_fitness:
best_g_fitness = swarm[i].best_fitness.copy()
best_g_position = swarm[i].best_position.copy()
http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 6/7
31/5/2022 9_Metaheuristics_Numerical - Jupyter Notebook

monitor_fitness.append(best_g_fitness)

best_g_fitness,np.round(best_g_position,6)

100%|██████████| 500/500 [00:09<00:00, 53.79it/s]

Out[255]:

(0.03340983000845732, array([ 0.004593, -0.007167, -0.009797]))

http://localhost:8889/notebooks/python%20projects/optimization/9_Metaheuristics_Numerical.ipynb 7/7

You might also like