Tutorial 3: solving your first optimization problem with ABC

In this tutorial, you will learn how to use the Artificial Bee Colony (ABC) algorithm to optimize a complex objective function. You will get through the process of setting up the ArtificialBeeColony class and the configuration of its optimize method. As an example, we will consider the Eggholder function, a 2D function defined as follows:

\[f((x_1,x_2)) = -(x_2 + 47) \sin\left(\sqrt{\left|x_2 + \frac{x_1}{2} + 47\right|}\right) - x_1 \sin\left(\sqrt{|x_1 - (x_2 + 47)|}\right)\]

The first step is to define a BenchmarkFunction object that represents the Eggholder function. We can either define it from scratch or we can import it directly from the beeoptimal.benchmarks module.

[2]:
from beeoptimal.benchmarks import Eggholder

print(f"\nBenchmark:\n {Eggholder.name}")
print(f"\nDefault Bounds:\n {Eggholder.bounds}")
print(f"\nOptimal Solution:\n {Eggholder.optimal_solution}")
print(f"\nOptimal Value:\n {Eggholder.optimal_value}")

Benchmark:
 Eggholder

Default Bounds:
 [[-512  512]
 [-512  512]]

Optimal Solution:
 [512.     404.2319]

Optimal Value:
 -959.6406627106155

The next step is to import and instanciate an ArtificialBeeColony object. Its attributes are the following:

  • colony_size: the number of bees in the colony (at least 10 in order to ensure compatibility with all the implemented mutation strategies)

  • function: the function to optimize

  • bounds: the search space bounds

  • n_employed_bees: the number of employed bees

  • max_scouts: the maximum number of scout bees per iteration

The most simple way to initialize it is the following:

[3]:
from beeoptimal import ArtificialBeeColony

ABC = ArtificialBeeColony(
    colony_size = 100,
    function    = Eggholder.fun,
    bounds      = Eggholder.bounds,
    )

Note

If the attributes n_employed_bees and max_scouts are not provided, they will be both set to colony_size//2. In case you want to use a different number of employed bees or max scouts, just set them manually.

When specifying n_employed_bees and max_scouts, make sure to respect the following constraints:

  • 5 \(<\) n_employed_bees \(\leq\) colony_size

  • 0 \(<\) max_scouts \(\leq\) n_employed_bees

where the condition n_employed_bees > 5 is needed to ensure compatibility with all the implemented mutation strategies.

We are finally ready to call the optimize method. In this example, we will set up a standard configuration for the ABC algorithm

[4]:
ABC.optimize(
    max_iters        = 1000,
    limit            = 'default',
    selection        = 'RouletteWheel',
    mutation         = 'StandardABC',
    initialization   = 'random',
    stagnation_tol   = 1e-6,
    random_seed      = 1234,
    verbose          = True
    )
Running Optimization: 100%|██████████|[00:05<00:00]
[5]:
print('*'*50)
print(f"Optimal Solution:")
print(f"\tExpected : {Eggholder.optimal_solution}")
print(f"\tFound    : {ABC.optimal_bee.position}")
print(f"Optimal Value:")
print(f"\tExpected : {Eggholder.optimal_value}")
print(f"\tFound    : {ABC.optimal_bee.value}")
print('*'*50)
**************************************************
Optimal Solution:
        Expected : [512.     404.2319]
        Found    : [512.         404.23180504]
Optimal Value:
        Expected : -959.6406627106155
        Found    : -959.640662720851
**************************************************

If you want to experiment with another configuration, you can just reset the ArtificialBeeColony object and call the optimize method again, without the need of instantiating a new object.

[6]:
ABC.reset()

Another possible configuration:

[7]:
ABC.optimize(
    max_iters        = 1000,
    limit            = 'default',
    selection        = 'Tournament',
    tournament_size  = 20,
    mutation         = 'ABC/best/1',
    initialization   = 'cahotic',
    sf               = 1.0,
    self_adaptive_sf = False,
    stagnation_tol   = 1e-6,
    random_seed      = 1234,
    verbose          = True
    )
Running Optimization:  86%|████████▌ |[00:05<00:00]
Early termination: Optimization stagnated at iteration 861 / 1000

[8]:
print('*'*50)
print(f"Optimal Solution:")
print(f"\tExpected : {Eggholder.optimal_solution}")
print(f"\tFound    : {ABC.optimal_bee.position}")
print(f"Optimal Value:")
print(f"\tExpected : {Eggholder.optimal_value}")
print(f"\tFound    : {ABC.optimal_bee.value}")
print('*'*50)
**************************************************
Optimal Solution:
        Expected : [512.     404.2319]
        Found    : [512.         404.23180513]
Optimal Value:
        Expected : -959.6406627106155
        Found    : -959.640662720851
**************************************************