#!/usr/bin/env python

## Ilustrace 1 - maximalizace dane funkce
## xoujez03

import numpy as np
from matplotlib import pyplot as plt

A = np.random.uniform(low=0, high=9, size=(10,10))

def gaDemoEval(population):
    x  = population
    sec_val = x + 10*np.sin(5*x)+7*np.cos(4*x)

    return (x, sec_val)

def aritmetics_crossover(population):
    newPopulation = []
    for i in range(4):
        t = np.random.uniform(0, 1, size=1)
        #t = np.random.randint(0, 1)
        parent1 = population[np.random.randint(len(population))]
        parent2 = population[np.random.randint(len(population))]
        offspring1 = t*parent1 + (1 - t)*parent2
        parent1 = population[np.random.randint(len(population))]
        parent2 = population[np.random.randint(len(population))]
        offspring2 = (1 - t)*parent1 + t*parent2
        newPopulation.append(offspring1)
        newPopulation.append(offspring2)
    return np.asarray(newPopulation)

def selection_elitism(population):
    elite = []
    pop, solution = np.array(gaDemoEval(population))
    sort_x = solution.argsort()
    def sort(solution, sort_x):
        sort_y = []
        for index, sol in enumerate(solution):
            sort_solution_x = sol[sort_x[index]]
            sort_y.append(sort_solution_x[-1])
        return sort_y
    sort_xy = np.asarray(sort(solution, sort_x))
    final_sort = sort_xy.argsort()
    elite.append(population[final_sort[8]])
    elite.append(population[final_sort[9]])
    return elite

def mutation(population):
    D = population
    A = np.random.random(size=(len(D), 10)) < 0.001
    Z = np.random.random(size=(len(D), 10))
    D = (np.logical_not(A) * D) + (A * Z)
    return D

for repeate in range(1000):
    C = aritmetics_crossover(A)
    X = mutation(C)
    population = np.concatenate((selection_elitism(A), X), axis=0)
    A = population
    vysledek = np.asarray(gaDemoEval(A))
    print("Vysledek %s generace, hodnota max f(%s) = %s" % (repeate,  A.max(), vysledek.max()))

plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = ['Cambria Math'] + plt.rcParams['font.serif']
sx = plt.subplot(111)

x =  A #array(arange(0,9, .10))
y = x + 10*np.sin(5*x)+7*np.cos(4*x)
#plt.plot(x,y, 'b-', markevery=0.1)
sx.plot(x,y, 'ro')
x = np.array(np.arange(0,9, .10))
y = x + 10*np.sin(5*x)+7*np.cos(4*x)
sx.plot(x,y, 'b-', markevery=0.1)
plt.xlabel('$x$')
plt.ylabel('$y = f(x)$')
plt.show(sx)

