# ---
# jupyter:
#   jupytext:
#     cell_markers: '"""'
#     formats: ipynb,py:percent
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.16.1
#   kernelspec:
#     display_name: Python 3 (ipykernel)
#     language: python
#     name: python3
# ---

# %% [markdown] jp-MarkdownHeadingCollapsed=true
"""
# Evolutionary Computation

**Master in Artificial Intelligence, UVigo, UdC, USC**

Academic year 2025/26
"""

# %% [markdown]
"""
# Working environment

We work with a similar python environment as you are already used to.
"""

# %% [markdown]
"""
### Install the software

Please make sure you have installed the necessary python environment as described in the instruction sheet.

### Run the example:

For the Guofei-package run the demo-programs
in the examples directory `demo_ga.py`

Let us analize the example here:
"""

# %% [markdown]
"""
First make sure you can import all modules.
"""

# %%
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sko.GA import GA

# %% [markdown]
"""
Define the objective function (real values continuous function):
"""


# %%
def schaffer(p : np.ndarray) -> np.ndarray:
    '''
    This function has plenty of local minimum, with strong shocks
    global minimum at (0,0) with value 0
    https://en.wikipedia.org/wiki/Test_functions_for_optimization
    '''
    x1, x2 = p
    part1 = np.square(x1) - np.square(x2)
    part2 = np.square(x1) + np.square(x2)
    return 0.5 + (np.square(np.sin(part1)) - 0.5) / np.square(1 + 0.001 * part2)


# %% [markdown]
"""
Now, run the genetic algorithm with different parameters and see what happens.
"""

# %%
ga = GA(func=schaffer, n_dim=2, size_pop=50, 
        max_iter=800, prob_mut=0.001, lb=[-1, -1], ub=[1, 1],
        precision=1e-7)
best_x, best_y = ga.run()
print('best_x:', best_x, '\nbest_y:', best_y)

# %% [markdown]
"""
You can plot the results of the genetic algorithm...
What do the plots show you?
"""

# %%
Y_history = pd.DataFrame(ga.all_history_Y)
fig, ax = plt.subplots(2, 1)
ax[0].plot(Y_history.index, Y_history.values, '.', color='red')
Y_history.min(axis=1).cummin().plot(kind='line')
plt.show()

# %% [markdown]
"""
Let us define another function from the CEC 2017 benchmark: the Griewank function.
"""

# %%

def griewank(x: np.ndarray) -> np.ndarray:
    nx = x.shape[0]
    factor = 1/4000
    d = np.sqrt(np.expand_dims(np.arange(start=1, stop=nx + 1), 0))
    cs = np.cos(x / d)
    sm = np.sum(factor*x*x)
    pd = np.prod(np.cos(x / d))
    return sm - pd + 1

# %% [markdown]
"""
Your turn: run the same experiment with the Griewank function.
Where is the minium?
"""


# %%

# %% [markdown]
"""
Your turn: You can plot the results of the genetic algorithm...
"""

# %%

# %% [markdown]
"""
Your turn: Run experiments with a not to small set of different numbers
for iterations (max_iter) and population size (size_pop) and comment the
results regarding the best points found.
"""

# %%

