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

allow instantiation of qcvv experiments without superstaq credentials #1076

Merged
merged 3 commits into from
Sep 27, 2024
Merged
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
14 changes: 10 additions & 4 deletions supermarq-benchmarks/supermarq/qcvv/base_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"""
from __future__ import annotations

import functools
import math
import pprint
from abc import ABC, abstractmethod
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand Down
44 changes: 23 additions & 21 deletions supermarq-benchmarks/supermarq/qcvv/base_experiment_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -213,35 +212,34 @@ 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,
repetitions=100,
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}

Expand All @@ -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]
)


Expand Down Expand Up @@ -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",
Expand Down
95 changes: 42 additions & 53 deletions supermarq-benchmarks/supermarq/qcvv/irb_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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()

Expand All @@ -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(),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
76 changes: 36 additions & 40 deletions supermarq-benchmarks/supermarq/qcvv/xeb_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]]),
Expand Down