UNIVERSIDADE FEDERAL DE UBERLÂNDIA

Faculdade de Engenharia Elétrica




ALGORÍTMOS GENÉTICOS
Prof. Keiji Yamanaka




Algoritmos Genéticos – Problema de Scheduling





Luis Paulo Fagundes

Uberlândia
2014
Resumo

Um problema comum em sistemas de geração e distribuição de energia é o
agendamento da manutenção de geradores. Os sistemas elétricos trabalham
usualmente próximo de sua capacidade máxima, e enfrenta como desafio a variação
das demandas por energia ao longo do ano. Neste contexto o presente trabalho tem
por objetivo propor um algoritmo genético que seja capaz de encontrar uma solução
para o problema de agendamento de manutenção, de forma a maximizar a potência
líquida em todos os períodos do ano minimizando a variância da potência líquida ao
longo do ano.
Palavras-chave: Algoritmos genéticos, inteligência artificial, sistemas de geração de energia,
problema de scheduling.
Abstract
A common problem in power generation and distribution system is the generators
maintenance scheduling. Electrical system usuallly works close to its maximum
capacity, and faces the challenge of varying energy demands throughout the year. In
this context, this paper aims to propose a genetic algorithm which is able to find a
solution to the problem of maintenance scheduling, to maximize the net power in all
periods of the year minimizing the variance of net power throughout the year .
Keywords: Genetic Algorithm, artificial intelligence, power generation system, scheduling problem.
Sumário

Introdução.......................................................................................Pág 01
Desenvolvimento............................................................................Pág 02
Conclusão.......................................................................................Pág 04
Referências Bibliográficas.............................................................Pág 05
Apêndice A (Código fonte do programa).........................................Pág 06




















Introdução
As técnicas de otimização buscam encontrar pontos de ótimo em sistemas ou
processos. Tal ponto de ótimo poderia ser considerado os parâmetros de operação
de uma planta onde se teria uma maximização dos lucros, ou mesmo na busca de
estratégias de distribuição e logística que minimizariam as despesas. Uma técnica
que tem se destacado neste sentido, é o uso de algoritmos genéticos.
Dentro deste contexto de otimização um problema muito comum é o de
agendamento de manutenção. Tal problema consiste em encontrar uma escala para
manutenção de equipamentos de forma a atender as demandas, reduzir custos e
maximizar os lucros, consistindo assim em um problema de otimização com
restrições.
Os algoritmos genéticos visam encontrar soluções para problemas complexos
nos quais a abordagem analítica é demasiada complexa, ou até mesmo impossível.
Assim o fato do problema de agendamento de manutenção apresentar uma natureza
combinatória, o torna ideal para uma abordagem via algoritmos genéticos (Roberto,
2004).
O problema abordado neste trabalho consiste na obtenção de uma escala de
manutenção para sete geradores, com capacidades máximas variadas e requisitos
de tempo de manutenção. A tabela 1 mostra a capacidade máxima de cada gerador
bem como o tempo de manutenção necessário.
Número unidade Capacidade (MW) Número de intervalo de
manutenção/ano
1 20 2
2 15 2
3 35 1
4 40 1
5 15 1
6 15 1
7 10 1
Tabela 1 – Capacidade e tempo de manutenção de geradores. Fonte: Elaboração própria.
Além do problema da capacidade e número de manutenção variar para cada
unidade, ainda tem-se a demanda variando ao longo do ano como na tabela 2.

Período do ano Demanda em MW
Pd1 80
Pd2 90
Pd3 65
Pd4 70
Tabela 2 – Variação da demanda. Fonte: Elaboração própria.
A potência líquida é dada pela fórmula:
PL=Pt-Pp-Pd
Onde,
PL= potência líquida;
Pt= potência total ou capacidade máxima de geração;
Pp= potência perdida por equipamento parado devido a manutenção;
Pd= potência demandada no período em questão.
A potência líquida deve ser igual ou superior a zero para cada período. Deve-
se minimizar a variância da potência líquida de forma a evitar que um período fique
com potência líquida zero e outros fiquem com potência líquida muito alta.
O sistema de geração e distribuição deve atender a demanda de cada
período e ainda executar a manutenção nos geradores, de forma que ao final do ano
todos os geradores tenham sofrido manutenção.

Desenvolvimento
A população neste problema constituiu do espaço de solução, no qual cada
individuo era uma sequencia de agendamentos de manutenção.
A fim de codificar o problema adequadamente, os indivíduos foram
codificados contendo 7 posições cada, referentes a cada gerador. Assim a posição 1
representava o gerador 1, a posição 2 o gerador 2, geração 3 o gerador 3, e assim
por diante.
Em cada posição, um valor de 1 a 4 foi definido de forma aleatório,
representando o período inicial de manutenção. Logo o indivíduo [1 3 4 3 4 3 2],
apresentou a seguinte tabela de manutenção.

