Algoritmos Genéticos com Raspberry Pi – Parte 4 – Criando Genes

Como citar esse artigo: VERTULO, Rodrigo Cesar. Algoritmos Genéticos com Raspberry Pi – Parte 4 – Criando Genes. Disponível em: <http://labdeeletronica.com.br/algoritmos-geneticos-com-raspberry-pi-parte-4-criando-genes/>. Acesso em: 17/01/2019.


Agora que já sabemos o que é um Cromossomo dentro do contexto dos Algoritmos Genéticos, chegou o momento de iniciarmos a codificação. Nosso ponto de partida será a criação de uma rotina em Python que seja capaz de receber um número inteiro e converte-lo para uma cadeia binária de acordo com as regras descritas no artigo anterior.

Para relembrarmos, na parte 3 de nossa série foi dito que nossos Cromossomos armazenarão cada digito dos valores numéricos que serão representados nele em forma de uma cadeia binária de 4 bits. Como exemplo, considere que nosso objetivo seja armazenar o número 45 em um Cromossomo. Para conseguirmos isso precisaremos converter o número 4 e o número 5 em uma cadeia binária de 4 bits cada um. Para esse exemplo o número 45 seria armazenado na forma 01000101, pois 0100 = 4 e 0101 = 5.

A partir desse momento eu partirei do princípio de que você já possui algum conhecimento da linguagem de programação Python e, a não ser que seja estritamente necessário, não me prenderei em ensinar conceitos sobre a linguagem. Também partirei do princípio de que você já possui um ambiente de desenvolvimento instalado e configurado. Resumindo, meu foco será em apresentar o desenvolvimento do Algoritmo Genético e suas particularidades. Além disso, você poderá desenvolver o código apresentado a partir de agora em qualquer plataforma que tenha suporte ao Python 3.x, não necessariamente no Raspberry Pi. Faremos uso especificamente do Raspberry Pi no final de nossa série quando formos desenvolver uma aplicação prática baseada em Algoritmo Genético.

Todo o projeto será estruturando em uma classe que chamarei de GARV, abreviação de Genetic Algorithm by Rodrigo Vertulo, e peço desculpas pelo “narcisismo”, mas não pude evitar. 😉





A seguir podemos ver a codificação inicial da classe GARV com um construtor inicialmente sem funcionalidade alguma e um método chamado “converteINT2BIN” que recebe o parâmetro “valor”, que é o número inteiro cujos dígitos desejamos transformar em uma cadeia binária de 4 bits cada um. Como já era esperado, esse método retornará uma string com a representação binária, seguindo as regras já explicadas, do valor passado como parâmetro. Vamos entender como esse código funciona.

class GARV:
    def __init__(self):
        pass
 
    def converteINT2BIN(self, valor):
        n = str(valor)
        digitos = list(n)
        nbin = ""
        binariofinal = ""
 
        for d in digitos:
            nbin = "{0:b}".format(int(d))
            if(len(nbin) &lt; 4):
                nbin = ((4 - len(nbin)) * "0") + str(nbin)
            binariofinal += nbin
 
        return binariofinal

Inicialmente o número inteiro armazenado no parâmetro “valor” é convertido para o tipo string e o resultado dessa conversão é atribuído à variável “n”. Essa conversão foi necessária por que logo em seguida cada caracter da string armazenada na variável “n” é colocado em uma lista, chamada “digitos”, que foi criada com a instrução “list(n)” que é capaz de “desmembrar” uma string qualquer gerando uma lista a partir disso. Logo em seguida foi criada uma variável chamada “nbin”, cuja finalidade será explicada daqui a pouco, e uma chamada “binariofinal” que ao final da execução do método conterá a cadeia binária no formato desejado.

Agora é necessário converter cada item contido na lista “digitos” para seu correspondente binário. Vamos supor que o método foi executado com o parâmetro “valor” contendo o número 12. Isso significa que na lista “digitos” existem dois itens, sendo o primeiro o dígito 1 e o segundo o dígito 2, ambos armazenados como string. O laço “for” que pode ser observado no corpo do método será executado para cada item existente na lista “digitos”. No nosso exemplo, como a lista possui dois itens, o laço será executado duas vezes.

No corpo do laço “for” a primeira instrução executada atribui à variável “nbin” o resultado da instrução

“{0:b}”.format(int(d))

cujo processamento envolve duas operações. Primeiro a variável “d”, criada pelo laço “for” e que contém um item obtido da lista “digitos”, é convertida para o tipo inteiro – não se esqueça de que ela era string. Depois que essa conversão é feita, o número inteiro obtido é convertido para seu equivalente binário utilizando o método “format” como é apresentado acima. Existe uma observação muito importante nesse ponto em relação ao método “format”; ele faz seu papel muito bem ao transformar um número inteiro decimal em sua representação binária e, no nosso caso, isso não é tão bom. Voltando ao exemplo do número 12 que foi passado como parâmetro na variável “valor”, o primeiro digito é o número 1. Quando o método “format” converte o decimal 1 para o valor binário 1 o resultado é também 1. Isso está completamente correto! Contudo, o nosso Cromossomo precisa receber cadeias binárias de 4 bits e não é isso o que temos até o momento. O que precisamos é que ao invés de 1, tenhamos 0001. É isso o que a instrução “if” existente dentro do laço “for” faz. Dentro deste “if” é verificado se o tamanho do número binário armazenado na variável “nbin” é menor do que 4 bits e, caso seja verdade, é adicionada a quantidade de zeros na frente do número para completar o que está faltando para que a cadeia binária possua 4 bits.

Depois que o “if” é avaliado, a cadeia binária do dígito atual é concatenada à variável “binariofinal” para que o próximo dígito da lista “digitos” possa ser trabalhado. Quando todos os dígitos forem processados, a variável “binariofinal” conterá a cadeia binária completa correspondente ao número informado no parâmetro “valor”. Cada dígito contido na variável “binariofinal” é um Gene do parâmetro “valor”.

Agora já somos capazes do convertermos qualquer valor inteiro na base 10 para uma cadeia binária com cada dígito do valor representado na base 2 e com cada um possuindo 4 bits de comprimento. Vale ressaltar que no momento não estamos preocupados em criarmos um código otimizado e sim um que resolva nosso problema. Futuras otimizações para deixar o código mais compacto, veloz, etc. poderão ser feitas em uma ocasião mais oportuna para que não nos preocupemos com outros detalhes que fogem ao entendimento do funcionamento do Algoritmo Genético.

Nossa próxima tarefa será desenvolver um método na classe GARV que seja capaz de criar um Cromossomo completo. Mas isso será trabalho para o próximo artigo da série.

Comentários