Programação de restrição - Constraint programming

A programação de restrições (CP) é um paradigma para resolver problemas combinatórios que se baseia em uma ampla gama de técnicas de inteligência artificial , ciência da computação e pesquisa operacional . Na programação de restrição, os usuários declaram declarativamente as restrições sobre as soluções viáveis ​​para um conjunto de variáveis ​​de decisão. As restrições diferem das primitivas comuns das linguagens de programação imperativas porque não especificam uma etapa ou sequência de etapas a serem executadas, mas sim as propriedades de uma solução a ser encontrada. Além das restrições, os usuários também precisam especificar um método para resolver essas restrições. Isso normalmente se baseia em métodos padrão, como retrocesso cronológico e propagação de restrição , mas pode usar código personalizado como uma heurística de ramificação específica do problema .

A programação de restrição tem sua raiz e pode ser expressa na forma de programação lógica de restrição , que incorpora restrições em um programa lógico . Esta variante da programação lógica é devida a Jaffar e Lassez, que estendeu em 1987 uma classe específica de restrições que foram introduzidas no Prolog II . As primeiras implementações de programação de lógica de restrição foram Prolog III , CLP (R) e CHIP .

Em vez de programação lógica, as restrições podem ser combinadas com programação funcional , reescrita de termos e linguagens imperativas . As linguagens de programação com suporte integrado para restrições incluem Oz (programação funcional) e Caleidoscópio (programação imperativa). Na maioria das vezes, as restrições são implementadas em linguagens imperativas por meio de kits de ferramentas de solução de restrições , que são bibliotecas separadas para uma linguagem imperativa existente.

Programação de lógica de restrição

A programação de restrições é uma incorporação de restrições em uma linguagem hospedeira. As primeiras linguagens de host usadas foram as linguagens de programação lógica , então o campo foi inicialmente chamado de programação lógica de restrição . Os dois paradigmas compartilham muitos recursos importantes, como variáveis ​​lógicas e retrocesso . Hoje, a maioria das implementações do Prolog inclui uma ou mais bibliotecas para programação de lógica de restrição.

A diferença entre os dois está principalmente em seus estilos e abordagens para modelar o mundo. Alguns problemas são mais naturais (e, portanto, mais simples) de escrever como programas lógicos, enquanto outros são mais naturais de escrever como programas de restrição.

A abordagem de programação de restrições é procurar um estado do mundo no qual um grande número de restrições seja satisfeito ao mesmo tempo. Um problema é normalmente declarado como um estado do mundo contendo várias variáveis ​​desconhecidas. O programa de restrição procura valores para todas as variáveis.

A programação de restrição simultânea temporal (TCC) e a programação de restrição simultânea temporal não determinística (MJV) são variantes da programação de restrição que podem lidar com o tempo.

Problema de satisfação de restrição

Uma restrição é uma relação entre múltiplas variáveis ​​que limita os valores que essas variáveis ​​podem assumir simultaneamente.

Definição  -  Um problema de satisfação de restrição em domínios finitos (ou CSP) é definido por um trio onde:

  • é o conjunto de variáveis ​​do problema;
  • é o conjunto de domínios das variáveis, ou seja, para tudo o que temos ;
  • é um conjunto de restrições. Uma restrição é definida por um conjunto de variáveis ​​e uma relação que define o conjunto de valores permitidos simultaneamente para as variáveis ​​de :

Existem três categorias de restrições:

  • restrições extensionais: as restrições são definidas pela enumeração do conjunto de valores que as satisfaria;
  • restrições aritméticas: as restrições são definidas por uma expressão aritmética, ou seja, usando ;
  • restrições lógicas: as restrições são definidas com uma semântica explícita, ou seja, AllDifferent , AtMost , ...

Definição  -  Uma atribuição (ou modelo) de um CSP é definida pelo casal, onde:

  • é um subconjunto de variável;
  • é a tupla dos valores obtidos pelas variáveis ​​atribuídas.

