function [populationFinal]= GeneticAlgorithm(Generation, population, population_size, idxTrain, idxval, XTrain, TTrain, XVal,TVal, numFeatures, classes, layers, options, NeuronLayer1, NeuronLayer2, NeuronLayer3, directory, threshold,numClasses, MinNeuron)

best = round(0.3* population_size,"TieBreaker","plusinf");
crossingOver = round(0.2*population_size,'TieBreaker','plusinf'); 
mutation = round(0.05*population_size,'TieBreaker','plusinf');
migration = population_size - (best + crossingOver + mutation);

bestRNA = cell(1, numel(best));
CrossingOver = cell(1, numel(crossingOver));
NewMutation  = cell(1, numel(mutation));
NewMigration = cell(1, numel(migration));

for v= 1: Generation
    fprintf('Generation %d\n ',v);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%Best RNA's from the last generation
    for i=1:best
        bestRNA{i} = population{i};
    end


    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%Crossing Over
    for i =1:crossingOver
        CrossingOver{i} = bestRNA{i};
    end
    
    NewCrossingOver= CrossingOver; 
    if mod(length(CrossingOver),2)== 0
        for k = 1:2:(length(CrossingOver)-1)
            RNA1 = CrossingOver{k}.Layer1; 
            RNA2 = CrossingOver{k+1}.Layer1;
        
            NewCrossingOver{k}.Layer1 = RNA2;
            NewCrossingOver{k+1}.Layer1 = RNA1;
        end
    elseif mod(length(CrossingOver), 2) == 1
        for k = 1:2:length(CrossingOver)-1
            RNA1 = CrossingOver {k}.Layer1; 
            RNA2= CrossingOver{k+1}.Layer1;

            NewCrossingOver{k}.Layer1 = RNA2;
            NewCrossingOver{k+1}.Layer1 = RNA1;

        end
            RNA1 = CrossingOver{1, 1}.Layer1;       
            NewCrossingOver{length(CrossingOver)}.Layer1 = RNA1;          
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%Mutation
    for i= 1:mutation
        RandomMutation = randi([1 best]);
        RandomNeuron = randi([26 NeuronLayer1]);

        NewMutation{i} = population{RandomMutation};

        NewMutation{i}.Layer1 = RandomNeuron; 
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%Migration
    for p = 1 : migration  
        layer1 = randi([MinNeuron + 20 NeuronLayer1]);
        layer2 = randi([MinNeuron + 10 NeuronLayer2]);
        layer3 = randi([MinNeuron      NeuronLayer3]);

        net= trainnet(XTrain,TTrain,layers,"crossentropy",options);

        NewMigration {p}.network = net;

        NewMigration {p}.Layer1 = layer1;
        NewMigration {p}.Layer2 = layer2;
        NewMigration {p}.Layer3 = layer3;

    end

    int = [NewCrossingOver NewMutation];
    for i=1: (crossingOver+mutation)
        layer1 = int{1, i}.Layer1;
        layer2 = int{1, i}.Layer2;
        layer3 = int{1, i}.Layer3;
    
        layers = [
            featureInputLayer(numFeatures, Normalization="zscore")
            fullyConnectedLayer(layer1)
            fullyConnectedLayer(layer2)
            fullyConnectedLayer(layer3)
            fullyConnectedLayer(numClasses)
            sigmoidLayer];        
        
        net = trainnet(XTrain,TTrain,layers,"crossentropy",options);

        int{1,i}.network = net;
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if migration == 0
       NewPopulation= [bestRNA int];
    else
       NewPopulation= [bestRNA int NewMigration];
    end

    for i=1: length(NewPopulation)
        net = NewPopulation{i}.network;
        Data.idxTrain = idxTrain;
        Data.idxVal = idxval;
        NewPopulation{i}.Data = Data;
   
        %%AccuracyTrain
        YTrain = minibatchpredict(net,XTrain);
        YTrain = onehotdecode(YTrain,classes,2);
        Accuracy_Train = mean(YTrain == TTrain);
        NewPopulation{i}.Accuracy_Train = Accuracy_Train;
        disp(NewPopulation{i}.Accuracy_Train)

        %%AccuracyValidation
        YVal = minibatchpredict(net,XVal);
        YVal = onehotdecode(YVal,classes,2);
        Accuracy_Validation =  mean(YVal == TVal);
        NewPopulation{i}.Accuracy_Validation = Accuracy_Validation;    
    end

    for i = 1:length(NewPopulation)
        for j = i + 1:length(NewPopulation)
            if NewPopulation{1, i}.Accuracy_Train < NewPopulation{1, j}.Accuracy_Train
               temp = NewPopulation{1, i};
               NewPopulation{i} = NewPopulation{1, j};
               NewPopulation{j} = temp;
            end
        end
    end


    for i = 1:length(NewPopulation)
        if NewPopulation{1, i}.Accuracy_Train > threshold
           
           nome_pasta =fullfile(directory, strcat('Accuracy_', sprintf('%.2f', NewPopulation{i}.Accuracy_Train), '_Network.mat'));
           mkdir (nome_pasta);
           nome_arquivo = sprintf('Accuracy_%.2f_Network.mat', NewPopulation{i}.Accuracy_Train);
           RNA = NewPopulation{1, i};
           save(fullfile(nome_pasta, nome_arquivo), 'RNA');

           %Confusion matrix training
           figure
           plotconfusion(TTrain, YTrain);
           saveas(gcf, fullfile(nome_pasta, 'Train.png'));
           
           %Confusion matrix validation
           figure
           plotconfusion(TVal, YVal);
           saveas(gcf, fullfile(nome_pasta, 'Validation.png'));

           close all

        end   
    end
    population=  NewPopulation;
end
populationFinal= population;