diff --git a/supermarq-benchmarks/supermarq/qcvv/base_experiment.py b/supermarq-benchmarks/supermarq/qcvv/base_experiment.py index ca5c631cc..42b9ecdf6 100644 --- a/supermarq-benchmarks/supermarq/qcvv/base_experiment.py +++ b/supermarq-benchmarks/supermarq/qcvv/base_experiment.py @@ -14,6 +14,7 @@ """ from __future__ import annotations +import functools import math import pprint from abc import ABC, abstractmethod @@ -195,14 +196,19 @@ def __init__( self._samples: Sequence[Sample] | None = None """The attribute to store the experimental samples in.""" - self._service: css.service.Service = css.service.Service(**kwargs) - """The superstaq service for submitting jobs.""" + self._service_kwargs = kwargs + """Arguments to pass to the Superstaq service for submitting jobs.""" self._rng = np.random.default_rng(random_seed) ############## # Properties # ############## + @functools.cached_property + def _superstaq_service(self) -> css.Service: + """A Superstaq service to use for compilation and circuit submission.""" + return css.Service(**self._service_kwargs) + @property def num_qubits(self) -> int: """Returns: @@ -464,7 +470,7 @@ def compile_circuits(self, target: str, **kwargs: Any) -> None: target: The device to compile to. kwargs: Additional desired compile options. """ - compiled_circuits = self._service.compile( + compiled_circuits = self._superstaq_service.compile( [sample.circuit for sample in self.samples], target=target, **kwargs ).circuits @@ -533,7 +539,7 @@ def run_on_device( if not overwrite: self._has_raw_data() - experiment_job = self._service.create_job( + experiment_job = self._superstaq_service.create_job( [sample.circuit for sample in self.samples], target=target, method=method, diff --git a/supermarq-benchmarks/supermarq/qcvv/base_experiment_test.py b/supermarq-benchmarks/supermarq/qcvv/base_experiment_test.py index dc3095db2..6b926ccb0 100644 --- a/supermarq-benchmarks/supermarq/qcvv/base_experiment_test.py +++ b/supermarq-benchmarks/supermarq/qcvv/base_experiment_test.py @@ -40,8 +40,7 @@ class ExampleResults(BenchmarkingResults): @pytest.fixture @patch.multiple(BenchmarkingExperiment, __abstractmethods__=set()) def abc_experiment() -> BenchmarkingExperiment[ExampleResults]: - with patch("cirq_superstaq.service.Service"): - return BenchmarkingExperiment(num_qubits=2) # type: ignore[abstract] + return BenchmarkingExperiment(num_qubits=2) # type: ignore[abstract] @pytest.fixture @@ -213,13 +212,13 @@ def test_run_on_device( abc_experiment: BenchmarkingExperiment[ExampleResults], sample_circuits: list[Sample] ) -> None: abc_experiment._samples = sample_circuits - abc_experiment._service = (mock_service := MagicMock()) - job = abc_experiment.run_on_device( - target="example_target", repetitions=100, overwrite=False, **{"some": "options"} - ) + with patch("cirq_superstaq.Service") as mock_service: + job = abc_experiment.run_on_device( + target="example_target", repetitions=100, overwrite=False, **{"some": "options"} + ) - mock_service.create_job.assert_called_once_with( + mock_service.return_value.create_job.assert_called_once_with( [sample_circuits[0].raw_circuit, sample_circuits[1].raw_circuit], target="example_target", method=None, @@ -227,21 +226,20 @@ def test_run_on_device( some="options", ) - assert job == mock_service.create_job.return_value + assert job == mock_service.return_value.create_job.return_value assert ( sample_circuits[0].compiled_circuit - == mock_service.create_job.return_value.compiled_circuits.return_value[0] + == mock_service.return_value.create_job.return_value.compiled_circuits.return_value[0] ) assert ( sample_circuits[1].compiled_circuit - == mock_service.create_job.return_value.compiled_circuits.return_value[1] + == mock_service.return_value.create_job.return_value.compiled_circuits.return_value[1] ) def test_run_on_device_existing_probabilties( abc_experiment: BenchmarkingExperiment[ExampleResults], sample_circuits: list[Sample] ) -> None: - abc_experiment._service = MagicMock() sample_circuits[0].probabilities = {"00": 0.0, "01": 1.0, "10": 0.0, "11": 0.0} sample_circuits[1].probabilities = {"00": 0.0, "01": 1.0, "10": 0.0, "11": 0.0} @@ -260,24 +258,26 @@ def test_run_on_device_dry_run( abc_experiment: BenchmarkingExperiment[ExampleResults], sample_circuits: list[Sample] ) -> None: abc_experiment._samples = sample_circuits - abc_experiment._service = (mock_service := MagicMock()) - job = abc_experiment.run_on_device(target="example_target", repetitions=100, method="dry-run") + with patch("cirq_superstaq.Service") as mock_service: + job = abc_experiment.run_on_device( + target="example_target", repetitions=100, method="dry-run" + ) - mock_service.create_job.assert_called_once_with( + mock_service.return_value.create_job.assert_called_once_with( [sample_circuits[0].raw_circuit, sample_circuits[1].raw_circuit], target="example_target", method="dry-run", repetitions=100, ) - assert job == mock_service.create_job.return_value + assert job == mock_service.return_value.create_job.return_value assert ( sample_circuits[0].compiled_circuit - == mock_service.create_job.return_value.compiled_circuits.return_value[0] + == mock_service.return_value.create_job.return_value.compiled_circuits.return_value[0] ) assert ( sample_circuits[1].compiled_circuit - == mock_service.create_job.return_value.compiled_circuits.return_value[1] + == mock_service.return_value.create_job.return_value.compiled_circuits.return_value[1] ) @@ -546,11 +546,13 @@ def test_compile_circuit( ) -> None: abc_experiment._samples = sample_circuits - abc_experiment._service = (mock_service := MagicMock()) - mock_service.compile.return_value.circuits = (mock_compiled_circuits := MagicMock()) - abc_experiment.compile_circuits("example_target", additional="kwargs") + with patch("cirq_superstaq.Service") as mock_service: + mock_service.return_value.compile.return_value.circuits = ( + mock_compiled_circuits := MagicMock() + ) + abc_experiment.compile_circuits("example_target", additional="kwargs") - mock_service.compile.assert_called_once_with( + mock_service.return_value.compile.assert_called_once_with( [sample_circuits[0].raw_circuit, sample_circuits[1].raw_circuit], target="example_target", additional="kwargs", diff --git a/supermarq-benchmarks/supermarq/qcvv/irb_test.py b/supermarq-benchmarks/supermarq/qcvv/irb_test.py index 8a7b14b7c..82bce5893 100644 --- a/supermarq-benchmarks/supermarq/qcvv/irb_test.py +++ b/supermarq-benchmarks/supermarq/qcvv/irb_test.py @@ -29,37 +29,29 @@ def test_irb_init() -> None: - with patch("cirq_superstaq.service.Service"): - experiment = IRB() - assert experiment.num_qubits == 1 - assert experiment.interleaved_gate == cirq.ops.SingleQubitCliffordGate.Z - assert experiment.clifford_op_gateset == cirq.CZTargetGateset() + experiment = IRB() + assert experiment.num_qubits == 1 + assert experiment.interleaved_gate == cirq.ops.SingleQubitCliffordGate.Z + assert experiment.clifford_op_gateset == cirq.CZTargetGateset() - experiment = IRB(interleaved_gate=cirq.ops.SingleQubitCliffordGate.X) - assert experiment.num_qubits == 1 - assert experiment.interleaved_gate == cirq.ops.SingleQubitCliffordGate.X - assert experiment.clifford_op_gateset == cirq.CZTargetGateset() + experiment = IRB(interleaved_gate=cirq.ops.SingleQubitCliffordGate.X) + assert experiment.num_qubits == 1 + assert experiment.interleaved_gate == cirq.ops.SingleQubitCliffordGate.X + assert experiment.clifford_op_gateset == cirq.CZTargetGateset() - experiment = IRB(interleaved_gate=cirq.CZ) - assert experiment.num_qubits == 2 - assert experiment.clifford_op_gateset == cirq.CZTargetGateset() + experiment = IRB(interleaved_gate=cirq.CZ) + assert experiment.num_qubits == 2 + assert experiment.clifford_op_gateset == cirq.CZTargetGateset() - experiment = IRB(interleaved_gate=None, clifford_op_gateset=cirq.SqrtIswapTargetGateset()) - assert experiment.num_qubits == 1 - assert experiment.interleaved_gate is None - assert experiment.clifford_op_gateset == cirq.SqrtIswapTargetGateset() + experiment = IRB(interleaved_gate=None, clifford_op_gateset=cirq.SqrtIswapTargetGateset()) + assert experiment.num_qubits == 1 + assert experiment.interleaved_gate is None + assert experiment.clifford_op_gateset == cirq.SqrtIswapTargetGateset() def test_irb_bad_init() -> None: - with patch("cirq_superstaq.service.Service"): - with pytest.raises(NotImplementedError): - IRB(interleaved_gate=None, num_qubits=3) - - -@pytest.fixture -def irb_experiment() -> IRB: - with patch("cirq_superstaq.service.Service"): - return IRB() + with pytest.raises(NotImplementedError): + IRB(interleaved_gate=None, num_qubits=3) def test_reduce_clifford_sequence() -> None: @@ -74,27 +66,23 @@ def test_reduce_clifford_sequence() -> None: def test_random_single_qubit_clifford() -> None: - with patch("cirq_superstaq.service.Service"): - gate = IRB().random_single_qubit_clifford() - assert isinstance(gate, cirq.ops.SingleQubitCliffordGate) + gate = IRB().random_single_qubit_clifford() + assert isinstance(gate, cirq.ops.SingleQubitCliffordGate) def test_irb_random_clifford() -> None: - with patch("cirq_superstaq.service.Service"): - exp = IRB() - gate = exp.random_clifford() - assert isinstance(gate, cirq.SingleQubitCliffordGate) + exp = IRB() + gate = exp.random_clifford() + assert isinstance(gate, cirq.SingleQubitCliffordGate) - exp = IRB(interleaved_gate=cirq.CZ) - gate = exp.random_clifford() - assert isinstance(gate, cirq.CliffordGate) - assert gate.num_qubits() == 2 + exp = IRB(interleaved_gate=cirq.CZ) + gate = exp.random_clifford() + assert isinstance(gate, cirq.CliffordGate) + assert gate.num_qubits() == 2 def test_random_two_qubit_clifford() -> None: - with patch("cirq_superstaq.service.Service"), patch( - "numpy.random.default_rng", side_effect=np.random.default_rng - ) as rng: + with patch("numpy.random.default_rng", side_effect=np.random.default_rng) as rng: rng.return_value.integers.side_effect = range(20) exp = IRB() @@ -108,19 +96,19 @@ def test_random_two_qubit_clifford() -> None: def test_gates_per_clifford() -> None: - with patch("cirq_superstaq.service.Service"): - exp = IRB() - gates = exp.gates_per_clifford(samples=1000) - assert gates["single_qubit_gates"] == pytest.approx(0.95, abs=0.1) - assert gates["two_qubit_gates"] == 0.0 + exp = IRB() + gates = exp.gates_per_clifford(samples=1000) + assert gates["single_qubit_gates"] == pytest.approx(0.95, abs=0.1) + assert gates["two_qubit_gates"] == 0.0 - exp = IRB(interleaved_gate=cirq.CZ) - gates = exp.gates_per_clifford(samples=1000) - assert gates["single_qubit_gates"] == pytest.approx(4.5, abs=0.25) - assert gates["two_qubit_gates"] == pytest.approx(1.5, abs=0.1) + exp = IRB(interleaved_gate=cirq.CZ) + gates = exp.gates_per_clifford(samples=1000) + assert gates["single_qubit_gates"] == pytest.approx(4.5, abs=0.25) + assert gates["two_qubit_gates"] == pytest.approx(1.5, abs=0.1) -def test_irb_process_probabilities(irb_experiment: IRB) -> None: +def test_irb_process_probabilities() -> None: + irb_experiment = IRB() samples = [ Sample( raw_circuit=cirq.Circuit(), @@ -156,7 +144,8 @@ def test_irb_process_probabilities(irb_experiment: IRB) -> None: pd.testing.assert_frame_equal(expected_data, data) -def test_irb_build_circuit(irb_experiment: IRB) -> None: +def test_irb_build_circuit() -> None: + irb_experiment = IRB() with patch("supermarq.qcvv.irb.IRB.random_single_qubit_clifford") as mock_random_clifford: mock_random_clifford.side_effect = [ cirq.ops.SingleQubitCliffordGate.Z, @@ -290,7 +279,8 @@ def test_irb_build_circuit(irb_experiment: IRB) -> None: assert circuits[3].data == expected_circuits[3].data -def test_analyse_results(irb_experiment: IRB) -> None: +def test_analyse_results() -> None: + irb_experiment = IRB() irb_experiment._samples = MagicMock() # Noise added to allow estimate of covariance (otherwise scipy errors) irb_experiment._raw_data = pd.DataFrame( @@ -366,8 +356,7 @@ def test_analyse_results(irb_experiment: IRB) -> None: def test_analyse_results_rb() -> None: - with patch("cirq_superstaq.service.Service"): - rb_experiment = IRB(interleaved_gate=None) + rb_experiment = IRB(interleaved_gate=None) rb_experiment._samples = MagicMock() rb_experiment._raw_data = pd.DataFrame( diff --git a/supermarq-benchmarks/supermarq/qcvv/xeb_test.py b/supermarq-benchmarks/supermarq/qcvv/xeb_test.py index f6640035f..4c3634d2f 100644 --- a/supermarq-benchmarks/supermarq/qcvv/xeb_test.py +++ b/supermarq-benchmarks/supermarq/qcvv/xeb_test.py @@ -27,55 +27,51 @@ def test_xeb_init() -> None: - with patch("cirq_superstaq.service.Service"): - experiment = XEB() - assert experiment.num_qubits == 2 - assert experiment.two_qubit_gate == cirq.CZ - assert experiment.single_qubit_gate_set == [ - cirq.PhasedXZGate( - z_exponent=z, - x_exponent=0.5, - axis_phase_exponent=a, - ) - for a, z in itertools.product(np.linspace(start=0, stop=7 / 4, num=8), repeat=2) - ] + experiment = XEB() + assert experiment.num_qubits == 2 + assert experiment.two_qubit_gate == cirq.CZ + assert experiment.single_qubit_gate_set == [ + cirq.PhasedXZGate( + z_exponent=z, + x_exponent=0.5, + axis_phase_exponent=a, + ) + for a, z in itertools.product(np.linspace(start=0, stop=7 / 4, num=8), repeat=2) + ] - with pytest.raises( - RuntimeError, match="No samples to retrieve. The experiment has not been run." - ): - experiment.samples # pylint: disable=W0104 - - with pytest.raises( - RuntimeError, match="No data to retrieve. The experiment has not been run." - ): - experiment.circuit_fidelities # pylint: disable=W0104 - - experiment = XEB(two_qubit_gate=cirq.CX) - assert experiment.num_qubits == 2 - assert experiment.two_qubit_gate == cirq.CX - assert experiment.single_qubit_gate_set == [ - cirq.PhasedXZGate( - z_exponent=z, - x_exponent=0.5, - axis_phase_exponent=a, - ) - for a, z in itertools.product(np.linspace(start=0, stop=7 / 4, num=8), repeat=2) - ] + with pytest.raises( + RuntimeError, match="No samples to retrieve. The experiment has not been run." + ): + experiment.samples # pylint: disable=W0104 + + with pytest.raises(RuntimeError, match="No data to retrieve. The experiment has not been run."): + experiment.circuit_fidelities # pylint: disable=W0104 + + experiment = XEB(two_qubit_gate=cirq.CX) + assert experiment.num_qubits == 2 + assert experiment.two_qubit_gate == cirq.CX + assert experiment.single_qubit_gate_set == [ + cirq.PhasedXZGate( + z_exponent=z, + x_exponent=0.5, + axis_phase_exponent=a, + ) + for a, z in itertools.product(np.linspace(start=0, stop=7 / 4, num=8), repeat=2) + ] - experiment = XEB(single_qubit_gate_set=[cirq.X]) - assert experiment.num_qubits == 2 - assert experiment.two_qubit_gate == cirq.CZ - assert experiment.single_qubit_gate_set == [cirq.X] + experiment = XEB(single_qubit_gate_set=[cirq.X]) + assert experiment.num_qubits == 2 + assert experiment.two_qubit_gate == cirq.CZ + assert experiment.single_qubit_gate_set == [cirq.X] @pytest.fixture def xeb_experiment() -> XEB: - with patch("cirq_superstaq.service.Service"): - return XEB(single_qubit_gate_set=[cirq.X, cirq.Y, cirq.Z]) + return XEB(single_qubit_gate_set=[cirq.X, cirq.Y, cirq.Z]) def test_build_xeb_circuit() -> None: - with patch("cirq_superstaq.service.Service"), patch("numpy.random.default_rng") as rng: + with patch("numpy.random.default_rng") as rng: xeb_experiment = XEB(single_qubit_gate_set=[cirq.X, cirq.Y, cirq.Z]) rng.return_value.choice.side_effect = [ np.array([[cirq.X, cirq.Y], [cirq.Z, cirq.Y], [cirq.Y, cirq.Z]]),