Resolução de Problemas Com Procura - Técnico Lisboa · Exemplo: Roménia Inexistência de mapa...

66
Resolução de Problemas Com Procura Capítulo 3

Transcript of Resolução de Problemas Com Procura - Técnico Lisboa · Exemplo: Roménia Inexistência de mapa...

Resolução de Problemas Com Procura

Capítulo 3

Sumário

  Agentes que resolvem problemas   Tipos de problemas   Formulação de problemas   Exemplos de problemas   Algoritmos de procura básicos   Eliminação de estados repetidos   Procura com informação parcial

Exemplo: Roménia

  Férias na Roménia; actualmente em Arad   Voo parte amanhã de Bucareste   Formulação do objectivo:

  Estar em Bucareste

  Formulação do problema:   Estados: várias cidades   Acções: conduzir entre cidades

  Encontrar solução:   Sequência de cidades   E.g., Arad, Sibiu, Fagaras, Bucareste

Roménia: Arad

Roménia: Bucareste

Exemplo: Roménia

Exemplo: Roménia

Exemplo: Roménia

  Inexistência de mapa   Escolhas aleatórias…

  Existência de mapa   Possibilidade de considerar sequência de estados   Uma vez encontrada uma solução, basta executar uma

sequência de acções para atingir o objectivo   Procura = encontrar uma solução   Execução = sequência de acções que permitem

alcançar o objectivo

  Agente = Formular + Procurar + Executar

Agentes que resolvem problemas

Função AgenteResolveProblemas (percep) devolve acção Argumento: percep, uma percepção Estático: seq, sequência de acções inicialmente vazia estado, descrição do estado actual obj, objectivo inicialmente vazio prob, formulação do problema

estado ← ActualizaEstado(estado,percep) se seq vazia então obj ← FormulaObjectivo(estado) prob ← FormulaProblema(estado,obj) seq ← Procura(prob) acção ← FIRST(seq) seq ← REST(seq)

devolve acção

Tipo de ambiente/problema

  Estático (vs. dinâmico)   Ambiente não é alterado enquanto agente efectua

formulação e resolução do problema

  Observável (vs. parcialmente observável)   Sensores dão acesso ao estado completo do ambiente

  Discreto (vs. contínuo)   Número limitado de percepções e acções distintas

claramente definidas

  Determinístico (vs. estocástico)   Estado seguinte é determinado em função do estado

actual e da acção executada pelo agente; fase de execução independente das percepções!

Formulação do Problema (1/2)

  Estado inicial em que se encontra o agente   Em(Arad)

  Descrição das acções possíveis   Função sucessor-fn: estado <acção,sucessor>*   sucessor-fn(Em(Arad)) = {<Ir(Sibiu),Em(Sibiu)>,

<Ir(Timisoara),Em(Timisoara)>, <Ir(Zerind),Em(Zerind)>}

  Estado inicial e sucessor-fn definem implicitamente o espaço de estados do problema (mapa pode ser interpretado como espaço de estados)

  Um caminho num espaço de estados é uma sequência de estados resultantes de uma sequência de acções

Formulação do Problema (2/2)

  Teste objectivo que determina se um estado é um estado objectivo   Os estados objectivo podem ser explícitos (Em(Bucareste)) ou

implícitos (checkmate)

  Função de custo que atribui um custo numérico a cada caminho   Escolhida em função do desempenho pretendido para o agente

(rapidez km)

  Formulação do Problema = estado inicial + acções/sucessor-fn + teste objectivo + função de custo

  Solução = sequência de acções que permitem ir desde o estado inicial até um estado objectivo

Mundo do aspirador: estados

Espaço de Estados: grafo

  estados? sujidade e localização do robot   acções? Esquerda, Direita, Aspirar   teste objectivo? não haver sujidade em nenhuma

posição

  função de custo? 1 por acção

Exemplo: 8-puzzle

  estados? Localização das peças   acções? Mover espaço esq, dir, cima, baixo   teste objectivo? = estado objectivo (dado)   função de custo? 1 por movimento

