Skip to content

Commit 017b400

Browse files
moved test vieclus
1 parent 078b17f commit 017b400

File tree

2 files changed

+171
-81
lines changed

2 files changed

+171
-81
lines changed

python/test_vieclus.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
"""Test script for VieClus Python interface."""
2+
import vieclus
3+
import subprocess
4+
import re
5+
import os
6+
7+
print("=== Test 1: Import and version ===")
8+
print(f"VieClus version: {vieclus.__version__}")
9+
10+
print("\n=== Test 2: vieclus_graph helper class ===")
11+
# Build a small graph with two clear communities:
12+
# Community 1: nodes 0,1,2 (triangle with weight 5)
13+
# Community 2: nodes 3,4,5 (triangle with weight 5)
14+
# Bridge: edge (2,3) with weight 1
15+
g = vieclus.vieclus_graph()
16+
g.set_num_nodes(6)
17+
# Community 1
18+
g.add_undirected_edge(0, 1, 5)
19+
g.add_undirected_edge(1, 2, 5)
20+
g.add_undirected_edge(0, 2, 5)
21+
# Community 2
22+
g.add_undirected_edge(3, 4, 5)
23+
g.add_undirected_edge(4, 5, 5)
24+
g.add_undirected_edge(3, 5, 5)
25+
# Bridge
26+
g.add_undirected_edge(2, 3, 1)
27+
28+
vwgt, xadj, adjcwgt, adjncy = g.get_csr_arrays()
29+
print(f" vwgt: {vwgt}")
30+
print(f" xadj: {xadj}")
31+
print(f" adjcwgt: {adjcwgt}")
32+
print(f" adjncy: {adjncy}")
33+
print(f" num nodes: {g.num_nodes}")
34+
print(f" num edges (directed): {len(adjncy)}")
35+
36+
print("\n=== Test 3: Clustering (two communities) ===")
37+
modularity, clustering = vieclus.cluster(
38+
vwgt, xadj, adjcwgt, adjncy,
39+
suppress_output=False,
40+
seed=0,
41+
time_limit=1.0
42+
)
43+
print(f" Modularity: {modularity:.6f}")
44+
print(f" Clustering: {list(clustering)}")
45+
num_clusters = len(set(clustering))
46+
print(f" Number of clusters: {num_clusters}")
47+
assert len(clustering) == 6, f"Expected 6 entries, got {len(clustering)}"
48+
assert modularity > 0, f"Expected positive modularity, got {modularity}"
49+
print(" PASSED")
50+
51+
print("\n=== Test 4: Clustering with different seed ===")
52+
modularity, clustering = vieclus.cluster(
53+
vwgt, xadj, adjcwgt, adjncy,
54+
suppress_output=True,
55+
seed=42,
56+
time_limit=1.0
57+
)
58+
print(f" Modularity: {modularity:.6f}")
59+
print(f" Clustering: {list(clustering)}")
60+
num_clusters = len(set(clustering))
61+
print(f" Number of clusters: {num_clusters}")
62+
assert len(clustering) == 6
63+
assert modularity > 0
64+
print(" PASSED")
65+
66+
print("\n=== Test 5: Raw CSR arrays (5-node path graph) ===")
67+
# Simple path: 0-1-2-3-4
68+
xadj = [0, 1, 3, 5, 7, 8]
69+
adjncy = [1, 0, 2, 1, 3, 2, 4, 3]
70+
vwgt = [1, 1, 1, 1, 1]
71+
adjcwgt = [1, 1, 1, 1, 1, 1, 1, 1]
72+
73+
modularity, clustering = vieclus.cluster(
74+
vwgt, xadj, adjcwgt, adjncy,
75+
suppress_output=True,
76+
seed=0,
77+
time_limit=1.0
78+
)
79+
print(f" Modularity: {modularity:.6f}")
80+
print(f" Clustering: {list(clustering)}")
81+
assert len(clustering) == 5
82+
print(" PASSED")
83+
84+
85+
def read_metis_graph(filename):
86+
"""Read a METIS graph file and return CSR arrays."""
87+
with open(filename, 'r') as f:
88+
lines = f.readlines()
89+
90+
# Parse header: n m [fmt] [ncon]
91+
header = lines[0].split()
92+
n = int(header[0])
93+
# m = int(header[1]) # not needed directly
94+
95+
xadj = [0]
96+
adjncy = []
97+
adjcwgt = []
98+
vwgt = [1] * n
99+
100+
for i in range(1, n + 1):
101+
neighbors = lines[i].split()
102+
for nb in neighbors:
103+
adjncy.append(int(nb) - 1) # convert 1-indexed to 0-indexed
104+
adjcwgt.append(1)
105+
xadj.append(len(adjncy))
106+
107+
return n, vwgt, xadj, adjcwgt, adjncy
108+
109+
110+
print("\n=== Test 6: Facebook graph - Python vs command line ===")
111+
graph_file = "/home/c_schulz/projects/graph_collection/facebook100/Amherst41.graph"
112+
vieclus_bin = os.path.join(os.path.dirname(__file__), "deploy", "vieclus")
113+
114+
if not os.path.exists(graph_file):
115+
print(f" SKIPPED (graph file not found: {graph_file})")
116+
elif not os.path.exists(vieclus_bin):
117+
print(f" SKIPPED (vieclus binary not found: {vieclus_bin})")
118+
else:
119+
time_limit = 5.0
120+
seed = 0
121+
122+
# Run command-line tool
123+
print(f" Graph: {graph_file}")
124+
print(f" Time limit: {time_limit}s, Seed: {seed}")
125+
print(f" Running command-line vieclus...")
126+
result = subprocess.run(
127+
[vieclus_bin, graph_file,
128+
f"--time_limit={time_limit}",
129+
f"--seed={seed}"],
130+
capture_output=True, text=True, timeout=60
131+
)
132+
cli_output = result.stdout + result.stderr
133+
# Parse modularity from output: "modularity \t\t\t0.xxxxx"
134+
match = re.search(r'modularity\s+([\d.]+)', cli_output)
135+
if match:
136+
cli_modularity = float(match.group(1))
137+
print(f" CLI modularity: {cli_modularity:.6f}")
138+
else:
139+
print(f" Could not parse CLI modularity from output:")
140+
print(f" {cli_output}")
141+
cli_modularity = None
142+
143+
# Run Python interface
144+
print(f" Running Python vieclus...")
145+
n, vwgt, xadj, adjcwgt, adjncy = read_metis_graph(graph_file)
146+
print(f" Graph: {n} nodes, {len(adjncy)//2} edges")
147+
148+
py_modularity, clustering = vieclus.cluster(
149+
vwgt, xadj, adjcwgt, adjncy,
150+
suppress_output=True,
151+
seed=seed,
152+
time_limit=time_limit
153+
)
154+
num_clusters = len(set(clustering))
155+
print(f" Python modularity: {py_modularity:.6f}")
156+
print(f" Number of clusters: {num_clusters}")
157+
158+
if cli_modularity is not None:
159+
diff = abs(py_modularity - cli_modularity)
160+
print(f" Difference: {diff:.6f}")
161+
# Both should find roughly the same modularity (within 5%)
162+
assert diff < 0.05, (
163+
f"Modularity difference too large: CLI={cli_modularity:.6f}, "
164+
f"Python={py_modularity:.6f}, diff={diff:.6f}"
165+
)
166+
print(" PASSED")
167+
else:
168+
print(" SKIPPED (could not compare)")
169+
170+
171+
print("\n=== All tests passed! ===")

test_vieclus.py

Lines changed: 0 additions & 81 deletions
This file was deleted.

0 commit comments

Comments
 (0)