diff --git a/qiskit_experiments/test/mock_iq_backend.py b/qiskit_experiments/test/mock_iq_backend.py index ec68f7d479..3e5bab79d2 100644 --- a/qiskit_experiments/test/mock_iq_backend.py +++ b/qiskit_experiments/test/mock_iq_backend.py @@ -11,17 +11,14 @@ # that they have been altered from the originals. """A mock IQ backend for testing.""" -import datetime from abc import abstractmethod from typing import Sequence, List, Tuple, Dict, Union, Any import numpy as np from qiskit import QuantumCircuit -from qiskit.circuit.library import XGate, SXGate from qiskit.result import Result -from qiskit.providers import BackendV2, Provider, convert_to_target -from qiskit.providers.fake_provider import FakeOpenPulse2Q +from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.qobj.utils import MeasLevel from qiskit_experiments.exceptions import QiskitError @@ -35,59 +32,16 @@ ) -class FakeOpenPulse2QV2(BackendV2): - """BackendV2 conversion of qiskit.providers.fake_provider.FakeOpenPulse2Q""" - - def __init__( - self, - provider: Provider = None, - name: str = None, - description: str = None, - online_date: datetime.datetime = None, - backend_version: str = None, - **fields, - ): - super().__init__(provider, name, description, online_date, backend_version, **fields) - - backend_v1 = FakeOpenPulse2Q() - # convert_to_target requires the description attribute - backend_v1._configuration.description = "A fake test backend with pulse defaults" - - self._target = convert_to_target( - backend_v1.configuration(), - backend_v1.properties(), - backend_v1.defaults(), - add_delay=True, - ) - # See commented out defaults() method below - self._defaults = backend_v1._defaults - - # This method is not defined in the base class as we would like to avoid - # relying on it as much as necessary. Individual tests should add it when - # necessary. - # def defaults(self): - # """Pulse defaults""" - # return self._defaults - - @property - def max_circuits(self): - return 300 - - @property - def target(self): - return self._target - - -class MockRestlessBackend(FakeOpenPulse2QV2): +class MockRestlessBackend(GenericBackendV2): """An abstract backend for testing that can mock restless data.""" def __init__(self, rng_seed: int = 0): """ Initialize the backend. """ - self._rng = np.random.default_rng(rng_seed) + self.__rng = np.random.default_rng(rng_seed) self._precomputed_probabilities = None - super().__init__() + super().__init__(num_qubits=2, calibrate_instructions=True, seed=rng_seed) @classmethod def _default_options(cls): @@ -147,7 +101,7 @@ def run(self, run_input, **options): for circ_idx, _ in enumerate(run_input): probs = self._precomputed_probabilities[(circ_idx, prev_outcome)] # Generate the next shot dependent on the pre-computed probabilities. - outcome = self._rng.choice(state_strings, p=probs) + outcome = self.__rng.choice(state_strings, p=probs) # Append the single shot to the memory of the corresponding circuit. sorted_memory[circ_idx]["memory"].append(hex(int(outcome, 2))) @@ -192,9 +146,6 @@ def __init__( self._angle_per_gate = angle_per_gate super().__init__(rng_seed=rng_seed) - self.target.add_instruction(SXGate(), properties={(0,): None}) - self.target.add_instruction(XGate(), properties={(0,): None}) - def _compute_outcome_probabilities(self, circuits: List[QuantumCircuit]): """Compute the probabilities of being in the excited state or ground state for all circuits.""" @@ -219,7 +170,7 @@ def _compute_outcome_probabilities(self, circuits: List[QuantumCircuit]): self._precomputed_probabilities[(idx, "1")] = [prob_1, prob_0] -class MockIQBackend(FakeOpenPulse2QV2): +class MockIQBackend(GenericBackendV2): """A mock backend for testing with IQ data.""" def __init__( @@ -238,9 +189,10 @@ def __init__( """ self._experiment_helper = experiment_helper - self._rng = np.random.default_rng(rng_seed) + # Can not be called _rng because GenericBackendV2 sets a _rng attribute + self.__rng = np.random.default_rng(rng_seed) - super().__init__() + super().__init__(num_qubits=2, calibrate_instructions=True, seed=rng_seed) @classmethod def _default_options(cls): @@ -323,7 +275,7 @@ def _get_normal_samples_for_shot( Returns: Ndarray: A numpy array with values that were produced from normal distribution. """ - samples = [self._rng.normal(0, 1, size=1) for qubit in qubits] + samples = [self.__rng.normal(0, 1, size=1) for qubit in qubits] # we squeeze the second dimension because samples is List[qubit_number][0][0\1] = I\Q # and we want to change it to be List[qubit_number][0\1] return np.squeeze(np.array(samples), axis=1) @@ -396,7 +348,7 @@ def _draw_iq_shots( shot_num = 0 for output_number, number_of_occurrences in enumerate( - self._rng.multinomial(shots, prob, size=1)[0] + self.__rng.multinomial(shots, prob, size=1)[0] ): state_str = str(format(output_number, "b").zfill(len(circ_qubits))) for _ in range(number_of_occurrences): @@ -451,7 +403,7 @@ def _generate_data( if meas_level == MeasLevel.CLASSIFIED: counts = {} - results = self._rng.multinomial(shots, prob_arr, size=1)[0] + results = self.__rng.multinomial(shots, prob_arr, size=1)[0] for result, num_occurrences in enumerate(results): result_in_str = str(format(result, "b").zfill(output_length)) counts[result_in_str] = num_occurrences @@ -551,6 +503,7 @@ def __init__( helper classes for each experiment. rng_seed: The random seed value. """ + self.__rng = np.random.default_rng(rng_seed) super().__init__(experiment_helper, rng_seed) @property @@ -634,7 +587,7 @@ def _parallel_draw_iq_shots( shot_num = 0 for output_number, number_of_occurrences in enumerate( - self._rng.multinomial(shots, prob, size=1)[0] + self.__rng.multinomial(shots, prob, size=1)[0] ): state_str = str(format(output_number, "b").zfill(len(qubits))) for _ in range(number_of_occurrences): diff --git a/test/library/calibration/test_drag.py b/test/library/calibration/test_drag.py index 1c1f651028..2b89a9017c 100644 --- a/test/library/calibration/test_drag.py +++ b/test/library/calibration/test_drag.py @@ -46,7 +46,7 @@ def setUp(self): pulse.play(Drag(duration=160, amp=0.208519, sigma=40, beta=beta), DriveChannel(0)) self.x_plus = xp - self.test_tol = 0.1 + self.test_tol = 0.25 @data( (None, None, None), @@ -63,7 +63,7 @@ def test_end_to_end(self, freq, betas, p0_opt): backend = MockIQBackend(drag_experiment_helper) drag = RoughDrag([1], self.x_plus) - drag.set_run_options(shots=200) + drag.set_run_options(shots=500) if betas is not None: drag.set_experiment_options(betas=betas) diff --git a/test/library/calibration/test_fine_amplitude.py b/test/library/calibration/test_fine_amplitude.py index ea87c992b0..1a135d7070 100644 --- a/test/library/calibration/test_fine_amplitude.py +++ b/test/library/calibration/test_fine_amplitude.py @@ -46,10 +46,9 @@ def test_end_to_end_under_rotation(self, pi_ratio): error = -np.pi * pi_ratio backend = MockIQBackend(FineAmpHelper(error, np.pi, "x")) - backend.target.add_instruction(XGate(), properties={(0,): None}) - backend.target.add_instruction(SXGate(), properties={(0,): None}) - expdata = amp_exp.run(backend) + # Needs extra shots to avoid chisq > 3 + expdata = amp_exp.run(backend, shots=1600) self.assertExperimentDone(expdata) result = expdata.analysis_results("d_theta") d_theta = result.value.n @@ -67,8 +66,6 @@ def test_end_to_end_over_rotation(self, pi_ratio): error = np.pi * pi_ratio backend = MockIQBackend(FineAmpHelper(error, np.pi, "x")) - backend.target.add_instruction(XGate(), properties={(0,): None}) - backend.target.add_instruction(SXGate(), properties={(0,): None}) expdata = amp_exp.run(backend) self.assertExperimentDone(expdata) result = expdata.analysis_results("d_theta") @@ -99,7 +96,8 @@ def test_end_to_end(self, pi_ratio): backend = MockIQBackend(FineAmpHelper(error, np.pi / 2, "szx")) backend.target.add_instruction(Gate("szx", 2, []), properties={(0, 1): None}) - expdata = amp_exp.run(backend) + # Needs extra shots to avoid chisq > 3 + expdata = amp_exp.run(backend, shots=1600) self.assertExperimentDone(expdata) result = expdata.analysis_results("d_theta") d_theta = result.value.n @@ -218,8 +216,6 @@ def setUp(self): library = FixedFrequencyTransmon() self.backend = MockIQBackend(FineAmpHelper(-np.pi * 0.07, np.pi, "xp")) - self.backend.target.add_instruction(SXGate(), properties={(0,): None}) - self.backend.target.add_instruction(XGate(), properties={(0,): None}) self.cals = Calibrations.from_backend(self.backend, libraries=[library]) def test_cal_options(self): diff --git a/test/library/calibration/test_ramsey_xy.py b/test/library/calibration/test_ramsey_xy.py index 693e8b48ca..c89338be45 100644 --- a/test/library/calibration/test_ramsey_xy.py +++ b/test/library/calibration/test_ramsey_xy.py @@ -56,7 +56,7 @@ def test_end_to_end(self, freq_shift: float): This test also checks that we can pickup frequency shifts with different signs. """ - test_tol = 0.03 + test_tol = 0.05 abs_tol = max(1e3, abs(freq_shift) * test_tol) exp_helper = RamseyXYHelper() diff --git a/test/library/characterization/test_qubit_spectroscopy.py b/test/library/characterization/test_qubit_spectroscopy.py index ae8fc8bde8..c190b807ed 100644 --- a/test/library/characterization/test_qubit_spectroscopy.py +++ b/test/library/characterization/test_qubit_spectroscopy.py @@ -15,7 +15,6 @@ import numpy as np from qiskit.qobj.utils import MeasLevel -from qiskit.circuit.library import XGate from qiskit_ibm_runtime.fake_provider import FakeWashingtonV2 from qiskit_experiments.framework import ParallelExperiment @@ -42,7 +41,6 @@ def test_spectroscopy_end2end_classified(self): backend = MockIQBackend( experiment_helper=exp_helper, ) - backend.target.add_instruction(XGate(), properties={(0,): None}) qubit = 1 freq01 = BackendData(backend).drive_freqs[qubit] @@ -82,7 +80,6 @@ def test_spectroscopy_end2end_kerneled(self): backend = MockIQBackend( experiment_helper=exp_helper, ) - backend.target.add_instruction(XGate(), properties={(0,): None}) qubit = 0 freq01 = BackendData(backend).drive_freqs[qubit] @@ -128,7 +125,6 @@ def test_spectroscopy12_end2end_classified(self): iq_cluster_width=[0.2], ), ) - backend.target.add_instruction(XGate(), properties={(0,): None}) qubit = 0 freq01 = BackendData(backend).drive_freqs[qubit] frequencies = np.linspace(freq01 - 10.0e6, freq01 + 10.0e6, 21) @@ -174,7 +170,6 @@ def test_expdata_serialization(self): backend = MockIQBackend( experiment_helper=exp_helper, ) - backend.target.add_instruction(XGate(), properties={(0,): None}) qubit = 1 freq01 = BackendData(backend).drive_freqs[qubit] @@ -201,7 +196,6 @@ def test_kerneled_expdata_serialization(self): backend = MockIQBackend( experiment_helper=exp_helper, ) - backend.target.add_instruction(XGate(), properties={(0,): None}) qubit = 1 freq01 = BackendData(backend).drive_freqs[qubit] @@ -231,10 +225,6 @@ def test_parallel_experiment(self): experiment_helper=None, rng_seed=0, ) - parallel_backend.target.add_instruction( - XGate(), - properties={(0,): None, (1,): None}, - ) # experiment hyper parameters qubit1 = 0 diff --git a/test/library/characterization/test_resonator_spectroscopy.py b/test/library/characterization/test_resonator_spectroscopy.py index a0b9663d32..bd612ad3b6 100644 --- a/test/library/characterization/test_resonator_spectroscopy.py +++ b/test/library/characterization/test_resonator_spectroscopy.py @@ -12,6 +12,8 @@ """Spectroscopy tests for resonator spectroscopy experiment.""" +from __future__ import annotations + from test.base import QiskitExperimentsTestCase from typing import Any, List, Tuple @@ -34,6 +36,13 @@ ) +class MockDefaults: + """Just enough qiskit.providers.models.PulseDefaults for ResonatorSpectroscpy""" + + def __init__(self, meas_freq_est: list[float]): + self.meas_freq_est = meas_freq_est + + class MockIQBackendDefaults(MockIQBackend): """MockIQBackend with defaults() method""" @@ -45,7 +54,7 @@ def defaults(self): to Backend classes outside of this test module so that we do not introduce new dependencies on it. """ - return self._defaults + return MockDefaults(meas_freq_est=[7e9] * self.num_qubits) class MockIQParallelBackendDefaults(MockIQParallelBackend): @@ -59,7 +68,7 @@ def defaults(self): to Backend classes outside of this test module so that we do not introduce new dependencies on it. """ - return self._defaults + return MockDefaults(meas_freq_est=[7e9] * self.num_qubits) def data_valid_initial_circuits() -> List[Tuple[Any, str]]: diff --git a/test/library/characterization/test_zz_ramsey.py b/test/library/characterization/test_zz_ramsey.py index 10b12950a0..754329d633 100644 --- a/test/library/characterization/test_zz_ramsey.py +++ b/test/library/characterization/test_zz_ramsey.py @@ -49,7 +49,7 @@ def compute_probabilities(self, circuits: List[QuantumCircuit]) -> List[Dict[str freq = (-1 * self.zz_freq) / 2 else: freq = self.zz_freq / 2 - rz, _, _ = next(i for i in circuit.data if i[0].name == "u1") + rz, _, _ = next(i for i in circuit.data if i[0].name == "rz") phase = float(rz.params[0]) prob1 = 0.5 - 0.5 * np.cos(2 * np.pi * freq * delay + phase)