pyquil.compatibility.v2.api package

Sub-package for facilitating usage of APIs similar to those of pyQuil v2.

class pyquil.compatibility.v2.api.QPU(*args: Any, **kwargs: Any)[source]

Bases: pyquil.api._qpu.QPU

A connection to the QPU.

Parameters
  • quantum_processor_id – Processor to run against.

  • priority – The priority with which to insert jobs into the QPU queue. Lower integers correspond to higher priority.

  • timeout – Time limit for requests, in seconds.

  • client_configuration – Optional client configuration. If none is provided, a default one will be loaded.

  • endpoint_id – Optional endpoint ID to be used for engagement.

  • engagement_manager – Optional engagement manager. If none is provided, a default one will be created.

class pyquil.compatibility.v2.api.QVM(*args: Any, **kwargs: Any)[source]

Bases: pyquil.api._qvm.QVM

A virtual machine that classically emulates the execution of Quil programs.

Parameters
  • noise_model – A noise model that describes noise to apply when emulating a program’s execution.

  • gate_noise – A tuple of three numbers [Px, Py, Pz] indicating the probability of an X, Y, or Z gate getting applied to each qubit after a gate application or reset. The default value of None indicates no noise.

  • measurement_noise – A tuple of three numbers [Px, Py, Pz] indicating the probability of an X, Y, or Z gate getting applied before a measurement. The default value of None indicates no noise.

  • random_seed – A seed for the QVM’s random number generators. Either None (for an automatically generated seed) or a non-negative integer.

  • timeout – Time limit for requests, in seconds.

  • client_configuration – Optional client configuration. If none is provided, a default one will be loaded.

class pyquil.compatibility.v2.api.QuantumComputer(*, name: str, qam: pyquil.api._qam.QAM[Any], device: Optional[Any] = None, compiler: pyquil.api._abstract_compiler.AbstractCompiler, symmetrize_readout: bool = False)[source]

Bases: pyquil.api._quantum_computer.QuantumComputer

An interface designed to ease migration from pyQuil v2 to v3, and compatible with most use cases for the pyQuil v2 QuantumComputer.

A quantum computer for running quantum programs.

A quantum computer has various characteristics like supported gates, qubits, qubit topologies, gate fidelities, and more. A quantum computer also has the ability to run quantum programs.

A quantum computer can be a real Rigetti QPU that uses superconducting transmon qubits to run quantum programs, or it can be an emulator like the QVM with noise models and mimicked topologies.

Parameters
  • name – A string identifying this particular quantum computer.

  • qam – A quantum abstract machine which handles executing quantum programs. This dispatches to a QVM or QPU.

  • device – Ignored and accepted only for backwards compatibility.

  • symmetrize_readout – Whether to apply readout error symmetrization. See run_symmetrized_readout() for a complete description.

calibrate(experiment: pyquil.experiment._main.Experiment) List[pyquil.experiment._result.ExperimentResult][source]

Perform readout calibration on the various multi-qubit observables involved in the provided Experiment.

Parameters

experiment – The Experiment to calibrate readout error for.

Returns

A list of ExperimentResult objects that contain the expectation values that correspond to the scale factors resulting from symmetric readout error.

compile(program: pyquil.quil.Program, to_native_gates: bool = True, optimize: bool = True, *, protoquil: Optional[bool] = None) Union[pyquil.api._abstract_compiler.EncryptedProgram, pyquil.quil.Program][source]

A high-level interface to program compilation.

Compilation currently consists of two stages. Please see the AbstractCompiler docs for more information. This function does all stages of compilation.

Right now both to_native_gates and optimize must be either both set or both unset. More modular compilation passes may be available in the future.

Additionally, a call to compile also calls the reset method if one is running on the QPU. This is a bit of a sneaky hack to guard against stale compiler connections, but shouldn’t result in any material hit to performance (especially when taking advantage of parametric compilation for hybrid applications).

