TProcura
Biblioteca em C++ para testes paramétricos de algoritmos, e coleção de algoritmos de procura e otimização
Loading...
Searching...
No Matches
TProcuraMelhorativa.cpp
Go to the documentation of this file.
2
3#include <stdio.h>
4#include <time.h>
5#include <string.h>
6
7
8#define BUFFER_SIZE 1024
9
10
14
18
20{
21 static const char* nomesAlgoritmos[] = {
22 "Largura Primeiro",
23 "Custo Uniforme",
24 "Profundidade Primeiro",
25 "Melhor Primeiro",
26 "A*",
27 "IDA*",
28 "Branch and Bound",
29 "Escaldada do Monte",
30 "Algoritmo Genético" };
31 static const char* nomesMovePrimeiro[] = { "Primeiro","Melhor" };
33
34 parametro[limiteIteracoes].valor = 1000000;
35
36 // adicionar parâmetros da procura melhorativa
37 // alterar algoritmos
38 parametro[algoritmo] = { "Algoritmo",1,1,9,"Escolha do algoritmo base a executar.", nomesAlgoritmos };
39
40 // move primeiro
41 parametro.Add({ "Move",1,1,2, "Utilizado na Escalada do Monte", nomesMovePrimeiro });
42 // população
43 parametro.Add({ "População",20,2,1000000, "Número de elementos em cada geração, utilizado nos Algoritmos Genéticos",NULL });
44 // probabilidade de mutação
45 parametro.Add({ "Mutação",50,0,100, "Probabilidade de um estado sofrer uma mutação após gerado, utilizado nos Algoritmos Genéticos",NULL });
46 // distância mínima
47 parametro.Add({ "Distância",0,0,1000, "Distância mínima imposta entre elementos da população, utilizado nos Algoritmos Genéticos",NULL });
48
49 indicador.Add({ "Épocas","Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.", indEpocas });
50 indicador.Add({ "Gerações","número de estados gerados", indGeracoes });
52}
53
54
55
56// e gerada uma nova solucao aleatoriamente. Este metodo e definido iniciamente como uma procura em
57// profundidade em que o sucessor e escolhido aleatoriamente e sem retrocesso (caso falhe o processo re-inicia)
62
63// Retorna o valor da solucao completa actual.
65{
66 iteracoes++;
67 return custo;
68}
69
70
71// Operador de vizinhanca (apenas em solucoes completas)
76
78// Algoritmo de procura local: Escalada do Monte
80// retorna a avaliacao do resultado actual
82{
83 bool movePrimeiro = (parametro[movePrimeiroEM].valor == 1);
84 TPonto atual = this; // estado atual
85 TPonto melhor = this; // melhor estado para todas as escaladas
86 int procuras = 0;
87 TPonto solucao;
89 melhor->custo = atual->custo = Avaliar(); // avaliar o proprio estado
90 // estado atual distinto do melhor
91 atual = solucao = (TProcuraMelhorativa*)Duplicar();
92 while (!melhor->Parar()) {
93 // iniciar uma escalada
94 epocas++;
95 // ponto de partida uma solução aleatória (local no espaço de soluções completas)
96 solucao->NovaSolucao();
97 atual->custo = solucao->Avaliar();
98 DebugInicioEM(++procuras, solucao);
99
100 while (!melhor->Parar()) {
101 // ver de entre os vizinhos, qual o melhor, para avançar um degrau
103 bool alterado = false;
104 solucao->Vizinhanca(vizinhos);
105 if (movePrimeiro) {
106 // move logo que encontre um vizinho melhor
107 // (pode estar a ser ignorados vizinhos melhores)
108 while (vizinhos.Count() > 0) {
110 if (atual->custo > vizinhos.Last()->custo) {
111 solucao = MelhorAtual(atual, vizinhos, vizinhos.Count() - 1);
112 VerificaMelhor(melhor, atual);
113 // novos vizinhos a partir do estado atual são apagados
115 alterado = true;
116 }
117 else {
118 delete vizinhos.Last();
119 vizinhos.Pop();
120 }
121 }
122 }
123 else {
124 // analisa todos os vizinhos e avança apenas para o melhor vizinho
127 // trocar caso melhore
128 if (atual->custo > melhorValor) {
129 solucao = MelhorAtual(atual, vizinhos, melhorIndice);
130 VerificaMelhor(melhor, atual);
131 // novos vizinhos a partir do estado atual
132 alterado = true;
133 }
134 // tudo explorado, libertar
136 }
137 // final da análise da vizinhança, ver se se subiu alguma coisa
138 if (!alterado) {
139 // significa que estamos num óptimo local, no topo do moonte
140 DebugOptimoLocal(solucao);
141 break; // recomeçar nova escalada
142 }
143 else
144 DebugPassoEM(solucao);
145 }
146 }
147 //delete atual;
148 delete solucao;
149
150 return melhor->custo;
151}
152
154 if (parametro[nivelDebug].valor > 2) {
155 if (parametro[nivelDebug].valor > 3)
156 solucao->Debug();
157 }
158}
159
160
162 if (parametro[nivelDebug].valor > 1) {
163 printf(">> %d]", solucao->custo);
164 if (parametro[nivelDebug].valor > 2) {
165 solucao->Debug();
166 }
167 }
168}
169
171{
172 if (parametro[nivelDebug].valor > 1) {
173 if (parametro[nivelDebug].valor > 2)
174 printf("\n");
175 printf("\nEscalada %d - ", ID);
176 solucao->Debug();
177 }
178 if (parametro[nivelDebug].valor > 1) {
179 if (parametro[nivelDebug].valor > 2)
180 printf("\n");
181 printf(" [%d >> ", solucao->custo);
182 if (parametro[nivelDebug].valor > 3)
183 solucao->Debug();
184 }
185}
186
187
189{
190 for (int i = 0; i < vector.Count(); i++)
191 if (i != excepto && vector[i] != NULL)
192 delete vector[i];
193 vector.Count(0);
194}
195
197 if (melhor->custo > atual->custo) {
198 Copiar(atual);
199 custo = melhor->custo = atual->custo;
201 }
202}
203
205 atual->Copiar(vizinhos[indice]);
206 atual->custo = vizinhos[indice]->custo;
208 return (TProcuraMelhorativa*)atual;
209}
210
211
212void TProcuraMelhorativa::CalcularAvaliacoes(TVector<TPonto>& vizinhos, int& melhorValor, int& melhorIndice) {
213 for (int i = 0; i < vizinhos.Count(); i++) {
215 if (i == 0 || melhorValor > vizinhos[i]->custo) {
216 melhorValor = vizinhos[i]->custo;
217 melhorIndice = i;
218 }
219 }
220}
221
223// Algoritmo de procura local: Algoritmos Geneticos
225// retorna a avaliacao do resultado final
226// parametros para a mutacao e cruzamento podem ser dados em variaveis globais
228{
229 int populacao = parametro[populacaoAG].valor;
233 TVector<int> id;
234 TPonto melhor = this; // melhor estado para toda a procura
235 NovaSolucao();
236 melhor->Avaliar(); // avaliar o proprio
237 if (parametro[nivelDebug].valor > 1)
238 printf("\nPopulação inicial (%d elementos)", populacao);
239 // construir a geracao inicial
240 for (int i = 0; i < populacao; i++) {
242 geracaoAntiga.Last()->NovaSolucao();
243 geracaoAntiga.Last()->Avaliar();
245 }
246 while (!melhor->Parar()) {
247 // iniciar uma nova geração, com base na antiga
248 epocas++;
249
251 // cruzar conforme o custo
253 int minimo, maximo, total;
255 total = 0;
258 // calcular a probabilidade de um elemento ser selecionado
259 for (int i = 0; i < geracaoAntiga.Count(); i++) {
260 // cada elemento tem de ter sempre probabilidade de ser escolhido
261 // por isso adiciona-se 1 para que o custo maximo tenha probabilidade minima
263 total += probabilidade.Last();
264 }
265 // gerar novos elementos. gera-se o doubro para poder seleccionar os melhores
266 while (geracaoNova.Count() < 2 * populacao) {
267 // escolher dois individuos aleatoriamente de acordo com as probabilidades
268 int pai, mae, mutou = 0;
270 // gerar um novo individuo por cruzamento
272 geracaoNova.Last()->Cruzamento(geracaoAntiga[pai], geracaoAntiga[mae]);
273 // mudar o novo elemento, dependente da probabilidade
274 if (TRand::rand() % 100 < (unsigned)probablidadeMutacao) {
275 mutou = 1;
276 geracaoNova.Last()->Mutar();
277 }
278 // avaliar o valor do elemento
279 geracaoNova.Last()->Avaliar();
281 geracaoAntiga[pai]->custo,
283 geracaoNova.Last()->custo,
284 mutou);
286 }
287
288 // a nova geração já tem elementos, apagar a antiga
290 // seleccao: os melhores, com base no valor
292 // remover os elementos que são muito parecidos
293 for (int i = 0; i < populacao && i < geracaoNova.Count(); i++) {
294 // verificar se ha outro elemento muito parecido la
295 if (i > 0 && distanciaMinima > 0) {
296 bool diferente = true;
297 for (int j = 0; j < geracaoAntiga.Count(); j++)
299 diferente = false;
300 break;
301 }
302 if (!diferente)
303 continue;
304 }
305 // este elemento fica, passando para a geração antiga
306 geracaoAntiga.Add(geracaoNova[id[i]]);
307 geracaoNova[id[i]] = NULL;
308 }
309 // todos os novos que não se mantêm, são apagados
311 // tudo pronto para uma nova geração
312 }
313 // não há mais gerações, apagar tudo
315 return melhor->custo;
316}
317
318void TProcuraMelhorativa::DebugCruzamentoAG(int gPai, int gMae, int gFilho, int mutou)
319{
320 if (parametro[nivelDebug].valor > 2)
321 printf("\n Cruzar g %d x %d -> %d%s",
322 gPai, gMae, gFilho, mutou ? "*" : "");
323}
324
325void TProcuraMelhorativa::DebugPassoAG(int pop, int min, int max)
326{
327 if (parametro[nivelDebug].valor == 1)
328 printf(".");
329 else if (parametro[nivelDebug].valor >= 2)
330 printf("\nÉpoca %d #%d - %d|%d [%d-%d]",
331 epocas, pop, geracoes, iteracoes, min, max);
332}
333
334
336 TVector<int> valor;
337 for (int i = 0; i < populacao.Count(); i++)
338 valor.Add(populacao[i]->custo);
339 valor.Sort(&id);
340}
341
342void TProcuraMelhorativa::Selecao(int& pai, int& mae, TVector<int>& pesos, int total) {
343 int valor = TRand::rand() % total;
344 pai = 0;
345 while (valor >= 0)
346 valor -= pesos[pai++];
347 pai--;
348 valor = TRand::rand() % total;
349 mae = 0;
350 while (valor >= 0)
351 valor -= pesos[mae++];
352 mae--;
353}
354
355void TProcuraMelhorativa::ObterExtremos(TVector<TPonto>& populacao, int& minCusto, int& maxCusto) {
356 for (int i = 0; i < populacao.Count(); i++) {
357 if (i == 0 || populacao[i]->custo < minCusto)
358 minCusto = populacao[i]->custo;
359 if (i == 0 || populacao[i]->custo > maxCusto)
360 maxCusto = populacao[i]->custo;
361 }
362}
363
364// Chamar sempre que uma solucao melhor que a actual e encontrada
366{
367 if (parametro[nivelDebug].valor > 0) {
368 Debug();
369 }
370 if (parametro[nivelDebug].valor > 2)
371 Debug();
372}
373
375{
376 if (id == indEpocas)
377 return epocas;
378 else if (id == indGeracoes)
379 return geracoes;
380 return TProcura::Indicador(id);
381}
382
388
389// Metodo para teste manual do objecto (chamadas aos algoritmos, construcao de uma solucao manual)
390// Este metodo destina-se a testes preliminares, e deve ser redefinido apenas se forem definidos novos algoritmos
392{
394 int selecao, resultado;
398 Inicializar();
400 while (true) {
401 printf("\n%s (TProcuraMelhorativa)", nome);
403 Debug();
405 printf("\n\
406_______________________________________________________________________________\n\
407| 1 - Inicializar | 2 - Explorar | 3 - Solução/Caminho |\n\
408| 4 - Parâmetros | 5 - Executar | 6 - Configurações | 7 - Teste");
409 if ((selecao = NovoValor("\nOpção: ")) == NAO_LIDO)
410 return;
411 switch (Dominio(selecao, 0, 8)) {
412 case 0: return;
413 case 1:
416 Inicializar();
417 NovaSolucao();
418 Avaliar();
419 break;
420 case 2:
421 Explorar();
422 break;
423 case 3: MostrarSolucao(); break;
424 case 4: EditarParametros(); break;
425 case 5:
426 // executar um algoritmo
430 printf("\nResultado: %d", resultado);
433 break;
434 case 6: EditarConfiguracoes(); break;
435 case 7:
438 NovoValor("Mostrar soluções? "),
439 NovoTexto("Ficheiro (nada para mostrar no ecrã):"));
440 break;
441 case 8: return;
442 default: printf("\nOpção não definida."); break;
443 }
444 }
445}
446
448 if (parametro[algoritmo].valor <= 7)
449 return -1;
450 if (parametro[algoritmo].valor == 8)
451 return EscaladaDoMonte();
452 if (parametro[algoritmo].valor == 9)
453 return AlgoritmoGenetico();
454 return -1;
455}
456
458 static int populacao = 1;
461 int opcao = 0, indA, indB, indC;
462
463 populacao = NovoValor("População (1 para vizinhos):");
464 if (populacao < 0)
465 populacao = 1;
466
467 if (populacao > 1) {
468 printf("\nTeste da Mutação e Cruzamento:");
469 elementos.Count(populacao);
470 for (int i = 0; i < populacao; i++) {
473 }
476 do {
477 // solicitar operação de mutação ou cruzamento
478 opcao = NovoValor("\nOperação (1 - Mutar, 2 - Cruzar): ");
479 Dominio(opcao, 0, 2);
480 if (opcao == 1) { // mutar
481 printf("Individuo [1-%d]: ", elementos.Count());
482 indA = NovoValor("") - 1;
483 elementos[Dominio(indA, 0, elementos.Count() - 1)]->Mutar();
484 }
485 else if (opcao == 2) { // cruzar
486 printf("Pai [1-%d]: ", elementos.Count());
487 indA = NovoValor("") - 1;
488 printf("Mãe [1-%d]: ", elementos.Count());
489 indB = NovoValor("") - 1;
490 printf("Filho [1-%d]: ", elementos.Count());
491 indC = NovoValor("") - 1;
492 Dominio(indA, 0, elementos.Count());
493 Dominio(indB, 0, elementos.Count());
494 Dominio(indC, 0, elementos.Count());
495 elementos[indC]->Cruzamento(elementos[indA], elementos[indB]);
496 }
497 if (opcao != 0) {
500 }
501 } while (opcao != 0);
502 }
503 else {
504 printf("\nTeste da Vizinhança:");
505 NovaSolucao();
506 do {
507 char str[BUFFER_SIZE];
508 custo = Avaliar();
511 // linha com informação
512 Debug();
514 if (elementos.Count() == 0) {
515 printf("\nSem vizinhos.");
516 opcao = 0;
517 }
518 else {
519 printf("\nVizinho (0 sai) [1-%d, ação]: ", elementos.Count());
521 opcao = atoi(str);
522 }
523 if (opcao > 0 && opcao <= elementos.Count()) {
524 Copiar(elementos[opcao - 1]);
525 custo = elementos[opcao - 1]->custo;
526 }
527 else if (strlen(str) > 1) {
528 opcao = Acao(strtok(str, " \t\n\r"));
529 }
531 } while (opcao != 0);
532 }
533}
534
535// Mostrar vizinhos
539
#define BUFFER_SIZE
@ indEpocas
Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.
@ indGeracoes
número de estados gerados durante a procura
@ probMutacaoAG
@ populacaoAG
@ distMinimaAG
@ movePrimeiroEM
TProcuraMelhorativa * TPonto
#define NAO_LIDO
Definition TProcura.h:13
@ seed
Semente aleatória para inicializar a sequência de números pseudo-aleatórios.
Definition TProcura.h:44
@ nivelDebug
Nível de debug, de reduzido a completo.
Definition TProcura.h:43
@ algoritmo
Algoritmo base a executar.
Definition TProcura.h:42
@ limiteIteracoes
Número máximo de iterações (0 significa sem limite).
Definition TProcura.h:46
virtual void NovaSolucao(void)
bool Acao(const char *acao)
void ObterExtremos(TVector< TPonto > &populacao, int &minCusto, int &maxCusto)
int epocas
Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.
void LibertarVector(TVector< TPonto > &vector, int excepto=-1)
int Indicador(int id) override
Redefinição. Ver TProcura::Indicador().
virtual void Copiar(TPonto objecto)
Fica com uma cópia do objecto.
void DebugPassoAG(int pop, int min, int max)
void CalcularAvaliacoes(TVector< TPonto > &vizinhos, int &melhorValor, int &melhorIndice)
void TesteManualX(const char *nome)
provavelmente apagar
TPonto MelhorAtual(TPonto &atual, TVector< TPonto > &vizinhos, int indice)
void DebugOptimoLocal(TPonto solucao)
void DebugMelhorEncontrado(TPonto ponto)
provavalmente apagar
void DebugVizinhos(TVector< TPonto > &vizinhos)
void Explorar() override
definir para explorar manualmente os dados (não definido em TProcura, apenas em TProcuraConstrutiva)
virtual void Vizinhanca(TVector< TPonto > &vizinhos)
void LimparEstatisticas(clock_t &inicio)
Chapar antes da execução do algoritmo. Limpa valores estatísticos, e fixa o instante limite de tempo para...
virtual int Avaliar(void)
void DebugPassoEM(TPonto solucao)
void DebugInicioEM(int ID, TPonto solucao)
int custo
Custo total, atualizada após Avaliar()
virtual int Distancia(TPonto a)
void Selecao(int &pai, int &mae, TVector< int > &pesos, int total)
void DebugCruzamentoAG(int gPai, int gMae, int gFilho, int mutou)
void ResetParametros() override
Inicializa os parametros, indicadores e instâncias.
void VerificaMelhor(TPonto &melhor, TPonto atual)
void OrdemValor(TVector< TPonto > &populacao, TVector< int > &id)
int ExecutaAlgoritmo()
Executa o algoritmo com os parametros atuais.
virtual TPonto Duplicar(void)=0
Cria um objecto que é uma cópia deste.
int geracoes
Número de estados gerados.
virtual void MostrarSolucao()
definir para visualizar a solução
Definition TProcura.cpp:889
static int Dominio(int &variavel, int min=INT_MIN, int max=INT_MAX)
Limita o domínio de um parâmetro inteiro.
Definition TProcura.cpp:941
static char * NovoTexto(const char *prompt)
Definition TProcura.cpp:908
virtual void Inicializar(void)
Coloca o objecto no estado inicial da procura.
Definition TProcura.h:182
static int resultado
Resultado retornado pelo algoritmo na última execução.
Definition TProcura.h:459
virtual int Indicador(int id)
Retorna um indicador, após a execução do algoritmo.
Definition TProcura.cpp:74
static int iteracoes
Número total de iterações realizadas na última execução.
Definition TProcura.h:463
TVector< int > SolicitaInstancias()
Solicita ao utilizador uma lista de instâncias.
Definition TProcura.cpp:345
virtual void ResetParametros()
Inicializa os parametros, indicadores e instâncias.
Definition TProcura.cpp:37
void MostraParametros(int detalhe=1, TVector< int > *idParametros=NULL)
Mostra os parâmetros atuais.
Definition TProcura.cpp:155
virtual void ExecucaoTerminada(clock_t inicio)
Chamar após a execução do algoritmo. Grava o tempo consumido.
Definition TProcura.cpp:879
void MostraRelatorio(TVector< TResultado > &resultados, bool ultimo=false)
Mostra um relatório dos resultados.
Definition TProcura.cpp:705
virtual void Debug(void)
Mostra o estado no ecrã, para debug.
Definition TProcura.cpp:87
static int NovoValor(const char *prompt)
Definition TProcura.cpp:898
static TVector< TIndicador > indicador
Indicadores que podem ser calculados após a execução, quer com informação da instãncia, quer com resultado da ...
Definition TProcura.h:454
void EditarParametros()
Permite ao utilizador editar os parâmetros.
Definition TProcura.cpp:213
static TVector< int > indAtivo
Definition TProcura.h:455
static TParametro instancia
ID da instância atual, a ser utilizado em SolucaoVazia().
Definition TProcura.h:21
void InserirRegisto(TVector< TResultado > &resultados, int inst, int conf)
Insere um novo registo de resultados.
Definition TProcura.cpp:273
virtual void LimparEstatisticas(clock_t &inicio)
Chapar antes da execução do algoritmo. Limpa valores estatísticos, e fixa o instante limite de tempo para...
Definition TProcura.cpp:94
static TVector< TParametro > parametro
Parâmetros a serem utilizados na configuração atual.
Definition TProcura.h:451
void EditarConfiguracoes()
Permite ao utilizador editar as configurações.
Definition TProcura.cpp:361
void SolicitaInstancia()
Solicita ao utilizador o ID da instância a utilizar, permitindo alterar também o prefixo do ficheiro.
Definition TProcura.cpp:916
int Parametro(int id)
Definition TProcura.h:479
virtual void TesteEmpirico(TVector< int > instancias, bool mostrarSolucoes=true, char *ficheiro=NULL)
Executa testes empíricos, em todas as configurações guardadas, nas instâncias selecionadas.
Definition TProcura.cpp:509
TVector< Item > & Sort(TVector< int > *idxvect=nullptr)
Ordena todo o vetor, opcionalmente devolvendo índices ordenados.
Definition TVector.h:539
TVector< Item > & Add(Item a)
Definition TVector.h:115
int Count() const
Definition TVector.h:160
unsigned int rand(int seq)
Retorna o próximo valor pseudo-aleatório.
Definition TRand.cpp:46
void srand(unsigned int seed, int seq)
Inicializa a semente da geração pseudo-aleatória.
Definition TRand.cpp:34
int valor
valor do parametro
Definition TProcura.h:114