[Nota: solução óptima para a família n-Puzzle é NP-difícil]

Exemplo: montagem

  estados?: coordenadas das posições chave do robot e do objecto a ser montado

  acções?: movimentos do robot   teste objectivo?: montagem completa   função de custo?: tempo de execução

Exercício: 8-rainhas

  Colocar 8 rainhas num tabuleiro 8x8 tal que nenhuma rainha ataca outra rainha (uma rainha ataca outra rainha se estiver na mesma linha, na mesma coluna ou na mesma diagonal)

Solução: 8-rainhas

  Estados: qualquer tabuleiro de 8x8 com 8 rainhas   Acções: movimentar uma rainha para uma posição vazia   Teste objectivo: 8 rainhas no tabuleiro, nenhuma atacada   Função de custo: 1 por movimento

Árvores de Procura (1/2)

  Algoritmo:   Simulação da expansão do espaço de procura a

partir da geração dos sucessores dos estados já gerados (expansão de estados)

  Vs. espaço de estados   O mesmo estado pode estar em nós diferentes   Caminho bem definido

Árvores de Procura (2/2)

Função ArvoreDeProcura (problema, estratégia) devolve solução ou nãohásolução

InicializaArvoreDeProcuraComEstadoInicial(problema) loop se não há candidatos para expansão então devolve nãohásolução EscolheNóFolhaDaArvoreParaExpansao(estratégia) se o nó contém um estado objectivo então devolve solução senão expande o nó e

adiciona novos nós à árvore de procura

Exemplo: Roménia

Árvore de Procura: exemplo

Estado inicial

Espaço de estados

  Existe um único nó folha que pode ser expandido: Arad   Nós resultantes da expansão do nó Arad: Sibiu, Timisoara,

Zerind

Árvore de Procura: exemplo

Árvore de Procura: exemplo

  Existem três nós folha que podem ser expandidos: Sibiu, Timisoara, Zerind

  Nó Sibiu é escolhido pela estratégia de procura como o próximo nó a ser expandido

  Nós resultantes da expansão do nó Sibiu são adicionados ao conjunto de nós folha

Implementação: estados vs. nós

  Um estado é a representação de uma configuração física   Um nó é uma estrutura de dados que constitui parte de

uma árvore de procura e que inclui estado, nó pai, acção, custo do caminho g(x), profundidade

  A função Expande cria novos nós, preenche os vários campos da estrutura nó e usa a função successor-fn do problema para criar os estados correspondentes.

Implementação (1/4)

  Considerem-se definidos os seguintes campos para o tipo NÓ:   Estado   PaiNó   Acção   CustoCaminho   Profundidade

Implementação (2/4)

  Considerem-se definidas as seguintes funções para o tipo FILA:   CriaFila(elemento, …)   Vazia?(fila)   RemovePrimeiro(fila)   Insere(elemento,fila)   InsereTodos(elementos,fila)

Implementação (3/4)

Função ArvoreDeProcura (problema, filafolhas) devolve solução ou nãohásolução

filafolhas ← Insere(CriaNó(EstadoInicial[problema]),filafolhas)

loop se Vazia?(filafolhas) então devolve nãohásolução nó ← RemovePrimeiro(filafolhas) se TesteObjectivo[problema](nó) então devolve solução(nó) filafolhas ←

InsereTodos(Expande(nó,problema),filafolhas)

Implementação (4/4)

Função Expande (nó, problema) devolve sucessores (conjunto de nós)

sucessores ← conjunto vazio paracada <acção,resultado> em sucessor-fn[problema](Estado(nó)) s ← novo Nó Estado(s) ← resultado PaiNó(s) ← nó Acção(s) ← acção CustoCaminho(s) ← CustoCaminho(nó) + CustoRamo(Estado(nó),

acção, resultado) Profundidade(s) ← Profundidade(nó) +1 adiciona s aos sucessores devolve sucessores