Figura 1 – Parada de manutenção para o individuo [1 3 4 3 4 3 2]. Fonte: Elaboração própria.
Nesta codificação um cuidado teve de ser tomado foi com relação aos
geradores 1 e 2, pelo fato de os mesmos gastarem 2 períodos de manutenção, não
podendo portanto, iniciar após o período 3. Os demais geradores podiam variar de 1
a 4.
O método de seleção escolhido para tratar esse problema foi a roleta, outros
métodos poderiam ter sido utilizados, sendo este escolhido apenas por questão de
familiaridade do autor.
Abaixo na figura 2 tem-se a interface gráfica para resolução do problema.

Figura 2 – Interface para solução do problema. Fone: Elaboração própria.
Abaixo pode-se observar na figura 3, um caso em que o ótimo foi encontrado
na décima quinta geração.

Figura 3 – Obtenção do ótimo na décima quinta geração. Fonte: Elaboração própria.
Podemos observar que no melhor cenário, a potência líquida é otimizada em
30, 25, 25 e 30 para os períodos 1,2,3 e 4 respectivamente. Esta ordem pode
mudar, mas sempre encontraremos os valores de 30 e 25 presentes na melhor
solução.

Conclusão
Os algoritmos genéticos são suscetíveis a diversos fatores e casos. No
presente trabalho, a mutação apresentou resultados melhores quando o seu valor
era baixo, cerca de 1%, e impossibilitou a convergência em determinadas situações
quando seu valor estava acima de 5%.
O presente trabalhou permitiu uma abordagem de um problema de difícil
solução, que faz parte do escopo de serviço de diversos engenheiros, de forma
simples e com resultados satisfatórios.

Referências Bibliográficas
Roberto, M. L.R. Programação ótima de desligamentos em redes de energia elétrica
utilizando algoritmos genéticos. Niterói: 2004.
CATARINA, A.S. Algoritmos evolutivos aplicados ao processo de análise de dados
geográficos. São José dos Campos: [s,n], 2005.
Melanie, M. An introduction to genetic algorithms. Massachusetts: Cambridge, 1998.
SOARES, Gustavo L. Algoritmos Genéticos: Estudo, Novas técnicas e Aplicações.
Belo Horizonte: UFMG, 1997.


















