Aplicação de Algoritmos Genéticos na Otimização de Contratos de
Transcrição
Aplicação de Algoritmos Genéticos na Otimização de Contratos de
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 1 Aplicação de Algoritmos Genéticos na Otimização de Contratos de Demanda de Energia Elétrica Marco Aurélio C. Pacheco1, José Eduardo N. da Rocha,2 1 ICA: Laboratório de Inteligência Computacional, Departamento de Engenharia Elétrica, PUC-Rio R. Marques de S. Vicente 225, Gávea, Rio de Janeiro, CEP 22453-900, RJ, Brasil {marco, jerocha}@ele.puc-rio.br 2 Light Serviços de Eletricidade S/A Gerência de Sistemas Comerciais, Praia do Flamengo, 66-A, Flamengo, Rio de Janeiro, CEP 22228-900, RJ, Brasil [email protected] Resumo. Para os clientes supridos em Média Tensão ( >= 1kV e < 138 kV) e Alta Tensão ( >= 138 kV), o valor contratado de Demanda de Energia Elétrica (kW) com a concessionária, é um dos fatores determinantes do valor final da fatura mensal. A escolha precisa da alternativa tarifária e dos valores contratados de Demanda de Energia Elétrica deverão ser de forma que a energia requerida esteja disponível, sem ônus adicionais, e o valor do faturamento seja o mínimo possível. O objetivo deste estudo é achar a alternativa tarifária ótima utilizando técnicas de algoritmos genético. Abstract. For clients supplied in Medium Tension ( >= 1kV e < 138 kV) and High Tension ( >= 138 kV), the Power Energy (kW) contract is one of the most important factor for monthly billing total note. The precise evaluation of the tariffs alternatives and Power Energy (kW) contracts, must attend the required energy and, at the same time, lead to minimal billing value. The main objective of this paper is to explore the optimal tariff alternative using Genetic Algorithms techniques. palavras-chave: alternativas tarifárias, otimização, minimização. 1. Introdução Este trabalho apresenta um estudo sobre a utilização de Algoritmos Genéticos na otimização de contratos de Demanda de Energia Elétrica, celebrados entre o cliente e a concessionária, visando garantir a disponibilidade da energia contratada, minimizando os custos no faturamento para o cliente e otimizando o planejamento dos Sistemas Elétricos de Distribuição da concessionária. O GA deverá encontrar a melhor alternativa tarifária (convencional ou horo-sazonal) que garantam as condições acima identificadas. Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 2 2. O Problema das Demandas Contratuais de Energia Elétrica O valor contratado de Demanda de Energia Elétrica com a concessionária deverá ser o mais próximo possível do valor médio requerido, ao longo do tempo, pelas cargas da unidade consumidora. Quando o valor máximo demandado de energia elétrica supera o valor contratual do segmento, o valor do excedente de demanda sofre uma tarifação onerosa de ultrapassagem contratual (Tabela 1). Tarifas Demanda Ultrapassagem Demanda Ultrapassagem Demanda Ultrapassagem Período Único Período Único Ponta Ponta Fora Ponta Fora Ponta Convencional 1.00 3.00 -- x -- -- x -- -- x -- -- x -- Azul -- x -- -- x -- 2.65 7.95 0.88 2.65 Verde 0.88 2.65 -- x -- -- x -- -- x -- -- x -- Tabela 1 – Tarifas Normalizadas A análise periódica do comportamento da curva de carga da unidade consumidora, a partir de seus dados históricos de demanda medida de energia elétrica, são a base de avaliação para o ajuste ótimo da alternativa tarifária e contratual de demanda. Na figura 1 podemos simular a contratação de três Demandas (C1, C2 e C3). Em função dos níveis de carga requeridos, a mesma energia demandada resultará em diferentes valores faturados. Toda a energia que exceder o limite contratual é penalizada com uma tarifa de ultrapassagem. Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 3 Figura 1 – Curva de Carga e simulação de Demandas Contratadas 3. Aplicação de Algoritmos Genéticos Algoritmos Genéticos são métodos de busca estocásticos que emulam teorias evolucionárias biológicas para solucionar problemas de otimização, compreendendo um conjunto de elementos individuais (a população) e um conjunto de operadores biologicamente inspirados definidos sobre a própria população. De acordo com as teorias evolucionárias, somente os elementos mais adequados em uma população, têm maior probabilidade de sobrevivência e geram descendentes, assim transmitindo sua identidade biológica hereditária às novas gerações. Em termos computacionais, um algoritmo genético mapeia um problema em um conjunto (tipicamente) de palavras binárias, manipulando as mais promissoras em busca de soluções melhoradas. A Figura 2 mostra a estrutura de um Algoritmo Genético básico. Nota Técnica em Inteligência Computacional, ICA, PUC-Rio início inicialização da população cálculo da aptidão solução encontrada ? Sim Não seleção reprodução mutação Figura 2 – Estrutura básica de um Algoritmo Genético fim 4 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 5 3.1 Inicialização da População Uma vez conhecidos os valores mínimos e máximos das curvas de carga típicas das unidades consumidoras, a população é inicializada com valores aleatórios entre os dois limites. 3.2 Codificação A codificação da população é binária. Uma vez que o espaço de busca representado pelos limites máximo e mínimo é da ordem de 3 x 104 e a precisão desejada é 10-1 temos que adotar codificação binária de 19 dígitos. Para representar os três tipos possíveis de contrato temos uma representação binária de 2 dígitos. Assim sendo, para representar um tipo de contrato e dois valores de demanda (ponta e fora ponta), temos um cromossomo de 40 dígitos binários. (Figura 3) Figura 3 – Representação do Cromossomo 3.3 Função de Avaliação A função de avaliação é a função objetiva, e provém o mecanismo para avaliar o indivíduo da população, atribuindo o conceito para cada solução potencial. Como nosso problema é de minimização, quanto menor o valor da função objetiva, maiores serão as chances do indivíduo sobreviver e reproduzir-se. F = ∑ (DPi * TDPi + CPi * TCPi + DFi * TDFi + CFi * TCFi) j Onde : DP = Demanda Faturada Ponta (kW) DF = Demanda Faturada Fora de Ponta (kW) CP = Consumo Ponta (kWh) CF = Consumo Fora Ponta (kWh) TDP, TDF, TCP e TCF = Tarifas de cada segmento j = Meses de Avaliação Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 6 Neste estudo utilizaremos a técnica de aptidão de Normalização linear com o objetivo de aumentar a competição nos grupos de indivíduos com avaliação próxima. 3.4 Seleção O mecanismo de seleção modela o mecanismo natural de sobrevivência do indivíduo mais apto. Assim sendo, as soluções inaptas tendem a desaparecer. No esquema de seleção proporcional, um indivíduo com maior aptidão têm maior probabilidade de sobrevivência. Utilizamos a Regra da Roleta para seleção, onde cada indivíduo é alocado a um setor da roleta virtual ocupando uma área proporcional à sua aptidão (Figura 4). Figura 4 – Regra da Roleta 3.5 Crossover (Reprodução) Depois da seleção de genitores, ocorre o processo de crossover que consiste na recombinação de material genético entre indivíduos da população. Pares de indivíduos são escolhidos aleatoriamente na população, e é feita a troca de fragmentos entre os pares de genitores, a partir de um ponto de cruzamento aleatoriamente escolhido em cada cromossomo (Figura 5). Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 7 Figura 5 – Operador de Crossover de um ponto 3.6 Mutação Após o crossover, os novos indivíduos estão sujeitos à mutação. Esta consiste em selecionarmos aleatoriamente um gene em um cromossomo e alterar seu valor para um outro alelo possível. No caso de representação binária, o valor do gene sorteado é alterado, de “0” para “1”, ou vice-versa. O processo é controlado por um parâmetro fixo, que indica a probabilidade de um gene sofrer mutação. A mutação é um operador genético que tem a finalidade de restaurar material genético perdido. (Figura 6) Figura 6 – Operador de Mutação 3.7 Elitismo Baseia-se na idéia de garantir a sobrevivência do indivíduo mais apto. Copia-se o cromossomo mais apto para a próxima geração. Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 8 4. Resultados A implementação do algoritmo genético usado nos experimentos foi feita em linguagem C++. A listagem do código fonte é disponibilizada no Anexo 1. Verifica-se que, sem elitismo e sem normalização linear, o algoritmo genético não consegue convergir para a solução ótima, dentro do limite de 40 gerações. Mesmo alterando-se os parâmetros de controle (tamanho da população, probabilidade de crossover e mutação), não se obteve uma melhoria significativa. Todavia, quando se usa normalização linear e elitismo, o Algoritmo Genético tem sua performance melhorada consideravelmente, convergindo para o mínimo global desejado com extrema rapidez (menos de 15 gerações). A seguir apresentamos os gráficos resultantes da média dos melhores indivíduos a cada geração para todos experimentos. (Figura 7). Figura 7.a – Implementação de Algoritmo Genético sem normalização linear / elitismo. Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 9 Figura 7.b – Implementação de Algoritmo Genético com normalização linear. Figura 7.c – Implementação de Algoritmo Genético com normalização linear e elitismo. 5. Conclusões Os resultados obtidos neste trabalho confirmam a aplicabilidade de Algoritmos Genéticos nos problemas de otimização. Devido a excelente performance alcançada, a implementação estudada poderá ser utilizada em processamento de lote (batch processing) em uma base de dados de unidades consumidoras, visando a otimização individual de Contratos de Demanda de Energia Elétrica. Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 6. Referências D. GoldBerg, Genetic Algorithm in Search, Optimozation and Machine Learning. Addison-Wesley, (1989) . Z. Michalewickz, Genetic Algorithms + Data Structures = Evolution Programs. Springer-Verlag (1994). Marco Aurélio Pacheco, Notas de Aula em Computação Evolucionária www.ica.ele.puc-rio.br - (2001). 10 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 11 ANEXO 1 – Código Fonte //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "Unit2.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; /* estrutura que armazena um individuo da populacao: .value_c: armazena o valor do tipo de contrato .value_x: armazena o valor do número real do contrato de ponta .value_y: armazena o valor do número real do contrato fora de ponta .string: armazena o cromossoma do individuo .string_c: armazena o gene do tipo de contrato .string_x: armazena o gene da coordenada x do individuo .string_y: armazena o gene da coordenada y do individuo .fitness: armazena a fitness do individuo */ struct population { int value_c; double value_x; double value_y; unsigned char string_c[2]; unsigned char string_x[(CHROM_LENGTH-2)/2]; coordenada x */ /* a primeira metade do cromossoma representa a unsigned char string_y[(CHROM_LENGTH-2)/2]; coordenada y */ /* a segunda metade do cromossoma representa a unsigned char double }; string[CHROM_LENGTH]; fitness; /* o cromossoma inteiro */ Nota Técnica em Inteligência Computacional, ICA, PUC-Rio double bestid [100] [100]; /* estruturas de armazenamento da populacao: 'pool' armazena a populacao corrente, enquanto que 'new_pool' armazena os novos individuos criados a cada geracao; ao fim de cada geracao, os novos individuos sao copiados de volta para 'pool' */ struct population pool[10000]; struct population new_pool[10000]; /* armazena os indices dos indivuos selecionados para reproducao */ int selected[100000]; /* parâmetros do GA */ int minimo, maximo, popsize, rodadas; double pcross, pmut; /* contador do numero de geracoes */ int generations; double best [100]; int maxgen; /* Tarifas */ double TDCT, TDAP, TDAF, TDVT, TCCT, TCAP, TCAF, TCVP, TCVF; /*Medidas elétricas da Unidade Consumidora - Demanda e Consumo */ /* T = todos os períodos ou período único P = Ponta F = Fora da Ponta */ 12 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio double DT_1, DT_2, DT_3, DT_4, DT_5, DT_6, DT_7, DT_8, DT_9, DT_10, DT_11, DT_12; double DP_1, DP_2, DP_3, DP_4, DP_5, DP_6, DP_7, DP_8, DP_9, DP_10, DP_11, DP_12; double DF_1, DF_2, DF_3, DF_4, DF_5, DF_6, DF_7, DF_8, DF_9, DF_10, DF_11, DF_12; double CT_1, CT_2, CT_3, CT_4, CT_5, CT_6, CT_7, CT_8, CT_9, CT_10, CT_11, CT_12; double CP_1, CP_2, CP_3, CP_4, CP_5, CP_6, CP_7, CP_8, CP_9, CP_10, CP_11, CP_12; double CF_1, CF_2, CF_3, CF_4, CF_5, CF_6, CF_7, CF_8, CF_9, CF_10, CF_11, CF_12; //--------------------------------------------------------------------------__fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- //---------------------------------------------------------------------------void __fastcall TForm2::FormCreate(TObject *Sender) { Query1->Open(); } //---------------------------------------------------------------------------- void __fastcall TForm2::RadioGroup1Click(TObject *Sender) { if ((RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "normalização")|| 13 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio (RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "elitismo")) { Edit1->Enabled = true; Edit2->Enabled = true; } else { Edit1->Enabled = false; Edit2->Enabled = false; } } //--------------------------------------------------------------------------- void __fastcall TForm2::Button2Click(TObject *Sender) { Close(); } //--------------------------------------------------------------------------- void __fastcall TForm2::Button1Click(TObject *Sender) { int i, j, k, n; double sum_fitness, avg_fitness, old_avg_fitness; unsigned char temp_string[CHROM_LENGTH]; FILE *file, *fileb; int flip(double); void encode_c(int,int); void encode_x(int, int); void encode_y(int, int); 14 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio void join_xy(int); void split_xy(int); int decode_c(int); double decode_x(int); double decode_y(int); double evaluate(int, double, double); void initialize_population(void); int select(double); void crossover (int, int, int, int); void mutation(void); double normalize(struct population []); void statistics(FILE *, double); void pcrom(FILE *, int); minimo = StrToInt(Edit1 -> Text); maximo = StrToInt(Edit2 -> Text); popsize = StrToInt(Edit3 -> Text); pcross = StrToFloat(Edit5 -> Text); pmut = StrToFloat(Edit6 -> Text); rodadas = StrToInt(Edit7 -> Text); maxgen = StrToInt(Edit8 -> Text); /* Tarifas */ TDAP = StrToFloat(Edit10 -> Text); TDAF = StrToFloat(Edit11 -> Text); TDCT = StrToFloat(Edit4 -> Text); TDVT = StrToFloat(Edit9 -> Text); TCCT = StrToFloat(Edit13 -> Text); TCAP = StrToFloat(Edit14 -> Text); TCAF = StrToFloat(Edit15 -> Text); TCVP = StrToFloat(Edit16 -> Text); 15 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio TCVF = StrToFloat(Edit17 -> Text); /* Dados Históricos da UC DT_12 = StrToFloat(EditDT_12 -> Text); */ DT_12 = Query1->Fields[4]->AsFloat; DP_12 = Query1->Fields[5]->AsFloat; DF_12 = Query1->Fields[6]->AsFloat; CT_12 = Query1->Fields[7]->AsFloat; CP_12 = Query1->Fields[8]->AsFloat; CF_12 = Query1->Fields[9]->AsFloat; DT_11 = Query1->Fields[10]->AsFloat; DP_11 = Query1->Fields[11]->AsFloat; DF_11 = Query1->Fields[12]->AsFloat; CT_11 = Query1->Fields[13]->AsFloat; CP_11 = Query1->Fields[14]->AsFloat; CF_11 = Query1->Fields[15]->AsFloat; DT_10 = Query1->Fields[16]->AsFloat; DP_10 = Query1->Fields[17]->AsFloat; DF_10 = Query1->Fields[18]->AsFloat; CT_10 = Query1->Fields[19]->AsFloat; CP_10 = Query1->Fields[20]->AsFloat; CF_10 = Query1->Fields[21]->AsFloat; DT_9 = Query1->Fields[22]->AsFloat; DP_9 = Query1->Fields[23]->AsFloat; DF_9 = Query1->Fields[24]->AsFloat; CT_9 = Query1->Fields[25]->AsFloat; CP_9 = Query1->Fields[26]->AsFloat; 16 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio CF_9 = Query1->Fields[27]->AsFloat; DT_8 = Query1->Fields[28]->AsFloat; DP_8 = Query1->Fields[29]->AsFloat; DF_8 = Query1->Fields[30]->AsFloat; CT_8 = Query1->Fields[31]->AsFloat; CP_8 = Query1->Fields[32]->AsFloat; CF_8 = Query1->Fields[33]->AsFloat; DT_7 = Query1->Fields[34]->AsFloat; DP_7 = Query1->Fields[35]->AsFloat; DF_7 = Query1->Fields[36]->AsFloat; CT_7 = Query1->Fields[37]->AsFloat; CP_7 = Query1->Fields[38]->AsFloat; CF_7 = Query1->Fields[39]->AsFloat; DT_6 = Query1->Fields[40]->AsFloat; DP_6 = Query1->Fields[41]->AsFloat; DF_6 = Query1->Fields[42]->AsFloat; CT_6 = Query1->Fields[43]->AsFloat; CP_6 = Query1->Fields[44]->AsFloat; CF_6 = Query1->Fields[45]->AsFloat; DT_5 = Query1->Fields[46]->AsFloat; DP_5 = Query1->Fields[47]->AsFloat; DF_5 = Query1->Fields[48]->AsFloat; CT_5 = Query1->Fields[49]->AsFloat; CP_5 = Query1->Fields[50]->AsFloat; CF_5 = Query1->Fields[51]->AsFloat; DT_4 = Query1->Fields[52]->AsFloat; 17 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio DP_4 = Query1->Fields[53]->AsFloat; DF_4 = Query1->Fields[54]->AsFloat; CT_4 = Query1->Fields[55]->AsFloat; CP_4 = Query1->Fields[56]->AsFloat; CF_4 = Query1->Fields[57]->AsFloat; DT_3 = Query1->Fields[58]->AsFloat; DP_3 = Query1->Fields[59]->AsFloat; DF_3 = Query1->Fields[60]->AsFloat; CT_3 = Query1->Fields[61]->AsFloat; CP_3 = Query1->Fields[62]->AsFloat; CF_3 = Query1->Fields[63]->AsFloat; DT_2 = Query1->Fields[64]->AsFloat; DP_2 = Query1->Fields[65]->AsFloat; DF_2 = Query1->Fields[66]->AsFloat; CT_2 = Query1->Fields[67]->AsFloat; CP_2 = Query1->Fields[68]->AsFloat; CF_2 = Query1->Fields[69]->AsFloat; DT_1 = Query1->Fields[70]->AsFloat; DP_1 = Query1->Fields[71]->AsFloat; DF_1 = Query1->Fields[72]->AsFloat; CT_1 = Query1->Fields[73]->AsFloat; CP_1 = Query1->Fields[74]->AsFloat; CF_1 = Query1->Fields[75]->AsFloat; /* construtor do objeto Gráfico */ TFastLineSeries *ga = new TFastLineSeries(this); /* parametriza a barra de progresso */ 18 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio ProgressBar1->Max = popsize*maxgen; ProgressBar1->Position = 0; ProgressBar1->Step = popsize; /* abre o arquivo x2.txt, onde serao logadas as estatisticas do GA */ file = fopen("ga3.txt", "wt"); if (!file) return; /* abre o arquivo best.txt, onde será armazenado o melhor cromossoma de cada geração */ fileb = fopen("bga3.txt", "wt"); if (!fileb) return; /* estabelece a semente do gerador de numeros aleatorios (necessario antes de se chamar rand() pela primeira vez) */ randomize(); for (n=0; n<rodadas; n++) { generations = 0; avg_fitness = 1; /* inicializa a populacao */ initialize_population(); fprintf(fileb, "\n\nRodada: %d\n", n+1); do { Label9->Caption = IntToStr(n+1)+" "; Label9->Refresh(); Label11->Caption = IntToStr(generations+1)+" "; 19 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 20 Label11->Refresh(); ProgressBar1->StepIt(); sum_fitness = 0; old_avg_fitness = avg_fitness; bestid [n] [generations] = 1000000000; /* calcula avaliacao e fitness da populacao inteira */ for (i=0; i<popsize; i++) { pool[i].value_c = decode_c(i); /* Decodifica o tipo do contrato do individuo [i] */ pool[i].value_x = decode_x(i); /* Decodifica a coordenada x do individuo [i] */ pool[i].value_y = decode_y(i); /* Decodifica a coordenada y do individuo [i] */ pool[i].fitness = evaluate(pool[i].value_c, pool[i].value_x, pool[i].value_y); /* Avalia o individuo [i] if (pool[i].fitness < bestid [n] [generations]) /* Guarda o melhor cromossoma */ { bestid [n] [generations] = pool[i].fitness; k = i; Label13->Caption = FloatToStr(bestid [n] [generations])+" "; Label13->Refresh(); } sum_fitness +=pool[i].fitness; } /* normalização linear */ if ((RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "normalização")|| (RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "elitismo")) { sum_fitness = normalize(pool); k = 0; */ Nota Técnica em Inteligência Computacional, ICA, PUC-Rio } /* copia o melhor indivíduo para a próxima geração */ for (j=0; j < CHROM_LENGTH; j++) temp_string[j] = pool[k].string[j]; /* grava no arquivo o melhor cromossoma da geração */ pcrom(fileb, k); avg_fitness = sum_fitness / popsize; /* seleciona os individuos para reproducao */ for (i=0; i<popsize; i++) selected[i] = select(sum_fitness); /* realiza crossover entre os pares, sendo cada par (os pais) definido por selected[i] e selected[i+1]; os filhos gerados serao armazenados na estrutura 'new_pool' na posicao indicada por i e i+1 */ for (i=0; i<popsize; i=i+2) crossover(selected[i],selected[i+1],i,i+1); /* realiza mutacao sobre os individuos que acabaram de ser gerados, copiando-os entao de 'new_pool' de volta para 'pool' */ mutation(); /* elitismo - copia o melhor cromossoma da geração anterior */ if (RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "elitismo") { for (j=0; j < CHROM_LENGTH; j++) pool[popsize - 1].string[j] = temp_string[j]; split_xy(popsize - 1); 21 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio } /* imprime estatisticas sobre o andamento do GA */ statistics(file, avg_fitness/old_avg_fitness); } while (++generations < maxgen); /* fecha os arquivos de saida */ } /* Acha a média da aptidão do melhor indivíduo a cada rodada de cada geração*/ for (i=0;i<maxgen;i++) { best[i] = 0; for (j=0;j<rodadas;j++) best[i] += (bestid[j] [i] / rodadas); fprintf(fileb, "\n%f", best[i]); } fclose(file); fclose(fileb); /* Traça o gráfico do GA */ if (CheckBox1->Checked) Chart1->RemoveAllSeries(); Chart1->Title->Text->Clear(); Chart1->Title->Text-> Add("Comparação"); Chart1->Title->Text-> Add("GA1 - GA2 - GA3"); ga->ParentChart = Chart1; ga->AddArray(best,maxgen-1); if (RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "nenhum") 22 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio { ga->SeriesColor = clBlue; ga->Title = "GA1"; ga->ShowInLegend = true; } else if (RadioGroup1->Items->Strings[RadioGroup1->ItemIndex] == "normalização") { ga->SeriesColor = clRed; ga->Title = "GA2"; } else { ga->SeriesColor = clGreen; ga->Title = "GA3"; } for ( int i = popsize; i < maxgen*popsize+1; i=i+popsize ) ga->XLabel[(i /popsize)-1] = i; ProgressBar1->Position = 0; } //--------------------------------------------------------------------------- /* ****************************************** * * flip * Toss a biased coin * 23 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio ****************************************** */ /* se um numero aleatorio [i] for menor que o numero contido em prob, ou prob /* igual a 1, entao a funcao flip retorna verdadeiro(1), caso contrario falso(0) */ int flip(double prob) { double i; i=((double)rand())/RAND_MAX; if ((prob == 1.0) || (i < prob)) return (1); else return (0); } /* ****************************************** * encode_c * * Code a integer into binary string * ****************************************** */ void encode_c(int index, int value) { int i; /* E' recebido um indice que indica a que individuo estamos nos referenciando e o valor que sera codificado numa string binaria. Entao para codificar este valor e' necessario shiftar o valor fornecido por [i], obtendo-se entao um bit */ */ 24 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio for (i=0; i < 2; i++) /* este bit e' colocado na estrutura s */ pool[index].string_c[1-i] = (value >> i) & 0x01; } /* ****************************************** * encode_x * * Code a integer into binary string * ****************************************** */ void encode_x(int index, int value) { int i; /* E' recebido um indice que indica a que individuo estamos nos referenciando e o valor que sera codificado numa string binaria. Entao para codificar este valor e' necessario shiftar o valor fornecido por [i], obtendo-se entao um bit */ for (i=0; i < ((CHROM_LENGTH-2)/2); i++) /* este bit e' colocado na estrutura s */ pool[index].string_x[((CHROM_LENGTH-2)/2)-1-i] = (value >> i) & 0x01; /* coordenada x */ } /* ****************************************** * encode_y * * Code a integer into binary string * ****************************************** */ void encode_y(int index, int value) { int i; 25 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio /* E' recebido um indice que indica a que individuo estamos nos referenciando e o valor que sera codificado numa string binaria. Entao para codificar este valor e' necessario shiftar o valor fornecido por [i], obtendo-se entao um bit */ for (i=0; i < ((CHROM_LENGTH-2)/2); i++) /* este bit e' colocado na estrutura s */ pool[index].string_y[((CHROM_LENGTH-2)/2)-1-i] = (value >> i) & 0x01; /* coordenada y */ } /* ******************************************************************************* * join_xy * * Junta o tipo de contrato e as duas partes x e y em um único cromossoma * ******************************************************************************* */ void join_xy(int index) { int i; for (i=0; i < 2; i++) /* tipo de contrato - 2 bits */ pool[index].string[1-i] = pool[index].string_c[1-i]; for (i=0; i < ((CHROM_LENGTH-2)/2); i++) /* este bit e' colocado na estrutura s */ { pool[index].string[(CHROM_LENGTH/2)-i] = pool[index].string_x[((CHROM_LENGTH-2)/2)-1-i]; pool[index].string[(CHROM_LENGTH)-1-i] = pool[index].string_y[((CHROM_LENGTH-2)/2)-1-i]; } } /* 26 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio ******************************************************************************* * split_xy * * Separa o tipo de contrato e as duas partes x e y de um único cromossoma * ******************************************************************************* */ void split_xy(int index) { int i; for (i=0; i < 2; i++) /* tipo de contrato - 2 bits */ pool[index].string_c[1-i] = pool[index].string[1-i]; for (i=0; i < ((CHROM_LENGTH-2)/2); i++) /* este bit e' colocado na estrutura s */ { pool[index].string_x[(CHROM_LENGTH/2)-1-i] = pool[index].string[(CHROM_LENGTH/2)-i]; pool[index].string_y[(CHROM_LENGTH/2)-1-i] = pool[index].string[(CHROM_LENGTH)-1-i]; } } /* ****************************************** * decode_c * * Decode a binary string into an integer * ****************************************** */ int decode_c(int index) { int i, vv; vv = 0; for (i=0; i < 2; i++) /* Transforma um numero binario em decimal */ 27 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio vv += (pool[index].string_c[1-i] << i); return vv; } /* ****************************************** * decode_x * * Decode a binary string into an real * ****************************************** */ double decode_x(int index) { int i, vv; double value; vv = 0; for (i=0; i < (CHROM_LENGTH/2); i++) /* Transforma um numero binario em decimal */ vv += (pool[index].string_x[((CHROM_LENGTH-2)/2)-1-i] << i); value = (vv*0.055313215853149133966701444056404) + MINDEM; return value; } /* ****************************************** * decode_y * * Decode a binary string into an real ****************************************** */ double decode_y(int index) * 28 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio { int i, vv; double value; vv = 0; for (i=0; i < (CHROM_LENGTH/2); i++) /* Transforma um numero binario em decimal */ vv += (pool[index].string_y[((CHROM_LENGTH-2)/2)-1-i] << i); value = (vv*0.055313215853149133966701444056404) + MINDEM; return value; } /* ****************************************** * evaluate * * Evaluation Function * ****************************************** */ double evaluate(int value_c, double value_x, double value_y) { /* retorna o valor da função f para o contrato c e as coordenadas x e y */ double df; df=0; switch (value_c) { case 0 : case 1 : if (value_x < 1.1 * DT_1) df += value_x * TDCT + ((DT_1 - value_x) * 3 * TDCT); else df += value_x * TDCT; 29 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (value_x < 1.1 * DT_2) df += value_x * TDCT + ((DT_2 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_3) df += value_x * TDCT + ((DT_3 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_4) df += value_x * TDCT + ((DT_4 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_5) df += value_x * TDCT + ((DT_5 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_6) df += value_x * TDCT + ((DT_6 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_7) df += value_x * TDCT + ((DT_7 - value_x) * 3 * TDCT); else df += value_x * TDCT; 30 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (value_x < 1.1 * DT_8) df += value_x * TDCT + ((DT_8 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_9) df += value_x * TDCT + ((DT_9 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_10) df += value_x * TDCT + ((DT_10 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_11) df += value_x * TDCT + ((DT_11 - value_x) * 3 * TDCT); else df += value_x * TDCT; if (value_x < 1.1 * DT_12) df += value_x * TDCT + ((DT_12 - value_x) * 3 * TDCT); else df += value_x * TDCT; df += (CT_1 + CT_2 + CT_3 + CT_4 + CT_5 + CT_6 + CT_7 + CT_8 + CT_9 + CT_10 + CT_11 + CT_12) * TCCT; break; case 2 : 31 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (value_y < 1.1 * DP_1) df += value_y * TDAP + ((DP_1 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_2) df += value_y * TDAP + ((DP_2 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_3) df += value_y * TDAP + ((DP_3 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_4) df += value_y * TDAP + ((DP_4 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_5) df += value_y * TDAP + ((DP_5 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_6) df += value_y * TDAP + ((DP_6 - value_y) * 3 * TDAP); else df += value_y * TDAP; 32 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (value_y < 1.1 * DP_7) df += value_y * TDAP + ((DP_7 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_8) df += value_y * TDAP + ((DP_8 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_9) df += value_y * TDAP + ((DP_9 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_10) df += value_y * TDAP + ((DP_10 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_11) df += value_y * TDAP + ((DP_11 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_y < 1.1 * DP_12) df += value_y * TDAP + ((DP_12 - value_y) * 3 * TDAP); else df += value_y * TDAP; if (value_x < 1.1 * DF_1) 33 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio df += value_x * TDAF + ((DF_1 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_2) df += value_x * TDAF + ((DF_2 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_3) df += value_x * TDAF + ((DF_3 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_4) df += value_x * TDAF + ((DF_4 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_5) df += value_x * TDAF + ((DF_5 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_6) df += value_x * TDAF + ((DF_6 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_7) df += value_x * TDAF + ((DF_7 - value_x) * 3 * TDAF); 34 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio else df += value_x * TDAF; if (value_x < 1.1 * DF_8) df += value_x * TDAF + ((DF_8 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_9) df += value_x * TDAF + ((DF_9 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_10) df += value_x * TDAF + ((DF_10 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_11) df += value_x * TDAF + ((DF_11 - value_x) * 3 * TDAF); else df += value_x * TDAF; if (value_x < 1.1 * DF_12) df += value_x * TDAF + ((DF_12 - value_x) * 3 * TDAF); else df += value_x * TDAF; df += (CP_1 + CP_2 + CP_3 + CP_4 + CP_5 + CP_6 + CP_7 + CP_8 + CP_9 + CP_10 + CP_11 + CP_12) * TCAP; 35 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio df += (CF_1 + CF_2 + CF_3 + CF_4 + CF_5 + CF_6 + CF_7 + CF_8 + CF_9 + CF_10 + CF_11 + CF_12) * TCAF; break; case 3 : if (value_x < 1.1 * DT_1) df += value_x * TDVT + ((DT_1 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_2) df += value_x * TDVT + ((DT_2 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_3) df += value_x * TDVT + ((DT_3 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_4) df += value_x * TDVT + ((DT_4 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_5) df += value_x * TDVT + ((DT_5 - value_x) * 3 * TDVT); else df += value_x * TDVT; 36 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (value_x < 1.1 * DT_6) df += value_x * TDVT + ((DT_6 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_7) df += value_x * TDVT + ((DT_7 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_8) df += value_x * TDVT + ((DT_8 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_9) df += value_x * TDVT + ((DT_9 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_10) df += value_x * TDVT + ((DT_10 - value_x) * 3 * TDVT); else df += value_x * TDVT; if (value_x < 1.1 * DT_11) df += value_x * TDVT + ((DT_11 - value_x) * 3 * TDVT); else df += value_x * TDVT; 37 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (value_x < 1.1 * DT_12) df += value_x * TDVT + ((DT_12 - value_x) * 3 * TDVT); else df += value_x * TDVT; df += (CP_1 + CP_2 + CP_3 + CP_4 + CP_5 + CP_6 + CP_7 + CP_8 + CP_9 + CP_10 + CP_11 + CP_12) * TCVP; df += (CF_1 + CF_2 + CF_3 + CF_4 + CF_5 + CF_6 + CF_7 + CF_8 + CF_9 + CF_10 + CF_11 + CF_12) * TCVF; break; } return df; } /* ****************************************** * initialize_population * * creates and initializes a population * ****************************************** */ void initialize_population(void) { int i; /* para cada individuo i sera codificado um numero entre 0 e 2 elevado 38 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio a (CHROM_LENGTH-2)/2 */ for (i=0; i < popsize; i++) { encode_c(i, random((int)pow(2.0, 2.0))); encode_x(i, random((int)pow(2.0, ((CHROM_LENGTH-2)/2)))); encode_y(i, random((int)pow(2.0, ((CHROM_LENGTH-2)/2)))); join_xy(i); /* cria um único cromossoma juntando c, x e y */ } } /* ****************************************** * select * * selects strings for reproduction * ****************************************** */ int select(double sum_fitness) { int i; double rand_val; /* valor randomico entre 0 e sum_fitness */ double partial_sum; /* soma parcial do fitness dos elementos */ /* gera o rand_val */ rand_val = sum_fitness*(((double)rand())/RAND_MAX); /* inicializa partial_sum */ partial_sum = pool[0].fitness; /* encontra o indice indicado por rand_val 39 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 40 isto e' feito atraves da soma de todos os fitness dos elementos da populacao ate' que esta soma ultrapasse o valor gerado */ for (i=0; partial_sum<rand_val; i++) partial_sum += pool[i+1].fitness; /* retorna o indice encontrado */ return i; } /* ****************************************** * crossover * * Swaps 2 sub-strings * ****************************************** */ void crossover (int parent1, int parent2, int child1, int child2) { int i, site; if (flip(pcross)) /* Se um numero aleatorio gerado por flip for menor que PCROSS */ site = random((CHROM_LENGTH)); /* determina um ponto de corte aleatorio no cromossoma, senao */ else /* marca como ponto de corte o ultimo gen do cromossoma site = (CHROM_LENGTH)-1; /* ate' o ponto de corte, sao copiados genes de pai1 para filho1 e de pai2 para filho2 */ for (i=0; i <= site; i++) { new_pool[child1].string[i] = pool[parent1].string[i]; new_pool[child2].string[i] = pool[parent2].string[i]; } */ Nota Técnica em Inteligência Computacional, ICA, PUC-Rio /* apos o ponto de corte, sao copiados genes de pai2 para filho1 e de pai1 para filho2 */ /* (veja definicao de crossover de um ponto) */ for (i=site+1; i < CHROM_LENGTH; i++) { new_pool[child1].string[i] = pool[parent2].string[i]; new_pool[child2].string[i] = pool[parent1].string[i]; } } /* ****************************************** * mutation * * Changes the values of string position * ****************************************** */ void mutation(void) { int i, j; /* Percorrendo todos os individuos de uma populacao e todos os genes de */ /* cada individuo. Se um numero aleatorio gerado por flip for menor que PMUT */ /* entao o gene [j] sera invertido, caso contrario nao. */ /* Neste ponto da execucao do programa os individuos ja' sofreram crossover */ /* e os filhos gerados estao em new_pool, entao fazemos mutacao sobre new_pool */ /* e aproveitamos para copiar a nova populacao para a populacao corrente, ou */ /* seja a populacao que ira para a proxima geracao /* Note que um bit e' representado no programa por um char for (i=0; i < popsize; i++) { for (j=0; j < CHROM_LENGTH; j++) */ */ 41 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio if (flip(pmut)) { pool[i].string[j] = !new_pool[i].string[j]; } else { pool[i].string[j] = new_pool[i].string[j]; } split_xy(i); /* divide o cromossoma em x e y */ } } /* ******************************************** * normalize * * Técnica de Aptidão - Normalização Linear * ******************************************** */ double normalize(struct population pop[ ]) { int top, search; double sumfit; struct population temp; /* ordena os indivíduos em ordem decrescente */ for (top = 0; top < popsize - 1; top++) for (search = top +1; search < popsize; search ++) if (pop[search].fitness < pop[top].fitness) { temp = pool[search]; 42 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio pop[search] = pop[top]; pop[top] = temp; } /* normaliza a avaliação dos indivíduos */ sumfit = 0; for (top = 0; top < popsize; top++) { pop[popsize -1 - top].fitness = minimo + (((maximo - minimo) / (popsize - 1)) * top); sumfit += pop[popsize -1 - top].fitness; } return sumfit; } /* ****************************************** * * statistics * Print intermediary results * ****************************************** */ void statistics(FILE *file, double improvement) { int i, j; fprintf(file, "\nGeneration: %d\nSelected Strings\n", generations); /* individuos selecionados para reproducao */ for (i=0; i< popsize; i++) fprintf(file, " %d", selected[i]); fprintf(file, "\n"); 43 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio /* Imprime as seguintes informacoes para cada individuo da populacao: X: valor do individuo x Y: valor do individuo y f(x): aptidao do individuo New_String: o novo individuo X': o novo valor x do individuo Y': o novo valor y do individuo */ fprintf(file, "\nC\tX\tY\tf(x)\t Fitness\t New_String\tC'\tX'\tY'"); for (i=0; i< popsize; i++) { /* X, Y e f(x) */ fprintf(file, "\n %d\t%f\t%f\t%f\t%f ; ", pool[i].value_c, pool[i].value_x, pool[i].value_y, evaluate(pool[i].value_c, pool[i].value_x, pool[i].value_y), pool[i].fitness); /* New_String */ for (j=0; j<CHROM_LENGTH; j++) fprintf(file, "%d", pool[i].string[j]); /* X' e Y' */ fprintf(file, "\t%d\t%f\t%f", decode_c(i), decode_x(i), decode_y(i)); } fprintf(file, "\nImprovement: %f\n", improvement); } /* ************************************************* * pcrom * 44 Nota Técnica em Inteligência Computacional, ICA, PUC-Rio * Grava o iésimo cromossoma da geração * ************************************************* */ void pcrom(FILE *file, int i) { int j; fprintf(file, "\nGeneration: %d\n", generations + 1); for (j=0; j<CHROM_LENGTH; j++) fprintf(file, "%d", pool[i].string[j]); fprintf(file, "\t%d\t%f\t%f\t%f\t%f", decode_c(i), decode_x(i), decode_y(i), pool[i].fitness, evaluate(pool[i].value_c, pool[i].value_x, pool[i].value_y)); } //--------------------------------------------------------------------------- void __fastcall TForm2::Button3Click(TObject *Sender) { Query1->Close(); Query1->ParamByName("VUC")->AsInteger = StrToInt(Edit12->Text); Query1->Prepare(); Query1->Open(); } //--------------------------------------------------------------------------- 45