def test_active_reset_circuit(self, write_lat, cond_lat): """Test practical example of reset circuit. Because of the stimulus pulse overlap with the previous XGate on the q register, measure instruction is always triggered after XGate regardless of write latency. Thus only conditional latency matters in the scheduling. (input) ┌─┐ ┌───┐ ┌─┐ ┌───┐ ┌─┐ ┌───┐ q: ┤M├───┤ X ├───┤M├───┤ X ├───┤M├───┤ X ├─── └╥┘ └─╥─┘ └╥┘ └─╥─┘ └╥┘ └─╥─┘ ║ ┌────╨────┐ ║ ┌────╨────┐ ║ ┌────╨────┐ c: 1/═╩═╡ c_0=0x1 ╞═╩═╡ c_0=0x1 ╞═╩═╡ c_0=0x1 ╞ 0 └─────────┘ 0 └─────────┘ 0 └─────────┘ """ qc = QuantumCircuit(1, 1) qc.measure(0, 0) qc.x(0).c_if(0, 1) qc.measure(0, 0) qc.x(0).c_if(0, 1) qc.measure(0, 0) qc.x(0).c_if(0, 1) durations = InstructionDurations([("x", None, 100), ("measure", None, 1000)]) actual_asap = PassManager([ SetIOLatency(clbit_write_latency=write_lat, conditional_latency=cond_lat), ASAPScheduleAnalysis(durations), PadDelay(), ]).run(qc) actual_alap = PassManager([ SetIOLatency(clbit_write_latency=write_lat, conditional_latency=cond_lat), ALAPScheduleAnalysis(durations), PadDelay(), ]).run(qc) expected = QuantumCircuit(1, 1) expected.measure(0, 0) if cond_lat > 0: expected.delay(cond_lat, 0) expected.x(0).c_if(0, 1) expected.measure(0, 0) if cond_lat > 0: expected.delay(cond_lat, 0) expected.x(0).c_if(0, 1) expected.measure(0, 0) if cond_lat > 0: expected.delay(cond_lat, 0) expected.x(0).c_if(0, 1) self.assertEqual(expected, actual_asap) self.assertEqual(expected, actual_alap)
def test_hanh_echo_experiment_type(self): """Test Hahn echo experiment type circuit. (input) ┌────┐┌────────────────┐┌───┐┌────────────────┐┌────┐┌─┐ q_0: ┤ √X ├┤ Delay(100[dt]) ├┤ X ├┤ Delay(100[dt]) ├┤ √X ├┤M├ └────┘└────────────────┘└───┘└────────────────┘└────┘└╥┘ c: 1/══════════════════════════════════════════════════════╩═ 0 (output) ┌────┐┌────────────────┐┌───┐┌────────────────┐┌────┐┌──────────────┐┌─┐ q_0: ┤ √X ├┤ Delay(100[dt]) ├┤ X ├┤ Delay(100[dt]) ├┤ √X ├┤ Delay(8[dt]) ├┤M├ └────┘└────────────────┘└───┘└────────────────┘└────┘└──────────────┘└╥┘ c: 1/══════════════════════════════════════════════════════════════════════╩═ 0 This type of experiment doesn't change duration of interest (two in the middle). However induces slight delay less than alignment * dt before measurement. This might induce extra amplitude damping error. """ circuit = QuantumCircuit(1, 1) circuit.sx(0) circuit.delay(100, 0, unit="dt") circuit.x(0) circuit.delay(100, 0, unit="dt") circuit.sx(0) circuit.measure(0, 0) pm = PassManager([ # reproduce old behavior of 0.20.0 before #7655 # currently default write latency is 0 SetIOLatency(clbit_write_latency=1600, conditional_latency=0), ALAPScheduleAnalysis(durations=self.instruction_durations), ConstrainedReschedule(acquire_alignment=16), PadDelay(), ]) aligned_circuit = pm.run(circuit) ref_circuit = QuantumCircuit(1, 1) ref_circuit.sx(0) ref_circuit.delay(100, 0, unit="dt") ref_circuit.x(0) ref_circuit.delay(100, 0, unit="dt") ref_circuit.sx(0) ref_circuit.delay(8, 0, unit="dt") ref_circuit.measure(0, 0) self.assertEqual(aligned_circuit, ref_circuit)
def test_mid_circuit_measure(self): """Test circuit with mid circuit measurement. (input) ┌───┐┌────────────────┐┌─┐┌───────────────┐┌───┐┌────────────────┐┌─┐ q_0: ┤ X ├┤ Delay(100[dt]) ├┤M├┤ Delay(10[dt]) ├┤ X ├┤ Delay(120[dt]) ├┤M├ └───┘└────────────────┘└╥┘└───────────────┘└───┘└────────────────┘└╥┘ c: 2/════════════════════════╩══════════════════════════════════════════╩═ 0 1 (output) ┌───┐┌────────────────┐┌─┐┌───────────────┐┌───┐┌────────────────┐┌─┐ q_0: ┤ X ├┤ Delay(112[dt]) ├┤M├┤ Delay(10[dt]) ├┤ X ├┤ Delay(134[dt]) ├┤M├ └───┘└────────────────┘└╥┘└───────────────┘└───┘└────────────────┘└╥┘ c: 2/════════════════════════╩══════════════════════════════════════════╩═ 0 1 Extra delay is always added to the existing delay right before the measurement. Delay after measurement is unchanged. """ circuit = QuantumCircuit(1, 2) circuit.x(0) circuit.delay(100, 0, unit="dt") circuit.measure(0, 0) circuit.delay(10, 0, unit="dt") circuit.x(0) circuit.delay(120, 0, unit="dt") circuit.measure(0, 1) pm = PassManager([ # reproduce old behavior of 0.20.0 before #7655 # currently default write latency is 0 SetIOLatency(clbit_write_latency=1600, conditional_latency=0), ALAPScheduleAnalysis(durations=self.instruction_durations), ConstrainedReschedule(acquire_alignment=16), PadDelay(), ]) aligned_circuit = pm.run(circuit) ref_circuit = QuantumCircuit(1, 2) ref_circuit.x(0) ref_circuit.delay(112, 0, unit="dt") ref_circuit.measure(0, 0) ref_circuit.delay(10, 0, unit="dt") ref_circuit.x(0) ref_circuit.delay(134, 0, unit="dt") ref_circuit.measure(0, 1) self.assertEqual(aligned_circuit, ref_circuit)
def test_t1_experiment_type(self): """Test T1 experiment type circuit. (input) ┌───┐┌────────────────┐┌─┐ q_0: ┤ X ├┤ Delay(100[dt]) ├┤M├ └───┘└────────────────┘└╥┘ c: 1/════════════════════════╩═ 0 (aligned) ┌───┐┌────────────────┐┌─┐ q_0: ┤ X ├┤ Delay(112[dt]) ├┤M├ └───┘└────────────────┘└╥┘ c: 1/════════════════════════╩═ 0 This type of experiment slightly changes delay duration of interest. However the quantization error should be less than alignment * dt. """ circuit = QuantumCircuit(1, 1) circuit.x(0) circuit.delay(100, 0, unit="dt") circuit.measure(0, 0) pm = PassManager([ # reproduce old behavior of 0.20.0 before #7655 # currently default write latency is 0 SetIOLatency(clbit_write_latency=1600, conditional_latency=0), ALAPScheduleAnalysis(durations=self.instruction_durations), ConstrainedReschedule(acquire_alignment=16), PadDelay(), ]) aligned_circuit = pm.run(circuit) ref_circuit = QuantumCircuit(1, 1) ref_circuit.x(0) ref_circuit.delay(112, 0, unit="dt") ref_circuit.measure(0, 0) self.assertEqual(aligned_circuit, ref_circuit)
def test_random_complicated_circuit(self): """Test scheduling complicated circuit with control flow. (input) ┌────────────────┐ ┌───┐ ░ ┌───┐ » q_0: ┤ Delay(100[dt]) ├───┤ X ├────░──────────────────┤ X ├───» └────────────────┘ └─╥─┘ ░ ┌───┐ └─╥─┘ » q_1: ───────────────────────╫──────░───────┤ X ├────────╫─────» ║ ░ ┌─┐ └─╥─┘ ║ » q_2: ───────────────────────╫──────░─┤M├─────╫──────────╫─────» ┌────╨────┐ ░ └╥┘┌────╨────┐┌────╨────┐» c: 1/══════════════════╡ c_0=0x1 ╞════╩═╡ c_0=0x0 ╞╡ c_0=0x0 ╞» └─────────┘ 0 └─────────┘└─────────┘» « ┌────────────────┐┌───┐ «q_0: ┤ Delay(300[dt]) ├┤ X ├─────■───── « └────────────────┘└───┘ ┌─┴─┐ «q_1: ────────■─────────────────┤ X ├─── « ┌─┴─┐ ┌─┐ └─╥─┘ «q_2: ──────┤ X ├────────┤M├──────╫───── « └───┘ └╥┘ ┌────╨────┐ «c: 1/════════════════════╩══╡ c_0=0x0 ╞ « 0 └─────────┘ (ASAP scheduled) duration = 2800 dt ┌────────────────┐ ┌───┐ ░ ┌─────────────────┐ » q_0: ┤ Delay(200[dt]) ├───┤ X ├────░─┤ Delay(1400[dt]) ├───────────» ├────────────────┤ └─╥─┘ ░ ├─────────────────┤ ┌───┐ » q_1: ┤ Delay(300[dt]) ├─────╫──────░─┤ Delay(1200[dt]) ├───┤ X ├───» ├────────────────┤ ║ ░ └───────┬─┬───────┘ └─╥─┘ » q_2: ┤ Delay(300[dt]) ├─────╫──────░─────────┤M├─────────────╫─────» └────────────────┘┌────╨────┐ ░ └╥┘ ┌────╨────┐» c: 1/══════════════════╡ c_0=0x1 ╞════════════╩═════════╡ c_0=0x0 ╞» └─────────┘ 0 └─────────┘» « ┌───┐ ┌────────────────┐ ┌───┐ » «q_0: ─────────────────────┤ X ├───┤ Delay(300[dt]) ├──────┤ X ├───────» « └─╥─┘ └────────────────┘┌─────┴───┴──────┐» «q_1: ───────────────────────╫─────────────■─────────┤ Delay(400[dt]) ├» « ┌────────────────┐ ║ ┌─┴─┐ ├────────────────┤» «q_2: ┤ Delay(300[dt]) ├─────╫───────────┤ X ├───────┤ Delay(300[dt]) ├» « └────────────────┘┌────╨────┐ └───┘ └────────────────┘» «c: 1/══════════════════╡ c_0=0x0 ╞════════════════════════════════════» « └─────────┘ » « ┌────────────────┐ «q_0: ─────■─────┤ Delay(700[dt]) ├ « ┌─┴─┐ ├────────────────┤ «q_1: ───┤ X ├───┤ Delay(700[dt]) ├ « └─╥─┘ └──────┬─┬───────┘ «q_2: ─────╫────────────┤M├──────── « ┌────╨────┐ └╥┘ «c: 1/╡ c_0=0x0 ╞════════╩═════════ « └─────────┘ 0 (ALAP scheduled) duration = 3100 ┌────────────────┐ ┌───┐ ░ ┌─────────────────┐ » q_0: ┤ Delay(200[dt]) ├───┤ X ├────░─┤ Delay(1400[dt]) ├───────────» ├────────────────┤ └─╥─┘ ░ ├─────────────────┤ ┌───┐ » q_1: ┤ Delay(300[dt]) ├─────╫──────░─┤ Delay(1200[dt]) ├───┤ X ├───» ├────────────────┤ ║ ░ └───────┬─┬───────┘ └─╥─┘ » q_2: ┤ Delay(300[dt]) ├─────╫──────░─────────┤M├─────────────╫─────» └────────────────┘┌────╨────┐ ░ └╥┘ ┌────╨────┐» c: 1/══════════════════╡ c_0=0x1 ╞════════════╩═════════╡ c_0=0x0 ╞» └─────────┘ 0 └─────────┘» « ┌───┐ ┌────────────────┐ ┌───┐ » «q_0: ─────────────────────┤ X ├───┤ Delay(300[dt]) ├──────┤ X ├───────» « ┌────────────────┐ └─╥─┘ └────────────────┘┌─────┴───┴──────┐» «q_1: ┤ Delay(300[dt]) ├─────╫─────────────■─────────┤ Delay(100[dt]) ├» « ├────────────────┤ ║ ┌─┴─┐ └──────┬─┬───────┘» «q_2: ┤ Delay(600[dt]) ├─────╫───────────┤ X ├──────────────┤M├────────» « └────────────────┘┌────╨────┐ └───┘ └╥┘ » «c: 1/══════════════════╡ c_0=0x0 ╞══════════════════════════╩═════════» « └─────────┘ 0 » « ┌────────────────┐ «q_0: ─────■─────┤ Delay(700[dt]) ├ « ┌─┴─┐ ├────────────────┤ «q_1: ───┤ X ├───┤ Delay(700[dt]) ├ « └─╥─┘ └────────────────┘ «q_2: ─────╫─────────────────────── « ┌────╨────┐ «c: 1/╡ c_0=0x0 ╞══════════════════ « └─────────┘ """ qc = QuantumCircuit(3, 1) qc.delay(100, 0) qc.x(0).c_if(0, 1) qc.barrier() qc.measure(2, 0) qc.x(1).c_if(0, 0) qc.x(0).c_if(0, 0) qc.delay(300, 0) qc.cx(1, 2) qc.x(0) qc.cx(0, 1).c_if(0, 0) qc.measure(2, 0) durations = InstructionDurations([("x", None, 100), ("measure", None, 1000), ("cx", None, 200)]) actual_asap = PassManager([ SetIOLatency(clbit_write_latency=100, conditional_latency=200), ASAPScheduleAnalysis(durations), PadDelay(), ]).run(qc) actual_alap = PassManager([ SetIOLatency(clbit_write_latency=100, conditional_latency=200), ALAPScheduleAnalysis(durations), PadDelay(), ]).run(qc) expected_asap = QuantumCircuit(3, 1) expected_asap.delay(200, 0) # due to conditional latency of 200dt expected_asap.delay(300, 1) expected_asap.delay(300, 2) expected_asap.x(0).c_if(0, 1) expected_asap.barrier() expected_asap.delay(1400, 0) expected_asap.delay(1200, 1) expected_asap.measure(2, 0) expected_asap.x(1).c_if(0, 0) expected_asap.x(0).c_if(0, 0) expected_asap.delay(300, 0) expected_asap.x(0) expected_asap.delay(300, 2) expected_asap.cx(1, 2) expected_asap.delay(400, 1) expected_asap.cx(0, 1).c_if(0, 0) expected_asap.delay(700, 0) # creg is released at t0 of cx(0,1).c_if(0,0) expected_asap.delay( 700, 1 ) # no creg write until 100dt. thus measure can move left by 300dt. expected_asap.delay(300, 2) expected_asap.measure(2, 0) self.assertEqual(expected_asap, actual_asap) self.assertEqual(actual_asap.duration, 3100) expected_alap = QuantumCircuit(3, 1) expected_alap.delay(200, 0) # due to conditional latency of 200dt expected_alap.delay(300, 1) expected_alap.delay(300, 2) expected_alap.x(0).c_if(0, 1) expected_alap.barrier() expected_alap.delay(1400, 0) expected_alap.delay(1200, 1) expected_alap.measure(2, 0) expected_alap.x(1).c_if(0, 0) expected_alap.x(0).c_if(0, 0) expected_alap.delay(300, 0) expected_alap.x(0) expected_alap.delay(300, 1) expected_alap.delay(600, 2) expected_alap.cx(1, 2) expected_alap.delay(100, 1) expected_alap.cx(0, 1).c_if(0, 0) expected_alap.measure(2, 0) expected_alap.delay(700, 0) expected_alap.delay(700, 1) self.assertEqual(expected_alap, actual_alap) self.assertEqual(actual_alap.duration, 3100)
def test_measure_after_c_if_on_edge_locking(self): """Test if ALAP/ASAP schedules circuits with c_if after measure with a common clbit. The scheduler is configured to reproduce behavior of the 0.20.0, in which clbit lock is applied to the end-edge of measure instruction. See https://github.com/Qiskit/qiskit-terra/pull/7655 (input) ┌─┐ q_0: ┤M├────────────── └╥┘ ┌───┐ q_1: ─╫────┤ X ├────── ║ └─╥─┘ ┌─┐ q_2: ─╫──────╫─────┤M├ ║ ┌────╨────┐└╥┘ c: 1/═╩═╡ c_0 = T ╞═╩═ 0 └─────────┘ 0 (ASAP scheduled) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(200[dt]) ├───────────────────── ┌─────────────────┐└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1000[dt]) ├─╫───────┤ X ├──────────────────────────── └─────────────────┘ ║ └─╥─┘ ┌─┐┌────────────────┐ q_2: ────────────────────╫─────────╫─────────┤M├┤ Delay(200[dt]) ├ ║ ┌────╨────┐ └╥┘└────────────────┘ c: 1/════════════════════╩════╡ c_0=0x1 ╞═════╩═══════════════════ 0 └─────────┘ 0 (ALAP scheduled) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(200[dt]) ├─── ┌─────────────────┐└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1000[dt]) ├─╫───────┤ X ├────────── └┬────────────────┤ ║ └─╥─┘ ┌─┐ q_2: ─┤ Delay(200[dt]) ├─╫─────────╫─────────┤M├ └────────────────┘ ║ ┌────╨────┐ └╥┘ c: 1/════════════════════╩════╡ c_0=0x1 ╞═════╩═ 0 └─────────┘ 0 """ qc = QuantumCircuit(3, 1) qc.measure(0, 0) qc.x(1).c_if(0, 1) qc.measure(2, 0) durations = InstructionDurations([("x", None, 200), ("measure", None, 1000)]) # lock at the end edge actual_asap = PassManager([ SetIOLatency(clbit_write_latency=1000), ASAPScheduleAnalysis(durations), PadDelay(), ]).run(qc) actual_alap = PassManager([ SetIOLatency(clbit_write_latency=1000), ALAPScheduleAnalysis(durations), PadDelay(), ]).run(qc) # start times of 2nd measure depends on ASAP/ALAP expected_asap = QuantumCircuit(3, 1) expected_asap.measure(0, 0) expected_asap.delay(1000, 1) expected_asap.x(1).c_if(0, 1) expected_asap.measure(2, 0) expected_asap.delay(200, 0) expected_asap.delay(200, 2) self.assertEqual(expected_asap, actual_asap) expected_alap = QuantumCircuit(3, 1) expected_alap.measure(0, 0) expected_alap.delay(1000, 1) expected_alap.x(1).c_if(0, 1) expected_alap.delay(200, 2) expected_alap.measure(2, 0) expected_alap.delay(200, 0) self.assertEqual(expected_alap, actual_alap)
def test_circuit_using_clbit(self): """Test a circuit with instructions using a common clbit. (input) ┌───┐┌────────────────┐┌─┐ q_0: ┤ X ├┤ Delay(100[dt]) ├┤M├────────────── └───┘└────────────────┘└╥┘ ┌───┐ q_1: ────────────────────────╫────┤ X ├────── ║ └─╥─┘ ┌─┐ q_2: ────────────────────────╫──────╫─────┤M├ ║ ┌────╨────┐└╥┘ c: 1/════════════════════════╩═╡ c_0 = T ╞═╩═ 0 └─────────┘ 0 (aligned) ┌───┐ ┌────────────────┐┌─┐┌────────────────┐ q_0: ───────┤ X ├───────┤ Delay(112[dt]) ├┤M├┤ Delay(160[dt]) ├─── ┌──────┴───┴──────┐└────────────────┘└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1872[dt]) ├───────────────────╫───────┤ X ├────────── └┬────────────────┤ ║ └─╥─┘ ┌─┐ q_2: ─┤ Delay(432[dt]) ├───────────────────╫─────────╫─────────┤M├ └────────────────┘ ║ ┌────╨────┐ └╥┘ c: 1/══════════════════════════════════════╩════╡ c_0 = T ╞═════╩═ 0 └─────────┘ 0 Looking at the q_0, the total schedule length T becomes 160 (x) + 112 (aligned delay) + 1600 (measure) + 160 (delay) = 2032. The last delay comes from ALAP scheduling called before the AlignMeasure pass, which aligns stop times as late as possible, so the start time of x(1).c_if(0) and the stop time of measure(0, 0) become T - 160. """ circuit = QuantumCircuit(3, 1) circuit.x(0) circuit.delay(100, 0, unit="dt") circuit.measure(0, 0) circuit.x(1).c_if(0, 1) circuit.measure(2, 0) pm = PassManager([ # reproduce old behavior of 0.20.0 before #7655 # currently default write latency is 0 SetIOLatency(clbit_write_latency=1600, conditional_latency=0), ALAPScheduleAnalysis(durations=self.instruction_durations), ConstrainedReschedule(acquire_alignment=16), PadDelay(fill_very_end=False), ]) aligned_circuit = pm.run(circuit) self.assertEqual(aligned_circuit.duration, 2032) ref_circuit = QuantumCircuit(3, 1) ref_circuit.x(0) ref_circuit.delay(112, 0, unit="dt") ref_circuit.delay(1872, 1, unit="dt") # 2032 - 160 ref_circuit.delay(432, 2, unit="dt") # 2032 - 1600 ref_circuit.measure(0, 0) ref_circuit.x(1).c_if(0, 1) ref_circuit.measure(2, 0) self.assertEqual(aligned_circuit, ref_circuit)
def test_mid_circuit_multiq_gates(self): """Test circuit with mid circuit measurement and multi qubit gates. (input) ┌───┐┌────────────────┐┌─┐ ┌─┐ q_0: ┤ X ├┤ Delay(100[dt]) ├┤M├──■───────■──┤M├ └───┘└────────────────┘└╥┘┌─┴─┐┌─┐┌─┴─┐└╥┘ q_1: ────────────────────────╫─┤ X ├┤M├┤ X ├─╫─ ║ └───┘└╥┘└───┘ ║ c: 2/════════════════════════╩═══════╩═══════╩═ 0 1 0 (output) ┌───┐ ┌────────────────┐┌─┐ ┌─────────────────┐ ┌─┐» q_0: ───────┤ X ├───────┤ Delay(112[dt]) ├┤M├──■──┤ Delay(1600[dt]) ├──■──┤M├» ┌──────┴───┴──────┐└────────────────┘└╥┘┌─┴─┐└───────┬─┬───────┘┌─┴─┐└╥┘» q_1: ┤ Delay(1872[dt]) ├───────────────────╫─┤ X ├────────┤M├────────┤ X ├─╫─» └─────────────────┘ ║ └───┘ └╥┘ └───┘ ║ » c: 2/══════════════════════════════════════╩═══════════════╩═══════════════╩═» 0 1 0 » « «q_0: ─────────────────── « ┌─────────────────┐ «q_1: ┤ Delay(1600[dt]) ├ « └─────────────────┘ «c: 2/═══════════════════ « Delay for the other channel paired by multi-qubit instruction is also scheduled. Delay (1872dt) = X (160dt) + Delay (100dt + extra 12dt) + Measure (1600dt). """ circuit = QuantumCircuit(2, 2) circuit.x(0) circuit.delay(100, 0, unit="dt") circuit.measure(0, 0) circuit.cx(0, 1) circuit.measure(1, 1) circuit.cx(0, 1) circuit.measure(0, 0) pm = PassManager([ # reproduce old behavior of 0.20.0 before #7655 # currently default write latency is 0 SetIOLatency(clbit_write_latency=1600, conditional_latency=0), ALAPScheduleAnalysis(durations=self.instruction_durations), ConstrainedReschedule(acquire_alignment=16), PadDelay(), ]) aligned_circuit = pm.run(circuit) ref_circuit = QuantumCircuit(2, 2) ref_circuit.x(0) ref_circuit.delay(112, 0, unit="dt") ref_circuit.measure(0, 0) ref_circuit.delay(160 + 112 + 1600, 1, unit="dt") ref_circuit.cx(0, 1) ref_circuit.delay(1600, 0, unit="dt") ref_circuit.measure(1, 1) ref_circuit.cx(0, 1) ref_circuit.delay(1600, 1, unit="dt") ref_circuit.measure(0, 0) self.assertEqual(aligned_circuit, ref_circuit)