Post on 09-Jan-2017
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 jose.rocha@lightrio.com.br
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
Período Único
Ultrapassagem
Período Único
Demanda
Ponta
Ultrapassagem
Ponta
Demanda
Fora Ponta
Ultrapassagem
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 4
início
inicialização da população
cálculo da aptidão
solução encontrada
?
seleção
reprodução
fim
mutação
Sim
Não
Figura 2 – Estrutura básica de um Algoritmo Genético
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 10
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).
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]; /* a primeira metade do cromossoma representa a coordenada x */
unsigned char string_y[(CHROM_LENGTH-2)/2]; /* a segunda metade do cromossoma representa a coordenada y */
unsigned char string[CHROM_LENGTH]; /* o cromossoma inteiro */
double fitness;
};
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 12
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 */
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 13
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")||
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 14
(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);
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 15
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);
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 16
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 17
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 18
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 */
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 19
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)+" ";
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 21
}
/* 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);
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 22
}
/* 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")
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 23
{
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 *
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 24
******************************************
*/
/* 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 */
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 25
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 26
/* 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];
}
}
/*
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 27
*******************************************************************************
* 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 */
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 28
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)
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 29
{
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 30
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 31
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 :
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 32
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 33
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)
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 34
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);
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 35
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 36
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 37
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;
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 38
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
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 39
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
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 41
/* 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++)
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 42
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];
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 43
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");
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 44
/*
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 *
Nota Técnica em Inteligência Computacional, ICA, PUC-Rio 45
* 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();
}
//---------------------------------------------------------------------------