TProcura
Biblioteca em C++ para testes paramétricos de algoritmos, e coleção de algoritmos de procura e otimização
Loading...
Searching...
No Matches
TProcura.cpp
Go to the documentation of this file.
1#include "TProcura.h"
2#include <stdio.h>
3#include <time.h>
4#include <string.h>
5#ifdef MPI_ATIVO
6#include <mpi.h>
7#endif
8constexpr int BUFFER_SIZE = 1024;
9
10// Resultado retornado pelo algoritmo na última execução.
12// tempo consumido na última execução.
13double TProcura::tempo = 0;
14// numero de iterações, conforme definido no algoritmo
16
17// deadline da corrida atual
18clock_t TProcura::instanteFinal = 0;
19// flag de problemas de memória esgotada
20bool TProcura::memoriaEsgotada = false;
21// ID da instância atual (problemas com várias instâncias, a utilizar em SolucaoVazia())
22TParametro TProcura::instancia = { "",1,1,1 };
23// nome do ficheiro de uma instância (utilizar como prefixo, concatenando com ID da instância)
25// idêntico mas para gravar a instância (terá sido gerada)
27
28
29// adicionar parâmetros específicos, se necessário
31// adicionar indicadores conforme a necessidade
33// lista por ordem dos indicadores a utilizar
35
36// MPI - rank do processo
37int TProcura::mpiID = 0;
38// MPI - número de processos
39int TProcura::mpiCount = 1;
40// Modo MPI : 0 = divisão estática, 1 = mestre-escravo
41int TProcura::modoMPI = 0;
42// Gravar solução CSV (todas as ações): 0 = não grava, 1 = grava
44
45// conjuntos de valores de parâmetros, para teste
47
49{
50 // definir parametros base
51 parametro = {
52 { "ALGORITMO", 1, 1, 1, "Algoritmo base a executar.", {"Algoritmo base"} },
53 { "NIVEL_DEBUG", 0, 0, 4, "Nível de debug, de reduzido a completo.",
54 { "NADA", "ATIVIDADE", "PASSOS", "DETALHE", "COMPLETO" } },
55 { "SEMENTE", 1, 1, 1000000000, "Semente aleatória para inicializar a sequência de números pseudo-aleatórios." },
56 { "LIMITE_TEMPO", 10, 1, 3600, "Limite de tempo em segundos. " },
57 { "LIMITE_ITERACOES", 0, 0, 1000000000, "Limite de número de iterações (0 não há limite). " }
58 };
59
60 // definir indicadores base
61 indicador = {
62 { "Resultado", "Resultado do algoritmo, interpretado conforme o algoritmo (sucesso/insucesso, custo, qualidade, valor, etc.).", IND_RESULTADO },
63 { "Tempo(ms)", "Tempo em milissegundos da execução (medida de esforço computacional).", IND_TEMPO },
64 { "Iterações", "Iterações do algoritmo, interpretadas conforme o algoritmo (medida de esforço independente do hardware).", IND_ITERACOES }
65 };
67
68 // colocar as configurações vazias (podem ser inicializadas se existirem configurações por omissão)
69 configuracoes = {};
70}
71
72// retorna o valor do indicador[id]
73int64_t TProcura::Indicador(int id) {
74 switch (id) {
75 case IND_RESULTADO:
76 return resultado;
77 case IND_TEMPO:
78 return (int64_t)(1000 * tempo + 0.5);
79 case IND_ITERACOES:
80 return iteracoes;
81 }
82 return 0;
83}
84
85// Escrever informacao de debug sobre o objecto atual
86void TProcura::Debug(bool completo)
87{
88 Debug(ATIVIDADE, false, "\nTProcura::Debug() método não redefinido.");
89}
90
91// Chamar antes de iniciar uma procura
100
101// Metodo para teste manual do objecto (chamadas aos algoritmos, construcao de uma solucao manual)
102// Este metodo destina-se a testes preliminares, e deve ser redefinido apenas se forem definidos novos algoritmos
104{
105 int selecao;
108 Inicializar();
110 while (true) {
111 printf("\n%s", *nome);
113 Debug();
115 printf("\n"
116 "┌─ %-2sMenu ─────────┬────────────────┬─────────────────────┬──────────────┐\n"
117 "│ 1 %-2s " COR_LEVE "Instância" COR_RESET " │ 2 %-2s " COR_LEVE "Explorar" COR_RESET " │ 3 %-2s " COR_LEVE "Parâmetros" COR_RESET " │ 4 %-2s " COR_LEVE "Solução" COR_RESET " │\n"
118 "│ 5 %-2s " COR_LEVE "Indicadores" COR_RESET " │ 6 %-2s " COR_LEVE "Executar" COR_RESET " │ 7 %-2s " COR_LEVE "Configurações" COR_RESET " │ 8 %-2s " COR_LEVE "Teste" COR_RESET " │\n"
119 "└───────────────────┴────────────────┴─────────────────────┴──────────────┘",
120 Icon(EIcon::MENU), Icon(EIcon::INST), Icon(EIcon::EXP), Icon(EIcon::PARAM),
121 Icon(EIcon::SOL), Icon(EIcon::IND), Icon(EIcon::EXEC), Icon(EIcon::CONF),
122 Icon(EIcon::TESTE));
123 if ((selecao = NovoValor("\nOpção: ")) == NAO_LIDO)
124 return;
125 switch (Dominio(selecao, 0, 9)) {
126 case 0: return;
127 case 1: SolicitaInstancia(); break;
128 case 2: Explorar(); break;
129 case 3: EditarParametros(); break;
130 case 4: MostrarSolucao(); break;
131 case 5: if (EditarIndicadores())
132 resultados = {};
133 break;
134 case 6:
135 // executar um algoritmo
136 printf("\n═╤═ %-2s Execução iniciada ═══", Icon(EIcon::EXEC));
143 printf("\n═╧═ %-2s Execução terminada %-2s %s ═══",
144 Icon(EIcon::FIM), Icon(EIcon::TEMPO),
146 break;
147 case 7: EditarConfiguracoes(); break;
148 case 8: {
150 TesteEmpirico(instancias, NovoTexto("🗎 Ficheiro resultados (nada para mostrar no ecrã): "));
151 break;
152 }
153 case 9: return;
154 default: Mensagem(Icon(EIcon::IMP), "Opção não definida."); break;
155 }
156 }
157}
158
159// Idêntico ao teste empírico, mas utiliza a configuração atual e verifica se uma solução é válida para cada instância
160void TProcura::TesteValidacao(TVector<int> instancias, TVector<int> impossiveis, TVector<int> referencias, TString fichSolucoes, TString fichResultados)
161{
162 TVector<TResultado> solucoes; // guarda soluções para valiação
163 TVector<TResultado> resultados; // guarda resultados da validação para gravação
164 TVector<int> atual;
165 TVector<TVector<int>> instSolucoes; // para cada instância, os IDs dos resultados
167
168 TesteInicio(instancias, atual);
169#ifdef VPL_ATIVO
170 Debug(ATIVIDADE, false, "\n<|--\n");
171#endif
172 instSolucoes.Count(instancias.Count());
173
174 // ler ficheiro de soluções, formato: id; (qualquer número de parâmetros); solução
175 for (auto& linha : TString().printf("%s.csv", *fichSolucoes).readLines()) {
176 TVector<TString> tokens = linha.tok(";");
177 int id = atoi(tokens.First());
178 int indice = instancias.Find(id);
179 if (linha[linha.Count() - 2] == ';')
180 tokens += TString("vazio");
181 if (tokens.Count() < 3 || indice < 0)
182 continue;
183 instSolucoes[indice] += solucoes.Count(); // registar o índice do resultado para a instância correspondente
184 int tempo = atoi(tokens[tokens.Count() - 2]);
185 solucoes += { id, 0, { tempo }, tokens.Last().tok()}; // registar a instância, solução e indicadores (a preencher após validação)
186 }
187
188 Debug(ATIVIDADE, false,
189 "\n ├─ %-2sSoluções:%d %-2sInstâncias: %d.",
190 Icon(EIcon::SUCESSO), solucoes.Count(),
191 Icon(EIcon::INST), instancias.Count()) &&
192 fflush(stdout);
193
194 // verificar cada instância, para as soluções existentes
195 for (auto inst : instancias) {
196 int validas = 0, invalidas = 0, melhor = RES_VAZIO, pior = RES_VAZIO, tempo = 0;
197 int indice = instancias.Find(inst);
198 bool impossivel = impossiveis.Find(inst) >= 0;
199 if (indice >= 0)
200 for (auto solucao : instSolucoes[indice]) {
201 tempo += (int)solucoes[solucao].valor.First(); // acumular tempo das soluções para a instância atual
202 if (impossivel) {
203 // se a instância é conhecida por ser impossível, a solução tem de ser vazia e o tempo dentro do permitido
204 if (solucoes[solucao].solucao.First() == TString("vazio"))
205 {
206 validas++;
208 if (pior == RES_VAZIO)
210 Debug(COMPLETO, false,
211 "\n ├─ %-2s:%d %-2s %-2s %-2s %-2s %d",
212 Icon(EIcon::INST), inst,
213 Icon(EIcon::SUCESSO),
214 Icon(EIcon::VALOR), Icon(EIcon::IMP),
215 Icon(EIcon::TEMPO), tempo);
216 }
217 else {
218 // se existe solução para uma instância impossível, é inválida
219 invalidas++;
220 if (melhor == RES_VAZIO)
223 Debug(COMPLETO, false,
224 "\n ├─ %-2s:%d %-2s %-2s %d",
225 Icon(EIcon::INST), inst,
226 Icon(EIcon::INSUC),
227 Icon(EIcon::TEMPO), tempo);
228 for (auto& token : solucoes[solucao].solucao)
229 Debug(COMPLETO, false, " %s", *token);
230 }
231 }
232 else {
233 // validar solução para a instância atual, e calcular indicadores
234 // gravar o ID da instância atual
235 instancia.valor = inst;
236 Inicializar();
238 // validar a solução para a instância atual
239 if (Validar(solucoes[solucao].solucao)) {
240 validas++;
242 if (resultado >= 0) {
243 if (melhor == RES_VAZIO || melhor > resultado)
245 if (pior == RES_VAZIO || (pior >= 0 && pior < resultado))
246 pior = resultado;
247 }
248 Debug(COMPLETO, false,
249 "\n ├─ %-2s:%d %-2s %-2s %d %-2s %d",
250 Icon(EIcon::INST), inst,
251 Icon(EIcon::SUCESSO),
252 Icon(EIcon::VALOR), resultado,
253 Icon(EIcon::TEMPO), tempo);
254 }
255 else {
256 invalidas++;
257 if (melhor == RES_VAZIO)
260 Debug(COMPLETO, false,
261 "\n ├─ %-2s:%d %-2s %-2s %d",
262 Icon(EIcon::INST), inst,
263 Icon(EIcon::INSUC),
264 Icon(EIcon::TEMPO), tempo);
265 }
266 }
267 }
268 if (validas + invalidas == 0) {
269 // se não existem soluções para a instância, considerar como não resolvida
270 invalidas++;
272 }
273 // registar a instância e resultados (válidas, inválidas, melhor e pior valores), e tempo para gravação
274 resultados += { inst, 0, { validas, invalidas, melhor, pior, tempo }, { }};
275 }
276
279
280 // gravar resultados, um por instância
282
283 // repor a instância atual
285 Inicializar();
286#ifdef VPL_ATIVO
287 Debug(ATIVIDADE, false, "\n--|>\n");
288#endif
289 TesteFim();
290
291}
292
294 int validas = 0, melhorCusto = 0, piorCusto = 0, tempoTotal = 0;
295 double taxaEficacia = 0, taxaQualidade = 0, taxaEficiencia = 0, desempenho = 0;
296 bool considerarQualidade = (referencias[1] > referencias[0]); // custoMin < custoMax (se iguais, o custo não é considerado para o indicador global)
297 for (auto& res : resultados) {
298 // instância válida apenas se todas as soluções para a instância forem válidas
299 if (res.valor[0] > 0 && res.valor[1] == 0) {
300 validas++;
301 if (res.valor[2] >= 0)
302 melhorCusto += (int)res.valor[2];
303 if (res.valor[3] >= 0)
304 piorCusto += (int)res.valor[3];
305 tempoTotal += (int)res.valor[4];
306 }
307 // não resolvidas se existirem resultados inválidos
308 if (res.valor[1] > 0) {
309 // custo máximo por instância
310 piorCusto += referencias[1] / resultados.Count();
311 // tempo máximo por instância
312 tempoTotal += referencias[3] / resultados.Count();
313 }
314 }
315 Debug(ATIVIDADE, false,
316 "\n ├─ %-2sVálidas:%d %-2sInstâncias: %d.",
317 Icon(EIcon::SUCESSO), validas,
318 Icon(EIcon::INST), resultados.Count()) &&
319 fflush(stdout);
320 Debug(ATIVIDADE, false,
321 "\n ├─ %-2sMelhor:%d %-2sPior: %d.",
322 Icon(EIcon::VALOR), melhorCusto,
323 Icon(EIcon::VALOR), piorCusto) &&
324 fflush(stdout);
326 "\n ├─ %-2sTempo(ms):%d.",
327 Icon(EIcon::TEMPO), tempoTotal) &&
328 fflush(stdout);
329
330 // indicador de desempenho global:
331 // - taxaEficacia * taxaQualidade * taxaEficiencia (todos entre 0 e 1)
332 // - resultado final na escala entre 0 e 100 pontos.
333 // eficácia: percentagem de instâncias resolvidas
334 taxaEficacia = 100.0 * validas / resultados.Count();
335 // qualidade: (custoMax - custoTotal) / (custoMax - custoMin)
337 taxaQualidade = 100.0 * (referencias[1] - piorCusto) / (referencias[1] - referencias[0]);
338 // eficiência: (tempoMax - tempoTotal) / (tempoMax - tempoMin)
339 taxaEficiencia = 100.0 * (referencias[3] - tempoTotal) / (referencias[3] - referencias[2]);
340 // ajuste de limites
342 taxaQualidade = (taxaQualidade > 100 ? 100 : (taxaQualidade < 0 ? 0 : taxaQualidade));
343 taxaEficiencia = (taxaEficiencia > 100 ? 100 : (taxaEficiencia < 0 ? 0 : taxaEficiencia));
344 // calculo do indicador global
347 Debug(ATIVIDADE, false,
348 "\n ├─ %-2s %.1f%% (%-2s %.1f%% %-2s %.1f%% %-2s %.1f%%)",
349 Icon(EIcon::IND), desempenho,
350 Icon(EIcon::SUCESSO), taxaEficacia,
351 Icon(EIcon::VALOR), taxaQualidade,
352 Icon(EIcon::TEMPO), taxaEficiencia);
353 else
354 Debug(ATIVIDADE, false,
355 "\n ├─ %-2s %.1f%% (%-2s %.1f%% %-2s %.1f%%)",
356 Icon(EIcon::IND), desempenho,
357 Icon(EIcon::SUCESSO), taxaEficacia,
358 Icon(EIcon::TEMPO), taxaEficiencia);
359 fflush(stdout);
360
361#ifdef VPL_ATIVO
362 // nota no VPL
363 Debug(ATIVIDADE, false, "\n--|>\nGrade :=>> %d\n<|--\n", (int)(desempenho + 0.5));
364#endif
365}
366
367
368void TProcura::MostraCaixa(TVector<TString> titulo, ECaixaParte parte, TVector<int> largura, bool aberta, int identacao) {
369 for (int i = 0; i < titulo.Count(); i++) {
370 unsigned int len = (unsigned int)(
372 largura[i] :
374
375 if (len > 100)
376 len = 0;
377
378 switch (parte) {
380
381 if (i == 0) {
382 if (!titulo[i].Empty())
383 printf("\n%*s┌─ %s ─", identacao, "", *titulo[i]);
384 else
385 printf("\n%*s┌────", identacao, "");
386 break;
387 }
388 if (!titulo[i].Empty())
389 printf("┬─ %s ─", *titulo[i]);
390 else
391 printf("┬────");
392 break;
394 if (i == 0) {
395 if (!titulo[i].Empty())
396 printf("\n%*s├─ %s ─", identacao, "", *titulo[i]);
397 else
398 printf("\n%*s├────", identacao, "");
399 break;
400 }
401 if (!titulo[i].Empty())
402 printf("┼─ %s ─", *titulo[i]);
403 else
404 printf("┼────");
405 break;
407 if (i == 0) { printf("\n%*s│ %s", identacao, "", *titulo[i]); break; }
408 printf("│ %s", *titulo[i]); break;
410 if (i == 0) { printf("\n%*s└", identacao, ""); break; }
411 printf("┴"); break;
412 }
413
414 // mostrar a barra com len de comprimento
415 while (len-- > 0)
416 printf(parte == ECaixaParte::Meio ? " " : "─");
417
418 }
419
420 if (!aberta)
421 switch (parte) {
422 case ECaixaParte::Topo: printf("┐"); break;
423 case ECaixaParte::Separador: printf("┤"); break;
424 case ECaixaParte::Meio: printf("│"); break;
425 case ECaixaParte::Fundo: printf("┘"); break;
426 }
427}
428
429
430void TProcura::MostraCaixa(TString titulo, ECaixaParte parte, int largura,
431 bool aberta, int identacao, const char* icon)
432{
433 // início da caixa ou linha de separação ou fim da caixa
434 bool novaLinha = true;
435 if (identacao < 0) {
436 novaLinha = false;
437 identacao = -identacao - 1;
438 }
439 unsigned int len = (unsigned int)(
441 largura - (titulo.Empty() ? 0 : compat::ContaUTF8(titulo) - 4) :
443
444 if (icon[0] != 0)
445 len -= 3;
446
447 if (len > 100)
448 len = 0;
449
450 if (novaLinha)
451 printf("\n");
452 switch (parte) {
454 if (icon[0] != 0)
455 printf("%*s┌─ %-2s%s ─", identacao, "", icon, *titulo);
456 else
457 printf("%*s┌─ %s ─", identacao, "", *titulo);
458 break;
460 if (icon[0] != 0)
461 printf("%*s├─ %-2s%s ─", identacao, "", icon, *titulo);
462 else
463 printf("%*s├─ %s ─", identacao, "", *titulo);
464 break;
466 if (icon[0] != 0)
467 printf("%*s│ %-2s%s", identacao, "", icon, *titulo);
468 else
469 printf("%*s│ %s", identacao, "", *titulo);
470 break;
472 printf("%*s└", identacao, "");
473 if (!titulo.Empty()) { // texto a ser inserido no fundo
474 if (icon[0] != 0)
475 printf("─ %-2s%s ─", icon, *titulo);
476 else
477 printf("─ %s ─", *titulo);
478 }
479 break;
480 }
481
482 // mostrar a barra com len de comprimento
483 while (len-- > 0)
484 printf(parte == ECaixaParte::Meio ? " " : "─");
485
486 if (!aberta)
487 switch (parte) {
488 case ECaixaParte::Topo: printf("┐"); break;
489 case ECaixaParte::Separador: printf("┤"); break;
490 case ECaixaParte::Meio: printf("│"); break;
491 case ECaixaParte::Fundo: printf("┘"); break;
492 }
493}
494
495void TProcura::MostraCaixa(TVector<TString> textos, int largura, bool aberta, int identacao) {
497 for (int i = 1; i < textos.Count(); i++)
500}
501
502void TProcura::Mensagem(TString titulo, const char* fmt, ...) {
503 if (titulo.Empty())
504 titulo = "⚠️";
505
507 va_start(args, fmt);
510
511 int64_t len = vsnprintf(nullptr, 0, fmt, args_copy);
513
514 TVector<char> texto((int)len + 1);
515 if (texto.Data()) {
516 vsnprintf(texto.Data(), len + 1, fmt, args);
517 len = compat::ContaUTF8(texto.Data()) + 2;
519 MostraCaixa(textos, len < 20 ? 20 : (int)len);
520 }
521 va_end(args);
522}
523
525void TProcura::DebugHSL(float h, float s, float l, bool fundo) {
526 if (h < 0 || h > 360) { // reset de cores
527 printf("%s", COR_RESET);
528 }
529 else {
530 float f = (2 * l - 1);
531 float c = (1 - (f < 0 ? -f : f)) * s;
532
533 float h60 = h / 60.0f;
534 float hmod2 = h60 - 2 * int(h60 / 2);
535 float x = c * (1 - ((hmod2 - 1) < 0 ? -(hmod2 - 1) : (hmod2 - 1)));
536 float m = l - c / 2;
537
538 float r, g, b;
539 if (h < 60) { r = c; g = x; b = 0; }
540 else if (h < 120) { r = x; g = c; b = 0; }
541 else if (h < 180) { r = 0; g = c; b = x; }
542 else if (h < 240) { r = 0; g = x; b = c; }
543 else if (h < 300) { r = x; g = 0; b = c; }
544 else { r = c; g = 0; b = x; }
545
546 printf("\x1b[%d;2;%d;%d;%dm", (fundo ? 48 : 38),
547 (int)((r + m) * 255), (int)((g + m) * 255), (int)((b + m) * 255));
548 }
549}
550
551
552
553void TProcura::MostraParametros(int detalhe, TVector<int>* idParametros, TString titulo) {
554 int nElementos = (idParametros == NULL ? parametro.Count() : idParametros->Count());
555 int col = 2;
556 bool parBin = false;
557 if (titulo.Empty())
558 titulo = "Parâmetros";
559 // detalhe 0 é só uma linha (separador)
560 if (detalhe) {
561 MostraCaixa(titulo, ECaixaParte::Topo, 70, true, 0, Icon(EIcon::PARAM));
563 }
564 else {
566 printf(" ");
567 }
568 col = 3;
569
570 for (int i = 0; i < nElementos; i++) {
571 int parID = (idParametros == NULL ? i : (*idParametros)[i]);
572 if (!ParametroAtivo(parID))
573 continue;
574 // caso o parâmetro seja 0/1 mostrar o valor em cor 0=vermelho 1=verde
575 if ((parBin = (parametro[parID].min == 0 && parametro[parID].max == 1)) == true) {
576 // identificação do parâmetro e valor com cor
577 if (detalhe == 0 || parametro[parID].nome.Empty() ||
578 (detalhe == 1 && !parametro[parID].dependencia.Empty()))
579 col += printf("%sP%d%s%s" COR_RESET,
580 (const char*)(Parametro(parID) == 1 ? COR_ATIVO_LEVE : COR_INATIVO_LEVE),
581 parID + 1,
582 (const char*)(Parametro(parID) == 1 ? COR_ATIVO : COR_INATIVO),
583 Icon(Parametro(parID) == 1 ? EIcon::SEL : EIcon::NSEL)) - COR_LEVE_TAM;
584 else {
585 if (detalhe == 2 && !parametro[parID].dependencia.Empty())
586 col += printf(" ");
587 col += printf("%sP%d(%s)%s%s" COR_RESET,
588 (const char*)(Parametro(parID) == 1 ? COR_ATIVO_LEVE : COR_INATIVO_LEVE),
589 parID + 1, *parametro[parID].nome,
590 (const char*)(Parametro(parID) == 1 ? COR_ATIVO : COR_INATIVO),
591 Icon(Parametro(parID) == 1 ? EIcon::SEL : EIcon::NSEL)) - COR_LEVE_TAM;
592 }
593 }
594 else {
595 // identificação do parâmetro
596 if (detalhe == 0 || parametro[parID].nome.Empty() ||
597 (detalhe == 1 && !parametro[parID].dependencia.Empty()))
598 col += printf(COR_LEVE "P%d=" COR_RESET, parID + 1) - COR_LEVE_TAM;
599 else {
600 if (detalhe == 2 && !parametro[parID].dependencia.Empty())
601 col += printf(" ");
602 col += printf(COR_LEVE "P%d(%s):" COR_RESET " ", parID + 1, *parametro[parID].nome) - COR_LEVE_TAM;
603 }
604 // valor do parâmetro
605 if (detalhe > 1 && col < 30)
606 col += printf("%*s", (30 - col), "");
607 if (detalhe == 0 || parametro[parID].nomeValores.Empty() ||
608 (detalhe == 1 && !parametro[parID].dependencia.Empty()))
609 col += printf("%d", Parametro(parID));
610 else
611 col += printf("%s", *parametro[parID].nomeValores[Parametro(parID) - parametro[parID].min]);
612 }
613
614 // mostrar intervalo permitido
615 if (detalhe > 1) {
616 if (col < 40)
617 col += printf("%*s", (40 - col), "");
618 col += printf(" " COR_LEVE "(%d a %d)" COR_RESET, parametro[parID].min, parametro[parID].max) - COR_LEVE_TAM;
619 }
620 if (detalhe == 2 && !parametro[parID].dependencia.Empty()) {
621 // mostrar variável dependente
622 int dependente = parametro[parID].dependencia.First();
623 col += printf(COR_LEVE " [P%d(%s)]" COR_RESET " ", dependente + 1, *parametro[dependente].nome) - COR_LEVE_TAM;
624 }
625 // separador/mudança de linha
626 if (i < nElementos - 1) {
627 if (detalhe > 1 || col > 70) { // limite de largura
628 if (detalhe == 0) {
629 MostraCaixa(" ", ECaixaParte::Separador, 1, true, 1, Icon(EIcon::PARAM));
630 printf(" ");
631 }
632 else
634 col = 3;
635 }
636 else if (detalhe > 0)
637 col += printf(" | ");
638 else
639 col += printf(" ");
640 }
641 }
642 if (detalhe)
644}
645
647 int opcao = 0;
648 bool editado = false;
649 while (true) {
651 if ((opcao = NovoValor("\nAlterar indicador: ")) == NAO_LIDO || opcao == 0)
652 return editado;
653 opcao = Dominio(opcao, 1, indicador.Count());
654 if (indicador[opcao - 1].indice >= 0) {
655 for (int i = 0; i < indicador.Count(); i++)
656 if (i != opcao - 1 && indicador[i].indice > indicador[opcao - 1].indice)
657 indicador[i].indice--;
658 indicador[opcao - 1].indice = -1;
659 indAtivo -= (opcao - 1);
660 }
661 else {
662 indicador[opcao - 1].indice = 0;
663 for (int i = 0; i < indicador.Count(); i++)
664 if (i != opcao - 1 && indicador[i].indice >= indicador[opcao - 1].indice)
665 indicador[opcao - 1].indice = indicador[i].indice + 1;
666 indAtivo += (opcao - 1); // coloca no fim
667 }
668 // invalidar resultados atuais
669 editado = true;
670 }
671 return editado;
672}
673
675 int opcao = 0, valor;
676 while (true) {
678 if ((opcao = NovoValor("\nParâmetro:")) == NAO_LIDO || opcao == 0)
679 return;
680 opcao = Dominio(opcao, 1, parametro.Count());
681 if (!ParametroAtivo(opcao - 1)) {
682 printf("\nParâmetro inativo.");
683 continue;
684 }
685 // iniciar caixa com nome do parametro
687 TString().printf("%-2s P%d(%s)", Icon(EIcon::PARAM), opcao, *parametro[opcao - 1].nome),
689 // mostrar descrição se existir
690 if (!parametro[opcao - 1].descricao.Empty())
692 // mostrar textos dos valores possíveis, caso existam
693 if (!parametro[opcao - 1].nomeValores.Empty())
694 for (int i = parametro[opcao - 1].min; i <= parametro[opcao - 1].max; i++) {
696 printf(COR_LEVE "%d:" COR_RESET " %s", i,
697 *parametro[opcao - 1].nomeValores[i - parametro[opcao - 1].min]);
698 }
699 else {
700 // mostrar intervalo possível
702 printf("Intervalo: %d a %d",
703 parametro[opcao - 1].min,
704 parametro[opcao - 1].max);
705 }
707
708 // valor atual
709 if (!parametro[opcao - 1].nome.Empty())
710 printf("\n%s (atual %d): ", *parametro[opcao - 1].nome, Parametro(opcao - 1));
711 else
712 printf("\nP%d (atual %d): ", opcao, Parametro(opcao - 1));
713 // solicitar valor
714 valor = NovoValor("");
715 if (valor != NAO_LIDO || valor == 0)
716 Parametro(opcao - 1) =
717 Dominio(valor,
718 parametro[opcao - 1].min,
719 parametro[opcao - 1].max);
720 }
721}
722
724{
725 int id = -1;
726 // procurar pela configuração
727 for (int i = 0; i < configuracoes.Count() && id < 0; i++)
728 if (configuracoes[i].Equal(parametros))
729 id = i;
730 if (id < 0) {
733 return configuracoes.Count() - 1;
734 }
735 return id;
736}
737
738
739// gravar (ou ler) a configuração atual
740void TProcura::ConfiguracaoAtual(TVector<int>& parametros, int operacao) {
741 if (operacao == GRAVAR) {
742 for (int i = 0; i < parametro.Count() && i < parametros.Count(); i++)
744 }
745 else if (operacao == LER) {
746 parametros = {};
747 for (int i = 0; i < parametro.Count(); i++)
749 }
750}
751
753{
754 static const int64_t segundo = 1000;
755 static const int64_t minuto = 60 * segundo;
756 static const int64_t hora = 60 * minuto;
757 static const int64_t dia = 24 * hora;
758 static const int64_t semana = 7 * dia;
759 static const int64_t mes = 30 * dia;
760 static const int64_t ano = 365 * dia;
762 static TVector<char> unidadesStr = { 'a', 'm', 's', 'd', 'h', '\'', '"' };
763 TString str;
764
765 int64_t ms = (int64_t)(1000 * segundos + 0.5);
766
767 for (int i = 0; i < unidades.Count(); i++)
768 if (ms >= unidades[i]) {
769 str.printf("%" PRId64 "%c ", ms / unidades[i], unidadesStr[i]);
770 ms %= unidades[i];
771 }
772 if (ms > 0)
773 str.printf("%" PRId64 "ms ", ms);
774
775 return str;
776}
777
778void TProcura::InserirRegisto(TVector<TResultado>& resultados, int inst, int conf)
779{
780 resultados += { inst, conf };
781 for (auto ind : indAtivo)
782 Registo(resultados.Last(), ind, Indicador(ind));
783 // adicionar no final a solução codificada em inteiros
784 resultados.Last().valor += CodificarSolucao();
785 resultados.Last().solucao = Solucao();
786}
787
788int64_t TProcura::Registo(TResultado& resultado, int id)
789{
790 if (id >= 0 && id < indicador.Count() && indicador[id].indice >= 0)
791 return resultado.valor[indicador[id].indice];
792 return 0;
793}
794
795void TProcura::Registo(TResultado& resultado, int id, int64_t valor)
796{
797 if (id >= 0 && id < indicador.Count() && indicador[id].indice >= 0)
798 resultado.valor[indicador[id].indice] = valor;
799}
800
802{
803 TString str;
804 TVector<TString> textos = { "📖 Sintaxe comando"," " COR_LEVE "Instâncias:" COR_RESET " A,B,C | A:B | A : B : C" };
805
806 MostraCaixa(textos, 40);
807
808 printf("\n%-2s IDs das instâncias (%d a %d): ", Icon(EIcon::INST), instancia.min, instancia.max);
809
810 str = NovoTexto("");
811 if (!str.Empty())
812 return _TV(str);
813 // colocar apenas a instância atual
814 return TVector<int>() += instancia.valor;
815}
816
818 TVector<int> atual; // parâmetros atuais
819 int id = -1, auxID;
820 TString str;
821
822 ConfiguracaoAtual(atual, LER);
823
824 id = NovaConfiguracao(atual);
825
826 do {
828 "📖 Sintaxe comando",
829 " id / -id " COR_LEVE "- Seleciona configuração como atual ou apaga 'id'" COR_RESET,
830 " Pk = <conj.> " COR_LEVE "- Varia Pk na configuração atual (gera N configs)" COR_RESET,
831 " Pk = <conj.> x Pw = <conj.> " COR_LEVE "- produto externo (gera NxM configs)" COR_RESET,
832 " " COR_LEVE "Sintaxe de <conj.> :" COR_RESET " A,B,C | A:B | A:B:C"
833 };
835
836 MostraCaixa(textos, 70);
837
838 if ((str = NovoTexto("\n✏️ Comando: ")).Empty())
839 break;
840
841 if ((auxID = atoi(str)) != 0) {
842 id = auxID;
844 if (id < 0) {
845 id++;
847 }
848 else if (id > 0) {
849 id--;
850 atual = configuracoes[id];
851 }
852 }
853 else {
855 configuracoes[id] = atual; // alterar atual se necessário
857 }
858 } while (true);
860}
861
865 auto tokens = str.tok();
866
867 // processar todos os itens a iniciar em P, obtendo informação entre quais existe x
868 for (auto& token : tokens) {
869 if (token[0] == 'P') {
870 int param;
871 auto par = token.tok("="); // obter o token do parâmetro e o token dos valores
872 if (par.Count() == 2) {
873 param = atoi(*par.First() + 1);
874 if (param > 0 && param <= parametro.Count()) {
875 valores.Count(valores.Count() + 1);
876 valores.Last() = {};
877 valores.Last() += param; // primeiro valor é ID do parâmetro
878 valores.Last() += _TV(par.Last()); // valores para o parâmetro tomar
879 if (valores.Last().Count() == 2) {
880 // apenas um elemento, altera a configuração atual
881 // (se fosse para alternar, colocava o valor base mais o valor a alternar)
882 int valor = valores.Last().Last();
883 if (valor >= parametro[param - 1].min &&
884 valor <= parametro[param - 1].max)
885 base[param - 1] = valor;
886 }
887 if (valores.Last().Count() <= 2)
888 valores.Count(valores.Count() - 1);
889 }
890 }
891 }
892 else if (token[0] == 'x') {
893 valores.Count(valores.Count() + 1);
894 valores.Last() += 0; // produto externo
895 }
896 }
897
898 // inserir configurações de acordo com o pretendido (produto externo, ou apenas à configuração base)
899 produto = {};
900 for (int i = 0; i < valores.Count(); i++)
901 if (valores[i].First() > 0) { // c.c. é o operador produto externo
902 if (i == valores.Count() - 1 || valores[i + 1].First() != 0) { // não há outro produto externo, colocar na configuração atual
903 produto += i;
905 produto = {};
906 }
907 else
908 produto += i;
909 }
910}
911
913{
914 // inserir os valores do último elemento de forma recursiva
915 int idLista = produto.Pop();
918 int param = lista.First();
919
920 for (int i = 1; i < lista.Count(); i++)
921 if (lista[i] >= parametro[param - 1].min &&
922 lista[i] <= parametro[param - 1].max)
923 {
924 base[param - 1] = lista[i];
925 if (produto.Empty())
927 else
929 }
930 base = backup;
931 produto += idLista;
932}
933
934void TProcura::MostrarConfiguracoes(int detalhe, int atual) {
936 // identificar parametros comuns e distintos entre as parametrizações
937 for (int i = 0; i < configuracoes.First().Count(); i++) {
938 bool igual = true;
939 for (int j = 1; j < configuracoes.Count() && igual; j++)
941 if (igual)
942 comum += i;
943 else
944 distinto += i;
945 }
946 // mostra parametros comuns, evitando repetição em cada configuração
947 MostraParametros(detalhe, &comum, Icon(EIcon::CONF));
948 printf(COR_LEVE " (parâmetros comuns)" COR_RESET);
949
950 if (configuracoes.Count() > 1) {
951 // visualizar configurações atuais, assinalando a atualmente escolhida
952 printf("\n═╪═ Configurações ═══");
953 for (int i = 0; i < configuracoes.Count(); i++) {
954 TString str;
955 str.printf("%-2s [%d]", Icon(EIcon::PARAM), i + 1);
958 if (i == atual)
959 printf(" ⭐ atual");
960 if (atual < 0 && i == 2 && configuracoes.Count() > 10) {
961 printf("\n │ ...");
962 i = configuracoes.Count() - 4;
963 }
964 }
965 }
966 printf("\n═╧═══════════════════");
967}
968
969void TProcura::MostraConjunto(TVector<int> valores, const char* etiqueta) {
970 printf(" { ");
971 if (valores.Count() <= 10) {
972 for (auto ind : valores)
973 printf("%-2s%d ", etiqueta, ind);
974 }
975 else {
976 for (int i = 0; i <= 2; i++)
977 printf("%-2s%d ", etiqueta, valores[i]);
978 printf("… ");
979 for (int i = valores.Count() - 3; i < valores.Count(); i++)
980 printf("%-2s%d ", etiqueta, valores[i]);
981 }
982 printf("} ");
983 if (valores.Count() > 10)
984 printf("#%d", valores.Count());
985}
986
987void TProcura::TesteInicio(TVector<int>& instancias, TVector<int>& configAtual) {
989 if (configuracoes.Empty()) {
990 // não foram feitas configurações, utilizar a atual
993 }
994 for (auto item : instancias)
996 item = -1;
997 instancias -= (-1);
998 if (mpiID == 0) {
999 printf("\n\n═╤═ Instâncias ═══");
1000 MostraConjunto(instancias, Icon(EIcon::INST));
1002 }
1003 if (mpiCount < 10 || mpiID == 0)
1004 printf("\n═╤═ %-2s Início do Teste (%-2s%d) ═══",
1005 Icon(EIcon::TESTE), Icon(EIcon::PROCESSO), mpiID);
1006 fflush(stdout);
1007 Cronometro(CONT_TESTE, true); // reiniciar cronómetro global
1008}
1009
1011 if (mpiCount < 10 || mpiID == 0)
1012 printf("\n═╧═ %-2s Fim do Teste (%-2s%d %-2s%s) ═══",
1013 Icon(EIcon::FIM), Icon(EIcon::PROCESSO), mpiID, Icon(EIcon::TEMPO),
1015 fflush(stdout);
1016}
1017
1018
1019// utilizar para executar testes empíricos, utilizando todas as instâncias,
1020// com o último algoritmo executado e configurações existentes
1022 TVector<TResultado> resultados; // guarda as soluções obtidas
1023 TVector<int> atual;
1024 int backupID = instancia.valor;
1025 int nTarefa = 0;
1026 double periodoReporte = 60;
1027
1028 TesteInicio(instancias, atual);
1029
1030 switch (Parametro(NIVEL_DEBUG)) {
1031 case DETALHE: periodoReporte = 10; break;
1032 case COMPLETO: periodoReporte = 0; break; // reporte em todos os eventos
1033 }
1034 Cronometro(CONT_REPORTE, true); // reiniciar cronómetro evento
1035 if (mpiID == 0)
1036 Debug(ATIVIDADE, false,
1037 "\n ├─ %-2sTarefas:%d %-2sInstâncias: %d %-2sConfigurações: %d %-2sProcessos: %d.",
1038 Icon(EIcon::TAREFA), instancias.Count() * configuracoes.Count(),
1039 Icon(EIcon::INST), instancias.Count(),
1040 Icon(EIcon::CONF), configuracoes.Count(),
1041 Icon(EIcon::PROCESSO), mpiCount) &&
1042 fflush(stdout);
1043 // percorrer todas as instâncias
1044 for (int configuracao = 0; configuracao < configuracoes.Count(); configuracao++) {
1045 ConfiguracaoAtual(configuracoes[configuracao], GRAVAR);
1046
1047 for (auto inst : instancias) {
1048 // distribuir tarefas por MPI
1049 if ((nTarefa++) % mpiCount != mpiID)
1050 continue;
1051
1053 Debug(ATIVIDADE, false,
1054 "\n ├─ %-2s%-15s %-2s%-5d %-2s%-5d %-2s%-5d %-2s%-5d",
1055 Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_TESTE)),
1056 Icon(EIcon::TAREFA), nTarefa,
1057 Icon(EIcon::INST), inst,
1058 Icon(EIcon::CONF), configuracao + 1,
1059 Icon(EIcon::PROCESSO), mpiCount) &&
1060 fflush(stdout);
1061 Cronometro(CONT_REPORTE, true);
1062 }
1063 ExecutaTarefa(resultados, inst, configuracao);
1064 }
1065 }
1066
1067 if (ficheiro.Empty())
1069 else {
1070 // gravar resultados em ficheiro CSV
1072
1074 double tempoTotal = tempoLocal;
1075 double tempoMaximo = tempoLocal;
1076#ifdef MPI_ATIVO
1079#endif
1080
1081 if (mpiCount > 1 && modoMPI == 0)
1082 // tenta juntar ficheiros, caso existam os ficheiros dos outros processos
1084 if (mpiID == 0)
1085 Debug(ATIVIDADE, false,
1086 "\n ├─ %-2s Ficheiro %s.csv gravado.\n"
1087 " │ %-2s Tempo real: %s",
1088 Icon(EIcon::RESULT), *ficheiro,
1089 Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_TESTE))) &&
1090 Debug(ATIVIDADE, false, "\n │ %-2s CPU total: %s",
1091 Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_TESTE) * mpiCount)) &&
1092 Debug(ATIVIDADE, false, "\n │ %-2s Utilização: %.1f%%",
1093 Icon(EIcon::TAXA), 100. * tempoTotal / (tempoMaximo * mpiCount));
1094 }
1095
1096 ConfiguracaoAtual(atual, GRAVAR);
1098 Inicializar();
1099 TesteFim();
1100}
1101
1103{
1104#ifdef MPI_ATIVO
1105 int dados[3] = { 0, 0, 0 }; // instância, configuração
1106 double esperaTrabalhadores = 0, esperaGestor = 0;
1107 TVector<double> terminou; // instante em que terminou cada trabalhador
1109 TVector<int> atual;
1110 double periodoReporte = 60;
1111
1112 TesteInicio(instancias, atual);
1113
1114 switch (Parametro(NIVEL_DEBUG)) {
1115 case DETALHE: periodoReporte = 10; break;
1116 case COMPLETO: periodoReporte = 0; break;
1117 }
1118 for (int i = 1; i < mpiCount; i++)
1119 trabalhador += i;
1120
1121 terminou.Count(mpiCount);
1122 terminou.Reset(0);
1123
1124 // Ciclo:
1125 // 1. Enviar trabalho para os escravos
1126 // 2. Encerrar escravos a mais
1127 // 3. Receber resultados e repetir 1 ou 2 conforme as necessidades
1128
1129 TVector<TResultado> resultados; // guarda as soluções obtidas
1130 TVector<TResultado> tarefas; // guarda informação apenas das tarefas a realizar (sem resultados)
1131 Cronometro(CONT_REPORTE, true); // reiniciar cronómetro evento
1132
1133 // construir todas as tarefas
1134 for (int configuracao = 0; configuracao < configuracoes.Count(); configuracao++)
1135 for (auto inst : instancias)
1136 tarefas += { inst, configuracao };
1137
1138 int totalTarefas = tarefas.Count();
1139 Debug(ATIVIDADE, false, "\n ├─ %-2sTarefas:%d %-2sInstâncias: %d %-2sConfigurações: %d %-2sProcessos: %d.",
1140 Icon(EIcon::TAREFA), tarefas.Count(),
1141 Icon(EIcon::INST), instancias.Count(),
1142 Icon(EIcon::CONF), configuracoes.Count(),
1143 Icon(EIcon::PROCESSO), trabalhador.Count() + 1) &&
1144 fflush(stdout);
1145
1146 // dar uma tarefa a cada escravo
1147 while (!tarefas.Empty() && !trabalhador.Empty()) {
1148 auto tarefa = tarefas.Pop();
1149 dados[0] = tarefa.instancia;
1150 dados[1] = tarefa.configuracao;
1151 trabalhar += trabalhador.Last();
1153 esperaTrabalhadores += Cronometro(CONT_TESTE); // estava parado até esta altura
1154 }
1155 // caso existam escravos sem trabalho, mandar fechar todos, não há mais tarefas
1156 dados[0] = dados[1] = -1;
1157 while (!trabalhador.Empty()) {
1158 auto trabalhadorID = trabalhador.Pop();
1161 }
1162
1163 // receber resultados e continuar a dar trabalho caso exista
1164 while (!trabalhar.Empty()) {
1166
1170 resultados += {dados[0], dados[1]};
1171 resultados.Last().valor.Count(dados[2]);
1172 trabalhar -= stat.MPI_SOURCE;
1173 trabalhador += stat.MPI_SOURCE;
1174 MPI_Recv(resultados.Last().valor.Data(), dados[2], MPI_LONG_LONG,
1176 // tempo de espera do trabalhador
1177 esperaTrabalhadores += (double)((int64_t)resultados.Last().valor.Pop()) / 1000.;
1178
1180 // mostrar uma linha por cada execução
1181 Debug(ATIVIDADE, false,
1182 "\n ├─ %-2s%-15s %-2s%-5d %-2s%-5d %-2s%-5d %-2s%-5d %-2s ",
1183 Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_TESTE)),
1184 Icon(EIcon::TAREFA), totalTarefas - tarefas.Count(),
1185 Icon(EIcon::INST), resultados.Last().instancia,
1186 Icon(EIcon::CONF), resultados.Last().configuracao,
1187 Icon(EIcon::PROCESSO), trabalhador.Last(),
1188 Icon(EIcon::IND));
1189 for (auto ind : resultados.Last().valor)
1190 printf("%" PRId64 " ", ind);
1191 fflush(stdout);
1192 Cronometro(CONT_REPORTE, true);
1193 }
1194
1195 // ainda há tarefas
1196 if (!tarefas.Empty()) {
1197 auto tarefa = tarefas.Pop();
1198 dados[0] = tarefa.instancia;
1199 dados[1] = tarefa.configuracao;
1200 trabalhar += trabalhador.Last();
1202 }
1203 else { // tudo feito, mandar sair
1204 dados[0] = dados[1] = -1;
1205 auto trabalhadorID = trabalhador.Pop();
1208 }
1209 }
1210
1211 // contar a espera dos trabalhadores, após terminarem
1212 for (int i = 1; i < mpiCount; i++)
1214
1215 // escrever o ficheiro de resultados
1216 int backupCount = mpiCount;
1220 mpiCount = 1; // forçar a escrita do ficheiro apenas neste processo
1222 Debug(ATIVIDADE, false,
1223 "\n ├─ %-2s Ficheiro %s.csv gravado.\n"
1224 " │ %-2s Tempo real: %s",
1225 Icon(EIcon::RESULT), *ficheiro,
1226 Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_TESTE))) &&
1227 Debug(ATIVIDADE, false, "\n │ %-2s CPU total: %s",
1228 Icon(EIcon::TEMPO), *MostraTempo(Cronometro(CONT_TESTE) * (backupCount - 1))) &&
1229 Debug(ATIVIDADE, false, "\n │ %-2s Espera do gestor: %s",
1230 Icon(EIcon::TEMPO), *MostraTempo(esperaGestor)) &&
1231 Debug(ATIVIDADE, false, "\n │ %-2s Espera trabalhadores: %s",
1232 Icon(EIcon::TEMPO), *MostraTempo(esperaTrabalhadores)) &&
1233 Debug(ATIVIDADE, false, "\n │ %-2s Utilização:\n │ - Total: %.1f%%\n │ - Gestor: %.1f%%\n │ - Trabalhadores: %.1f%% ",
1234 Icon(EIcon::TAXA), taxaUtilizacao * 100, taxaUtilizacaoG * 100, taxaUtilizacaoT * 100);
1236
1237 TesteFim();
1238#endif
1239}
1240
1242{
1243#ifdef MPI_ATIVO
1244 int dados[3] = { 0, 0, 0 }; // instância, configuração
1245 // Ciclo:
1246 // 1. Solicitar tarefa ao mestre
1247 // 2. Executar tarefa
1248 // 3. Enviar resultados ao mestre
1249 // 4. Repetir até receber ordem de paragem
1250
1251 TVector<TResultado> resultados; // guarda as soluções obtidas
1252 TVector<int> atual;
1253
1254 TesteInicio(instancias, atual);
1255
1256 for (;;) {
1257 // receber nova tarefa
1259 if (dados[0] < 0)
1260 break;
1261
1263
1264 // enviar registo para master, e apagar
1265 // dados[0] e dados[1] já têm a configuração e instância
1266 dados[2] = resultados.Last().valor.Count() + 1;
1269 // colocar a espera no final do vetor de resultados
1270 resultados.Last().valor += (int64_t)((Cronometro(CONT_TESTE) - inicioEspera) * 1000 + 0.5);
1271 MPI_Send(resultados.Last().valor.Data(), dados[2], MPI_LONG_LONG, 0, TAG_VALORES, MPI_COMM_WORLD);
1272
1273 resultados.Pop();
1274 }
1275
1276 // saída, enviar o tempo de trabalho e tempo de espera totais
1277
1278 TesteFim();
1279#endif
1280}
1281
1282void TProcura::ExecutaTarefa(TVector<TResultado>& resultados, int inst, int conf)
1283{
1284 // carregar a configuração
1286 instancia.valor = inst;
1287 // carregar instância
1288 Inicializar();
1289 // executar um algoritmo
1291 {
1293 Parametro(NIVEL_DEBUG) = NADA; // remover informação de debug do algoritmo, já que é um teste empírico
1294 if (!ficheiroGravar.Empty()) {
1295 Gravar();
1297 }
1298 else
1301 }
1304
1305
1306 if (resultado >= 0) {
1307 mpiID == 0 && Debug(COMPLETO, false, "%-2s%-5d", Icon(EIcon::SUCESSO), resultado);
1308 }
1309 else {
1310 if (Parar())
1311 mpiID == 0 && Debug(COMPLETO, false, "%-2s", Icon(EIcon::INSUC));
1312 if (TempoExcedido())
1313 mpiID == 0 && Debug(COMPLETO, false, "%-2s", Icon(EIcon::TEMPO));
1314 if (memoriaEsgotada)
1315 mpiID == 0 && Debug(COMPLETO, false, "%-2s", Icon(EIcon::MEMORIA));
1316 if (resultado < 0 && !Parar()) { //Instância Impossível! (se algoritmo completo) ");
1317 mpiID == 0 && Debug(COMPLETO, false, "%-2s%-2s", Icon(EIcon::SUCESSO), Icon(EIcon::IMP));
1318 resultados.Last().solucao = "vazio";
1319 }
1320 else // não resolvido, cancelar resultados
1321 resultados.Last().valor.First() = RES_NAO_RESOLVIDO;
1322 }
1323 if (mpiID == 0 && Parametro(NIVEL_DEBUG) >= COMPLETO) {
1324 printf("%-2s ", Icon(EIcon::IND));
1325 for (auto ind : resultados.Last().valor)
1326 printf("%" PRId64 " ", ind);
1327 }
1328}
1329
1330// processa os argumentos da função main
1331void TProcura::main(int argc, char* argv[], TString nome) {
1335 bool configIntroduzido = false; // caso sejam dadas configurações, remover as existentes
1336 TVector<int> referencias = { 0,100,0,100000 }; // custoMin, custoMax, tempoMin, tempoMax
1337
1339
1340 if (argc <= 1) {
1341 TesteManual(*nome);
1342 return;
1343 }
1344 else if (strcmp(argv[1], "-h") == 0) {
1346 return;
1347 }
1348
1349 // 1:10 --- conjunto de instâncias (idêntico ao interativo)
1350 instancias = argv[1];
1351 if (instancias.Empty()) {
1353 return;
1354 }
1355
1356 fichResultados = "resultados";
1357
1359
1360 // opcionais:
1361 // -R resultados --- ficheiro de resultados em CSV (adicionada extensão .csv)
1362 // -S solucoes [custoMin custoMax tempoMin tempoMax [<ids>]] --- ficheiro de solucoes em CSV
1363 // -F instancia_ --- prefixo dos ficheiros de instâncias
1364 // -I 2,1,3 --- indicadores selecionados por ordem
1365 // -P P1=1:3 x P2=0:2 --- formatação de parâmetros (idêntico ao interativo)
1366 for (int i = 2; i < argc; i++) {
1367 if (strcmp(argv[i], "-R") == 0 && i + 1 < argc) {
1368 (fichResultados = "").printf("%s", argv[++i]);
1369 }
1370 else if (strcmp(argv[i], "-S") == 0 && i + 1 < argc) {
1371 (fichSolucoes = "").printf("%s", argv[++i]);
1372 // carregar as 4 referências, caso existam
1373 if (i + 1 < argc && isdigit(argv[i + 1][0])) {
1374 referencias = {};
1375 for (auto& token : TString(argv[++i]).tok(","))
1377 if (referencias.Count() != 4) // usar valores por omissão se não forem dadas as 4 referências
1378 referencias = { 0,100,0,100000 };
1379 }
1380 // e os ids de instâncias impossíveis, caso existam
1381 if (i + 1 < argc && isdigit(argv[i + 1][0]))
1382 impossiveis = argv[++i];
1383 }
1384 else if (strcmp(argv[i], "-F") == 0 && i + 1 < argc) {
1385 (ficheiroInstancia = "").printf("%s", argv[++i]);
1386 }
1387 else if (strcmp(argv[i], "-FG") == 0 && i + 1 < argc) {
1388 (ficheiroGravar = "").printf("%s", argv[++i]);
1389 }
1390 else if (strcmp(argv[i], "-M") == 0 && i + 1 < argc) {
1391 if ((modoMPI = atoi(argv[i + 1])) != 1)
1392 modoMPI = 0; // apenas 0 ou 1
1393 }
1394 else if (strcmp(argv[i], "-G") == 0 && i + 1 < argc) {
1395 if ((gravarSolucao = atoi(argv[i + 1])) != 1)
1396 gravarSolucao = 0; // apenas 0 ou 1
1397 }
1398 else if (strcmp(argv[i], "-I") == 0 && i + 1 < argc) {
1399 indAtivo = {};
1400 for (auto& token : TString(argv[i + 1]).tok(",")) {
1401 indAtivo += (atoi(token) - 1);
1402 indicador[indAtivo.Last()].indice = indAtivo.Count() - 1;
1403 }
1404 }
1405 else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc) {
1407 if (!configIntroduzido) { // limpa configurações anteriores ou por omissão
1408 configIntroduzido = true;
1409 configuracoes = {};
1410 }
1411 // o resto é para concatenar e enviar, até outro "-P" ou fim
1412 argParametros = "";
1413 while (++i < argc && strcmp(argv[i], "-P") != 0)
1414 argParametros.printf(" %s", argv[i]);
1419
1420 if (i >= argc) // era o último conjunto de argumentos
1421 break;
1422 else
1423 i -= 2; // recuar para processar o -P seguinte
1424 }
1425 }
1426
1427 if (!fichSolucoes.Empty()) {
1428 // dado ficheiro de soluções, apenas validar as soluções, não executar o teste empírico
1430 }
1431 else {
1432 // arrancar MPI apenas após processar os argumentos
1434
1435 if (modoMPI == 0 || mpiCount == 1)
1436 // divisão estática ou execução em série
1438 else {
1439 if (mpiID == 0)
1440 // processo mestre
1442 else
1443 // processos escravos
1445 }
1446
1447 FinalizaMPI();
1448 }
1449}
1450
1452 printf(
1453 "Uso: %s <instâncias> [opções]\n"
1454 " <instâncias> Conjunto de IDs: A | A,B,C | A:B[:C]\n"
1455 "Opções:\n"
1456 " -R <ficheiro> Nome do CSV de resultados (omissão: resultados.csv)\n"
1457 " -S solucoes [custoMin,custoMax,tempoMin,tempoMax [<ids>]]\n"
1458 " caso exista ficheiro de soluções, pretende-se apenas validação\n"
1459 " pode-se dar referências de custo min/max e tempo min/max para indicador de desempenho\n"
1460 " <ids> - identificação das instâncias impossíveis\n"
1461 " -F <prefixo> Prefixo para leitura da instância por ficheiro (omissão: vazio)\n"
1462 " -FG <prefixo> Prefixo para gravação da instância em ficheiro (omissão: vazio)\n"
1463 " -M <modo> Modo MPI: 0 = divisão estática, 1 = gestor-trabalhador\n"
1464 " -G <0/1> Gravar solução (sequência de ações): 0 = não grava, 1 = grava\n"
1465 " -I <ind> Lista de indicadores (e.g. 2,1,3)\n"
1466 " -h Esta ajuda\n"
1467 " -P <expr> Parâmetros (e.g. P1=1:3 x P2=0:2) - valores para cada parâmetro, distintos dos por omissão\n"
1468 "Exemplo: %s 1:5 -R out -F fich_ -I 3,1,4,2 -P P1=1:5 x P6=1,2 \n"
1469 " Executar sem argumentos entra em modo interativo, para explorar todos os parâmetros e indicadores\n",
1471 );
1475}
1476
1477
1478bool TProcura::RelatorioCSV(TVector<TResultado>& resultados, TString ficheiro, bool parametros) {
1479 TString nome;
1481 if (mpiCount > 1)
1482 nome.printf("%s_%d.csv", *ficheiro.tok().First(), mpiID);
1483 else
1484 nome.printf("%s.csv", *ficheiro.tok().First());
1485
1486 // cabeçalho: instância, parametros, indicadores
1487 linhas += TString("Instância;");
1488 if (parametros) {
1489 for (int i = 0; i < parametro.Count(); i++)
1490 linhas.Last().printf("P%d(%s);", i + 1, *parametro[i].nome);
1491 for (auto item : indAtivo)
1492 linhas.Last().printf("I%d(%s);", item + 1, *indicador[item].nome);
1493 linhas.Last().printf("Solução");
1494 }
1495 else {
1496 // apenas soluções: válidas, inválidas, melhor, pior
1497 linhas.Last().printf("Válidas;Inválidas;Melhor;Pior;Tempo(ms)");
1498 }
1499 for (auto& res : resultados) {
1500 linhas += TString().printf("%d;", res.instancia);
1501 if (parametros) {
1502 for (int j = 0; j < parametro.Count(); j++)
1503 // ver se parametro j está ativo na configuração configuracoes[res.configuracao]
1504 if (!ParametroAtivo(j, &(configuracoes[res.configuracao])))
1505 linhas.Last().printf(";"); // parametro inativo, não mostrar
1506 else if (parametro[j].nomeValores.Empty())
1507 linhas.Last().printf("%d;", configuracoes[res.configuracao][j]); // mostrar valor
1508 else
1509 linhas.Last().printf("%d:%s;", // mostrar valor e texto
1510 configuracoes[res.configuracao][j],
1511 *parametro[j].nomeValores[configuracoes[res.configuracao][j] - parametro[j].min]);
1512 for (auto ind : indAtivo)
1513 linhas.Last().printf("%" PRId64 ";", Registo(res, ind));
1514
1515 if (gravarSolucao) {
1516 if (!res.solucao.Empty()) {
1517 for (auto& acao : res.solucao)
1518 linhas.Last().printf("%s ", *acao);
1519 }
1520 else {
1521 // imprimir todos os valores após os indicadores
1522 for (int i = indicador.Count(); i < res.valor.Count(); i++)
1523 linhas.Last().printf("%" PRId64 ";", res.valor[i]);
1524 }
1525 }
1526 }
1527 else {
1528 // apenas soluções: válidas, inválidas, melhor, pior, tempo
1529 for (auto item : res.valor)
1530 linhas.Last().printf("%" PRId64 ";", item);
1531 }
1532 }
1533
1534 nome.writeLines(linhas);
1535
1536 return true;
1537}
1538
1540{
1541 if (ultimo) {
1542 if (!resultados.Empty() && !indAtivo.Empty()) {
1543 int col = 2;
1544 MostraCaixa("Indicadores", ECaixaParte::Topo, 70, true, 0, Icon(EIcon::IND));
1546 for (auto ind : indAtivo) {
1547 if (col > 2)
1548 col += printf(" | ");
1549 if (col >= 70) {
1551 col = 2;
1552 }
1553 col += printf(COR_LEVE "I%d(%s):" COR_RESET " %" PRId64, ind + 1,
1554 *indicador[ind].nome, Registo(resultados.Last(), ind)) - COR_LEVE_TAM;
1555 }
1557 }
1558 return;
1559 }
1560
1561 TVector<TResultado> total; // totais por cada configuração
1563 for (int i = 0; i < total.Count(); i++) {
1564 total[i].instancia = total[i].configuracao = 0;
1565 total[i].valor.Count(indicador.Count());
1566 total[i].valor.Reset(0);
1567 }
1568 TVector<int> larguras = { 6,7,11,11 };
1569 TVector<TString> titulosVazios = { "", "", "", "" };
1571 Icon(EIcon::INST),
1572 Icon(EIcon::CONF),
1573 Icon(EIcon::VALOR),
1574 Icon(EIcon::TEMPO)
1575 };
1576
1577 // mostrar os resultados apenas do custo e tempo
1581
1582
1583 for (auto& res : resultados) {
1585 if (Registo(res, IND_RESULTADO) >= -1)
1586 total[res.configuracao].instancia++;
1587
1588 str[0].printf("%d", res.instancia);
1589 str[1].printf("%d", res.configuracao + 1);
1590 str[2].printf("%" PRId64, Registo(res, IND_RESULTADO));
1591 str[3].printf("%" PRId64, Registo(res, IND_TEMPO));
1592
1594
1595 // somar tudo
1596 for (auto ind : indAtivo)
1597 Registo(total[res.configuracao], ind,
1598 Registo(total[res.configuracao], ind) +
1599 Registo(res, ind));
1600 }
1602
1603 // tabela com os totais por configuração
1604 for (int i = 0; i < total.Count(); i++) {
1605 TString str;
1606 int col = 2;
1607 str.printf("%-2s Total %-2s%d", Icon(EIcon::TAXA), Icon(EIcon::CONF), i + 1);
1610 for (auto ind : indAtivo) {
1611 col += printf(COR_LEVE "%s:" COR_RESET " ", *indicador[ind].nome) - COR_LEVE_TAM;
1612 col += printf("%" PRId64 " ", Registo(total[i], ind));
1613 if (col > 70) {
1615 col = 2;
1616 }
1617 }
1618 if (col > 70)
1620 printf(COR_LEVE "Instâncias resolvidas:" COR_RESET " %d", total[i].instancia);
1622 }
1623 // mostrar torneio entre configurações
1625 printf("\n");
1626}
1627
1629 TVector<TVector<int>> torneio; // pares de configurações: 1 melhor, 0 igual -1 pior
1631 for (int i = 0; i < torneio.Count(); i++) {
1632 torneio[i].Count(configuracoes.Count());
1633 torneio[i].Reset(0);
1634 }
1635 // registar resultados mediante o melhor resultado
1636 for (int i = 0; i < configuracoes.Count(); i++) {
1638 for (int j = 0; j < configuracoes.Count(); j++)
1639 if (i != j) {
1641 // resultados sempre por mesma ordem de instância
1642 for (int k = 0; k < configuracaoI.Count() && k < configuracaoJ.Count(); k++)
1644 }
1645 }
1647}
1648
1650{
1651 MostraCaixa("Indicadores", ECaixaParte::Topo, 70, true, 0, Icon(EIcon::IND));
1652 for (int i = 0; i < indicador.Count(); i++) {
1654 printf(COR_LEVE "I%d(%s):" COR_RESET " ", i + 1, *indicador[i].nome);
1655 if (indicador[i].indice < 0)
1656 printf("%-2sinativo ", Icon(EIcon::NSEL));
1657 else
1658 printf("%-2s%dº lugar ", Icon(EIcon::SEL), indicador[i].indice + 1);
1660 printf(COR_LEVE "%s" COR_RESET, *indicador[i].descricao);
1661 }
1663}
1664
1665
1667{
1669 pontos.Count(torneio.Count());
1670 pontos.Reset(0);
1671 // registar resultados mediante o melhor resultado
1672 for (int i = 0; i < torneio.Count(); i++)
1673 for (int j = 0; j < torneio.Count(); j++)
1674 if (i != j) {
1675 pontos[i] += torneio[i][j];
1676 if (jogo) // contar pontos perdidos de pretas
1677 pontos[j] -= torneio[i][j];
1678 }
1679
1680 // mostrar tabela do torneio
1681 printf("\n%-2s Torneio (#instâncias melhores):", Icon(EIcon::TORNEIO));
1682 BarraTorneio(true);
1683 for (int i = 0; i < pontos.Count(); i++) {
1684 printf("\n%2d", i + 1);
1685 for (int j = 0; j < pontos.Count(); j++)
1686 if (i == j)
1687 printf(" |");
1688 else
1689 printf("%3d |", torneio[i][j]);
1690 // no final colocar os pontos totais
1691 printf("%3d", pontos[i]);
1692 BarraTorneio(false);
1693 }
1694}
1695
1698 for (auto& res : resultados)
1699 if (res.configuracao == configuracao)
1700 extracao += res;
1701 return extracao;
1702}
1703
1704
1705void TProcura::BarraTorneio(bool nomes) {
1706 // barra inical/final: |----|----|----|
1707 printf("\n |");
1708 for (int i = 0; i < configuracoes.Count(); i++)
1709 if (nomes)
1710 printf("-%02d-|", i + 1);
1711 else
1712 printf("----|");
1713}
1714
1715
1717 // se não resolvido por ambos, retornar igualdade (assumir código -1 para impossível, -2 para não resolvido, menor é melhor)
1719 return 0;
1720 // se igual no custo e o tempo menor que 100, retornar igualdade
1723 return 0;
1724 // primeiro custo (ou não resolvido, -2)
1725 if ((Registo(base, IND_RESULTADO) == -2 &&
1729 return -1;
1730 if ((Registo(base, IND_RESULTADO) > -2 &&
1732 (Registo(base, IND_RESULTADO) > 0 &&
1734 return 1;
1735 // agora o tempo
1736 return Registo(base, IND_TEMPO) < Registo(alternativa, IND_TEMPO) ? 1 : -1;
1737}
1738
1740{
1741 if (TempoExcedido())
1742 Mensagem(Icon(EIcon::INSUC), " Tempo excedido");
1743 else if (memoriaEsgotada)
1744 Mensagem(Icon(EIcon::INSUC), " Memória esgotada");
1745}
1746
1747// MostrarSolucao: definir para visualizar a solução
1750 printf("\nSolução: ");
1751 for (auto& x : solucao)
1752 printf("%" PRId64 " ", x);
1753 printf(".");
1754}
1755
1756
1758 TString str;
1760 printf("%s", *prompt);
1761 if (fgets(str.Data(), BUFFER_SIZE, stdin))
1762 if (strlen(str) > 1)
1763 return atoi(str);
1764 return NAO_LIDO;
1765}
1766
1767// ler uma string
1769 TString str;
1771 printf("%s", *prompt);
1772
1773 if (fgets(str.Data(), BUFFER_SIZE, stdin) == nullptr)
1774 return TString("");
1775
1776 // remover o '\n' do final
1777 int len = (int)strlen(str);
1778 if (len > 0 && str[len - 1] == '\n')
1779 str[len - 1] = 0;
1780
1781 // retorna nova TString, com o tamanho certo
1782 return TString(*str);
1783}
1784
1786 if (instancia.max != instancia.min) {
1787 int resultado;
1788 TString texto;
1789
1790 MostraCaixa("Instância", ECaixaParte::Topo, 70, true, 0, Icon(EIcon::INST));
1792 printf(COR_LEVE "ID atual:" COR_RESET " %d " COR_LEVE "Intervalo:" COR_RESET " [%d–%d] ",
1795 printf(COR_LEVE "Prefixo atual:" COR_RESET " '%s' ", *ficheiroInstancia);
1797 texto = NovoTexto("\nNovo ID (ENTER mantém) ou novo prefixo (texto): ");
1798 resultado = atoi(texto);
1799 if (resultado != 0 || texto.Empty()) {
1800 if (resultado != 0)
1803 }
1804 else if (texto.Count() < 256)
1806 }
1807 else
1809 Inicializar();
1810}
1811
1812
1813int TProcura::Dominio(int& variavel, int min, int max) {
1814 if (variavel < min)
1815 variavel = min;
1816 if (variavel > max)
1817 variavel = max;
1818 return variavel;
1819}
1820
1821void TProcura::InicializaMPI(int argc, char* argv[])
1822{
1823#ifdef MPI_ATIVO
1824 MPI_Init(&argc, &argv);
1827#endif
1828}
1829
1831{
1832#ifdef MPI_ATIVO
1833 MPI_Finalize();
1834#endif
1835}
1836
1838 TString prefixo, int modoCor, bool duplaColuna)
1839{
1840 if (Parametro(NIVEL_DEBUG) < nivel)
1841 return;
1842 printf("\n%s%-4s ", *prefixo, *tipo);
1843 for (int i = 0; i < 10 && i < tabela.Count(); i++)
1844 printf("%4d ", i + 1);
1845 printf("\n%s────┼", *prefixo);
1846 for (int i = 0; i < 10 && i < tabela.Count(); i++)
1847 printf("────┼");
1848 for (int i = 0; i < tabela.Count(); i++) {
1849 if (i % 10 == 0)
1850 printf("\n%s%4d│", *prefixo, i);
1851 if (modoCor > 0 && modoCor <= 1000000) // conteúdo com cor de 1 a modoCor
1852 DebugHSL(tabela[i] * 360.0f / modoCor);
1853 else if (modoCor > 1000000) // 0 - verde e maiorCusto vermelho
1854 DebugHSL((1 - 1.0f * tabela[i] / (modoCor - 1000000)) * 120, .75, .5, false);
1855 else if (modoCor < 0) // índice com a cor
1856 DebugHSL((i + 1) * 360.0f / tabela.Count());
1857 printf("%4d", tabela[i]);
1858 DebugHSL();
1859 if (duplaColuna && i % 2 == 0)
1860 printf("⇄");
1861 else
1862 printf("│");
1863 }
1864}
1865
1867{
1868 // ficheiros CSV com o mesmo cabeçalho, ficheiro0.csv, ficheiro1.csv, ..., ficheiroN.csv
1870
1871 // verifica se existem os ficheiros intermédios
1872 for (int i = 0; i < mpiCount; i++)
1873 if (TString().printf("%s_%d.csv", *ficheiro, i).readLines().Empty())
1874 // não existe este ficheiro, ainda não está tudo
1875 return false;
1876
1877 for (int i = 0; i < mpiCount; i++) {
1878 linhas = TString().printf("%s_%d.csv", *ficheiro, i).readLines();
1879 if (i == 0)
1881 else
1882 // não incluir a linha de cabeçalho
1883 for (int j = 1; j < linhas.Count(); j++)
1884 todasLinhas += linhas[j];
1885
1886 remove(TString().printf("%s_%d.csv", *ficheiro, i)); // apagar ficheiro intermédio
1887 }
1889 return true;
1890}
1891
1893{
1895
1896 // adicionar os indicadores e parâmetros específicos
1897 indicador += ind;
1898 parametro += par;
1899
1900 // atualizar os valores por omissão
1901 omissao.Count(parametro.Count());
1902 for (int i = 0; i < parametro.Count(); i++)
1903 omissao[i] = parametro[i].valor;
1904
1905 instancia = inst;
1906
1907 indValores.Count(indicador.Count()).Reset(0);
1908
1909 // colocar todos os indicadores ativos por ordem de ID
1910 indAtivo = {};
1911 for (int i = 0; i < indicador.Count(); i++)
1912 indAtivo += i;
1913
1914 // corrigir prefixos ineixistentes
1915 while (parPrefixo.Count() < parametro.Count())
1916 parPrefixo += TString("");
1917 while (indPrefixo.Count() < indicador.Count())
1918 indPrefixo += TString("");
1919}
1920
1922{
1924 int error;
1925
1927
1928 // construir as opções que são distintas dos valores por omissão
1929 for (int i = 0; i < parametro.Count(); i++)
1930 if (Parametro(i) != omissao[i])
1931 opcoes.printf("%s%d ", *parPrefixo[i], Parametro(i));
1932
1933 error = system(TString().printf("%s %s %s%d > %s",
1935 if (error == -1) {
1936 Mensagem(Icon(EIcon::INSUC), " Erro ao executar o comando.");
1937 return RES_NAO_RESOLVIDO;
1938 }
1939 else if (error != 0) {
1940 Mensagem(Icon(EIcon::INSUC), " O comando retornou um código de erro: %d", error);
1941 return RES_NAO_RESOLVIDO;
1942 }
1943
1944 // extrair indicadores com base no indPrefixo
1945 for (auto& linha : resultFile.readLines())
1946 for (int i = 0; i < indPrefixo.Count(); i++)
1947 if (!indPrefixo[i].Empty()) {
1948 const char* ptr = strstr(linha, indPrefixo[i]);
1949 if (ptr)
1950 indValores[i] = (int)(atof(ptr + indPrefixo[i].Count() - 1) + 0.5);
1951 }
1952
1954 remove(resultFile); // apagar ficheiro de resultados intermédio
1955 return 0;
1956}
1957
1959{
1960 if (id < indValores.Count())
1961 return indValores[id];
1962 return TProcura::Indicador(id);
1963}
constexpr int BUFFER_SIZE
constexpr int BUFFER_SIZE
Definition TProcura.cpp:8
@ TAG_TRABALHO
Definition TProcura.h:125
@ TAG_VALORES
Definition TProcura.h:127
@ TAG_CABECALHO
Definition TProcura.h:126
#define COR_LEVE
Definition TProcura.h:34
@ GRAVAR
Definition TProcura.h:104
@ LER
Definition TProcura.h:104
constexpr int RES_INVALIDO
Definition TProcura.h:19
@ IND_TEMPO
tempo em milissegundos consumidos
Definition TProcura.h:46
@ IND_ITERACOES
número de iterações consumidas
Definition TProcura.h:47
@ IND_RESULTADO
resultado do algoritmo (>=0 custo da solução, -1 impossível, -2 não resolvido)
Definition TProcura.h:45
constexpr int COR_LEVE_TAM
Definition TProcura.h:42
constexpr int NAO_LIDO
Definition TProcura.h:14
#define COR_RESET
Definition TProcura.h:35
#define COR_INATIVO_LEVE
Definition TProcura.h:39
constexpr int RES_NAO_RESOLVIDO
Definition TProcura.h:18
constexpr int RES_VAZIO
Definition TProcura.h:20
ENivelDebug
Níveis de detalhamento para debug.
Definition TProcura.h:90
@ ATIVIDADE
Apenas eventos principais.
Definition TProcura.h:92
@ COMPLETO
Mostra toda a execução detalhadamente.
Definition TProcura.h:95
@ NADA
Sem informações de debug.
Definition TProcura.h:91
@ DETALHE
Debug detalhada sobre estados e decisões.
Definition TProcura.h:94
constexpr int RES_IMPOSSIVEL
Definition TProcura.h:17
@ CONT_TESTE
Tempo total do teste (todas as execuções)
Definition TProcura.h:113
@ CONT_REPORTE
Tempo entre mensagens durante o teste.
Definition TProcura.h:114
@ CONT_ALGORITMO
Tempo da execução do algoritmo por instância.
Definition TProcura.h:112
@ NIVEL_DEBUG
Nível de debug, de reduzido a completo.
Definition TProcura.h:71
@ LIMITE_TEMPO
Tempo limite em segundos.
Definition TProcura.h:73
#define COR_ATIVO_LEVE
Definition TProcura.h:38
ECaixaParte
Define as partes de uma caixa de texto para exibição formatada.
Definition TProcura.h:136
#define COR_INATIVO
Definition TProcura.h:37
#define COR_ATIVO
Definition TProcura.h:36
TVector< int > _TV(const char *str)
Definition TVector.h:1460
TVector< int64_t > indValores
Definition TProcura.h:890
void ResetParametros()
Reset parâmetros, assumindo variáveis da classe definidas.
int ExecutaAlgoritmo()
Executa o algoritmo e extrai os indicadores.
int64_t Indicador(int id)
retorna indicadores após execução
TVector< TString > indPrefixo
Definition TProcura.h:880
TVector< int > omissao
Definition TProcura.h:891
TVector< TIndicador > ind
Definition TProcura.h:879
TVector< TString > parPrefixo
Definition TProcura.h:884
TVector< TParametro > par
Definition TProcura.h:883
TParametro inst
Definition TProcura.h:878
virtual void MostrarSolucao()
definir para visualizar a solução
static bool memoriaEsgotada
Flag indicando problemas de memória esgotada.
Definition TProcura.h:583
static void MostraCaixa(TVector< TString > titulo, ECaixaParte parte, TVector< int > largura, bool aberta=true, int identacao=0)
Definition TProcura.cpp:368
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
virtual int ExecutaAlgoritmo()
Executa o algoritmo com os parametros atuais.
Definition TProcura.h:262
static int Dominio(int &variavel, int min=INT_MIN, int max=INT_MAX)
Limita o domínio de um parâmetro inteiro.
virtual void RelatorioValidacao(TVector< TResultado > resultados, TVector< int > referencias)
Definition TProcura.cpp:293
static int modoMPI
Modo MPI.
Definition TProcura.h:590
virtual void Inicializar(void)
Coloca o objecto no estado inicial da procura.
Definition TProcura.h:248
static TVector< TVector< int > > configuracoes
Conjuntos de configurações para teste empírico.
Definition TProcura.h:573
static int resultado
Resultado retornado pelo algoritmo na última execução.
Definition TProcura.h:575
void BarraTorneio(bool nomes)
Mostra a barra de progresso ou nomes do torneio.
void ExecutaTarefa(TVector< TResultado > &resultados, int inst, int conf)
Executa uma tarefa num teste empírico.
void AjudaUtilizacao(TString programa)
Mostra ajuda de utilização do programa.
void MostrarTorneio(TVector< TVector< int > > &torneio, bool jogo=false)
Mostra os resultados do torneio.
static TString ficheiroInstancia
prefixo do nome ficheiro de uma instância - editado pelo utilizador Caso não seja nulo,...
Definition TProcura.h:562
static int mpiID
MPI - rank do processo.
Definition TProcura.h:585
void MostrarConfiguracoes(int detalhe, int atual=-1)
Mostra as configurações disponíveis.
Definition TProcura.cpp:934
void MostraParametros(int detalhe=1, TVector< int > *idParametros=NULL, TString titulo="")
Mostra os parâmetros atuais.
Definition TProcura.cpp:553
virtual int64_t Indicador(int id)
Retorna um indicador, após a execução do algoritmo.
Definition TProcura.cpp:73
virtual TVector< TString > Solucao()
retorna uma solução no formato do TResultado, para ser gravada em ficheiro de soluções,...
Definition TProcura.h:553
static TString NovoTexto(TString prompt)
static int gravarSolucao
Gravar solução CSV (todas as ações)
Definition TProcura.h:593
static TString ficheiroGravar
prefixo do nome do ficheiro para gravar a instância para ficheiro (terá sido gerada)
Definition TProcura.h:564
TVector< TResultado > ExtrairConfiguracao(TVector< TResultado > &resultados, int configuracao)
Extrai resultados de uma determinada configuração.
virtual void Gravar(void)
Definition TProcura.h:251
void TesteInicio(TVector< int > &instancias, TVector< int > &configAtual)
arranque de teste, auxiliar aos Testes Empíricos
Definition TProcura.cpp:987
static int iteracoes
Número total de iterações realizadas na última execução.
Definition TProcura.h:579
static void FinalizaMPI()
Finaliza o ambiente MPI, se aplicável.
virtual void TesteValidacao(TVector< int > instancias, TVector< int > impossiveis, TVector< int > referencias, TString fichSolucoes, TString fichResultados="")
Executa testes de validação, executando cada solução na instância respetiva, e verificando a sua vali...
Definition TProcura.cpp:160
int NovaConfiguracao(TVector< int > &parametros)
Adiciona uma nova configuração se ainda não existir.
Definition TProcura.cpp:723
TVector< int > SolicitaInstancias()
Solicita ao utilizador uma lista de instâncias.
Definition TProcura.cpp:801
virtual void ResetParametros()
Inicializa os parâmetros, indicadores e instâncias.
Definition TProcura.cpp:48
virtual void TesteEmpiricoTrabalhador(TVector< int > instancias, TString ficheiro="")
Teste empírico com modo mestre-escravo (este é o escravo)
virtual bool Parar(void)
Verifica se a procura deve ser interrompida.
Definition TProcura.h:405
bool JuntarCSV(TString ficheiro)
Juntar ficheiros CSV gerados por diferentes processos MPI em um único ficheiro.
static int NovoValor(TString prompt)
bool ParametroAtivo(int id, TVector< int > *valores=NULL) const
Definition TProcura.h:609
virtual void TesteManual(TString nome)
Inicializa a interação com o utilizador.
Definition TProcura.cpp:103
static TString MostraTempo(double segundos)
Mostra tempo num formato humano.
Definition TProcura.cpp:752
virtual void ExecucaoTerminada()
Chamar após a execução do algoritmo. Grava o tempo consumido.
virtual void main(int argc, char *argv[], TString nome)
Inicializa a interação com o utilizador.
void MostraRelatorio(TVector< TResultado > &resultados, bool ultimo=false)
Mostra um relatório dos resultados.
bool EditarIndicadores()
Permite ao utilizador editar os indicadores a utilizar.
Definition TProcura.cpp:646
static int mpiCount
MPI - número de processos.
Definition TProcura.h:587
static void InicializaMPI(int argc, char *argv[])
Inicializa o ambiente MPI, se aplicável.
void MostraIndicadores()
Mostra os indicadores definidos.
static void Mensagem(TString titulo, const char *fmt,...)
Definition TProcura.cpp:502
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
virtual void TesteEmpiricoGestor(TVector< int > instancias, TString ficheiro="")
Teste empírico com modo mestre-escravo (este é o mestre)
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...
bool RelatorioCSV(TVector< TResultado > &resultados, TString ficheiro, bool parametros=true)
Gera um relatório CSV com os resultados.
virtual bool Validar(TVector< TString > solucao)
Verifica a validade de uma solução para a instância atual.
Definition TProcura.h:481
void TesteFim()
static clock_t instanteFinal
Instante final (deadline) da corrida atual.
Definition TProcura.h:581
void EditarParametros()
Permite ao utilizador editar os parâmetros.
Definition TProcura.cpp:674
void InserirConfiguracoes(TString str, TVector< int > &base)
Insere configurações a partir de uma string.
Definition TProcura.cpp:862
int MelhorResultado(TResultado base, TResultado alternativa)
Compara dois resultados para determinar o melhor.
virtual void Explorar()
definir para explorar manualmente os dados (não definido em TProcura, apenas em TProcuraConstrutiva)
Definition TProcura.h:547
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
void CalculaTorneio(TVector< TResultado > &resultados)
Calcula o torneio entre várias configurações.
void ConfiguracaoAtual(TVector< int > &parametros, int operacao)
Grava ou lê a configuração atual.
Definition TProcura.cpp:740
static TVector< int > indAtivo
Definition TProcura.h:571
static TParametro instancia
ID da instância atual, a ser utilizado em SolucaoVazia().
Definition TProcura.h:22
virtual TVector< int64_t > CodificarSolucao()
retorna um vetor de inteiros com a codificação da solução (esta codificação será adicionada aos indic...
Definition TProcura.h:551
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
void InserirRegisto(TVector< TResultado > &resultados, int inst, int conf)
Insere um novo registo de resultados.
Definition TProcura.cpp:778
virtual void TesteEmpirico(TVector< int > instancias, TString ficheiro="")
Executa testes empíricos, em todas as configurações guardadas, nas instâncias selecionadas.
static TVector< TParametro > parametro
Parâmetros a serem utilizados na configuração atual.
Definition TProcura.h:567
void EditarConfiguracoes()
Permite ao utilizador editar as configurações.
Definition TProcura.cpp:817
int64_t Registo(TResultado &resultado, int id)
Procura um registo com determinado id.
Definition TProcura.cpp:788
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
void SolicitaInstancia()
Solicita ao utilizador o ID da instância a utilizar, permitindo alterar também o prefixo do ficheiro.
static double tempo
tempo consumido na última execução.
Definition TProcura.h:577
bool TempoExcedido()
Definition TProcura.h:597
static void MostraConjunto(TVector< int > valores, const char *etiqueta)
Definition TProcura.cpp:969
TVector< TString > tok(const char *delim=" \t\n\r") const
Definition TVector.h:1196
TString & printf(const char *fmt,...)
Definition TVector.h:1150
bool Empty() const
Definition TVector.h:1184
TVector< TString > readLines()
Definition TVector.h:1229
TString & writeLines(const TVector< TString > &lines, bool append=false)
Definition TVector.h:1248
Item & First()
Definition TVector.h:224
Item & Last()
Definition TVector.h:227
TVector< Item > & Delete(int i)
Remove o elemento na posição i deslocando os seguintes.
Definition TVector.h:826
int Count() const
Definition TVector.h:230
Item * Data()
Acesso direto.
Definition TVector.h:219
virtual bool Empty() const
Definition TVector.h:233
int ContaUTF8(const char *str)
Definition compact.h:26
void init_io()
Definition compact.h:14
Estrutura para registo de um parâmetro.
Definition TProcura.h:175
int valor
valor do parâmetro
Definition TProcura.h:179
int max
valor máximo que o parâmetro pode tomar
Definition TProcura.h:183
int min
valor mínimo que o parÂmetro pode tomar
Definition TProcura.h:181