예제 #1
0
 def add_delay_to_dag(self, duration, dag, qargs, cargs):
     if self.delay_quantum:
         number_of_delays = int(duration / self.delay_quantum)
         for ii in range(number_of_delays):
             dag.apply_operation_back(Delay(self.delay_quantum), qargs,
                                      cargs)
     else:
         dag.apply_operation_back(Delay(duration), qargs, cargs)
예제 #2
0
 def test_add_delay_on_single_qubit_to_circuit(self):
     qc = QuantumCircuit(1)
     qc.h(0)
     qc.delay(100, 0)
     qc.delay(200, [0])
     qc.delay(300, qc.qubits[0])
     self.assertEqual(qc.data[1], (Delay(duration=100), qc.qubits, []))
     self.assertEqual(qc.data[2], (Delay(duration=200), qc.qubits, []))
     self.assertEqual(qc.data[3], (Delay(duration=300), qc.qubits, []))
    def setUp(self) -> None:
        """Setup."""
        super().setUp()

        self.qubit = list(qiskit.QuantumRegister(1))[0]

        self.u1 = types.ScheduledGate(t0=100,
                                      operand=library.U1Gate(0),
                                      duration=0,
                                      bits=[self.qubit],
                                      bit_position=0)

        self.u3 = types.ScheduledGate(t0=100,
                                      operand=library.U3Gate(0, 0, 0),
                                      duration=20,
                                      bits=[self.qubit],
                                      bit_position=0)

        self.delay = types.ScheduledGate(t0=100,
                                         operand=Delay(20),
                                         duration=20,
                                         bits=[self.qubit],
                                         bit_position=0)

        style = stylesheet.QiskitTimelineStyle()
        self.formatter = style.formatter
예제 #4
0
 def pad_with_delays(qubits: List[int], until, unit) -> None:
     """Pad idle time-slots in ``qubits`` with delays in ``unit`` until ``until``."""
     for q in qubits:
         if qubit_time_available[q] < until:
             idle_duration = until - qubit_time_available[q]
             new_dag.apply_operation_back(Delay(idle_duration, unit),
                                          [q])
    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)