Estratégias de Procura

  Uma estratégia de procura é caracterizada por escolher a ordem de expansão dos nós   Ou em alternativa a ordem de inserção dos nós na

fila de folhas

Estratégias de Procura

  As estratégias são avaliadas de acordo com 4 aspectos:   Completude: encontra sempre uma solução caso exista (se não

existir diz que não há solução)   Complexidade temporal: número de nós gerados   Complexidade espacial: número máximo de nós em memória   Optimalidade: encontra a solução de menor custo

  Complexidade temporal e espacial são medidas em termos de:   r: máximo factor de ramificação da árvore de procura   p: profundidade da solução de menor custo (nó com estado

inicial tem profundidade 0)   m: máxima profundidade do espaço de estados (pode ser ∞)

Procura Não Informada

  Estratégias de procura não informada usam apenas a informação disponível na definição do problema

  Largura Primeiro   Custo Uniforme   Profundidade Primeiro   Profundidade Limitada   Profundidade Iterativa   Bi-Direccional

  Também chamadas estratégias de procura cega

Largura Primeiro

  Expande nó folha de menor profundidade   Implementação:

  folhas colocadas numa fila (FIFO), i.e., novos sucessores são colocadas no fim da lista

Largura Primeiro

  Nó A é expandido: novos nós B e C   B está no início da fila: próximo nó a expandir

  A ordem é irrelevante para nós com a mesma profundidade (pode usar-se ordem alfabética para desempate)

Largura Primeiro

  Nó B é expandido: novos nós D e E   C está no início da fila; os outros nós folha (D e E)

têm maior profundidade

Largura Primeiro

  Estado actual   Fila nós folha: D, E, F, G nós abertos

  Nós gerados mas ainda não expandidos

  Nós expandidos: A, B, C nós fechados

Largura Primeiro: propriedades

  Completa? Sim (se r é finito)   Tempo? 1+r+r2+r3+… +rp + (rp+1-r) = O(rp+1), i.e.

exponencial em p   Espaço? O(rp+1) (todos os nós por expandir em memória)   Óptima? Sim (se custo = 1 por acção); logo não é óptima

no caso geral

  r: máximo factor de ramificação da árvore de procura   p: profundidade da solução de menor custo

  Espaço é o maior problema (mais do que tempo)   Se forem gerados nós a 100MB/s então 24h = 8640GB ≈ 8.4TB

Complexidade: exemplo

  Estado objectivo G   Factor de ramificação r=2   Profundidade da solução p=2   Tempo

  1+21+22+(23-2)   O(23), i.e, O(rp+1)

  Espaço   23-2   O(23) i.e, O(rp+1)

A

C

E

H

G F D

I J L M N

B

p=0

p=1

p=2

p=3

Exemplo: Roménia

  Profundidade da Solução?   Nº mínimo de nós expandidos até solução?   Obs: teste objectivo é feito antes da expansão do nó!

Exemplo: solução

  Profundidade da solução: 3   Nº mínimo de nós expandidos: 12

  Obs: estados iguais correspondem a nós diferentes (Arad, Oradea,…)

Custo Uniforme

  Expandir nó folha n que tem menor custo g(n)   Implementação:

  folhas = fila ordenada por custo do caminho   Equivalente à procura por largura primeiro se todos os

ramos tiverem o mesmo custo   Completa? Sim, se custo do ramo ≥ ε

  ε é uma constante > 0, para evitar ciclos em ramos com custo 0   Custo do caminho aumenta sempre com a profundidade

  Tempo? # de nós com g ≤ custo da solução óptima, O(r1+C*/ε) onde C* é o custo da solução óptima   Todos os ramos com o mesmo custo O(r1+C*/ε) = O(rp+1)

  Espaço? # de nós com g ≤ custo da solução óptima, O(r1+C*/ε)

  Óptima? Sim – nós expandidos por ordem crescente de g

Custo Uniforme: exemplo

  Custo associado a cada ramo

  Ordem de expansão dos nós?   Desempate: ordem

