1)
a) Agente por objetivos
b) Características del entorno REAS:
Rendimiento: El rendimiento se mide por la capacidad del agente para encontrar la
salida del laberinto en el menor tiempo posible.
Entorno: El entorno del agente es un laberinto, compuesto por pasillos y paredes, con
una única salida.
Actuadores: Los actuadores del agente son las acciones que puede realizar para
moverse en el laberinto, como avanzar hacia adelante, girar a la izquierda o a la
derecha.
Sensores: Los sensores del agente son los que le proporcionan información sobre su
entorno actual, como la presencia de paredes en las direcciones adyacentes.
c) Propiedades del entorno del agente:
Estático: El laberinto no cambia mientras el agente está buscando la salida.
Discreto: El laberinto está compuesto por celdas discretas, donde el agente puede
estar ubicado.
Determinista: Las acciones del agente y sus consecuencias son conocidas y
predecibles.
Episódico: La experiencia del agente se divide en episodios individuales, donde cada
uno comienza en una ubicación aleatoria dentro del laberinto.
d) Formulación del problema:
Estado inicial: La ubicación inicial del agente en el laberinto.
Test objetivo:
Función sucesora: Para cada estado del agente (ubicación y dirección),
determina los posibles estados alcanzables mediante las acciones disponibles
(avanzar, girar a la izquierda, girar a la derecha).
Función costo: Puede ser uniforme, asignando un costo unitario a cada paso
que el agente da.
e) Pasos para solucionar el problema:
Inicializar el agente en una ubicación aleatoria dentro del laberinto.
Mientras el agente no haya alcanzado el objetivo (la salida del laberinto):
a. Percibir el entorno actual.
b. Planificar la próxima acción basada en el objetivo de alcanzar la salida.
c. Ejecutar la acción.
Repetir el paso 2 hasta que el agente alcance la salida del laberinto.2)
a) agente basado en objetivos
b) Las características del entorno (REAS):
Rendimiento: Las ciudades que el agente debe visitar.
Entorno: Un espacio donde las ciudades están conectadas por caminos o
distancias definidas entre ellas.
Actuadores: El agente puede realizar acciones para moverse de una ciudad a
otra siguiendo las conexiones existentes en el espacio de búsqueda.
Sensores: El agente debe ser capaz de percibir la distancia entre las ciudades
y posiblemente la estructura del espacio de búsqueda para determinar qué
acciones tomar.
c) Propiedades del entorno del agente:
Determinista: Las acciones del agente y sus consecuencias son conocidas y
predecibles.
Competitivo: No hay otros agentes que compitan activamente por los mismos
recursos o metas.
Observable: El agente puede observar el estado actual, es decir, la distancia
entre las ciudades y posiblemente la estructura del espacio de búsqueda.
Secuencial: Las acciones del agente afectan el estado del entorno de manera
secuencial.
d) Formulación del problema:
Estado inicial: Una ciudad de partida.
Test objetivo: Todas las ciudades han sido visitadas exactamente una vez y el
agente ha vuelto a la ciudad de partida.
Función sucesora: Dada una ciudad actual, la función sucesora genera todas
las ciudades que aún no han sido visitadas y calcula la distancia entre la ciudad
actual y cada una de estas ciudades.
Función de costo: La función de costo asigna un valor numérico a cada
acción (es decir, moverse de una ciudad a otra) que representa la distancia
entre las dos ciudades.
e) Pasos para solucionar el problema:
1. Inicialización: Selecciona una ciudad de partida.
2. Generación de sucesores: Genera todas las posibles rutas que el agente
puede tomar desde la ciudad actual.
3. Evaluación de rutas: Calcula el costo de cada ruta (es decir, la distancia total
recorrida).
4. Selección de la mejor ruta: Selecciona la ruta con el costo más bajo.
5. Actualización del estado: Marca las ciudades visitadas y avanza al siguiente
estado.
6. Repetición: Repite los pasos 2-5 hasta que se haya completado la ruta óptima.
3)
a) Agente basado en modelos
b) Las características del entorno (REAS):
Rendimiento: El entorno está compuesto por el cruce de tráfico vehicular.
Entorno: El cruce puede contener múltiples carriles, semáforos, señales de
tráfico, peatones, y otros vehículos.
Actuadores: Los actuadores que el agente puede realizar incluyen cambiar la
duración de los semáforos, alterar la velocidad de los vehículos, dirigir el flujo
de tráfico, etc.
Sensores: La percepción del agente incluye la observación del tráfico actual, la
velocidad y la dirección de los vehículos, la duración de los semáforos, la
presencia de peatones, etc.
c) Propiedades del entorno del agente:
Dinámico: El entorno del agente cambia continuamente a medida que los
vehículos entran y salen del cruce, los semáforos cambian de estado, etc.
Estocástico: El comportamiento de los vehículos y otros factores en el entorno
pueden ser aleatorios.
Continuo: El estado del entorno puede cambiar en intervalos de tiempo muy
pequeños, y las acciones del agente pueden tener efectos a largo plazo.
d) Formulación del problema:
Estado inicial: El estado inicial del problema es el cruce de tráfico en un
momento específico, con ciertas condiciones de tráfico y configuraciones de
semáforos.
Test objetivo: El objetivo del agente es optimizar la eficiencia del cruce,
minimizando el tiempo de espera de los vehículos y maximizando el flujo de
tráfico.
Función sucesora: La función sucesora genera nuevos estados del cruce al
aplicar acciones como cambiar la duración de los semáforos, ajustar la
velocidad de los vehículos, etc.
Función de costo: La función de costo puede ser definida como el tiempo
promedio de espera de los vehículos en el cruce.
e) Pasos para solucionar el problema:
1. Percepción del entorno: El agente debe observar el tráfico actual, la duración
de los semáforos y otras condiciones relevantes.
2. Construcción de modelos internos: El agente construye modelos internos
del flujo de tráfico y predice cómo cambiará el entorno en respuesta a
diferentes acciones.
3. Toma de decisiones: El agente elige la mejor acción para optimizar la
eficiencia del cruce, basándose en sus modelos internos y objetivos.
4. Ejecución de acciones: El agente implementa las acciones elegidas, como
cambiar la duración de los semáforos o ajustar la velocidad de los vehículos.
5. Evaluación de resultados: El agente evalúa los resultados de sus acciones
en términos de la eficiencia del cruce y ajusta su estrategia si es necesario.
6. Iteración: El agente continúa observando, modelando, tomando decisiones y
actuando en un ciclo iterativo para optimizar continuamente el cruce de tráfico.
4.Implemente en Python los algoritmos de:
a) Búsqueda de costo uniforme (Dijkstra)
# Programa en Python para el algoritmo de la ruta más corta de
Dijkstra.
class Grafo():
def __init__(self, vertices):
self.V = vertices
self.grafo = [[0 for columna in range(vertices)]
for fila in range(vertices)]
def imprimirSolucion(self, dist):
print("Vértice \t Distancia desde el Origen")
for nodo in range(self.V):
print(nodo, "\t\t", dist[nodo])
def distanciaMinima(self, dist, conjunto_caminos_mas_cortos):
minimo = 1e7
for v in range(self.V):
if dist[v] < minimo and conjunto_caminos_mas_cortos[v] ==
False:
minimo = dist[v]
indice_minimo = v
return indice_minimo
def dijkstra(self, origen):
dist = [1e7] * self.V
dist[origen] = 0
conjunto_caminos_mas_cortos = [False] * self.V
for contador in range(self.V):
u = self.distanciaMinima(dist, conjunto_caminos_mas_cortos)
conjunto_caminos_mas_cortos[u] = True
for v in range(self.V):
if (self.grafo[u][v] > 0 and
conjunto_caminos_mas_cortos[v] == False and
dist[v] > dist[u] + self.grafo[u][v]):
dist[v] = dist[u] + self.grafo[u][v]
self.imprimirSolucion(dist)
g = Grafo(9)
g.grafo = [[0, 4, 0, 0, 0, 0, 0, 8, 0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0]]
g.dijkstra(0)
b) Búsqueda primero en amplitud
graph = {
'5' : ['3','7'],
'3' : ['2', '4'],
'7' : ['8'],
'2' : [],
'4' : ['8'],
'8' : []
}
visited = []
queue = []
def bfs(visited, graph, node):
visited.append(node)
queue.append(node)
while queue:
m = queue.pop(0)
print (m, end = " ")
for neighbour in graph[m]:
if neighbour not in visited:
visited.append(neighbour)
queue.append(neighbour)
print("Following is the Breadth-First Search")
bfs(visited, graph, '5')
c) Búsqueda primero en profundidad
graph = {
'5' : ['3','7'],
'3' : ['2', '4'],
'7' : ['8'],
'2' : [],
'4' : ['8'],
'8' : []
}
visited = set()
def dfs(visited, graph, node):
if node not in visited:
print (node)
visited.add(node)
for neighbour in graph[node]:
dfs(visited, graph, neighbour)
print("Following is the Depth-First Search")
dfs(visited, graph, '5')
5.
6. Implemente en Python el algoritmo de búsqueda informada o heurística A*.
import math
import heapq
# Define la clase Nodo
class Nodo:
def __init__(self):
self.parent_i = 0 # Índice de fila del nodo padre
self.parent_j = 0 # Índice de columna del nodo padre
self.f = float('inf') # Costo total del nodo (g + h)
self.g = float('inf') # Costo desde el inicio hasta este nodo
self.h = 0 # Costo heurístico desde este nodo hasta el destino
# Define el tamaño de la matriz
FILA = 9
COL = 10
# Comprueba si un nodo es válido (dentro de la matriz)
def es_valido(fila, col):
return (fila >= 0) and (fila < FILA) and (col >= 0) and (col < COL)
# Comprueba si un nodo no está bloqueado
def no_bloqueado(matriz, fila, col):
return matriz[fila][col] == 1
# Comprueba si un nodo es el destino
def es_destino(fila, col, destino):
return fila == destino[0] and col == destino[1]
# Calcula el valor heurístico de un nodo (distancia euclidiana al destino)
def calcular_heuristica(fila, col, destino):
return ((fila - destino[0]) ** 2 + (col - destino[1]) ** 2) ** 0.5
# Rastrea el camino desde el origen hasta el destino
def rastrear_ruta(detalle_nodo, destino):
print("La ruta es ")
ruta = []
fila = destino[0]
col = destino[1]
# Rastrea la ruta desde el destino hasta el origen usando los nodos padres
while not (detalle_nodo[fila][col].parent_i == fila and detalle_nodo[fila][col].parent_j
== col):
ruta.append((fila, col))
fila_temp = detalle_nodo[fila][col].parent_i
col_temp = detalle_nodo[fila][col].parent_j
fila = fila_temp
col = col_temp
# Agrega el nodo de origen a la ruta
ruta.append((fila, col))
# Invierte la ruta para obtener la ruta desde el origen hasta el destino
ruta.reverse()
# Imprime la ruta
for i in ruta:
print("->", i, end=" ")
print()
# Implementa el algoritmo de búsqueda A*
def busqueda_a_estrella(matriz, origen, destino):
# Comprueba si el origen y el destino son válidos
if not es_valido(origen[0], origen[1]) or not es_valido(destino[0], destino[1]):
print("El origen o el destino no son válidos")
return
# Comprueba si el origen y el destino no están bloqueados
if not no_bloqueado(matriz, origen[0], origen[1]) or not no_bloqueado(matriz,
destino[0], destino[1]):
print("El origen o el destino está bloqueado")
return
# Comprueba si ya estamos en el destino
if es_destino(origen[0], origen[1], destino):
print("Ya estamos en el destino")
return
# Inicializa la lista cerrada (nodos visitados)
lista_cerrada = [[False for _ in range(COL)] for _ in range(FILA)]
# Inicializa los detalles de cada nodo
detalle_nodo = [[Nodo() for _ in range(COL)] for _ in range(FILA)]
# Inicializa los detalles del nodo de inicio
i = origen[0]
j = origen[1]
detalle_nodo[i][j].f = 0
detalle_nodo[i][j].g = 0
detalle_nodo[i][j].h = 0
detalle_nodo[i][j].parent_i = i
detalle_nodo[i][j].parent_j = j
# Inicializa la lista abierta (nodos a visitar) con el nodo de inicio
lista_abierta = []
heapq.heappush(lista_abierta, (0.0, i, j))
# Inicializa el indicador para saber si se encontró el destino
destino_encontrado = False
# Bucle principal del algoritmo de búsqueda A*
while len(lista_abierta) > 0:
# Extrae el nodo con el valor f más pequeño de la lista abierta
p = heapq.heappop(lista_abierta)
# Marca el nodo como visitado
i = p[1]
j = p[2]
lista_cerrada[i][j] = True
# Para cada dirección, comprueba los sucesores
direcciones = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
for dir in direcciones:
nueva_i = i + dir[0]
nueva_j = j + dir[1]
# Si el sucesor es válido, no está bloqueado y no está visitado
if es_valido(nueva_i, nueva_j) and no_bloqueado(matriz, nueva_i, nueva_j) and
not lista_cerrada[nueva_i][nueva_j]:
# Si el sucesor es el destino
if es_destino(nueva_i, nueva_j, destino):
# Establece el padre del nodo de destino
detalle_nodo[nueva_i][nueva_j].parent_i = i
detalle_nodo[nueva_i][nueva_j].parent_j = j
print("Se encontró el nodo de destino")
# Rastrea e imprime la ruta desde el origen hasta el destino
rastrear_ruta(detalle_nodo, destino)
destino_encontrado = True
return
else:
# Calcula los nuevos valores f, g y h
g_nuevo = detalle_nodo[i][j].g + 1.0
h_nuevo = calcular_heuristica(nueva_i, nueva_j, destino)
f_nuevo = g_nuevo + h_nuevo
# Si el nodo no está en la lista abierta o el nuevo valor f es menor
if detalle_nodo[nueva_i][nueva_j].f == float('inf') or detalle_nodo[nueva_i]
[nueva_j].f > f_nuevo:
# Agrega el nodo a la lista abierta
heapq.heappush(lista_abierta, (f_nuevo, nueva_i, nueva_j))
# Actualiza los detalles del nodo
detalle_nodo[nueva_i][nueva_j].f = f_nuevo
detalle_nodo[nueva_i][nueva_j].g = g_nuevo
detalle_nodo[nueva_i][nueva_j].h = h_nuevo
detalle_nodo[nueva_i][nueva_j].parent_i = i
detalle_nodo[nueva_i][nueva_j].parent_j = j
# Si el destino no se encuentra después de visitar todos los nodos
if not destino_encontrado:
print("No se encontró el nodo de destino")
def main():
# Define la matriz (1 para desbloqueado, 0 para bloqueado)
matriz = [
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
[1, 1, 1, 0, 1, 1, 1, 0, 1, 1],
[1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 1, 0, 0, 0, 0, 1],
[1, 1, 1, 0, 1, 1, 1, 0, 1, 0],
[1, 0, 1, 1, 1, 1, 0, 1, 0, 0],
[1, 0, 0, 0, 0, 1, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 0, 0, 1]
]
# Define el origen y el destino
origen = [8, 0]
destino = [0, 0]
# Ejecuta el algoritmo de búsqueda A*
busqueda_a_estrella(matriz, origen, destino)
if __name__ == "__main__":
main()
7) Aplicar el programa de A* al problema de la ruta más corta, donde los nodos
son los departamentos de Bolivia.
import heapq
# Representación del grafo de los departamentos de Bolivia
grafo = {
'Beni': {'La Paz', 'Cochabamba', 'Pando'},
'Chuquisaca': {'La Paz', 'Potosí', 'Santa Cruz'},
'Cochabamba': {'La Paz', 'Oruro', 'Santa Cruz'},
'La Paz': {'Beni', 'Cochabamba', 'Oruro', 'Potosí', 'Chuquisaca'},
'Oruro': {'La Paz', 'Cochabamba', 'Potosí'},
'Pando': {'Beni'},
'Potosí': {'La Paz', 'Oruro', 'Chuquisaca'},
'Santa Cruz': {'Chuquisaca', 'Cochabamba', 'Tarija'},
'Tarija': {'Santa Cruz'}
}
# Coordenadas de los departamentos para la heurística de distancia de Manhattan
coordenadas = {
'Beni': (1, 1),
'Chuquisaca': (2, 2),
'Cochabamba': (3, 1),
'La Paz': (1, 3),
'Oruro': (2, 1),
'Pando': (1, 0),
'Potosí': (2, 0),
'Santa Cruz': (3, 2),
'Tarija': (4, 2)
}
# Distancias entre los departamentos (puede ignorarse en esta versión)
distancias = {
('Beni', 'La Paz'): 900,
('Beni', 'Cochabamba'): 800,
('Beni', 'Pando'): 200,
('Chuquisaca', 'La Paz'): 600,
('Chuquisaca', 'Potosí'): 850,
('Chuquisaca', 'Santa Cruz'): 750,
('Cochabamba', 'La Paz'): 300,
('Cochabamba', 'Oruro'): 350,
('Cochabamba', 'Santa Cruz'): 500,
('La Paz', 'Oruro'): 250,
('La Paz', 'Potosí'): 500,
('Oruro', 'Potosí'): 300,
('Santa Cruz', 'Tarija'): 300
}
def heuristic(a, b):
# Heurística: distancia de Manhattan entre los nodos
coord_a = coordenadas[a]
coord_b = coordenadas[b]
return abs(coord_a[0] - coord_b[0]) + abs(coord_a[1] - coord_b[1])
def a_star(start, goal):
frontier = []
heapq.heappush(frontier, (0, start))
came_from = {}
cost_so_far = {}
came_from[start] = None
cost_so_far[start] = 0
while frontier:
current_cost, current_node = heapq.heappop(frontier)
if current_node == goal:
break
for next_node in grafo[current_node]:
new_cost = cost_so_far[current_node] + distancias.get((current_node, next_node),
0)
if next_node not in cost_so_far or new_cost < cost_so_far[next_node]:
cost_so_far[next_node] = new_cost
priority = new_cost + heuristic(next_node, goal)
heapq.heappush(frontier, (priority, next_node))
came_from[next_node] = current_node
# Reconstruir el camino desde el inicio hasta el objetivo
path = []
current_node = goal
while current_node != start:
path.append(current_node)
current_node = came_from[current_node]
path.append(start)
path.reverse()
return path
def obtener_departamentos():
start = input("Ingrese el departamento de inicio: ")
goal = input("Ingrese el departamento de destino: ")
return start, goal
if _name_ == "_main_":
start, goal = obtener_departamentos()
shortest_path = a_star(start, goal)
print("La ruta más corta desde {} hasta {} es:".format(start, goal))
print(shortest_path)