Parameters
  • program – A Program

  • to_native_gates – Whether to compile non-native gates to native gates.

  • optimize – Whether to optimize the program to reduce the number of operations.

  • protoquil – Whether to restrict the input program to and the compiled program to protoquil (executable on QPU). A value of None means defer to server.

Returns

An executable binary suitable for passing to QuantumComputer.run().

compiler: pyquil.api._abstract_compiler.AbstractCompiler
experiment(experiment: pyquil.experiment._main.Experiment, memory_map: Optional[Mapping[str, Sequence[Union[int, float]]]] = None) List[pyquil.experiment._result.ExperimentResult][source]

Run an Experiment on a QVM or QPU backend. An Experiment is composed of:

  • A main Program body (or ansatz).

  • A collection of ExperimentSetting objects, each of which encodes a particular state preparation and measurement.

  • A SymmetrizationLevel for enacting different readout symmetrization strategies.

  • A number of shots to collect for each (unsymmetrized) ExperimentSetting.

Because the main Program is static from run to run of an Experiment, we can leverage our platform’s Parametric Compilation feature. This means that the Program can be compiled only once, and the various alterations due to state preparation, measurement, and symmetrization can all be realized at runtime by providing a memory_map. Thus, the steps in the experiment method are as follows:

  1. Generate a parameterized program corresponding to the Experiment

    (see the Experiment.generate_experiment_program() method for more details on how it changes the main body program to support state preparation, measurement, and symmetrization).

  2. Compile the parameterized program into a parametric (binary) executable, which

    contains declared variables that can be assigned at runtime.

  3. For each ExperimentSetting in the Experiment, we repeat the following:

    1. Build a collection of memory maps that correspond to the various state preparation, measurement, and symmetrization specifications.

    2. Run the parametric executable on the QVM or QPU backend, providing the memory map to assign variables at runtime.

    3. Extract the desired statistics from the classified bitstrings that are produced by the QVM or QPU backend, and package them in an ExperimentResult object.

  4. Return the list of ExperimentResult objects.

This method is extremely useful shorthand for running near-term applications and algorithms, which often have this ansatz + settings structure.

Parameters
  • experiment – The Experiment to run.

  • memory_map – A dictionary mapping declared variables / parameters to their values. The values are a list of floats or integers. Each float or integer corresponds to a particular classical memory register. The memory map provided to the experiment method corresponds to variables in the main body program that we would like to change at runtime (e.g. the variational parameters provided to the ansatz of the variational quantum eigensolver).

Returns

A list of ExperimentResult objects containing the statistics gathered according to the specifications of the Experiment.

qam: pyquil.compatibility.v2.api._qam.StatefulQAM[Any]
reset() None[source]

Reset the QuantumComputer’s QAM to its initial state.

run(executable: Union[pyquil.api._abstract_compiler.EncryptedProgram, pyquil.quil.Program], memory_map: Optional[Mapping[str, Sequence[Union[int, float]]]] = None) numpy.ndarray[source]

Run a quil executable. If the executable contains declared parameters, then a memory map must be provided, which defines the runtime values of these parameters.

Parameters
  • executable – The program to run. You are responsible for compiling this first.

  • memory_map – The mapping of declared parameters to their values. The values are a list of floats or integers.

Returns

A numpy array of shape (trials, len(ro-register)) that contains 0s and 1s.

run_and_measure(program: pyquil.quil.Program, trials: int) Dict[int, numpy.ndarray][source]

Run the provided state preparation program and measure all qubits.

The returned data is a dictionary keyed by qubit index because qubits for a given QuantumComputer may be non-contiguous and non-zero-indexed. To turn this dictionary into a 2d numpy array of bitstrings, consider:

bitstrings = qc.run_and_measure(...)
bitstring_array = np.vstack([bitstrings[q] for q in qc.qubits()]).T
bitstring_array.shape  # (trials, len(qc.qubits()))

Note

