Initial commit
This commit is contained in:
commit
9e833eaf57
|
@ -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/
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
from constraintsearch import *
|
||||
|
||||
amigos = ["Andre", "Bernardo", "Claudio"]
|
||||
|
||||
cs = ConstraintSearch(None, None)
|
||||
|
||||
print(cs.search())
|
|
@ -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')
|
||||
"""
|
||||
|
||||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -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())
|
|
@ -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())
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
mock
|
||||
pytest
|
|
@ -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]))
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import os
|
||||
import sys
|
||||
PROJECT_PATH = os.getcwd()
|
||||
SOURCE_PATH = os.path.join(
|
||||
PROJECT_PATH,"."
|
||||
)
|
||||
sys.path.append(SOURCE_PATH)
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)]"
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue