Experiment

The experiment module offers a schema and utilities for succinctly expressing commonly used applications and algorithms in near-term quantum programming. An Experiment object is intended to be consumed by the QuantumComputer.experiment method.

NOTE: When working with the experiment method, the following declared memory labels are reserved:

  • “preparation_alpha”, “preparation_beta”, and “preparation_gamma”

  • “measurement_alpha”, “measurement_beta”, and “measurement_gamma”

  • “symmetrization”

  • “ro”

Schema

class pyquil.experiment.Experiment(settings, program, qubits=None, *, symmetrization=<SymmetrizationLevel.EXHAUSTIVE: -1>, calibration=<CalibrationMethod.PLUS_EIGENSTATE: 1>)[source]

A tomography-like experiment.

Many near-term quantum algorithms involve:

  • some limited state preparation

  • enacting a quantum process (like in tomography) or preparing a variational ansatz state (like in VQE)

  • measuring observables of the state.

Where we typically use a large number of (state_prep, measure) pairs but keep the ansatz program consistent. This class stores the ansatz program as a Program and maintains a list of ExperimentSetting objects which each represent a (state_prep, measure) pair.

Settings diagonalized by a shared tensor product basis (TPB) can (optionally) be estimated simultaneously. Therefore, this class is backed by a list of list of ExperimentSettings. Settings sharing an inner list will be estimated simultaneously. If you don’t want this, provide a list of length-1-lists. As a convenience, if you pass a 1D list to the constructor will expand it to a list of length-1-lists.

This class will not group settings for you. Please see group_experiments() for a function that will automatically process a Experiment to group Experiments sharing a TPB.

Variables
  • settings – The collection of ExperimentSetting objects that define this experiment.

  • program – The main program body of this experiment. Also determines the shots and reset instance variables. The shots instance variable is the number of shots to take per ExperimentSetting. The reset instance variable is whether to actively reset qubits instead of waiting several times the coherence length for qubits to decay to |0> naturally. Setting this to True is much faster but there is a ~1% error per qubit in the reset operation. Thermal noise from “traditional” reset is not routinely characterized but is of the same order.

  • symmetrization

    the level of readout symmetrization to perform for the estimation and optional calibration of each observable. The following integer levels, encapsulated in the SymmetrizationLevel integer enum, are currently supported:

    • -1 – exhaustive symmetrization uses every possible combination of flips

    • 0 – no symmetrization

    • 1 – symmetrization using an orthogonal array (OA) with strength 1

    • 2 – symmetrization using an orthogonal array (OA) with strength 2

    • 3 – symmetrization using an orthogonal array (OA) with strength 3

    Note that (default) exhaustive symmetrization requires a number of QPU calls exponential in the number of qubits in the union of the support of the observables in any group of settings in tomo_experiment; the number of shots may need to be increased to accommodate this. see run_symmetrized_readout() in api._quantum_computer for more information.

Methods

get_meas_qubits()

Return the sorted list of qubits that are involved in the all the out_operators of the settings for this Experiment object.

get_meas_registers([qubits])

Return the sorted list of memory registers corresponding to the list of qubits provided.

generate_experiment_program()

Generate a parameterized program containing the main body program along with some additions to support the various state preparation, measurement, and symmetrization specifications of this Experiment.

build_setting_memory_map(setting)

Build the memory map corresponding to the state preparation and measurement specifications encoded in the provided ExperimentSetting, taking into account the full set of qubits that are present in the Experiment object.

build_symmetrization_memory_maps(qubits[, label])

Build a list of memory maps to be used in a program that is trying to perform readout symmetrization via parametric compilation.

generate_calibration_experiment()

Generate another Experiment object that can be used to calibrate the various multi-qubit observables involved in this Experiment.

class pyquil.experiment.ExperimentSetting(in_state, out_operator, additional_expectations=None)[source]

Input and output settings for a tomography-like experiment.

Many near-term quantum algorithms take the following form:

  • Start in a pauli state

  • Prepare some ansatz

  • Measure it w.r.t. pauli operators

Where we typically use a large number of (start, measure) pairs but keep the ansatz preparation program consistent. This class represents the (start, measure) pairs. Typically a large number of these ExperimentSetting objects will be created and grouped into an Experiment.

Variables

additional_expectations – A list of lists, where each inner list specifies a qubit subset to calculate the joint expectation value for. This attribute allows users to extract simultaneously measurable expectation values from a single experiment setting.

