DQC Examples¶
Examples demonstrating simulation of quantum circuit execution across distributed quantum nodes with communication protocols.
DQC QFT¶
dqc_qft_example.py¶
1from typing import Any
2
3import numpy as np
4
5from kosmos.dqc_scheduling.space_time_matrix import SpaceTimeMatrix
6from kosmos.partitioning.mqt_bench.bench_circuit import MQTBenchCircuit
7from kosmos.simulator.dqc_simulator import DQCSimulator
8from kosmos.topology.link import LinkId, QuantumLink
9from kosmos.topology.net import Network
10from kosmos.topology.node import NodeId, NodeRole, QuantumNode
11
12
13def dqc_qft_example() -> None:
14 """Run a distributed quantum computing simulation with QFT circuit."""
15 # Create desired network
16 network = create_dqc_network()
17
18 # Define circuit to be executed
19 bench_circuit = MQTBenchCircuit(circuit_type="qft", num_qubits=4)
20 circuit = bench_circuit.circuit()
21
22 # Set up the Simulator for DQC
23 # Optional: specify custom entanglement generation protocol and qubit assignment strategy
24 simulator = DQCSimulator(network=network, seed=1)
25 simulator.load_circuit(circuit)
26 simulator.schedule_protocols()
27
28 # Run simulation and get results
29 results = simulator.run()
30
31 # Retrieve qubit assignment from simulator
32 qubit_assignment_matrix = simulator.execution_scheduler.space_time_matrix
33
34 # Retrieve measurement results
35 measurement_counts = results["counts"]
36 num_qubits = circuit.num_qubits
37
38 # Retrieve density matrix
39 density_matrix = results["density_matrix"]
40
41 # Retrieve additional information
42 additional_simulation_results = [
43 results["computation_time"],
44 results["communication_time"],
45 results["total_time"],
46 results["num_remote_gates"],
47 results["num_teleportations"],
48 results.get("expectation_values"),
49 ]
50
51 # Print retrieved results
52 print_space_time_matrix(qubit_assignment_matrix)
53 print_measurement_counts(measurement_counts, num_qubits)
54 print_density_matrix_diagonal(density_matrix, num_qubits)
55 print_additional_simulation_results(additional_simulation_results)
56
57
58def create_dqc_network() -> Network:
59 """Create a quantum network with multiple QPUs.
60
61 Returns:
62 Network: A network with 3 quantum nodes connected by quantum links.
63
64 """
65 network = Network()
66
67 qpu_1 = QuantumNode(
68 id=NodeId("QPU_1"),
69 roles=[NodeRole.END_USER],
70 num_qubits=4,
71 num_data_qubits=3, # If not provided, defaults to half of num_qubits (rounded down)
72 coherence_time=100e-6, # 100 microseconds
73 gate_fid=0.99,
74 meas_fid=0.98,
75 has_transceiver=True,
76 )
77 qpu_2 = QuantumNode(
78 id=NodeId("QPU_2"),
79 roles=[NodeRole.END_USER],
80 num_qubits=4,
81 num_data_qubits=3,
82 coherence_time=100e-6,
83 gate_fid=0.99,
84 meas_fid=0.98,
85 has_transceiver=True,
86 )
87 qpu_3 = QuantumNode(
88 id=NodeId("QPU_3"),
89 roles=[NodeRole.END_USER],
90 num_qubits=5,
91 num_data_qubits=3,
92 coherence_time=100e-6,
93 gate_fid=0.99,
94 meas_fid=0.98,
95 has_transceiver=True,
96 )
97
98 link_1_2 = QuantumLink(
99 id=LinkId("QPU_1_2"),
100 src=qpu_1,
101 dst=qpu_2,
102 distance=50000.0, # 50 km
103 attenuation=0.0002,
104 signal_speed=200.0,
105 repetition_rate=1e6, # 1 MHz
106 polarization_fidelity=0.98,
107 )
108 link_1_3 = QuantumLink(
109 id=LinkId("QPU_1_3"),
110 src=qpu_1,
111 dst=qpu_3,
112 distance=50000.0, # 50 km
113 attenuation=0.0002,
114 signal_speed=200.0,
115 repetition_rate=1e6, # 1 MHz
116 polarization_fidelity=0.98,
117 )
118 link_2_3 = QuantumLink(
119 id=LinkId("QPU_2_3"),
120 src=qpu_2,
121 dst=qpu_3,
122 distance=100000.0, # 100 km
123 attenuation=0.0002,
124 signal_speed=200.0,
125 repetition_rate=1e6, # 1 MHz
126 polarization_fidelity=0.98,
127 )
128
129 network.add_node(qpu_1)
130 network.add_node(qpu_2)
131 network.add_node(qpu_3)
132 network.add_link(link_1_2)
133 network.add_link(link_2_3)
134 network.add_link(link_1_3)
135
136 return network
137
138
139def print_space_time_matrix(qubit_assignment_matrix: SpaceTimeMatrix) -> None:
140 """Visualize the space-time matrix showing qubit-node assignments over time.
141
142 Args:
143 qubit_assignment_matrix (SpaceTimeMatrix): The space-time matrix containing qubit to node
144 assignments.
145
146 """
147 output = ["\n" + "=" * 60, "SPACE-TIME MATRIX (Qubit → Node Assignment)\n"]
148
149 header = "Qubit |"
150 for t in range(min(qubit_assignment_matrix.num_timesteps, 20)):
151 header += f" T{t:2d} |"
152 output.append(header)
153 output.append("-" * len(header))
154
155 for qubit in range(qubit_assignment_matrix.num_qubits):
156 row = f" {qubit:2d} |"
157 for t in range(min(qubit_assignment_matrix.num_timesteps, 20)):
158 node = qubit_assignment_matrix.get_node_at(qubit, t)
159 if node:
160 # Use short node ID (e.g., QPU_1 -> "1")
161 node_short = node.id.value.split("_")[-1]
162 row += f" {node_short:3s} |"
163 else:
164 row += " - |"
165 output.append(row)
166
167 output.append("\nLegend:")
168 nodes_used = set()
169 for partition in qubit_assignment_matrix.partition_info.values():
170 if partition.node:
171 nodes_used.add(partition.node)
172 if partition.is_multi_node:
173 nodes_used.update(partition.qubit_to_node_mapping.values())
174
175 for node in sorted(nodes_used, key=lambda n: n.id.value):
176 node_short = node.id.value.split("_")[-1]
177 output.append(f" {node_short} = {node.id.value}")
178
179 print("\n".join(output)) # noqa: T201
180
181
182def print_measurement_counts(
183 counts: dict[str, int], num_qubits: int, max_display: int = 16
184) -> None:
185 """Print measurement counts in a cleaner format.
186
187 Args:
188 counts (dict[str, int]): Dictionary of measurement counts.
189 num_qubits (int): Number of qubits in the circuit.
190 max_display (int): Maximum number of bitstrings to display.
191
192 """
193 output = ["\n" + "=" * 60, "MEASUREMENT COUNTS"]
194
195 total_shots = sum(counts.values())
196 output.append(f"\nTotal shots: {total_shots}")
197 output.append(f"Number of qubits: {num_qubits}")
198
199 if len(counts) <= max_display:
200 output.append("\nAll measurement outcomes:")
201 else:
202 output.append(f"\nTop {max_display} most probable outcomes:")
203
204 sorted_counts = sorted(counts.items(), key=lambda x: x[1], reverse=True)
205
206 for bitstring, count in sorted_counts[:max_display]:
207 probability = count / total_shots
208 output.append(f" {bitstring}: {count:5d} ({probability:.4f})")
209
210 if len(counts) > max_display:
211 output.append(f"\n... and {len(counts) - max_display} more outcomes")
212
213 print("\n".join(output)) # noqa: T201
214
215
216def print_density_matrix_diagonal(
217 density_matrix: np.ndarray, num_qubits: int, max_display: int = 16
218) -> None:
219 """Print the diagonal of the resultant density matrix.
220
221 Args:
222 density_matrix: The density matrix to display.
223 num_qubits: Number of qubits.
224 max_display: Maximum number of basis states to display.
225
226 """
227 output = ["\n" + "=" * 60, "DENSITY MATRIX"]
228
229 dim = 2**num_qubits
230
231 output.append("\nDiagonal Elements (Populations):")
232 for i in range(min(dim, max_display)):
233 bitstring = format(i, f"0{num_qubits}b")
234 val = density_matrix[i, i]
235 output.append(f" |{bitstring}⟩: {val.real:.6f}")
236
237 if dim > max_display:
238 output.append(f" ... ({dim - max_display} more states)")
239
240 print("\n".join(output)) # noqa: T201
241
242
243def print_additional_simulation_results(additional_simulation_results: list[Any]) -> None:
244 """Print the simulation results.
245
246 Args:
247 additional_simulation_results (list[Any]): List of additional simulation results.
248
249 """
250 (
251 computation_time,
252 communication_time,
253 total_time,
254 num_remote_gates,
255 num_teleportations,
256 expectation_values,
257 ) = additional_simulation_results
258 output = [
259 "\n" + "=" * 60,
260 "SIMULATION RESULTS",
261 "\nTiming:",
262 f" Computation time: {computation_time:.2f} ps",
263 f" Communication time: {communication_time:.2f} ps",
264 f" Total execution time: {total_time:.2f} ps",
265 ]
266
267 if communication_time > 0:
268 overhead_pct = (communication_time / total_time) * 100
269 output.append(f" Communication overhead: {overhead_pct:.1f}%")
270
271 output.append("\nRemote Operations:")
272 output.append(f" Remote CNOT gates: {num_remote_gates}")
273 output.append(f" Teleportations: {num_teleportations}")
274
275 if expectation_values is not None:
276 output.append("\nExpectation Values (Z basis):")
277 for qubit_idx, exp_val in enumerate(expectation_values):
278 output.append(f" Qubit {qubit_idx}: {exp_val:+.6f}")
279
280 print("\n".join(output)) # noqa: T201
281
282
283if __name__ == "__main__":
284 dqc_qft_example()