Add Eulerian and Hamiltonian cycle benchmark
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
benchmark
|
benchmark
|
||||||
*.csv
|
*.csv
|
||||||
charts/
|
charts/
|
||||||
|
direnv/
|
||||||
+173
@@ -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.")
|
||||||
@@ -20,14 +20,6 @@
|
|||||||
clang-tools
|
clang-tools
|
||||||
cmake
|
cmake
|
||||||
libgcc
|
libgcc
|
||||||
codespell
|
|
||||||
conan
|
|
||||||
cppcheck
|
|
||||||
doxygen
|
|
||||||
gtest
|
|
||||||
lcov
|
|
||||||
vcpkg
|
|
||||||
vcpkg-tool
|
|
||||||
python312Packages.matplotlib
|
python312Packages.matplotlib
|
||||||
] ++ (if system == "aarch64-darwin" then [ ] else [ gdb ]);
|
] ++ (if system == "aarch64-darwin" then [ ] else [ gdb ]);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user