In [48]:
import os
import numpy
import math
import matplotlib.pyplot as plt
import random

os.chdir('/home/andrey/Jupyter Notebooks/Andrey/Genom')
print(os.getcwd())
from GenomClass import Genom


/home/andrey/Jupyter Notebooks/Andrey/Genom

In [44]:
gaussianParams = [[-1, 0.2], [1, 2], [3, 3]]
a = -10
b = 10
numPoints = 2000

random.seed()

In [5]:
def gaussian(X, x0, sigma):
    res = ((1 / (math.sqrt(2 * math.pi) * sigma)) * numpy.exp(-((X - x0) ** 2) / (2 * (sigma) ** 2)))
    return res

In [6]:
def gaussianComb(X: object, params: object) -> object:
    res = numpy.zeros(X.size)
    for par in params:
        x0 = par[0]
        sigma = par[1]
        res += gaussian(X, x0, sigma)
    return res

In [7]:
def calcCostFunction(X, y, params):
    times = len(params)
    m = X.size
    resX = gaussianComb(X, params)
    costVector = (resX - y) ** 2
    J = (1 / (2 * m)) * numpy.sum(costVector)
    return J

In [45]:
X = numpy.linspace(a, b, numPoints)
y = gaussianComb(X, gaussianParams)
plt.plot(X, y)
plt.show()



In [43]:
numberOfIndiv = 70
Population = []
for i in range(numberOfIndiv):
    gene = Genom(3)
    gene.calcFitnessFunction(X, y)
    Population.append(gene)

In [47]:
def findNearest(popul, num):
    indiv = popul[num]
    population = []
    population.extend(popul)
    population.pop(num)
    l = len(population)
    indFF = indiv.getFitnessFunction()
    popFF = numpy.zeros(l)

    for i in range(l - 1):
        popFF[i] = population[i].getFitnessFunction()
    distances = numpy.abs(popFF - indFF)

    minimum = distances.min()
    for i in range(distances.size):
        if distances[i] == minimum:
            return population[i]  # Переписать, говнокод

In [41]:
def selectParentsByInbriding(population):
    N = len(population) - 1
    parents = []

    for i in range(numberOfIndiv):
        fatherNum = random.randint(0, N)
        father = population[fatherNum]
        mother = findNearest(population, fatherNum)
        pair = [father, mother]
        parents.append(pair)

    return parents

In [40]:
def newSelectParentsByInbriding(population):
    N = len(population) - 1
    parents = []

    for i in range(numberOfIndiv // 2):
        fatherNum = random.randint(0, N)
        father = population[fatherNum]
        mother = findNearest(population, fatherNum)
        pair = [father, mother]
        parents.append(pair)

    return parents

In [39]:
def selectParents(population):
    N = len(population) - 1
    parents = []

    for i in range(numberOfIndiv):
        fatherNum = random.randint(0, N)
        motherNum = random.randint(0, N)
        father = population[fatherNum]
        mother = population[motherNum]
        pair = [father, mother]
        parents.append(pair)

    return parents

In [35]:
def newSelectParents(population):
    N = len(population) - 1
    parents = []

    for i in range(numberOfIndiv // 2):
        fatherNum = random.randint(0, N)
        motherNum = random.randint(0, N)
        father = population[fatherNum]
        mother = population[motherNum]
        pair = [father, mother]
        parents.append(pair)

    return parents

In [38]:
def crossingover(parents):
    parentsList = list(map((lambda pair: list(map(lambda p: p.getParams(), pair))), parents)) #Составление списка генов родителей 
    numberOfGaussians = len(parentsList[0][0])
    children = []
    child = []

    for pair in parentsList:
        breakPoint = random.randint(1, (numberOfGaussians * 2) - 1) #Выбор точки разрыва хромосомы

        if ((breakPoint % 2) == 0):
            n = breakPoint // 2
            child1 = [pair[0][i] for i in range(n)]
            child2 = [pair[1][i] for i in range(n, numberOfGaussians)]
            child = child1
            child.extend(child2)
        else:
            n = (breakPoint - 1) // 2
            child1 = [pair[0][i] for i in range(n)]
            boundGaussian = [[pair[0][n][0], pair[1][n][1]]]
            child2 = [pair[1][i] for i in range(n + 1, numberOfGaussians)]
            child = child1
            child.extend(boundGaussian)
            child.extend(child2)

        mutation = random.random() #Мутация
        if (mutation >= 0.89):
            num = random.randint(0, (numberOfGaussians * 2) - 1)
            numOfGauss = num // 2
            numOfElement = num % 2
            child[numOfGauss][numOfElement] += random.uniform(-5, 5)

        childObject = Genom(numberOfGaussians)
        childObject.setParams(child)
        children.append(childObject)

    return children

In [32]:
def sortPop(population):
    l = len(population)
    sortList = [] #Временный list для сортировки вида [значение фитнесс функции, особь]

    for i in range(l):
        temp = [population[i].getFitnessFunction(), population[i]]
        sortList.append(temp)
    
    sortList.sort(key=lambda sL: sL[0])
    
    sortedPopulation = list(map(lambda p: p[1], sortList))  

    return sortedPopulation

In [30]:
def makeNewPopulation(population, tX, tY):
    for ind in population:
        ind.calcFitnessFunction(tX, tY) #Вычисление фитнесс функции для каждей особи

    sortedPopulation = sortPop(population) #Сортировка поппуляции по значению фитнесс функции
    newPopulation = [sortedPopulation[i] for i in range(numberOfIndiv)] 

    return newPopulation

In [29]:
def new_makeNewPopulation(population, children, tX, tY):
    newPopulation = []

    for ind in population:
        ind.calcFitnessFunction(tX, tY)

    for ind in children:
        ind.calcFitnessFunction(tX, tY)

    sortedPopulation = sortPop(population)
    newPopulation1 = [sortedPopulation[i] for i in range(numberOfIndiv // 2)]
    newPopulation2 = [children[i] for i in range(numberOfIndiv // 2)]
    newPopulation.extend(newPopulation1)
    newPopulation.extend(newPopulation2)

    return newPopulation

In [28]:
def geneticAlgorithm(pop, maxIters, tX, tY):
    population = []
    population.extend(pop)
    bestList = []

    for i in range(maxIters):
        parents = selectParents(population)
        childs = crossingover(parents)
        all = []
        all.extend(population)
        all.extend(childs)
        population = makeNewPopulation(all, tX, tY)
        bestList.append(population[0].getFitnessFunction())

    return [population[0].getParams(), bestList]

In [46]:
resList = geneticAlgorithm(Population, 2000, X, y)
params = resList[0]
bestList = resList[1]
yfit = gaussianComb(X, params)

print('Gaussian parametrs:')
print(params)

fig1 = plt.figure(figsize=(7, 7))
plt.title('Original and approximated function')
plt.plot(X, y, 'x', color='red')
plt.plot(X, yfit)
plt.show()

fig2 = plt.figure(figsize=(7, 7))
plt.title('Best fitness function')
plt.plot(bestList)
plt.show()

err = yfit - y

fig3 = plt.figure(figsize=(7, 7))
plt.title('Error')
plt.plot(X, err)
plt.show()

print('Mean error: ' + str(math.fabs(numpy.mean(err))))


Gaussian parametrs:
[[2.916075306332576, 3.106158050635747], [1.0862404693339123, 2.0079504561808377], [-0.9952669046008449, 0.19836959611614224]]
Mean error: 7.377860889762413e-05