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
7constexpr int BUFFER_SIZE = 1024;
8
15
16
18{
19 geracoes++; // cada estado criado conta como uma geração
20}
21
25
27{
28 static const char* nomesAlgoritmos[] = {
29 "Escalada do Monte",
30 "Algoritmo Genético",
31 "Algoritmo Evolutivo" };
32 static const char* nomesMovePrimeiro[] = { "Primeiro","Melhor" };
33 static const char* nomesSelecao[] = {
34 "Roleta", // roleta implementada com Stochastic Universal Sampling (SUS)
35 "Torneio", // requere tamanho do torneio, se é determinístico, se é com reposição
36 "Uniforme" // todos com igual probabilidade
37 };
38 static const char* nomesSobrevivencia[] = {
39 "Idade",
40 "Substitui piores",
41 "round-robin" // cada elemento compete com q outros, os que perdem mais são eliminados
42 };
43 static const char* nomesDiversidade[] = {
44 "Nenhuma",
45 "Avaliação partilhada",
46 "Limpeza"
47 };
48
50
51 // alterar parametros base
52 Parametro(LIMITE_ITERACOES) = 1000000;
53 parametro[ALGORITMO] = { "ALGORITMO",3,1,3,"Escolha do algoritmo base a executar.", nomesAlgoritmos };
54
55 // adicionar parâmetros da procura melhorativa
56 parametro += {
57 { "POPULACAO", 20, 2, 1000000, "Número de elementos em cada geração", NULL, _TV("0,2,3") },
58 { "PROB_CRUZAR",100,0,100, "Probabilidade de um estado ser cruzado",NULL, _TV("0,3") },
59 { "PROB_MUTAR",50,0,100, "Probabilidade de um estado sofrer uma mutação após gerado",NULL, _TV("0,3") },
60 { "SELECAO",1,1,3, "Método de seleção dos pais para cruzamento", nomesSelecao, _TV("0,3") },
61 { "PRESSAO",150,100,200,
62"Pressão da seleção (1.0 a 2.0 > 100 a 200). \
63Controla a diferença de probabilidade entre o melhor e o pior indivíduo no método Ranking Selection.\n\
64Valores próximos de 1 (100) dão probabilidades quase iguais; valores próximos de 2 (200) favorecem fortemente os melhores.", NULL, TVector<int>({8,1}) },
65 { "TAMANHO_TORNEIO",2,2,100, "Tamanho do torneio, caso a sobrevivência seja do tipo torneio.", NULL, TVector<int>({8,2}) },
66 { "PROB_MELHOR_TORNEIO",100,0,100, "Probabilidade do melhor ganhar o torneio.", NULL, TVector<int>({8,2}) },
67 { "SOBREVIVENCIA",1,1,3, "Método de seleção dos elementos que sobrevivem à nova geração, utilizado nos Algoritmos Genéticos", nomesSobrevivencia, _TV("0,3") },
68 { "PERC_DESCENDENTES",100,0,100, "Número de descendentes a substituirem elementos na população, em percentagem (100 toda a população é substituída, 0 apenas um elemento)", NULL, _TV("0,3") },
69 { "Q_ROUND_ROBIN",3,2,100, "Número de elementos no round-robin (valor de q)", NULL, TVector<int>({12,3}) },
70 { "ELITISMO",1,0,100, "Número absoluto de indivíduos melhores, que se mantêm na geração seguinte, excepto se há descendência com valor igual ou superior", NULL, _TV("0,3") },
71 { "IMIGRANTES",1,0,100, "Número absoluto de indivíduos imigrantes, substituindo quaisquer outros na população.", NULL, _TV("0,3") },
72 { "DIVERSIDADE",3,1,3, "Estratégia de diversidade. ", nomesDiversidade, _TV("0,3") },
73 { "DIST_MINIMA",0,0,1000, "Distância mínima imposta entre elementos da população", NULL, _TV("0,2,3") },
74 { "MOVE_PRIMEIRO",1,1,2, "Utilizado na Escalada do Monte", nomesMovePrimeiro, _TV("0,1") }
75 };
76
77 // adicionar indicadores da procura melhorativa
78 indicador += {
79 { "Épocas", "Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.", IND_EPOCAS },
80 { "Gerações","número de estados gerados", IND_GERACOES }
81 };
83}
84
85// Retorna o valor da solucao completa actual.
87{
88 // dar informação de progresso, serão 128 pontos até ao limite de iterações
89 if (iteracoes % (Parametro(LIMITE_ITERACOES) >> 7) == 0)
90 Debug(ATIVIDADE, true, ".");
91 iteracoes++;
92 return custo;
93}
94
96// Algoritmo de procura local: Escalada do Monte
98// retorna a avaliacao do resultado actual
100{
101 bool movePrimeiro = (Parametro(MOVE_PRIMEIRO) == 1);
102 TPonto atual = this; // estado atual
103 TPonto melhor = this; // melhor estado para todas as escaladas
104 int procuras = 0;
105 TPonto solucao;
106 NovaSolucao();
107 melhor->custo = atual->custo = Avaliar(); // avaliar o proprio estado
108 // estado atual distinto do melhor
109 atual = solucao = (TProcuraMelhorativa*)Duplicar();
110 while (!melhor->Parar()) {
111 // iniciar uma escalada
112 epocas++;
113 // ponto de partida uma solução aleatória (local no espaço de soluções completas)
114 solucao->NovaSolucao();
115 atual->custo = solucao->Avaliar();
116 DebugInicioEM(++procuras, solucao);
117
118 while (!melhor->Parar()) {
119 // ver de entre os vizinhos, qual o melhor, para avançar um degrau
121 bool alterado = false;
122 solucao->Vizinhanca(vizinhos);
123 if (movePrimeiro) {
124 // move logo que encontre um vizinho melhor
125 // (pode estar a ser ignorados vizinhos melhores)
126 while (!vizinhos.Empty()) {
128 if (atual->custo > vizinhos.Last()->custo) {
129 solucao = MelhorAtual(atual, vizinhos, vizinhos.Count() - 1);
130 VerificaMelhor(melhor, atual);
131 // novos vizinhos a partir do estado atual são apagados
133 alterado = true;
134 }
135 else {
136 delete vizinhos.Last();
137 vizinhos.Pop();
138 }
139 }
140 }
141 else {
142 // analisa todos os vizinhos e avança apenas para o melhor vizinho
145 // trocar caso melhore
146 if (atual->custo > melhorValor) {
147 solucao = MelhorAtual(atual, vizinhos, melhorIndice);
148 VerificaMelhor(melhor, atual);
149 // novos vizinhos a partir do estado atual
150 alterado = true;
151 }
152 // tudo explorado, libertar
154 }
155 // final da análise da vizinhança, ver se se subiu alguma coisa
156 if (!alterado) {
157 // significa que estamos num óptimo local, no topo do moonte
158 DebugOptimoLocal(solucao);
159 break; // recomeçar nova escalada
160 }
161 else
162 DebugPassoEM(solucao);
163 }
164 }
165 //delete atual;
166 delete solucao;
167
168 return melhor->custo;
169}
170
173 solucao->Debug();
174}
175
176
178 Debug(PASSOS, false, ">> %d]", solucao->custo);
180 solucao->Debug();
181}
182
184{
185 if (Debug(PASSOS, true, "\nEscalada %d - ", ID) ||
186 Debug(DETALHE, false, "\n\nEscalada %d - ", ID))
187 solucao->Debug();
188}
189
190
192{
193 for (int i = 0; i < vector.Count(); i++)
194 if (i != excepto && vector[i] != NULL)
195 delete vector[i];
196 vector = {};
197}
198
200 if (melhor->custo > atual->custo) {
201 Copiar(atual);
202 custo = melhor->custo = atual->custo;
204 }
205}
206
208{
209 if (custo > atual->custo) {
210 Copiar(atual);
211 custo = atual->custo;
213 return true;
214 }
215 return false;
216}
217
219{
220 int custo = inverter ? 0 : INT_MAX;
221 for (int i = 0; i < populacao.Count(); i++)
222 if (inverter ? custo < populacao[i]->custo : custo > populacao[i]->custo)
224 return custo;
225}
226
228 atual->Copiar(vizinhos[indice]);
229 atual->custo = vizinhos[indice]->custo;
231 return (TProcuraMelhorativa*)atual;
232}
233
234
235void TProcuraMelhorativa::CalcularAvaliacoes(TVector<TPonto>& vizinhos, int& melhorValor, int& melhorIndice) {
236 for (int i = 0; i < vizinhos.Count(); i++) {
238 if (i == 0 || melhorValor > vizinhos[i]->custo) {
239 melhorValor = vizinhos[i]->custo;
240 melhorIndice = i;
241 }
242 }
243}
244
246// Algoritmo de procura local: Algoritmos Geneticos
248// retorna a avaliacao do resultado final
249// parametros para a mutacao e cruzamento podem ser dados em variaveis globais
251{
256 TVector<int> id;
257 TPonto melhor = this; // melhor estado para toda a procura
258 NovaSolucao();
259 melhor->Avaliar(); // avaliar o proprio
260 Debug(PASSOS, false, "\nPopulação inicial (%d elementos)", populacao);
261 // construir a geracao inicial
262 for (int i = 0; i < populacao; i++) {
264 geracaoAntiga.Last()->NovaSolucao();
265 geracaoAntiga.Last()->Avaliar();
267 }
268 while (!melhor->Parar()) {
269 // iniciar uma nova geração, com base na antiga
270 epocas++;
271
273 // cruzar conforme o custo
275 int minimo, maximo, total;
277 total = 0;
280 // calcular a probabilidade de um elemento ser selecionado
281 for (int i = 0; i < geracaoAntiga.Count(); i++) {
282 // cada elemento tem de ter sempre probabilidade de ser escolhido
283 // por isso adiciona-se 1 para que o custo maximo tenha probabilidade minima
284 probabilidade += (maximo - geracaoAntiga[i]->custo + 1);
285 total += probabilidade.Last();
286 }
287 // gerar novos elementos. gera-se o doubro para poder seleccionar os melhores
288 while (geracaoNova.Count() < 2 * populacao) {
289 // escolher dois individuos aleatoriamente de acordo com as probabilidades
290 int pai, mae, mutou = 0;
292 // gerar um novo individuo por cruzamento
294 geracaoNova.Last()->Cruzamento(geracaoAntiga[pai], geracaoAntiga[mae]);
295 // mudar o novo elemento, dependente da probabilidade
297 mutou = 1;
298 geracaoNova.Last()->Mutar();
299 }
300 // avaliar o valor do elemento
301 geracaoNova.Last()->Avaliar();
303 geracaoAntiga[pai]->custo,
305 geracaoNova.Last()->custo,
306 mutou);
308 }
309
310 // a nova geração já tem elementos, apagar a antiga
312 // seleccao: os melhores, com base no valor
314 // remover os elementos que são muito parecidos
315 for (int i = 0; i < populacao && i < geracaoNova.Count(); i++) {
316 // verificar se ha outro elemento muito parecido la
317 if (i > 0 && distanciaMinima > 0) {
318 bool diferente = true;
319 for (int j = 0; j < geracaoAntiga.Count(); j++)
321 diferente = false;
322 break;
323 }
324 if (!diferente)
325 continue;
326 }
327 // este elemento fica, passando para a geração antiga
329 geracaoNova[id[i]] = NULL;
330 }
331 // todos os novos que não se mantêm, são apagados
333 // tudo pronto para uma nova geração
334 }
335 // não há mais gerações, apagar tudo
337 return melhor->custo;
338}
339
340void TProcuraMelhorativa::DebugCruzamentoAG(int gPai, int gMae, int gFilho, int mutou)
341{
342 Debug(DETALHE, false, "\n Cruzar g %d x %d -> %d%s",
343 gPai, gMae, gFilho, mutou ? "*" : "");
344}
345
346void TProcuraMelhorativa::DebugPassoAG(int pop, int min, int max)
347{
348 Debug(PASSOS, false, "\nÉpoca %d #%d - %d|%d [%d-%d]",
349 epocas, pop, geracoes, iteracoes, min, max);
350}
351
352
354 TVector<int> valor;
355 for (int i = 0; i < populacao.Count(); i++)
356 valor += populacao[i]->custo;
357 valor.Sort(&id);
358}
359
360void TProcuraMelhorativa::Selecao(int& pai, int& mae, TVector<int>& pesos, int total) {
361 int valor = TRand::rand() % total;
362 pai = 0;
363 while (valor >= 0)
364 valor -= pesos[pai++];
365 pai--;
366 valor = TRand::rand() % total;
367 mae = 0;
368 while (valor >= 0)
369 valor -= pesos[mae++];
370 mae--;
371}
372
373void TProcuraMelhorativa::ObterExtremos(TVector<TPonto>& populacao, int& minCusto, int& maxCusto) {
374 minCusto = maxCusto = populacao.First()->custo;
375 for (auto elemento : populacao) {
376 if (elemento->custo < minCusto)
377 minCusto = elemento->custo;
378 if (elemento->custo > maxCusto)
379 maxCusto = elemento->custo;
380 }
381}
382
384{
386 Avaliar(); // avaliar a solução atual, fica sempre com o melhor resultado
387 while (!Parar()) {
388 // Repor o tamanho da população nesta geração
390 // Reportar informação sobre a geração
392 // Selecionar pais
394 // Gerar descendentes por cruzamento
395 // Mutar descendentes
396 // Avaliar descendentes
398 // Selecionar sobreviventes entre pais e descendentes
400 // Aplicar a diversidade
402 epocas++;
403 }
404 return custo;
405}
406
408 // mostrar informação sobre a população
409 if (Debug(PASSOS, false, "\n%s Época %d, população %d",
411 epoca,
412 populacao.Count()))
413 {
414 int minimo, maximo;
415 if (populacao.Empty())
416 return;
418 Debug(PASSOS, false, " (g: %d a %d)", minimo, maximo);
419 if (Parametro(NIVEL_DEBUG) == DETALHE) { // mostrar custos de toda a população
422 // mostrar diversidade da população
424 Debug(DETALHE, false, " [d: %d a %d (média %d, melhor/pior %d)]",
426 for (auto individuo : populacao)
427 custos += individuo->custo;
428 DebugTabela(DETALHE, custos, "Ind");
429 }
430 else if (Parametro(NIVEL_DEBUG) >= COMPLETO) { // mostrar diversidade da população
431 DebugPopulacaoAE(populacao, "\nPopulação:");
432 Debug(COMPLETO, false, "\nDiversidade:");
433 if (populacao.Count() <= 20) { // matriz de distâncias
434 Debug(COMPLETO, false, "\n |");
435 for (int i = 0; i < populacao.Count(); i++)
436 Debug(COMPLETO, false, "%4d|", i + 1);
437 Debug(COMPLETO, false, "\n----|");
438 for (int i = 0; i < populacao.Count(); i++)
439 Debug(COMPLETO, false, "----|");
440 for (int i = 0; i < populacao.Count(); i++) {
441 Debug(COMPLETO, false, "\n%4d|", i + 1);
442 for (int j = 0; j < populacao.Count(); j++)
443 if (i == j)
444 Debug(COMPLETO, false, " |");
445 else
446 Debug(COMPLETO, false, "%4d|", populacao[i]->Distancia(populacao[j]));
447 }
448 }
449 else { // distâncias entre dois elementos aleatórios
450 TVector<int> id;
451 for (int i = 0; i < populacao.Count(); i++)
452 id += i;
453 id.RandomOrder();
454 Debug(COMPLETO, false, "\nInd |Ind | g |\n----|----|----|");
455 for (int i = 0; i < id.Count(); i += 2)
456 Debug(COMPLETO, false, "\n%4d|%4d|%4d|",
457 id[i], id[i + 1], populacao[id[i]]->Distancia(populacao[id[i + 1]]));
458 }
459 }
460 }
461}
462
463void TProcuraMelhorativa::DebugPopulacaoAE(TVector<TPonto>& populacao, const char* titulo)
464{
465 Debug(COMPLETO, false, titulo);
466 for (int i = 0; i < populacao.Count(); i++) {
467 Debug(COMPLETO, false, "\n%4d: ", i + 1);
468 populacao[i]->Debug(false);
469 Debug(COMPLETO, false, " (g: %d)", populacao[i]->custo);
470 }
471}
472
474 int& minDist, int& maxDist, int& avgDist, int& melhorPior)
475{
476 // processar todos os pares
477 // Futuro: caso POPULACAO seja grande, processar apenas alguns pares
478 int contagem = 0, melhor = 0, pior = populacao.Count() - 1;
480 maxDist = 0;
481 avgDist = 0;
482 for (int i = 0; i < populacao.Count(); i++) {
484 melhor = i;
486 pior = i;
487 for (int j = i + 1; j < populacao.Count(); j++) {
488 int dist = populacao[i]->Distancia(populacao[j]);
489 if (dist < minDist)
490 minDist = dist;
491 if (dist > maxDist)
492 maxDist = dist;
493 avgDist += dist;
494 contagem++;
495 }
496 }
497 melhorPior = populacao[melhor]->Distancia(populacao[pior]);
498 if (contagem > 0)
499 avgDist /= contagem;
500 else
501 minDist = avgDist = maxDist = 0;
502}
503
504
506 while (populacao.Count() < Parametro(POPULACAO) && !Parar()) {
507 auto novo = Duplicar();
508 novo->NovaSolucao();
509 novo->Avaliar();
511 populacao += novo;
512 }
513 return populacao;
514}
515
518 // selecionar os pais, de acordo com o método escolhido
519 int descendentes = (Parametro(PERC_DESCENDENTES) * populacao.Count()) / 100;
520 int pop = populacao.Count();
521 if (descendentes < 1)
522 descendentes = 1;
523 else if (descendentes > pop)
525
526 Debug(COMPLETO, false, "\nFASE Selecionar %d pais", descendentes);
527 pais = {};
528 if (Parametro(SELECAO) == 1) { // roleta
529 // roleta implementada como Stochastic Universal Sampling (SUS)
530 TVector<int> id, peso;
533 Debug(COMPLETO, false, " - Roleta, pressão %d.", pressao);
535 peso.Count(id.Count());
536 peso.Reset(0);
537 for (int i = 0; i < id.Count(); i++)
538 peso[id[i]] = id.Count() - i;
539 for (int i = 0; i < populacao.Count(); i++) {
540 // calcular a probabilidade de um elemento ser selecionado
541 // utilizando o método Ranking Selection
542 probabilidades += ((2.0f - (float)pressao / 100.0f) / pop +
543 (2.0f * (peso[i] - 1) * ((float)pressao / 100.0f - 1.0f)) / (float)(pop * (pop - 1)));
544 if (i > 0)
546 }
547 probabilidades.Last() = 1;
550 for (int i = 0; i < probabilidades.Count(); i++)
551 prob += (int)((i == 0 ? probabilidades[i] :
552 probabilidades[i] - probabilidades[i - 1]) * 1000 + 0.5);
553 DebugTabela(COMPLETO, prob, "100%");
554 }
555 // escolher os pais (roleta implementado como SUS)
556 float valor = (float)(TRand::rand() % 10000) / (descendentes * 10000.0f);
557 for (int escolhido = 0; pais.Count() < descendentes; escolhido++) {
558 while (pais.Count() < descendentes && valor <= probabilidades[escolhido]) {
560 valor += 1.0f / (float)descendentes;
561 }
562 }
563 }
564 else if (Parametro(SELECAO) == 3) { // uniforme
565 Debug(COMPLETO, false, " - Uniforme");
566 for (int i = 0; i < descendentes; i++)
567 pais += populacao.Random();
568 }
569 else if (Parametro(SELECAO) == 2) { // torneio
572 Debug(COMPLETO, false, " - Torneio, tamanho %d, probabilidade melhor %d.",
574 for (int i = 0; i < descendentes; i++) {
576 TVector<int> id;
577 for (int j = 0; j < tamanho; j++)
579 // ordenar por custo
581 // escolher melhor ou segundo melhor
582 if ((TRand::rand() % 100) < (unsigned)probMelhor)
583 pais += competidores[id[0]];
584 else
585 pais += competidores[id[1 % tamanho]];
586 }
587 }
588 // reportar quantas vezes cada elemento foi pai
590 TVector<int> pai;
591 Debug(COMPLETO, false, "\nNúmero de seleções");
592 pai.Count(populacao.Count());
593 pai.Reset(0);
594 for (auto elemento : pais) {
595 int id = populacao.Find(elemento);
596 if (id >= 0)
597 pai[id]++;
598 }
599 DebugTabela(COMPLETO, pai, "#Pai");
600 }
601 return pais;
602}
603
606 int cruzamentos = 0, mutacoes = 0;
608 Debug(COMPLETO, false, "\nFASE Reproduzir %d pais\nPais emparelhados:", pais.Count());
609 pais.RandomOrder();
612 for (auto elemento : pais) {
613 int id = popoulacao.Find(elemento);
614 if (id >= 0)
615 paiID += (id + 1);
616 }
617 DebugTabela(COMPLETO, paiID, "IDs");
618 }
619 while (!pais.Empty()) {
620 TPonto pai = pais.Pop();
621 custoPais += pai->custo;
622
623 if (pais.Empty()) {
624 // não há mãe, apenas copiar o pai
625 descendentes += pai->Duplicar();
626 }
627 else {
628 TPonto mae = pais.Pop();
629 custoPais += mae->custo;
630 if (TRand::rand() % 100 < (unsigned)Parametro(PROB_CRUZAR)) {
631 // gerar um novo individuo por cruzamento
632 TPonto filho = pai->Duplicar();
633 filho->Cruzamento(pai, mae);
635 filho = mae->Duplicar();
636 filho->Cruzamento(mae, pai);
638 cruzamentos++;
639 }
640 else {
641 // copia o elemento sem alterações
642 descendentes += pai->Duplicar();
644 }
645 }
646 }
647 // mutar e avaliar descendentes
648 for (auto descendente : descendentes) {
649 // mudar o novo elemento, dependente da probabilidade
650 if (TRand::rand() % 100 < (unsigned)Parametro(PROB_MUTAR)) {
652 mutacoes++;
653 }
654 // avaliar o valor do elemento
655 descendente->Avaliar();
656 custoFilhos += descendente->custo;
658 }
659 Debug(COMPLETO, false, "\nCusto (g):");
661 Debug(COMPLETO, false, "\nFilhos (g) - %d cruzamentos, %d mutações",
664 return descendentes;
665}
666
672 Debug(COMPLETO, false, "\nFASE Selecionar sobreviventes");
673 if (nElite > 0) {
674 // 1. Copiar os N melhores da população atual
675 TVector<int> id;
676 OrdemValor(populacao, id); // melhor primeiro
677 for (int i = 0; i < nElite && i < populacao.Count(); i++) {
678 elite += populacao[id[i]]->Duplicar();
679 elite.Last()->custo = populacao[id[i]]->custo;
680 }
681 // encontrar o melhor descendente
683 Debug(COMPLETO, false, " - Elite %d (se < %d)",
685 }
686
687 if (Parametro(SOBREVIVENCIA) == 1) { // idade
688 Debug(COMPLETO, false, " - Idade");
689 // remover os mais velhos (os que estão mais tempo na população)
690 for (int i = 0; i < descendentes.Count() && i < populacao.Count(); i++) {
691 delete populacao[i];
692 populacao[i] = NULL;
693 }
694 populacao -= NULL;
696 descendentes = {};
697 }
698 else if (Parametro(SOBREVIVENCIA) == 2) { // substituir piores
700 Debug(COMPLETO, false, " - Substituir piores");
702 descendentes = {};
704 for (auto individuo : populacao)
705 custos += individuo->custo;
706 Debug(COMPLETO, false, "\nCustos em ambas gerações:");
707 DebugTabela(COMPLETO, custos, "Ind");
708 }
709 TVector<int> id;
710 OrdemValor(populacao, id); // ordena por custo (melhor primeiro)
712 for (int i = 0; i < Parametro(POPULACAO); i++) {
713 novaPopulacao += populacao[id[i]];
714 populacao[id[i]] = NULL;
715 }
718 }
719 else if (Parametro(SOBREVIVENCIA) == 3) { // round-robin
720 // cada elemento compete com q outros, os que perdem mais são eliminados
721 int q = Parametro(Q_ROUND_ROBIN); // número de competidores
723 Debug(COMPLETO, false, " - Round Robin (q: %d)", q);
725 descendentes = {};
727 for (auto individuo : populacao)
728 custos += individuo->custo;
729 Debug(COMPLETO, false, "\nCustos em ambas gerações:");
730 DebugTabela(COMPLETO, custos, "Ind");
731 }
732 perdas.Count(populacao.Count());
733 perdas.Reset(0);
734 for (int i = 0; i < populacao.Count(); i++) {
735 TPonto atual = populacao[i];
736 for (int j = 0; j < q; j++) {
738 do {
739 oponente = populacao.Random();
740 } while (oponente == atual && populacao.Count() > 1);
741 if (atual->custo > oponente->custo)
742 perdas[i]++;
743 }
744 }
745 Debug(COMPLETO, false, "\nNúmero de perdas:");
746 DebugTabela(COMPLETO, perdas, "Perd");
747 // ordenar por número de perdas
748 TVector<int> id;
749 perdas.Sort(&id);
751 for (int i = 0; i < Parametro(POPULACAO); i++) {
752 novaPopulacao += populacao[id[i]];
753 populacao[id[i]] = NULL;
754 }
757 }
758
759 if (imigrantes > 0) {
760 // 3. Adicionar novos elementos aleatórios
761 Debug(COMPLETO, false, " - Imigrantes %d", imigrantes);
762 for (int i = 0; i < imigrantes; i++) {
763 // remover um aleatório para dar lugar a um imigrante
764 int idx = TRand::rand() % populacao.Count();
765 delete populacao[idx];
766 populacao[idx] = NULL;
767 }
768 populacao -= NULL;
769 }
770
771 if (nElite > 0) {
772 // 2. Garantir que os elites estão presentes
773 // (apenas se forem melhores que o melhor descendente)
774 for (auto& e : elite) {
775 if (e->custo < melhorDescendente) {
776 // remover um aleatório para dar lugar ao elite
777 int idx = TRand::rand() % populacao.Count();
778 delete populacao[idx];
779 populacao[idx] = e;
780 }
781 else
782 delete e; // já não é necessário
783 }
784 }
785
786 return populacao;
787}
788
790{
792 if (Parametro(DIVERSIDADE) == 2) { // avaliação partilhada
794 int count = 0;
795 for (int i = 0; i < populacao.Count(); i++)
796 id += i;
797 Debug(COMPLETO, false, "\nFASE Diversidade - avaliação partilhada");
798 for (int j = 0; j < populacao.Count(); j++) {
799 if (id.Count() > 20)
800 id.RandomOrder();
801 for (int i = 0; i < id.Count() && i < 20; i++)
802 if (j != id[i] &&
804 populacao[j]->custo++; // soma 1 por cada elemento muito parecido
805 populacao[id[i]]->custo++;
806 count++;
807 penalizados += (id[i] + 1);
808 penalizados += (j + 1);
809 }
810 }
811 if (!penalizados.Empty()) {
812 penalizados.BeASet();
813 Debug(COMPLETO, false, " (%d penalizações aplicadas)", count);
815 }
816 }
817 else if (Parametro(DIVERSIDADE) == 3) { // limpeza
819 for (int i = 0; i < populacao.Count(); i++)
820 id += i;
821 Debug(COMPLETO, false, "\nFASE Diversidade - limpeza");
822 for (int j = 0; j < populacao.Count(); j++) {
823 if (id.Count() > 20)
824 id.RandomOrder();
825 for (int i = 0; i < id.Count() && i < 20; i++)
826 if (j != id[i] &&
828 {
829 remover += id[i];
830 //remover += j; // apenas um
831 id -= id[i];
832 id -= j;
833 break;
834 }
835 }
836 for (auto i : remover) {
837 delete populacao[i];
838 populacao[i] = NULL;
839 }
840 populacao -= NULL;
841 Debug(COMPLETO, false, " (%d removidos)", remover.Count());
842 }
843
844 return populacao;
845}
846
847
848// Chamar sempre que uma solucao melhor que a actual e encontrada
850{
851 if (Debug(ATIVIDADE, false, "\n%s Melhor solução (g:%d)",
853 Debug();
854}
855
857{
858 if (id == IND_EPOCAS)
859 return epocas;
860 else if (id == IND_GERACOES)
861 return geracoes;
862 return TProcura::Indicador(id);
863}
864
870
872 // escolher o algoritmo a executar
873 switch (Parametro(ALGORITMO)) {
874 case 1: return EscaladaDoMonte();
875 case 2: return AlgoritmoGenetico();
876 case 3: return AlgoritmoEvolutivo();
877 }
878 return -1;
879}
880
885 int opcao = 0, indA, indB, indC;
889 int epoca = 0;
890
891 Parametro(NIVEL_DEBUG) = EXTRA_DEBUG; // mostrar todo o debug existente, incluindo operadores
892 Parametro(POPULACAO) = 4; // manter um número baixo de elementos, só para explorar manualmente
893 Parametro(LIMITE_TEMPO) = 3600; // 1h para resolução manual
894
896 Avaliar();
897 populacao = {};
899 do {
901 opcao = NovoValor("\nOperação (1 - Mutar, 2 - Cruzar, 3 - Vizinhos): ");
902 Dominio(opcao, 0, 3);
903 if (opcao == 1) { // mutar
904 printf("Individuo [1-%d]: ", populacao.Count());
905 indA = NovoValor("") - 1;
906 Dominio(indA, 0, populacao.Count());
907 printf("\nAtual: ");
908 populacao[indA]->Debug(false);
909 populacao[indA]->Mutar();
910 printf("\nMutado: ");
911 populacao[indA]->Debug(false);
912 populacao[indA]->Avaliar();
914 populacao[indA]->Debug();
915 }
916 else if (opcao == 2) { // cruzar
917 printf("Pai [1-%d]: ", populacao.Count());
918 indA = NovoValor("") - 1;
919 printf("Mãe [1-%d]: ", populacao.Count());
920 indB = NovoValor("") - 1;
921 printf("Filho [1-%d]: ", populacao.Count());
922 indC = NovoValor("") - 1;
923 Dominio(indA, 0, populacao.Count());
924 Dominio(indB, 0, populacao.Count());
925 Dominio(indC, 0, populacao.Count());
926 printf("\nPai: ");
927 populacao[indA]->Debug(false);
928 printf("\nMãe: ");
929 populacao[indB]->Debug(false);
930 populacao[indC]->Cruzamento(populacao[indA], populacao[indB]);
931 printf("\nFilho: ");
932 populacao[indC]->Debug(false);
933 populacao[indC]->Avaliar();
935 populacao[indC]->Debug();
936 }
937 else if (opcao == 3) { // vizinhos
938 printf("Individuo [1-%d]: ", populacao.Count());
939 indA = NovoValor("") - 1;
940 Dominio(indA, 0, populacao.Count() - 1);
941 printf("\nAtual: ");
942 populacao[indA]->Debug(false);
943 populacao[indA]->Vizinhanca(vizinhos);
945 DebugPopulacaoAE(vizinhos, "\nVizinhos:");
946 printf("\nVizinho [1-%d]: ", vizinhos.Count());
947 indB = NovoValor("") - 1;
948 Dominio(indB, 0, vizinhos.Count() - 1);
949 delete populacao[indA];
951 vizinhos[indB] = NULL;
953 populacao[indA]->Debug();
955 }
956
957 epoca++;
958 } while (opcao > 0 && !Parar());
959
964}
965
966
constexpr int BUFFER_SIZE
@ IND_GERACOES
número de estados gerados durante a procura
@ IND_EPOCAS
Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.
@ DIVERSIDADE
@ PROB_CRUZAR
@ DIST_MINIMA
@ PROB_MUTAR
@ TAMANHO_TORNEIO
@ Q_ROUND_ROBIN
@ IMIGRANTES
@ MOVE_PRIMEIRO
@ PROB_MELHOR_TORNEIO
@ PERC_DESCENDENTES
@ SOBREVIVENCIA
@ POPULACAO
TProcuraMelhorativa * TPonto
@ PASSOS
Exibe passos intermediários.
Definition TProcura.h:65
@ EXTRA_DEBUG
Nível extra para debug muito detalhado (uso interno).
Definition TProcura.h:68
@ ATIVIDADE
Apenas eventos principais.
Definition TProcura.h:64
@ COMPLETO
Mostra toda a execução detalhadamente.
Definition TProcura.h:67
@ DETALHE
Debug detalhada sobre estados e decisões.
Definition TProcura.h:66
@ CONT_ALGORITMO
Tempo da execução do algoritmo por instância.
Definition TProcura.h:84
@ ALGORITMO
Algoritmo base a executar.
Definition TProcura.h:42
@ LIMITE_ITERACOES
Número máximo de iterações (0 significa sem limite).
Definition TProcura.h:46
@ NIVEL_DEBUG
Nível de debug, de reduzido a completo.
Definition TProcura.h:43
@ LIMITE_TEMPO
Tempo limite em segundos.
Definition TProcura.h:45
TVector< int > _TV(const char *str)
Definition TVector.h:1154
TVector< TPonto > SelecionarSobreviventesAE(TVector< TPonto > &populacao, TVector< TPonto > &descendentes)
void ObterExtremos(TVector< TPonto > &populacao, int &minCusto, int &maxCusto)
static int epocas
Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.
virtual void Mutar(void)
void LibertarVector(TVector< TPonto > &vector, int excepto=-1)
TVector< TPonto > SelecionarPaisAE(TVector< TPonto > &populacao)
virtual void Cruzamento(TPonto a, TPonto b)
void DebugPopulacaoAE(TVector< TPonto > &populacao, const char *titulo)
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)
virtual void NovaSolucao(void)
TPonto MelhorAtual(TPonto &atual, TVector< TPonto > &vizinhos, int indice)
void DebugOptimoLocal(TPonto solucao)
TVector< TPonto > AplicarDiversidadeAE(TVector< TPonto > &populacao)
TVector< TPonto > CompletarPopulacaoAE(TVector< TPonto > &populacao)
TVector< TPonto > ReproduzirAE(TVector< TPonto > &pais, TVector< TPonto > &populacao)
void DiversidadeAE(TVector< TPonto > &populacao, int &minDist, int &maxDist, int &avgDist, int &melhorPior)
void LimparEstatisticas()
Chapar antes da execução do algoritmo. Limpa valores estatísticos, e fixa o instante limite de tempo para...
void DebugMelhorEncontrado(TPonto ponto)
void Explorar() override
definir para explorar manualmente os dados (não definido em TProcura, apenas em TProcuraConstrutiva)
virtual int Avaliar(void)
void DebugGeracaoAE(int epoca, TVector< TPonto > &populacao)
int MelhorCusto(TVector< TPonto > &populacao, bool inverter=false)
int64_t Indicador(int id) override
Redefinição. Ver TProcura::Indicador().
void DebugPassoEM(TPonto solucao)
void DebugInicioEM(int ID, TPonto solucao)
int custo
Custo total, atualizada após Avaliar()
static int lowerBound
Lower Bound, se existir.
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)
virtual void Vizinhanca(TVector< TPonto > &vizinhos)
void ResetParametros() override
Inicializa os parametros, indicadores e instâncias.
bool Parar(void)
Verifica se a procura deve ser interrompida.
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.
static int geracoes
Número de estados gerados.
virtual void Debug(bool completo=true)
Mostra o estado no ecrã, para debug.
Definition TProcura.cpp:93
int Parametro(int id) const
Definition TProcura.h:522
static int Dominio(int &variavel, int min=INT_MIN, int max=INT_MAX)
Limita o domínio de um parâmetro inteiro.
static int resultado
Resultado retornado pelo algoritmo na última execução.
Definition TProcura.h:493
virtual int64_t Indicador(int id)
Retorna um indicador, após a execução do algoritmo.
Definition TProcura.cpp:80
static char * MostraTempo(double segundos)
Mostra tempo num formato humano.
Definition TProcura.cpp:281
static int iteracoes
Número total de iterações realizadas na última execução.
Definition TProcura.h:497
virtual void ResetParametros()
Inicializa os parametros, indicadores e instâncias.
Definition TProcura.cpp:47
static int NovoValor(const char *prompt)
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:488
void DebugTabela(ENivelDebug nivel, TVector< int >tabela, const char *tipo="")
Mostra uma tabela de inteiros, 10 elementos por linha, apenas se o nível de debug for igual ou superior...
static TVector< int > indAtivo
Definition TProcura.h:489
static TVector< TParametro > parametro
Parâmetros a serem utilizados na configuração atual.
Definition TProcura.h:485
static double Cronometro(enum ECronometro id=CONT_ALGORITMO, bool inicialiar=false)
retorna o tempo em segundos desde que o cronómetro foi inicializado
Definition TProcura.h:750
virtual void LimparEstatisticas()
Chapar antes da execução do algoritmo. Limpa valores estatísticos, e fixa o instante limite de tempo para...
Definition TProcura.cpp:99
TVector< Item > & RandomOrder()
Coloca os elementos em ordem aleatória (Fisher–Yates shuffle).
Definition TVector.h:752
TVector< Item > & Sort(TVector< int > *idxvect=nullptr)
Ordena todo o vetor, opcionalmente devolvendo índices ordenados.
Definition TVector.h:597
Item & Random()
Definition TVector.h:250
TVector< Item > & Reset(Item const &i)
Preenche todo o vetor com um mesmo valor.
Definition TVector.h:784
int Count() const
Definition TVector.h:227
int Find(Item &i, bool binary=false, int left=0, int right=-1)
Procura um elemento no vetor.
Definition TVector.h:567
unsigned int rand(int seq)
Retorna o próximo valor pseudo-aleatório.
Definition TRand.cpp:46