예제 #6
0
    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(
            [
                ALAPSchedule(self.durations),
                DynamicalDecoupling(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_interleaving_delay(self):
        """Test delay instruction can be interleaved."""
        # See qiskit-experiments/#727 for details
        interleaved_element = Delay(10, unit="us")
        exp = rb.InterleavedRB(
            interleaved_element,
            qubits=[0],
            lengths=[1],
            num_samples=1,
        )
        # Not raises an error
        _, int_circ = exp.circuits()

        # barrier, clifford, barrier, "delay", barrier, ...
        self.assertEqual(int_circ.data[3][0], interleaved_element)
    def _deprecate_id_instruction(
        self, circuits: Union[QasmQobj, PulseQobj, QuantumCircuit, Schedule,
                              List[Union[QuantumCircuit, Schedule]]]
    ) -> None:
        """Raise a DeprecationWarning if any circuit contains an 'id' instruction.

        Additionally, if 'delay' is a 'supported_instruction', replace each 'id'
        instruction (in-place) with the equivalent ('sx'-length) 'delay' instruction.

        Args:
            circuits: The individual or list of :class:`~qiskit.circuits.QuantumCircuit` or
                :class:`~qiskit.pulse.Schedule` objects passed to
                :meth:`IBMQBackend.run()<IBMQBackend.run>`. Modified in-place.

        Returns:
            None
        """

        if isinstance(circuits, PulseQobj):
            return

        id_support = 'id' in getattr(self.configuration(), 'basis_gates', [])
        delay_support = 'delay' in getattr(self.configuration(),
                                           'supported_instructions', [])

        if not delay_support:
            return

        if isinstance(circuits, QasmQobj):
            circuit_has_id = any(instr.name == 'id'
                                 for experiment in circuits.experiments
                                 for instr in experiment.instructions)
        else:
            if not isinstance(circuits, List):
                circuits = [circuits]

            circuit_has_id = any(instr.name == 'id' for circuit in circuits
                                 if isinstance(circuit, QuantumCircuit)
                                 for instr, qargs, cargs in circuit.data)

        if not circuit_has_id:
            return

        if not self.id_warning_issued:
            if id_support and delay_support:
                warnings.warn(
                    "Support for the 'id' instruction has been deprecated "
                    "from IBM hardware backends. Any 'id' instructions "
                    "will be replaced with their equivalent 'delay' instruction. "
                    "Please use the 'delay' instruction instead.",
                    DeprecationWarning,
                    stacklevel=4)
            else:
                warnings.warn(
                    "Support for the 'id' instruction has been removed "
                    "from IBM hardware backends. Any 'id' instructions "
                    "will be replaced with their equivalent 'delay' instruction. "
                    "Please use the 'delay' instruction instead.",
                    DeprecationWarning,
                    stacklevel=4)

            self.id_warning_issued = True

        dt_in_s = self.configuration().dt

        if isinstance(circuits, QasmQobj):
            for experiment in circuits.experiments:
                for instr in experiment.instructions:
                    if instr.name == 'id':
                        sx_duration = self.properties().gate_length(
                            'sx', instr.qubits[0])
                        sx_duration_in_dt = duration_in_dt(
                            sx_duration, dt_in_s)

                        instr.name = 'delay'
                        instr.params = [sx_duration_in_dt]
        else:
            for circuit in circuits:
                if isinstance(circuit, Schedule):
                    continue

                for idx, (instr, qargs, cargs) in enumerate(circuit.data):
                    if instr.name == 'id':

                        sx_duration = self.properties().gate_length(
                            'sx', qargs[0].index)
                        sx_duration_in_dt = duration_in_dt(
                            sx_duration, dt_in_s)

                        delay_instr = Delay(sx_duration_in_dt)

                        circuit.data[idx] = (delay_instr, qargs, cargs)
예제 #9
0
    def run(self, dag):
        """Run the ASAPSchedule pass on `dag`.

        Args:
            dag (DAGCircuit): DAG to schedule.

        Returns:
            DAGCircuit: A scheduled DAG.

        Raises:
            TranspilerError: if the circuit is not mapped on physical qubits.
            TranspilerError: if conditional bit is added to non-supported instruction.
        """
        if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None:
            raise TranspilerError(
                "ASAP schedule runs on physical circuits only")

        time_unit = self.property_set["time_unit"]

        new_dag = DAGCircuit()
        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        idle_after = {q: 0 for q in dag.qubits + dag.clbits}
        bit_indices = {q: index for index, q in enumerate(dag.qubits)}
        for node in dag.topological_op_nodes():
            op_duration = self._get_node_duration(node, bit_indices, dag)

            # compute t0, t1: instruction interval, note that
            # t0: start time of instruction
            # t1: end time of instruction
            if isinstance(node.op, self.CONDITIONAL_SUPPORTED):
                t0q = max(idle_after[q] for q in node.qargs)
                if node.op.condition_bits:
                    # conditional is bit tricky due to conditional_latency
                    t0c = max(idle_after[bit]
                              for bit in node.op.condition_bits)
                    if t0q > t0c:
                        # This is situation something like below
                        #
                        #           |t0q
                        # Q ▒▒▒▒▒▒▒▒▒░░
                        # C ▒▒▒░░░░░░░░
                        #     |t0c
                        #
                        # In this case, you can insert readout access before tq0
                        #
                        #           |t0q
                        # Q ▒▒▒▒▒▒▒▒▒▒▒
                        # C ▒▒▒░░░▒▒░░░
                        #         |t0q - conditional_latency
                        #
                        t0c = max(t0q - self.conditional_latency, t0c)
                    t1c = t0c + self.conditional_latency
                    for bit in node.op.condition_bits:
                        # Lock clbit until state is read
                        idle_after[bit] = t1c
                    # It starts after register read access
                    t0 = max(t0q, t1c)
                else:
                    t0 = t0q
                t1 = t0 + op_duration
            else:
                if node.op.condition_bits:
                    raise TranspilerError(
                        f"Conditional instruction {node.op.name} is not supported in ASAP scheduler."
                    )

                if isinstance(node.op, Measure):
                    # measure instruction handling is bit tricky due to clbit_write_latency
                    t0q = max(idle_after[q] for q in node.qargs)
                    t0c = max(idle_after[c] for c in node.cargs)
                    # Assume following case (t0c > t0q)
                    #
                    #       |t0q
                    # Q ▒▒▒▒░░░░░░░░░░░░
                    # C ▒▒▒▒▒▒▒▒░░░░░░░░
                    #           |t0c
                    #
                    # In this case, there is no actual clbit access until clbit_write_latency.
                    # The node t0 can be push backward by this amount.
                    #
                    #         |t0q' = t0c - clbit_write_latency
                    # Q ▒▒▒▒░░▒▒▒▒▒▒▒▒▒▒
                    # C ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
                    #           |t0c' = t0c
                    #
                    # rather than naively doing
                    #
                    #           |t0q' = t0c
                    # Q ▒▒▒▒░░░░▒▒▒▒▒▒▒▒
                    # C ▒▒▒▒▒▒▒▒░░░▒▒▒▒▒
                    #              |t0c' = t0c + clbit_write_latency
                    #
                    t0 = max(t0q, t0c - self.clbit_write_latency)
                    t1 = t0 + op_duration
                    for clbit in node.cargs:
                        idle_after[clbit] = t1
                else:
                    # It happens to be directives such as barrier
                    t0 = max(idle_after[bit]
                             for bit in node.qargs + node.cargs)
                    t1 = t0 + op_duration

            # Add delay to qubit wire
            for bit in node.qargs:
                delta = t0 - idle_after[bit]
                if delta > 0 and isinstance(bit, Qubit):
                    new_dag.apply_operation_back(Delay(delta, time_unit),
                                                 [bit], [])
                idle_after[bit] = t1

            new_dag.apply_operation_back(node.op, node.qargs, node.cargs)

        circuit_duration = max(idle_after.values())
        for bit, after in idle_after.items():
            delta = circuit_duration - after
            if not (delta > 0 and isinstance(bit, Qubit)):
                continue
            new_dag.apply_operation_back(Delay(delta, time_unit), [bit], [])

        new_dag.name = dag.name
        new_dag.metadata = dag.metadata
        new_dag.calibrations = dag.calibrations

        # set circuit duration and unit to indicate it is scheduled
        new_dag.duration = circuit_duration
        new_dag.unit = time_unit
        return new_dag
예제 #10
0
    def _deprecate_id_instruction(
        self,
        circuits: Union[QuantumCircuit, Schedule, List[Union[QuantumCircuit,
                                                             Schedule]]],
    ) -> Union[QuantumCircuit, Schedule, List[Union[QuantumCircuit,
                                                    Schedule]]]:
        """Raise a DeprecationWarning if any circuit contains an 'id' instruction.

        Additionally, if 'delay' is a 'supported_instruction', replace each 'id'
        instruction (in-place) with the equivalent ('sx'-length) 'delay' instruction.

        Args:
            circuits: The individual or list of :class:`~qiskit.circuits.QuantumCircuit` or
                :class:`~qiskit.pulse.Schedule` objects passed to
                :meth:`IBMBackend.run()<IBMBackend.run>`. Modified in-place.

        Returns:
            A modified copy of the original circuit where 'id' instructions are replaced with
            'delay' instructions. A copy is used so the original circuit is not modified.
            If there are no 'id' instructions or 'delay' is not supported, return the original circuit.
        """

        id_support = "id" in getattr(self.configuration(), "basis_gates", [])
        delay_support = "delay" in getattr(self.configuration(),
                                           "supported_instructions", [])

        if not delay_support:
            return circuits

        if not isinstance(circuits, List):
            circuits = [circuits]

        circuit_has_id = any(instr.name == "id" for circuit in circuits
                             if isinstance(circuit, QuantumCircuit)
                             for instr, qargs, cargs in circuit.data)

        if not circuit_has_id:
            return circuits

        if not self.id_warning_issued:
            if id_support and delay_support:
                warnings.warn(
                    "Support for the 'id' instruction has been deprecated "
                    "from IBM hardware backends. Any 'id' instructions "
                    "will be replaced with their equivalent 'delay' instruction. "
                    "Please use the 'delay' instruction instead.",
                    DeprecationWarning,
                    stacklevel=4,
                )
            else:
                warnings.warn(
                    "Support for the 'id' instruction has been removed "
                    "from IBM hardware backends. Any 'id' instructions "
                    "will be replaced with their equivalent 'delay' instruction. "
                    "Please use the 'delay' instruction instead.",
                    DeprecationWarning,
                    stacklevel=4,
                )

            self.id_warning_issued = True

        dt_in_s = self.configuration().dt

        circuits_copy = copy.deepcopy(circuits)
        for circuit in circuits_copy:
            if isinstance(circuit, Schedule):
                continue

            for idx, (instr, qargs, cargs) in enumerate(circuit.data):
                if instr.name == "id":

                    sx_duration = self.properties().gate_length(
                        "sx", qargs[0].index)
                    sx_duration_in_dt = duration_in_dt(sx_duration, dt_in_s)

                    delay_instr = Delay(sx_duration_in_dt)

                    circuit.data[idx] = (delay_instr, qargs, cargs)
        return circuits_copy
    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_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_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_can_get_unbounded_duration_without_unit_conversion(self):
     param = Parameter("t")
     parameterized_delay = Delay(param, "dt")
     actual = InstructionDurations().get(parameterized_delay, 0)
     self.assertEqual(actual, param)
예제 #16
0
 def test_to_matrix_return_identity_matrix(self):
     actual = Delay(100).to_matrix()
     expected = np.array([[1, 0], [0, 1]], dtype=complex)
     self.assertTrue(np.array_equal(actual, expected))
예제 #17
0
    def run(self, dag):
        """Run the ALAPSchedule pass on `dag`.

        Args:
            dag (DAGCircuit): DAG to schedule.

        Returns:
            DAGCircuit: A scheduled DAG.

        Raises:
            TranspilerError: if the circuit is not mapped on physical qubits.
            TranspilerError: if conditional bit is added to non-supported instruction.
        """
        if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None:
            raise TranspilerError(
                "ALAP schedule runs on physical circuits only")

        time_unit = self.property_set["time_unit"]
        new_dag = DAGCircuit()
        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        idle_before = {q: 0 for q in dag.qubits + dag.clbits}
        bit_indices = {bit: index for index, bit in enumerate(dag.qubits)}
        for node in reversed(list(dag.topological_op_nodes())):
            op_duration = self._get_node_duration(node, bit_indices, dag)

            # compute t0, t1: instruction interval, note that
            # t0: start time of instruction
            # t1: end time of instruction

            # since this is alap scheduling, node is scheduled in reversed topological ordering
            # and nodes are packed from the very end of the circuit.
            # the physical meaning of t0 and t1 is flipped here.
            if isinstance(node.op, self.CONDITIONAL_SUPPORTED):
                t0q = max(idle_before[q] for q in node.qargs)
                if node.op.condition_bits:
                    # conditional is bit tricky due to conditional_latency
                    t0c = max(idle_before[c] for c in node.op.condition_bits)
                    # Assume following case (t0c > t0q):
                    #
                    #                |t0q
                    # Q ░░░░░░░░░░░░░▒▒▒
                    # C ░░░░░░░░▒▒▒▒▒▒▒▒
                    #           |t0c
                    #
                    # In this case, there is no actual clbit read before gate.
                    #
                    #             |t0q' = t0c - conditional_latency
                    # Q ░░░░░░░░▒▒▒░░▒▒▒
                    # C ░░░░░░▒▒▒▒▒▒▒▒▒▒
                    #         |t1c' = t0c + conditional_latency
                    #
                    # rather than naively doing
                    #
                    #        |t1q' = t0c + duration
                    # Q ░░░░░▒▒▒░░░░░▒▒▒
                    # C ░░▒▒░░░░▒▒▒▒▒▒▒▒
                    #     |t1c' = t0c + duration + conditional_latency
                    #
                    t0 = max(t0q, t0c - op_duration)
                    t1 = t0 + op_duration
                    for clbit in node.op.condition_bits:
                        idle_before[clbit] = t1 + self.conditional_latency
                else:
                    t0 = t0q
                    t1 = t0 + op_duration
            else:
                if node.op.condition_bits:
                    raise TranspilerError(
                        f"Conditional instruction {node.op.name} is not supported in ALAP scheduler."
                    )

                if isinstance(node.op, Measure):
                    # clbit time is always right (alap) justified
                    t0 = max(idle_before[bit]
                             for bit in node.qargs + node.cargs)
                    t1 = t0 + op_duration
                    #
                    #        |t1 = t0 + duration
                    # Q ░░░░░▒▒▒▒▒▒▒▒▒▒▒
                    # C ░░░░░░░░░▒▒▒▒▒▒▒
                    #            |t0 + (duration - clbit_write_latency)
                    #
                    for clbit in node.cargs:
                        idle_before[clbit] = t0 + (op_duration -
                                                   self.clbit_write_latency)
                else:
                    # It happens to be directives such as barrier
                    t0 = max(idle_before[bit]
                             for bit in node.qargs + node.cargs)
                    t1 = t0 + op_duration

            for bit in node.qargs:
                delta = t0 - idle_before[bit]
                if delta > 0:
                    new_dag.apply_operation_front(Delay(delta, time_unit),
                                                  [bit], [])
                idle_before[bit] = t1

            new_dag.apply_operation_front(node.op, node.qargs, node.cargs)

        circuit_duration = max(idle_before.values())
        for bit, before in idle_before.items():
            delta = circuit_duration - before
            if not (delta > 0 and isinstance(bit, Qubit)):
                continue
            new_dag.apply_operation_front(Delay(delta, time_unit), [bit], [])

        new_dag.name = dag.name
        new_dag.metadata = dag.metadata
        new_dag.calibrations = dag.calibrations

        # set circuit duration and unit to indicate it is scheduled
        new_dag.duration = circuit_duration
        new_dag.unit = time_unit

        return new_dag
예제 #18
0
 def test_can_append_parameterized_delay(self):
     dur = Parameter("t")
     qc = QuantumCircuit(1)
     qc.delay(dur)
     self.assertEqual(qc.data[0].operation, Delay(dur))
예제 #19
0
 def test_can_accept_parameterized_duration(self):
     dur = Parameter("t")
     self.assertEqual(Delay(dur).duration, dur)
 def test_fail_if_get_unbounded_duration_with_unit_conversion_when_dt_is_not_provided(
         self):
     param = Parameter("t")
     parameterized_delay = Delay(param, "s")
     with self.assertRaises(TranspilerError):
         InstructionDurations().get(parameterized_delay, 0)
 def test_can_get_unbounded_duration_with_unit_conversion_when_dt_is_provided(
         self):
     param = Parameter("t")
     parameterized_delay = Delay(param, "s")
     actual = InstructionDurations(dt=100).get(parameterized_delay, 0)
     self.assertEqual(actual, param / 100)