pyquil package

pyQuil is a Python library for quantum programming using Quil. pyQuil enables users to construct, manipulate, and execute quantum programs on a quantum virtual machine (QVM) and Rigetti quantum processing units (QPUs).

Refer to the pyQuil Documentation for more information.

class pyquil.Program(*instructions: AbstractInstruction | Instruction | Program | Program | Sequence[Any] | tuple[Any, ...] | str | Generator[Any, Any, Any])[source]

Bases: object

A list of pyQuil instructions that comprise a quantum program.

>>> from pyquil import Program
>>> from pyquil.gates import H, CNOT
>>> p = Program()
>>> p += H(0)
>>> p += CNOT(0, 1)

Initialize a Program.

calibrate(instruction: AbstractInstruction, previously_calibrated_instructions: set[AbstractInstruction] | None = None) list[AbstractInstruction][source]

Expand an instruction into its calibrated definition.

If a calibration definition matches the provided instruction, then the definition body is returned with appropriate substitutions made for parameters and qubit arguments. If no calibration definition matches, then the original instruction is returned. Calibrations are performed recursively, so that if a calibrated instruction produces an instruction that has a corresponding calibration, it will be expanded, and so on. If a cycle is encountered, a CalibrationError is raised.

Parameters:
  • instruction – An instruction.

  • previously_calibrated_instructions – A set of instructions that are the results of calibration expansions in the direct ancestry of instruction. Used to catch cyclic calibration expansions.

Returns:

A list of instructions, with the active calibrations expanded.

property calibrations: list[DefCalibration]

A list of Quil-T calibration definitions.

control_flow_graph() ControlFlowGraph[source]

Return the ControlFlowGraph of the program.

copy() Program[source]

Perform a deep copy of this program.

Returns:

a new Program

copy_everything_except_instructions() Program[source]

Copy all the members that live on a Program object.

Returns:

a new Program

dagger() Program[source]

Create the conjugate transpose of the Quil program. The program must contain only gate applications.

Returns:

The Quil program’s inverse

property declarations: dict[str, Declare]

A mapping from declared region names to their declarations.

declare(name: str, memory_type: str = 'BIT', memory_size: int = 1, shared_region: str | None = None, offsets: Sequence[tuple[int, str]] | None = None) MemoryReference[source]

DECLARE a quil variable.

This adds the declaration to the current program and returns a MemoryReference to the base (offset = 0) of the declared memory.

Note

This function returns a MemoryReference and cannot be chained like some of the other Program methods. Consider using inst(DECLARE(...)) if you would like to chain methods, but please be aware that you must create your own MemoryReferences later on.

Parameters:
  • name – Name of the declared variable

  • memory_type – Type of the declared memory: ‘BIT’, ‘REAL’, ‘OCTET’ or ‘INTEGER’

  • memory_size – Number of array elements in the declared memory.

  • shared_region – You can declare a variable that shares its underlying memory with another region. This allows aliasing. For example, you can interpret an array of measured bits as an integer.

  • offsets – If you are using shared_region, this allows you to share only a part of the parent region. The offset is given by an array type and the number of elements of that type. For example, DECLARE target-bit BIT SHARING real-region OFFSET 1 REAL 4 BIT will let you use target-bit to poke into the fourth bit of the second real from the leading edge of real-region.

Returns:

a MemoryReference to the start of the declared memory region, ie a memory reference to name[0].

defgate(name: str, matrix: list[list[Any]] | ndarray | matrix, parameters: list[Parameter] | None = None) Program[source]

Define a new static gate.

Note

The matrix elements along each axis are ordered by bitstring. For two qubits the order is 00, 01, 10, 11, where the the bits are ordered in reverse by the qubit index, i.e., for qubits 0 and 1 the bitstring 01 indicates that qubit 0 is in the state 1. See also the related docs in the WavefunctionSimulator Overview.

Parameters:
  • name – The name of the gate.

  • matrix – List of lists or Numpy 2d array.

  • parameters – list of parameters that are used in this gate

Returns:

The Program instance.