class pyquil.experiment.ExperimentResult(setting, expectation, total_counts, stddev=None, std_err=None, raw_expectation=None, raw_stddev=None, raw_std_err=None, calibration_expectation=None, calibration_stddev=None, calibration_std_err=None, calibration_counts=None, additional_results=None)[source]

An expectation and standard deviation for the measurement of one experiment setting in a tomographic experiment.

In the case of readout error calibration, we also include expectation, standard deviation and count for the calibration results, as well as the expectation and standard deviation for the corrected results.

class pyquil.experiment.SymmetrizationLevel(value)[source]

An enumeration.

class pyquil.experiment.CalibrationMethod(value)[source]

An enumeration.

Utilities

pyquil.experiment.bitstrings_to_expectations(bitstrings, joint_expectations=None)[source]

Given an array of bitstrings (each of which is represented as an array of bits), map them to expectation values and return the desired joint expectation values. If no joint expectations are desired, then just the 1 -> -1, 0 -> 1 mapping is performed.

Parameters
  • bitstrings (ndarray) – Array of bitstrings to map.

  • joint_expectations (Optional[List[List[int]]]) – Joint expectation values to calculate. Each entry is a list which contains the qubits to use in calculating the joint expectation value. Entries of length one just calculate single-qubit expectation values. Defaults to None, which is equivalent to the list of single-qubit expectations [[0], [1], …, [n-1]] for bitstrings of length n.

Return type

ndarray

Returns

An array of expectation values, of the same length as the array of bitstrings. The “width” could be different than the length of an individual bitstring (n) depending on the value of the joint_expectations parameter.

pyquil.experiment.correct_experiment_result(result, calibration)[source]

Given a raw, unmitigated result and its associated readout calibration, produce the result absent readout error.

Parameters
  • result (ExperimentResult) – An ExperimentResult object with unmitigated readout error.

  • calibration (ExperimentResult) – An ExperimentResult object resulting from running readout calibration on the ExperimentSetting associated with the result parameter.

Return type

ExperimentResult

Returns

An ExperimentResult object corrected for symmetric readout error.

pyquil.experiment.merge_memory_map_lists(mml1, mml2)[source]

Given two lists of memory maps, produce the “cartesian product” of the memory maps:

merge_memory_map_lists([{a: 1}, {a: 2}], [{b: 3, c: 4}, {b: 5, c: 6}])

-> [{a: 1, b: 3, c: 4}, {a: 1, b: 5, c: 6}, {a: 2, b: 3, c: 4}, {a: 2, b: 5, c: 6}]

Parameters
Return type

List[Dict[str, List[float]]]

Returns

A list of the merged memory maps.

pyquil.experiment.ratio_variance(a, var_a, b, var_b)[source]

Given random variables ‘A’ and ‘B’, compute the variance on the ratio Y = A/B. Denote the mean of the random variables as a = E[A] and b = E[B] while the variances are var_a = Var[A] and var_b = Var[B] and the covariance as Cov[A,B]. The following expression approximates the variance of Y

Var[Y] approx (a/b) ^2 * ( var_a /a^2 + var_b / b^2 - 2 * Cov[A,B]/(a*b) )

We assume the covariance of A and B is negligible, resting on the assumption that A and B are independently measured. The expression above rests on the assumption that B is non-zero, an assumption which we expect to hold true in most cases, but makes no such assumptions about A. If we allow E[A] = 0, then calculating the expression above via numpy would complain about dividing by zero. Instead, we can re-write the above expression as

Var[Y] approx var_a /b^2 + (a^2 * var_b) / b^4

where we have dropped the covariance term as noted above.

See the following for more details:
Parameters
  • a (Union[float, ndarray]) – Mean of ‘A’, to be used as the numerator in a ratio.

  • var_a (Union[float, ndarray]) – Variance in ‘A’

  • b (Union[float, ndarray]) – Mean of ‘B’, to be used as the numerator in a ratio.

  • var_b (Union[float, ndarray]) – Variance in ‘B’

Return type

Union[float, ndarray]

pyquil.experiment.read_json(fn)[source]

Convenience method to read pyquil.experiment objects from a JSON file.

See to_json().

Return type

Any

pyquil.experiment.to_json(fn, obj)[source]

Convenience method to save pyquil.experiment objects as a JSON file.

See read_json().

Return type

str