Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions cirq-core/cirq/experiments/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,5 @@
InferredXEBResult,
TwoQubitXEBResult,
parallel_two_qubit_xeb,
run_rb_and_xeb,
)
65 changes: 64 additions & 1 deletion cirq-core/cirq/experiments/two_qubit_xeb.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
from cirq.experiments.xeb_fitting import benchmark_2q_xeb_fidelities
from cirq.experiments.xeb_fitting import fit_exponential_decays, exponential_decay
from cirq.experiments import random_quantum_circuit_generation as rqcg
from cirq.experiments.qubit_characterizations import ParallelRandomizedBenchmarkingResult
from cirq.experiments.qubit_characterizations import (
ParallelRandomizedBenchmarkingResult,
parallel_single_qubit_randomized_benchmarking,
)
from cirq.qis import noise_utils
from cirq._compat import cached_method

Expand Down Expand Up @@ -386,3 +389,63 @@ def parallel_two_qubit_xeb(
)

return TwoQubitXEBResult(fit_exponential_decays(fids))


def run_rb_and_xeb(
sampler: 'cirq.Sampler',
qubits: Optional[Sequence['cirq.GridQubit']] = None,
repetitions: int = 10**3,
num_circuits: int = 20,
num_clifford_range: Sequence[int] = tuple(
np.logspace(np.log10(5), np.log10(1000), 5, dtype=int)
),
entangling_gate: 'cirq.Gate' = ops.CZ,
depths_xeb: Sequence[int] = tuple(np.arange(3, 100, 20)),
xeb_combinations: int = 10,
random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = 42,
Comment thread
NoureldinYosri marked this conversation as resolved.
Outdated
) -> InferredXEBResult:
"""A convenience method that runs both RB and XEB workflows.

Args:
sampler: The quantum engine or simulator to run the circuits.
qubits: Qubits under test. If none, uses all qubits on the sampler's device.
repetitions: The number of repetitions to use for RB and XEB.
num_circuits: The number of circuits to generate for RB and XEB.
num_clifford_range: The different numbers of Cliffords in the RB study.
entangling_gate: The entangling gate to use.
depths_xeb: The cycle depths to use for XEB.
xeb_combinations: The number of combinations to generate for XEB.
random_state: The random state to use.

Returns:
An InferredXEBResult object representing the results of the experiment.

Raises:
ValueError: If qubits are not specified and the sampler has no device.
"""

if qubits is None:
qubits = _grid_qubits_for_sampler(sampler)
if qubits is None:
raise ValueError("Couldn't determine qubits from sampler. Please specify them.")

rb = parallel_single_qubit_randomized_benchmarking(
sampler=sampler,
qubits=qubits,
repetitions=repetitions,
num_circuits=num_circuits,
num_clifford_range=num_clifford_range,
)

xeb = parallel_two_qubit_xeb(
sampler=sampler,
qubits=qubits,
entangling_gate=entangling_gate,
n_repetitions=repetitions,
n_circuits=num_circuits,
cycle_depths=depths_xeb,
n_combinations=xeb_combinations,
random_state=random_state,
)

return InferredXEBResult(rb, xeb)
48 changes: 48 additions & 0 deletions cirq-core/cirq/experiments/two_qubit_xeb_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,51 @@ def test_inferred_plots(ax, target_error, kind):
combined_results.plot_histogram(target_error=target_error, kind=kind, ax=ax)
else:
combined_results.plot_histogram(target_error=target_error, kind=kind, ax=ax)


@pytest.mark.parametrize(
'sampler,qubits',
[
(
cirq.DensityMatrixSimulator(
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
),
cirq.GridQubit.rect(3, 2, 4, 3),
),
(
DensityMatrixSimulatorWithProcessor(
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
),
None,
),
],
)
def test_run_rb_and_xeb(sampler: cirq.Sampler, qubits: Optional[Sequence[cirq.GridQubit]]):
np.random.seed(0)
random.seed(0)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove here and in test_parallel_two_qubit_xeb above.

Both tests pass random_state=0 so the global seeds should not matter.
To the contrary if we see any flakiness w/r to global seeds here that would show something is wrong with random_state handling.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed them, I forgot that I already figuredout why the methods produce different results for the same seed. the reason isn't treating random_state in a wrong way but that some of the subroutines are parallized. so the order of parallization changes the results. however the tests are not flaky I wrote them to be resilient to that.


with redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):
Comment thread
NoureldinYosri marked this conversation as resolved.
Outdated
res = cirq.experiments.run_rb_and_xeb(
sampler=sampler,
qubits=qubits,
repetitions=100,
num_clifford_range=tuple(np.arange(3, 10, 1)),
xeb_combinations=1,
num_circuits=1,
depths_xeb=(3, 4, 5),
random_state=0,
)
np.testing.assert_allclose(
[res.xeb_result.xeb_error(*pair) for pair in res.all_qubit_pairs], 0.1, atol=1e-1
)


def test_run_rb_and_xeb_without_processor_fails():
sampler = (
cirq.DensityMatrixSimulator(
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
),
)

with pytest.raises(ValueError):
_ = cirq.experiments.run_rb_and_xeb(sampler=sampler)