define_noisy_gate(name: str, qubit_indices: Sequence[int], kraus_ops: Sequence[Any]) Program[source]

Overload a static ideal gate with a noisy one defined in terms of a Kraus map.

Note

The matrix elements along each axis are ordered by bitstring. For two qubits the order is 00, 01, 10, 11, where the the bits are ordered in reverse by the qubit index, i.e., for qubits 0 and 1 the bitstring 01 indicates that qubit 0 is in the state 1. See also the related docs in the WavefunctionSimulator Overview.

Parameters:
  • name – The name of the gate.

  • qubit_indices – The qubits it acts on.

  • kraus_ops – The Kraus operators.

Returns:

The Program instance

define_noisy_readout(qubit: int, p00: float, p11: float) Program[source]

For this program define a classical bit flip readout error channel parametrized by p00 and p11.

This models the effect of thermal noise that corrupts the readout signal after it has interrogated the qubit.

Parameters:
  • qubit – The qubit with noisy readout.

  • p00 – The probability of obtaining the measurement result 0 given that the qubit is in state 0.

  • p11 – The probability of obtaining the measurement result 1 given that the qubit is in state 1.

Returns:

The Program with an appended READOUT-POVM Pragma.

property defined_gates: list[DefGate]

A list of defined gates on the program.

filter_instructions(predicate: Callable[[AbstractInstruction], bool]) Program[source]

Return a new Program containing only the instructions for which predicate returns True.

Parameters:

predicate – A function that takes an instruction and returns True if the instruction should not be removed from the program, False otherwise.

Returns:

A new Program object with the filtered instructions.

property frames: dict[Frame, DefFrame]

A mapping from Quil-T frames to their definitions.

gate(name: str, params: Sequence[Expression | MemoryReference | int | float | complex | number], qubits: Sequence[Qubit | QubitPlaceholder]) Program[source]

Add a gate to the program.

Note

The matrix elements along each axis are ordered by bitstring. For two qubits the order is 00, 01, 10, 11, where the the bits are ordered in reverse by the qubit index, i.e., for qubits 0 and 1 the bitstring 01 indicates that qubit 0 is in the state 1. See also the related docs in the WavefunctionSimulator Overview.

Parameters:
  • name – The name of the gate.

  • params – Parameters to send to the gate.

  • qubits – Qubits that the gate operates on.

Returns:

The Program instance

get_all_instructions() list[AbstractInstruction][source]

Get _all_ instructions that makeup the program.

get_calibration(instr: AbstractInstruction) DefCalibration | DefMeasureCalibration | None[source]

Get the calibration corresponding to the provided instruction.

Parameters:

instr – An instruction.

Returns:

A matching Quil-T calibration definition, if one exists.

get_qubit_indices() set[int][source]

Return the index of each qubit used in the program.

Will raise an exception if any of the qubits are placeholders.

get_qubits(indices: bool = True) set[Qubit | QubitPlaceholder | FormalArgument | int] | set[int][source]

Return all of the qubit indices used in this program, including gate applications and allocated qubits.

For example:

>>> from pyquil.gates import H
>>> p = Program()
>>> p.inst(("H", 1))
Program { ... }
>>> p.get_qubits()
{1}
>>> q = QubitPlaceholder()
>>> p.inst(H(q))
Program { ... }
>>> len(p.get_qubits(indices=False))
2
Parameters:

indices – Return qubit indices as integers instead of the wrapping Qubit object

Returns:

A set of all the qubit indices used in this program

Deprecated since version 4.0: The indices flag will be removed. Use get_qubit_indices() instead.

if_then(classical_reg: MemoryReference | MemoryReference | tuple[str, int] | list[Any] | str, if_program: Program, else_program: Program | None = None) Program[source]

If the classical register at index classical reg is 1, run if_program, else run else_program.

Equivalent to the following construction:

IF [c]:
   instrA...
ELSE:
   instrB...
=>
  JUMP-WHEN @THEN [c]
  instrB...
  JUMP @END
  LABEL @THEN
  instrA...
  LABEL @END
