supermarq.qcvv
A toolkit of QCVV routines.
Submodules
Classes
Interleaved random benchmarking (IRB) experiment. |
|
Data structure for the IRB experiment results. |
|
Base class for gate benchmarking experiments. |
|
A dataclass for storing the data and analyze results of the experiment. Requires |
|
Data structure for the RB experiment results. |
|
SU2 benchmarking experiment. |
|
Data structure for the SU2 experiment results. |
|
A sample circuit to use along with any data about the circuit |
|
Cross-entropy benchmarking (XEB) experiment. |
|
Results from an XEB experiment. |
Package Contents
- class supermarq.qcvv.IRB(num_circuits: int, cycle_depths: collections.abc.Iterable[int], interleaved_gate: cirq.Gate | None = cirq.Z, qubits: int | collections.abc.Sequence[cirq.Qid] = 1, clifford_op_gateset: cirq.CompilationTargetGateset = cirq.CZTargetGateset(), *, random_seed: int | numpy.random.Generator | None = None, _samples: list[supermarq.qcvv.base_experiment.Sample] | None = None, **kwargs: str)
Bases:
supermarq.qcvv.base_experiment.QCVVExperiment[_RBResultsBase]Interleaved random benchmarking (IRB) experiment.
IRB estimates the gate error of specified Clifford gate, \(\mathcal{C}^*\). This is achieved by first choosing a random sequence, \(\{\mathcal{C_i}\}_m\) of \(m\) Clifford gates and then using this to generate two circuits. The first is generated by appending to this sequence the single gate that corresponds to the inverse of the original sequence. The second circuit it obtained by inserting the interleaving gate, \(\mathcal{C}^*\) after each gate in the sequence and then again appending the corresponding inverse element of the new circuit. Thus both circuits correspond to the identity operation.
We run both circuits on the specified target and calculate the probability of measuring the resulting state in the ground state, \(p(0...0)\). This gives the circuit fidelity
\[f(m) = 2p(0...0) - 1\]We can then fit an exponential decay \(\log(f) \sim m\) to this circuit fidelity for each circuit, with decay rates \(\alpha\) and \(\tilde{\alpha}\) for the circuit without and with interleaving respectively. Finally the gate error of the specified gate, \(\mathcal{C}^*\) is estimated as
\[e_{\mathcal{C}^*} = \frac{1}{2} \left(1 - \frac{\tilde{\alpha}}{\alpha}\right)\]For more details see: https://arxiv.org/abs/1203.4550
- gates_per_clifford(samples: int = 500) dict[str, float]
Samples a number of random Clifford operations and calculates the average number of single and two qubit gates used to implement them. Note this depends on the gateset chosen for the experiment.
- Parameters:
samples – Number of samples to use. Defaults to 500.
- Returns:
A dictionary with the average number of one and two qubit gates used.
- random_clifford() cirq.CliffordGate
Returns: A random clifford gate with the correct number of qubits for the current experiment.
- random_single_qubit_clifford() cirq.SingleQubitCliffordGate
Choose a random single qubit clifford gate.
- Returns:
The random clifford gate.
- random_two_qubit_clifford() cirq.CliffordGate
Choose a random two qubit clifford gate.
For algorithm details see https://arxiv.org/abs/1402.4848 & https://arxiv.org/abs/1210.7011.
- Returns:
The random clifford gate.
- clifford_op_gateset
The gateset to use when implementing Clifford operations.
- class supermarq.qcvv.IRBResults
Bases:
_RBResultsBaseData structure for the IRB experiment results.
- plot_results(filename: str | None = None) matplotlib.pyplot.Figure
Plot the exponential decay of the circuit fidelity with cycle depth.
- Parameters:
filename – Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot.
- Returns:
A single matplotlib figure containing the IRB and RB decay plots and the corresponding fits.
- Raises:
RuntimeError – If no data is stored.
- print_results() None
Prints the key results data.
- property average_interleaved_gate_error: float
Returns: Estimate of the interleaving gate error.
- property average_interleaved_gate_error_std: float
Returns: Standard deviation of the estimate for the interleaving gate error.
- property irb_decay_coefficient: float
Returns: Decay coefficient estimate with the interleaving gate.
- property irb_decay_coefficient_std: float
Returns: Standard deviation of the decay coefficient estimate with the interleaving gate.
- class supermarq.qcvv.QCVVExperiment(qubits: int | collections.abc.Sequence[cirq.Qid], num_circuits: int, cycle_depths: collections.abc.Iterable[int], *, random_seed: int | numpy.random.Generator | None = None, results_cls: type[ResultsT], _samples: collections.abc.Sequence[Sample] | None = None, **kwargs: Any)
Bases:
abc.ABC,Generic[ResultsT]Base class for gate benchmarking experiments.
The interface for implementing these experiments is as follows:
First instantiate the desired experiment object
experiment = ExampleExperiment(<<args/kwargs>>)
Prepare the circuits and run the experiment on the desired target. This can either be a custom simulator or a real device name. For example:
noise_model = cirq.depolarize(p=0.01, n_qubits=1) sim = cirq.DensityMatrixSimulator(noise=noise_model) results = experiment.run_with_simulator(simulator=sim, <<args/kwargs>>)
Then we analyse the results. If the target was a local simulator this will be available as soon as the
run_with_simulator()method has finished executing. On the other hand if a real device was accessed via Superstaq then it may take time for the data to be available from the server. Theresults.data_readyattribute will returnTruewhen all data has been collected and is ready to be analyzed.if results.data_ready(): results.analyze(<<args>>)
When implementing a new experiment, 4 methods need to be implemented:
experiment._build_circuits(): Given a number of circuits and an iterable of thedifferent numbers of layers to use, return a list of
Sampleobjects that need to be sampled during the experiment.
results._analyse_results(): Analyse the experimental data and store the finalresults, for example some fidelities.
results.plot_results(): Produce any relevant plots that are useful for understandingthe results of the experiment.
results.print_results(): Prints the results to the console.
- static canonicalize_bitstring(key: int | str, num_qubits: int) str
Checks that the provided key represents a bit string for the given number of qubits. If the key is provided as an integer then this is reformatted as a bitstring.
- Parameters:
key – The integer or string which represents a bitstring.
num_qubits – The number of bits that the bitstring needs to have
- Raises:
ValueError – If the key is integer and negative
ValueError – If the key is integer but to large for the given number of qubits.
ValueError – If the key is a string but the wrong length.
ValueError – If the key is a string but contains characters that are not 0 or 1.
TypeError – If the key value is not a string or integral.
- Returns:
The canonicalized representation of the bitstring.
- static canonicalize_probabilities(results: collections.abc.Mapping[str, float] | collections.abc.Mapping[int, float], num_qubits: int) dict[str, float]
Reformats a dictionary of probabilities/counts so that all keys are bitstrings and that there are no missing values. Also renormalizes so that the resulting probabilities sum to 1 and sorts the dictionary by bitstring.
- Parameters:
results – The unformatted probabilities or counts
num_qubits – The number of qubits, used to determine the bitstring length.
- Raises:
ValueError – If any counts or probabilities are negative.
ValueError – If there are no non-zero counts.
- Returns:
The formatted dictionary of probabilities.
- classmethod from_file(filename: str | pathlib.Path) Self
Load the experiment from a json file.
- Parameters:
filename – Filename to load from.
- Returns:
The loaded experiment.
- results_from_records(records: _typeshed.SupportsItems[uuid.UUID | int, collections.abc.Mapping[str, float] | collections.abc.Mapping[int, float]]) ResultsT
Creates a results object from records of the counts/probabilities for each sample circuit. This function is aimed at users who would like to use the QCVV framework to generate sample circuits and analyse the results but need to run these circuits without submitting a job to Superstaq.
- Parameters:
records – A dictionary of the counts/probabilities for each sample, keyed by either the sample UUID or the index of the sample in the experiment. The counts/probabilities for each sample should be provided as a dictionary of keyed by either the bitstring or the integer value of that bitstring.
- Returns:
The experiment results object.
- run_on_device(target: str, repetitions: int = 10000, method: str | None = None, **target_options: Any) ResultsT
Submit the circuit samples to the desired target device and store the resulting probabilities.
The set of circuits is partitioned as necessary to not exceed the maximum circuits that can be submitted to the given target device. The function then waits for the jobs to complete before saving the resulting probability distributions.
- Parameters:
target – The name of a Superstaq target.
repetitions – The number of shots to sample. Defaults to 10,000.
method – Optional method to use on the Superstaq device. Defaults to None corresponding to normal running.
target_options – Optional configuration dictionary passed when submitting the job.
- Returns:
The experiment results object.
- run_with_callable(circuit_eval_func: collections.abc.Callable[[cirq.Circuit], collections.abc.Mapping[str, float] | collections.abc.Mapping[int, float]], **kwargs: Any) ResultsT
Evaluates the probabilities for each circuit using a user provided callable function. This function should take a circuit as input and return a dictionary of probabilities for each bitstring (including states with zero probability).
- Parameters:
circuit_eval_func – The custom function to use when evaluating circuit probabilities.
kwargs – Additional arguments to pass to the custom function.
- Returns:
The experiment results object.
- run_with_simulator(simulator: cirq.Sampler | None = None, repetitions: int = 10000) ResultsT
Use the local simulator to sample the circuits and store the resulting probabilities.
- Parameters:
simulator – A local
Samplerto use. If None then the defaultcirq.Simulatorsimulator is used. Defaults to None.repetitions – The number of shots to sample. Defaults to 10,000.
- Returns:
The experiment results object.
- to_file(filename: str | pathlib.Path) None
Save the experiment to a json file.
- Parameters:
filename – Filename to save to.
- property circuits: list[cirq.Circuit]
All circuits in this experiment, as a list.
- cycle_depths
The different cycle depths to test at.
- num_circuits
The number of circuits to build for each cycle depth.
- property num_qubits: int
The number of qubits used in the experiment.
- qubits: tuple[cirq.Qid, Ellipsis]
- class supermarq.qcvv.QCVVResults
Bases:
abc.ABCA dataclass for storing the data and analyze results of the experiment. Requires subclassing for each new experiment type.
- analyze(plot_results: bool = True, print_results: bool = True, plot_filename: str | None = None) None
Perform the experiment analysis and store the results in the results attribute.
- Parameters:
plot_results – Whether to generate plots of the results. Defaults to True.
print_results – Whether to print the final results. Defaults to True.
plot_filename – Optional argument providing a filename to save the plots to. Ignored if plot_results=False Defaults to None, indicating not to save the plot.
- abstract plot_results(filename: str | None = None) matplotlib.pyplot.Figure
Plot the results of the experiment.
- Parameters:
filename – Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot.
- Returns:
A single matplotlib figure containing the relevant plots of the results data.
- abstract print_results() None
Prints the key results data.
- data: pandas.DataFrame | None = None
The raw data generated.
- property data_ready: bool
Whether the experimental data is ready to analyse.
- Raises:
RuntimeError – If their is no stored data and no Superstaq job to use to collect the results.
- experiment: QCVVExperiment[QCVVResults]
Reference to the underlying experiment that generated these results experiment.
- job: cirq_superstaq.Job | None = None
The associated Superstaq job (if applicable).
- property num_circuits: int
Returns: The number of circuits in the experiment.
- property num_qubits: int
Returns: The number of qubits in the experiment.
- property parent: Self
- property qubits: tuple[cirq.Qid, Ellipsis]
- target: str
The target device that was used.
- class supermarq.qcvv.RBResults
Bases:
_RBResultsBaseData structure for the RB experiment results.
- plot_results(filename: str | None = None) matplotlib.pyplot.Figure
Plot the exponential decay of the circuit fidelity with cycle depth.
- Parameters:
filename – Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot.
- Returns:
A single matplotlib figure containing the RB decay plot and the corresponding fit.
- Raises:
RuntimeError – If no data is stored.
- print_results() None
Prints the key results data.
- property average_error_per_clifford: float
Returns: Estimate of the average error per Clifford operation.
- property average_error_per_clifford_std: float
Returns: Standard deviation of the the average error per Clifford operation.
- class supermarq.qcvv.SU2(num_circuits: int, cycle_depths: collections.abc.Iterable[int], two_qubit_gate: cirq.Gate = cirq.CZ, *, random_seed: int | numpy.random.Generator | None = None, _samples: list[supermarq.qcvv.base_experiment.Sample] | None = None, **kwargs: str)
Bases:
supermarq.qcvv.base_experiment.QCVVExperiment[SU2Results]SU2 benchmarking experiment.
SU2 benchmarking extracts the fidelity of a given two qubit gate, even in the presence of additional single qubit errors. The method works by sampling circuits of the form
0: ──|─Rr───Q───X───Q──|─ ^{n} ... ─|─Rr───X─|─ ^{N-n} ... ──Rf───M─── | │ │ | | | │ 1: ──|─Rr───Q───X───Q──|─ ... ─|─Rr───X─|─ ... ──Rf───M───Where each
Rrgate is a randomly chosen \(SU(2)\) rotation and theRfgates are single qubit \(SU(2)\) rotations that in the absence of noise invert the preceding circuit so that the final qubit state should be00.An exponential fit decay is then fitted to the observed 00 state probability as it decays with the number of two qubit gates included. Note that all circuits contain a fixed number of single qubit gates, so that the contribution for single qubit noise is constant.
See Fig. 3 of https://www.nature.com/articles/s41586-023-06481-y#Fig3 for further details.
- two_qubit_gate
The two qubit gate to be benchmarked
- class supermarq.qcvv.SU2Results
Bases:
supermarq.qcvv.base_experiment.QCVVResultsData structure for the SU2 experiment results.
- plot_results(filename: str | None = None) matplotlib.pyplot.Figure
Plot the results of the experiment.
- Parameters:
filename – Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot.
- Returns:
A single matplotlib figure containing the relevant plots of the results data.
- Raises:
RuntimeError – If there is no data stored.
- print_results() None
Prints the key results data.
- property single_qubit_noise: float
Returns: Estimated single qubit noise.
- property single_qubit_noise_std: float
Returns: Standard deviation of estimated single qubit noise.
- property two_qubit_gate_error: float
Returns: The two qubit gate error. Equal to one minus the fidelity.
- property two_qubit_gate_error_std: float
Returns: The two qubit gate error standard deviation. Equal to standard deviation of the fidelity.
- property two_qubit_gate_fidelity: float
Returns: Estimated two qubit gate fidelity.
- property two_qubit_gate_fidelity_std: float
Returns: Standard deviation of estimated two qubit gate fidelity.
- class supermarq.qcvv.Sample
A sample circuit to use along with any data about the circuit that is needed for analysis.
- circuit: cirq.Circuit
The raw (i.e. pre-compiled) sample circuit.
- circuit_realization: int
Indicates which realization of the random circuit this sample is. There will be D samples with matching circuit realization value, one for each cycle depth being measured. This index is useful for grouping results during analysis.
- data: dict[str, Any]
The corresponding data about the circuit that is needed when analyzing results (e.g. cycle depth).
- uuid: Sample.uuid
The unique ID of the sample.
- class supermarq.qcvv.XEB(num_circuits: int, cycle_depths: collections.abc.Iterable[int], interleaved_layer: cirq.Gate | cirq.OP_TREE | None = cirq.CZ, single_qubit_gate_set: collections.abc.Sequence[cirq.Gate] | None = None, *, random_seed: int | numpy.random.Generator | None = None, _samples: list[supermarq.qcvv.base_experiment.Sample] | None = None, **kwargs: str)
Bases:
supermarq.qcvv.base_experiment.QCVVExperiment[XEBResults]Cross-entropy benchmarking (XEB) experiment.
The XEB experiment can be used to estimate the combined fidelity of a repeating cycle of gates. Cycles are made up of randomly selected single qubit gates and a constant layer of interest. This is illustrated as follows:
For each randomly generated circuit, with a given number of cycle, we compare the simulated state probabilities, \(p(x)\) with those achieved by running the circuit on a given target, \(\hat{p}(x)\). The fidelity of a circuit containing \(d\) cycles, \(f_d\) can then be estimated as
\[\sum_{x \in \{0, 1\}^n} p(x) \hat{p}(x) - \frac{1}{2^n} = f_d \left(\sum_{x \in \{0, 1\}^n} p(x)^2 - \frac{1}{2^n}\right)\]We can therefore fit a linear model to estimate the value of \(f_d\). We the estimate the fidelity of the cycle, \(f_{\mathrm{cycle}}\) as
\[f_d = A(f_{cycle})^d\]Thus fitting another linear model to \(\log(f_d) \sim d\) provides us with an estimate of the cycle fidelity.
For more details see: https://www.nature.com/articles/s41586-019-1666-5
- independent_qubit_groups() list[tuple[cirq.Qid, Ellipsis]]
Get all independent subsets of qubits in this experiment.
- Returns:
A list of disjoint tuples of cirq.Qid objects, each of which can be analyzed as an independent XEB experiment.
- interleaved_layer: cirq.OP_TREE | None
The layer to interleave.
- single_qubit_gate_set: list[cirq.Gate]
The single qubit gates to randomly sample from
- class supermarq.qcvv.XEBResults
Bases:
supermarq.qcvv.base_experiment.QCVVResultsResults from an XEB experiment.
- plot_results(filename: str | None = None) matplotlib.pyplot.Figure
Plot the experiment data and the corresponding fits.
- Parameters:
filename – Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot.
- Returns:
A single matplotlib figure containing both the linear fit per cycle depth and the decay with cycle depth.
- Raises:
RuntimeError – If there is no data stored.
- plot_speckle(filename: str | None = None) matplotlib.pyplot.Figure
Creates the speckle plot of the XEB data. See Fig. S18 of https://arxiv.org/abs/1910.11333 for an explanation of this plot.
- Parameters:
filename – Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot.
- Returns:
A matplotlib figure with the speckle plot.
- Raises:
RuntimeError – If there is no data stored.
- print_results() None
Prints the key results data.
- property cycle_fidelity_estimate: float
Estimated cycle fidelity.
- property cycle_fidelity_estimate_std: float
Standard deviation for the cycle fidelity estimate.