Skip to content

Commit

Permalink
Add missing test coverage for RZXCalibration builder with target (#9416)
Browse files Browse the repository at this point in the history
In the recently merged #9343 support for using the Target directly was
added to the RZXCalibrartionBuilder family of passes. However, test
coverage in that PR was omitted by mistake for that pass (other passes
in the PR were covered). There was a bug in the code change introduced
in that PR which caused an error on initialization if a target were
specified without an InstructionScheduleMap (which was the intent of the
new target kwarg). This commit fixes the logic bug in the pass and adds
test coverage to ensure specifying only a target continues to work
moving forward.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
mtreinish and mergify[bot] authored Jan 23, 2023
1 parent 247c298 commit e981b7e
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 4 deletions.
5 changes: 2 additions & 3 deletions qiskit/transpiler/passes/calibration/rzx_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@ def __init__(
"""
super().__init__()

if instruction_schedule_map is None:
raise QiskitError("Calibrations can only be added to Pulse-enabled backends")

if qubit_channel_mapping:
warnings.warn(
"'qubit_channel_mapping' is no longer used. This value is ignored.",
Expand All @@ -97,6 +94,8 @@ def __init__(
self._verbose = verbose
if target:
self._inst_map = target.instruction_schedule_map()
if self._inst_map is None:
raise QiskitError("Calibrations can only be added to Pulse-enabled backends")

def supported(self, node_op: CircuitInst, qubits: List) -> bool:
"""Determine if a given node supports the calibration.
Expand Down
128 changes: 127 additions & 1 deletion test/python/transpiler/test_calibrationbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from qiskit import circuit, schedule
from qiskit.circuit.library.standard_gates import SXGate, RZGate
from qiskit.providers.fake_provider import FakeHanoi
from qiskit.providers.fake_provider import FakeHanoi, FakeHanoiV2
from qiskit.pulse import (
ControlChannel,
DriveChannel,
Expand Down Expand Up @@ -109,6 +109,132 @@ def test_rzx_calibration_rotary_pulse_stretch(self, theta: float):

self.assertEqual(test_sched.duration, self.compute_stretch_duration(self.d1p_play, theta))

def test_native_cr_with_target(self):
"""Test that correct pulse sequence is generated for native CR pair."""
# Sufficiently large angle to avoid minimum duration, i.e. amplitude rescaling
theta = np.pi / 4

qc = circuit.QuantumCircuit(2)
qc.rzx(theta, 0, 1)

target = FakeHanoiV2().target

_pass = RZXCalibrationBuilder(target=target)
test_qc = PassManager(_pass).run(qc)

duration = self.compute_stretch_duration(self.u0p_play, theta)
with builder.build(
self.backend,
default_alignment="sequential",
default_transpiler_settings={"optimization_level": 0},
) as ref_sched:
with builder.align_left():
# Positive CRs
u0p_params = self.u0p_play.pulse.parameters
u0p_params["duration"] = duration
u0p_params["width"] = self.compute_stretch_width(self.u0p_play, theta)
builder.play(
GaussianSquare(**u0p_params),
ControlChannel(0),
)
d1p_params = self.d1p_play.pulse.parameters
d1p_params["duration"] = duration
d1p_params["width"] = self.compute_stretch_width(self.d1p_play, theta)
builder.play(
GaussianSquare(**d1p_params),
DriveChannel(1),
)
builder.x(0)
with builder.align_left():
# Negative CRs
u0m_params = self.u0m_play.pulse.parameters
u0m_params["duration"] = duration
u0m_params["width"] = self.compute_stretch_width(self.u0m_play, theta)
builder.play(
GaussianSquare(**u0m_params),
ControlChannel(0),
)
d1m_params = self.d1m_play.pulse.parameters
d1m_params["duration"] = duration
d1m_params["width"] = self.compute_stretch_width(self.d1m_play, theta)
builder.play(
GaussianSquare(**d1m_params),
DriveChannel(1),
)
builder.x(0)

self.assertEqual(schedule(test_qc, self.backend), target_qobj_transform(ref_sched))

def test_non_native_cr_with_target(self):
"""Test that correct pulse sequence is generated for non-native CR pair."""
# Sufficiently large angle to avoid minimum duration, i.e. amplitude rescaling
theta = np.pi / 4

qc = circuit.QuantumCircuit(2)
qc.rzx(theta, 1, 0)

target = FakeHanoiV2().target

_pass = RZXCalibrationBuilder(target=target)
test_qc = PassManager(_pass).run(qc)

duration = self.compute_stretch_duration(self.u0p_play, theta)
with builder.build(
self.backend,
default_alignment="sequential",
default_transpiler_settings={"optimization_level": 0},
) as ref_sched:
# Hadamard gates
builder.call_gate(RZGate(np.pi / 2), qubits=(0,))
builder.call_gate(SXGate(), qubits=(0,))
builder.call_gate(RZGate(np.pi / 2), qubits=(0,))
builder.call_gate(RZGate(np.pi / 2), qubits=(1,))
builder.call_gate(SXGate(), qubits=(1,))
builder.call_gate(RZGate(np.pi / 2), qubits=(1,))
with builder.align_left():
# Positive CRs
u0p_params = self.u0p_play.pulse.parameters
u0p_params["duration"] = duration
u0p_params["width"] = self.compute_stretch_width(self.u0p_play, theta)
builder.play(
GaussianSquare(**u0p_params),
ControlChannel(0),
)
d1p_params = self.d1p_play.pulse.parameters
d1p_params["duration"] = duration
d1p_params["width"] = self.compute_stretch_width(self.d1p_play, theta)
builder.play(
GaussianSquare(**d1p_params),
DriveChannel(1),
)
builder.x(0)
with builder.align_left():
# Negative CRs
u0m_params = self.u0m_play.pulse.parameters
u0m_params["duration"] = duration
u0m_params["width"] = self.compute_stretch_width(self.u0m_play, theta)
builder.play(
GaussianSquare(**u0m_params),
ControlChannel(0),
)
d1m_params = self.d1m_play.pulse.parameters
d1m_params["duration"] = duration
d1m_params["width"] = self.compute_stretch_width(self.d1m_play, theta)
builder.play(
GaussianSquare(**d1m_params),
DriveChannel(1),
)
builder.x(0)
# Hadamard gates
builder.call_gate(RZGate(np.pi / 2), qubits=(0,))
builder.call_gate(SXGate(), qubits=(0,))
builder.call_gate(RZGate(np.pi / 2), qubits=(0,))
builder.call_gate(RZGate(np.pi / 2), qubits=(1,))
builder.call_gate(SXGate(), qubits=(1,))
builder.call_gate(RZGate(np.pi / 2), qubits=(1,))

self.assertEqual(schedule(test_qc, self.backend), target_qobj_transform(ref_sched))

def test_native_cr(self):
"""Test that correct pulse sequence is generated for native CR pair."""
# Sufficiently large angle to avoid minimum duration, i.e. amplitude rescaling
Expand Down

0 comments on commit e981b7e

Please sign in to comment.