Atribuição é a associação de uma variável a um valor de seu domínio. Uma atribuição parcial é quando um subconjunto das variáveis ​​do problema foi atribuído. Uma atribuição total é quando todas as variáveis ​​do problema foram atribuídas.

Propriedade  -  Dada uma atribuição (parcial ou total) de um CSP e uma restrição de tal como , a atribuição satisfaz a restrição se e somente se todos os valores das variáveis ​​da restrição pertencerem .

Definição  -  A solução de um CSP é uma atribuição total que satisfaz todas as restrições do problema.

Durante a busca das soluções de um CSP, um usuário pode desejar:

  • encontrar uma solução (satisfazendo todas as restrições);
  • encontrar todas as soluções do problema;
  • comprovando a insatisfação do problema.

Problema de otimização de restrição

Um problema de otimização de restrição (COP) é ​​um problema de satisfação de restrição associado a uma função objetivo.

Uma solução ótima para um COP de minimização (maximização) é uma solução que minimiza (maximiza) o valor da função objetivo .

Durante a busca das soluções de um CSP, um usuário pode desejar:

  • encontrar uma solução (satisfazendo todas as restrições);
  • encontrar a melhor solução com relação ao objetivo;
  • comprovando a otimalidade da melhor solução encontrada;
  • comprovando a insatisfação do problema.

Modelos de perturbação vs refinamento

Linguagens para programação baseada em restrições seguem uma das duas abordagens:

  • Modelo de refinamento: as variáveis ​​no problema são inicialmente não atribuídas e cada variável é considerada capaz de conter qualquer valor incluído em seu intervalo ou domínio. À medida que o cálculo avança, os valores no domínio de uma variável são removidos se se mostrarem incompatíveis com os valores possíveis de outras variáveis, até que um único valor seja encontrado para cada variável.
  • Modelo de perturbação: as variáveis ​​do problema recebem um único valor inicial. Em momentos diferentes, uma ou mais variáveis ​​recebem perturbações (mudanças em seus valores anteriores), e o sistema propaga a mudança tentando atribuir novos valores a outras variáveis ​​que sejam consistentes com a perturbação.

A propagação de restrições em problemas de satisfação de restrições é um exemplo típico de um modelo de refinamento, e as planilhas são um exemplo típico de um modelo de perturbação.

O modelo de refinamento é mais geral, pois não restringe as variáveis ​​a um único valor, podendo levar a várias soluções para o mesmo problema. No entanto, o modelo de perturbação é mais intuitivo para programadores que usam linguagens orientadas a objetos de restrição imperativa mista.

Domínios

As restrições usadas na programação de restrições são normalmente sobre alguns domínios específicos. Alguns domínios populares para programação de restrição são:

Os domínios finitos são um dos domínios de maior sucesso da programação de restrições. Em algumas áreas (como pesquisa operacional ), a programação de restrições é frequentemente identificada com a programação de restrições em domínios finitos.

Propagação de restrição

Condições de consistência local são propriedades de problemas de satisfação de restrição relacionados à consistência de subconjuntos de variáveis ​​ou restrições. Eles podem ser usados ​​para reduzir o espaço de pesquisa e tornar o problema mais fácil de resolver. Vários tipos de condições de consistência local são aproveitados, incluindo consistência de nó , consistência de arco e consistência de caminho .

Cada condição de consistência local pode ser imposta por uma transformação que muda o problema sem mudar suas soluções. Essa transformação é chamada de propagação de restrição . A propagação de restrições funciona reduzindo domínios de variáveis, fortalecendo restrições ou criando novas. Isso leva a uma redução do espaço de busca, tornando o problema mais fácil de ser resolvido por alguns algoritmos. A propagação de restrições também pode ser usada como um verificador de insatisfação, incompleto em geral, mas completo em alguns casos particulares.

Resolução de restrições