Parameters:
  • classical_reg – The classical register to check as the condition

  • if_program – A Quil program to execute if classical_reg is 1

  • else_program – A Quil program to execute if classical_reg is 0. This argument is optional and defaults to an empty Program.

Returns:

The Quil Program with the branching instructions added.

inst(*instructions: AbstractInstruction | Instruction | Program | Program | Sequence[Any] | tuple[Any, ...] | str | Generator[Any, Any, Any]) Program[source]

Mutates the Program object by appending new instructions.

This function accepts a number of different valid forms, e.g.

>>> from pyquil import Program
>>> from pyquil.gates import H
>>> p = Program()
>>> p.inst(H(0))  # A single instruction
Program { ... }
>>> p.inst(H(0), H(1))  # Multiple instructions
Program { ... }
>>> p.inst([H(0), H(1)])  # A list of instructions
Program { ... }
>>> p.inst(H(i) for i in range(4))  # A generator of instructions
Program { ... }
>>> p.inst("H 0")  # A string representing an instruction
Program { ... }
>>> q = Program()
>>> p.inst(q)  # Another program
Program { ... }
It can also be chained:
>>> p = Program()
>>> p.inst(H(0)).inst(H(1))
Program { ... }
Parameters:

instructions – A list of Instruction objects, e.g. Gates

Returns:

self for method chaining

property instructions: list[AbstractInstruction]

Fill in any placeholders and return a list of quil AbstractInstructions.

is_protoquil(quilt: bool = False) bool[source]

Return True, this method is deprecated.

Deprecated since version 4.0: This function always returns True and will be removed.

is_supported_on_qpu() bool[source]

Return True, this method is deprecated.

Deprecated since version 4.0: This function always returns True and will be removed.

match_calibrations(instr: AbstractInstruction) CalibrationMatch | None[source]

Attempt to match a calibration to the provided instruction.

Note: preference is given to later calibrations, i.e. in a program with

DEFCAL X 0:

<a>

DEFCAL X 0:

<b>

the second calibration, with body <b>, would be the calibration matching X 0.

Parameters:

instr – An instruction.

Returns:

a CalibrationMatch object, if one can be found.

measure(qubit: Qubit | QubitPlaceholder | FormalArgument | int, classical_reg: MemoryReference | MemoryReference | tuple[str, int] | list[Any] | str | None) Program[source]

Measures a qubit at qubit_index and puts the result in classical_reg.

Parameters:
  • qubit – The qubit to measure.

  • classical_reg – The classical register to measure into, or None.

Returns:

The Quil Program with the appropriate measure instruction appended, e.g. MEASURE 0 [1]

measure_all(*qubit_reg_pairs: tuple[Qubit | QubitPlaceholder | FormalArgument | int, MemoryReference | MemoryReference | tuple[str, int] | list[Any] | str | None]) Program[source]

Measures many qubits into their specified classical bits, in the order they were entered.

If no qubit/register pairs are provided, measure all qubits present in the program into classical addresses of the same index.

Parameters:

qubit_reg_pairs – Tuples of qubit indices paired with classical bits.

Returns:

The Quil Program with the appropriate measure instructions appended, e.g.

MEASURE 0 [1]
MEASURE 1 [2]
MEASURE 2 [3]
property measure_calibrations: list[DefMeasureCalibration]

A list of measure calibrations.

no_noise() Program[source]

Prevent a noisy gate definition from being applied to the immediately following Gate instruction.

Returns:

Program

out(*, calibrations: bool | None = True) str[source]

Serialize the Quil program to a string suitable for submitting to the QVM or QPU.

prepend_instructions(instructions: Iterable[AbstractInstruction]) Program[source]

Prepend instructions to the beginning of the program.

remove_quil_t_instructions() Program[source]

Return a copy of the program with all Quil-T instructions removed.

reset(qubit_index: int | None = None) Program[source]

Reset all qubits or just a specific qubit at qubit_index.

Parameters:

qubit_index – The address of the qubit to reset. If None, reset all qubits.

Returns:

The Quil Program with the appropriate reset instruction appended, e.g. RESET 0