Apêndice A (Código fonte do programa)
function varargout = AG_TRAB04(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @AG_TRAB04_OpeningFcn, ...
'gui_OutputFcn', @AG_TRAB04_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
end



% --- Executes just before AG_TRAB04 is made visible.
function AG_TRAB04_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to AG_TRAB04 (see VARARGIN)
set(findobj(gcf,'Tag','populacao_text_box'),'String',20);
set(findobj(gcf,'Tag','tx_cruzamento_text_box'),'String',0.8);
set(findobj(gcf,'Tag','tx_mutacao_text_box'),'String',0.05);
set(findobj(gcf,'Tag','geracoes_text_box'),'String',1);

% Choose default command line output for AG_TRAB04
handles.output = hObject;
global geracao;
geracao=0;
% Update handles structure
guidata(hObject, handles);

% UIWAIT makes AG_TRAB04 wait for user response (see UIRESUME)
% uiwait(handles.figure1);
end


function Ger_Pop_Callback(hObject, eventdata, handles)
% hObject handle to Ger_Pop (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global populacao tasks PotenciaPerdida PotenciaDemandada
global PotenciaLiquidaTotal Fitness
global FitnessDesvio Melhor_Fitness Index_MF List_PL_Liquida tabela_marca
global Melhor_sequencia data geracao

clearvars PotenciaLiquidaTotal FitnessDesvio List_PL_Liquida
clearvars tabela_marca Melhor_sequencia data
cla(handles.axes1);
cla(handles.axes2);
geracao=0;
for d=1:7
for f=1:4
tabela_marca(d,f)=' ';
end
end
data=num2cell(tabela_marca);
set(handles.Tabela,'data',data);
PotenciaDemandada=[80 90 65 70];
populacao = str2double(get(handles.populacao_text_box,'String'));
for i=1:populacao
for j=1:7
tasks(i,j)=0;
end
end
for i=1:populacao

for k=1:4
PotenciaPerdida(i,k)=0;
PotenciaLiquida(i,k)=0;
end
for j=1:7

if(j==1 || j==2)
tasks(i,j)=randi(3,1);
else
tasks(i,j)=randi(4,1);
end

if(j==1)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+20;

PotenciaPerdida(i,(tasks(i,j)+1))=PotenciaPerdida(i,(tasks(i,j)+1))+20;
end
if(j==2)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+15;

PotenciaPerdida(i,(tasks(i,j)+1))=PotenciaPerdida(i,(tasks(i,j)+1))+15;
end
if(j==3)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+35;
end
if(j==4)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+40;
end
if(j==5)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+15;
end
if(j==6)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+15;
end
if(j==7)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+10;
end
end
for z=1:4
PotenciaLiquida(i,z)=150-PotenciaPerdida(i,z)-
PotenciaDemandada(1,z);
end
PotenciaLiquidaTotal=sum(PotenciaLiquida,2);

FitnessDesvio(i)=sqrt(((PotenciaLiquida(i,1)-27.5)^2)+
((PotenciaLiquida(i,2)-27.5)^2)+ ((PotenciaLiquida(i,3)-27.5)^2)+
((PotenciaLiquida(i,4)-27.5)^2));

Fitness=PotenciaLiquidaTotal-FitnessDesvio';

[Melhor_Fitness,Index_MF]=max(Fitness);
Melhor_sequencia=tasks(Index_MF,:);

set(findobj(gcf,'Tag','Melhor_fitness_text_box'),'String',Melhor_Fitness);
for y=1:4
handles.List_PL_Liquida(y)=PotenciaLiquida(Index_MF,y);
set(handles.listbox_PL,'String',handles.List_PL_Liquida);
end

end
for d=1:7

if(d==1 || d==2)
tabela_marca(d,Melhor_sequencia(1,d))='x';
tabela_marca(d,(Melhor_sequencia(1,d)+1))='x';
else
if(d==3)
tabela_marca(3,Melhor_sequencia(1,d))='x';
end
if(d==4)
tabela_marca(4,Melhor_sequencia(1,d))='x';
end
if(d==5)
tabela_marca(5,Melhor_sequencia(1,d))='x';
end
if(d==6)
tabela_marca(6,Melhor_sequencia(1,d))='x';
end
if(d==7)
tabela_marca(7,Melhor_sequencia(1,d))='x';
end

end

end

data=num2cell(tabela_marca);
set(handles.Tabela,'data',data);
end


% --- Executes on button press in prox_geracao.
function prox_geracao_Callback(hObject, eventdata, handles)
% hObject handle to prox_geracao (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global populacao tasks PotenciaPerdida PotenciaDemandada
global PotenciaLiquidaTotal Fitness probabilidade_individual
global NovoFitnessDesvio Melhor_Fitness Index_MF List_PL_Liquida
tabela_marca
global Melhor_sequencia tasks_filho Segundo_melhor_Fitness
global probabilidade_acumulada Novo_Melhor_Fitness data2 data geracao
geracoes= str2num(get(handles.geracoes_text_box,'String'));
for l=1:geracoes
Novo_Melhor_Fitness=0;
geracao=geracao+1;
clearvars data tabela_marca
for i=1:populacao
for j=1:7
tasks_filho(i,j)=0;
end
for d=1:4
PotenciaPerdida(i,d)=0;
end
end
for d=1:7
for f=1:4
tabela_marca(d,f)=' ';
end
end
%elitismo: determinar os dois melhores individuos
Segundo_melhor_Fitness=0;
for i=1:populacao
if(Fitness(i)>Segundo_melhor_Fitness && Fitness(i)<Melhor_Fitness)
Segundo_melhor_Fitness=Fitness(i);
Index_SMF=i;
end
end
for k=1:7
tasks_filho(1,k)=tasks(Index_MF,k);
tasks_filho(2,k)=tasks(Index_SMF,k);
end

%Roleta
soma= sum(Fitness); %calcula a soma do fitness da população
%inicializar variáveis

%calculo da probabilidade individual
for i=1:populacao
probabilidade_individual(i)=Fitness(i)/soma;
end

%calculo da probabilidade acumulada
probabilidade_acumulada(1)=probabilidade_individual(1);
for i=2:populacao

probabilidade_acumulada(i)=probabilidade_individual(i)+probabilidade_acumul
ada(i-1);
end


novapopulacao=populacao/2;


for i=3:novapopulacao+1
%Sorteio pai1 dos X
sorteio_roleta=rand();
for j=1:populacao
if(probabilidade_acumulada(j)>sorteio_roleta)
indice_sorteado=(j);
break;
end
end
task1_sorteado=tasks(indice_sorteado,:);

%Sorteio pai2 dos X
sorteio_roleta=rand();
for j=1:populacao
if(probabilidade_acumulada(j)>sorteio_roleta)
indice_sorteado=(j);
break;
end
end
task2_sorteado=tasks(indice_sorteado,:);

%Cruzamento

taxa_cruzamento=str2num(get(handles.tx_cruzamento_text_box,'String'));
tx_cruzamento_sorteada=rand();

if(tx_cruzamento_sorteada<taxa_cruzamento)

ponto_de_cruzamento=randi(7,1);
filho1=[task1_sorteado(1:ponto_de_cruzamento)
task2_sorteado(ponto_de_cruzamento+1:end)];
filho2=[task2_sorteado(1:ponto_de_cruzamento)
task1_sorteado(ponto_de_cruzamento+1:end)];
else
filho1=task1_sorteado;
filho2=task2_sorteado;
end

%Mutacaooo

taxa_mutacao=str2double(get(handles.tx_mutacao_text_box,'String'));
for j=1:7
taxa_mutacao_sorteada=rand();
if(j==1 || j==2)
if(taxa_mutacao_sorteada<taxa_mutacao)
filho1(j)=randi(3,1);
end
else
if(taxa_mutacao_sorteada<taxa_mutacao)
filho1(j)=randi(4,1);
end
end

end
for j=1:7
taxa_mutacao_sorteada=rand();
if(j==1 || j==2)
if(taxa_mutacao_sorteada<taxa_mutacao)
filho2(j)=randi(3,1);
end
else
if(taxa_mutacao_sorteada<taxa_mutacao)
filho2(j)=randi(4,1);
end
end

end

tasks_filho(i,:)=filho1;
tasks_filho(((populacao+3)-i),:)=filho2;



end
for d=1:populacao
tasks(d,:)=tasks_filho(d,:);
end
for i=1:populacao
for j=1:7
if(j==1)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+20;

PotenciaPerdida(i,(tasks(i,j)+1))=PotenciaPerdida(i,(tasks(i,j)+1))+20;
end
if(j==2)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+15;

PotenciaPerdida(i,(tasks(i,j)+1))=PotenciaPerdida(i,(tasks(i,j)+1))+15;
end
if(j==3)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+35;
end
if(j==4)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+40;
end
if(j==5)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+15;
end
if(j==6)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+15;
end
if(j==7)

PotenciaPerdida(i,(tasks(i,j)))=PotenciaPerdida(i,(tasks(i,j)))+10;
end
end

for z=1:4
PotenciaLiquida(i,z)=150-PotenciaPerdida(i,z)-
PotenciaDemandada(1,z);
end
PotenciaLiquidaTotal=sum(PotenciaLiquida,2);

NovoFitnessDesvio(i)=sqrt(((PotenciaLiquida(i,1)-27.5)^2)+
((PotenciaLiquida(i,2)-27.5)^2)+ ((PotenciaLiquida(i,3)-27.5)^2)+
((PotenciaLiquida(i,4)-27.5)^2));

Fitness(i)=PotenciaLiquidaTotal(i)-NovoFitnessDesvio(i);
end
[Novo_Melhor_Fitness,Index_NMF]=max(Fitness);
Melhor_sequencia=tasks(Index_NMF,:);
if(Novo_Melhor_Fitness>=Melhor_Fitness)
Melhor_Fitness=Novo_Melhor_Fitness;
Index_MF=Index_NMF;
end

set(findobj(gcf,'Tag','Melhor_fitness_text_box'),'String',Melhor_Fitness);
for y=1:4
handles.List_PL_Liquida(y)=PotenciaLiquida(Index_MF,y);
set(handles.listbox_PL,'String',handles.List_PL_Liquida);
end
for d=1:7

if(d==1 || d==2)
tabela_marca(d,Melhor_sequencia(1,d))='x';
tabela_marca(d,(Melhor_sequencia(1,d)+1))='x';
else
if(d==3)
tabela_marca(3,Melhor_sequencia(1,d))='x';
end
if(d==4)
tabela_marca(4,Melhor_sequencia(1,d))='x';
end
if(d==5)
tabela_marca(5,Melhor_sequencia(1,d))='x';
end
if(d==6)
tabela_marca(6,Melhor_sequencia(1,d))='x';
end
if(d==7)
tabela_marca(7,Melhor_sequencia(1,d))='x';
end

end

end

data2=num2cell(tabela_marca);
set(handles.Tabela,'data',data2);
%Melhor individuo
axes(handles.axes1);
aptidao=Melhor_Fitness;
hold on;
plot(geracao,aptidao,'r*');
%Média da população
axes(handles.axes2);
media=(sum(Fitness)/(populacao));
hold on;
plot(geracao,media,'r*');
end
end