alfabética

  Solução encontrada?

A

C

E G F D

J L M N

B

2

2 1 1 5

1 2 3 1

3

Custo Uniforme: exemplo

  Ordem de expansão dos nós?   A(0), B(2), C(3), E(3),

F(4), J(4)   Nós folha: G(5), L(5),

N(5), D(7), M(7)

  Solução encontrada?   J (custo 4)

A

C

E G F D

J L M N

B 2

5 4 3 7

4 5 7 5

3

0

Complexidade: exemplo

  Todos os ramos com custo ε, com excepção do ramo assinalado

  Objectivo G (C*=3.1ε)

  Factor de ramificação r=2   Tempo e Espaço

  1+21+22+(23-2)+(24-4)   O(24), i.e, O(r1+C*/ε)

A

C

E

H

G F D

I J L M N

B

p=0

p=1

p=2

p=3

p=4

2.1 ε

Profundidade Primeiro

  Expandir nó folha com a maior profundidade   Implementação:

  listafolhas = fila LIFO (pilha), i.e., sucessores colocados no início da fila

Profundidade Primeiro

Profundidade Primeiro: propriedades

  Completa? Não: não encontra a solução em espaços de estados com profundidade infinita/com ciclos   Modificação para evitar estados repetidos ao longo do

caminho completa em espaços finitos

  Tempo? O(rm): problemático se máxima profundidade do espaço de estados m é muito maior do que profundidade da solução de menor custo p

  Espaço? O(r*m) - espaço linear (só um caminho)   Óptima? Não

Profundidade Primeiro

  Implementação: habitualmente recursiva   Nós deixam de ser guardados em memória quando

todos os seus sucessores são gerados   Variante: procura por retrocesso

  Usa ainda menos memória: O(m) vs. O(r*m)   Só é gerado um sucessor de cada vez

Profundidade Limitada

  Profundidade primeiro com limite de profundidade l, i.e., nós com profundidade l não têm sucessores

  Resolve problema da profundidade infinita   Limite pode ser determinado em função do tipo de

problema   Diâmetro do espaço de estados define máxima

profundidade da solução

  Se p > l não é encontrada solução   Complexidade temporal O(rl)   Complexidade espacial O(rl)

Exemplo: diâmetro? 9

Distância minima de 9 troços entre quaisquer duas cidades

Implementação Recursiva

Função ProcuraProfundidadeLimitada (prob,limite) devolve solução ou nãohásolução/corta

devolve PPLrecursiva (CriaNó(EstadoInicial[problema]),prob,limite)

Função PPLrecursiva (nó,prob,limite) devolve solução ou nãohásolução/corta

atingiu_limite? ← falso se TesteObjectivo[problema](nó) então devolve solução(nó) senão se Profundidade(nó)=limite então devolve corta senão para cada sucessor em Expande(nó,prob) resultado ← PPLrecursiva (sucessor,prob,limite) se resultado = corta então atingiu_limite ← verdadeiro senão se resultado ≠ corta então devolve resultado se atingiu_limite? então devolve corta senão devolve nãohásolução

Implementação Recursiva

  Algoritmo ProcuraProfundidadeLimitada tem 3 outputs possíveis:   Solução: se encontra solução   Corta: se não encontra solução mas não chegou

a expandir toda a árvore devido ao limite de profundidade

  Não há solução: se não encontrou solução e expandiu toda a árvore

Profundidade Limitada: exemplo

  Solução encontrada?   Profundidade Primeiro   Profundidade Limitada

  l =1

  l =2

A

C

E G F D

J L M N

B

Profundidade Iterativa

  Profundidade limitada com limite incremental: l=0, l=1, l=2, l=3, …, l=p

  Combina vantagens da largura primeiro e da profundidade primeiro

Função ProcuraProfundidadeIterativa (prob) devolve solução ou nãohásolução

