Skip to main content

Tutorial 13 — Comparing Candidate Topologies for a Route

Objective: Compare two candidate network designs for the same source→target pair using Monte Carlo simulation, and programmatically pick a winner by success rate.

When you have multiple topology options (e.g., "should I build a direct long link or install repeaters?"), compare_topologies() automates the evaluation across both designs.

Define Two Candidate Designs

from qnet_core import QNetEngine, NodeDefinition, LinkDefinition, StrategyType, compare_topologies, TopologyEndpoints

print("=== Two Candidates: Long Single-Hop vs Multi-Hop Chain ===\n")

# Design A: One long fiber link (fewer components, higher single-link risk)
engine_a = QNetEngine()
nodes_a = [
NodeDefinition(id="Alice", memory_lifetime_t2=1.0),
NodeDefinition(id="Bob", memory_lifetime_t2=1.0),
]
links_a = [
LinkDefinition("Alice", "Bob", distance_km=80.0, base_fidelity=0.70, generation_rate_hz=300.0),
]
engine_a.define_network(nodes_a, links_a)

# Design B: Three shorter hops with repeaters (more components, higher per-hop fidelity)
engine_b = QNetEngine()
nodes_b = [
NodeDefinition(id="Alice", memory_lifetime_t2=1.0),
NodeDefinition(id="R1", memory_lifetime_t2=0.8),
NodeDefinition(id="R2", memory_lifetime_t2=0.8),
NodeDefinition(id="Bob", memory_lifetime_t2=1.0),
]
links_b = [
LinkDefinition("Alice", "R1", distance_km=15.0, base_fidelity=0.93, generation_rate_hz=800.0),
LinkDefinition("R1", "R2", distance_km=15.0, base_fidelity=0.91, generation_rate_hz=700.0),
LinkDefinition("R2", "Bob", distance_km=15.0, base_fidelity=0.89, generation_rate_hz=600.0),
]
engine_b.define_network(nodes_b, links_b)

Run Individual Simulations

designs = {
"A: Long single-hop (80 km)": (engine_a,),
"B: 3-hop chain (15+15+15 km)": (engine_b,),
}

print(f"{'Design':<40} {'Success':>9} {'Fidelity':>10}")
print("-" * 62)

for name, (eng,) in designs.items():
stats = eng.simulate(
from_node="Alice", to="Bob",
fidelity_target=0.80, max_latency_ms=10_000.0,
runs=500, strategy=StrategyType.HighestFidelity, seed=42,
)
print(f"{name:<40} {stats.empirical_success_rate:>8.1%} {stats.mean_fidelity:>9.4f}")

Use compare_topologies() for Automated Comparison

# compare_topologies() requires TopologyEndpoints objects that map
# generated topology names to source and target node IDs
endpoints = [
TopologyEndpoints("telecom_backbone", "node_0", "node_N"),
TopologyEndpoints("hybrid_satellite_fiber", "satellite", "ground"),
]

report = compare_topologies(
endpoints=endpoints,
fidelity_target=0.75,
max_latency_ms=5000.0,
runs=1000,
strategy=StrategyType.HighestFidelity,
)

print(f"Recommended: {report.recommended_topology}")
print(report.summary)

for r in report.results:
print(f"{r.topology_name}: success={r.success_rate:.2%}, "
f"latency={r.mean_latency_ms:.1f}ms, fidelity={r.mean_fidelity:.4f}")

Result Types

TopologyComparisonReport Fields

FieldTypeDescription
source_nodestrSource node ID for the comparison
target_nodestrTarget node ID
fidelity_targetfloatFidelity threshold used
max_latency_msfloatLatency cap used
runsintNumber of Monte Carlo runs per topology
resultsList[TopologyComparisonResult]Per-topology results, sorted by success rate descending
recommended_topologystrTopology name with the highest success rate
summarystrHuman-readable comparison summary

TopologyComparisonResult Fields

FieldTypeDescription
topology_namestrName of the compared topology
success_ratefloatMonte Carlo success rate [0, 1]
mean_latency_msfloatMean latency across runs
mean_fidelityfloatMean fidelity across successful runs
link_utilizationDict[str, int]Per-link usage counts

Typical Outcome

On the example above, Design B (multi-hop chain) typically wins because:

  1. BBPSSW purification recovers fidelity across short links much more effectively than on a single long link
  2. Higher per-hop generation rates reduce latency compared to a single slow 80 km link
  3. Redundancy — multiple hops provide more routing options under the HighestFidelity strategy

What's next