resolve_label_placeholders() None[source]

Resolve all label placeholders in the program.

resolve_placeholders() None[source]

Resolve all label and qubit placeholders in the program.

A default resolver will generate a unique value for each placeholder within the scope of the program.

resolve_placeholders_with_custom_resolvers(*, label_resolver: Callable[[LabelPlaceholder], str | None] | None = None, qubit_resolver: Callable[[QubitPlaceholder], int | None] | None = None) None[source]

Resolve LabelPlaceholder\s and QubitPlaceholder\s within the program using a function.

If you provide label_resolver and/or qubit_resolver, they will be used to resolve those values respectively. If your resolver returns None for a particular placeholder, it will not be replaced but will be left as a placeholder.

If you do not provide a resolver for a placeholder, a default resolver will be used which will generate a unique value for that placeholder within the scope of the program using an auto-incrementing value (for qubit) or suffix (for target) while ensuring that unique value is not already in use within the program.

resolve_qubit_placeholders() None[source]

Resolve all qubit placeholders in the program.

resolve_qubit_placeholders_with_mapping(qubit_mapping: dict[QubitPlaceholder, int]) None[source]

Resolve all qubit placeholders using a mapping of QubitPlaceholder\s to the index they resolve to.

property waveforms: dict[str, DefWaveform]

A mapping from waveform names to their corresponding definitions.

while_do(classical_reg: MemoryReference | MemoryReference | tuple[str, int] | list[Any] | str, q_program: Program) Program[source]

While a classical register at index classical_reg is 1, loop q_program.

Equivalent to the following construction:

WHILE [c]:
   instr...
=>
  LABEL @START
  JUMP-UNLESS @END [c]
  instr...
  JUMP @START
  LABEL @END
Parameters:
  • classical_reg (MemoryReferenceDesignator) – The classical register to check

  • q_program (Program) – The Quil program to loop.

Returns:

The Quil Program with the loop instructions added.

with_loop(num_iterations: int, iteration_count_reference: MemoryReference, start_label: Label | LabelPlaceholder, end_label: Label | LabelPlaceholder) Program[source]

Return a copy of the Program wrapped in a Quil loop that will execute num_iterations times.

This loop is implemented with Quil and should not be confused with the num_shots property set by wrap_in_numshots_loop(). The latter is metadata on the program that can tell an executor how many times to run the program. In comparison, this method adds Quil instructions to your program to specify a loop in the Quil program itself.

The loop is constructed by wrapping the body of the program in classical Quil instructions. The given iteration_count_reference must refer to an INTEGER memory region. The value at the reference given will be set to num_iterations and decremented in the loop. The loop will terminate when the reference reaches 0. For this reason your program should not itself modify the value at the reference unless you intend to modify the remaining number of iterations (i.e. to break the loop).

The given start_label and end_label will be used as the entry and exit points for the loop, respectively. You should provide unique JumpTarget\s that won’t be used elsewhere in the program.

If num_iterations is 1, then a copy of the program is returned without any changes. Raises a TypeError if num_iterations is negative.

Parameters:
  • num_iterations – The number of times to execute the loop.

  • loop_count_reference – The memory reference to use as the loop counter.

  • start_label – The JumpTarget to use at the start of the loop.

  • end_label – The JumpTarget to use to at the end of the loop.

wrap_in_numshots_loop(shots: int) Program[source]

Wrap a Quil program in a loop that re-runs the same program many times.

Note: this function is a prototype of what will exist in the future when users will be responsible for writing this loop instead of having it happen automatically.

Parameters:

shots – Number of iterations to loop through.

pyquil.get_qc(name: str, *, as_qvm: bool | None = None, noisy: bool | None = None, compiler_timeout: float = 30.0, execution_timeout: float = 30.0, client_configuration: QCSClient | None = None, endpoint_id: str | None = None, quilc_client: QuilcClient | None = None, qvm_client: QVMClient | None = None) QuantumComputer[source]

Get a quantum computer.

