def test_dd_with_calibrations_with_parameters(self, param_value): """Check that calibrations in a circuit with parameters work fine.""" circ = QuantumCircuit(2) circ.x(0) circ.cx(0, 1) circ.rx(param_value, 1) rx_duration = int(param_value * 1000) with pulse.build() as rx: pulse.play(pulse.Gaussian(rx_duration, 0.1, rx_duration // 4), pulse.DriveChannel(1)) circ.add_calibration("rx", (1, ), rx, params=[param_value]) durations = InstructionDurations([("x", None, 100), ("cx", None, 300)]) dd_sequence = [XGate(), XGate()] pm = PassManager([ ALAPScheduleAnalysis(durations), PadDynamicalDecoupling(durations, dd_sequence) ]) self.assertEqual(pm.run(circ).duration, rx_duration + 100 + 300)
def test_insert_dd_ghz_everywhere(self): """Test DD gates even on initial idle spots. ┌───┐ ┌────────────────┐┌───┐┌────────────────┐┌───┐» q_0: ──────┤ H ├─────────■──┤ Delay(100[dt]) ├┤ Y ├┤ Delay(200[dt]) ├┤ Y ├» ┌─────┴───┴─────┐ ┌─┴─┐└────────────────┘└───┘└────────────────┘└───┘» q_1: ┤ Delay(50[dt]) ├─┤ X ├───────────────────────────────────────────■──» ├───────────────┴┐├───┤┌────────────────┐┌───┐┌────────────────┐┌─┴─┐» q_2: ┤ Delay(162[dt]) ├┤ Y ├┤ Delay(326[dt]) ├┤ Y ├┤ Delay(162[dt]) ├┤ X ├» ├────────────────┤├───┤├────────────────┤├───┤├────────────────┤└───┘» q_3: ┤ Delay(212[dt]) ├┤ Y ├┤ Delay(426[dt]) ├┤ Y ├┤ Delay(212[dt]) ├─────» └────────────────┘└───┘└────────────────┘└───┘└────────────────┘ » « ┌────────────────┐ «q_0: ┤ Delay(100[dt]) ├───────────────────────────────────────────── « ├───────────────┬┘┌───┐┌────────────────┐┌───┐┌───────────────┐ «q_1: ┤ Delay(50[dt]) ├─┤ Y ├┤ Delay(100[dt]) ├┤ Y ├┤ Delay(50[dt]) ├ « └───────────────┘ └───┘└────────────────┘└───┘└───────────────┘ «q_2: ────────■────────────────────────────────────────────────────── « ┌─┴─┐ «q_3: ──────┤ X ├──────────────────────────────────────────────────── « └───┘ """ dd_sequence = [YGate(), YGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, skip_reset_qubits=False), ]) ghz4_dd = pm.run(self.ghz4) expected = self.ghz4.copy() expected = expected.compose(Delay(50), [1], front=True) expected = expected.compose(Delay(162), [2], front=True) expected = expected.compose(YGate(), [2], front=True) expected = expected.compose(Delay(326), [2], front=True) expected = expected.compose(YGate(), [2], front=True) expected = expected.compose(Delay(162), [2], front=True) expected = expected.compose(Delay(212), [3], front=True) expected = expected.compose(YGate(), [3], front=True) expected = expected.compose(Delay(426), [3], front=True) expected = expected.compose(YGate(), [3], front=True) expected = expected.compose(Delay(212), [3], front=True) expected = expected.compose(Delay(100), [0]) expected = expected.compose(YGate(), [0]) expected = expected.compose(Delay(200), [0]) expected = expected.compose(YGate(), [0]) expected = expected.compose(Delay(100), [0]) expected = expected.compose(Delay(50), [1]) expected = expected.compose(YGate(), [1]) expected = expected.compose(Delay(100), [1]) expected = expected.compose(YGate(), [1]) expected = expected.compose(Delay(50), [1]) self.assertEqual(ghz4_dd, expected)
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_insert_dd_bad_sequence(self): """Test DD raises when non-identity sequence is inserted.""" dd_sequence = [XGate(), YGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence), ]) with self.assertRaises(TranspilerError): pm.run(self.ghz4)
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_insert_midmeas_hahn_alap(self): """Test a single X gate as Hahn echo can absorb in the downstream circuit. global phase: 3π/2 ┌────────────────┐ ┌───┐ ┌────────────────┐» q_0: ────────■─────────┤ Delay(625[dt]) ├───────┤ X ├───────┤ Delay(625[dt]) ├» ┌─┴─┐ └────────────────┘┌──────┴───┴──────┐└────────────────┘» q_1: ──────┤ X ├───────────────■─────────┤ Delay(1000[dt]) ├────────■─────────» ┌─────┴───┴──────┐ ┌─┴─┐ └───────┬─┬───────┘ ┌─┴─┐ » q_2: ┤ Delay(700[dt]) ├──────┤ X ├───────────────┤M├──────────────┤ X ├───────» └────────────────┘ └───┘ └╥┘ └───┘ » c: 1/═════════════════════════════════════════════╩═══════════════════════════» 0 » « ┌───────────────┐ «q_0: ┤ U(0,π/2,-π/2) ├───■── « └───────────────┘ ┌─┴─┐ «q_1: ──────────────────┤ X ├ « ┌────────────────┐└───┘ «q_2: ┤ Delay(700[dt]) ├───── « └────────────────┘ «c: 1/═══════════════════════ """ dd_sequence = [XGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence), ]) midmeas_dd = pm.run(self.midmeas) combined_u = UGate(0, pi / 2, -pi / 2) expected = QuantumCircuit(3, 1) expected.cx(0, 1) expected.delay(625, 0) expected.x(0) expected.delay(625, 0) expected.compose(combined_u, [0], inplace=True) expected.delay(700, 2) expected.cx(1, 2) expected.delay(1000, 1) expected.measure(2, 0) expected.cx(1, 2) expected.cx(0, 1) expected.delay(700, 2) expected.global_phase = 4.71238898038469 self.assertEqual(midmeas_dd, expected) # check the absorption into U was done correctly self.assertEqual(Operator(combined_u), Operator(XGate()) & Operator(XGate()))
def test_insert_dd_ghz_one_qubit(self): """Test DD gates are inserted on only one qubit. ┌───┐ ┌────────────────┐ ┌───┐ » q_0: ──────┤ H ├─────────■──┤ Delay(100[dt]) ├──────┤ X ├───────» ┌─────┴───┴─────┐ ┌─┴─┐└────────────────┘┌─────┴───┴──────┐» q_1: ┤ Delay(50[dt]) ├─┤ X ├────────■─────────┤ Delay(300[dt]) ├» ├───────────────┴┐└───┘ ┌─┴─┐ └────────────────┘» q_2: ┤ Delay(750[dt]) ├───────────┤ X ├───────────────■─────────» ├────────────────┤ └───┘ ┌─┴─┐ » q_3: ┤ Delay(950[dt]) ├─────────────────────────────┤ X ├───────» └────────────────┘ └───┘ » meas: 4/═══════════════════════════════════════════════════════════» » « ┌────────────────┐┌───┐┌────────────────┐ ░ ┌─┐ « q_0: ┤ Delay(200[dt]) ├┤ X ├┤ Delay(100[dt]) ├─░─┤M├───────── « └────────────────┘└───┘└────────────────┘ ░ └╥┘┌─┐ « q_1: ──────────────────────────────────────────░──╫─┤M├────── « ░ ║ └╥┘┌─┐ « q_2: ──────────────────────────────────────────░──╫──╫─┤M├─── « ░ ║ ║ └╥┘┌─┐ « q_3: ──────────────────────────────────────────░──╫──╫──╫─┤M├ « ░ ║ ║ ║ └╥┘ «meas: 4/═════════════════════════════════════════════╩══╩══╩══╩═ « 0 1 2 3 """ dd_sequence = [XGate(), XGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0]), ]) ghz4_dd = pm.run(self.ghz4.measure_all(inplace=False)) expected = self.ghz4.copy() expected = expected.compose(Delay(50), [1], front=True) expected = expected.compose(Delay(750), [2], front=True) expected = expected.compose(Delay(950), [3], front=True) expected = expected.compose(Delay(100), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(200), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(100), [0]) expected = expected.compose(Delay(300), [1]) expected.measure_all() self.assertEqual(ghz4_dd, expected)
def test_dd_can_sequentially_called(self): """Test if sequentially called DD pass can output the same circuit. This test verifies: - if global phase is properly propagated from the previous padding node. - if node_start_time property is properly updated for new dag circuit. """ dd_sequence = [XGate(), YGate(), XGate(), YGate()] pm1 = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0]), PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[1]), ]) circ1 = pm1.run(self.ghz4) pm2 = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0, 1]), ]) circ2 = pm2.run(self.ghz4) self.assertEqual(circ1, circ2)
def test_insert_dd_ghz(self): """Test DD gates are inserted in correct spots. ┌───┐ ┌────────────────┐ ┌───┐ » q_0: ──────┤ H ├─────────■──┤ Delay(100[dt]) ├──────┤ X ├──────» ┌─────┴───┴─────┐ ┌─┴─┐└────────────────┘┌─────┴───┴─────┐» q_1: ┤ Delay(50[dt]) ├─┤ X ├────────■─────────┤ Delay(50[dt]) ├» ├───────────────┴┐└───┘ ┌─┴─┐ └───────────────┘» q_2: ┤ Delay(750[dt]) ├───────────┤ X ├───────────────■────────» ├────────────────┤ └───┘ ┌─┴─┐ » q_3: ┤ Delay(950[dt]) ├─────────────────────────────┤ X ├──────» └────────────────┘ └───┘ » « ┌────────────────┐ ┌───┐ ┌────────────────┐ «q_0: ┤ Delay(200[dt]) ├──────┤ X ├───────┤ Delay(100[dt]) ├───────────────── « └─────┬───┬──────┘┌─────┴───┴──────┐└─────┬───┬──────┘┌───────────────┐ «q_1: ──────┤ X ├───────┤ Delay(100[dt]) ├──────┤ X ├───────┤ Delay(50[dt]) ├ « └───┘ └────────────────┘ └───┘ └───────────────┘ «q_2: ─────────────────────────────────────────────────────────────────────── « «q_3: ─────────────────────────────────────────────────────────────────────── « """ dd_sequence = [XGate(), XGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence), ]) ghz4_dd = pm.run(self.ghz4) expected = self.ghz4.copy() expected = expected.compose(Delay(50), [1], front=True) expected = expected.compose(Delay(750), [2], front=True) expected = expected.compose(Delay(950), [3], front=True) expected = expected.compose(Delay(100), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(200), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(100), [0]) expected = expected.compose(Delay(50), [1]) expected = expected.compose(XGate(), [1]) expected = expected.compose(Delay(100), [1]) expected = expected.compose(XGate(), [1]) expected = expected.compose(Delay(50), [1]) self.assertEqual(ghz4_dd, expected)
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_asymmetric_xy4_in_t2(self): """Test insertion of XY4 sequence with unbalanced spacing. global phase: π ┌───┐┌───┐┌────────────────┐┌───┐┌────────────────┐┌───┐┌────────────────┐» q_0: ┤ H ├┤ X ├┤ Delay(450[dt]) ├┤ Y ├┤ Delay(450[dt]) ├┤ X ├┤ Delay(450[dt]) ├» └───┘└───┘└────────────────┘└───┘└────────────────┘└───┘└────────────────┘» « ┌───┐┌────────────────┐┌───┐ «q_0: ┤ Y ├┤ Delay(450[dt]) ├┤ H ├ « └───┘└────────────────┘└───┘ """ dd_sequence = [XGate(), YGate()] * 2 spacing = [0] + [1 / 4] * 4 pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, spacing=spacing), ]) t2 = QuantumCircuit(1) t2.h(0) t2.delay(2000, 0) t2.h(0) expected = QuantumCircuit(1) expected.h(0) expected.x(0) expected.delay(450, 0) expected.y(0) expected.delay(450, 0) expected.x(0) expected.delay(450, 0) expected.y(0) expected.delay(450, 0) expected.h(0) expected.global_phase = pi t2_dd = pm.run(t2) self.assertEqual(t2_dd, expected) # check global phase is correct self.assertEqual(Operator(t2), Operator(expected))
def test_alap_agree_with_reverse_asap_reverse(self): """Test if ALAP schedule agrees with doubly-reversed ASAP schedule.""" qc = QuantumCircuit(2) qc.h(0) qc.delay(500, 1) qc.cx(0, 1) qc.measure_all() durations = InstructionDurations([("h", 0, 200), ("cx", [0, 1], 700), ("measure", None, 1000)]) pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay()]) alap_qc = pm.run(qc) pm = PassManager([ASAPScheduleAnalysis(durations), PadDelay()]) new_qc = pm.run(qc.reverse_ops()) new_qc = new_qc.reverse_ops() new_qc.name = new_qc.name self.assertEqual(alap_qc, new_qc)
def test_dd_after_reset(self): """Test skip_reset_qubits option works. ┌─────────────────┐┌───┐┌────────────────┐┌───┐┌─────────────────┐» q_0: ─|0>─┤ Delay(1000[dt]) ├┤ H ├┤ Delay(190[dt]) ├┤ X ├┤ Delay(1710[dt]) ├» └─────────────────┘└───┘└────────────────┘└───┘└─────────────────┘» « ┌───┐┌───┐ «q_0: ┤ X ├┤ H ├ « └───┘└───┘ """ dd_sequence = [XGate(), XGate()] spacing = [0.1, 0.9] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, spacing=spacing, skip_reset_qubits=True), ]) t2 = QuantumCircuit(1) t2.reset(0) t2.delay(1000) t2.h(0) t2.delay(2000, 0) t2.h(0) expected = QuantumCircuit(1) expected.reset(0) expected.delay(1000) expected.h(0) expected.delay(190, 0) expected.x(0) expected.delay(1710, 0) expected.x(0) expected.h(0) t2_dd = pm.run(t2) self.assertEqual(t2_dd, expected)
def test_both_pulse_and_acquire_alignment(self): """Test when both acquire and pulse alignment are specified. (input) ┌────────────────┐┌───┐┌───────────────┐┌─┐ q: ┤ Delay(100[dt]) ├┤ X ├┤ Delay(10[dt]) ├┤M├ └────────────────┘└───┘└───────────────┘└╥┘ c: 1/═════════════════════════════════════════╩═ 0 (aligned) ┌────────────────┐┌───┐┌───────────────┐┌─┐ q: ┤ Delay(112[dt]) ├┤ X ├┤ Delay(16[dt]) ├┤M├ └────────────────┘└───┘└───────────────┘└╥┘ c: 1/═════════════════════════════════════════╩═ 0 """ pm = PassManager([ ALAPScheduleAnalysis(durations=self.instruction_durations), ConstrainedReschedule(pulse_alignment=16, acquire_alignment=16), PadDelay(fill_very_end=False), ]) circuit = QuantumCircuit(1, 1) circuit.delay(100, 0, unit="dt") circuit.x(0) circuit.delay(10, 0, unit="dt") circuit.measure(0, 0) ref_circ = QuantumCircuit(1, 1) ref_circ.delay(112, 0, unit="dt") ref_circ.x(0) ref_circ.delay(16, 0, unit="dt") ref_circ.measure(0, 0) self.assertEqual(pm.run(circuit), ref_circ)
def test_insert_dd_ghz_xy4_with_alignment(self): """Test DD with pulse alignment constraints. ┌───┐ ┌───────────────┐ ┌───┐ ┌───────────────┐» q_0: ──────┤ H ├─────────■──┤ Delay(40[dt]) ├──────┤ X ├──────┤ Delay(70[dt]) ├» ┌─────┴───┴─────┐ ┌─┴─┐└───────────────┘┌─────┴───┴─────┐└─────┬───┬─────┘» q_1: ┤ Delay(50[dt]) ├─┤ X ├────────■────────┤ Delay(20[dt]) ├──────┤ X ├──────» ├───────────────┴┐└───┘ ┌─┴─┐ └───────────────┘ └───┘ » q_2: ┤ Delay(750[dt]) ├───────────┤ X ├──────────────■─────────────────────────» ├────────────────┤ └───┘ ┌─┴─┐ » q_3: ┤ Delay(950[dt]) ├────────────────────────────┤ X ├───────────────────────» └────────────────┘ └───┘ » « ┌───┐ ┌───────────────┐ ┌───┐ ┌───────────────┐» «q_0: ──────┤ Y ├──────┤ Delay(70[dt]) ├──────┤ X ├──────┤ Delay(70[dt]) ├» « ┌─────┴───┴─────┐└─────┬───┬─────┘┌─────┴───┴─────┐└─────┬───┬─────┘» «q_1: ┤ Delay(20[dt]) ├──────┤ Y ├──────┤ Delay(20[dt]) ├──────┤ X ├──────» « └───────────────┘ └───┘ └───────────────┘ └───┘ » «q_2: ────────────────────────────────────────────────────────────────────» « » «q_3: ────────────────────────────────────────────────────────────────────» « » « ┌───┐ ┌───────────────┐ «q_0: ──────┤ Y ├──────┤ Delay(50[dt]) ├───────────────── « ┌─────┴───┴─────┐└─────┬───┬─────┘┌───────────────┐ «q_1: ┤ Delay(20[dt]) ├──────┤ Y ├──────┤ Delay(20[dt]) ├ « └───────────────┘ └───┘ └───────────────┘ «q_2: ─────────────────────────────────────────────────── « «q_3: ─────────────────────────────────────────────────── « """ dd_sequence = [XGate(), YGate(), XGate(), YGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling( self.durations, dd_sequence, pulse_alignment=10, extra_slack_distribution="edges", ), ]) ghz4_dd = pm.run(self.ghz4) expected = self.ghz4.copy() expected = expected.compose(Delay(50), [1], front=True) expected = expected.compose(Delay(750), [2], front=True) expected = expected.compose(Delay(950), [3], front=True) expected = expected.compose(Delay(40), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(70), [0]) expected = expected.compose(YGate(), [0]) expected = expected.compose(Delay(70), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(70), [0]) expected = expected.compose(YGate(), [0]) expected = expected.compose(Delay(50), [0]) expected = expected.compose(Delay(20), [1]) expected = expected.compose(XGate(), [1]) expected = expected.compose(Delay(20), [1]) expected = expected.compose(YGate(), [1]) expected = expected.compose(Delay(20), [1]) expected = expected.compose(XGate(), [1]) expected = expected.compose(Delay(20), [1]) expected = expected.compose(YGate(), [1]) expected = expected.compose(Delay(20), [1]) self.assertEqual(ghz4_dd, expected)
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_insert_ghz_uhrig(self): """Test custom spacing (following Uhrig DD [1]). [1] Uhrig, G. "Keeping a quantum bit alive by optimized π-pulse sequences." Physical Review Letters 98.10 (2007): 100504. ┌───┐ ┌──────────────┐ ┌───┐ ┌──────────────┐┌───┐» q_0: ──────┤ H ├─────────■──┤ Delay(3[dt]) ├──────┤ X ├───────┤ Delay(8[dt]) ├┤ X ├» ┌─────┴───┴─────┐ ┌─┴─┐└──────────────┘┌─────┴───┴──────┐└──────────────┘└───┘» q_1: ┤ Delay(50[dt]) ├─┤ X ├───────■────────┤ Delay(300[dt]) ├─────────────────────» ├───────────────┴┐└───┘ ┌─┴─┐ └────────────────┘ » q_2: ┤ Delay(750[dt]) ├──────────┤ X ├──────────────■──────────────────────────────» ├────────────────┤ └───┘ ┌─┴─┐ » q_3: ┤ Delay(950[dt]) ├───────────────────────────┤ X ├────────────────────────────» └────────────────┘ └───┘ » « ┌───────────────┐┌───┐┌───────────────┐┌───┐┌───────────────┐┌───┐┌───────────────┐» «q_0: ┤ Delay(13[dt]) ├┤ X ├┤ Delay(16[dt]) ├┤ X ├┤ Delay(20[dt]) ├┤ X ├┤ Delay(16[dt]) ├» « └───────────────┘└───┘└───────────────┘└───┘└───────────────┘└───┘└───────────────┘» «q_1: ───────────────────────────────────────────────────────────────────────────────────» « » «q_2: ───────────────────────────────────────────────────────────────────────────────────» « » «q_3: ───────────────────────────────────────────────────────────────────────────────────» « » « ┌───┐┌───────────────┐┌───┐┌──────────────┐┌───┐┌──────────────┐ «q_0: ┤ X ├┤ Delay(13[dt]) ├┤ X ├┤ Delay(8[dt]) ├┤ X ├┤ Delay(3[dt]) ├ « └───┘└───────────────┘└───┘└──────────────┘└───┘└──────────────┘ «q_1: ──────────────────────────────────────────────────────────────── « «q_2: ──────────────────────────────────────────────────────────────── « «q_3: ──────────────────────────────────────────────────────────────── « """ n = 8 dd_sequence = [XGate()] * n # uhrig specifies the location of the k'th pulse def uhrig(k): return np.sin(np.pi * (k + 1) / (2 * n + 2))**2 # convert that to spacing between pulses (whatever finite duration pulses have) spacing = [] for k in range(n): spacing.append(uhrig(k) - sum(spacing)) spacing.append(1 - sum(spacing)) pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0], spacing=spacing), ]) ghz4_dd = pm.run(self.ghz4) expected = self.ghz4.copy() expected = expected.compose(Delay(50), [1], front=True) expected = expected.compose(Delay(750), [2], front=True) expected = expected.compose(Delay(950), [3], front=True) expected = expected.compose(Delay(3), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(8), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(13), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(16), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(20), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(16), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(13), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(8), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(3), [0]) expected = expected.compose(Delay(300), [1]) self.assertEqual(ghz4_dd, expected)
def test_insert_dd_ghz_xy4(self): """Test XY4 sequence of DD gates. ┌───┐ ┌───────────────┐ ┌───┐ ┌───────────────┐» q_0: ──────┤ H ├─────────■──┤ Delay(37[dt]) ├──────┤ X ├──────┤ Delay(75[dt]) ├» ┌─────┴───┴─────┐ ┌─┴─┐└───────────────┘┌─────┴───┴─────┐└─────┬───┬─────┘» q_1: ┤ Delay(50[dt]) ├─┤ X ├────────■────────┤ Delay(12[dt]) ├──────┤ X ├──────» ├───────────────┴┐└───┘ ┌─┴─┐ └───────────────┘ └───┘ » q_2: ┤ Delay(750[dt]) ├───────────┤ X ├──────────────■─────────────────────────» ├────────────────┤ └───┘ ┌─┴─┐ » q_3: ┤ Delay(950[dt]) ├────────────────────────────┤ X ├───────────────────────» └────────────────┘ └───┘ » « ┌───┐ ┌───────────────┐ ┌───┐ ┌───────────────┐» «q_0: ──────┤ Y ├──────┤ Delay(76[dt]) ├──────┤ X ├──────┤ Delay(75[dt]) ├» « ┌─────┴───┴─────┐└─────┬───┬─────┘┌─────┴───┴─────┐└─────┬───┬─────┘» «q_1: ┤ Delay(25[dt]) ├──────┤ Y ├──────┤ Delay(26[dt]) ├──────┤ X ├──────» « └───────────────┘ └───┘ └───────────────┘ └───┘ » «q_2: ────────────────────────────────────────────────────────────────────» « » «q_3: ────────────────────────────────────────────────────────────────────» « » « ┌───┐ ┌───────────────┐ «q_0: ──────┤ Y ├──────┤ Delay(37[dt]) ├───────────────── « ┌─────┴───┴─────┐└─────┬───┬─────┘┌───────────────┐ «q_1: ┤ Delay(25[dt]) ├──────┤ Y ├──────┤ Delay(12[dt]) ├ « └───────────────┘ └───┘ └───────────────┘ «q_2: ─────────────────────────────────────────────────── « «q_3: ─────────────────────────────────────────────────── """ dd_sequence = [XGate(), YGate(), XGate(), YGate()] pm = PassManager([ ALAPScheduleAnalysis(self.durations), PadDynamicalDecoupling(self.durations, dd_sequence), ]) ghz4_dd = pm.run(self.ghz4) expected = self.ghz4.copy() expected = expected.compose(Delay(50), [1], front=True) expected = expected.compose(Delay(750), [2], front=True) expected = expected.compose(Delay(950), [3], front=True) expected = expected.compose(Delay(37), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(75), [0]) expected = expected.compose(YGate(), [0]) expected = expected.compose(Delay(76), [0]) expected = expected.compose(XGate(), [0]) expected = expected.compose(Delay(75), [0]) expected = expected.compose(YGate(), [0]) expected = expected.compose(Delay(37), [0]) expected = expected.compose(Delay(12), [1]) expected = expected.compose(XGate(), [1]) expected = expected.compose(Delay(25), [1]) expected = expected.compose(YGate(), [1]) expected = expected.compose(Delay(26), [1]) expected = expected.compose(XGate(), [1]) expected = expected.compose(Delay(25), [1]) expected = expected.compose(YGate(), [1]) expected = expected.compose(Delay(12), [1]) self.assertEqual(ghz4_dd, expected)
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)
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_parallel_gate_different_length_with_barrier(self): """Test circuit having two parallel instruction with different length with barrier. (input) ┌───┐┌─┐ q_0: ┤ X ├┤M├─── ├───┤└╥┘┌─┐ q_1: ┤ X ├─╫─┤M├ └───┘ ║ └╥┘ c: 2/══════╩══╩═ 0 1 (expected, ALAP) ┌────────────────┐┌───┐ ░ ┌─┐ q_0: ┤ Delay(200[dt]) ├┤ X ├─░─┤M├─── └─────┬───┬──────┘└───┘ ░ └╥┘┌─┐ q_1: ──────┤ X ├─────────────░──╫─┤M├ └───┘ ░ ║ └╥┘ c: 2/═══════════════════════════╩══╩═ 0 1 (expected, ASAP) ┌───┐┌────────────────┐ ░ ┌─┐ q_0: ┤ X ├┤ Delay(200[dt]) ├─░─┤M├─── ├───┤└────────────────┘ ░ └╥┘┌─┐ q_1: ┤ X ├───────────────────░──╫─┤M├ └───┘ ░ ║ └╥┘ c: 2/═══════════════════════════╩══╩═ 0 1 """ qc = QuantumCircuit(2, 2) qc.x(0) qc.x(1) qc.barrier() qc.measure(0, 0) qc.measure(1, 1) durations = InstructionDurations([("x", [0], 200), ("x", [1], 400), ("measure", None, 1000)]) pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay()]) qc_alap = pm.run(qc) alap_expected = QuantumCircuit(2, 2) alap_expected.delay(200, 0) alap_expected.x(0) alap_expected.x(1) alap_expected.barrier() alap_expected.measure(0, 0) alap_expected.measure(1, 1) self.assertEqual(qc_alap, alap_expected) pm = PassManager([ASAPScheduleAnalysis(durations), PadDelay()]) qc_asap = pm.run(qc) asap_expected = QuantumCircuit(2, 2) asap_expected.x(0) asap_expected.delay(200, 0) asap_expected.x(1) asap_expected.barrier() asap_expected.measure(0, 0) asap_expected.measure(1, 1) self.assertEqual(qc_asap, asap_expected)
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)