7#define BUFFER_SIZE 1024
52 static const char* nomesAlgoritmos[] = {
55 "Profundidade Primeiro",
60 static const char* nomesDebug[] = {
66 static const char* nomesRepetidos[] = {
73 parametro.Add({
"Algoritmo",1,1,7,
"Algoritmo base a executar.", nomesAlgoritmos });
75 parametro.Add({
"Debug",0,0,4,
"Nível de debug, de reduzido a completo.",nomesDebug });
77 parametro.Add({
"Ver",4,1,100,
"Mostra estado a cada K ações. Se 1 mostra sempre estados e nunca ações.",NULL });
79 parametro.Add({
"Seed",1,1,1000000,
"Semente aleatória para inicializar a sequência de números pseudo-aleatórios.",NULL });
81 parametro.Add({
"Tempo",10,1,3600,
"Tempo limite em segundos. ",NULL });
83 parametro.Add({
"Gerações",0,0,1000000000,
"Número de gerações máximo (0 não há limite). ", NULL });
85 parametro.Add({
"Expansões",0,0,1000000000,
"Número de expansões máximo (0 não há limite). ",NULL });
87 parametro.Add({
"Avaliações",0,0,1000000000,
"Número de avaliações máximo (0 não há limite). ",NULL });
90 "Valor dependente do algoritmo. \n\
91Largura: 0 sem limite, >0 número máximo de estados gerados não expandidos. \n\
92Profundidade: >0 limite de profundidade, =0 iterativo, <0 sem limite.",NULL });
94 parametro.Add({
"Repetidos", 1,1,3,
"Forma de lidar com os estados repetidos (ignorá-los, ascendentes, gerados).",
98 "Peso aplicado à heuristica, na soma com o custo para calculo do lower bound. No A*, se peso 0, fica custo uniforme, h(n) não conta, se peso 100 fica A* normal, se superior a 100 aproxima-se do melhor primeiro.",NULL });
101 "Ruído a adicionar à heurística, para testes de robustez. Se K positivo, adicionar entre 0 e K-1, se negativo, o valor a adicionar pode ser positivo ou negativo.",NULL });
104 "Baralhar os sucessores ao expandir.",NULL });
114 for (
int i = 0; i < sucessores.
Count(); i++)
115 if (strcmp(acao,
Acao(sucessores[i])) == 0) {
131 for (
int i = 0; i < sucessores.
Count(); i++) {
132 sucessores[i]->pai =
this;
133 sucessores[i]->custo +=
custo;
138 for (
int i = 0; i < sucessores.
Count(); i++)
141 delete sucessores[i];
142 sucessores[i] = NULL;
148 for (
int i = 0; i < sucessores.
Count(); i++) {
150 while (avo != NULL && avo->
Distinto(sucessores[i]))
154 delete sucessores[i];
155 sucessores[i] = NULL;
170 for (
int i = 0; i < vector.
Count(); i++)
171 if (i != excepto && i > maiorQue && vector[i] != NULL)
185 for (
int i = 0; i < lista.
Count() && !
Parar(); i++) {
187 lista[i]->DebugPasso();
190 lista[i]->Sucessores(sucessores);
194 for (
int j = 0; j < sucessores.
Count(); j++) {
195 lista.
Add(sucessores[j]);
198 if (lista.
Last()->SolucaoCompleta()) {
205 lista[i]->DebugSucessores(sucessores);
244 while (atual->
pai != NULL) {
259 int maximo =
limite - porProcessar;
260 if (maximo >= 0 && maximo < sucessores.
Count()) {
261 for (
int i = maximo; i < sucessores.
Count(); i++)
262 delete sucessores[i];
263 sucessores.
Count(maximo);
311 }
while (resultado == -1 && !
Parar());
320 if((nivel>1 || nivel<0) && !
Parar()) {
325 for (
int i = 0; i < sucessores.
Count(); i++) {
363 for (
int i = 0; i <
caminho.Count(); i++) {
381 printf(
"Caminho vazio.");
394 if ((nivel <= 0 || nivel > 1) && !
Parar()) {
401 for (
int i = 0; i <
id.Count(); i++) {
420 if (upperBound == 0) {
433 }
while (resultado == -1 && !
Parar());
447 for (
int i = 0; i <
id.Count(); i++) {
448 int atual = sucessores[
id[i]]->LowerBound();
450 if (atual > upperBound) {
457 if (sucessores[
id[i]]->
IDAStar(upperBound) >= 0)
483 for (
int i = 0; i <
id.Count(); i++) {
485 if (upperBound && sucessores[
id[i]]->
LowerBound() >= upperBound) {
489 int resultado = sucessores[
id[i]]->BranchAndBound(upperBound);
491 if (resultado > 0 && (!upperBound || resultado < upperBound))
492 upperBound = resultado;
505 for (
int i = 0; i < sucessores.
Count(); i++) {
506 sucessores[i]->heuristica = sucessores[i]->Heuristica();
511 heuristicas.
Sort(
id);
561 printf(
"\nTProcuraConstrutiva::Debug() não definido.");
571 if (sucessor == 0 && sucessores == 1) {
575 else if (sucessor == 0) {
579 else if (sucessor > 0 && sucessor < sucessores - 1) {
608 }
else if(sucessores>0)
623 printf(
" Solução encontrada!");
627 printf(
"(g:%d)",
custo);
645 printf(
" %s",
pai->
Acao(
this));
656 for (
int i = 0; i <
ramo.
Count() - (tudo ? 0 : 1); i++)
677 for (
int i = 0; i < sucessores.
Count() && i < 30; i++) {
678 printf(
"%s ",
Acao(sucessores[i]));
686 for (
int i = 0; i < sucessores.
Count() && i < 30; i++) {
689 sucessores[i]->DebugEstado(i + 1);
690 if (i < sucessores.
Count() - 1)
694 printf(
" %s",
Acao(sucessores[i]));
696 sucessores[i]->Debug();
709 printf(
"\nIteração %d:", iteracao);
722 printf(
"(#%d) ",
pai);
724 printf(
"g:%d ",
custo);
758 int selecao, resultado;
765 printf(
"\n%s", nome);
767 printf(
"\n[Estatísticas] expansões %d | gerações %d | avaliações %d ",
771_______________________________________________________________________________\n\
772| 1 - Inicializar | 2 - Explorar | 3 - Solução/Caminho |\n\
773| 4 - Parâmetros | 5 - Executar | 6 - Configurações | 7 - Teste");
776 switch (
Dominio(selecao, 0, 8)) {
787 printf(
"\nResultado: %d", resultado);
798 default: printf(
"\nOpção não definida.");
break;
806 for (
int i = 0; i < nElementos; i++) {
807 int parID = (idParametros == NULL ? i : (*idParametros)[i]);
810 printf(
"P%d:", parID + 1);
812 printf(
"P%d(%s): ", parID + 1,
parametro[parID].nome);
822 if (i < nElementos - 1) {
834 int opcao = 0, valor;
841 if (
parametro[opcao - 1].descricao != NULL)
842 printf(
"\n%s",
parametro[opcao - 1].descricao);
844 if (
parametro[opcao - 1].nomeValores != NULL)
846 printf(
"\n%d: %s", i,
853 printf(
"\nP%d (atual %d): ", opcao,
parametro[opcao - 1].valor);
856 if (valor !=
NAO_LIDO || valor == 0)
867 for (
int i = 0; i <
parametro.Count() && i < parametros.
Count(); i++)
870 else if (operacao ==
ler) {
872 for (
int i = 0; i <
parametro.Count(); i++)
897 if ((
id =
NovoValor(
"\nSelecionar configuração (negativo apaga): ")) !=
NAO_LIDO) {
927 printf(
"\n--- Configuração %d", i + 1);
929 printf(
" --- atual");
958 if (inicio ==
NAO_LIDO || inicio == 0)
976 clock_t inicioCorrida;
982 inicioCorrida = clock();
989 clock() - inicioCorrida });
996 printf(
"Não resolvido. ");
998 printf(
"Tempo excedido. ");
1000 printf(
"Memória esgotada. ");
1001 if (resultado < 0 && !
Parar())
1002 printf(
"Instância Impossível! (se algoritmo completo) ");
1004 resultados.
Last().custo = -2;
1023 for (
int i = 0; i < total.
Count(); i++)
1024 total[i] = { 0,0,0,0,0,0,0 };
1027 printf(
"\n ID |conf| custo(g) | expansões | gerações | avaliações | tempo(s) |");
1028 printf(
"\n----|----|----------|------------|-----------|------------|----------|");
1029 for (
int i = 0; i < resultados.
Count(); i++) {
1030 if (resultados[i].
custo >= -1)
1031 total[resultados[i].configuracao].instancia++;
1032 printf(
"\n%3d |%3d |", resultados[i].
instancia, resultados[i].configuracao + 1);
1033 if (resultados[i].
custo < 0)
1034 printf(
" %8s |", resultados[i].
custo < -1 ?
"não res." :
"sem sol.");
1036 printf(
" %8d |", resultados[i].
custo);
1037 printf(
" %10d | %9d | %10d | %7.3fs |",
1041 1. * resultados[i].tempo / CLOCKS_PER_SEC);
1042 if (resultados[i].
custo > 0)
1043 total[resultados[i].configuracao].custo += resultados[i].custo;
1044 total[resultados[i].configuracao].expansoes += resultados[i].expansoes;
1045 total[resultados[i].configuracao].geracoes += resultados[i].geracoes;
1046 total[resultados[i].configuracao].avaliacoes += resultados[i].avaliacoes;
1047 total[resultados[i].configuracao].tempo += resultados[i].tempo;
1049 printf(
"\n----|----|----------|------------|-----------|------------|----------| resolvidas");
1051 for (
int i = 0; i < total.
Count(); i++) {
1052 printf(
"\nTotal%3d |", i+1);
1053 printf(
" %8d | %10d | %9d | %10d | %7.3fs | %3d",
1058 1. * total[i].tempo / CLOCKS_PER_SEC,
1072 torneio[i].
Reset(0);
1081 for (
int k = 0; k < configuracaoI.
Count() && k < configuracaoJ.
Count(); k++)
1092 pontos.
Count(torneio.Count());
1095 for (
int i = 0; i < torneio.Count(); i++)
1096 for (
int j = 0; j < torneio.Count(); j++)
1098 pontos[i] += torneio[i][j];
1100 pontos[j] -= torneio[i][j];
1104 printf(
"\nTorneio (#instâncias melhores):");
1106 for (
int i = 0; i < pontos.
Count(); i++) {
1107 printf(
"\n%2d", i + 1);
1108 for (
int j = 0; j < pontos.
Count(); j++)
1112 printf(
"%3d |", torneio[i][j]);
1114 printf(
"%3d", pontos[i]);
1122 for (
int j = 0; j < resultados.
Count(); j++)
1123 if (resultados[j].
instancia == i && resultados[j].configuracao == configuracao)
1124 extracao.
Add(resultados[j]);
1133 printf(
"-%02d-|", i + 1);
1141 if (base.
custo == -2 && alternativa.
custo == -2)
1144 if (base.
custo == alternativa.
custo && 10 * abs(base.
tempo - alternativa.
tempo) / CLOCKS_PER_SEC == 0)
1152 return base.
tempo < alternativa.
tempo ? 1 : -1;
1162 printf(
" (%.3fs)", 1.0 * (clock() - inicio) / CLOCKS_PER_SEC);
1164 printf(
" Tempo excedido.");
1166 printf(
" Memória esgotada.");
1171 printf(
"%s", prompt);
1173 if (strlen(str) > 1)
1181 printf(
"\nNova instância (atual %d) [%d-%d]: ",
1212 if (sucessores.
Count() == 0) {
1213 printf(
"\nSem sucessores.");
1218 printf(
"\nSucessor [1-%d, ação(ões), exe]:", sucessores.
Count());
1221 if (opcao == 0 && strlen(str)>1) {
1223 opcao = sucessores.
Count() + 1;
1224 token = strtok(str,
" \t\n\r");
1226 if (strcmp(token,
"exe") == 0) {
1233 printf(
"Valor: %d\n", valor);
1241 case -1: printf(
"Impossível\n");
break;
1242 case -2: printf(
"Não resolvido\n");
break;
1243 default: printf(
"Resolvido (%d)\n", resultado);
break;
1247 delete backup.
Pop();
1263 printf(
"Ação %s inválida.\n", token);
1266 token = strtok(NULL,
" \t\n\r");
1268 if (token != NULL) {
1277 }
while (token != NULL);
1279 printf(
"Executadas %d ações com sucesso.\n", nAcoes);
1283 if (opcao > 0 && opcao <= sucessores.
Count())
1284 Copiar(sucessores[opcao - 1]);
1286 }
while (opcao != 0);
1291 uint32_t h = 2166136261;
1298 for (
int i = 0; i < 8 && valor; i++) {
1299 unsigned char octeto = valor & 255;
1324 printf(
"\nHT: utilização %d%%, reuso: %.2f vezes",
1341 unsigned int original =
Hash();
1386 for (
int i = 1; i < indice.Count(); i++)
1387 if (indice[i].estado != NULL)
1388 delete indice[i].estado;
1392int CListaNo::NovoElemento(
TNo elemento) {
1394 if (limite == 0 || indice.Count() < 2 * limite) {
1396 indice.Add({ elemento, 1, 1 });
1397 id = indice.Count() - 1;
1401 if (livre.
Count() == 0)
1406 indice[
id = livre.
Pop()] = { elemento, 1, 1 };
1411void CListaNo::LibertarLista() {
1412 bool jaProcessados =
false;
1415 while (livre.
Count() < limite) {
1416 if (!jaProcessados) {
1417 jaProcessados =
true;
1420 LibertarSeguinte(0);
1423 int anteriorID = -1, piorID = -1;
1430 while (livre.
Count() < limite)
1431 LibertarSeguinte(
atual);
1436 LibertarSeguinte(piorID);
1437 if (livre.
Count() < limite) {
1440 while (
Proximo(anteriorID) != piorID) {
1441 indice[anteriorID].proxDistinto = 1;
1442 anteriorID =
Proximo(anteriorID);
1444 LibertarSeguinte(anteriorID);
1452void CListaNo::LibertarSeguinte(
int id) {
1455 if (indice[i].estado != NULL) {
1456 delete indice[i].estado;
1457 indice[i].estado = NULL;
1459 indice[id].prox = indice[i].prox;
1460 indice[id].proxDistinto = indice[i].proxDistinto;
1466 int idNovo = NovoElemento(elemento);
1469 indice.Add({ NULL,-1,-1 });
1472 valor =
Valor(idNovo);
1476 if (valorI == valor) {
1478 indice[idNovo].prox =
Proximo(i);
1480 indice[i].prox = idNovo;
1483 else if (valorI < valor)
1491 indice[idNovo].prox =
Proximo(i);
1492 indice[idNovo].proxDistinto =
Proximo(i);
1493 indice[i].prox = idNovo;
1494 indice[i].proxDistinto = idNovo;
1501 indice[idNovo].prox = i;
1502 indice[idNovo].proxDistinto = i;
1503 while (j != idNovo) {
1504 indice[j].proxDistinto = idNovo;
1506 indice[j].prox = idNovo;
1522 for (
int j = 0; j < elementos.
Count(); j++)
1523 lbElementos.
Add(elementos[j]->LowerBound());
1524 lbElementos.
Sort(&idElementos);
1527 for (
int j = 0; j < idElementos.
Count(); j++)
1528 id =
Inserir(elementos[idElementos[j]],
id);
@ limite
Valor dependente do algoritmo. Exemplo: Profundidade limitada.
@ ruidoHeur
Ruído a adicionar à heurística para testes de robustez.
@ estadosRepetidos
Forma de lidar com estados repetidos (ignorá-los, ascendentes, gerados).
@ verAcoes
Mostra estado a cada K ações. Se 1, mostra sempre estados e nunca ações.
@ seed
Semente aleatória para inicializar a sequência de números pseudo-aleatórios.
@ nivelDebug
Nível de debug, de reduzido a completo.
@ limiteTempo
Tempo limite em segundos.
@ baralharSuc
Baralhar os sucessores ao expandir.
@ algoritmo
Algoritmo base a executar.
@ ascendentes
estados são comparados com ascendentes, e se forem repetidos são removidos
@ gerados
estados são comparados com todos os gerados, e se forem repetidos são removidos
#define TAMANHO_HASHTABLE
@ detalhe
Debug detalhada sobre estados e decisões.
@ atividade
Apenas eventos principais.
@ completo
Mostra toda a execução detalhadamente.
@ passos
Exibe passos intermediários.
@ nada
Sem informações de debug.
int Inserir(TNo elemento, int id=0)
int ProximoDistinto(int i=-1)
Representa um estado no espaço de estados.
void DebugCorte(int sucessores=-1, bool duplo=false)
void DebugSucessores(TVector< TNo > &sucessores)
void MostrarTorneio(TVector< TVector< int > > &torneio, bool jogo=false)
TProcuraConstrutiva(void)
void DebugRamo(char ramo, char folha)
int SolucaoEncontrada(bool continuar=false)
void DebugEstado(int id=-1, int pai=-1)
void DebugSolucao(bool continuar=false)
static int NovoValor(const char *prompt)
void ConfiguracaoAtual(TVector< int > ¶metros, int operacao)
void BarraTorneio(bool nomes)
void CalculaTorneio(TVector< TResultado > &resultados)
static uint64_t elementosHT[TAMANHO_HASHTABLE][OBJETO_HASHTABLE]
void CalcularHeuristicas(TVector< TNo > &sucessores, TVector< int > *id=NULL, bool sortLB=false)
int SolucaoParcial(int i, TVector< TNo > &sucessores)
int Dominio(int &variavel, int min=INT_MIN, int max=INT_MAX)
void NovaLinha(bool tudo=true)
void EditarConfiguracoes()
int ObjetivoAlcancado(int item, TVector< TNo > &lista)
int MelhorResultado(TResultado base, TResultado alternativa)
static void LibertarVector(TVector< TNo > &vector, int excepto=-1, int maiorQue=-1)
virtual void SubstituirHT(int indice)
void MostrarConfiguracoes(int detalhe, int atual=-1)
void CalculaCaminho(bool completa=true)
void ExplorarSucessores(bool jogo=false)
void MostraRelatorio(TVector< TResultado > &resultados)
void DebugExpansao(int sucessor, int sucessores, bool duplo=false)
void ExtrairConfiguracao(TVector< TResultado > &resultados, TVector< TResultado > &extracao, int configuracao)
void LimparEstatisticas(clock_t &inicio)
void DebugIteracao(int iteracao)
void VerificaLimites(int limite, int porProcessar, TVector< TNo > &sucessores)
void FinalizarCorrida(clock_t inicio)
static int custoHT[TAMANHO_HASHTABLE]
void MostraParametros(int detalhe=1, TVector< int > *idParametros=NULL)
static uint64_t estadoCodHT[OBJETO_HASHTABLE]
static unsigned int rand(int seq=0)
static void srand(unsigned int seed, int seq=0)
void Reset(Item const &i)
void Remove(Item const &i)
void Sort(TVector< int > *idxvect=NULL)
int CustoUniforme(int limite=0)
Executa a procura por custo uniforme, algoritmo cego.
int ProfundidadePrimeiro(int nivel=0)
Executa a procura em profundidade primeiro, algoritmo cego.
int LarguraPrimeiro(int limite=0)
Executa a procura em largura primeiro, algoritmo cego.
virtual void Sucessores(TVector< TNo > &sucessores)
Coloca em sucessores a lista de estados sucessores.
virtual bool SolucaoCompleta(void)
Verifica se o estado actual é objectivo (é uma solução completa)
virtual void SolucaoVazia(void)
Coloca o objecto no estado inicial da procura.
virtual void TesteManual(const char *nome)
Inicializa a interação com o utilizador.
virtual void Copiar(TNo objecto)
Fica com uma cópia do objecto.
virtual TNo Duplicar(void)=0
Cria um objecto que é uma cópia deste.
virtual bool Distinto(TNo estado)
Verifica se o estado actual distinto do fornecido.
virtual void MostrarSolucao(void)
Mostrar solução, seja um caminho ou o próprio estado.
virtual void TesteEmpirico(int inicio=-1, int fim=-1, bool mostrarSolucoes=true)
Executa testes empíricos, em todas as configurações guardadas, nas instâncias selecionadas.
virtual int ExecutaAlgoritmo()
Executa o algoritmo com os parametros atuais.
virtual bool Parar(void)
Verifica se a procura deve ser interrompida.
virtual int Heuristica(void)
Função para calcular quanto falta para o final, o valor da heurística.
virtual void Codifica(uint64_t estado[OBJETO_HASHTABLE])
Codifica o estado para um vetor de inteiros de 64 bits.
virtual void Debug(void)
Mostra o estado no ecrã, para debug.
virtual void ResetParametros()
Inicializa os parametros.
virtual const char * Acao(TNo sucessor)
Retorna a ação (movimento, passo, jogada, lance, etc.) que gerou o sucessor.
int heuristica
Estimativa para o custo até um estado objetivo, se disponível.
int custo
Custo total acumulado desde o estado inicial.
TNo pai
Ponteiro para o estado pai, na árvore de procura.
static int expansoes
Número total de expansões realizadas na procura.
static int lowerBound
Valor mínimo que a solução pode apresentar, obtido pela procura.
static int avaliacoes
Número total de avaliações realizadas na procura.
static bool memoriaEsgotada
Flag indicando problemas de memória esgotada.
static int tamanhoCodificado
Número de inteiros de 64 bits utilizados para codificar um objeto (≤ OBJETO_HASHTABLE).
static int geracoes
Número total de gerações realizadas na procura.
static TVector< TNo > caminho
Solução retornada pela procura (os estados devem ser libertados).
static TVector< TVector< int > > configuracoes
Conjuntos de configurações para teste empírico.
static TVector< TParametro > parametro
Parâmetros a serem utilizados na configuração atual.
static TVector< unsigned char > ramo
static TNo solucao
Estado objetivo encontrado, retornado pela procura (deve ser libertado).
static TParametro instancia
ID da instância atual, a ser utilizado em SolucaoVazia().
static clock_t instanteFinal
Estrutura para registo de um parâmetro.
int valor
valor do parametro
int max
valor máximo que o parametro pode tomar
int min
valor mínimo que o parametro pode tomar