3 DESENVOLVIMENTO DO TRABALHO
3.3 IMPLEMENTAÇÃO
3.3.1 Técnicas e ferramentas utilizadas
3.3.1.1 Implementação do algoritmo busca-com-retrocesso
A primeira parte da implementação deste trabalho foi programar o algoritmo de resolução de CSPs busca-com-retrocesso. Durante a etapa de desenvolvimento, o mesmo sofreu diversas melhorias com relação ao código em Java, até obter-se um algoritmo com código simples e objetivo. O algoritmo de busca-com-retrocesso ficou implementado de acordo com o Quadro 13, o Quadro 14, o Quadro 15 e com o Quadro 16.
No Quadro 13 é apresentado parte do código da classe resolveCSP com o método
pesquisaComRetrocesso. Pode-se verificar que o método pesquisaComRetrocesso inicia o
algoritmo para a busca da solução do CSP. Ao chamar este método, devem ser enviados como parâmetros o objeto csp e um inteiro que fará o papel de um seletor para a heurística desejada.
36
foi acionada com o parâmetro usarHeuristica e que logo após criar o objeto de atribuição
vazia, é efetuado um condicional if chamando o método recursivo retrocessoRecursivo,
enviando como parâmetros a atribuição e o CSP, para que seja criado a árvore de busca, e quando finalizar, ele deverá retornar true ou false, sinalizando se foi encontrada ou não a
solução, para aí sim calcular o tempo de execução, número de verificações de consistência e retornar para o método ou a atribuição completa ou nulo.
public Assignment pesquisaComRetrocesso(CSP csp,int usarHeuristica){ //Seta qual heurística será usada
chaveHeuristica = usarHeuristica; //Determina heurística
switch(chaveHeuristica){ case 1:
//Ordena lista de variavel mais restritiva ordenarVariavelMaisRestritiva(csp);
break; case 2:
//Ordena lista de variavel mais restringida ordenarVariavelMaisRestringida(csp);
break; case 3:
//Pega tempo inicial da heuristica tInicial = System.nanoTime();
//Tenta resolver pelos conflitos mínimos Assignment confMinAtrib =
new ConflitosMinimos().iniciaConflitosMinimos(csp,50,this); //se achou resposta
if(confMinAtrib != null){
//calcula e exibe o tempo de execução
tempoExecucao(tInicial,System.nanoTime(),descHeuristica); //retorna a atribuição completa
return confMinAtrib; };
}
//Pega tempo inicial
long tInicial = System.nanoTime(); //Cria o objeto de atribuiçao vazia
Assignment atribuicao = new Assignment();
//Inicia retrocesso recursivo RETROCESSO-RECURSIVO( {}, psr ) if (retrocessoRecursivo(atribuicao,csp)) {
//calcula e exibe o tempo de execução
tempoExecucao(tInicial,System.nanoTime(),descHeuristica); //retorna a atribuição completa
return atribuicao; } else {
//calcula e exibe o tempo de execução
tempoExecucao(tInicial,System.nanoTime(),descHeuristica); //retorna nulo, ou seja, não há solução para o CSP
return null; }
}
Quadro 13 – Método pesquisaComRetrocesso da classe resolveCSP
No quadro 14, é demonstrado o método retrocessoRecursivo também incluso na
37
private boolean retrocessoRecursivo(Assignment atrib, CSP csp) { //Se atribuição está completa
if( ehCompleta(atrib, csp) ){
//Então retorna a Atribuição completa return true;
}
//var <- SELECIONAR VARIAVEL NAO ATRIBUIDA Variable var = null;
switch(chaveHeuristica){ case 0: var = getVarSemValor(atrib, csp); break; case 1: var = Heuristicas.getVarMaisRestritiva(atrib); break; case 2: var = Heuristicas.getVarMaisRestringida(atrib); break; }
//Para cada valor do Domínio faça
Iterator i = var.getDomain().iterator(); while(i.hasNext()){
Value v = (Value)i.next();
//adiciona valor e variável na Atribuição atrib.putVariableValue(var, v);
//Incrementa verificações de consistência vc++;
//Se valor é consistente na atribuição if (csp.isConsistent(atrib)){
//resultado <- RETROCESSO RECURSIVO(atribuicao,csp) if (retrocessoRecursivo(atrib,csp)) {
//retorna resultado return true;
} }
//Remove variável e valor da Atribuição atrib.removeVariable(var);
}
//retorna resultado falso return false;
}
Quadro 14 – Método retrocessoRecursivo da classe resolveCSP
No início do método retrocessoRecursivo é efetuado um condicional if com o
método ehCompleta enviando a atribuição e o CSP como parâmetros que verifica se a
atribuição é completa, retornando true. Caso a atribuição não esteja completa, é selecionada
uma variável que ainda não foi atribuída, utilizando heurística, ou não, dependendo da entrada inicial do algoritmo com a chave chaveHeuristica. Se não foi utilizado heurística na seleção
da variável, é apenas retornada uma da lista de variáveis do objeto csp com o método getVarSemValor, enviando como parâmetros a atribuição para descobrir quais variáveis já
foram atribuídas e o objeto csp para obter a lista de variáveis.
Após, para cada valor do domínio da variável selecionada, é adicionado a variável e o valor na atribuição e verificado se a consistência com as restrições é mantida com o método
isConsistent, encontrado na classe CSP da biblioteca dynDCSP. Sendo sim, é feito mais um
38
retrocessoRecursivo. Caso contrário, a atribuição inconsistente é removida e é continuado o
laço iterativo de cada valor do domínio da variável.
Quando a árvore montada tiver uma atribuição completa, os métodos subseqüentes chamados recursivamente, retornaram true sucessivamente até o algoritmo chegar no método
pesquisaComRetrocesso, que é o primeiro nível da busca, para retornar a atribuição, o mesmo
pode-se dizer quando não se consegue achar a consistência com as atribuições, retornando
false, e por fim o método pesquisaComRetrocesso retornando null.
A seguir, o Quadro 15 exibe o método ehCompleta que verifica se a atribuição é
completa.
public boolean ehCompleta(Assignment atrib, CSP csp){ int atribSize = atrib.size();
int varsSize = csp.getVariables().size(); return atribSize == varsSize;
}
Quadro 15 – Método ehCompleta da classe resolveCSP
O método ehCompleta avalia o tamanho das listas de atribuição e das variáveis do CSP,
se os tamanhos forem iguais, retorna true, senão false. Esse método se tornou simples pois a
atribuição sempre será consistente antes da sua chamada, bastando apenas verificar se o tamanho da lista atribuição corresponde com o tamanho da lista de variáveis do CSP.
O método getVarSemValor é um método que meramente retorna a primeira variável não
atribuída da lista de variáveis. As variáveis do CSP são percorridas e é efetuado o condicional
if para verificar se a variável atual da lista ainda não foi atribuída, caso verdadeiro, retorna-se
a variável, caso contrário, continua-se percorrendo até achar a variável que ainda não foi atribuída. Ocorrendo o término da lista, ou seja, não havendo nenhuma variável sem valor, é retornado null. No Quadro 16 e demonstrado o método getVarSemValor.
private Variable getVarSemValor(Assignment atrib, CSP csp){ ArrayList variaveis = new ArrayList();
variaveis = (ArrayList)csp.getVariables(); for(int i=0; i < variaveis.size(); i++){ Variable var = (Variable)variaveis.get(i); if(!atrib.contains(var)){ return var; } } return null; }
Quadro 16 – Método getVarSemValor da classe resolveCSP
Com o algoritmo busca-com-retrocesso implementado, a validação do mesmo foi efetuada com o problema de coloração de mapas, e com sucesso, obteve-se como solução a saída do console conforme o Quadro 17.
39
Algoritmo Iniciado...
*** Atribuicao Completa! *** Verificações de Consistência = 21
Tempo de execução= 0.007523861 segundos.
{v=azul, tn=verde, t=azul, q=azul, ngs=verde, ao=azul, am=vermelho}
Quadro 17 – Saída do console da resolução de um CSP
Como se pode observar no Quadro 17, o algoritmo busca-com-retrocesso executou quatorze verificações de consistência (VC), ou seja, chamou o método isConsistent do CSP
quatorze vezes. O tempo de execução do algoritmo foi de 0,007523861 segundos e obteve como resposta para o problema, a atribuição {v=verde, tn=azul, t=vermelho, q=verde, ngs=azul, ao=verde, am=vermelho}, uma solução consistente para o problema.