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

Programación paralela 2024A #22

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
99 changes: 99 additions & 0 deletions ALGORITMOS BFS Y DFS/BFS_DFS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""Programa en python para algotimos de
de busqueda por amplitud (bfs) y por
profundidad (dfs)"""

from collections import defaultdict
import time

"""Esta clase reprenta un grafo dirigido
que hace uso de la representación de listas
de adyacencia"""

class Graph:
def __init__(self):
# Utilizamos defaultdict para crear una lista de adyacencia
self.graph = defaultdict(list)

def add_edge(self, u, v):
# Función para agregar una arista al grafo
self.graph[u].append(v)

def bfs(self, s):
# Función para recorrido BFS (Breadth First Search)
visited = [False] * (len(self.graph)) # Marcamos todos los vértices como no visitados
queue = [] # Inicializamos una cola para el BFS

visited[s] = True # Marcamos el vértice inicial como visitado
queue.append(s) # Añadimos el vértice inicial a la cola

start_time = time.time() # Medimos el tiempo de inicio del algoritmo

while queue: # Mientras la cola no esté vacía
s = queue.pop(0) # Obtenemos el primer elemento de la cola
print(s, end=" ") # Imprimimos el vértice actual

# Recorremos todos los vértices adyacentes al vértice actual
for i in self.graph[s]:
if not visited[i]: # Si el vértice adyacente no ha sido visitado
visited[i] = True # Marcamos el vértice como visitado
queue.append(i) # Añadimos el vértice a la cola

end_time = time.time() # Medimos el tiempo de finalización del algoritmo
print("\nTiempo de ejecución de BFS: {:.10} segundos".format(end_time - start_time))

def dfs_util(self, v, visited):
# Función de utilidad para el recorrido DFS (Depth First Search)
visited[v] = True # Marcamos el vértice actual como visitado
print(v, end=" ") # Imprimimos el vértice actual

# Recorremos todos los vértices adyacentes al vértice actual
for i in self.graph[v]:
if not visited[i]: # Si el vértice adyacente no ha sido visitado
self.dfs_util(i, visited) # Llamamos recursivamente a la función DFS_util

def dfs(self):
# Función para recorrido DFS
visited = [False] * (len(self.graph)) # Marcamos todos los vértices como no visitados
start_time = time.time() # Medimos el tiempo de inicio del algoritmo
for i in range(len(self.graph)):
if not visited[i]: # Si el vértice no ha sido visitado
self.dfs_util(i, visited) # Llamamos a la función de utilidad DFS_util
end_time = time.time() # Medimos el tiempo de finalización del algoritmo
print("\nTiempo de ejecución de DFS: {:.10f} segundos".format(end_time - start_time))

# Grafo utilizado para BFS
g_bfs = Graph()
g_bfs.add_edge(0, 1)
g_bfs.add_edge(0, 2)
g_bfs.add_edge(1, 2)
g_bfs.add_edge(2, 0)
g_bfs.add_edge(2, 3)
g_bfs.add_edge(3, 5)
g_bfs.add_edge(3, 3)
g_bfs.add_edge(3, 4)
g_bfs.add_edge(4, 2)
g_bfs.add_edge(4, 4)
g_bfs.add_edge(4, 5)
g_bfs.add_edge(5, 1)
g_bfs.add_edge(5, 5)
print("Recorrido de la búsqueda por anchura:")
g_bfs.bfs(5) # Realizamos el recorrido BFS empezando desde el vértice 5
print("\n")

# Grafo para DFS
g_dfs = Graph()
g_dfs.add_edge(0, 1)
g_dfs.add_edge(0, 2)
g_dfs.add_edge(1, 1)
g_dfs.add_edge(1, 2)
g_dfs.add_edge(2, 2)
g_dfs.add_edge(2, 3)
g_dfs.add_edge(3, 3)
g_dfs.add_edge(3, 4)
g_dfs.add_edge(4, 3)
g_dfs.add_edge(4, 4)
g_dfs.add_edge(4, 5)
g_dfs.add_edge(5, 4)
g_dfs.add_edge(5, 5)
print("El recorrido a profundidad es el siguiente:")
g_dfs.dfs() # Realizamos el recorrido DFS
49 changes: 49 additions & 0 deletions Estructura.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Este módulo es un ejemplo que sigue las pautas de PEP 8.
"""

import os
import sys



class MyClass:
"""
Clase de ejemplo que sigue las convenciones de nombres CamelCase.
"""

def __init__(self, name):
"""
Inicializador de la clase.
"""
self.name = name

def get_name(self):
"""
Método que devuelve el nombre de la instancia.
"""
pass


def add_numbers(a, b):
"""
Función de ejemplo que suma dos números.

:param a: Primer número
:param b: Segundo número
:return: Suma de a y b
"""
return a + b


def main():
"""
Función principal de ejecución.

Esta función muestra cómo estructurar un programa principal.
"""
pass


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions Hello.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world of git :)
75 changes: 75 additions & 0 deletions PROYECTO_PARALELA24A/BFSParalelo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from mpi4py import MPI
import time
import os

# Inicialización de MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

# Función BFS
def BFS(graph, frontier_nodes, bfs_tree, end_node):
start_time = time.time()
# Terminar cuando no haya más nodos en la frontera o se encuentre el nodo final
if len(frontier_nodes) == 0 or any(node == end_node for node in frontier_nodes):
end_time = time.time() #Tiempo de finalización
execution_time = end_time - start_time #Calcular el tiempo de ejecución
print(f"Rango: {rank}. Tiempo de ejecucion: {execution_time} segundos.")
return bfs_tree
else:
# Obtener todos los vecinos de la frontera actual
neighbors = graph[list(frontier_nodes)[0]]

