diff --git a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py index 706719edf6d2..a1552f91e1b8 100644 --- a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +++ b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py @@ -46,7 +46,7 @@ def __init__(self, durations: InstructionDurations = None, target: Target = None self.durations = target.durations() # Ensure op node durations are attached and in consistent unit - self.requires.append(TimeUnitConversion(durations)) + self.requires.append(TimeUnitConversion(inst_durations=durations, target=target)) # Initialize timeslot if "node_start_time" in self.property_set: diff --git a/test/python/transpiler/test_dynamical_decoupling.py b/test/python/transpiler/test_dynamical_decoupling.py index e7c751b57e44..ca57a82239ed 100644 --- a/test/python/transpiler/test_dynamical_decoupling.py +++ b/test/python/transpiler/test_dynamical_decoupling.py @@ -17,8 +17,8 @@ from numpy import pi from ddt import ddt, data -from qiskit.circuit import QuantumCircuit, Delay -from qiskit.circuit.library import XGate, YGate, RXGate, UGate +from qiskit.circuit import QuantumCircuit, Delay, Measure, Reset, Parameter +from qiskit.circuit.library import XGate, YGate, RXGate, UGate, CXGate, HGate from qiskit.quantum_info import Operator from qiskit.transpiler.instruction_durations import InstructionDurations from qiskit.transpiler.passes import ( @@ -28,8 +28,8 @@ ) from qiskit.transpiler.passmanager import PassManager from qiskit.transpiler.exceptions import TranspilerError - -import qiskit.pulse as pulse +from qiskit.transpiler.target import Target, InstructionProperties +from qiskit import pulse from qiskit.test import QiskitTestCase @@ -143,6 +143,87 @@ def test_insert_dd_ghz(self): self.assertEqual(ghz4_dd, expected) + def test_insert_dd_ghz_with_target(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: ─────────────────────────────────────────────────────────────────────── + « + """ + target = Target(num_qubits=4, dt=1) + target.add_instruction(HGate(), {(0,): InstructionProperties(duration=50)}) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=700), + (1, 2): InstructionProperties(duration=200), + (2, 3): InstructionProperties(duration=300), + }, + ) + target.add_instruction( + XGate(), {(x,): InstructionProperties(duration=50) for x in range(4)} + ) + target.add_instruction( + YGate(), {(x,): InstructionProperties(duration=50) for x in range(4)} + ) + target.add_instruction( + UGate(Parameter("theta"), Parameter("phi"), Parameter("lambda")), + {(x,): InstructionProperties(duration=100) for x in range(4)}, + ) + target.add_instruction( + RXGate(Parameter("theta")), + {(x,): InstructionProperties(duration=100) for x in range(4)}, + ) + target.add_instruction( + Measure(), {(x,): InstructionProperties(duration=1000) for x in range(4)} + ) + target.add_instruction( + Reset(), {(x,): InstructionProperties(duration=1500) for x in range(4)} + ) + dd_sequence = [XGate(), XGate()] + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDynamicalDecoupling(target=target, dd_sequence=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_insert_dd_ghz_one_qubit(self): """Test DD gates are inserted on only one qubit. diff --git a/test/python/transpiler/test_scheduling_padding_pass.py b/test/python/transpiler/test_scheduling_padding_pass.py index bf05f6decaec..bfa968d16e2f 100644 --- a/test/python/transpiler/test_scheduling_padding_pass.py +++ b/test/python/transpiler/test_scheduling_padding_pass.py @@ -12,10 +12,13 @@ """Test the Scheduling/PadDelay passes""" +import math import unittest from ddt import ddt, data, unpack from qiskit import QuantumCircuit +from qiskit.circuit import Measure +from qiskit.circuit.library import CXGate, HGate from qiskit.pulse import Schedule, Play, Constant, DriveChannel from qiskit.test import QiskitTestCase from qiskit.transpiler.instruction_durations import InstructionDurations @@ -27,6 +30,8 @@ ) from qiskit.transpiler.passmanager import PassManager from qiskit.transpiler.exceptions import TranspilerError +from qiskit.transpiler.target import Target, InstructionProperties +from qiskit.providers.fake_provider.fake_backend_v2 import FakeBackendV2 @ddt @@ -55,6 +60,35 @@ def test_alap_agree_with_reverse_asap_reverse(self): self.assertEqual(alap_qc, new_qc) + def test_alap_agree_with_reverse_asap_with_target(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() + + target = Target(num_qubits=2, dt=3.5555555555555554) + target.add_instruction(HGate(), {(0,): InstructionProperties(duration=200)}) + target.add_instruction(CXGate(), {(0, 1): InstructionProperties(duration=700)}) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + + pm = PassManager([ALAPScheduleAnalysis(target=target), PadDelay()]) + alap_qc = pm.run(qc) + + pm = PassManager([ASAPScheduleAnalysis(target=target), 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) + @data(ALAPScheduleAnalysis, ASAPScheduleAnalysis) 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.