Existem três técnicas algorítmicas principais para resolver problemas de satisfação de restrições: pesquisa de retrocesso, pesquisa local e programação dinâmica.

Backtracking search

A pesquisa de retrocesso é um algoritmo geral para encontrar todas (ou algumas) soluções para alguns problemas computacionais , notavelmente problemas de satisfação de restrição , que cria candidatos para as soluções de forma incremental e abandona um candidato ("retrocesso") assim que determina que o candidato não pode possivelmente ser completado para uma solução válida.

Pesquisa Local

A pesquisa local é um método incompleto para encontrar uma solução para um problema . Baseia-se na melhoria iterativa de uma atribuição das variáveis ​​até que todas as restrições sejam satisfeitas. Em particular, os algoritmos de pesquisa local geralmente modificam o valor de uma variável em uma atribuição em cada etapa. A nova atribuição está próxima da anterior no espaço de atribuição, daí o nome pesquisa local .

Programaçao dinamica

A programação dinâmica é um método de otimização matemática e um método de programação de computador. Refere-se à simplificação de um problema complicado dividindo-o em subproblemas mais simples de maneira recursiva . Embora alguns problemas de decisão não possam ser separados dessa maneira, as decisões que abrangem vários pontos no tempo geralmente se separam recursivamente. Da mesma forma, na ciência da computação, se um problema pode ser resolvido de forma otimizada dividindo-o em subproblemas e, em seguida, encontrando recursivamente as soluções ótimas para os subproblemas, então é dito que ele tem uma subestrutura ótima .

Exemplo

A sintaxe para expressar restrições em domínios finitos depende da linguagem hospedeira. O seguinte é um programa Prolog que resolve o quebra-cabeça alfamético clássico ENVIAR + MAIS = DINHEIRO na programação de lógica de restrição:

% This code works in both YAP and SWI-Prolog using the environment-supplied
% CLPFD constraint solver library.  It may require minor modifications to work
% in other Prolog environments or using other constraint solvers.
:- use_module(library(clpfd)).
sendmore(Digits) :-
   Digits = [S,E,N,D,M,O,R,N,Y],   % Create variables
   Digits ins 0..9,                % Associate domains to variables
   S #\= 0,                        % Constraint: S must be different from 0
   M #\= 0,
   all_different(Digits),          % all the elements must take different values
                1000*S + 100*E + 10*N + D     % Other constraints
              + 1000*M + 100*O + 10*R + E
   #= 10000*M + 1000*O + 100*N + 10*E + Y,
   label(Digits).                  % Start the search

O intérprete cria uma variável para cada letra do quebra-cabeça. O operador ins é usado para especificar os domínios dessas variáveis, de modo que elas variam sobre o conjunto de valores {0,1,2,3, ..., 9}. As restrições S#\=0 e M#\=0 significam que essas duas variáveis ​​não podem assumir o valor zero. Quando o interpretador avalia essas restrições, ele reduz os domínios dessas duas variáveis ​​removendo o valor 0 delas. Então, a restrição all_different(Digits) é considerada; não reduz nenhum domínio, então é simplesmente armazenado. A última restrição especifica que os dígitos atribuídos às letras devem ser tais que "ENVIAR + MAIS = DINHEIRO" se mantém quando cada letra é substituída por seu dígito correspondente. A partir dessa restrição, o solucionador infere que M = 1. Todas as restrições armazenadas envolvendo a variável M são ativadas: neste caso, a propagação da all_different restrição na restrição remove o valor 1 do domínio de todas as variáveis ​​restantes. A propagação de restrições pode resolver o problema reduzindo todos os domínios a um único valor, pode provar que o problema não tem solução reduzindo um domínio ao conjunto vazio, mas também pode terminar sem provar satisfatibilidade ou insatisfação. Os literais de rótulo são usados ​​para realmente realizar a pesquisa de uma solução.

Veja também

Referências

links externos