# Etiquetar los vecinos con el nodo del que provienen y aplanar
next_nodes = {(ne, n): ne for n in frontier_nodes for ne in graph[n]}

# Eliminar los vecinos que ya han sido explorados
next_nodes = {ne for ne in next_nodes if bfs_tree.get(ne, -1) == -1}

# Escribir en bfs_tree los punteros hacia atrás
for ne, n in next_nodes:
bfs_tree[ne] = n

# Eliminar duplicados comprobando si ya se ha escrito
next_nodes = {ne for ne, n in next_nodes if n not in bfs_tree or bfs_tree[n] != ne}

# Recursión
return BFS(graph, next_nodes, bfs_tree, end_node)
# Función para obtener el camino de un nodo a su raíz en el árbol
def TREE_PATH(node, bfs_tree):
if bfs_tree[node] == node:
return [node]
else:
return [node] + TREE_PATH(bfs_tree[node], bfs_tree)

if rank == 0:
# Grafo de ejemplo
graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'F'],
'D': ['B'],
'E': ['B', 'F'],
'F': ['C', 'E']
}

# Nodo inicial y nodo final
start_node = 'A'
end_node = 'F'

# Inicializar bfs_tree con el nodo inicial apuntando a sí mismo
bfs_tree = {start_node: start_node}

start_time = time.time()
# Ejecutar BFS en el nodo raíz (nodo inicial)
bfs_tree = BFS(graph, {start_node}, bfs_tree, end_node)
end_time = time.time()
execution_time = end_time - start_time
print(f"Rango:{rank}. Tiempo de ejecucion: {execution_time} segundos.")
# Imprimir el árbol BFS resultante
print("BFS Tree:", bfs_tree)

# Sincronizar todos los procesos antes de finalizar
comm.Barrier()

print(f"Rango actual: {rank} de total de procesos: {size}")
71 changes: 71 additions & 0 deletions PROYECTO_PARALELA24A/BFSParaleloExplicación.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""
Pseudocódigo:
INICIO
CREAR COLA Q
CREAR GRAFO
PARA CADA NODO EN GRAFO:
VISITADO [NODO] = FALSE
INICIA RECORRIDO
MIENTRAS:
VISITADO[NODO] = TRUE
HAZ:
Q.INSERTAR(VALOR_NODO)
MIENTRAS !Q.EMPTY():
NODO_ACTUAL = EXTRAER VALOR
PROCESAR(NODO_ACTUAL)
PROCESO EN PARALELO:
PARA CADA HILO:
SI !Q.EMPTY():
NODO_ACTUAL = Q.EXTRAER()
PROCESAR(NODO_ACTUAL):
PARA CDA NODO_ADYACENTE AL NODO_ACTUAL:
SI VISITADO [NODO_ADYACENTE] = FALSE:
PROCESO EN PARALELO:
VISITADO [NODO_ADYACENTE] = TRUE
Q.INSERTAR(NODO_ADYACENTE)
"""

"""
EL PROCESO EN PARALELO SE UTILIZA PARA ASEGURAR QUE LOS HILOS MODIFIQUEN
LA ESTRUCTURA DE LOS DATOS COMPARTIDOS (ACCIONES DE RECORRIDO, VALIDACIÓN E INSERCIÓN)
PARA EVITAR LAS CONDICIONES DE CARRERA Y GARANTIZAR QUE LA ACTUALIZACIÓN DE LOS DATO SE
HAGA DE MANERA CORRECTA.

"""

"""
Comando para ejecutar determiando número de procesos
mpiexec -n ? python C:\Users\AldoG\Documents\GitHub\CuTonala_2024_A\BFSParalelo.py
"""

USOS DE ESTE ALGORITMO EN LA ACTULIDAD:
Tecnología y redes sociales: En plataformas como Facebook,
LinkedIn o Twitter, BFS se utiliza para recomendar amigos o
conexiones basadas en la red de contactos existente.
También se emplea en la propagación de información o contenido viral.

Transporte y logística: En la planificación de rutas de transporte,
BFS puede utilizarse para encontrar la ruta más corta entre dos ubicaciones,
minimizando el tiempo y los costos de transporte.

Telecomunicaciones: En la optimización de redes de comunicación,
BFS se aplica para encontrar la ruta más eficiente para
transmitir datos entre nodos, minimizando la latencia y
maximizando el ancho de banda disponible.

Finanzas: En el análisis de riesgos y la gestión de carteras,
BFS puede ayudar a identificar las conexiones entre diferentes
activos financieros y evaluar el impacto potencial de un evento en toda la red.

Manufactura: En la cadena de suministro y gestión de inventario,
BFS puede utilizarse para optimizar el flujo de materiales y
minimizar los tiempos de espera en la producción.

Salud: En bioinformática y genómica, BFS se utiliza para
analizar redes de interacción de proteínas o genes,
ayudando a identificar relaciones funcionales y biomarcadores relevantes
para enfermedades específicas.

Seguridad cibernética: En la detección de amenazas y el análisis de
vulnerabilidades, BFS puede utilizarse para modelar y
analizar la propagación de malware o la propagación de ataques en una red informática.
Loading