-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathbenchmark_pareto_selection.py
More file actions
121 lines (103 loc) · 3.62 KB
/
Copy pathbenchmark_pareto_selection.py
File metadata and controls
121 lines (103 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""Demonstrate Pareto selection mode for multi-objective optimization.
This example shows:
1. Pareto front computation across multiple metrics
2. Non-dominated solutions
3. Trade-offs between modularity and runtime
4. Weighted selection as alternative
"""
from py3plex.core import multinet
from py3plex.dsl import B, L
import numpy as np
# Create test network with known structure
np.random.seed(42)
net = multinet.multi_layer_network(directed=False)
# Two communities
nodes = [{"source": f"N{i}", "type": "layer1"} for i in range(40)]
net.add_nodes(nodes)
# Dense within communities
for i in range(20):
for j in range(i + 1, 20):
if np.random.rand() < 0.4: # 40% density in block 1
net.add_edges([{
"source": f"N{i}",
"target": f"N{j}",
"source_type": "layer1",
"target_type": "layer1",
}])
for i in range(20, 40):
for j in range(i + 1, 40):
if np.random.rand() < 0.4: # 40% density in block 2
net.add_edges([{
"source": f"N{i}",
"target": f"N{j}",
"source_type": "layer1",
"target_type": "layer1",
}])
# Sparse between communities
for i in range(20):
for j in range(20, 40):
if np.random.rand() < 0.05: # 5% density between blocks
net.add_edges([{
"source": f"N{i}",
"target": f"N{j}",
"source_type": "layer1",
"target_type": "layer1",
}])
print("Running benchmark with Pareto selection...")
res_pareto = (
B.community()
.on(net)
.layers(L["layer1"])
.algorithms(
("louvain", {"grid": {"resolution": [0.5, 0.8, 1.0, 1.2, 1.5]}}),
("leiden", {"grid": {"gamma": [0.5, 0.8, 1.0, 1.2, 1.5], "n_iter": [2, 5]}}),
)
.metrics("modularity", "coverage", "runtime_ms")
.repeat(1, seed=42)
.select("pareto")
.execute()
)
print("\n=== Pareto Selection Results ===\n")
df_pareto = res_pareto.to_pandas()
# Show all evaluated configs
print(f"Total configs evaluated: {len(df_pareto)}")
# Show Pareto front
if hasattr(res_pareto, "benchmark"):
print("\n=== Pareto Front (non-dominated solutions) ===")
pareto = res_pareto.benchmark.pareto_front()
if pareto is not None and not pareto.empty:
print(pareto[["algorithm", "params_json", "modularity", "coverage", "runtime_ms"]])
print(f"\nPareto front size: {len(pareto)} solutions")
else:
print("(Pareto front not available)")
print("\n" + "="*60)
print("Now running with weighted selection...")
print("="*60 + "\n")
# Alternative: weighted selection
res_weighted = (
B.community()
.on(net)
.layers(L["layer1"])
.algorithms(
("louvain", {"grid": {"resolution": [0.5, 0.8, 1.0, 1.2, 1.5]}}),
("leiden", {"grid": {"gamma": [0.5, 0.8, 1.0, 1.2, 1.5], "n_iter": [2, 5]}}),
)
.metrics("modularity", "coverage", "runtime_ms")
.repeat(1, seed=42)
.select(("weighted", {
"modularity": 0.6,
"coverage": 0.3,
"runtime_ms": -0.1, # Negative weight = prefer lower
}))
.execute()
)
print("\n=== Weighted Selection Results ===\n")
if hasattr(res_weighted, "benchmark"):
print("Best overall (weighted score):")
best = res_weighted.benchmark.best_by_algo()
if best is not None and not best.empty:
print(best[["algorithm", "params_json", "modularity", "coverage", "runtime_ms"]])
else:
print("(Best by algorithm not available)")
print("\nPareto selection demo complete.")
print("\nKey insight: Pareto front reveals trade-offs, weighted selection picks one solution.")