Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trabalho G1 - IA #11

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/busca/a_star.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
"""Implementação do algoritmo A*."""

from queue import PriorityQueue
from util import heuristic

def a_star(graph, start: int, goal: int) -> (int, float, [int]):
"""Busca em graph, um caminho entre start e goal usando A*."""
frontier = PriorityQueue()
frontier.put(start, 0)
came_from = {}
const_so_far = {}
came_from[start] = None
const_so_far[start] = 0
while not frontier.empty():
vertex = frontier.get()
if vertex == goal:
break
for nbor_vertex in graph[vertex][1]:
nbor_dist = graph[vertex][1][nbor_vertex]
new_cost = const_so_far[vertex] + nbor_dist
if nbor_vertex not in const_so_far or new_cost < const_so_far[nbor_vertex]:
const_so_far[nbor_vertex] = new_cost
priority = new_cost + heuristic(graph[nbor_vertex], graph[goal])
frontier.put(nbor_vertex, priority)
came_from[nbor_vertex] = vertex
predecessor = came_from[vertex]
path = [vertex]
while predecessor != None:
path.append(predecessor)
predecessor = came_from[predecessor]
path.reverse()
return (len(path) + 1, const_so_far[goal], path)
29 changes: 23 additions & 6 deletions src/busca/bfs.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
"""Implementação da busca em profundidade."""

from queue import deque as Queue

from util import reverse_path

"""Implementação da busca em largura."""
from collections import deque

def bfs(graph, start: int, goal: int) -> (int, float, [int]):
"""Busca um caminho entre start e goal usando busca em largura."""
queue = deque([(start, None)])
visited = {}
count_nodes = 0
while queue:
vertex, last_vertex = queue.popleft()
count_nodes += 1
if vertex == goal:
path = [vertex]
total_cost = 0
while last_vertex is not None:
path.append(last_vertex)
total_cost += graph[last_vertex][1][vertex]
vertex = last_vertex
last_vertex = visited.get(vertex)
path.reverse()
return (count_nodes, total_cost, path)
visited[vertex] = last_vertex
for next_node, cost in graph[vertex][1].items():
if next_node not in visited:
queue.append((next_node, vertex))
return (count_nodes, float('inf'), [])
13 changes: 13 additions & 0 deletions src/busca/branch_and_bound.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
"""Implementação do algoritmo 'branch and bound'."""

import heapq

def branch_and_bound(graph, start: int, goal: int) -> (int, float, [int]):
"""Busca um caminho entre start e goal usando Branch and Bound."""
queue = [(0, start, [start])]
dist = {index: float('inf') for index, _ in enumerate(graph)}
while queue:
vertex_dist, vertex, path = heapq.heappop(queue)
if vertex == goal:
return len(path), vertex_dist, path
for nbor_vertex, weight in graph[vertex][1].items():
new_dist = vertex_dist + weight
if new_dist < dist[nbor_vertex]:
dist[nbor_vertex] = new_dist
heapq.heappush(queue, (new_dist, nbor_vertex, path + [nbor_vertex]))
return float('inf'), None, []
25 changes: 22 additions & 3 deletions src/busca/dfs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
"""Implementação da busca em profundidade."""

from util import reverse_path


def dfs(graph, start: int, goal: int) -> (int, float, [int]):
"""Busca um caminho entre start e goal usando busca em profundidade."""
stack = [(start, None)]
visited = {}
front = 0
while True:
vertex, last_vertex = stack[front]
front += 1
if vertex == goal:
break
if vertex not in visited:
visited[vertex] = last_vertex
for neighbor in graph[vertex][1]:
if neighbor not in visited:
stack.append((neighbor, vertex))
path = [vertex]
while last_vertex is not None:
path.append(last_vertex)
totalCost = 0
totalCost += graph[last_vertex][1][vertex]
vertex = last_vertex
last_vertex = visited.get(vertex)
path.reverse()
return (len(path), totalCost, path)
30 changes: 25 additions & 5 deletions src/busca/dijkstra.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
"""Implementação do algoritmo de Dijkstra para o menor caminho em grafos."""

from heapq import heapify, heappush, heappop

from util import reverse_path


def dijkstra(graph, start: int, goal: int) -> (int, float, [int]):
"""Busca em graph, um caminho entre start e goal usando Dijkstra."""
distances = {vertex: float('inf') for vertex in range(len(graph))}
distances[start] = 0
path = []
priority_queue = [(start, 0)]
prev = {}
while priority_queue:
vertex, current_dist = min(priority_queue)
if vertex == goal:
break
priority_queue.remove((vertex, current_dist))
for nbor_vertex in graph[vertex][1]:
nbor_dist = graph[vertex][1][nbor_vertex]
new_dist = current_dist + nbor_dist
if new_dist < distances[nbor_vertex]:
distances[nbor_vertex] = new_dist
prev[nbor_vertex] = vertex
priority_queue.append((nbor_vertex, new_dist))
vertex = goal
while vertex != start:
path.append(vertex)
vertex = prev[vertex]
path.append(start)
path.reverse()

return len(path), distances[goal], path
17 changes: 8 additions & 9 deletions src/graph.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
"""Implementação de uma estrutura de grafo."""

import sys


def read_graph(filename: str):
"""Le uma estrutura de grafo de um arquivo e retorna a estrutura."""
graph = None
graph = []
with open(filename, "rt") as input_file:
vertex_count = int(input_file.readline().strip())
for _ in range(vertex_count):
index, latitude, longitude = input_file.readline().strip().split()

index, latitude, longitude = [ int(index), float(latitude), float(longitude) ]
graph.append([(latitude, longitude),{}])

edge_count = int(input_file.readline().strip())
for _ in range(edge_count):
from_vertex, to_vertex, cost = (
input_file.readline().strip().split()
)
from_vertex, to_vertex, cost = (input_file.readline().strip().split())
from_vertex, to_vertex, cost = [ int(from_vertex), int(to_vertex), float(cost) ]
graph[from_vertex][1][to_vertex] = cost

return graph
12 changes: 7 additions & 5 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""Utilize este arquivo para depurar seus algoritmos."""

from graph import read_graph
from busca import a_star

from busca import dfs, bfs, branch_and_bound, a_star, dijkstra

if __name__ == "__main__":
grafo = read_graph("vertices.txt")
vertices_avaliados, custo, caminho = a_star(grafo, 1, 100)
print(vertices_avaliados, custo, caminho)
graph = read_graph("mapas\mini_map.txt")
print(dfs(graph, 0, 9))
print(bfs(graph, 0, 9))
print(branch_and_bound(graph, 0, 9))
print(a_star(graph, 0, 9))
print(dijkstra(graph, 0, 9))
7 changes: 6 additions & 1 deletion src/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import math


def haversine(lat1, lon1, lat2, lon2):
"""Calcula a distância, em metros, entre duas coordenadas GPS."""
dLat = (lat2 - lat1) * math.pi / 180.0 # pylint: disable=invalid-name
Expand All @@ -24,3 +23,9 @@ def haversine(lat1, lon1, lat2, lon2):
#
# Não altere este comentário e adicione suas funções ao final do arquivo.
#

def heuristic(node, goal_node):
x1, y1 = float(node[0][0]), float(node[0][1])
x2, y2 = float(goal_node[0][0]), float(goal_node[0][1])
val = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
return val # Euclidean distance
Loading