Add Eulerian and Hamiltonian cycle benchmark

This commit is contained in:
2025-06-03 15:38:44 +02:00
parent 899c844c78
commit 15a95c8e73
3 changed files with 174 additions and 8 deletions
+173
View File
@@ -0,0 +1,173 @@
import random
import time
import matplotlib.pyplot as plt
def generateGraph(n: int, saturation: int):
edges = (n * (n - 1)) // 2
maxEdges = edges * saturation // 100
graph = {i: [] for i in range(n)}
edgeCount = 0
# Generate a Hamiltonian cycle
cycle = list(range(n))
random.shuffle(cycle)
for i in range(n):
u = cycle[i]
v = cycle[(i + 1) % n]
graph[u].append(v)
graph[v].append(u)
edgeCount += 1
while edgeCount < maxEdges:
# Find all pairs (u, v) where u < v, u != v, v not in graph[u], and deg(u)%2 == deg(v)%2
candidates = []
for u in range(n):
for v in range(u + 1, n):
if v not in graph[u] and (len(graph[u]) % 2) == (len(graph[v]) % 2):
candidates.append((u, v))
if not candidates:
break # No more valid pairs to add without breaking Eulerian property
u, v = random.choice(candidates)
graph[u].append(v)
graph[v].append(u)
edgeCount += 1
for i in range(n):
random.shuffle(graph[i])
print(f"Generated graph with {n} nodes and {edgeCount} edges (saturation: {saturation}%, max edges: {maxEdges})")
# # Print the graph as a matrix for debugging
# graph_matrix = [[0] * n for _ in range(n)]
# for u in range(n):
# for v in graph[u]:
# graph_matrix[u][v] = 1
# print("Graph adjacency matrix:")
# for row in graph_matrix:
# print(" ".join(map(str, row)))
return graph
def findEulerianCycle(graph_adj_sets):
current_graph = {v: set(neighbors) for v, neighbors in graph_adj_sets.items()}
if not current_graph:
return None # No nodes, empty path
path = []
start_vertex = -1
for v_check, neigh_check in current_graph.items():
if neigh_check:
start_vertex = v_check
break
if start_vertex == -1:
if len(current_graph) == 1:
return [next(iter(current_graph))] # Single node graph
return None
stack = [start_vertex]
while stack:
v = stack[-1]
if current_graph.get(v):
u = current_graph[v].pop()
current_graph[u].remove(v)
stack.append(u) # Move to the next vertex
else:
path.append(stack.pop()) # Backtrack and add to the path
return path[::-1] # Return the path in reverse order
def findHamiltonianCycle(graph):
n = len(graph)
path = []
def backtrack(v, visited):
if len(path) == n:
return path[0] in graph[v] # Check if the last node connects to the first
for neighbor in graph[v]:
if neighbor not in visited:
visited.add(neighbor)
path.append(neighbor)
if backtrack(neighbor, visited):
return True
visited.remove(neighbor)
path.pop()
return False
for start in range(n):
path.append(start)
visited = {start}
if backtrack(start, visited):
return path
path.pop()
return None
if __name__ == "__main__":
n_values = range(10, 26) # Number of nodes to test
saturations = [30, 70] # Saturation levels to test
results = {}
for saturation in saturations:
hamilton_times = []
eulerian_times = []
for n in n_values:
print(f"Running tests for {n} nodes with {saturation}% saturation...")
graph = generateGraph(n, saturation)
eulerian_time = 0
hamilton_time = 0
for _ in range(10):
start_time = time.time()
if findHamiltonianCycle(graph) is None:
raise ValueError("Hamiltonian cycle not found, which should not happen with the generated graph.")
end_time = time.time()
measured_time = (end_time - start_time) * 1000
hamilton_time += measured_time
eulerian_graph_repr = {v_node: set(v_neighbors) for v_node, v_neighbors in graph.items()}
start_time = time.time()
graph_for_eulerian_run = {node: set(adj_nodes) for node, adj_nodes in graph.items()}
start_time = time.time()
if findEulerianCycle(graph_for_eulerian_run) is None: # Pass the new set-based representation
raise ValueError("Eulerian cycle not found...")
end_time = time.time()
eulerian_time += (end_time - start_time) * 1000
# Average the times over 10 runs
hamilton_times.append(hamilton_time / 10)
eulerian_times.append(eulerian_time / 10)
time.sleep(0.1) # Sleep to avoid overwhelming the system
results[saturation] = {
"hamilton_times": hamilton_times,
"eulerian_times": eulerian_times,
}
plt.figure(figsize=(10, 6))
plt.plot(n_values, hamilton_times, label="Cykl Hamiltona", marker="o")
plt.plot(n_values, eulerian_times, label="Cykl Eulera", marker="s")
plt.xlabel("Liczba wierzchołków (n)")
plt.ylabel("Czas działania (ms)")
plt.title(f"Czas działania algorytmów dla {saturation}% nasycenia")
plt.legend()
plt.grid(True)
if(saturation == 30):
plt.yscale('log', base=2)
filename = f"saturation_{saturation}.png"
plt.savefig(filename)
print(f"Plot saved as '{filename}'")
print("All tests completed.")