A quantum computer is an object of type QuantumComputer and can be backed either by a QVM simulator (“Quantum/Quil Virtual Machine”) or a physical Rigetti QPU (“Quantum Processing Unit”) made of superconducting qubits.

You can choose the quantum computer to target through a combination of its name and optional flags. There are multiple ways to get the same quantum computer. The following are equivalent:

>>> qc = get_qc("Aspen-M-3-qvm")  
>>> qc = get_qc("Aspen-M-3", as_qvm=True)  

and will construct a simulator of an Aspen-M-3 lattice. We also provide a means for constructing generic quantum simulators that are not related to a given piece of Rigetti hardware:

>>> qc = get_qc("9q-square-qvm")
>>> qc = get_qc("9q-square", as_qvm=True)

Finally, you can get request a QVM with “no” topology of a given number of qubits (technically, it’s a fully connected graph among the given number of qubits) with:

>>> qc = get_qc("5q-qvm") # or "6q-qvm", or "34q-qvm", ...

These less-realistic, fully-connected QVMs will also be more lenient on what types of programs they will run. Specifically, you do not need to do any compilation. For the other, realistic QVMs you must use qc.compile() or qc.compiler.native_quil_to_executable() prior to qc.run().

The Rigetti QVM must be downloaded from https://www.rigetti.com/forest and run as a server alongside your python program. To use pyQuil’s built-in QVM, replace all "-qvm" suffixes with "-pyqvm":

>>> qc = get_qc("5q-pyqvm")

Redundant flags are acceptable, but conflicting flags will raise an exception:

>>> qc = get_qc("9q-square-qvm") # qc is fully specified by its name
>>> qc = get_qc("9q-square-qvm", as_qvm=True) # redundant, but ok
>>> qc = get_qc("9q-square-qvm", as_qvm=False) # Error!
Traceback (most recent call last):
ValueError: The provided qc name indicates you are getting a QVM, but you have specified `as_qvm=False`

Use list_quantum_computers() to retrieve a list of known qc names.

This method is provided as a convenience to quickly construct and use QVM’s and QPU’s. Power users may wish to have more control over the specification of a quantum computer (e.g. custom noise models, bespoke topologies, etc.). This is possible by constructing a QuantumComputer object by hand. Please refer to the documentation on QuantumComputer for more information.

Parameters:
  • name – The name of the desired quantum computer. This should correspond to a name returned by list_quantum_computers(). Names ending in “-qvm” will return a QVM. Names ending in “-pyqvm” will return a PyQVM. Names ending in “-noisy-qvm” will return a QVM with a noise model. Otherwise, we will return a QPU with the given name.

  • as_qvm – An optional flag to force construction of a QVM (instead of a QPU). If specified and set to True, a QVM-backed quantum computer will be returned regardless of the name’s suffix

  • noisy – An optional flag to force inclusion of a noise model. If specified and set to True, a quantum computer with a noise model will be returned regardless of the name’s suffix. The generic QVM noise model is simple T1 and T2 noise plus readout error. See decoherence_noise_with_asymmetric_ro(). Note, we currently do not support noise models based on QCS hardware; a value of True` will result in an error if the requested QPU is a QCS hardware QPU.

  • compiler_timeout – Time limit for compilation requests, in seconds.

  • execution_timeout – Time limit for execution requests, in seconds.

  • client_configuration – Optional client configuration. If none is provided, a default one will be loaded. For more information on setting up QCS credentials, see documentation for using the QCS CLI: [https://docs.rigetti.com/qcs/guides/using-the-qcs-cli#configuring-credentials].

  • endpoint_id – Optional quantum processor endpoint ID, as used in the QCS API Docs.

Returns:

A pre-configured QuantumComputer

pyquil.list_quantum_computers(qpus: bool = True, qvms: bool = True, timeout: float = 10.0, client_configuration: QCSClient | None = None) list[str][source]

List the names of available quantum computers.

Parameters:
  • qpus – Whether to include QPUs in the list.

  • qvms – Whether to include QVMs in the list.

  • timeout – Time limit for request, in seconds.

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

Subpackages

Submodules