mirror of https://github.com/Qiskit/qiskit.git
1084 lines
64 KiB
Python
1084 lines
64 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) Copyright IBM 2021.
|
|
#
|
|
# This code is licensed under the Apache License, Version 2.0. You may
|
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
#
|
|
# Any modifications or derivative works of this code must retain this
|
|
# copyright notice, and modified files need to carry a notice indicating
|
|
# that they have been altered from the originals.
|
|
|
|
"""Test dynamical decoupling insertion pass."""
|
|
|
|
import unittest
|
|
import numpy as np
|
|
from numpy import pi
|
|
from ddt import ddt, data
|
|
|
|
from qiskit import pulse
|
|
from qiskit.circuit import Gate, 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 (
|
|
ASAPScheduleAnalysis,
|
|
ALAPScheduleAnalysis,
|
|
PadDynamicalDecoupling,
|
|
)
|
|
from qiskit.transpiler.passmanager import PassManager
|
|
from qiskit.transpiler.exceptions import TranspilerError
|
|
from qiskit.transpiler.target import Target, InstructionProperties
|
|
from test import QiskitTestCase # pylint: disable=wrong-import-order
|
|
|
|
|
|
@ddt
|
|
class TestPadDynamicalDecoupling(QiskitTestCase):
|
|
"""Tests PadDynamicalDecoupling pass."""
|
|
|
|
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_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_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)}
|
|
)
|
|
target.add_instruction(Delay(Parameter("t")), {(x,): None 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.
|
|
|
|
┌───┐ ┌────────────────┐ ┌───┐ »
|
|
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_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_insert_dd_with_pulse_gate_calibrations(self):
|
|
"""Test DD gates are inserted without error when circuit calibrations are used
|
|
|
|
┌───┐ ┌───────────────┐ ┌───┐ »
|
|
q_0: ──────┤ H ├─────────■──┤ Delay(75[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(150[dt]) ├┤ X ├┤ Delay(75[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]),
|
|
]
|
|
)
|
|
|
|
# Change duration to 100 from the 50 in self.durations to make sure
|
|
# gate duration is used correctly.
|
|
with self.assertWarns(DeprecationWarning):
|
|
with pulse.builder.build() as x_sched:
|
|
pulse.builder.delay(100, pulse.DriveChannel(0))
|
|
|
|
circ_in = self.ghz4.measure_all(inplace=False)
|
|
with self.assertWarns(DeprecationWarning):
|
|
circ_in.add_calibration(XGate(), (0,), x_sched)
|
|
|
|
ghz4_dd = pm.run(circ_in)
|
|
|
|
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)
|
|
|
|
# Delays different from those of the default case using self.durations
|
|
expected = expected.compose(Delay(75), [0])
|
|
expected = expected.compose(XGate(), [0])
|
|
expected = expected.compose(Delay(150), [0])
|
|
expected = expected.compose(XGate(), [0])
|
|
expected = expected.compose(Delay(75), [0])
|
|
|
|
expected = expected.compose(Delay(300), [1])
|
|
|
|
expected.measure_all()
|
|
with self.assertWarns(DeprecationWarning):
|
|
expected.add_calibration(XGate(), (0,), x_sched)
|
|
|
|
self.assertEqual(ghz4_dd, expected)
|
|
|
|
def test_insert_dd_with_pulse_gate_calibrations_with_parmas(self):
|
|
"""Test DD gates are inserted without error when parameterized circuit calibrations are used
|
|
|
|
┌───┐ ┌───────────────┐ ┌───┐ »
|
|
q_0: ──────┤ H ├─────────■──┤ Delay(75[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(150[dt]) ├┤ X ├┤ Delay(75[dt]) ├─░─┤M├─────────
|
|
« └────────────────┘└───┘└───────────────┘ ░ └╥┘┌─┐
|
|
« q_1: ─────────────────────────────────────────░──╫─┤M├──────
|
|
« ░ ║ └╥┘┌─┐
|
|
« q_2: ─────────────────────────────────────────░──╫──╫─┤M├───
|
|
« ░ ║ ║ └╥┘┌─┐
|
|
« q_3: ─────────────────────────────────────────░──╫──╫──╫─┤M├
|
|
« ░ ║ ║ ║ └╥┘
|
|
«meas: 4/════════════════════════════════════════════╩══╩══╩══╩═
|
|
« 0 1 2 3
|
|
"""
|
|
# Change duration to 100 from the 50 in self.durations to make sure
|
|
# gate duration is used correctly.
|
|
amp = Parameter("amp")
|
|
with self.assertWarns(DeprecationWarning):
|
|
with pulse.builder.build() as sched:
|
|
pulse.builder.play(
|
|
pulse.Gaussian(100, amp=amp, sigma=10.0),
|
|
pulse.DriveChannel(0),
|
|
)
|
|
|
|
class Echo(Gate):
|
|
"""Dummy Gate subclass for testing
|
|
|
|
In this test, we use a non-standard gate so we can add parameters
|
|
to it, in order to test the handling of parameters by
|
|
PadDynamicalDecoupling. PadDynamicalDecoupling checks that the DD
|
|
sequence is equivalent to the identity, so we can not use Gate
|
|
directly. Here we subclass Gate and add the identity as its matrix
|
|
representation to satisfy PadDynamicalDecoupling's check.
|
|
"""
|
|
|
|
def __array__(self, dtype=None, copy=None):
|
|
if copy is False:
|
|
raise ValueError("cannot produce matrix without calculation")
|
|
return np.eye(2, dtype=dtype)
|
|
|
|
# A gate with one unbound and one bound parameter to leave in the final
|
|
# circuit.
|
|
echo = Echo("echo", 1, [amp, 10.0])
|
|
|
|
circ_in = self.ghz4.measure_all(inplace=False)
|
|
with self.assertWarns(DeprecationWarning):
|
|
circ_in.add_calibration(echo, (0,), sched)
|
|
|
|
dd_sequence = [echo, echo]
|
|
pm = PassManager(
|
|
[
|
|
ALAPScheduleAnalysis(self.durations),
|
|
PadDynamicalDecoupling(self.durations, dd_sequence, qubits=[0]),
|
|
]
|
|
)
|
|
|
|
ghz4_dd = pm.run(circ_in)
|
|
|
|
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)
|
|
|
|
# Delays different from those of the default case using self.durations
|
|
expected = expected.compose(Delay(75), [0])
|
|
expected = expected.compose(echo, [0])
|
|
expected = expected.compose(Delay(150), [0])
|
|
expected = expected.compose(echo, [0])
|
|
expected = expected.compose(Delay(75), [0])
|
|
|
|
expected = expected.compose(Delay(300), [1])
|
|
|
|
expected.measure_all()
|
|
with self.assertWarns(DeprecationWarning):
|
|
expected.add_calibration(echo, (0,), sched)
|
|
|
|
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_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, 0, 0)
|
|
|
|
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 = pi
|
|
|
|
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_midmeas_hahn_asap(self):
|
|
"""Test a single X gate as Hahn echo can absorb in the upstream circuit.
|
|
|
|
┌──────────────────┐ ┌────────────────┐┌─────────┐»
|
|
q_0: ────────■─────────┤ U(3π/4,-π/2,π/2) ├─┤ Delay(600[dt]) ├┤ Rx(π/4) ├»
|
|
┌─┴─┐ └──────────────────┘┌┴────────────────┤└─────────┘»
|
|
q_1: ──────┤ X ├────────────────■──────────┤ Delay(1000[dt]) ├─────■─────»
|
|
┌─────┴───┴──────┐ ┌─┴─┐ └───────┬─┬───────┘ ┌─┴─┐ »
|
|
q_2: ┤ Delay(700[dt]) ├───────┤ X ├────────────────┤M├───────────┤ X ├───»
|
|
└────────────────┘ └───┘ └╥┘ └───┘ »
|
|
c: 1/═══════════════════════════════════════════════╩════════════════════»
|
|
0 »
|
|
« ┌────────────────┐
|
|
«q_0: ┤ Delay(600[dt]) ├──■──
|
|
« └────────────────┘┌─┴─┐
|
|
«q_1: ──────────────────┤ X ├
|
|
« ┌────────────────┐└───┘
|
|
«q_2: ┤ Delay(700[dt]) ├─────
|
|
« └────────────────┘
|
|
«c: 1/═══════════════════════
|
|
«
|
|
"""
|
|
dd_sequence = [RXGate(pi / 4)]
|
|
pm = PassManager(
|
|
[
|
|
ASAPScheduleAnalysis(self.durations),
|
|
PadDynamicalDecoupling(self.durations, dd_sequence),
|
|
]
|
|
)
|
|
|
|
midmeas_dd = pm.run(self.midmeas)
|
|
|
|
combined_u = UGate(3 * pi / 4, -pi / 2, pi / 2)
|
|
|
|
expected = QuantumCircuit(3, 1)
|
|
expected.cx(0, 1)
|
|
expected.compose(combined_u, [0], inplace=True)
|
|
expected.delay(600, 0)
|
|
expected.rx(pi / 4, 0)
|
|
expected.delay(600, 0)
|
|
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)
|
|
|
|
self.assertEqual(midmeas_dd, expected)
|
|
# check the absorption into U was done correctly
|
|
self.assertTrue(
|
|
Operator(XGate()).equiv(
|
|
Operator(UGate(3 * pi / 4, -pi / 2, pi / 2)) & Operator(RXGate(pi / 4))
|
|
)
|
|
)
|
|
|
|
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_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_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_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)
|
|
|
|
@data(0.5, 1.5)
|
|
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 self.assertWarns(DeprecationWarning):
|
|
with pulse.build() as rx:
|
|
pulse.play(
|
|
pulse.Gaussian(rx_duration, 0.1, rx_duration // 4), pulse.DriveChannel(1)
|
|
)
|
|
|
|
with self.assertWarns(DeprecationWarning):
|
|
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_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_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_respect_target_instruction_constraints(self):
|
|
"""Test if DD pass does not pad delays for qubits that do not support delay instructions
|
|
and does not insert DD gates for qubits that do not support necessary gates.
|
|
See: https://github.com/Qiskit/qiskit-terra/issues/9993
|
|
"""
|
|
qc = QuantumCircuit(3)
|
|
qc.cx(0, 1)
|
|
qc.cx(1, 2)
|
|
|
|
target = Target(dt=1)
|
|
# Y is partially supported (not supported on qubit 2)
|
|
target.add_instruction(
|
|
XGate(), {(q,): InstructionProperties(duration=100) for q in range(2)}
|
|
)
|
|
target.add_instruction(
|
|
CXGate(),
|
|
{
|
|
(0, 1): InstructionProperties(duration=1000),
|
|
(1, 2): InstructionProperties(duration=1000),
|
|
},
|
|
)
|
|
# delays are not supported
|
|
|
|
# No DD instructions nor delays are padded due to no delay support in the target
|
|
pm_xx = PassManager(
|
|
[
|
|
ALAPScheduleAnalysis(target=target),
|
|
PadDynamicalDecoupling(dd_sequence=[XGate(), XGate()], target=target),
|
|
]
|
|
)
|
|
scheduled = pm_xx.run(qc)
|
|
self.assertEqual(qc, scheduled)
|
|
|
|
# Fails since Y is not supported in the target
|
|
with self.assertRaises(TranspilerError):
|
|
PassManager(
|
|
[
|
|
ALAPScheduleAnalysis(target=target),
|
|
PadDynamicalDecoupling(
|
|
dd_sequence=[XGate(), YGate(), XGate(), YGate()], target=target
|
|
),
|
|
]
|
|
)
|
|
|
|
# Add delay support to the target
|
|
target.add_instruction(Delay(Parameter("t")), {(q,): None for q in range(3)})
|
|
# No error but no DD on qubit 2 (just delay is padded) since X is not supported on it
|
|
scheduled = pm_xx.run(qc)
|
|
|
|
expected = QuantumCircuit(3)
|
|
expected.delay(1000, [2])
|
|
expected.cx(0, 1)
|
|
expected.cx(1, 2)
|
|
expected.delay(200, [0])
|
|
expected.x([0])
|
|
expected.delay(400, [0])
|
|
expected.x([0])
|
|
expected.delay(200, [0])
|
|
self.assertEqual(expected, scheduled)
|
|
|
|
def test_paramaterized_global_phase(self):
|
|
"""Test paramaterized global phase in DD circuit.
|
|
See:https://github.com/Qiskit/qiskit-terra/issues/10569
|
|
"""
|
|
dd_sequence = [XGate(), YGate()] * 2
|
|
qc = QuantumCircuit(1, 1)
|
|
qc.h(0)
|
|
qc.delay(1700, 0)
|
|
qc.y(0)
|
|
qc.global_phase = Parameter("a")
|
|
pm = PassManager(
|
|
[
|
|
ALAPScheduleAnalysis(self.durations),
|
|
PadDynamicalDecoupling(self.durations, dd_sequence),
|
|
]
|
|
)
|
|
|
|
self.assertEqual(qc.global_phase + np.pi, pm.run(qc).global_phase)
|
|
|
|
def test_misalignment_at_boundaries(self):
|
|
"""Test the correct error message is raised for misalignments at In/Out nodes."""
|
|
# a circuit where the previous node is DAGInNode, and the next DAGOutNode
|
|
circuit = QuantumCircuit(1)
|
|
circuit.delay(101)
|
|
|
|
dd_sequence = [XGate(), XGate()]
|
|
pm = PassManager(
|
|
[
|
|
ALAPScheduleAnalysis(self.durations),
|
|
PadDynamicalDecoupling(self.durations, dd_sequence, pulse_alignment=2),
|
|
]
|
|
)
|
|
|
|
with self.assertRaises(TranspilerError):
|
|
_ = pm.run(circuit)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|