import numpy as np
import matplotlib.pyplot as plt

def system_equations(x, y):
    eq1 = x**2 + y**2 - 25
    eq2 = x*y - 9
    return eq1, eq2

def genetic_algorithm(population_size, generations, target_solution):
    population = np.random.uniform(low=-5, high=5, size=(population_size, 2))
    path = [population.copy()]

    for generation in range(generations):
        fitness = np.sum(np.abs(np.array(system_equations(population[:, 0], population[:, 1]))), axis=0)

        best_solution = population[np.argmin(fitness)]
        if np.all(np.isclose(best_solution, target_solution, atol=1e-2)):
            break  # Ako smo blizu cilja, prekinite evoluciju

        selected_indices = np.argsort(fitness)[:population_size//2]
        parents = population[selected_indices]
        crossover_point = parents.shape[0] // 2
        children = np.vstack((parents[:crossover_point], parents[crossover_point:][::-1]))
        mutation_rate = 0.1
        mutation = np.random.uniform(low=-0.1, high=0.1, size=children.shape)
        children += mutation

        population[selected_indices] = children
        path.append(population.copy())

    return population[np.argmin(fitness)], path

# Postavljanje analitičkih rešenja
analytic_solution1, analytic_solution2 = (1.96, 4.6), (4.62, 1.95)

# Pokretanje genetskog algoritma
best_solution_genetic, path = genetic_algorithm(population_size=50, generations=100, target_solution=analytic_solution1)

# Vizualizacija rezultata
x_vals = np.linspace(-5, 5, 100)
y_vals = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x_vals, y_vals)
Z1, Z2 = system_equations(X, Y)

plt.contour(X, Y, Z1, levels=[0], colors='r', label='Equation 1')
plt.contour(X, Y, Z2, levels=[0], colors='b', label='Equation 2')

for i, pop in enumerate(path):
    if i == 0:
        plt.scatter(pop[:, 0], pop[:, 1], color='grey', alpha=0.1, label='Genetic Algorithm Path')
    else:
        plt.scatter(pop[:, 0], pop[:, 1], color='grey', alpha=0.1)

plt.scatter(*best_solution_genetic, color='green', marker='*', label='Genetic Algorithm')
plt.scatter(*analytic_solution1, color='orange', marker='o', label='Analytical solution 1')

plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.title('Visualization of genetic algorithm solutions and analytical solutions 1')
plt.show()
