def _parse_instruction_durations(backend, inst_durations, dt, circuits): """Create a list of ``InstructionDuration``s. If ``inst_durations`` is provided, the backend will be ignored, otherwise, the durations will be populated from the backend. If any circuits have gate calibrations, those calibration durations would take precedence over backend durations, but be superceded by ``inst_duration``s. """ if not inst_durations: backend_durations = InstructionDurations() try: backend_durations = InstructionDurations.from_backend(backend) except AttributeError: pass durations = [] for circ in circuits: circ_durations = InstructionDurations() if not inst_durations: circ_durations.update(backend_durations, dt or backend_durations.dt) if circ.calibrations: cal_durations = [] for gate, gate_cals in circ.calibrations.items(): for (qubits, _), schedule in gate_cals.items(): cal_durations.append((gate, qubits, schedule.duration)) circ_durations.update(cal_durations, circ_durations.dt) if inst_durations: circ_durations.update(inst_durations, dt or getattr(inst_durations, 'dt', None)) durations.append(circ_durations) return durations
def test_update_with_parameters(self): durations = InstructionDurations( [("rzx", (0, 1), 150, (0.5,)), ("rzx", (0, 1), 300, (1.0,))] ) self.assertEqual(durations.get("rzx", [0, 1], parameters=[0.5]), 150) self.assertEqual(durations.get("rzx", [0, 1], parameters=[1.0]), 300)
def _parse_instruction_durations(backend, inst_durations, dt, scheduling_method, num_circuits): durations = None if scheduling_method is not None: from qiskit.transpiler.instruction_durations import InstructionDurations if backend: durations = InstructionDurations.from_backend(backend).update( inst_durations, dt) else: durations = InstructionDurations(inst_durations, dt) if not isinstance(durations, list): durations = [durations] * num_circuits return durations
def _parse_instruction_durations(backend, inst_durations, dt, num_circuits): durations = None if inst_durations is None and backend: try: backend_durations = InstructionDurations.from_backend(backend) except AttributeError: backend_durations = InstructionDurations() durations = backend_durations.update(None, dt) else: durations = InstructionDurations( inst_durations, dt or getattr(inst_durations, 'dt', None)) if not isinstance(durations, list): durations = [durations] * num_circuits return durations
def from_backend(cls, backend, **pass_manager_options): """Construct a configuration based on a backend and user input. This method automatically gererates a PassManagerConfig object based on the backend's features. User options can be used to overwrite the configuration. Args: backend (BackendV1): The backend that provides the configuration. pass_manager_options: User-defined option-value pairs. Returns: PassManagerConfig: The configuration generated based on the arguments. Raises: AttributeError: If the backend does not support a `configuration()` method. """ res = cls(**pass_manager_options) config = backend.configuration() if res.basis_gates is None: res.basis_gates = getattr(config, "basis_gates", None) if res.inst_map is None and hasattr(backend, "defaults"): res.inst_map = backend.defaults().instruction_schedule_map if res.coupling_map is None: res.coupling_map = CouplingMap( getattr(config, "coupling_map", None)) if res.instruction_durations is None: res.instruction_durations = InstructionDurations.from_backend( backend) if res.backend_properties is None: res.backend_properties = backend.properties() return res
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_unit_seconds_for_users_who_uses_durations_given_by_backend(self): qc = QuantumCircuit(2) qc.h(0) qc.delay(500 * self.dt, 1, 's') qc.cx(0, 1) # usual case scheduled = transpile(qc, backend=self.backend_with_dt, scheduling_method='alap') self.assertEqual(scheduled.duration, 1908) # update durations scheduled = transpile(qc, backend=self.backend_with_dt, scheduling_method='alap', instruction_durations=[('cx', [0, 1], 1000 * self.dt, 's')]) self.assertEqual(scheduled.duration, 1500) my_own_durations = InstructionDurations([('cx', [0, 1], 1000 * self.dt, 's')]) scheduled = transpile( qc, backend=self.backend_with_dt, # unit='s' scheduling_method='alap', instruction_durations=my_own_durations) self.assertEqual(scheduled.duration, 1500)
def test_scheduling_with_calibration(self): """Test if calibrated instruction can update node duration.""" qc = QuantumCircuit(2) qc.x(0) qc.cx(0, 1) qc.x(1) qc.cx(0, 1) xsched = Schedule(Play(Constant(300, 0.1), DriveChannel(0))) qc.add_calibration("x", (0, ), xsched) durations = InstructionDurations([("x", None, 160), ("cx", None, 600)]) pm = PassManager([ASAPScheduleAnalysis(durations), PadDelay()]) scheduled = pm.run(qc) expected = QuantumCircuit(2) expected.x(0) expected.delay(300, 1) expected.cx(0, 1) expected.x(1) expected.delay(160, 0) expected.cx(0, 1) expected.add_calibration("x", (0, ), xsched) self.assertEqual(expected, scheduled)
def test_no_pad_very_end_of_circuit(self): """Test padding option that inserts no delay at the very end of circuit. This circuit will be unchanged after ASAP-schedule/padding. ┌────────────────┐┌─┐ q_0: ┤ Delay(100[dt]) ├┤M├ └─────┬───┬──────┘└╥┘ q_1: ──────┤ X ├────────╫─ └───┘ ║ c: 1/═══════════════════╩═ 0 """ qc = QuantumCircuit(2, 1) qc.delay(100, 0) qc.x(1) qc.measure(0, 0) durations = InstructionDurations([("x", None, 160), ("measure", None, 1000)]) scheduled = PassManager([ ASAPScheduleAnalysis(durations), PadDelay(fill_very_end=False), ]).run(qc) self.assertEqual(scheduled, qc)
def __init__(self, inst_durations: InstructionDurations): """TimeUnitAnalysis initializer. Args: inst_durations (InstructionDurations): A dictionary of durations of instructions. """ super().__init__() self.inst_durations = inst_durations or InstructionDurations()
def test_from_backend_for_backend_without_dt(self): backend = FakeTokyo() gate = self._find_gate_with_length(backend) durations = InstructionDurations.from_backend(backend) self.assertIsNone(durations.dt) self.assertGreater(durations.get(gate, 0, "s"), 0) with self.assertRaises(TranspilerError): durations.get(gate, 0)
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 setUp(self): """Circuits to test DD on. ┌───┐ q_0: ┤ H ├──■──────────── └───┘┌─┴─┐ q_1: ─────┤ X ├──■─────── └───┘┌─┴─┐ q_2: ──────────┤ X ├──■── └───┘┌─┴─┐ q_3: ───────────────┤ X ├ └───┘ ┌──────────┐ q_0: ──■──┤ U(π,0,π) ├──────────■── ┌─┴─┐└──────────┘ ┌─┴─┐ q_1: ┤ X ├─────■───────────■──┤ X ├ └───┘ ┌─┴─┐ ┌─┐┌─┴─┐└───┘ q_2: ────────┤ X ├────┤M├┤ X ├───── └───┘ └╥┘└───┘ c: 1/══════════════════╩═══════════ 0 """ super().setUp() self.ghz4 = QuantumCircuit(4) self.ghz4.h(0) self.ghz4.cx(0, 1) self.ghz4.cx(1, 2) self.ghz4.cx(2, 3) self.midmeas = QuantumCircuit(3, 1) self.midmeas.cx(0, 1) self.midmeas.cx(1, 2) self.midmeas.u(pi, 0, pi, 0) self.midmeas.measure(2, 0) self.midmeas.cx(1, 2) self.midmeas.cx(0, 1) self.durations = InstructionDurations( [ ("h", 0, 50), ("cx", [0, 1], 700), ("cx", [1, 2], 200), ("cx", [2, 3], 300), ("x", None, 50), ("y", None, 50), ("u", None, 100), ("rx", None, 100), ("measure", None, 1000), ("reset", None, 1500), ] )
def test_c_if_on_different_qubits(self, schedule_pass): """Test if ALAP/ASAP schedules circuits with `c_if`s on different qubits. (input) ┌─┐ q_0: ┤M├────────────────────── └╥┘ ┌───┐ q_1: ─╫────┤ X ├────────────── ║ └─╥─┘ ┌───┐ q_2: ─╫──────╫────────┤ X ├─── ║ ║ └─╥─┘ ║ ┌────╨────┐┌────╨────┐ c: 1/═╩═╡ c_0 = T ╞╡ c_0 = T ╞ 0 └─────────┘└─────────┘ (scheduled) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(200[dt]) ├─────────── ┌─────────────────┐└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1000[dt]) ├─╫───────┤ X ├────────────────── ├─────────────────┤ ║ └─╥─┘ ┌───┐ q_2: ┤ Delay(1000[dt]) ├─╫─────────╫────────────┤ X ├─── └─────────────────┘ ║ ║ └─╥─┘ ║ ┌────╨────┐ ┌────╨────┐ c: 1/════════════════════╩════╡ c_0=0x1 ╞════╡ c_0=0x1 ╞ 0 └─────────┘ └─────────┘ """ qc = QuantumCircuit(3, 1) qc.measure(0, 0) qc.x(1).c_if(0, True) qc.x(2).c_if(0, True) durations = InstructionDurations([("x", None, 200), ("measure", None, 1000)]) pm = PassManager([schedule_pass(durations), PadDelay()]) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) expected.measure(0, 0) expected.delay(1000, 1) expected.delay(1000, 2) expected.x(1).c_if(0, True) expected.x(2).c_if(0, True) expected.delay(200, 0) self.assertEqual(expected, scheduled)
def test_measure_after_c_if(self, schedule_pass): """Test if ALAP/ASAP schedules circuits with c_if after measure with a common clbit. (input) ┌─┐ q_0: ┤M├────────────── └╥┘ ┌───┐ q_1: ─╫────┤ X ├────── ║ └─╥─┘ ┌─┐ q_2: ─╫──────╫─────┤M├ ║ ┌────╨────┐└╥┘ c: 1/═╩═╡ c_0 = T ╞═╩═ 0 └─────────┘ 0 (scheduled) ┌─┐┌─────────────────┐ q_0: ───────────────────┤M├┤ Delay(1000[dt]) ├────────────────── ┌─────────────────┐└╥┘└──────┬───┬──────┘┌────────────────┐ q_1: ┤ Delay(1000[dt]) ├─╫────────┤ X ├───────┤ Delay(800[dt]) ├ ├─────────────────┤ ║ └─╥─┘ └──────┬─┬───────┘ q_2: ┤ Delay(1000[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)]) pm = PassManager([schedule_pass(durations), PadDelay()]) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) expected.delay(1000, 1) expected.delay(1000, 2) expected.measure(0, 0) expected.x(1).c_if(0, 1) expected.measure(2, 0) expected.delay(1000, 0) expected.delay(800, 1) self.assertEqual(expected, scheduled)
def test_dag_introduces_extra_dependency_between_conditionals(self): """Test dependency between conditional operations in the scheduling. In the below example circuit, the conditional x on q1 could start at time 0, however it must be scheduled after the conditional x on q0 in ASAP scheduling. That is because circuit model used in the transpiler passes (DAGCircuit) interprets instructions acting on common clbits must be run in the order given by the original circuit (QuantumCircuit). (input) ┌────────────────┐ ┌───┐ q_0: ┤ Delay(100[dt]) ├───┤ X ├─── └─────┬───┬──────┘ └─╥─┘ q_1: ──────┤ X ├────────────╫───── └─╥─┘ ║ ┌────╨────┐ ┌────╨────┐ c: 1/═══╡ c_0=0x1 ╞════╡ c_0=0x1 ╞ └─────────┘ └─────────┘ (ASAP scheduled) ┌────────────────┐ ┌───┐ q_0: ┤ Delay(100[dt]) ├───┤ X ├────────────── ├────────────────┤ └─╥─┘ ┌───┐ q_1: ┤ Delay(100[dt]) ├─────╫────────┤ X ├─── └────────────────┘ ║ └─╥─┘ ┌────╨────┐┌────╨────┐ c: 1/══════════════════╡ c_0=0x1 ╞╡ c_0=0x1 ╞ └─────────┘└─────────┘ """ qc = QuantumCircuit(2, 1) qc.delay(100, 0) qc.x(0).c_if(0, True) qc.x(1).c_if(0, True) durations = InstructionDurations([("x", None, 160)]) pm = PassManager([ASAPScheduleAnalysis(durations), PadDelay()]) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) expected.delay(100, 0) expected.delay(100, 1) # due to extra dependency on clbits expected.x(0).c_if(0, True) expected.x(1).c_if(0, True) self.assertEqual(expected, scheduled)
def durations(self): """Get an InstructionDurations object from the target Returns: InstructionDurations: The instruction duration represented in the target """ if self._instruction_durations is not None: return self._instruction_durations out_durations = [] for instruction, props_map in self._gate_map.items(): for qarg, properties in props_map.items(): if properties is not None and properties.duration is not None: out_durations.append( (instruction, list(qarg), properties.duration, "s")) self._instruction_durations = InstructionDurations(out_durations, dt=self.dt) return self._instruction_durations
def test_durations(self): empty_durations = self.empty_target.durations() self.assertEqual( empty_durations.duration_by_name_qubits, InstructionDurations().duration_by_name_qubits ) aqt_durations = self.aqt_target.durations() self.assertEqual(aqt_durations.duration_by_name_qubits, {}) ibm_durations = self.ibm_target.durations() expected = { ("cx", (0, 1)): (5.1911e-07, "s"), ("cx", (1, 0)): (5.5466e-07, "s"), ("cx", (1, 2)): (2.2755e-07, "s"), ("cx", (1, 3)): (4.9777e-07, "s"), ("cx", (2, 1)): (2.6311e-07, "s"), ("cx", (3, 1)): (4.6222e-07, "s"), ("cx", (3, 4)): (2.7022e-07, "s"), ("cx", (4, 3)): (3.0577e-07, "s"), ("id", (0,)): (3.55e-08, "s"), ("id", (1,)): (3.55e-08, "s"), ("id", (2,)): (3.55e-08, "s"), ("id", (3,)): (3.55e-08, "s"), ("id", (4,)): (3.55e-08, "s"), ("measure", (0,)): (5.813e-06, "s"), ("measure", (1,)): (5.813e-06, "s"), ("measure", (2,)): (5.813e-06, "s"), ("measure", (3,)): (5.813e-06, "s"), ("measure", (4,)): (5.813e-06, "s"), ("rz", (0,)): (0, "s"), ("rz", (1,)): (0, "s"), ("rz", (2,)): (0, "s"), ("rz", (3,)): (0, "s"), ("rz", (4,)): (0, "s"), ("sx", (0,)): (3.55e-08, "s"), ("sx", (1,)): (3.55e-08, "s"), ("sx", (2,)): (3.55e-08, "s"), ("sx", (3,)): (3.55e-08, "s"), ("sx", (4,)): (3.55e-08, "s"), ("x", (0,)): (3.55e-08, "s"), ("x", (1,)): (3.55e-08, "s"), ("x", (2,)): (3.55e-08, "s"), ("x", (3,)): (3.55e-08, "s"), ("x", (4,)): (3.55e-08, "s"), } self.assertEqual(ibm_durations.duration_by_name_qubits, expected)
def test_unit_seconds_when_using_backend_durations(self): qc = QuantumCircuit(2) qc.h(0) qc.delay(500 * self.dt, 1, 's') qc.cx(0, 1) # usual case scheduled = transpile(qc, backend=self.backend_with_dt, scheduling_method='alap') self.assertEqual(scheduled.duration, 1908) # update durations durations = InstructionDurations.from_backend(self.backend_with_dt) durations.update([('cx', [0, 1], 1000 * self.dt, 's')]) scheduled = transpile(qc, backend=self.backend_with_dt, scheduling_method='alap', instruction_durations=durations) self.assertEqual(scheduled.duration, 1500)
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(ALAPSchedule(durations)) alap_qc = pm.run(qc) pm = PassManager(ASAPSchedule(durations)) new_qc = pm.run(qc.reverse_ops()) new_qc = new_qc.reverse_ops() # pylint: disable=no-member new_qc.name = new_qc.name self.assertEqual(alap_qc, new_qc)
def test_measure_after_measure(self, schedule_pass): """Test if ALAP/ASAP schedules circuits with measure after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7006 (input) ┌───┐┌─┐ q_0: ┤ X ├┤M├─── └───┘└╥┘┌─┐ q_1: ──────╫─┤M├ ║ └╥┘ c: 1/══════╩══╩═ 0 0 (scheduled) ┌───┐ ┌─┐ q_0: ──────┤ X ├───────┤M├─── ┌─────┴───┴──────┐└╥┘┌─┐ q_1: ┤ Delay(200[dt]) ├─╫─┤M├ └────────────────┘ ║ └╥┘ c: 1/═══════════════════╩══╩═ 0 0 """ qc = QuantumCircuit(2, 1) qc.x(0) qc.measure(0, 0) qc.measure(1, 0) durations = InstructionDurations([("x", None, 200), ("measure", None, 1000)]) pm = PassManager(schedule_pass(durations)) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) expected.x(0) expected.measure(0, 0) expected.delay( 200, 1) # 2nd measure starts at the same time as 1st measure starts expected.measure(1, 0) self.assertEqual(expected, scheduled)
def test_classically_controlled_gate_after_measure(self, schedule_pass): """Test if ALAP/ASAP schedules circuits with c_if after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7006 (input) ┌─┐ q_0: ┤M├─────────── └╥┘ ┌───┐ q_1: ─╫────┤ X ├─── ║ └─╥─┘ ║ ┌────╨────┐ c: 1/═╩═╡ c_0 = T ╞ 0 └─────────┘ (scheduled) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(200[dt]) ├ ┌─────────────────┐└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1000[dt]) ├─╫───────┤ X ├─────── └─────────────────┘ ║ └─╥─┘ ║ ┌────╨────┐ c: 1/════════════════════╩════╡ c_0 = T ╞════ 0 └─────────┘ """ qc = QuantumCircuit(2, 1) qc.measure(0, 0) qc.x(1).c_if(0, True) durations = InstructionDurations([("x", None, 200), ("measure", None, 1000)]) pm = PassManager(schedule_pass(durations)) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) expected.measure(0, 0) expected.delay(200, 0) expected.delay(1000, 1) # x.c_if starts after measure expected.x(1).c_if(0, True) self.assertEqual(expected, scheduled)
def test_unit_seconds_when_using_backend_durations(self): qc = QuantumCircuit(2) qc.h(0) qc.delay(500 * self.dt, 1, "s") qc.cx(0, 1) # usual case scheduled = transpile( qc, backend=self.backend_with_dt, scheduling_method="alap", layout_method="trivial" ) self.assertEqual(scheduled.duration, 2132) # update durations durations = InstructionDurations.from_backend(self.backend_with_dt) durations.update([("cx", [0, 1], 1000 * self.dt, "s")]) scheduled = transpile( qc, backend=self.backend_with_dt, scheduling_method="alap", instruction_durations=durations, layout_method="trivial", ) self.assertEqual(scheduled.duration, 1500)
def test_shorter_measure_after_measure(self, schedule_pass): """Test if ALAP/ASAP schedules circuits with shorter measure after measure with a common clbit. (input) ┌─┐ q_0: ┤M├─── └╥┘┌─┐ q_1: ─╫─┤M├ ║ └╥┘ c: 1/═╩══╩═ 0 0 (scheduled) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(700[dt]) ├ ┌─────────────────┐└╥┘└──────┬─┬───────┘ q_1: ┤ Delay(1000[dt]) ├─╫────────┤M├──────── └─────────────────┘ ║ └╥┘ c: 1/════════════════════╩═════════╩═════════ 0 0 """ qc = QuantumCircuit(2, 1) qc.measure(0, 0) qc.measure(1, 0) durations = InstructionDurations([("measure", [0], 1000), ("measure", [1], 700)]) pm = PassManager([schedule_pass(durations), PadDelay()]) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) expected.measure(0, 0) expected.delay(1000, 1) expected.measure(1, 0) expected.delay(700, 0) self.assertEqual(expected, scheduled)
def test_fail_if_invalid_dict_is_supplied_when_construction(self): invalid_dic = [('cx', [0, 1])] # no duration with self.assertRaises(TranspilerError): InstructionDurations(invalid_dic)
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_empty(self): durations = InstructionDurations() self.assertEqual(durations.dt, None) with self.assertRaises(TranspilerError): durations.get('cx', [0, 1], 'dt')
def test_from_backend_for_backend_with_dt(self): durations = InstructionDurations.from_backend(FakeParis()) self.assertGreater(durations.dt, 0) self.assertGreater(durations.get('u2', 0), 0)
def test_from_backend_for_backend_without_dt(self): durations = InstructionDurations.from_backend(FakeVigo()) self.assertIsNone(durations.dt) self.assertGreater(durations.get('u2', 0, 's'), 0) with self.assertRaises(TranspilerError): durations.get('u2', 0)
def test_measure_after_c_if(self): """Test if ALAP/ASAP schedules circuits with c_if after measure with a common clbit. (input) ┌─┐ q_0: ┤M├────────────── └╥┘ ┌───┐ q_1: ─╫────┤ X ├────── ║ └─╥─┘ ┌─┐ q_2: ─╫──────╫─────┤M├ ║ ┌────╨────┐└╥┘ c: 1/═╩═╡ c_0 = T ╞═╩═ 0 └─────────┘ 0 (scheduled - ASAP) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(200[dt]) ├───────────────────── ┌─────────────────┐└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1000[dt]) ├─╫───────┤ X ├──────────────────────────── └─────────────────┘ ║ └─╥─┘ ┌─┐┌────────────────┐ q_2: ────────────────────╫─────────╫─────────┤M├┤ Delay(200[dt]) ├ ║ ┌────╨────┐ └╥┘└────────────────┘ c: 1/════════════════════╩════╡ c_0 = T ╞═════╩═══════════════════ 0 └─────────┘ 0 (scheduled - ALAP) ┌─┐┌────────────────┐ q_0: ───────────────────┤M├┤ Delay(200[dt]) ├─── ┌─────────────────┐└╥┘└─────┬───┬──────┘ q_1: ┤ Delay(1000[dt]) ├─╫───────┤ X ├────────── └┬────────────────┤ ║ └─╥─┘ ┌─┐ q_2: ─┤ Delay(200[dt]) ├─╫─────────╫─────────┤M├ └────────────────┘ ║ ┌────╨────┐ └╥┘ c: 1/════════════════════╩════╡ c_0 = T ╞═════╩═ 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)]) actual_asap = PassManager(ASAPSchedule(durations)).run(qc) actual_alap = PassManager(ALAPSchedule(durations)).run(qc) # start times of 2nd measure depends on ASAP/ALAP expected_asap = QuantumCircuit(3, 1) expected_asap.measure(0, 0) expected_asap.delay(200, 0) expected_asap.delay(1000, 1) expected_asap.x(1).c_if(0, 1) expected_asap.measure(2, 0) expected_asap.delay(200, 2) # delay after measure on q_2 self.assertEqual(expected_asap, actual_asap) expected_aslp = QuantumCircuit(3, 1) expected_aslp.measure(0, 0) expected_aslp.delay(200, 0) expected_aslp.delay(1000, 1) expected_aslp.x(1).c_if(0, 1) expected_aslp.delay(200, 2) expected_aslp.measure(2, 0) # delay before measure on q_2 self.assertEqual(expected_aslp, actual_alap)