Compare commits

...

2 Commits

Author SHA1 Message Date
Tiago Garcia 2d498eb231
test_aula5 finished
Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
2024-10-13 19:49:14 +01:00
Tiago Garcia bb7c5a1acb
test_aula4 finished
Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
2024-10-13 19:26:19 +01:00
2 changed files with 161 additions and 125 deletions

View File

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

View File

@ -62,12 +62,16 @@ class SearchProblem:
# Nos de uma arvore de pesquisa # Nos de uma arvore de pesquisa
class SearchNode: class SearchNode:
def __init__(self,state,parent, depth): def __init__(self,state,parent, depth, cost=0, heuristic=0):
self.state = state self.state = state
self.parent = parent self.parent = parent
self.depth = depth self.depth = depth
self.cost = cost
self.heuristic = heuristic
def __str__(self): def __str__(self):
return "no(" + str(self.state) + "," + str(self.parent) + ")" return "no(" + str(self.state) + "," + str(self.parent) + ")"
def __repr__(self): def __repr__(self):
return str(self) return str(self)
@ -83,6 +87,8 @@ class SearchTree:
self.solution = None self.solution = None
self.terminals = 0 self.terminals = 0
self.non_terminals = 0 self.non_terminals = 0
self.highest_cost_nodes = [root]
self.average_depth = 0
@property @property
def length(self): def length(self):
@ -92,6 +98,10 @@ class SearchTree:
def avg_branching(self): def avg_branching(self):
return ((self.terminals + self.non_terminals) - 1) / self.non_terminals if self.non_terminals > 0 else None return ((self.terminals + self.non_terminals) - 1) / self.non_terminals if self.non_terminals > 0 else None
@property
def cost(self):
return self.solution.cost if self.solution else None
# obter o caminho (sequencia de estados) da raiz ate um no # obter o caminho (sequencia de estados) da raiz ate um no
def get_path(self,node): def get_path(self,node):
if node.parent == None: if node.parent == None:
@ -105,8 +115,10 @@ class SearchTree:
while self.open_nodes != []: while self.open_nodes != []:
self.terminals = len(self.open_nodes) self.terminals = len(self.open_nodes)
node = self.open_nodes.pop(0) node = self.open_nodes.pop(0)
if self.problem.goal_test(node.state): if self.problem.goal_test(node.state):
self.solution = node self.solution = node
self.average_depth = self.average_depth / (self.terminals + self.non_terminals)
return self.get_path(node) return self.get_path(node)
self.non_terminals += 1 self.non_terminals += 1
@ -114,13 +126,22 @@ class SearchTree:
for a in self.problem.domain.actions(node.state): for a in self.problem.domain.actions(node.state):
newstate = self.problem.domain.result(node.state,a) newstate = self.problem.domain.result(node.state,a)
if newstate not in self.get_path(node): if newstate not in self.get_path(node):
newnode = SearchNode(newstate,node,node.depth+1) newnode = SearchNode(
if limit != None and self.strategy == 'depth': newstate,
if newnode.depth <= limit: node,
lnewnodes.append(newnode) node.depth+1,
else: node.cost+self.problem.domain.cost(node.state,a),
self.problem.domain.heuristic(newstate,self.problem.goal)
)
if not (limit != None and self.strategy == 'depth' and newnode.depth > limit):
lnewnodes.append(newnode) lnewnodes.append(newnode)
if newnode.cost > self.highest_cost_nodes[0].cost:
self.highest_cost_nodes = [newnode]
elif newnode.cost == self.highest_cost_nodes[0].cost:
self.highest_cost_nodes.append(newnode)
self.average_depth += newnode.depth
self.add_to_open(lnewnodes) self.add_to_open(lnewnodes)
return None return None
# juntar novos nos a lista de nos abertos de acordo com a estrategia # juntar novos nos a lista de nos abertos de acordo com a estrategia
@ -130,5 +151,9 @@ class SearchTree:
elif self.strategy == 'depth': elif self.strategy == 'depth':
self.open_nodes[:0] = lnewnodes self.open_nodes[:0] = lnewnodes
elif self.strategy == 'uniform': elif self.strategy == 'uniform':
pass self.open_nodes = sorted(self.open_nodes + lnewnodes, key=lambda node: node.cost)
elif self.strategy == 'greedy':
self.open_nodes = sorted(self.open_nodes + lnewnodes, key=lambda node: node.heuristic)
elif self.strategy == 'a*':
self.open_nodes = sorted(self.open_nodes + lnewnodes, key=lambda node: node.cost + node.heuristic)