Note
Go to the end to download the full example code.
Scheduler IR and Execution Tradeoffs¶
This example compares scheduling strategies, shows how they change depth and space usage, and illustrates how schedules become TICK-delimited pattern slices.
from graphqomb.pattern import Pattern, print_pattern
from graphqomb.qompiler import qompile
from graphqomb.random_objects import generate_random_flow_graph
from graphqomb.schedule_solver import ScheduleConfig, Strategy
from graphqomb.scheduler import Scheduler
Create sample graph state and flow
print("=== Scheduler-based Pattern Generation Demo ===\n")
print("1. Creating sample graph state...")
graph, xflow = generate_random_flow_graph(width=3, depth=3, edge_p=0.7)
print(f" Graph has {len(graph.nodes)} nodes")
print(f" Input nodes: {list(graph.input_node_indices.keys())}")
print(f" Output nodes: {list(graph.output_node_indices.keys())}")
print(f" Edges: {len(graph.edges)}")
=== Scheduler-based Pattern Generation Demo ===
1. Creating sample graph state...
Graph has 9 nodes
Input nodes: [0, 1, 2]
Output nodes: [6, 7, 8]
Edges: 8
Demonstrate space-optimized scheduling
print("\n2. Space-optimized Scheduling:")
print("=" * 40)
scheduler_space = Scheduler(graph, xflow)
space_config = ScheduleConfig(strategy=Strategy.MINIMIZE_SPACE)
success_space = scheduler_space.solve_schedule(space_config, timeout=10)
pattern_space = None
if success_space:
scheduler_space.validate_schedule() # Will raise ValueError if invalid
print(" Scheduling successful!")
print(f" Number of time slices: {scheduler_space.num_slices()}")
prep_times = {k: v for k, v in scheduler_space.prepare_time.items() if v is not None}
if prep_times:
print(f" Preparation times: {prep_times}")
meas_times = {k: v for k, v in scheduler_space.measure_time.items() if v is not None}
if meas_times:
print(f" Measurement times: {meas_times}")
print("\n Generated Pattern (Space-optimized):")
pattern_space = qompile(graph, xflow, scheduler=scheduler_space)
print(f" Pattern has {len(pattern_space.commands)} commands")
print(f" Maximum space usage: {pattern_space.max_space} qubits")
print(f" Space usage over time: {pattern_space.space}")
print("\n Pattern commands:")
print_pattern(pattern_space, lim=10)
else:
print(" Failed to find solution for Space-optimized strategy")
2. Space-optimized Scheduling:
========================================
Scheduling successful!
Number of time slices: 7
Preparation times: {3: 1, 4: 0, 5: 3, 6: 2, 7: 5, 8: 4}
Measurement times: {0: 2, 1: 1, 2: 4, 3: 3, 4: 6, 5: 5}
Generated Pattern (Space-optimized):
Pattern has 33 commands
Maximum space usage: 4 qubits
Space usage over time: [3, 4, 4, 4, 4, 4, 4, 3]
Pattern commands:
N: node=4
E: nodes=(1, 4)
TICK
N: node=3
E: nodes=(0, 3)
E: nodes=(3, 4)
M: node=1, plane=Plane.XY, angle=0.0
TICK
N: node=6
E: nodes=(3, 6)
23 more commands truncated. Change lim argument of print_pattern() to show more
Demonstrate time-optimized scheduling
print("\n3. Time-optimized Scheduling:")
print("=" * 40)
scheduler_time = Scheduler(graph, xflow)
time_config = ScheduleConfig(strategy=Strategy.MINIMIZE_TIME)
success_time = scheduler_time.solve_schedule(time_config, timeout=10)
pattern_time = None
if success_time:
scheduler_time.validate_schedule() # Will raise ValueError if invalid
print(" Scheduling successful!")
print(f" Number of time slices: {scheduler_time.num_slices()}")
prep_times = {k: v for k, v in scheduler_time.prepare_time.items() if v is not None}
if prep_times:
print(f" Preparation times: {prep_times}")
meas_times = {k: v for k, v in scheduler_time.measure_time.items() if v is not None}
if meas_times:
print(f" Measurement times: {meas_times}")
print("\n Generated Pattern (Time-optimized):")
pattern_time = qompile(graph, xflow, scheduler=scheduler_time)
print(f" Pattern has {len(pattern_time.commands)} commands")
print(f" Maximum space usage: {pattern_time.max_space} qubits")
print(f" Space usage over time: {pattern_time.space}")
print("\n Pattern commands:")
print_pattern(pattern_time, lim=10)
else:
print(" Failed to find solution for Time-optimized strategy")
3. Time-optimized Scheduling:
========================================
Scheduling successful!
Number of time slices: 3
Preparation times: {3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0}
Measurement times: {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2}
Generated Pattern (Time-optimized):
Pattern has 29 commands
Maximum space usage: 9 qubits
Space usage over time: [3, 9, 6, 3]
Pattern commands:
N: node=3
N: node=4
N: node=5
N: node=6
N: node=7
N: node=8
E: nodes=(3, 4)
E: nodes=(5, 8)
E: nodes=(0, 3)
E: nodes=(1, 4)
19 more commands truncated. Change lim argument of print_pattern() to show more
Demonstrate space-constrained time optimization using ScheduleConfig
print("\n4. Space-constrained Time-optimized Scheduling (ScheduleConfig):")
print("=" * 60)
# Use ScheduleConfig for more detailed control
max_qubits = 5
constrained_config = ScheduleConfig(
strategy=Strategy.MINIMIZE_TIME,
max_qubit_count=max_qubits,
max_time=20, # Custom time limit
)
scheduler_constrained = Scheduler(graph, xflow)
success_constrained = scheduler_constrained.solve_schedule(constrained_config, timeout=15)
pattern_constrained = None
if success_constrained:
scheduler_constrained.validate_schedule() # Will raise ValueError if invalid
print(" Scheduling successful!")
print(f" Number of time slices: {scheduler_constrained.num_slices()}")
print(f" Max qubits constraint: {max_qubits}")
prep_times = {k: v for k, v in scheduler_constrained.prepare_time.items() if v is not None}
if prep_times:
print(f" Preparation times: {prep_times}")
meas_times = {k: v for k, v in scheduler_constrained.measure_time.items() if v is not None}
if meas_times:
print(f" Measurement times: {meas_times}")
print("\n Generated Pattern (Space-constrained Time-optimized):")
pattern_constrained = qompile(graph, xflow, scheduler=scheduler_constrained)
print(f" Pattern has {len(pattern_constrained.commands)} commands")
print(f" Maximum space usage: {pattern_constrained.max_space} qubits")
print(f" Space usage over time: {pattern_constrained.space}")
if pattern_constrained.max_space <= max_qubits:
print(f" ✓ Space constraint satisfied: {pattern_constrained.max_space} <= {max_qubits}")
else:
print(f" ⚠ Space constraint violated: {pattern_constrained.max_space} > {max_qubits}")
print("\n Pattern commands:")
print_pattern(pattern_constrained, lim=10)
else:
print(f" Failed to find solution with {max_qubits} qubits constraint")
4. Space-constrained Time-optimized Scheduling (ScheduleConfig):
============================================================
Scheduling successful!
Number of time slices: 4
Max qubits constraint: 5
Preparation times: {3: 1, 4: 0, 5: 0, 6: 2, 7: 2, 8: 1}
Measurement times: {0: 2, 1: 1, 2: 1, 3: 3, 4: 3, 5: 2}
Generated Pattern (Space-constrained Time-optimized):
Pattern has 30 commands
Maximum space usage: 5 qubits
Space usage over time: [3, 5, 5, 5, 3]
✓ Space constraint satisfied: 5 <= 5
Pattern commands:
N: node=4
N: node=5
E: nodes=(4, 5)
E: nodes=(2, 5)
E: nodes=(1, 4)
TICK
N: node=8
N: node=3
E: nodes=(0, 3)
E: nodes=(3, 4)
20 more commands truncated. Change lim argument of print_pattern() to show more
Demonstrate custom max_time using ScheduleConfig
print("\n5. Custom max_time Scheduling (ScheduleConfig):")
print("=" * 50)
custom_time_config = ScheduleConfig(
strategy=Strategy.MINIMIZE_SPACE,
max_time=15, # Smaller time horizon for faster solving
)
scheduler_custom = Scheduler(graph, xflow)
success_custom = scheduler_custom.solve_schedule(custom_time_config, timeout=10)
if success_custom:
scheduler_custom.validate_schedule() # Will raise ValueError if invalid
print(" Scheduling with custom max_time successful!")
print(f" Number of time slices: {scheduler_custom.num_slices()}")
print(f" Custom max_time: {custom_time_config.max_time}")
pattern_custom = qompile(graph, xflow, scheduler=scheduler_custom)
print(f" Maximum space usage: {pattern_custom.max_space} qubits")
else:
print(" Failed to find solution with custom max_time")
5. Custom max_time Scheduling (ScheduleConfig):
==================================================
Scheduling with custom max_time successful!
Number of time slices: 8
Custom max_time: 15
Maximum space usage: 4 qubits
Compare all strategies
print("\n6. Strategy Comparison:")
print("=" * 40)
all_results: list[tuple[str, Scheduler, Pattern]] = []
if success_space and pattern_space:
all_results.append(("Space-optimized", scheduler_space, pattern_space))
if success_time and pattern_time:
all_results.append(("Time-optimized", scheduler_time, pattern_time))
if success_constrained and pattern_constrained:
all_results.append(("Space-constrained", scheduler_constrained, pattern_constrained))
min_results_needed = 2
if len(all_results) >= min_results_needed:
for name, scheduler, pattern in all_results:
print(
f" {name:18}: {scheduler.num_slices()} slices, "
f"{pattern.max_space} max qubits, {len(pattern.commands)} commands"
)
print("\n Analysis:")
min_results_for_comparison = 2
if len(all_results) >= min_results_for_comparison:
min_slices = min(s.num_slices() for _, s, _ in all_results)
min_qubits = min(p.max_space for _, _, p in all_results)
for name, scheduler, pattern in all_results:
notes: list[str] = []
if scheduler.num_slices() == min_slices:
notes.append("fastest execution")
if pattern.max_space == min_qubits:
notes.append("lowest qubit usage")
if notes:
print(f" → {name}: {', '.join(notes)}")
print("\nDemo completed successfully!")
6. Strategy Comparison:
========================================
Space-optimized : 7 slices, 4 max qubits, 33 commands
Time-optimized : 3 slices, 9 max qubits, 29 commands
Space-constrained : 4 slices, 5 max qubits, 30 commands
Analysis:
→ Space-optimized: lowest qubit usage
→ Time-optimized: fastest execution
Demo completed successfully!
Total running time of the script: (0 minutes 0.137 seconds)