If the target QuantumComputer is a noiseless QVM then only the qubits explicitly used in the program will be measured. Otherwise all qubits will be measured. In some circumstances this can exhaust the memory available to the simulator, and this may be manifested by the QVM failing to respond or timeout.

Note

In contrast to QVMConnection.run_and_measure, this method simulates noise correctly for noisy QVMs. However, this method is slower for trials > 1. For faster noise-free simulation, consider WavefunctionSimulator.run_and_measure.

Parameters
  • program – The state preparation program to run and then measure.

  • trials – The number of times to run the program.

Returns

A dictionary keyed by qubit index where the corresponding value is a 1D array of measured bits.

run_symmetrized_readout(program: pyquil.quil.Program, trials: int, symm_type: int = 3, meas_qubits: Optional[List[int]] = None) numpy.ndarray[source]

Run a quil program in such a way that the readout error is made symmetric. Enforcing symmetric readout error is useful in simplifying the assumptions in some near term error mitigation strategies, see measure_observables for more information.

The simplest example is for one qubit. In a noisy device, the probability of accurately reading the 0 state might be higher than that of the 1 state; due to e.g. amplitude damping. This makes correcting for readout more difficult. In the simplest case, this function runs the program normally (trials//2) times. The other half of the time, it will insert an X gate prior to any MEASURE instruction and then flip the measured classical bit back. Overall this has the effect of symmetrizing the readout error.

The details. Consider preparing the input bitstring |i> (in the computational basis) and measuring in the Z basis. Then the Confusion matrix for the readout error is specified by the probabilities

p(j|i) := Pr(measured = j | prepared = i ).

In the case of a single qubit i,j in [0,1] then: there is no readout error if p(0|0) = p(1|1) = 1. the readout error is symmetric if p(0|0) = p(1|1) = 1 - epsilon. the readout error is asymmetric if p(0|0) != p(1|1).

If your quantum computer has this kind of asymmetric readout error then qc.run_symmetrized_readout will symmetrize the readout error.

The readout error above is only asymmetric on a single bit. In practice the confusion matrix on n bits need not be symmetric, e.g. for two qubits p(ij|ij) != 1 - epsilon for all i,j. In these situations a more sophisticated means of symmetrization is needed; and we use orthogonal arrays (OA) built from Hadamard matrices.

The symmetrization types are specified by an int; the types available are: -1 – exhaustive symmetrization uses every possible combination of flips 0 – trivial that is no symmetrization 1 – symmetrization using an OA with strength 1 2 – symmetrization using an OA with strength 2 3 – symmetrization using an OA with strength 3 In the context of readout symmetrization the strength of the orthogonal array enforces the symmetry of the marginal confusion matrices.

By default a strength 3 OA is used; this ensures expectations of the form <b_k . b_j . b_i> for bits any bits i,j,k will have symmetric readout errors. Here expectation of a random variable x as is denote <x> = sum_i Pr(i) x_i. It turns out that a strength 3 OA is also a strength 2 and strength 1 OA it also ensures <b_j . b_i> and <b_i> have symmetric readout errors for any bits b_j and b_i.

Parameters
  • program – The program to run symmetrized readout on.

  • trials – The minimum number of times to run the program; it is recommend that this number should be in the hundreds or thousands. This parameter will be mutated if necessary.

  • symm_type – the type of symmetrization

  • meas_qubits – An advanced feature. The groups of measurement qubits. Only these qubits will be symmetrized over, even if the program acts on other qubits.

Returns

A numpy array of shape (trials, len(ro-register)) that contains 0s and 1s.

pyquil.compatibility.v2.api.get_qc(name: str, *, as_qvm: Optional[bool] = None, noisy: Optional[bool] = None, connection: Optional[Any] = None, compiler_timeout: float = 10, client_configuration: Optional[qcs_api_client.client._configuration.configuration.QCSClientConfiguration] = None) pyquil.compatibility.v2.api._quantum_computer.QuantumComputer[source]

Compatibility layer to build a QuantumComputer supporting an API closely similar to that in pyQuil v2.