Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update HamiltonianGate path and add tolerance to PulseBackend (backport #1280) #1366

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions qiskit_experiments/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
MockIQParallelBackend
T2HahnBackend
NoisyDelayAerBackend
PulseBackend
SingleTransmonTestBackend

Helpers
=======
Expand Down
17 changes: 17 additions & 0 deletions qiskit_experiments/test/pulse_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ def __init__(
dt: float = 0.1 * 1e-9,
solver_method="RK23",
seed: int = 0,
atol: float = None,
rtol: float = None,
**kwargs,
):
"""Initialize a backend with model information.
Expand All @@ -86,6 +88,8 @@ def __init__(
methods. Defaults to "RK23".
seed: An optional seed given to the random number generator. If this argument is not
set then the seed defaults to 0.
atol: Absolute tolerance during solving.
rtol: Relative tolerance during solving.
"""
super().__init__(
None,
Expand All @@ -108,6 +112,12 @@ def __init__(

self.solver_method = solver_method

self.solve_kwargs = {}
if atol:
self.solve_kwargs["atol"] = atol
if rtol:
self.solve_kwargs["rtol"] = rtol

self.static_hamiltonian = static_hamiltonian
self.hamiltonian_operators = hamiltonian_operators
self.static_dissipators = static_dissipators
Expand Down Expand Up @@ -338,6 +348,7 @@ def solve(self, schedule: Union[ScheduleBlock, Schedule], qubits: Tuple[int]) ->
t_eval=[time_f],
signals=signal,
method=self.solver_method,
**self.solve_kwargs,
).y[0]

return unitary
Expand Down Expand Up @@ -452,6 +463,8 @@ def __init__(
lambda_2: float = 0.8e9,
gamma_1: float = 1e4,
noise: bool = True,
atol: float = None,
rtol: float = None,
**kwargs,
):
"""Initialise backend with hamiltonian parameters
Expand All @@ -464,6 +477,8 @@ def __init__(
gamma_1: Relaxation rate (1/T1) for 1-0. Defaults to 1e4.
noise: Defaults to True. If True then T1 dissipation is included in the pulse-simulation.
The strength is given by ``gamma_1``.
atol: Absolute tolerance during solving.
rtol: Relative tolerance during solving.
"""
qubit_frequency_02 = 2 * qubit_frequency + anharmonicity
ket0 = np.array([[1, 0, 0]]).T
Expand Down Expand Up @@ -505,6 +520,8 @@ def __init__(
rwa_cutoff_freq=1.9 * qubit_frequency,
rwa_carrier_freqs=[qubit_frequency],
evaluation_mode=evaluation_mode,
atol=atol,
rtol=rtol,
**kwargs,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ upgrade:
setting backend for just checking experiment sequence. The sequence with actual parameters
is generated after the backend is set. In addition, now experiments can take ``cr_gate``
in the constractor which is ``Gate`` type subclass taking a single parameter (flat-top width).
If one inputs a :class:`~qiskit.extensions.hamiltonian_gate.HamiltonianGate` subclass with
If one inputs a :class:`~qiskit.circuit.library.HamiltonianGate` subclass with
cross resonance Hamiltonian, experiment can be simulated with Aer QASM simulator.
62 changes: 62 additions & 0 deletions test/library/calibration/test_half_angle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# 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 rough amplitude calibration experiment classes."""

from test.base import QiskitExperimentsTestCase

from qiskit import pulse
from qiskit.circuit import Parameter

from qiskit_experiments.exceptions import CalibrationError
from qiskit_experiments.calibration_management.basis_gate_library import FixedFrequencyTransmon
from qiskit_experiments.calibration_management import Calibrations
from qiskit_experiments.library import HalfAngleCal
from qiskit_experiments.test.pulse_backend import SingleTransmonTestBackend


class TestHalfAngleCal(QiskitExperimentsTestCase):
"""A class to test the half angle calibration experiments."""

def setUp(self):
"""Setup the tests."""
super().setUp()
library = FixedFrequencyTransmon()

self.backend = SingleTransmonTestBackend(noise=False, atol=1e-3)
self.cals = Calibrations.from_backend(self.backend, libraries=[library])

def test_amp_parameter_error(self):
"""Test that setting cal_parameter_name to amp raises an error"""
with self.assertRaises(CalibrationError):
HalfAngleCal([0], self.cals, cal_parameter_name="amp")

def test_angle_parameter_missing_error(self):
"""Test that default cal_parameter_name with no matching parameter raises an error"""
cals_no_angle = Calibrations()
dur = Parameter("dur")
amp = Parameter("amp")
sigma = Parameter("σ")
beta = Parameter("β")
drive = pulse.DriveChannel(Parameter("ch0"))

with pulse.build(name="sx") as sx:
pulse.play(pulse.Drag(dur, amp, sigma, beta), drive)

cals_no_angle.add_schedule(sx, num_qubits=1)
with self.assertRaises(CalibrationError):
HalfAngleCal([0], cals_no_angle)

def test_circuits_roundtrip_serializable(self):
"""Test circuits serialization of the experiment."""
exp = HalfAngleCal([0], self.cals, backend=self.backend)
self.assertRoundTripSerializable(exp._transpiled_circuits())
17 changes: 9 additions & 8 deletions test/library/calibration/test_rabi.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,18 @@
class TestRabiEndToEnd(QiskitExperimentsTestCase):
"""Test the rabi experiment."""

def setUp(self):
@classmethod
def setUpClass(cls):
"""Setup the tests."""
super().setUp()
super().setUpClass()

self.qubit = 0
cls.qubit = 0

with pulse.build(name="x") as sched:
pulse.play(pulse.Drag(160, Parameter("amp"), 40, 0.4), pulse.DriveChannel(self.qubit))
pulse.play(pulse.Drag(160, Parameter("amp"), 40, 0.4), pulse.DriveChannel(cls.qubit))

self.sched = sched
self.backend = SingleTransmonTestBackend(noise=False)
cls.sched = sched
cls.backend = SingleTransmonTestBackend(noise=False, atol=1e-3)

# pylint: disable=no-member
def test_rabi_end_to_end(self):
Expand Down Expand Up @@ -100,7 +101,7 @@ def setUp(self):
super().setUp()

self.qubit = 0
self.backend = SingleTransmonTestBackend(noise=False)
self.backend = SingleTransmonTestBackend(noise=False, atol=1e-4)
self.anharmonicity = self.backend.anharmonicity
with pulse.build(name="x") as sched:
with pulse.frequency_offset(self.anharmonicity, pulse.DriveChannel(self.qubit)):
Expand All @@ -114,7 +115,7 @@ def setUp(self):
def test_ef_rabi_end_to_end(self):
"""Test the EFRabi experiment end to end."""

test_tol = 0.01
test_tol = 0.05

# Note that the backend is not sophisticated enough to simulate an e-f
# transition so we run the test with a tiny frequency shift, still driving the e-g transition.
Expand Down
4 changes: 2 additions & 2 deletions test/library/calibration/test_rough_amplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def setUp(self):
super().setUp()
library = FixedFrequencyTransmon()

self.backend = SingleTransmonTestBackend(noise=False)
self.backend = SingleTransmonTestBackend(noise=False, atol=1e-3)
self.cals = Calibrations.from_backend(self.backend, libraries=[library])

def test_circuits(self):
Expand Down Expand Up @@ -100,7 +100,7 @@ def setUp(self):

library = FixedFrequencyTransmon()

self.backend = SingleTransmonTestBackend(noise=False)
self.backend = SingleTransmonTestBackend(noise=False, atol=1e-3)
self.cals = Calibrations.from_backend(self.backend, libraries=[library])

# Add some pulses on the 1-2 transition.
Expand Down
6 changes: 4 additions & 2 deletions test/library/calibration/test_rough_frequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class TestRoughFrequency(QiskitExperimentsTestCase):
def setUp(self):
"""Setup the tests."""
super().setUp()
self.backend = SingleTransmonTestBackend(noise=False)
self.backend = SingleTransmonTestBackend(noise=False, atol=1e-3)

def test_init(self):
"""Test that initialization."""
Expand All @@ -53,7 +53,9 @@ def test_update_calibrations(self):

freq01 = BackendData(self.backend).drive_freqs[0]

backend_5mhz = SingleTransmonTestBackend(qubit_frequency=freq01 + 5e6, noise=False)
backend_5mhz = SingleTransmonTestBackend(
qubit_frequency=freq01 + 5e6, noise=False, atol=1e-3
)

library = FixedFrequencyTransmon()
cals = Calibrations.from_backend(self.backend, libraries=[library])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@
from ddt import ddt, data, unpack
from qiskit import QuantumCircuit, pulse, quantum_info as qi
from qiskit.providers.fake_provider import FakeBogotaV2
from qiskit.extensions.hamiltonian_gate import HamiltonianGate

# TODO: remove old path after we stop supporting the relevant version of Qiskit
try:
from qiskit.circuit.library.hamiltonian_gate import HamiltonianGate
except ModuleNotFoundError:
from qiskit.extensions.hamiltonian_gate import HamiltonianGate

from qiskit_aer import AerSimulator
from qiskit_experiments.library.characterization import cr_hamiltonian

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def setUp(self):
"""Setup test variables."""
super().setUp()

self.backend = SingleTransmonTestBackend(noise=False)
self.backend = SingleTransmonTestBackend(noise=False, atol=1e-3)

# Build x12 schedule
self.qubit = 0
Expand Down Expand Up @@ -97,7 +97,7 @@ def test_discrimination_analysis(self, n_states):

fidelity = exp_data.analysis_results("fidelity").value

self.assertGreaterEqual(fidelity, 0.96)
self.assertGreaterEqual(fidelity, 0.93)

# check that the discriminator differentiates n different states
discrim_lbls = exp_data.analysis_results("discriminator_config").value["attributes"][
Expand Down
Loading