# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

import numpy as np
import random


def GrayСode(BinLen=32, NDimension=1):
    """
    BinLen: Length of a bit line / Длина битовой строки
    NDimension: The dimension of the space / Размерность пространтсва 
    """
    return np.random.randint(2, size=[NDimension,BinLen])


def GrayToBinar(GrayString):
    """
    BitString: string to convert into binar code
    
    The rule of conversion from gray code to positional code: each digit in a positional
    the code is the sum modulo two of this and all the high bits in the gray code
    
    Правило перевода из кода Грея в позиционный код: каждый разряд в позиционном
    коде равен сумме по модулю два этого и всех старших разрядов в коде Грея
    """
    binar = []
    for number in GrayString:
        binar.append([sum(number[:i]) % 2 for i in range(len(number),0,-1)][::-1])
    return binar


def BinaryToInt(BinaryString):
    """
    BinaryString: string to convert into integer
    """
    integer = []
    for number in BinaryString:
        integer.append(sum([int(x) * 2 ** y for x, y in zip(list(number), range(len(number) - 1, -1, -1))]))
    return integer



def Decode(limits,integers,bitLen):
    """
    limits: list of limit like [[a1,b1],[a2,b2]]
    integers: number of interval
    bitLen: length of origin binary string
    """
    numbers = []
    for limit,integer in zip(limits,integers):
        k = 2**bitLen - 1
        h = (limit[1] - limit[0])/(k - 1)
        if integer == 0:
            numbers.append(limit[0])
        elif integer == k:
            numbers.append(limit[1])
        else:
            numbers.append(((limit[0] + (integer - 1)*h + (limit[0]+integer*h)))/2)
    return numbers


Decode([[-1,6],[-1,6]],[2,9],bitLen=4)


# Write decode pipeline
def DecodePipeLine(GrayString,limits):
    return Decode(limits,BinaryToInt(GrayToBinar(GrayString)),len(GrayString[0])) 


DecodePipeLine([[0,0,1,1],[1,1,0,1]],[[-1,6],[-1,6]])


def SinglePointCrossing(parent_one,parent_two):
    """
    По хорошему нужен более качественный генератор случайных чисел
    """
    children = []
    for ParentOneGen, ParentTwoGen in zip(parent_one,parent_two):
        point = np.random.randint(min(len(ParentOneGen),len(ParentTwoGen)) - 1)
        children.append(np.hstack([ParentOneGen[:point],ParentTwoGen[point:]]))
    return children


def UniformCrossing(parent_one,parent_two,probability = 0.5):
    children = []
    
    
    for i,ParentOneGen, ParentTwoGen in zip(range(min(len(parent_one),len(parent_two))),parent_one,parent_two):
        children.append([])
        for j in range(min(len(ParentOneGen),len(ParentTwoGen))):
            if np.random.rand() > probability:
                children[i].append(ParentOneGen[j])
            else:
                children[i].append(ParentTwoGen[j])
            
    return children

UniformCrossing([[0,0,0,0],[0,0,0,0]],[[1,1,1,1],[1,1,1,1]])

SinglePointCrossing([[0,0,0,0],[0,0,0,0]],[[1,1,1,1],[1,1,1,1]])


def Mutation(individual,probability = 0.5):
    """
    вероятность поменять ген
    """
    mutant = individual.copy()
    for i in range(len(individual)):
        for j in range(len(individual[i])):
            if np.random.rand() > probability:
                mutant[i][j] = (mutant[i][j] + 1) % 2
    return mutant


Mutation([[0,0,0,0],[0,0,0,0]])


def f(x):
    """
    Попробуем написать вот так
    """
    return -(x[0]**2) + -(x[1]**2)



def MyFunc(x):
    return f(DecodePipeLine(x,[[-5,5],[-5,5]]))


def InitFunction(BinLen,NDimension,IndNum):
    return [GrayСode(BinLen,NDimension) for i in range(IndNum)]


class GeneticAlgorithm:
    def __init__(self,BinLen,NDimension,IndNum,MutationNum,TopNum,ChildrenNum,Steps,InitFunction,AdaptabilityFunction,MutationFunction,CrossingFunction):
        self.BinLen = BinLen
        self.NDimension = NDimension
        self.IndNum = IndNum
        self.ChildrenNum = ChildrenNum
        self.MutationNum = MutationNum
        self.TopNum = TopNum
        self.Steps = Steps
        self.InitFunction = InitFunction
        self.AdaptabilityFunction = AdaptabilityFunction 
        self.MutationFunction = MutationFunction
        self.CrossingFunction = CrossingFunction
    
    def run(self):
        self.population = self.InitFunction(self.BinLen,self.NDimension,self.IndNum)
        for i in range(self.Steps):
            self.population = sorted(self.population,key=self.AdaptabilityFunction,reverse=True)
            children = []
            for j in range(self.ChildrenNum):
                children.append(self.CrossingFunction(
                    random.sample(self.population[:self.TopNum], 1)[0],
                    random.sample(self.population[:self.TopNum], 1)[0]))
            for j in range(self.MutationNum):
                children.append(self.MutationFunction(random.sample(self.population, 1)[0]))
            self.population = np.vstack([self.population,children])
            self.population = sorted(self.population,key=self.AdaptabilityFunction,reverse=True)[:self.IndNum]
        return(self.population)


testGen = GeneticAlgorithm(
    BinLen=32, IndNum=20,NDimension = 2,MutationNum=10,TopNum=10,ChildrenNum=10,Steps=1000, InitFunction = InitFunction,
    AdaptabilityFunction=MyFunc,MutationFunction=Mutation, CrossingFunction=SinglePointCrossing)

answers = testGen.run()

for i in answers:
    print(DecodePipeLine(i,[[-5,5],[-5,5]]))


# +
def f(x):
    return -(x[0]**2) - (x[1]**2) - (x[2]**2) 

def MyFunc(x):
    return f(DecodePipeLine(x,[[-5,5],[-2,2],[-3,1]]))


# -

testGen = GeneticAlgorithm(
    BinLen=32, IndNum=20,NDimension = 3,MutationNum=10,TopNum=10,ChildrenNum=10,Steps=1000, InitFunction = InitFunction,
    AdaptabilityFunction=MyFunc,MutationFunction=Mutation, CrossingFunction=SinglePointCrossing)

answers = testGen.run()

for i in answers:
    print(DecodePipeLine(i,[[-5,5],[-2,2],[-3,1]]))



StarcoderdataJupyterScriptsDedupFiltered