Initial commit

This commit is contained in:
github-classroom[bot] 2024-09-17 10:51:48 +00:00 committed by GitHub
commit 9e833eaf57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 928 additions and 0 deletions

129
.gitignore vendored Normal file
View File

@ -0,0 +1,129 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

24
README.md Normal file
View File

@ -0,0 +1,24 @@
# iia-ia-guiao-pesquisa
Guião de resolução automatica de problemas
# Como resolver o guião
1. Crie um virtual environment:
```bash
python3 -m venv venv
```
2. Active o virtual environment (precisa de repetir este passo sempre que começar uma nossa sessão/terminal):
```bash
source venv/bin/activate
```
3. Instale os requisitos:
```bash
pip install -r requirements.txt
```
4. Programe a sua solução.
5. Teste a sua solução.
```bash
pytest

7
amigos.py Normal file
View File

@ -0,0 +1,7 @@
from constraintsearch import *
amigos = ["Andre", "Bernardo", "Claudio"]
cs = ConstraintSearch(None, None)
print(cs.search())

122
blocksworld.py Normal file
View File

@ -0,0 +1,122 @@
#
# Module: blocksworld
#
# Based on the imported "strips" module, the "blocksworld" module
# defines a set of predicates and operators for representing
# the "Blocks World" planning domain.
#
# (c) Luis Seabra Lopes
# Inteligência Artificial & Introducao a Inteligencia Artificial, 2019-2020
#
import time
from strips import *
# Blocks world predicates
class Floor(Predicate):
def __init__(self,block):
self.args = [block]
class On(Predicate):
def __init__(self,b1,b2):
self.args = [b1,b2]
class Free(Predicate):
def __init__(self,block):
self.args = [block]
class Holds(Predicate):
def __init__(self,block):
self.args = [block]
class HandFree(Predicate):
def __init__(self):
self.args = []
# Blocks world operators
X='X'
Y='Y'
Z='Z'
class Stack(Operator):
args = [X,Y]
pc = [Holds(X),Free(Y)]
neg = [Holds(X),Free(Y)]
pos = [On(X,Y),HandFree(),Free(X)]
class Unstack(Operator):
args = [X,Y]
pc = [On(X,Y),HandFree(),Free(X)]
neg = [On(X,Y),HandFree(),Free(X)]
pos = [Holds(X),Free(Y)]
class Putdown(Operator):
args = [X]
pc = [Holds(X)]
neg = [Holds(X)]
pos = [Floor(X),HandFree(),Free(X)]
class Pickup(Operator):
args = [X]
pc = [Floor(X),HandFree(),Free(X)]
neg = [Floor(X),HandFree(),Free(X)]
pos = [Holds(X)]
a='a'
b='b'
c='c'
d='d'
e='e'
initial_state = [ Floor(a), Floor(b), Floor(d), Holds(e), On(c,d),
Free(a), Free(b), Free(c) ]
# _
# / \
# | (e)
# |
# | |c|
# _|___|a|____|b|_____|d|_
#
goal_state = [ Floor(c), On(d,c), On(e,d), On(a,e), Floor(b) ]
# _
# / \
# | ( ) |a|
# | |e|
# | |d|
# _|__________|b|___|c|___
#
print('Substitute:',On(X,Y).substitute({ X : a, Y : b, Z : c}))
print('Instanciate:',Stack.instanciate([a,b]))
bwdomain = STRIPS()
print('Actions:',bwdomain.actions(initial_state))
"""
# uncomment to test
inittime = time.time()
p = SearchProblem(bwdomain,initial_state,goal_state)
t = SearchTree(p)
t.search()
print(t.plan)
print('time=',time.time()-inittime)
print(len(t.open_nodes),' nodes')
"""

119
cidades.py Normal file
View File

@ -0,0 +1,119 @@
#
# Module: cidades
#
# Implements a SearchDomain for find paths between cities
# using the tree_search module
#
# (c) Luis Seabra Lopes
# Introducao a Inteligencia Artificial, 2012-2020
# Inteligência Artificial, 2014-2023
#
from tree_search import *
class Cidades(SearchDomain):
def __init__(self,connections, coordinates):
self.connections = connections
self.coordinates = coordinates
def actions(self,city):
actlist = []
for (C1,C2,D) in self.connections:
if (C1==city):
actlist += [(C1,C2)]
elif (C2==city):
actlist += [(C2,C1)]
return actlist
def result(self,city,action):
(C1,C2) = action
if C1==city:
return C2
def cost(self, city, action):
pass
def heuristic(self, city, goal_city):
pass
def satisfies(self, city, goal_city):
return goal_city==city
cidades_portugal = Cidades(
# Ligacoes por estrada
[
('Coimbra', 'Leiria', 73),
('Aveiro', 'Agueda', 35),
('Porto', 'Agueda', 79),
('Agueda', 'Coimbra', 45),
('Viseu', 'Agueda', 78),
('Aveiro', 'Porto', 78),
('Aveiro', 'Coimbra', 65),
('Figueira', 'Aveiro', 77),
('Braga', 'Porto', 57),
('Viseu', 'Guarda', 75),
('Viseu', 'Coimbra', 91),
('Figueira', 'Coimbra', 52),
('Leiria', 'Castelo Branco', 169),
('Figueira', 'Leiria', 62),
('Leiria', 'Santarem', 78),
('Santarem', 'Lisboa', 82),
('Santarem', 'Castelo Branco', 160),
('Castelo Branco', 'Viseu', 174),
('Santarem', 'Evora', 122),
('Lisboa', 'Evora', 132),
('Evora', 'Beja', 105),
('Lisboa', 'Beja', 178),
('Faro', 'Beja', 147),
# extra
('Braga', 'Guimaraes', 25),
('Porto', 'Guimaraes', 44),
('Guarda', 'Covilha', 46),
('Viseu', 'Covilha', 57),
('Castelo Branco', 'Covilha', 62),
('Guarda', 'Castelo Branco', 96),
('Lamego','Guimaraes', 88),
('Lamego','Viseu', 47),
('Lamego','Guarda', 64),
('Portalegre','Castelo Branco', 64),
('Portalegre','Santarem', 157),
('Portalegre','Evora', 194) ],
# City coordinates
{ 'Aveiro': (41,215),
'Figueira': ( 24, 161),
'Coimbra': ( 60, 167),
'Agueda': ( 58, 208),
'Viseu': ( 104, 217),
'Braga': ( 61, 317),
'Porto': ( 45, 272),
'Lisboa': ( 0, 0),
'Santarem': ( 38, 59),
'Leiria': ( 28, 115),
'Castelo Branco': ( 140, 124),
'Guarda': ( 159, 204),
'Evora': (120, -10),
'Beja': (125, -110),
'Faro': (120, -250),
#extra
'Guimaraes': ( 71, 300),
'Covilha': ( 130, 175),
'Lamego' : (125,250),
'Portalegre': (130,170) }
)
p = SearchProblem(cidades_portugal,'Braga','Faro')
t = SearchTree(p,'breadth')
print(t.search())
# Atalho para obter caminho de c1 para c2 usando strategy:
def search_path(c1,c2,strategy):
my_prob = SearchProblem(cidades_portugal,c1,c2)
my_tree = SearchTree(my_prob)
my_tree.strategy = strategy
return my_tree.search()

56
constraintsearch.py Normal file
View File

@ -0,0 +1,56 @@
# Pesquisa para resolucao de problemas de atribuicao
#
# Introducao a Inteligencia Artificial
# DETI / UA
#
# (c) Luis Seabra Lopes, 2012-2019
#
class ConstraintSearch:
# domains é um dicionário com o domínio de cada variável;
# constaints e' um dicionário com a restrição aplicável a cada aresta;
def __init__(self,domains,constraints):
self.domains = domains
self.constraints = constraints
self.calls = 0
# domains é um dicionário com os domínios actuais
# de cada variável
# ( ver acetato "Pesquisa com propagacao de restricoes
# em problemas de atribuicao - algoritmo" )
def search(self,domains=None):
self.calls += 1
if domains==None:
domains = self.domains
# se alguma variavel tiver lista de valores vazia, falha
if any([lv==[] for lv in domains.values()]):
return None
# se nenhuma variavel tiver mais do que um valor possivel, sucesso
if all([len(lv)==1 for lv in list(domains.values())]):
# se valores violam restricoes, falha
# ( verificacao desnecessaria se for feita a propagacao
# de restricoes )
for (var1,var2) in self.constraints:
constraint = self.constraints[var1,var2]
if not constraint(var1,domains[var1][0],var2,domains[var2][0]):
return None
return { v:lv[0] for (v,lv) in domains.items() }
# continuação da pesquisa
# ( falta fazer a propagacao de restricoes )
for var in domains.keys():
if len(domains[var])>1:
for val in domains[var]:
newdomains = dict(domains)
newdomains[var] = [val]
solution = self.search(newdomains)
if solution != None:
return solution
return None

BIN
guiao-pesquisa-en.pdf Normal file

Binary file not shown.

BIN
guiao-pesquisa.pdf Normal file

Binary file not shown.

8
mapas.py Normal file
View File

@ -0,0 +1,8 @@
from constraintsearch import *
region = ['A', 'B', 'C', 'D', 'E']
colors = ['red', 'blue', 'green', 'yellow', 'white']
cs = ConstraintSearch(None, None)
print(cs.search())

26
rainhas.py Normal file
View File

@ -0,0 +1,26 @@
from constraintsearch import *
def queen_constraint(r1,c1,r2,c2):
l1 = int(r1[1:])
l2 = int(r2[1:])
if c1==c2:
return False
if abs(l1-l2)==abs(c1-c2):
return False
return True
def make_constraint_graph(n):
queens = [ 'R'+str(i+1) for i in range(n) ]
return { (X,Y):queen_constraint for X in queens for Y in queens if X!=Y }
def make_domains(n):
queens = [ 'R'+str(i+1) for i in range(n) ]
cols = [ i+1 for i in range(n) ]
return { r:cols for r in queens }
cs = ConstraintSearch(make_domains(4),make_constraint_graph(4))
print(cs.search())

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
mock
pytest

124
strips.py Normal file
View File

@ -0,0 +1,124 @@
#
# Module: strips
#
# This module provides classes for representing STRIPS-based
# planning domains:
# Predicate - used to represent conditions in states and operators
# Operator - used to represent STRIPS operators
# STRIPS - a "SearchDomain" for planning with STRIPS operators
#
# (c) Luis Seabra Lopes
# Inteligência Artificial & Introducao a Inteligencia Artificial, 2019
#
from tree_search import *
from functools import reduce
from itertools import product
# Predicates used to describe states, preconditions and effects
class Predicate:
def __str__(self):
argsstr = args2string(self.args)
return type(self).__name__ + "(" + argsstr + ")"
def __repr__(self):
return str(self)
def __eq__(self,predicate): # allows for comparisons with "==", etc.
return str(self)==str(predicate)
def substitute(self,assign): # Substitute the arguments in a predicate
la = self.args # by constants according to a given
if len(la)==0: # assignment (i.e. a dictionary)
return type(self)()
if len(la)==1:
return type(self)(assign[la[0]])
# add other cases if needed
return type(self)(assign[la[0]],assign[la[1]])
# STRIPS operators
# -- operators for a specific domain will be subclasses
# -- concrete actions will be instances of specific operators
class Operator:
def __init__(self,args,pc,neg,pos):
self.args = args
self.pc = pc
self.neg = neg
self.pos = pos
def __str__(self):
return type(self).__name__ + '([' + args2string(self.args) + "]," + \
str(self.pc) + ',' + str(self.neg) + ',' + \
str(self.pos) + ')'
def __repr__(self):
argsstr = args2string(self.args)
return type(self).__name__ + "(" + argsstr + ")"
# Produce a concrete action by instanciating a specific
# operator (i.e. the "Operator" subclass where the method was
# called) for the arguments given in "args"
# ( returns None if the action is not applicable in the given "state" )
@classmethod
def instanciate(cls,args):
if len(args)!=len(cls.args):
return None
assign = dict(zip(cls.args, args))
pc = [ p.substitute(assign) for p in cls.pc ]
neg = [ p.substitute(assign) for p in cls.neg ]
pos = [ p.substitute(assign) for p in cls.pos ]
return cls(args,pc,neg,pos)
# Search domains based on STRIPS actions
class STRIPS(SearchDomain):
# constructor
def __init__(self):
pass
# list of applicable actions in a given "state"
def actions(self, state):
constants = state_constants(state)
operators = Operator.__subclasses__()
actions = []
for op in operators:
lassign = assignments(op.args,constants)
for assign in lassign:
argvalues = [assign[a] for a in op.args]
action = op.instanciate(argvalues)
if all(c in state for c in action.pc):
actions.append(action)
return actions
# Result of a given "action" in a given "state"
# ( returns None, if the action is not applicable in the state)
def result(self, state, action):
pass
def cost(self, state, action):
return 1
def heuristic(self, state, goal):
return 0
# Checks if a given "goal" is satisfied in a given "state"
def satisfies(self, state, goal):
pass
# Auxiliary functions
def state_constants(state):
return list(set(reduce(lambda r,h : h.args+r, state,[])))
def assignments(lvars,lconsts):
lcombs = product(lconsts,repeat=len(lvars))
makeassign = lambda comb : dict(zip(lvars,comb))
return list(map(makeassign,lcombs))
def args2string(args):
if args == []:
return ""
return reduce(lambda r,h : r+','+str(h), args[1:],str(args[0]))

7
tests/__init__.py Normal file
View File

@ -0,0 +1,7 @@
import os
import sys
PROJECT_PATH = os.getcwd()
SOURCE_PATH = os.path.join(
PROJECT_PATH,"."
)
sys.path.append(SOURCE_PATH)

51
tests/test_aula3.py Normal file
View File

@ -0,0 +1,51 @@
import pytest
from cidades import SearchProblem, SearchTree, cidades_portugal
@pytest.fixture
def braga_faro():
return SearchProblem(cidades_portugal,'Braga','Faro')
def test_exercicio1(braga_faro):
t = SearchTree(braga_faro,'depth')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Beja', 'Faro']
def test_exercicio2(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.open_nodes[-1].depth == 0
t.search()
assert t.solution.depth == 11
def test_exercicio3(braga_faro):
t = SearchTree(braga_faro, 'depth')
t.search()
assert t.length == 11
def test_exercicio4(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.search(limit=9) == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Santarem', 'Lisboa', 'Beja', 'Faro']
assert t.length <= 9
def test_exercicio5(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Beja', 'Faro']
assert t.terminals == 19
assert t.non_terminals == 11
t = SearchTree(braga_faro, 'depth')
assert t.search(limit=9) == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Santarem', 'Lisboa', 'Beja', 'Faro']
assert t.terminals == 12
assert t.non_terminals == 58
def test_exercicio6(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Beja', 'Faro']
assert round(t.avg_branching,2) == round((19+11-1)/11,2)

30
tests/test_aula4.py Normal file
View File

@ -0,0 +1,30 @@
import pytest
from cidades import SearchProblem, SearchTree, cidades_portugal
@pytest.fixture
def braga_faro():
return SearchProblem(cidades_portugal,'Braga','Faro')
def test_exercicio7(braga_faro):
assert cidades_portugal.cost('Aveiro', ('Aveiro', 'Agueda')) == 35
assert cidades_portugal.cost('Agueda', ('Agueda', 'Aveiro')) == 35
assert cidades_portugal.cost('Aveiro', ('Aveiro', 'Lisboa')) == None
def test_exercicio8(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Beja', 'Faro']
assert t.solution.cost == 1104
def test_exercicio9(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Beja', 'Faro']
assert t.cost == 1104
def test_exercicio10(braga_faro):
t = SearchTree(braga_faro, 'uniform')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Coimbra', 'Leiria', 'Santarem', 'Evora', 'Beja', 'Faro']
assert t.cost == 706
assert t.length == 8

48
tests/test_aula5.py Normal file
View File

@ -0,0 +1,48 @@
import pytest
from cidades import SearchProblem, SearchTree, cidades_portugal
@pytest.fixture
def braga_faro():
return SearchProblem(cidades_portugal,'Braga','Faro')
def test_exercicio11(braga_faro):
assert round(cidades_portugal.heuristic('Aveiro', 'Agueda'),2) == 18.38
assert round(cidades_portugal.heuristic('Agueda', 'Aveiro'),2) == 18.38
assert round(cidades_portugal.heuristic('Aveiro', 'Lisboa'),2) == 218.87
def test_exercicio12(braga_faro):
t = SearchTree(braga_faro, 'depth')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Aveiro', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Beja', 'Faro']
assert t.solution.heuristic == 0
assert t.solution.parent.state == 'Beja'
assert round(t.solution.parent.heuristic, 2) == 140.09
def test_exercicio13(braga_faro):
t = SearchTree(braga_faro, 'greedy')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Coimbra', 'Leiria', 'Santarem', 'Evora', 'Beja', 'Faro']
assert t.cost == 706
assert t.length == 8
assert round(t.avg_branching,2) == round((17+8-1)/8,2)
def test_exercicio14(braga_faro):
t = SearchTree(braga_faro, 'a*')
assert t.search() == ['Braga', 'Porto', 'Agueda', 'Coimbra', 'Leiria', 'Santarem', 'Evora', 'Beja', 'Faro']
assert t.cost == 706
assert t.length == 8
assert round(t.avg_branching,2) == round((160+84-1)/84,2)
def test_exercicio15(braga_faro):
t = SearchTree(braga_faro, 'uniform')
t.search()
assert len(t.highest_cost_nodes) == 5
assert [t.get_path(n) for n in t.highest_cost_nodes] == [['Braga', 'Porto', 'Agueda', 'Viseu', 'Castelo Branco', 'Santarem', 'Portalegre', 'Evora'], ['Braga', 'Guimaraes', 'Lamego', 'Viseu', 'Coimbra', 'Agueda', 'Aveiro', 'Figueira', 'Leiria', 'Santarem', 'Portalegre', 'Evora'], ['Braga', 'Guimaraes', 'Lamego', 'Viseu', 'Guarda', 'Castelo Branco', 'Santarem', 'Lisboa', 'Evora', 'Portalegre'], ['Braga', 'Porto', 'Agueda', 'Coimbra', 'Leiria', 'Castelo Branco', 'Santarem', 'Evora', 'Portalegre'], ['Braga', 'Porto', 'Aveiro', 'Figueira', 'Leiria', 'Coimbra', 'Agueda', 'Viseu', 'Guarda', 'Castelo Branco', 'Portalegre', 'Evora']]
def test_exercicio16(braga_faro):
t = SearchTree(braga_faro, 'uniform')
t.search()
assert round(t.average_depth,2) == 9.02

26
tests/test_constraints.py Normal file
View File

@ -0,0 +1,26 @@
import pytest
import mapas
import amigos
def test_exercicio1_4():
assert mapas.cs.search() == {'A': 'red', 'B': 'blue', 'C': 'red', 'D': 'blue', 'E': 'green'}
def test_exercicio1_5():
solution = amigos.cs.search()
for amigo, (bicicleta, chapeu) in solution.items():
assert amigo != bicicleta
assert amigo != chapeu
if chapeu == "Claudio":
assert bicicleta == "Bernardo"
bicicletas = [ bicicleta for _, (bicicleta, _) in solution.items() ]
assert len(bicicletas) == len(set(bicicletas))
chapeus = [ chapeu for _, (_, chapeu) in solution.items() ]
assert len(chapeus) == len(set(chapeus))
def test_exercicio2():
assert amigos.cs.calls == 14

34
tests/test_strips.py Normal file
View File

@ -0,0 +1,34 @@
import pytest
from blocksworld import Floor, Holds, On, Free, a, b, c, d, e, Stack, Putdown, HandFree
from strips import STRIPS
from tree_search import SearchProblem, SearchTree
@pytest.fixture
def initial_state():
return [ Floor(a), Floor(b), Floor(d), Holds(e), On(c,d), Free(a), Free(b), Free(c) ]
@pytest.fixture
def goal_state():
return [ Floor(c), On(d,c), On(e,d), On(a,e), Floor(b) ]
def test_exercicio1(initial_state):
bwdomain = STRIPS()
actions = bwdomain.actions(initial_state)
assert all(op in str(actions) for op in ["Stack(e,b)", "Stack(e,a)", "Stack(e,c)", "Putdown(e)"])
assert bwdomain.result(initial_state, actions[-1]) == {Free(e), On(c,d), Floor(d), Floor(b), HandFree(), Floor(a), Free(a), Free(c), Free(b), Floor(e)}
assert bwdomain.satisfies(initial_state, [On(c,d), Free(a)])
def test_exercicio2(initial_state, goal_state):
bwdomain = STRIPS()
p = SearchProblem(bwdomain,initial_state,goal_state)
t = SearchTree(p)
t.search()
assert str(t.plan) == "[Stack(e,b), Unstack(c,d), Putdown(c), Pickup(d), Stack(d,c), Unstack(e,b), Stack(e,d), Pickup(a), Stack(a,e)]"

115
tree_search.py Normal file
View File

@ -0,0 +1,115 @@
# Module: tree_search
#
# This module provides a set o classes for automated
# problem solving through tree search:
# SearchDomain - problem domains
# SearchProblem - concrete problems to be solved
# SearchNode - search tree nodes
# SearchTree - search tree with the necessary methods for searhing
#
# (c) Luis Seabra Lopes
# Introducao a Inteligencia Artificial, 2012-2020,
# Inteligência Artificial, 2014-2023
from abc import ABC, abstractmethod
# Dominios de pesquisa
# Permitem calcular
# as accoes possiveis em cada estado, etc
class SearchDomain(ABC):
# construtor
@abstractmethod
def __init__(self):
pass
# lista de accoes possiveis num estado
@abstractmethod
def actions(self, state):
pass
# resultado de uma accao num estado, ou seja, o estado seguinte
@abstractmethod
def result(self, state, action):
pass
# custo de uma accao num estado
@abstractmethod
def cost(self, state, action):
pass
# custo estimado de chegar de um estado a outro
@abstractmethod
def heuristic(self, state, goal):
pass
# test if the given "goal" is satisfied in "state"
@abstractmethod
def satisfies(self, state, goal):
pass
# Problemas concretos a resolver
# dentro de um determinado dominio
class SearchProblem:
def __init__(self, domain, initial, goal):
self.domain = domain
self.initial = initial
self.goal = goal
def goal_test(self, state):
return self.domain.satisfies(state,self.goal)
# Nos de uma arvore de pesquisa
class SearchNode:
def __init__(self,state,parent):
self.state = state
self.parent = parent
def __str__(self):
return "no(" + str(self.state) + "," + str(self.parent) + ")"
def __repr__(self):
return str(self)
# Arvores de pesquisa
class SearchTree:
# construtor
def __init__(self,problem, strategy='breadth'):
self.problem = problem
root = SearchNode(problem.initial, None)
self.open_nodes = [root]
self.strategy = strategy
self.solution = None
# obter o caminho (sequencia de estados) da raiz ate um no
def get_path(self,node):
if node.parent == None:
return [node.state]
path = self.get_path(node.parent)
path += [node.state]
return(path)
# procurar a solucao
def search(self):
while self.open_nodes != []:
node = self.open_nodes.pop(0)
if self.problem.goal_test(node.state):
self.solution = node
return self.get_path(node)
lnewnodes = []
for a in self.problem.domain.actions(node.state):
newstate = self.problem.domain.result(node.state,a)
newnode = SearchNode(newstate,node)
lnewnodes.append(newnode)
self.add_to_open(lnewnodes)
return None
# juntar novos nos a lista de nos abertos de acordo com a estrategia
def add_to_open(self,lnewnodes):
if self.strategy == 'breadth':
self.open_nodes.extend(lnewnodes)
elif self.strategy == 'depth':
self.open_nodes[:0] = lnewnodes
elif self.strategy == 'uniform':
pass