# Callback¶

A Callback class can be used to receive a notification of the algorithm object each generation. This can be useful to keep track of metrics, do additional calculations or even modify the algorithm object during the run. The latter is only recommend for experienced users.

For instance, to keep track of the best solution each generation:

[1]:

import matplotlib.pyplot as plt
import numpy as np

from pymoo.algorithms.so_genetic_algorithm import GA
from pymoo.factory import get_problem
from pymoo.model.callback import Callback
from pymoo.optimize import minimize

class MyCallback(Callback):

def __init__(self) -> None:
super().__init__()
self.data["best"] = []

def notify(self, algorithm):
self.data["best"].append(algorithm.pop.get("F").min())

problem = get_problem("sphere")

algorithm = GA(pop_size=100)

res = minimize(problem,
algorithm,
('n_gen', 20),
seed=1,
callback=MyCallback(),
save_history=True,
verbose=True)

val = res.algorithm.callback.data["best"]
plt.plot(np.arange(len(val)), val)
plt.show()


=============================================
n_gen |  n_eval |     fopt     |     favg
=============================================
1 |     100 |  0.387099336 |  0.831497479
2 |     200 |  0.302189349 |  0.578035582
3 |     300 |  0.267733594 |  0.443801185
4 |     400 |  0.188215259 |  0.347200983
5 |     500 |  0.083479177 |  0.272644726
6 |     600 |  0.083479177 |  0.212567874
7 |     700 |  0.072492126 |  0.173574163
8 |     800 |  0.051256476 |  0.140740462
9 |     900 |  0.041778020 |  0.110370322
10 |    1000 |  0.041778020 |  0.089125798
11 |    1100 |  0.031644566 |  0.071339910
12 |    1200 |  0.030055810 |  0.057941249
13 |    1300 |  0.021855327 |  0.047786695
14 |    1400 |  0.017620999 |  0.040676540
15 |    1500 |  0.014756395 |  0.034902705
16 |    1600 |  0.014756395 |  0.029778240
17 |    1700 |  0.012976416 |  0.026185115
18 |    1800 |  0.008637920 |  0.022664820
19 |    1900 |  0.006399439 |  0.019648350
20 |    2000 |  0.006399439 |  0.016725603


If the analysis of the run should be done during post-processing the option save_history can be used as well. If a callback is used the history does not need to be saved. By using the history object the same as above can be achieved by using the stored information during the run:

[2]:

val = [e.pop.get("F").min() for e in res.history]
plt.plot(np.arange(len(val)), val)
plt.show()


If the save_history is true a deep copy of the algorithm object takes place each generation. Please note that this can be quite expensive and might not be desired for all runs. However, it provides great post-processing options because all data can be accessed respectively.