ciclo limite ← 0 até ∞ resultado ← ProcuraProfundidadeLimitada(prob,limite) se resultado ≠ corta então devolve resultado

Profundidade Iterativa l=0

Profundidade Iterativa l=1

Profundidade Iterativa l=2

Profundidade Iterativa l=3

Profundidade Iterativa

  Número de nós gerados na procura em profundidade limitada com profundidade p e factor de ramificação r:

NPPL = r0 + r1 + r2 + … + rp-2 + rp-1 + rp

  Número de nós gerados na procura em profundidade iterativa com profundidade p e factor de ramificação r: NPPI=(p+1)r0 + pr^1 + (p-1)r^2 + … + 3rp-2 +2rp-1 + 1rp

  Para r = 10, p = 5,   NPPL = 1 + 10 + 100 + 1,000 + 10,000 + 100,000 = 111,111   NPPI = 6 + 50 + 400 + 3,000 + 20,000 + 100,000 = 123,456

  Esforço adicional = (123,456 - 111,111)/111,111 = 11%

Profundidade Iterativa: propriedades

  Completa? Sim   Tempo? (p+1)r0 + pr1 + (p-1)r2 + … + rp =

O(rp)   Espaço? O(r*p)   Óptima? Sim, se custo de cada ramo = 1

Procura Bi-Direccional

  Executar duas procuras em largura em simultâneo   Uma a partir do estado inicial (forward, para a frente)   Outra a partir do estado final (backward, para trás)

  Procura termina quando as duas procuras se encontram (têm um estado em comum)

  Motivação: rp/2 + rp/2 << rp

  Necessidade de calcular eficientemente os predecessores de um nó

  Problemática quando estados objectivos são descritos implicitamente (por exº, checkmate)

Procura Bi-Direccional: propriedades

  Completa? Sim, se p é finito e se executa procura em largura primeiro em ambas as direcções

  Tempo? O(rp/2)   Espaço? O(rp/2)   Óptima? Sim, se custo de cada ramo = 1 e se

executa procura em largura primeiro em ambas as direcções

Resumo dos algoritmos

  a completa se r é finito   b completa se custo de cada ramo > 0   c óptima se todos os ramos têm o mesmo custo   d se ambas as direcções executam procura em largura primeiro

Largura Primeiro

Custo Uniforme

Profund. Primeiro

Profund. Limitada

Profund. Iterativa

Bi-direc-cional

Completa? Sima Sima,b Não Não Sima Sima,d

Tempo O(r p+1) O(r1+C*/ε) O(r m) O(r l) O(r p) O(r p/2)

Espaço O(r p+1) O(r1+C*/ε) O(rm) O(r l) O(rp) O(r p/2)

Óptima? Simc Sim Não Não Simc Simc,d

Eliminação de Estados Repetidos

  Não detecção de estados repetidos pode transformar um problema linear em exponencial!

  Alterar procura em árvore para procura em grafo com análise de nós fechados   Optimalidade pode ser afectada se usarmos nós abertos

Procura em grafo

Função GrafoDeProcura (problema, filafolhas) devolve solução ou nãohásolução

fechados ← conjunto vazio filafolhas ←

Insere(CriaNó(EstadoInicial[problema]),filafolhas) loop se Vazia?(filafolhas) então devolve nãohásolução nó ← RemovePrimeiro(filafolhas) se TesteObjectivo[problema](nó) então devolve solução(nó) se nó não está em fechados então adiciona Estado(nó) a fechados nó ← InsereTodos(Expande(nó,problema),filafolhas)

Procura com Informação Parcial

  Problemas nos sensores   O estado actual consiste num conjunto de estados acreditados   O resultado das acções é conhecido transição entre conjuntos de

estados acreditados

  Problemas de contingência   Ambiente parcialmente observável ou resultado das acções é incerto

nova informação depois de cada acção   Solução dada ao agente é um plano de contingência: acções

dependem de condições

  Problemas de exploração   Estados e acções do ambiente são desconhecidos   Caso extremo de problema de contingência