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
17
18
20{
21 geracoes++; // cada estado criado conta como uma geração
22}
23
27
29{
31
32 // alterar parâmetros base
33 Parametro(LIMITE_ITERACOES) = 1000000;
34 // parametro[ALGORITMO] = { "ALGORITMO",3,1,3,"Escolha do algoritmo base a executar.", nomesAlgoritmos };
35 parametro[ALGORITMO] = { "ALGORITMO",1,1,1,"Escolha do algoritmo base a executar.",{"Algoritmo Evolutivo" }};
36
37 // adicionar parâmetros da procura melhorativa
38 parametro += {
39 { "POPULACAO", 20, 2, 1000000, "Número de elementos em cada geração" },
40 { "PROB_CRUZAR",100,0,100, "Probabilidade de um estado ser cruzado" },
41 { "PROB_MUTAR",50,0,100, "Probabilidade de um estado sofrer uma mutação após gerado" },
42 { "SELECAO",1,1,3, "Método de seleção dos pais para cruzamento", {
43 "Roleta", // roleta implementada com Stochastic Universal Sampling (SUS)
44 "Torneio", // requere tamanho do torneio, se é determinístico, se é com reposição
45 "Uniforme" // todos com igual probabilidade
46 } },
47 { "PRESSAO",150,100,200,
48"Pressão da seleção (1.0 a 2.0 > 100 a 200). \
49Controla a diferença de probabilidade entre o melhor e o pior indivíduo no método Ranking Selection.\n\
50Valores próximos de 1 (100) dão probabilidades quase iguais; valores próximos de 2 (200) favorecem fortemente os melhores.", "", {SELECAO,1}},
51 { "TAMANHO_TORNEIO",2,2,100, "Tamanho do torneio, caso a sobrevivência seja do tipo torneio.", "", {SELECAO,2}},
52 { "PROB_MELHOR_TORNEIO",100,0,100, "Probabilidade do melhor ganhar o torneio.", "", {SELECAO,2}},
53 { "SOBREVIVENCIA",1,1,3, "Método de seleção dos elementos que sobrevivem à nova geração, utilizado nos Algoritmos Genéticos", {
54 "Idade",
55 "Substitui piores",
56 "round-robin" // cada elemento compete com q outros, os que perdem mais são eliminados
57 } },
58 { "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)" },
59 { "Q_ROUND_ROBIN",3,2,100, "Número de elementos no round-robin (valor de q)", "", {SOBREVIVENCIA,3}},
60 { "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" },
61 { "IMIGRANTES",1,0,100, "Número absoluto de indivíduos imigrantes, substituindo quaisquer outros na população." },
62 { "DIVERSIDADE",3,1,3, "Estratégia de diversidade. ", {
63 "Nenhuma",
64 "Avaliação partilhada",
65 "Limpeza"
66 } },
67 { "DIST_MINIMA",0,0,1000, "Distância mínima imposta entre elementos da população" }
68 };
69
70 // adicionar indicadores da procura melhorativa
71 indicador += {
72 { "Épocas", "Número de épocas decorridas num algoritmo evolutivo. Uma época é uma geração única.", IND_EPOCAS },
73 { "Gerações","número de estados gerados", IND_GERACOES }
74 };
76}
77
78// Retorna o valor da solucao completa actual.
80{
81 // dar informação de progresso, serão 128 pontos até ao limite de iterações
82 if (iteracoes % (Parametro(LIMITE_ITERACOES) >> 7) == 0)
83 Debug(ATIVIDADE, true, ".");
84 iteracoes++;
85 return custo;
86}
87
89// Algoritmo de procura local: Escalada do Monte
91// retorna a avaliacao do resultado actual
93{
94 bool movePrimeiro = true; //(Parametro(MOVE_PRIMEIRO) == 1);
95 TPonto atual = this; // estado atual
96 TPonto melhor = this; // melhor estado para todas as escaladas
97 int procuras = 0;
98 TPonto solucao;
100 melhor->custo = atual->custo = Avaliar(); // avaliar o proprio estado
101 // estado atual distinto do melhor
102 atual = solucao = (TProcuraMelhorativa*)Duplicar();
103 while (!melhor->Parar()) {
104 // iniciar uma escalada
105 epocas++;
106 // ponto de partida uma solução aleatória (local no espaço de soluções completas)
107 solucao->NovaSolucao();
108 atual->custo = solucao->Avaliar();
109 DebugInicioEM(++procuras, solucao);
110
111 while (!melhor->Parar()) {
112 // ver de entre os vizinhos, qual o melhor, para avançar um degrau
114 bool alterado = false;
115 solucao->Vizinhanca(vizinhos);
116 if (movePrimeiro) {
117 // move logo que encontre um vizinho melhor
118 // (pode estar a ser ignorados vizinhos melhores)
119 while (!vizinhos.Empty()) {
121 if (atual->custo > vizinhos.Last()->custo) {
122 solucao = MelhorAtual(atual, vizinhos, vizinhos.Count() - 1);
123 VerificaMelhor(melhor, atual);
124 // novos vizinhos a partir do estado atual são apagados
126 alterado = true;
127 }
128 else {
129 delete vizinhos.Last();
130 vizinhos.Pop();
131 }
132 }
133 }
134 else {
135 // analisa todos os vizinhos e avança apenas para o melhor vizinho
136 int melhorValor = 0, melhorIndice = 0;
138 // trocar caso melhore
139 if (atual->custo > melhorValor) {
140 solucao = MelhorAtual(atual, vizinhos, melhorIndice);
141 VerificaMelhor(melhor, atual);
142 // novos vizinhos a partir do estado atual
143 alterado = true;
144 }
145 // tudo explorado, libertar
147 }
148 // final da análise da vizinhança, ver se se subiu alguma coisa
149 if (!alterado) {
150 // significa que estamos num óptimo local, no topo do monte
151 DebugOptimoLocal(solucao);
152 break; // recomeçar nova escalada
153 }
154 else
155 DebugPassoEM(solucao);
156 }
157 }
158 //delete atual;
159 delete solucao;
160
161 return melhor->custo;
162}
163
166 solucao->Debug();
167}
168
169
171 Debug(PASSOS, false, ">> %d]", solucao->custo);
173 solucao->Debug();
174}
175
177{
178 if (Debug(PASSOS, true, "\nEscalada %d - ", ID) ||
179 Debug(DETALHE, false, "\n\nEscalada %d - ", ID))
180 solucao->Debug();
181}
182
183
185{
186 for (int i = 0; i < vector.Count(); i++)
187 if (i != excepto && vector[i] != NULL)
188 delete vector[i];
189 vector = {};
190}
191
193 if (melhor->custo > atual->custo) {
194 Copiar(atual);
195 custo = melhor->custo = atual->custo;
197 }
198}
199
201{
202 if (custo > atual->custo) {
203 Copiar(atual);
204 custo = atual->custo;
206 return true;
207 }
208 return false;
209}
210
212{
213 int custo = inverter ? 0 : INT_MAX;
214 for (int i = 0; i < populacao.Count(); i++)
215 if (inverter ? custo < populacao[i]->custo : custo > populacao[i]->custo)
217 return custo;
218}
219
221 atual->Copiar(vizinhos[indice]);
222 atual->custo = vizinhos[indice]->custo;
224 return (TProcuraMelhorativa*)atual;
225}
226
227
228void TProcuraMelhorativa::CalcularAvaliacoes(TVector<TPonto>& vizinhos, int& melhorValor, int& melhorIndice) {
229 for (int i = 0; i < vizinhos.Count(); i++) {
231 if (i == 0 || melhorValor > vizinhos[i]->custo) {
232 melhorValor = vizinhos[i]->custo;
233 melhorIndice = i;
234 }
235 }
236}
237
239// Algoritmo de procura local: Algoritmos Geneticos
241// retorna a avaliacao do resultado final
242// parâmetros para a mutacao e cruzamento podem ser dados em variaveis globais
244{
249 TVector<int> id;
250 TPonto melhor = this; // melhor estado para toda a procura
251 NovaSolucao();
252 melhor->Avaliar(); // avaliar o proprio
253 Debug(PASSOS, false, "\nPopulação inicial (%d elementos)", populacao);
254 // construir a geracao inicial
255 for (int i = 0; i < populacao; i++) {
257 geracaoAntiga.Last()->NovaSolucao();
258 geracaoAntiga.Last()->Avaliar();
260 }
261 while (!melhor->Parar()) {
262 // iniciar uma nova geração, com base na antiga
263 epocas++;
264
266 // cruzar conforme o custo
268 int minimo, maximo, total;
270 total = 0;
273 // calcular a probabilidade de um elemento ser selecionado
274 for (int i = 0; i < geracaoAntiga.Count(); i++) {
275 // cada elemento tem de ter sempre probabilidade de ser escolhido
276 // por isso adiciona-se 1 para que o custo maximo tenha probabilidade minima
277 probabilidade += (maximo - geracaoAntiga[i]->custo + 1);
278 total += probabilidade.Last();
279 }
280 // gerar novos elementos. gera-se o dobro para poder seleccionar os melhores
281 while (geracaoNova.Count() < 2 * populacao) {
282 // escolher dois individuos aleatoriamente de acordo com as probabilidades
283 int pai, mae, mutou = 0;
285 // gerar um novo individuo por cruzamento
287 geracaoNova.Last()->Cruzamento(geracaoAntiga[pai], geracaoAntiga[mae]);
288 // mudar o novo elemento, dependente da probabilidade
290 mutou = 1;
291 geracaoNova.Last()->Mutar();
292 }
293 // avaliar o valor do elemento
294 geracaoNova.Last()->Avaliar();
296 geracaoAntiga[pai]->custo,
298 geracaoNova.Last()->custo,
299 mutou);
301 }
302
303 // a nova geração já tem elementos, apagar a antiga
305 // seleccao: os melhores, com base no valor
307 // remover os elementos que são muito parecidos
308 for (int i = 0; i < populacao && i < geracaoNova.Count(); i++) {
309 // verificar se ha outro elemento muito parecido la
310 if (i > 0 && distanciaMinima > 0) {
311 bool diferente = true;
312 for (int j = 0; j < geracaoAntiga.Count(); j++)
314 diferente = false;
315 break;
316 }
317 if (!diferente)
318 continue;
319 }
320 // este elemento fica, passando para a geração antiga
322 geracaoNova[id[i]] = NULL;
323 }
324 // todos os novos que não se mantêm, são apagados
326 // tudo pronto para uma nova geração
327 }
328 // não há mais gerações, apagar tudo
330 return melhor->custo;
331}
332
333void TProcuraMelhorativa::DebugCruzamentoAG(int gPai, int gMae, int gFilho, int mutou)
334{
335 Debug(DETALHE, false, "\n Cruzar g %d x %d -> %d%s",
336 gPai, gMae, gFilho, mutou ? "*" : "");
337}
338
339void TProcuraMelhorativa::DebugPassoAG(int pop, int min, int max)
340{
341 Debug(PASSOS, false, "\nÉpoca %d #%d - %d|%d [%d-%d]",
342 epocas, pop, geracoes, iteracoes, min, max);
343}
344
345
347 TVector<int> valor;
348 for (int i = 0; i < populacao.Count(); i++)
349 valor += populacao[i]->custo;
350 valor.Sort(&id);
351}
352
353void TProcuraMelhorativa::Selecao(int& pai, int& mae, TVector<int>& pesos, int total) {
354 int valor = TRand::rand() % total;
355 pai = 0;
356 while (valor >= 0)
357 valor -= pesos[pai++];
358 pai--;
359 valor = TRand::rand() % total;
360 mae = 0;
361 while (valor >= 0)
362 valor -= pesos[mae++];
363 mae--;
364}
365
366void TProcuraMelhorativa::ObterExtremos(TVector<TPonto>& populacao, int& minCusto, int& maxCusto) {
367 minCusto = maxCusto = populacao.First()->custo;
368 for (auto elemento : populacao) {
369 if (elemento->custo < minCusto)
370 minCusto = elemento->custo;
371 if (elemento->custo > maxCusto)
372 maxCusto = elemento->custo;
373 }
374}
375
377{
379 Avaliar(); // avaliar a solução atual, fica sempre com o melhor resultado
380 while (!Parar()) {
381 // Repor o tamanho da população nesta geração
383 // Reportar informação sobre a geração
385 // Selecionar pais
387 // Gerar descendentes por cruzamento
388 // Mutar descendentes
389 // Avaliar descendentes
391 // Selecionar sobreviventes entre pais e descendentes
393 // Aplicar a diversidade
395 epocas++;
396 }
397 return custo;
398}
399
401 // mostrar informação sobre a população
402 if (Debug(PASSOS, false, "\n ├─"))
403 {
404 int minimo, maximo;
405 Debug(PASSOS, true, "─") || Debug(DETALHE, false, "┬");
406 Debug(PASSOS, false, "─ %-2s%d %-2s%s ────",
407 Icon(EIcon::EPOCA), epoca, Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_ALGORITMO)));
408 if (populacao.Empty())
409 return;
411 Debug(PASSOS, false, " %-2sg%d-%d", Icon(EIcon::VALOR), minimo, maximo);
412 if (Parametro(NIVEL_DEBUG) == DETALHE) { // mostrar custos de toda a população
415 // mostrar diversidade da população
417 Debug(DETALHE, false, " [%-2s%d-%d (μ=%d, melhor/pior %d)]",
418 Icon(EIcon::DIST), minDist, maxDist, avgDist, melhorPior);
419 for (auto individuo : populacao) {
420 custos += individuo->custo;
422 maiorCusto = individuo->custo;
423 }
424 DebugTabela(DETALHE, custos, Icon(EIcon::ELEMENTO), " │ │", 1000000 + maiorCusto);
425 Debug(DETALHE, false, "\n │ └──────────────────────────────────── ");
426 }
427 else if (Parametro(NIVEL_DEBUG) >= COMPLETO) { // mostrar diversidade da população
428 DebugPopulacaoAE(populacao, Icon(EIcon::POP));
429 DebugDiversidadeAE(populacao, Icon(EIcon::DIST));
430 }
431 }
432}
433
435{
436 int maiorCusto = 0;
437 for (auto ind : populacao)
439 maiorCusto = ind->custo;
440 printf("\n │ ├───── %s ───── ", *titulo);
441 for (int i = 0; i < populacao.Count(); i++) {
442 printf("\n │ │ %-2s", Icon(EIcon::ELEMENTO));
443 DebugID(i + 1, populacao.Count());
444 populacao[i]->Debug(false);
445 printf(" %-2s", Icon(EIcon::VALOR));
446 DebugHSL((1 - 1.0f * populacao[i]->custo / maiorCusto) * 120, .75, .5, false);
447 printf("g:%d", populacao[i]->custo);
448 DebugHSL();
449 }
450}
451
453{
454 printf("\n │ ├───── %s ───── ", *titulo);
455 if (populacao.Count() <= 10) { // matriz de distâncias
456 printf("\n │ │ %-2s ", Icon(EIcon::ELEMENTO));
457 for (int i = 0; i < populacao.Count(); i++) {
458 DebugID(i + 1, populacao.Count());
459 printf(" ");
460 }
461 printf("\n │ │ ────┼");
462 for (int i = 0; i < populacao.Count(); i++)
463 printf("────┼");
464 for (int i = 0; i < populacao.Count(); i++) {
465 printf("\n │ │ ");
466 DebugID(i + 1, populacao.Count());
467 printf("│");
468 for (int j = 0; j < populacao.Count(); j++)
469 if (i == j)
470 printf(" │");
471 else
472 printf("%4d│", populacao[i]->Distancia(populacao[j]));
473 }
474 printf("\n │ │ ────┴");
475 for (int i = 0; i < populacao.Count(); i++)
476 printf("────┴");
477 }
478 else { // distâncias entre dois elementos aleatórios
479 TVector<int> id;
480 for (int i = 0; i < populacao.Count(); i++)
481 id += i;
482 //id.RandomOrder(); // não utilizar aleatório para não alterar a sequência para o algoritmo principal
483 printf("\n │ │ %-2s %-2s %-2s \n │ │ ────┼────┼────┼",
484 Icon(EIcon::ELEMENTO), Icon(EIcon::ELEMENTO), Icon(EIcon::DIST));
485 for (int i = 0; i < id.Count(); i += 2) {
486 printf("\n │ │ ");
487 DebugID(id[i] + 1, populacao.Count());
488 printf("│");
489 DebugID(id[i + 1] + 1, populacao.Count());
490 printf("│%4d│", populacao[id[i]]->Distancia(populacao[id[i + 1]]));
491 }
492 printf("\n │ │ ────┴────┴────┴");
493 }
494}
495
496void TProcuraMelhorativa::DebugID(int id, int pop)
497{
498 DebugHSL(360.0f * id / pop);
499 printf("%-4d", id);
500 DebugHSL();
501}
502
504 int& minDist, int& maxDist, int& avgDist, int& melhorPior)
505{
506 // processar todos os pares
507 // Futuro: caso POPULACAO seja grande, processar apenas alguns pares
508 int contagem = 0, melhor = 0, pior = populacao.Count() - 1;
510 maxDist = 0;
511 avgDist = 0;
512 for (int i = 0; i < populacao.Count(); i++) {
514 melhor = i;
516 pior = i;
517 for (int j = i + 1; j < populacao.Count(); j++) {
518 int dist = populacao[i]->Distancia(populacao[j]);
519 if (dist < minDist)
520 minDist = dist;
521 if (dist > maxDist)
522 maxDist = dist;
523 avgDist += dist;
524 contagem++;
525 }
526 }
527 melhorPior = populacao[melhor]->Distancia(populacao[pior]);
528 if (contagem > 0)
529 avgDist /= contagem;
530 else
531 minDist = avgDist = maxDist = 0;
532}
533
534
536 while (populacao.Count() < Parametro(POPULACAO) && !Parar()) {
537 auto novo = Duplicar();
538 novo->NovaSolucao();
539 novo->Avaliar();
541 populacao += novo;
542 }
543 return populacao;
544}
545
548 // selecionar os pais, de acordo com o método escolhido
549 int descendentes = (Parametro(PERC_DESCENDENTES) * populacao.Count()) / 100;
550 int pop = populacao.Count();
551 pais = {};
552 if (Parar())
553 return pais;
554 if (descendentes < 1)
555 descendentes = 1;
556 else if (descendentes > pop)
558
559 Debug(COMPLETO, false, "\n │ ├─┬─── FASE %-2s Selecionar %d %-2spais ───── ",
560 Icon(EIcon::SEL_PAIS), descendentes, Icon(EIcon::PAIS));
561 if (Parametro(SELECAO) == 1) { // roleta
562 // roleta implementada como Stochastic Universal Sampling (SUS)
563 TVector<int> id, peso;
566 Debug(COMPLETO, false, "\n │ │ ├───── Roleta, pressão %d ───── ", pressao);
568 peso.Count(id.Count());
569 peso.Reset(0);
570 for (int i = 0; i < id.Count(); i++)
571 peso[id[i]] = id.Count() - i;
572 for (int i = 0; i < populacao.Count(); i++) {
573 // calcular a probabilidade de um elemento ser selecionado
574 // utilizando o método Ranking Selection
575 probabilidades += ((2.0f - (float)pressao / 100.0f) / pop +
576 (2.0f * (peso[i] - 1) * ((float)pressao / 100.0f - 1.0f)) / (float)(pop * (pop - 1)));
577 if (i > 0)
579 }
580 probabilidades.Last() = 1;
583 for (int i = 0; i < probabilidades.Count(); i++)
584 prob += (int)((i == 0 ? probabilidades[i] :
585 probabilidades[i] - probabilidades[i - 1]) * 1000 + 0.5);
586 DebugTabela(COMPLETO, prob, "100%", " │ │ │ ", -1);
587 }
588 // escolher os pais (roleta implementado como SUS)
589 float valor = (float)(TRand::rand() % 10000) / (descendentes * 10000.0f);
590 for (int escolhido = 0; pais.Count() < descendentes; escolhido++) {
591 while (pais.Count() < descendentes && valor <= probabilidades[escolhido]) {
593 valor += 1.0f / (float)descendentes;
594 }
595 }
596 }
597 else if (Parametro(SELECAO) == 3) { // uniforme
598 Debug(COMPLETO, false, "\n │ │ ├───── Uniforme ───── ");
599 for (int i = 0; i < descendentes; i++)
600 pais += populacao.Random();
601 }
602 else if (Parametro(SELECAO) == 2) { // torneio
605 Debug(COMPLETO, false, "\n │ │ ├───── Torneio, tamanho %d, probabilidade melhor %d ───── ",
607 for (int i = 0; i < descendentes; i++) {
609 TVector<int> id;
610 for (int j = 0; j < tamanho; j++)
612 // ordenar por custo
614 // escolher melhor ou segundo melhor
615 if ((TRand::rand() % 100) < (unsigned)probMelhor)
616 pais += competidores[id[0]];
617 else
618 pais += competidores[id[1 % tamanho]];
619 }
620 }
621 // reportar quantas vezes cada elemento foi pai
623 TVector<int> pai;
624 Debug(COMPLETO, false, "\n │ │ ├───── Número de seleções ───── ");
625 pai.Count(populacao.Count());
626 pai.Reset(0);
627 for (auto elemento : pais) {
628 int id = populacao.Find(elemento);
629 if (id >= 0)
630 pai[id]++;
631 }
632 DebugTabela(COMPLETO, pai, "#Pai", " │ │ │ ", -1);
633 }
634 Debug(COMPLETO, false, "\n │ │ └──────────────────────────────────── ");
635 return pais;
636}
637
640 int cruzamentos = 0, mutacoes = 0;
641 int melhor, pior, igual; // estatística do avanço da nova geração
643 descendentes = {};
644 if (Parar())
645 return descendentes;
646 Debug(COMPLETO, false, "\n │ ├─┬─── FASE %-2s Reproduzir %d pais ───── ", Icon(EIcon::CRUZAR), pais.Count());
647 Debug(COMPLETO, false, "\n │ │ ├───── Pais (%-2s) ───── ", Icon(EIcon::PAIS));
648 pais.RandomOrder();
651 for (auto elemento : pais) {
652 int id = popoulacao.Find(elemento);
653 if (id >= 0)
654 paiID += (id + 1);
655 }
656 DebugTabela(COMPLETO, paiID, Icon(EIcon::ELEMENTO), " │ │ │ ", popoulacao.Count(), true);
657 }
658 while (!pais.Empty()) {
659 TPonto pai = pais.Pop();
660 custoPais += pai->custo;
661
662 if (pais.Empty()) {
663 // não há mãe, apenas copiar o pai
664 descendentes += pai->Duplicar();
665 }
666 else {
667 TPonto mae = pais.Pop();
668 custoPais += mae->custo;
669 if (TRand::rand() % 100 < (unsigned)Parametro(PROB_CRUZAR)) {
670 // gerar um novo individuo por cruzamento
671 TPonto filho = pai->Duplicar();
672 filho->Cruzamento(pai, mae);
674 filho = mae->Duplicar();
675 filho->Cruzamento(mae, pai);
677 cruzamentos++;
678 }
679 else {
680 // copia o elemento sem alterações
681 descendentes += pai->Duplicar();
683 }
684 }
685 }
686 custoPais.Invert();
687 // mutar e avaliar descendentes
688 for (auto descendente : descendentes) {
689 // mudar o novo elemento, dependente da probabilidade
690 if (TRand::rand() % 100 < (unsigned)Parametro(PROB_MUTAR)) {
692 mutacoes++;
693 }
694 // avaliar o valor do elemento
695 descendente->Avaliar();
696 custoFilhos += descendente->custo;
698 }
699 custoFilhos.Invert();
700 int maiorCusto = 0;
701 for (auto custo : custoPais)
702 if (maiorCusto < custo)
704 for (auto custo : custoFilhos)
705 if (maiorCusto < custo)
707
708 melhor = pior = igual = 0;
709 for (int i = 0; i < custoPais.Count(); i += 2) {
710 int paiMelhor, paiPior;
712 if (paiMelhor > custoPais[i + 1])
713 paiMelhor = custoPais[i + 1];
714 if (paiPior < custoPais[i + 1])
715 paiPior = custoPais[i + 1];
716 for (int j = i; j <= i + 1; j++)
717 if (custoFilhos[j] > paiPior)
718 pior++;
719 else if (custoFilhos[j] < paiMelhor)
720 melhor++;
721 else
722 igual++;
723 }
724
725 Debug(COMPLETO, false, "\n │ │ ├───── Pais (%-2s) ───── ", Icon(EIcon::VALOR));
726 DebugTabela(COMPLETO, custoPais, Icon(EIcon::ELEMENTO), " │ │ │ ", 1000000 + maiorCusto, true);
727 Debug(COMPLETO, false, "\n │ │ ├───── Filhos (%-2s) %-2s%d %-2s%d ───── %-2s%d %-2s%d %-2s%d",
728 Icon(EIcon::VALOR),
729 Icon(EIcon::CRUZAR), cruzamentos,
730 Icon(EIcon::MUTAR), mutacoes,
731 Icon(EIcon::UB), melhor,
732 Icon(EIcon::EMPATE), igual,
733 Icon(EIcon::LB), pior);
734 DebugTabela(COMPLETO, custoFilhos, Icon(EIcon::ELEMENTO), " │ │ │ ", 1000000 + maiorCusto, true);
735 Debug(COMPLETO, false, "\n │ │ └──────────────────────────────────── ");
736 return descendentes;
737}
738
745 if(Parar())
746 return populacao;
747 Debug(COMPLETO, false, "\n │ ├─┬─── FASE %-2s Sobrevivência ───── ", Icon(EIcon::SOBREVIVENCIA));
748 if (nElite > 0) {
749 // 1. Copiar os N melhores da população atual
750 TVector<int> id;
751 OrdemValor(populacao, id); // melhor primeiro
752 for (int i = 0; i < nElite && i < populacao.Count(); i++) {
753 elite += populacao[id[i]]->Duplicar();
754 elite.Last()->custo = populacao[id[i]]->custo;
755 idElite += id[i];
756 }
757 // encontrar o melhor descendente
759 }
760
761 if (Parametro(SOBREVIVENCIA) == 1) { // idade
762 Debug(COMPLETO, false, "\n │ │ ├───── %-2s Idade ───── ", Icon(EIcon::IDADE));
763 // remover os mais velhos (os que estão mais tempo na população)
764 for (int i = 0; i < descendentes.Count() && i < populacao.Count(); i++) {
765 delete populacao[i];
766 populacao[i] = NULL;
767 }
768 populacao -= NULL;
770 descendentes = {};
771 }
772 else if (Parametro(SOBREVIVENCIA) == 2) { // substituir piores
774 Debug(COMPLETO, false, "\n │ │ ├───── Substituir piores ───── ");
776 descendentes = {};
778 for (auto individuo : populacao)
779 custos += individuo->custo;
780 Debug(COMPLETO, false, "\n │ │ ├───── Custos em ambas gerações ───── ");
781 DebugTabela(COMPLETO, custos, "Ind", " │ │ │ ");
782 }
783 TVector<int> id;
784 OrdemValor(populacao, id); // ordena por custo (melhor primeiro)
786 for (int i = 0; i < Parametro(POPULACAO); i++) {
787 novaPopulacao += populacao[id[i]];
788 populacao[id[i]] = NULL;
789 }
792 }
793 else if (Parametro(SOBREVIVENCIA) == 3) { // round-robin
794 // cada elemento compete com q outros, os que perdem mais são eliminados
795 int q = Parametro(Q_ROUND_ROBIN); // número de competidores
797 Debug(COMPLETO, false, "\n │ │ ├───── Round Robin (q: %d) ───── ", q);
799 descendentes = {};
801 for (auto individuo : populacao)
802 custos += individuo->custo;
803 Debug(COMPLETO, false, "\n │ │ ├───── Custos em ambas gerações ───── ", q);
804 DebugTabela(COMPLETO, custos, "Ind", " │ │ │ ");
805 }
806 perdas.Count(populacao.Count());
807 perdas.Reset(0);
808 for (int i = 0; i < populacao.Count(); i++) {
809 TPonto atual = populacao[i];
810 for (int j = 0; j < q; j++) {
812 do {
813 oponente = populacao.Random();
814 } while (oponente == atual && populacao.Count() > 1);
815 if (atual->custo > oponente->custo)
816 perdas[i]++;
817 }
818 }
819 Debug(COMPLETO, false, "\n │ │ ├───── Número de perdas ───── ");
820 DebugTabela(COMPLETO, perdas, "Perd", " │ │ │ ");
821 // ordenar por número de perdas
822 TVector<int> id;
823 perdas.Sort(&id);
825 for (int i = 0; i < Parametro(POPULACAO); i++) {
826 novaPopulacao += populacao[id[i]];
827 populacao[id[i]] = NULL;
828 }
831 }
832
833 if (imigrantes > 0) {
834 // 3. Adicionar novos elementos aleatórios
835 Debug(COMPLETO, false, "\n │ │ ├───── 🚶‍🌍 Imigrantes ",
836 Icon(EIcon::IMIGRANTES));
837 for (int i = 0; i < imigrantes && populacao.Count() - i > 0; i++) {
838 // remover um aleatório para dar lugar a um imigrante
839 int idx = TRand::rand() % populacao.Count();
840 if (populacao[idx] != NULL)
841 delete populacao[idx];
842 populacao[idx] = NULL;
843 Debug(COMPLETO, false, " %d✖ →🆕", idx + 1, Icon(EIcon::APAGADO), Icon(EIcon::IMIGRANTES));
844 }
845 Debug(COMPLETO, false, " ───── ");
846 }
847 populacao -= NULL;
848
849 if (nElite > 0) {
850 // 2. Garantir que os elites estão presentes
851 // (apenas se forem melhores que o melhor descendente)
852 bool primeiro = false;
853 for (int i = 0; i < elite.Count() && populacao.Count() - i > 0; i++) {
854 if (elite[i]->custo < melhorDescendente) {
855 // remover um aleatório para dar lugar ao elite
856 int idx = TRand::rand() % populacao.Count();
857 delete populacao[idx];
858 populacao[idx] = elite[i];
859 elite[i] = NULL;
860 if (!primeiro) {
861 Debug(COMPLETO, false, "\n │ │ ├───── %-2s Elite %d→%d",
862 Icon(EIcon::ELITE), idElite[i] + 1, idx + 1);
863 primeiro = true;
864 }
865 else
866 Debug(COMPLETO, false, " %d→%d",
867 idElite[i] + 1, idx + 1);
868 }
869 }
871 if (primeiro)
872 Debug(COMPLETO, false, " ───── ");
873 }
874 Debug(COMPLETO, false, "\n │ │ └──────────────────────────────────── ");
875 return populacao;
876}
877
879{
881 if (Parar())
882 return populacao;
883 if (Parametro(DIVERSIDADE) == 2) { // avaliação partilhada
885 int count = 0;
886 for (int i = 0; i < populacao.Count(); i++)
887 id += i;
888 Debug(COMPLETO, false, "\n │ ├───── FASE %-2s Diversidade - avaliação partilhada ───── ",
889 Icon(EIcon::DIVERSIDADE));
890 for (int j = 0; j < populacao.Count(); j++) {
891 if (id.Count() > 20)
892 id.RandomOrder();
893 for (int i = 0; i < id.Count() && i < 20; i++)
894 if (j != id[i] &&
896 populacao[j]->custo++; // soma 1 por cada elemento muito parecido
897 populacao[id[i]]->custo++;
898 count++;
899 penalizados += (id[i] + 1);
900 penalizados += (j + 1);
901 }
902 }
903 if (!penalizados.Empty()) {
904 penalizados.BeASet();
905 Debug(COMPLETO, false, " (%d penalizações aplicadas)", count);
906 DebugTabela(COMPLETO, penalizados, "Ind", " │ │ ");
907 }
908 Debug(COMPLETO, false, "\n │ └────────────────────────────────────── ");
909 }
910 else if (Parametro(DIVERSIDADE) == 3) { // limpeza
912 remover = {};
913 for (int i = 0; i < populacao.Count(); i++)
914 id += i;
915 Debug(COMPLETO, false, "\n │ └───── FASE %-2s Diversidade - limpeza ───── ",
916 Icon(EIcon::DIVERSIDADE));
917 for (int j = 0; j < populacao.Count(); j++) {
918 if (id.Count() > 20)
919 id.RandomOrder();
920 for (int i = 0; i < id.Count() && i < 20; i++)
921 if (j != id[i] &&
923 {
924 remover += id[i];
925 //remover += j; // apenas um
926 id -= id[i];
927 id -= j;
928 break;
929 }
930 }
931 for (auto i : remover) {
932 delete populacao[i];
933 populacao[i] = NULL;
934 Debug(COMPLETO, false, " %-2s%d", Icon(EIcon::APAGADO), i + 1);
935 }
936 populacao -= NULL;
937 }
938 return populacao;
939}
940
941
942// Chamar sempre que uma solucao melhor que a actual e encontrada
944{
945 if (Debug(ATIVIDADE, false, "\n │ %-2s %-2s%s %-2sg:%d\n─┴───────────────────",
946 Icon(EIcon::TORNEIO), Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_ALGORITMO)),
947 Icon(EIcon::VALOR), custo))
948 {
949 Debug();
950 printf("\n─┬───────────────────");
951 }
952}
953
955{
956 if (id == IND_EPOCAS)
957 return epocas;
958 else if (id == IND_GERACOES)
959 return geracoes;
960 return TProcura::Indicador(id);
961}
962
968
970 // escolher o algoritmo a executar
971 switch (Parametro(ALGORITMO)) {
972 case 1: return AlgoritmoEvolutivo();
973 //case 3: return EscaladaDoMonte();
974 //case 2: return AlgoritmoGenetico();
975 }
976 return -1;
977}
978
983 int opcao = 0, indA, indB, indC;
987 int epoca = 0;
988
989 Parametro(NIVEL_DEBUG) = EXTRA_DEBUG; // mostrar todo o debug existente, incluindo operadores
990 Parametro(POPULACAO) = 4; // manter um número baixo de elementos, só para explorar manualmente
991 Parametro(LIMITE_TEMPO) = 3600; // 1h para resolução manual
992
994 Avaliar();
995 populacao = {};
997 do {
999 if ((opcao = NovoValor("\n │ └─■ ⚡ Operação (1 🦠 Mutar, 2 🧬 Cruzar, 3 🧍🧍Vizinhos): ")) == NAO_LIDO)
1000 break;
1001 Dominio(opcao, 0, 3);
1002 debugPrefixo = " │ │ ";
1003 if (opcao == 1) { // mutar
1004 printf(" │ ┌───── %-2s ───── ", Icon(EIcon::MUTAR));
1005 printf("\n │ │ %-2s [1-%d]: ", Icon(EIcon::ELEMENTO), populacao.Count());
1006 indA = NovoValor("") - 1;
1007 Dominio(indA, 0, populacao.Count());
1008 printf(" │ │ %-2s ", Icon(EIcon::ELEMENTO));
1009 populacao[indA]->Debug(false);
1010 populacao[indA]->Mutar();
1011 printf("\n │ │ %-2s ", Icon(EIcon::MUTAR));
1012 populacao[indA]->Debug(false);
1013 populacao[indA]->Avaliar();
1015 populacao[indA]->Debug();
1016 printf("\n │ └────────────── ");
1017 }
1018 else if (opcao == 2) { // cruzar
1019 printf(" │ ┌───── %-2s ───── ", Icon(EIcon::CRUZAR));
1020 printf("\n │ │ %-2sPai [1-%d]: ", Icon(EIcon::ELEMENTO), populacao.Count());
1021 indA = NovoValor("") - 1;
1022 printf(" │ │ %-2sMãe [1-%d]: ", Icon(EIcon::ELEMENTO), populacao.Count());
1023 indB = NovoValor("") - 1;
1024 printf(" │ │ %-2sFilho [1-%d]: ", Icon(EIcon::ELEMENTO), populacao.Count());
1025 indC = NovoValor("") - 1;
1026 printf(" │ │ ");
1027 Dominio(indA, 0, populacao.Count());
1028 Dominio(indB, 0, populacao.Count());
1029 Dominio(indC, 0, populacao.Count());
1030 printf("\n │ │ %-2sPai ", Icon(EIcon::ELEMENTO));
1031 populacao[indA]->Debug(false);
1032 printf("\n │ │ %-2sMãe ", Icon(EIcon::ELEMENTO));
1033 populacao[indB]->Debug(false);
1034 populacao[indC]->Cruzamento(populacao[indA], populacao[indB]);
1035 printf("\n │ │ %-2sFilho ", Icon(EIcon::CRUZAR));
1036 populacao[indC]->Debug(false);
1037 populacao[indC]->Avaliar();
1039 populacao[indC]->Debug();
1040 printf("\n │ └────────────── ");
1041 }
1042 else if (opcao == 3) { // vizinhos
1043 printf(" │ ┌───── %-2s ───── ", Icon(EIcon::VIZINHO));
1044 printf("\n │ │ %-2s[1-%d]: ", Icon(EIcon::ELEMENTO), populacao.Count());
1045 indA = NovoValor("") - 1;
1046 Dominio(indA, 0, populacao.Count() - 1);
1047 printf(" │ │ %-2s ", Icon(EIcon::ELEMENTO));
1048 populacao[indA]->Debug(false);
1049 populacao[indA]->Vizinhanca(vizinhos);
1051 DebugPopulacaoAE(vizinhos, "Vizinhos");
1052 printf("\n │ │ %-2s[1-%d]: ", Icon(EIcon::ELEMENTO), vizinhos.Count());
1053 indB = NovoValor("") - 1;
1054 printf(" │ │ ");
1055 Dominio(indB, 0, vizinhos.Count() - 1);
1056 delete populacao[indA];
1058 vizinhos[indB] = NULL;
1060 populacao[indA]->Debug();
1062 printf("\n │ └────────────── ");
1063 }
1064
1065 epoca++;
1066 } while (opcao > 0 && !Parar());
1067 printf(" └──────────────── ");
1068 debugPrefixo = "";
1073}
1074
1075
@ 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
@ PROB_MELHOR_TORNEIO
@ PERC_DESCENDENTES
@ SOBREVIVENCIA
@ POPULACAO
TProcuraMelhorativa * TPonto
constexpr int NAO_LIDO
Definition TProcura.h:14
@ PASSOS
Exibe passos intermediários.
Definition TProcura.h:93
@ EXTRA_DEBUG
Nível extra para debug muito detalhado (uso interno).
Definition TProcura.h:96
@ ATIVIDADE
Apenas eventos principais.
Definition TProcura.h:92
@ COMPLETO
Mostra toda a execução detalhadamente.
Definition TProcura.h:95
@ DETALHE
Debug detalhada sobre estados e decisões.
Definition TProcura.h:94
@ CONT_ALGORITMO
Tempo da execução do algoritmo por instância.
Definition TProcura.h:112
@ ALGORITMO
Algoritmo base a executar.
Definition TProcura.h:70
@ LIMITE_ITERACOES
Número máximo de iterações (0 significa sem limite).
Definition TProcura.h:74
@ NIVEL_DEBUG
Nível de debug, de reduzido a completo.
Definition TProcura.h:71
@ LIMITE_TEMPO
Tempo limite em segundos.
Definition TProcura.h:73
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)
virtual void Copiar(TPonto objecto)
Fica com uma cópia do objecto.
void DebugID(int id, int pop)
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()
Chamar antes da execução do algoritmo. Limpa valores estatísticos, e fixa o instante limite de tempo ...
void DebugMelhorEncontrado(TPonto ponto)
void Explorar() override
definir para explorar manualmente os dados (não definido em TProcura, apenas em TProcuraConstrutiva)
void DebugPopulacaoAE(TVector< TPonto > &populacao, TString titulo)
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)
void DebugDiversidadeAE(TVector< TPonto > &populacao, TString titulo)
virtual void Vizinhanca(TVector< TPonto > &vizinhos)
void ResetParametros() override
Inicializa os parâmetros, indicadores e instâncias.
static const char * debugPrefixo
Utilizar como prefixo em cada linha no método Debug() do estado.
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:86
int Parametro(int id) const
Definition TProcura.h:607
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:575
virtual int64_t Indicador(int id)
Retorna um indicador, após a execução do algoritmo.
Definition TProcura.cpp:73
static int iteracoes
Número total de iterações realizadas na última execução.
Definition TProcura.h:579
virtual void ResetParametros()
Inicializa os parâmetros, indicadores e instâncias.
Definition TProcura.cpp:48
static int NovoValor(TString prompt)
static TString MostraTempo(double segundos)
Mostra tempo num formato humano.
Definition TProcura.cpp:752
static TVector< TIndicador > indicador
Indicadores que podem ser calculados após a execução, quer com informação da instãncia,...
Definition TProcura.h:570
void DebugTabela(ENivelDebug nivel, TVector< int >tabela, TString tipo="", TString prefixo="", int modoCor=0, bool duplaColuna=false)
Mostra uma tabela de inteiros, 10 elementos por linha, apenas se o nível de debug for igual ou superi...
static void DebugHSL(float h=-1, float s=1.0, float l=0.2, bool fundo=true)
Muda a cor (fundo/letra) com HSL.
Definition TProcura.cpp:525
static TVector< int > indAtivo
Definition TProcura.h:571
static double Cronometro(enum ECronometro id=CONT_ALGORITMO, bool inicializar=false)
retorna o tempo em segundos desde que o cronómetro foi inicializado
Definition TProcura.h:854
static TVector< TParametro > parametro
Parâmetros a serem utilizados na configuração atual.
Definition TProcura.h:567
virtual void LimparEstatisticas()
Chamar antes da execução do algoritmo. Limpa valores estatísticos, e fixa o instante limite de tempo ...
Definition TProcura.cpp:92
TVector< Item > & Sort(TVector< int > *idxvect=nullptr)
Ordena todo o vetor, opcionalmente devolvendo índices ordenados.
Definition TVector.h:606
Item & Random()
Definition TVector.h:253
TVector< Item > & Reset(Item const &i)
Preenche todo o vetor com um mesmo valor.
Definition TVector.h:793
int Count() const
Definition TVector.h:230
int Find(Item &i, bool binary=false, int left=0, int right=-1)
Procura um elemento no vetor.
Definition TVector.h:576
unsigned int rand(int seq)
Retorna o próximo valor pseudo-aleatório.
Definition TRand.cpp:46