Domínios Finitos Em muitas problemas de interesse, não é possível aceditar soluções fraccionárias ou reais, mas apenas soluções inteiras. Exemplos destas aplicações incluem: • Planeamento de testes em circuitos digitais – Para detecção/distinção de avarias • Gestão da Produção – quantidades inteiras • Sequenciação de Tarefas (Scheduling) • Geração de Horários • Caixeiro Viajante – Simples ou Multiplo 1 Domínios Finitos De uma forma mais geral, as soluções não necessitam sequer ser numéricas. Por exemplo, num problema de coloração de grafos (ou mapas) pretende-se escolher cores que não constituem um conjunto numérico (nem sequer ordenado, na interpretação habitual). Para estes domínios, não existem resolvedores simbólicos completos, isto é, não existem procedimentos algébricos que permitam decidir se um problema é possível ou não, sendo necessário recorrer, em geral, à pesquisa de um espaço finito de soluções potenciais. 2 Satisfação Booleana - SAT Um caso particular de domínios finitos, é o caso do domínio composto pelos valores booleanos, em que as variáveis podem tomar o valor 0/1. No domínio da informática, a importância deste domínio é óbvia: em última análise todos os problemas são compilados para especificações codificadas em bits numa linguagem máquina a executar por um processador. Mais praticamente, um grande número de problemas pode ser especificado através de um conjunto de expressões booleanas. Essas expressões booleanas podem ser colocadas na forma clausal (conversão para CNF - forma normal conjuntiva). 3 Satisfação Booleana - SAT Exemplo_1: n-rainhas Este problema já foi analisado anteriormente. Associandose a ausência/presença de uma rainha numa das n2 casas de um tabuleiro com n casas de lado, com uma variável 0/1, o problema é modelado através de um conjunto de dois tipos de restrições: • Deve haver pelo menos, uma rainha num conjunto de casas (linhas e colunas) • Deve haver no máximo uma rainha num conjunto de casas (linhas, colunas e diagonais). Estas restrições podem ser modeladas facilmente na forma clausal. 4 Satisfação Booleana - SAT R1: Deve haver pelo menos uma rainha num conjunto Q1 a Qn de casas • 1 só cláusula: Q1 Q2 ... Qn R2: Deve haver no máximo uma rainha num conjunto Q1 a Qn de casas • Várias (no total de n*(n-1)/2) claúsulas do tipo: Q1 Q2 Q1 Q3 .. Q1 Qn ... Qn-1 Qn 5 Satisfação Booleana - SAT Exemplo_2: Coloração de Grafos Dado um grafo não dirigido, garantir que dois nós adjacentes (ligados por um arco) têm cores diferentes. Em primeiro lugar há que modelar a cor de um nó do grafo. Em geral, k cores requerem ceiling(log2(k)) variáveis booleanas, ou bits, para serem representadas. Para simplificar, assumamos a existência de 4 cores. Neste caso, como ceiling(log2(4)) = 2, são necessárias duas variáveis booleanas para representar 4 cores distintas. Assim a cor do nó i é codificada com as variáveis booleanas Ci,1 e Ci,2. 6 Satisfação Booleana - SAT Exemplo_2: Coloração de Grafos Em segundo lugar há que modelar as restrições de que nós adjacentes têm cores diferentes. Considerando os nós i e j, esta restrição é modelada como (Ci,1 Cj,1 ) (Ci,2 Cj,2 ) Mas a b (a b) (a b) (a b) (a b) Assim a restrição [(Ci,1 Cj,1 ) ( Ci,1 Cj,1 )] [(Ci,2 Cj,2 ) ( Ci,2 Cj,2 )] É equivalente às 4 cláusulas Ci,1 Cj,1 Ci,2 Cj,2 Ci,1 Cj,1 Ci,2 Cj,2 Ci,1 Cj,1 Ci,2 Cj,2 Ci,1 Cj,1 Ci,2 Cj,2 7 Satisfação Booleana - SAT Exemplo_3: Saco Mochila (Decisão) Dado um conjunto de n objectos, cada um com um volume (inteiro) vi e um valor zi, verificar se numa mochila com capacidade (em volume) V podem ser colocado um conjunto de objectos com valor total não inferior a Z. Este problema pode ser modelado através de n variáveis booleanas, Xi, em que cada uma modela a selecção (1) ou não(0) do objecto para ser colocado na mochila. Assim, a restrição de não exceder o peso pode ser expressa como v1 X1 + v2 X2 + ... + vn Xn =< V 8 Satisfação Booleana - SAT Exemplo_3: Saco Mochila (Decisão) v1 X1 + v2 X2 + ... + vn Xn =< V Para modelar esta restrição em cláusulas, há que modelar a • a multiplicação de um inteiro por um bit (0/1) • a soma de valores inteiros • a comparação (=<) de dois inteiros Apesar de “trabalhosa”, esta modelação para a forma clausal é facilmente efectuada. 9 Satisfação Booleana - SAT Exemplo_3: Saco Mochila (Decisão) • a multiplicação de um inteiro por um bit (0/1) Dado o inteiro B representado em binário pelos bits Bk a B0, a multiplicação desse inteiro pelo bit X origina o inteiro representado pelos bits Mk a M0, tais que Mi = X Bi. Esta igualdade pode ser imposta através das cláusulas (X=0 Mi=0) ( X=1 Mi=Bi) (X=0 X=1)(X=0 Mi=Bi)(Mi=0 X=1)(Mi=0 Mi = Bi) (X Mi= Bi) ( Mi=Bi) ( Mi X) (Mi Bi) ( Mi Bi) ( Mi X) (Mi Bi) ( Mi Bi) ( Mi X) 10 Satisfação Booleana - SAT Exemplo_3: Saco Mochila (Decisão) • a soma de valores inteiros Dados os inteiros A e B representados em binário pelos bits ak/bk a ak/b0, a sua soma S pode ser obtida através das restrições Primeiro bit S0 = A0 B0 Último bit Sn+1 = Cn+1 Outros bits Si = Ai Bi Ci C1 = A0 B0 Ci+1 = (AiBi) (AiCi) (BiCi) que se colocam na forma clausal de uma forma semelhante. 11 Satisfação Booleana - SAT Primeiro bit • S0 = A0 B0 (S0 (A0 B0)) (S0 (A0 B0)) (S0((A0B0)(A0 B0))) ( S0 ((A0B0)(A0B0))) (S0A0B0 ) (S0A0B0) (S0A0B0) (S0A0B0) • C1 = A0 B0 (C1 (A0 B0)) (C1 (A0 B0)) (C1 A0 B0) (C1 A0 ) (C1 B) Último bit • Sn+1 = Cn+1 (Sn+1 Cn+1) ( Sn+1 Cn+1) 12 Satisfação Booleana - SAT Outros bits • Si = Ai Bi Ci (Si (Ai Bi Ci)) (Si (Ai Bi Ci)) ... (Si Ai Bi Ci) (Si Ai Bi Ci) (Si Ai Bi Ci) (Si Ai Bi Ci) (Si Ai Bi Ci) (Si Ai Bi Ci) (Si Ai Bi Ci) (Si Ai Bi Ci) • Ci+1 = (AiBi) (AiCi) (BiCi) ... (Ai Bi Ci+1) (Ai Bi Ci+1) (Ai Ci Ci+1) (Ai Ci Ci+1) (Bi Ci Ci+1) (Bi Ci Ci+1) 13 Satisfação Booleana - SAT Exemplo_3: Saco Mochila (Decisão) • a comparação (=<) de dois inteiros Dados os inteiros A e B representados em binário pelos bits Ak/Bk a A0/B0, a sua comparação (A =< B) pode ser feita através das variáveis booleanas X0 a Xk, em que Xi indica que Ai ... A0 =< Bi ... B0. Assim deveremos ter • X0 = (A0 =< B0) ... (A0 B0 X0) (A0 X0) (B0 X0) • Xk = (Ak< Bk) ((Ak=Bk) Xk-1) para k 1 (Ai Xi Xi-1) (Ai Xi Xi-1) (Ai Bi Xi ) (Ai Bi Xi ) (Bi Xi Xi-1) (Bi Xi Xi-1) 14 SAT e 3SAT Apesar de algumas cláusulas conterem mais de 3 variáveis, a satisfação de uma cláusula com mais de 3 variáveis pode ser sempre convertida, com introdução de variáveis extra, na satisfação de várias cláusulas com apenas 3 variáveis. Exemplo: A satisfação de uma cláusula P: A B C D é equivalente à satisfação das cláusulas Q e R abaixo Q: A B X e R: C D X Para provar este resultado temos de provar que: • P Q,R: sempre que P puder ser satisfeita Q e R tambem podem • Q,R P: sempre que Q e R puderem ser satisfeitas P também pode 15 SAT e 3SAT P: A B C D Q: A B X e R: C D X Se P pode ser satisfeito, então pelo menos uma variável A a D toma o valor 1. Sem perda de generalidade consideremos que é A(C). Então a cláusula Q já está satisfeita. A outra cláusula, R, é satisfeita com X = 0(1). Q: A B X e R: C D X P: A B C D Como X = 0 ou X=1, se Q e R são satisfeitas, então uma das cláusulas A B (se X=0) ou C D (se X=1) é satisfeita. Mas desta forma uma das variáveis A a D toma o valor 1, garantindo a satisfação da cláusula P: A B C D. 16 Importância de SAT Como se pode constatar, vários problemas de decisão podem ser modelados na forma de problemas SAT. Na realidade, qualquer problema de decisão pode ser modelado como um problema de satisfação booleana. Problema de Decisão Problema SAT Desta forma, um algoritmo genérico para resolver este tipo de problemas, resolve qualquer problema de decisão. A questão que se pode colocar é a de saber se existe um algoritmo “eficiente” para a resolução do problema de satisfação booleana (SAT). 17 Importância de SAT Um problema SAT com n variáveis (mais rigorosamente, que se pode descrever com uma cadeia de entrada de comprimento proporcional a n) pode ser resolvido em tempo polinomial numa máquina não-determinística (isto é, que adivinha os valores correctos a atribuir às n variáveis de decisão). Tais problemas de decisão, de que SAT é um exemplo, pertencem à classe NP. Mais concretamente, uma máquina determinística (as que há!) pode verificar as restrições para uma solução de um problema de decisão em tempo polinomial, isto é O(nk). 18 Importância de SAT Considerando-se n variáveis booleanas, combinações possíveis dos seus valores. existem 2n A verificação da satisfazibilidade de um conjunto de cláusulas com n variáveis pode pois ser feita através de um procedimento de geração e teste: • Gera-se cada uma das 2n combinações de valores; • Testa-se cada uma dessas combinações. Naturalmente este procedimento é muito ineficiente. No pior caso tem uma complexidade exponencial O(2n). Naturalmente nem todos os problemas de decisão são tão complexos. 19 Importância de SAT Para certos problemas existem algoritmos polinomiais (em n) que permitem decidir sobre a satisfação do problema. Alguns problemas, que constituem a classe de problemas P, são claramente polinomiais. • Por exemplo, decidir se uma lista corresponde à ordenação de outra lista com n inteiros pode ser feito com uma complexidade quadrática O(n2). Noutros problemas não claramente polinomiais, existem instâncias particularmente simples. • Por exemplo, o saco mochila torna-se trivial se todos os objectos tiverem o mesmo peso (não o mesmo valor!). Basta escolher primeiro os mais valiosos! 20 Importância de SAT Naturalmente, todos os problemas P pertencem à classe NP já que se uma máquina determinística os resolve em tempo polinomial, por mais forte razão uma máquina não determinística os consegue resolver nesse tempo. O que ainda não está demonstrado é que a classe NP contenha problemas que não são P. Este resultado é, por ora, uma simples conjectura: P ≠ NP. Em termos práticos, não foi ainda descoberto um qualquer algoritmo que resolva qualquer problema SAT em tempo polinomial (no número de variáveis). De um ponto de vista teórico, se tal acontecer, o que é extremamente improvável, então P=NP. 21 Importância de SAT De um ponto de vista mais prático, se tal improvável algoritmo fôr descoberto, então todos os problemas de decisão “interessantes” passarão a ser resolvidos em tempo polinomial. Com efeito, basta garantir que para cada problema existe um algoritmo que o transforme, em tempo polinomial, numa instância de um problema SAT. Estas transformações podem normalmente ser feitas de uma forma semelhante À usada nos exemplos anteriores (rainhas, coloração de grafos, saco-mochila, etc.). Este resultado é uma das razões pelas quais o problema SAT (ou 3SAT) tem sido tão estudado. 22 Importância de SAT A generalidade da abordagem SAT, na qual qualquer problemas de decisão pode ser modelado, constitui outra das razões pelas quais o problema SAT (ou 3SAT) tem sido tão estudado. Apesar de ser pouco provável a existência de um algoritmo que resolva qualquer instância de SAT em tempo polinomial, existem algoritmos que resolvem muito satisfatoriamente um grande número de instâncias de problemas SAT. Em particular, existem resolvedores de SAT que já conseguem lidar com instâncias de problemas com cerca de um milhão de variáveis e dez milhões de cláusulas. 23 Resolução de 3SAT A geração de todas as soluções pode ser obtida pelo mecanismo de retrocesso de uma linguagem de programação em lógica. Exemplo: rainhas_4(L):geração(L), teste(L), report(L). teste([Q1, Q2, Q3, ..., Q16]):um_ou_menos([Q1,Q2,Q3,Q4]), um_ou_mais([Q1,Q2,Q3,Q4]), ... geração([]). geração([H|T]):membro(H,[1,0]), geração(T). um_ou_menos([Q9,Q14]). 24 Resolução de 3SAT Para simplicidade, no programa rainhas_sat_1gt os testes foram programados explicitamente. 1ª linha % um_ou_menos([Q1,Q2,Q3,Q4]) ~Q1 # ~Q2, ~Q1 # ~Q3, ~Q2 # ~Q3, ~Q1 # ~Q4, ~Q2 # ~Q4, ~Q3 # ~Q4 % um_ou_mais([Q1,Q2,Q3,Q4]), Q1 # Q2 # Q3 # Q4, 25 Resolução de 3SAT Nesse programa rainhas_sat_1gt utilizam-se as facilidades sintáticas disponíbilizadas pela Pprogramação em Lógica, nomeadamente a definição de operadores. % declaração dos operadores booleanos :- op(300,fy,~). :- op(400,xfy,#). % verificação/teste de uma cláusula X # Y :exp(X # Y, Exp), Exp >= 1. exp(X, X):- atomic(X), !. exp(~X, 1-ExpX):- !, exp(X, ExpX). exp(X # Y, ExpX + ExpY):- !, exp(X, ExpX), exp(Y, ExpY). 26 Resolução de 3SAT - Retrocesso Muitas potenciais soluções podem ser descartadas apenas por análise de uma solução parcial. Por exemplo, qualquer solução com Q1=Q2=1 pode ser descartada, já que não pode haver 2 rainhas na mesma linha. Uma forma mais eficiente de verificar a satisfação de um problema é a utilização de um método construtivo, em que soluções parciais (em que apenas algumas variáveis têm valores atribuídos), vão sendo “completadas”, desde que não violem, por si só, nenhuma restrição. Se a solução parcial violar restrições, ela não é completada, explorando-se, por retrocesso (backtracking), alternativas. 27 Resolução de 3SAT - Retrocesso a b c d c c d b b X d a d d c c X d d d d b c c d d d d c d d d Se a combinação a=b=1 não satisfizer uma das restrições, não são testadas nenhumas combinações que incluam a=b=1. A “primeira” solução <a,b,c,d>= <1,0,0,1> é encontrada evitando-se o teste de 6 folhas. 28 Resolução de 3SAT A completação das soluções parciais pode ser facilmente obtida pelo mecanismo de retrocesso de uma linguagem de programação em lógica. A questão que se coloca aqui é a de garantir que os testes sejam feitos tão cedo quanto possível. Assim, • após instanciar as variáveis Q1 e Q2, da mesma linha, deverá ser verificado que elas não tomam ambas o valor 1. • ... • após instanciar a variável Q4 deve ser verificado que uma de Q1 a Q4 toma o valor 1. 29 Resolução de 3SAT Para simplificar a exposição, esta verificação é feita de uma forma explícita no programa rainhas_sat_1bk. lrainhas_4(_):label(Q1), % 1ª linha label(Q2), ~Q1 # ~Q2, label(Q3), ~Q1 # ~Q3, ~Q2 # ~Q3, label(Q4), Q1 # Q2 # Q3 # Q4, ~Q1 # ~Q4, ~Q2 # ~Q4, ~Q3 # ~Q4, ... % onde a atribuição de valor é feita através de label(Q):- mb(Q,[0,1]). 30 Resolução de 3SAT Como é fácilmente compreensível, a programação por retrocesso é muito mais eficiente. A contabilização quer dos testes feitos quer das atribuições efectuadas pode ser medida pela inserção de contadores. % contagem das atribuições feitas mb(X,[X|_]):- inc(l). mb(X,[_|T]):- mb(X,T). % contagem das testes feitos X # Y :exp(X # Y, Exp), inc(t), Exp >= 1. 31 Propagação de Restrições Uma alternativa à verificação por backtracking da compatibilidade entre cada variável e as variáveis passadas (com valor já atribuído), é geralmente muito vantajoso eliminar do domínio das variáveis futuras (com valor ainda por atribuir), os valores incompatíveis com os actualmente atribuídos. Esta filosofia permite, em muitos casos: • Perceber mais rapidamente a impossibilidade de completar a solução parcial • Retroceder para as causas relevantes da falha 32 Retrocesso Testes 0 Retrocessos 0 33 Retrocesso Q1 \= Q2, L1+Q1 \= L2+Q2, Testes 0 + 1 = 1 L1+Q2 \= L2+Q1. Retrocessos 0 34 Retrocesso Q1 \= Q2, L1+Q1 \= L2+Q2, Testes 1 + 1 = 2 L1+Q2 \= L2+Q1. Retrocessos 0 35 Retrocesso Q1 \= Q2, L1+Q1 \= L2+Q2, Testes 2 + 1 = 3 L1+Q2 \= L2+Q1. Retrocessos 0 36 Retrocesso Testes 3 + 1 = 4 Retrocessos 0 37 Retrocesso Testes 4 + 2 = 6 Retrocessos 0 38 Retrocesso Testes 6 + 1 = 7 Retrocessos 0 39 Retrocesso Testes 7 + 2 = 9 Retrocessos 0 40 Retrocesso Testes 9 + 2 = 11 Retrocessos 0 41 Retrocesso Testes 11 + 1 + 3 = 15 Retrocessos 0 42 Retrocesso Testes 15 + 1 + 4 + 2 + 4 = 26 Retrocessos 0 43 Retrocesso Testes 26 + 1 = 27 Retrocessos 0 44 Retrocesso Testes 27 + 3 = 30 Retrocessos 0 45 Retrocesso Testes 30 + 2 = 32 Retrocessos 0 46 Retrocesso Testes 32 + 4 = 36 Retrocessos 0 47 Retrocesso Testes 36 + 3 = 39 Retrocessos 0 48 Retrocesso Testes 39 + 1 = 40 Retrocessos 0 49 Retrocesso Testes 40 + 2 = 42 Retrocessos 0 50 Retrocesso Testes 42 + 3 = 45 Retrocessos 0 51 Retrocesso Falha 6 Retrocede 5 Testes 45 Retrocessos 0 52 Retrocesso Testes 45 Retrocessos 1 53 Retrocesso Testes 45 + 1 = 46 Retrocessos 1 54 Retrocesso Testes 46 + 2 = 48 Retrocessos 1 55 Retrocesso Testes 48 + 3 = 51 Retrocessos 1 56 Retrocesso Testes 51 + 4 = 55 Retrocessos 1 57 Retrocesso Falha 6 Retrocede 5e4 Testes 55+1+3+2+4+3+1+2+3 = 74 Retrocessos 1 58 Retrocesso Testes 74+2+1+2+3+3= 85 Retrocessos 1+2 = 3 59 Retrocesso Testes 85 + 1 + 4 = 90 Retrocessos 3 60 Retrocesso Testes 90 +1+3+2+5 = 101 Retrocessos 3 61 Retrocesso Testes 101+1+5+2+4+3+6= 122 Retrocessos 3 62 Retrocesso Falha 8 Retrocede 7 Testes 122+1+5+2+6+3+6+4+1= 150 Retrocessos 3+1=4 63 Retrocesso Falha 7 Retrocede 6 Testes 150+1+2= 153 Retrocessos 4+1=5 64 Retrocesso Falha 6 Retrocede 5 Testes 153+3+1+2+3= 162 Retrocessos 5+1=6 65 Retrocesso Testes 162+2+4= 168 Retrocessos 6+1=7 66 Retrocesso Falha 6 Retrocede 5 Testes 168+1+3+2+5+3+1+2+3= 188 Retrocessos 7 67 Retrocesso Falha 5 Retrocede 4 Testes 188+1+2+3+4= 198 Retrocessos 7+1=8 68 Retrocesso Testes 198 + 3 = 201 Retrocessos 8+1=9 69 Retrocesso Testes 201+1+4 = 206 Retrocessos 9 70 Retrocesso Testes 206+1+3+2+5 = 217 Retrocessos 9 71 Retrocesso Testes 217+1+5+2+5+3+6 = 239 Retrocessos 9 72 Retrocesso Falha 8 Retrocede 7 Testes 239+1+5+2+4+3+6+7+7= 274 Retrocessos 9+1=1073 Retrocesso Falha 7 Retrocede 6 Testes 274+1+2= 277 Retrocessos 10+1=11 74 Retrocesso Falha 6 Retrocede 5 Testes 277+3+1+2+3= 286 Retrocessos 11+1=12 75 Retrocesso Testes 286+2+4= 292 Retrocessos 12 76 Retrocesso Falha 6 Retrocede 5 Testes 292+1+3+2+5+3+1+2+3= 312 77 Retrocessos 12+1=13 Retrocesso Falha 5 Retrocede 4e3 Testes 312+1+2+3+4= 322 Retrocessos 13+2=15 78 Retrocesso X1=1 X2=3 X3=5 Impossível Testes 322 + 2 = 324 Retrocessos 15 79 Propagação Testes 0 Retrocessos 0 80 Propagação Q1 #\= Q2, 1 L1+Q1 #\= L2+Q2, L1+Q2 #\= L2+Q1. 1 1 1 1 1 1 1 Testes 8 * 7 = 56 1 1 1 1 1 1 Retrocessos 0 81 Propagação 1 1 1 2 1 2 1 2 1 1 2 1 2 1 2 1 2 Testes 56 + 6 * 6 = 92 2 1 2 1 2 1 2 1 Retrocessos 0 82 Propagação 1 1 1 2 1 2 1 2 1 1 2 3 2 1 2 3 2 3 1 2 3 1 2 3 1 2 1 2 3 1 3 Testes 92 + 4 * 5 = 112 1 Retrocessos 0 83 Propagação 2 X6 só pode tomar o valor 4 1 1 1 2 1 2 1 2 1 1 2 3 2 1 2 3 2 3 1 2 3 1 2 3 1 2 1 2 3 1 3 Testes 92 + 4 * 5 = 112 1 Retrocessos 0 84 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 2 6 1 2 3 3 1 2 3 1 2 1 1 3 1 1 6 2 2 6 3 2 6 3 Testes 112+3+3+3+4 = 125 6 1 Retrocessos 0 85 Propagação 2 X8 só pode tomar o valor 7 1 1 1 2 1 2 1 6 2 1 2 3 2 6 1 2 3 3 1 2 3 1 2 1 1 3 1 1 Testes 125 6 2 2 6 3 2 2 3 6 1 Retrocessos 0 86 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 2 6 1 2 3 3 1 2 3 1 2 1 1 3 1 1 Testes 125 6 2 2 6 3 2 2 3 6 1 Retrocessos 0 87 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 3 1 2 3 1 2 1 1 3 1 1 6 2 2 6 3 8 2 2 3 6 Testes 125+2+2+2=131 1 Retrocessos 0 88 Propagação 2 X4 só pode tomar o valor 8 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 3 1 2 3 1 2 1 1 3 1 1 Testes 131 6 2 2 6 3 8 2 2 3 6 1 Retrocessos 0 89 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 3 1 2 3 1 2 1 1 3 1 1 Testes 131 6 2 2 6 3 8 2 2 3 6 1 Retrocessos 0 90 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 4 3 1 2 3 1 2 1 1 3 1 1 6 2 2 6 3 8 2 2 3 6 Testes 131+2+2=135 1 Retrocessos 0 91 Propagação 2 X5 só pode tomar o valor 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 4 3 1 2 3 1 2 1 1 3 1 1 Testes 135 6 2 2 6 3 8 2 2 3 6 1 Retrocessos 0 92 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 4 3 1 2 3 1 2 1 1 3 1 1 Testes 135 6 2 2 6 3 8 2 2 3 6 1 Retrocessos 0 93 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 4 3 1 2 3 1 2 1 1 3 2 1 5 2 6 3 8 1 6 2 2 3 6 Testes 135+1=136 1 Retrocessos 0 94 Propagação 2 1 1 1 2 1 2 1 6 2 1 2 3 8 2 6 1 2 3 4 3 1 2 3 1 2 1 1 3 2 1 5 2 6 3 8 1 6 2 2 3 6 Testes 136 1 Retrocessos 0 95 Propagação 2 1 1 Falha 1 2 1 2 7 1 6 2 1 2 3 8 Retrocede 1 2 6 1 2 3 4 3 1 2 3 1 2 3! 1 3 2 1 5 2 6 3 8 1 6 2 2 3 6 Testes 136 1 Retrocessos 0+1=1 96 Propagação 2 1 X1=1 X2=3 X3=5 Impossível 1 1 2 1 2 2 1 1 1 1 Testes 136 1 3 Testes 2 1 3 2 1 3 2 136 3 (324) 3 3 2 1 2 3 2 3 1 2 2 3 Retrocessos 1 (15) 1 Retrocessos 1 97 Propagação de Restrições A programação deste tipo de mecanismo num sistema de Programação em Lógica com Restrições segue o seguinte esquema. Problema ( Vars):Declaração de Variáveis e Domínios, Lançamento das Restrições, Enumeração das Variáveis. Desta forma sempre que fôr enumerada uma variável, os efeitos dessa enumeração são propagados automáticamente para as restrições relevantes, diminuindo os domínios possíveis para as outras variáveis. Caso um domínio fique vazio, a pesquisa falha e é executado o retrocesso. 98 Propagação de Restrições Este é o estilo de programação adoptado no programa rainhas_sat_1fd. % Declaração de Domínios domain([Q1,Q2,Q3,Q4,...,Q13,Q14,Q15,Q16],0,1) % Lançamento de Restrições (1ª linha) ~Q1 # ~Q2, ~Q1 # ~Q3, ~Q2 # ~Q3, ~Q1 # ~Q4, ~Q2 # ~Q4, ~Q3 # ~Q4, Q1 # Q2 # Q3 # Q4, % Enumeração das Variáveis labeling([], [Q1,Q2,Q3,Q4,...,Q13,Q14,Q15,Q16]) 99 Propagação de Restrições O lançamento de restrições é tratado de uma forma semelhante à anterior, mas usando operadores de relação específicos (antecedidos de #). Desta forma, a avaliação tem em vista a redução do domínio das variáveis. X # Y :exp(X # Y, Exp), Exp #>= 1. exp(X, X):- var(X), !. exp(X, X):- atom(X), !. exp(~X, Exp):- !, exp(X, ExpX), Exp #= 1-ExpX. exp(X # Y, Exp):- !, exp(X, ExpX), exp(Y, ExpY), Exp #= ExpX + ExpY. 100 Propagação de Restrições Por exemplo, X | ?- domain([X,Y], 0,1), X # Y. X in 0..1,Y in 0..1 ? ; % não pode propagar no ?- domain([X,Y], 0,1), X # Y, X #= 1. X = 1,Y in 0..1 ? ; % não pode propagar no ?- domain([X,Y], 0,1), X # Y, X #= 0. X = 0,Y = 1 ? ; % propaga de X para Y no ?- domain([X,Y], 0,1), X + Y #> 1. X = 1,Y = 1 ? ; % propaga para X e Y no 101 Propagação de Restrições Em geral a solução de um problema usando propagação de restrições é bastante mais eficiente que a alternativa de retrocesso puro. A medição da eficiência pode ser feita pela invocação dos predicados pré-definido fd_statistics/0 e fd_statistics/2 | ?- fd_statistics. Resumptions: 28 Entailments: 2 Prunings: 23 Backtracks: 0 Constraints created: 4 yes 102 Propagação de Restrições Para um problema tão pequeno como as 4 rainhas, as diferenças na eficiência das duas versões não são significativas. No entanto tal não é o caso com instâncias maiores do problema. Esta diferença pode ser verificada na execução dos programas rainhas_sat_2bk e rainhas_sat_2fd que são parametrizados pela dimensão do problema. 103 Domínios Finitos Em muitas situações, e não obstante o interesse teórico e prático do problema SAT, os problemas são mais naturalmente especificados com variáveis cujo domínio não se restringe aos valores 0/1, podendo tomar outros valores (inteiros, no caso do SICStus). Em particular, o problema das N rainhas é mais naturalmente programado com N variáveis, uma para cada linha, cujo valor denota a coluna que uma rainha deve tomar nessa linha. Esta especificação, não só é mais natural como pode conduzir a uma substancial melhoria de eficiência. 104 Domínios Finitos Com efeito, estas codificações representam um espaço de pesquisa de dimensão substancialmente diferente. Domínios Booleanos k*n variáveis de valores 0/1. Espaço de pesquisa = 2k*n. Domínios Finitos n variáveis de valores 1..k. Espaço de pesquisa = kn = 2log2(k)*n Razão dos espaços de pesquisa r= 2k*n / 2log2(k)*n = 2 (k-log2(k))*n Por exemplo, com k=8 e n=8, vem r=2(8-3)*8 =240 105 Domínios Finitos Em geral, a variação do espaço a pesquisar não é tão substancial, nomeadamente se existir uma propagação eficiente no caso dos booleanos. Por exemplo, no caso das rainhas pode garantir-se que só uma em cada grupo de k variáveis (numa linha, coluna ou diagonal) pode tomar o valor 1. Quando isto se verificar, a propagação impõe que todas as outras tomem o valor 0, sem escolha. No entanto, as diferenças ainda são normalmente bastante substanciais, como se pode ver nos exemplos codificados directamente em domínios finitos rainhas_bk e rainhas_fd 106 Domínios Finitos A eficiência das programas em domínios finitos (incluindo booleanos) podem ainda ser melhoradas pelo uso de • Algoritmos de Propagação mais adequados • Heurísticas para escolha • da variável • do valor Estas variações podem ser verificadas na versão do programa das rainhas em domínios finitos rainhas_fd 107