##############################################################################
# Copyright 2016-2018 Rigetti Computing
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##############################################################################
"""
Contains the core pyQuil objects that correspond to Quil instructions.
"""
import abc
from typing import (
Any,
Callable,
ClassVar,
Container,
Dict,
Iterable,
List,
Optional,
Sequence,
Set,
Tuple,
Union,
TYPE_CHECKING,
)
from typing_extensions import Self
import numpy as np
from deprecated.sphinx import deprecated
from pyquil.quilatom import (
Expression,
Label,
LabelPlaceholder,
MemoryReference,
Parameter,
ParameterDesignator,
Frame,
Waveform,
Qubit,
QubitDesignator,
QubitPlaceholder,
FormalArgument,
_convert_to_py_qubit,
_convert_to_py_qubits,
_convert_to_rs_expression,
_convert_to_rs_expressions,
_convert_to_rs_qubit,
_convert_to_rs_qubits,
_convert_to_py_expression,
_convert_to_py_expressions,
_convert_to_py_waveform,
unpack_qubit,
)
if TYPE_CHECKING: # avoids circular import
from pyquil.paulis import PauliSum
import quil.instructions as quil_rs
import quil.expression as quil_rs_expr
class _InstructionMeta(abc.ABCMeta):
"""
A metaclass that allows us to group all instruction types from quil-rs and pyQuil as an `AbstractInstruction`.
As such, this should _only_ be used as a metaclass for `AbstractInstruction`.
"""
def __init__(self, *args: Any, **_: Any):
self.__name = args[0]
try:
self.__is_abstract_instruction = args[1][0] == AbstractInstruction
except Exception:
self.__is_abstract_instruction = False
def __instancecheck__(self, __instance: Any) -> bool:
# Already an Instruction, return True
if isinstance(__instance, quil_rs.Instruction):
return True
# __instance is not an Instruction or AbstractInstruction, return False
if self.__name not in ["AbstractInstruction", "DefGate"] and not self.__is_abstract_instruction:
return False
# __instance is a subclass of AbstractInstruction, do the normal check
return super().__instancecheck__(__instance)
[docs]class AbstractInstruction(metaclass=_InstructionMeta):
"""
Abstract class for representing single instructions.
"""
def __str__(self) -> str:
return self.__repr__()
def __eq__(self, other: object) -> bool:
return isinstance(other, self.__class__) and str(self) == str(other)
def __ne__(self, other: object) -> bool:
return not self.__eq__(other)
def __hash__(self) -> int:
return hash(str(self))
def _convert_to_rs_instruction(instr: Union[AbstractInstruction, quil_rs.Instruction]) -> quil_rs.Instruction:
if isinstance(instr, quil_rs.Instruction):
return instr
if isinstance(instr, quil_rs.Arithmetic):
return quil_rs.Instruction.from_arithmetic(instr)
if isinstance(instr, quil_rs.BinaryLogic):
return quil_rs.Instruction.from_binary_logic(instr)
if isinstance(instr, quil_rs.Capture):
return quil_rs.Instruction.from_capture(instr)
if isinstance(instr, quil_rs.CircuitDefinition):
return quil_rs.Instruction.from_circuit_definition(instr)
if isinstance(instr, quil_rs.Calibration):
return quil_rs.Instruction.from_calibration_definition(instr)
if isinstance(instr, quil_rs.Convert):
return quil_rs.Instruction.from_convert(instr)
if isinstance(instr, quil_rs.Declaration):
return quil_rs.Instruction.from_declaration(instr)
if isinstance(instr, quil_rs.Delay):
return quil_rs.Instruction.from_delay(instr)
if isinstance(instr, quil_rs.Exchange):
return quil_rs.Instruction.from_exchange(instr)
if isinstance(instr, quil_rs.Fence):
return quil_rs.Instruction.from_fence(instr)
if isinstance(instr, quil_rs.FrameDefinition):
return quil_rs.Instruction.from_frame_definition(instr)
if isinstance(instr, quil_rs.Gate):
return quil_rs.Instruction.from_gate(instr)
if isinstance(instr, quil_rs.GateDefinition):
return quil_rs.Instruction.from_gate_definition(instr)
if isinstance(instr, Halt):
return quil_rs.Instruction.new_halt()
if isinstance(instr, Include):
return quil_rs.Instruction.from_include(instr)
if isinstance(instr, quil_rs.Load):
return quil_rs.Instruction.from_load(instr)
if isinstance(instr, quil_rs.MeasureCalibrationDefinition):
return quil_rs.Instruction.from_measure_calibration_definition(instr)
if isinstance(instr, quil_rs.Measurement):
return quil_rs.Instruction.from_measurement(instr)
if isinstance(instr, Nop):
return quil_rs.Instruction.new_nop()
if isinstance(instr, quil_rs.Pragma):
return quil_rs.Instruction.from_pragma(instr)
if isinstance(instr, quil_rs.Pulse):
return quil_rs.Instruction.from_pulse(instr)
if isinstance(instr, quil_rs.RawCapture):
return quil_rs.Instruction.from_raw_capture(instr)
if isinstance(instr, quil_rs.Reset):
return quil_rs.Instruction.from_reset(instr)
if isinstance(instr, quil_rs.SetFrequency):
return quil_rs.Instruction.from_set_frequency(instr)
if isinstance(instr, quil_rs.SetPhase):
return quil_rs.Instruction.from_set_phase(instr)
if isinstance(instr, quil_rs.SetScale):
return quil_rs.Instruction.from_set_scale(instr)
if isinstance(instr, quil_rs.ShiftFrequency):
return quil_rs.Instruction.from_shift_frequency(instr)
if isinstance(instr, quil_rs.ShiftPhase):
return quil_rs.Instruction.from_shift_phase(instr)
if isinstance(instr, quil_rs.SwapPhases):
return quil_rs.Instruction.from_swap_phases(instr)
if isinstance(instr, quil_rs.Store):
return quil_rs.Instruction.from_store(instr)
if isinstance(instr, Wait):
return quil_rs.Instruction.new_wait()
if isinstance(instr, quil_rs.WaveformDefinition):
return quil_rs.Instruction.from_waveform_definition(instr)
if isinstance(instr, quil_rs.Label):
return quil_rs.Instruction.from_label(instr)
if isinstance(instr, quil_rs.Move):
return quil_rs.Instruction.from_move(instr)
if isinstance(instr, quil_rs.Jump):
return quil_rs.Instruction.from_jump(instr)
if isinstance(instr, quil_rs.JumpWhen):
return quil_rs.Instruction.from_jump_when(instr)
if isinstance(instr, quil_rs.JumpUnless):
return quil_rs.Instruction.from_jump_unless(instr)
if isinstance(instr, quil_rs.UnaryLogic):
return quil_rs.Instruction.from_unary_logic(instr)
if isinstance(instr, quil_rs.Comparison):
return quil_rs.Instruction.from_comparison(instr)
raise ValueError(f"{type(instr)} is not an Instruction")
def _convert_to_rs_instructions(instrs: Iterable[AbstractInstruction]) -> List[quil_rs.Instruction]:
return [_convert_to_rs_instruction(instr) for instr in instrs]
def _convert_to_py_instruction(instr: Any) -> AbstractInstruction:
if isinstance(instr, quil_rs.Instruction):
if instr.is_nop():
return Nop()
if instr.is_halt():
return Halt()
if instr.is_wait():
return Wait()
return _convert_to_py_instruction(instr.inner())
if isinstance(instr, quil_rs.Arithmetic):
return ArithmeticBinaryOp._from_rs_arithmetic(instr)
if isinstance(instr, quil_rs.BinaryLogic):
return LogicalBinaryOp._from_rs_binary_logic(instr)
if isinstance(instr, quil_rs.Calibration):
return DefCalibration._from_rs_calibration(instr)
if isinstance(instr, quil_rs.Capture):
return Capture._from_rs_capture(instr)
if isinstance(instr, quil_rs.CircuitDefinition):
return DefCircuit._from_rs_circuit_definition(instr)
if isinstance(instr, quil_rs.Convert):
return ClassicalConvert._from_rs_convert(instr)
if isinstance(instr, quil_rs.Comparison):
return ClassicalComparison._from_rs_comparison(instr)
if isinstance(instr, quil_rs.Declaration):
return Declare._from_rs_declaration(instr)
if isinstance(instr, quil_rs.Delay):
if len(instr.frame_names) > 0:
return DelayFrames._from_rs_delay(instr)
if len(instr.qubits) > 0:
return DelayQubits._from_rs_delay(instr)
return Delay._from_rs_delay(instr)
if isinstance(instr, quil_rs.Exchange):
return ClassicalExchange._from_rs_exchange(instr)
if isinstance(instr, quil_rs.Fence):
if len(instr.qubits) == 0:
return FenceAll()
return Fence._from_rs_fence(instr)
if isinstance(instr, quil_rs.FrameDefinition):
return DefFrame._from_rs_frame_definition(instr)
if isinstance(instr, quil_rs.GateDefinition):
return DefGate._from_rs_gate_definition(instr)
if isinstance(instr, quil_rs.Gate):
return Gate._from_rs_gate(instr)
if isinstance(instr, quil_rs.Include):
return Include._from_rs_include(instr)
if isinstance(instr, quil_rs.Jump):
return Jump._from_rs_jump(instr)
if isinstance(instr, quil_rs.JumpWhen):
return JumpWhen._from_rs_jump_when(instr)
if isinstance(instr, quil_rs.JumpUnless):
return JumpUnless._from_rs_jump_unless(instr)
if isinstance(instr, quil_rs.Label):
return JumpTarget._from_rs_label(instr)
if isinstance(instr, quil_rs.Load):
return ClassicalLoad._from_rs_load(instr)
if isinstance(instr, quil_rs.MeasureCalibrationDefinition):
return DefMeasureCalibration._from_rs_measure_calibration_definition(instr)
if isinstance(instr, quil_rs.Measurement):
return Measurement._from_rs_measurement(instr)
if isinstance(instr, quil_rs.Move):
return ClassicalMove._from_rs_move(instr)
if isinstance(instr, quil_rs.Pragma):
return Pragma._from_rs_pragma(instr)
if isinstance(instr, quil_rs.Pulse):
return Pulse._from_rs_pulse(instr)
if isinstance(instr, quil_rs.RawCapture):
return RawCapture._from_rs_raw_capture(instr)
if isinstance(instr, quil_rs.Reset):
if instr.qubit is None:
return Reset._from_rs_reset(instr)
else:
return ResetQubit._from_rs_reset(instr)
if isinstance(instr, quil_rs.SetFrequency):
return SetFrequency._from_rs_set_frequency(instr)
if isinstance(instr, quil_rs.SetPhase):
return SetPhase._from_rs_set_phase(instr)
if isinstance(instr, quil_rs.SetScale):
return SetScale._from_rs_set_scale(instr)
if isinstance(instr, quil_rs.ShiftFrequency):
return ShiftFrequency._from_rs_shift_frequency(instr)
if isinstance(instr, quil_rs.ShiftPhase):
return ShiftPhase._from_rs_shift_phase(instr)
if isinstance(instr, quil_rs.SwapPhases):
return SwapPhases._from_rs_swap_phases(instr)
if isinstance(instr, quil_rs.Store):
return ClassicalStore._from_rs_store(instr)
if isinstance(instr, quil_rs.UnaryLogic):
return UnaryClassicalInstruction._from_rs_unary_logic(instr)
if isinstance(instr, quil_rs.WaveformDefinition):
return DefWaveform._from_rs_waveform_definition(instr)
if isinstance(instr, quil_rs.Instruction):
raise NotImplementedError(f"The {type(instr)} Instruction hasn't been mapped to an AbstractInstruction yet.")
elif isinstance(instr, AbstractInstruction):
return instr
raise ValueError(f"{type(instr)} is not a valid Instruction type")
def _convert_to_py_instructions(instrs: Iterable[quil_rs.Instruction]) -> List[AbstractInstruction]:
return [_convert_to_py_instruction(instr) for instr in instrs]
RESERVED_WORDS: Container[str] = [
"DEFGATE",
"DEFCIRCUIT",
"MEASURE",
"LABEL",
"HALT",
"JUMP",
"JUMP-WHEN",
"JUMP-UNLESS",
"RESET",
"WAIT",
"NOP",
"INCLUDE",
"PRAGMA",
"DECLARE",
"NEG",
"NOT",
"AND",
"IOR",
"XOR",
"TRUE",
"FALSE",
"OR",
]
[docs]class Gate(quil_rs.Gate, AbstractInstruction):
"""
This is the pyQuil object for a quantum gate instruction.
"""
def __new__(
cls,
name: str,
params: Sequence[ParameterDesignator],
qubits: Sequence[Union[Qubit, QubitPlaceholder, FormalArgument, int]],
modifiers: Sequence[quil_rs.GateModifier] = [],
) -> Self:
return super().__new__(
cls, name, _convert_to_rs_expressions(params), _convert_to_rs_qubits(qubits), list(modifiers)
)
@classmethod
def _from_rs_gate(cls, gate: quil_rs.Gate) -> Self:
return super().__new__(cls, gate.name, gate.parameters, gate.qubits, gate.modifiers)
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Sequence[QubitDesignator]:
if indices:
return self.get_qubit_indices()
else:
return _convert_to_py_qubits(super().qubits)
@property # type: ignore[override]
def qubits(self) -> List[QubitDesignator]:
return self.get_qubits(indices=False) # type: ignore
@qubits.setter
def qubits(self, qubits: Sequence[Union[Qubit, QubitPlaceholder, FormalArgument]]) -> None:
quil_rs.Gate.qubits.__set__(self, _convert_to_rs_qubits(qubits)) # type: ignore
@property
def params(self) -> Sequence[ParameterDesignator]:
return _convert_to_py_expressions(super().parameters)
@params.setter
def params(self, params: Sequence[ParameterDesignator]) -> None:
quil_rs.Gate.parameters.__set__(self, _convert_to_rs_expressions(params)) # type: ignore
@property # type: ignore[override]
def modifiers(self) -> List[str]:
return [str(modifier).upper() for modifier in super().modifiers]
@modifiers.setter
def modifiers(self, modifiers: Union[List[str], List[quil_rs.GateModifier]]) -> None:
modifiers = [
self._to_rs_gate_modifier(modifier) if isinstance(modifier, str) else modifier for modifier in modifiers
]
quil_rs.Gate.modifiers.__set__(self, modifiers) # type: ignore[attr-defined]
def _to_rs_gate_modifier(self, modifier: str) -> quil_rs.GateModifier:
modifier = modifier.upper()
if modifier == "CONTROLLED":
return quil_rs.GateModifier.Controlled
if modifier == "DAGGER":
return quil_rs.GateModifier.Dagger
if modifier == "FORKED":
return quil_rs.GateModifier.Forked
raise ValueError(f"{modifier} is not a valid Gate modifier.")
[docs] def get_qubit_indices(self) -> List[int]:
return [qubit.to_fixed() for qubit in super().qubits]
[docs] def controlled(
self,
control_qubit: Union[
quil_rs.Qubit,
QubitDesignator,
Sequence[Union[QubitDesignator, quil_rs.Qubit]],
],
) -> "Gate":
"""
Add the CONTROLLED modifier to the gate with the given control qubit or Sequence of control
qubits.
"""
if isinstance(control_qubit, Sequence):
for qubit in control_qubit:
self._update_super(super().controlled(_convert_to_rs_qubit(qubit)))
else:
self._update_super(super().controlled(_convert_to_rs_qubit(control_qubit)))
return self
[docs] def forked(
self,
fork_qubit: Union[quil_rs.Qubit, QubitDesignator],
alt_params: Union[Sequence[ParameterDesignator], Sequence[quil_rs_expr.Expression]],
) -> "Gate":
"""
Add the FORKED modifier to the gate with the given fork qubit and given additional
parameters.
"""
forked = super().forked(_convert_to_rs_qubit(fork_qubit), _convert_to_rs_expressions(alt_params))
self._update_super(forked)
return self
[docs] def dagger(self) -> "Gate":
"""
Add the DAGGER modifier to the gate.
"""
self._update_super(super().dagger())
return self
[docs] def out(self) -> str:
return super().to_quil()
def _update_super(self, gate: quil_rs.Gate) -> None:
"""
Updates the state of the super class using a new gate.
The super class does not mutate the value of a gate when adding
modifiers with methods like `dagger()`, but pyQuil does.
"""
quil_rs.Gate.name.__set__(self, gate.name) # type: ignore[attr-defined]
quil_rs.Gate.parameters.__set__(self, gate.parameters) # type: ignore[attr-defined]
quil_rs.Gate.modifiers.__set__(self, gate.modifiers) # type: ignore[attr-defined]
quil_rs.Gate.qubits.__set__(self, gate.qubits) # type: ignore[attr-defined]
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Gate":
return Gate._from_rs_gate(super().__deepcopy__(memo))
def _strip_modifiers(gate: Gate, limit: Optional[int] = None) -> Gate:
"""
Remove modifiers from :py:class:`Gate`.
This function removes up to ``limit`` gate modifiers from the given gate,
starting from the leftmost gate modifier.
:param gate: A gate.
:param limit: An upper bound on how many modifiers to remove.
"""
if limit is None:
limit = len(gate.modifiers)
# We walk the modifiers from left-to-right, tracking indices to identify
# qubits/params introduced by gate modifiers.
#
# Invariants:
# - gate.qubits[0:qubit_index] are qubits introduced by gate modifiers
# - gate.params[param_index:] are parameters introduced by gate modifiers
qubit_index = 0
param_index = len(gate.params)
for m in gate.modifiers[:limit]:
if m == "CONTROLLED":
qubit_index += 1
elif m == "FORKED":
if param_index % 2 != 0:
raise ValueError("FORKED gate has an invalid number of parameters.")
param_index //= 2
qubit_index += 1
elif m == "DAGGER":
pass
else:
raise TypeError("Unsupported gate modifier {}".format(m))
stripped = Gate(gate.name, gate.params[:param_index], gate.qubits[qubit_index:])
stripped.modifiers = gate.modifiers[limit:]
return stripped
[docs]class Measurement(quil_rs.Measurement, AbstractInstruction):
"""
This is the pyQuil object for a Quil measurement instruction.
"""
def __new__(
cls,
qubit: QubitDesignator,
classical_reg: Optional[MemoryReference],
) -> Self:
target = cls._reg_to_target(classical_reg)
return super().__new__(cls, _convert_to_rs_qubit(qubit), target)
@classmethod
def _reg_to_target(cls, classical_reg: Optional[MemoryReference]) -> Optional[quil_rs.MemoryReference]:
if isinstance(classical_reg, quil_rs.MemoryReference):
return classical_reg
if classical_reg is not None:
return quil_rs.MemoryReference.parse(str(classical_reg))
return None
@classmethod
def _from_rs_measurement(cls, measurement: quil_rs.Measurement) -> "Measurement":
return super().__new__(cls, measurement.qubit, measurement.target)
@property # type: ignore[override]
def qubit(self) -> QubitDesignator:
return _convert_to_py_qubit(super().qubit)
@qubit.setter
def qubit(self, qubit: QubitDesignator) -> None:
quil_rs.Measurement.qubit.__set__(self, _convert_to_rs_qubit(qubit)) # type: ignore[attr-defined]
@property
def classical_reg(self) -> Optional[MemoryReference]:
target = super().target
if target is None:
return None
return MemoryReference._from_rs_memory_reference(target)
@classical_reg.setter
def classical_reg(self, classical_reg: Optional[MemoryReference]) -> None:
target = self._reg_to_target(classical_reg)
quil_rs.Measurement.target.__set__(self, target) # type: ignore[attr-defined]
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
else:
return {_convert_to_py_qubit(super().qubit)}
[docs] def get_qubit_indices(self) -> Set[int]:
return {super().qubit.to_fixed()}
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Measurement":
return Measurement._from_rs_measurement(super().__deepcopy__(memo))
[docs]class Reset(quil_rs.Reset, AbstractInstruction):
"""
The RESET instruction.
"""
def __new__(cls, qubit: Optional[Union[Qubit, QubitPlaceholder, FormalArgument, int]] = None) -> Self:
rs_qubit: Optional[quil_rs.Qubit] = None
if qubit is not None:
rs_qubit = _convert_to_rs_qubit(qubit)
return super().__new__(cls, rs_qubit)
@classmethod
def _from_rs_reset(cls, reset: quil_rs.Reset) -> "Reset":
return super().__new__(cls, reset.qubit)
[docs] def out(self) -> str:
return super().to_quil()
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Optional[Set[QubitDesignator]]:
if super().qubit is None:
return None
if indices:
return self.get_qubit_indices() # type: ignore
return {_convert_to_py_qubit(super().qubit)} # type: ignore
[docs] def get_qubit_indices(self) -> Optional[Set[int]]:
if super().qubit is None:
return None
return {super().qubit.to_fixed()} # type: ignore
@property # type: ignore[override]
def qubit(self) -> Optional[QubitDesignator]:
if super().qubit:
return _convert_to_py_qubit(super().qubit) # type: ignore
return None
@qubit.setter
def qubit(self, qubit: Optional[QubitDesignator]) -> None:
rs_qubit: Optional[quil_rs.Qubit] = None
if qubit is not None:
rs_qubit = _convert_to_rs_qubit(qubit)
quil_rs.Reset.qubit.__set__(self, rs_qubit) # type: ignore[attr-defined]
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Reset":
copy = Reset._from_rs_reset(super().__deepcopy__(memo))
copy.__class__ = self.__class__
return copy
[docs]class ResetQubit(Reset):
"""
This is the pyQuil object for a Quil targeted reset instruction.
"""
def __new__(cls, qubit: Union[Qubit, QubitPlaceholder, FormalArgument, int]) -> Self:
if qubit is None:
raise TypeError("qubit should not be None")
return super().__new__(cls, qubit)
@classmethod
def _from_rs_reset(cls, reset: quil_rs.Reset) -> "ResetQubit":
if reset.qubit is not None:
qubit = _convert_to_py_qubit(reset.qubit)
return ResetQubit.__new__(cls, qubit)
raise ValueError("reset.qubit should not be None")
[docs]class DefGate(quil_rs.GateDefinition, AbstractInstruction):
"""
A DEFGATE directive.
:param name: The name of the newly defined gate.
:param matrix: The matrix defining this gate.
:param parameters: list of parameters that are used in this gate
"""
def __new__(
cls,
name: str,
matrix: Union[List[List[Expression]], np.ndarray, np.matrix],
parameters: Optional[List[Parameter]] = None,
) -> Self:
DefGate._validate_matrix(matrix, parameters is not None and len(parameters) > 0)
specification = DefGate._convert_to_matrix_specification(matrix)
rs_parameters = [param.name for param in parameters or []]
return super().__new__(cls, name, rs_parameters, specification)
@classmethod
def _from_rs_gate_definition(cls, gate_definition: quil_rs.GateDefinition) -> Self:
return super().__new__(cls, gate_definition.name, gate_definition.parameters, gate_definition.specification)
@staticmethod
def _convert_to_matrix_specification(
matrix: Union[List[List[Expression]], np.ndarray, np.matrix]
) -> quil_rs.GateSpecification:
to_rs_matrix = np.vectorize(_convert_to_rs_expression, otypes=["O"])
return quil_rs.GateSpecification.from_matrix(to_rs_matrix(np.asarray(matrix)))
@staticmethod
def _validate_matrix(
matrix: Union[List[List[Expression]], np.ndarray, np.matrix], contains_parameters: bool
) -> None:
if isinstance(matrix, list):
rows = len(matrix)
if not all([len(row) == rows for row in matrix]):
raise ValueError("Matrix must be square.")
elif isinstance(matrix, (np.ndarray, np.matrix)):
rows, cols = matrix.shape
if rows != cols:
raise ValueError("Matrix must be square.")
else:
raise TypeError("Matrix argument must be a list or NumPy array/matrix")
if 0 != rows & (rows - 1):
raise ValueError("Dimension of matrix must be a power of 2, got {0}".format(rows))
if not contains_parameters:
np_matrix = np.asarray(matrix)
is_unitary = np.allclose(np.eye(rows), np_matrix.dot(np_matrix.T.conj()))
if not is_unitary:
raise ValueError("Matrix must be unitary.")
[docs] def out(self) -> str:
return super().to_quil()
[docs] def get_constructor(self) -> Union[Callable[..., Gate], Callable[..., Callable[..., Gate]]]:
"""
:returns: A function that constructs this gate on variable qubit indices. E.g.
`mygate.get_constructor()(1) applies the gate to qubit 1.`
"""
if self.parameters:
return lambda *params: lambda *qubits: Gate(
name=self.name, params=list(params), qubits=list(map(unpack_qubit, qubits))
)
else:
return lambda *qubits: Gate(name=self.name, params=[], qubits=list(map(unpack_qubit, qubits)))
[docs] def num_args(self) -> int:
"""
:return: The number of qubit arguments the gate takes.
"""
rows = len(self.matrix)
return int(np.log2(rows))
@property
def matrix(self) -> np.ndarray:
to_py_matrix = np.vectorize(_convert_to_py_expression, otypes=["O"])
return to_py_matrix(np.asarray(super().specification.to_matrix())) # type: ignore[no-any-return]
@matrix.setter
def matrix(self, matrix: np.ndarray) -> None:
quil_rs.GateDefinition.specification.__set__(self, DefGate._convert_to_matrix_specification(matrix)) # type: ignore[attr-defined] # noqa
@property # type: ignore[override]
def parameters(self) -> List[Parameter]:
return [Parameter(name) for name in super().parameters]
@parameters.setter
def parameters(self, parameters: Optional[List[Parameter]]) -> None:
quil_rs.GateDefinition.parameters.__set__(self, [param.name for param in parameters or []]) # type: ignore[attr-defined] # noqa
def __hash__(self) -> int:
return hash(self.out())
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "DefGate":
return DefGate._from_rs_gate_definition(super().__deepcopy__(memo))
[docs]class DefPermutationGate(DefGate):
def __new__(cls, name: str, permutation: Union[List[int], np.ndarray]) -> Self:
specification = DefPermutationGate._convert_to_permutation_specification(permutation)
gate_definition = quil_rs.GateDefinition(name, [], specification)
return super()._from_rs_gate_definition(gate_definition)
@staticmethod
def _convert_to_permutation_specification(permutation: Union[List[int], np.ndarray]) -> quil_rs.GateSpecification:
return quil_rs.GateSpecification.from_permutation([int(x) for x in permutation])
@property
def permutation(self) -> List[int]:
return super().specification.to_permutation()
@permutation.setter
def permutation(self, permutation: List[int]) -> None:
specification = DefPermutationGate._convert_to_permutation_specification(permutation)
quil_rs.GateDefinition.specification.__set__(self, specification) # type: ignore[attr-defined]
[docs] def num_args(self) -> int:
"""
:return: The number of qubit arguments the gate takes.
"""
return int(np.log2(len(self.permutation)))
def __str__(self) -> str:
return super().to_quil_or_debug()
[docs]class DefGateByPaulis(DefGate):
"""
Records a gate definition as the exponentiation of a PauliSum.
"""
def __new__(
cls,
gate_name: str,
parameters: List[Parameter],
arguments: List[QubitDesignator],
body: "PauliSum",
) -> Self:
specification = DefGateByPaulis._convert_to_pauli_specification(body, arguments)
rs_parameters = [param.name for param in parameters]
gate_definition = quil_rs.GateDefinition(gate_name, rs_parameters, specification)
return super()._from_rs_gate_definition(gate_definition)
@staticmethod
def _convert_to_pauli_specification(
body: "PauliSum", arguments: List[QubitDesignator]
) -> quil_rs.GateSpecification:
if isinstance(body, Sequence):
from pyquil.paulis import PauliSum
body = PauliSum(body)
return quil_rs.GateSpecification.from_pauli_sum(body._to_rs_pauli_sum(arguments))
@property
def arguments(self) -> List[FormalArgument]:
return [FormalArgument(arg) for arg in super().specification.to_pauli_sum().arguments]
@arguments.setter
def arguments(self, arguments: List[QubitDesignator]) -> None:
pauli_sum = super().specification.to_pauli_sum()
pauli_sum.arguments = [str(arg) for arg in arguments]
quil_rs.GateDefinition.specification.__set__(self, quil_rs.GateSpecification.from_pauli_sum(pauli_sum)) # type: ignore[attr-defined] # noqa
@property
def body(self) -> "PauliSum":
from pyquil.paulis import PauliSum # avoids circular import
return PauliSum._from_rs_pauli_sum(super().specification.to_pauli_sum())
@body.setter
def body(self, body: "PauliSum") -> None:
specification = quil_rs.GateSpecification.from_pauli_sum(body._to_rs_pauli_sum())
quil_rs.GateDefinition.specification.__set__(self, specification) # type: ignore[attr-defined]
[docs] def num_args(self) -> int:
return len(self.arguments)
def __str__(self) -> str:
return super().to_quil_or_debug()
[docs]class JumpTarget(quil_rs.Label, AbstractInstruction):
"""
Representation of a target that can be jumped to.
"""
def __new__(cls, label: Union[Label, LabelPlaceholder]) -> Self:
return super().__new__(cls, label.target)
@classmethod
def _from_rs_label(cls, label: quil_rs.Label) -> "JumpTarget":
return super().__new__(cls, label.target)
@property
def label(self) -> Union[Label, LabelPlaceholder]:
if super().target.is_placeholder():
return LabelPlaceholder._from_rs_target(super().target)
return Label._from_rs_target(super().target)
def __repr__(self) -> str:
return "<JumpTarget {0}>".format(str(self.label))
[docs] def out(self) -> str:
return super().to_quil()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "JumpTarget":
return JumpTarget._from_rs_label(super().__deepcopy__(memo))
[docs]class JumpWhen(quil_rs.JumpWhen, AbstractInstruction):
"""
The JUMP-WHEN instruction.
"""
def __new__(cls, target: Union[Label, LabelPlaceholder], condition: MemoryReference) -> Self:
return super().__new__(cls, target.target, condition._to_rs_memory_reference())
@classmethod
def _from_rs_jump_when(cls, jump_when: quil_rs.JumpWhen) -> Self:
return super().__new__(cls, jump_when.target, jump_when.condition)
[docs] def out(self) -> str:
return super().to_quil()
@property # type: ignore[override]
def condition(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().condition)
@condition.setter
def condition(self, condition: MemoryReference) -> None:
quil_rs.JumpWhen.condition.__set__(self, condition._to_rs_memory_reference()) # type: ignore[attr-defined]
@property # type: ignore[override]
def target(self) -> Union[Label, LabelPlaceholder]:
if super().target.is_placeholder():
return LabelPlaceholder._from_rs_target(super().target)
return Label._from_rs_target(super().target)
@target.setter
def target(self, target: Union[Label, LabelPlaceholder]) -> None:
quil_rs.JumpWhen.target.__set__(self, target) # type: ignore[attr-defined]
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "JumpWhen":
return JumpWhen._from_rs_jump_when(super().__deepcopy__(memo))
[docs]class JumpUnless(quil_rs.JumpUnless, AbstractInstruction):
"""
The JUMP-UNLESS instruction.
"""
def __new__(cls, target: Union[Label, LabelPlaceholder], condition: MemoryReference) -> Self:
return super().__new__(cls, target.target, condition._to_rs_memory_reference())
@classmethod
def _from_rs_jump_unless(cls, jump_unless: quil_rs.JumpUnless) -> Self:
return super().__new__(cls, jump_unless.target, jump_unless.condition)
[docs] def out(self) -> str:
return super().to_quil()
@property # type: ignore[override]
def condition(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().condition)
@condition.setter
def condition(self, condition: MemoryReference) -> None:
quil_rs.JumpUnless.condition.__set__(self, condition._to_rs_memory_reference()) # type: ignore[attr-defined]
@property # type: ignore[override]
def target(self) -> Union[Label, LabelPlaceholder]:
if super().target.is_placeholder():
return LabelPlaceholder._from_rs_target(super().target)
return Label._from_rs_target(super().target)
@target.setter
def target(self, target: Union[Label, LabelPlaceholder]) -> None:
quil_rs.JumpUnless.target.__set__(self, target) # type: ignore[attr-defined]
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "JumpUnless":
return JumpUnless._from_rs_jump_unless(super().__deepcopy__(memo))
[docs]class SimpleInstruction(AbstractInstruction):
"""
Abstract class for simple instructions with no arguments.
"""
instruction: ClassVar[quil_rs.Instruction]
[docs] def out(self) -> str:
return self.instruction.to_quil()
def __str__(self) -> str:
return self.out()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "SimpleInstruction":
return self
[docs]class Halt(SimpleInstruction):
"""
The HALT instruction.
"""
instruction = quil_rs.Instruction.new_halt()
[docs]class Wait(SimpleInstruction):
"""
The WAIT instruction.
"""
instruction = quil_rs.Instruction.new_wait()
[docs]class Nop(SimpleInstruction):
"""
The NOP instruction.
"""
instruction = quil_rs.Instruction.new_nop()
[docs]class UnaryClassicalInstruction(quil_rs.UnaryLogic, AbstractInstruction):
"""
The abstract class for unary classical instructions.
"""
op: ClassVar[quil_rs.UnaryOperator]
def __new__(cls, target: MemoryReference) -> "UnaryClassicalInstruction":
return super().__new__(cls, cls.op, target._to_rs_memory_reference())
@classmethod
def _from_rs_unary_logic(cls, unary_logic: quil_rs.UnaryLogic) -> Self:
return super().__new__(cls, unary_logic.operator, unary_logic.operand)
@property
def target(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().operand)
@target.setter
def target(self, target: MemoryReference) -> None:
quil_rs.UnaryLogic.operand.__set__(self, target._to_rs_memory_reference()) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "UnaryClassicalInstruction":
copy = UnaryClassicalInstruction._from_rs_unary_logic(super().__deepcopy__(memo))
copy.__class__ = self.__class__
return copy
[docs]class ClassicalNeg(UnaryClassicalInstruction):
"""
The NEG instruction.
"""
op = quil_rs.UnaryOperator.Neg
[docs]class ClassicalNot(UnaryClassicalInstruction):
"""
The NOT instruction.
"""
op = quil_rs.UnaryOperator.Not
[docs]class LogicalBinaryOp(quil_rs.BinaryLogic, AbstractInstruction):
"""
The abstract class for binary logical classical instructions.
"""
op: ClassVar[quil_rs.BinaryOperator]
def __new__(cls, left: MemoryReference, right: Union[MemoryReference, int]) -> Self:
operands = cls._to_rs_binary_operands(left, right)
return super().__new__(cls, cls.op, operands)
@classmethod
def _from_rs_binary_logic(cls, binary_logic: quil_rs.BinaryLogic) -> "LogicalBinaryOp":
return super().__new__(cls, binary_logic.operator, binary_logic.operands)
@staticmethod
def _to_rs_binary_operand(operand: Union[MemoryReference, int]) -> quil_rs.BinaryOperand:
if isinstance(operand, MemoryReference):
return quil_rs.BinaryOperand.from_memory_reference(operand._to_rs_memory_reference())
return quil_rs.BinaryOperand.from_literal_integer(operand)
@staticmethod
def _to_rs_binary_operands(left: MemoryReference, right: Union[MemoryReference, int]) -> quil_rs.BinaryOperands:
left_operand = left._to_rs_memory_reference()
right_operand = LogicalBinaryOp._to_rs_binary_operand(right)
return quil_rs.BinaryOperands(left_operand, right_operand)
@staticmethod
def _to_py_binary_operand(operand: quil_rs.BinaryOperand) -> Union[MemoryReference, int]:
if operand.is_literal_integer():
return operand.to_literal_integer()
return MemoryReference._from_rs_memory_reference(operand.to_memory_reference())
@property
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().operands.memory_reference)
@left.setter
def left(self, left: MemoryReference) -> None:
operands = super().operands
operands.memory_reference = left._to_rs_memory_reference()
quil_rs.BinaryLogic.operands.__set__(self, operands) # type: ignore[attr-defined]
@property
def right(self) -> Union[MemoryReference, int]:
return self._to_py_binary_operand(super().operands.operand)
@right.setter
def right(self, right: Union[MemoryReference, int]) -> None:
operands = super().operands
operands.operand = self._to_rs_binary_operand(right)
quil_rs.BinaryLogic.operands.__set__(self, operands) # type: ignore[attr-defined]
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "LogicalBinaryOp":
copy = LogicalBinaryOp._from_rs_binary_logic(super().__deepcopy__(memo))
copy.__class__ = self.__class__
return copy
[docs]class ClassicalAnd(LogicalBinaryOp):
"""
The AND instruction.
"""
op = quil_rs.BinaryOperator.And
[docs]class ClassicalInclusiveOr(LogicalBinaryOp):
"""
The IOR instruction.
"""
op = quil_rs.BinaryOperator.Ior
[docs]class ClassicalExclusiveOr(LogicalBinaryOp):
"""
The XOR instruction.
"""
op = quil_rs.BinaryOperator.Xor
[docs]class ArithmeticBinaryOp(quil_rs.Arithmetic, AbstractInstruction):
"""
The abstract class for binary arithmetic classical instructions.
"""
op: ClassVar[quil_rs.ArithmeticOperator]
def __new__(cls, left: MemoryReference, right: Union[MemoryReference, int, float]) -> Self:
left_operand = quil_rs.ArithmeticOperand.from_memory_reference(left._to_rs_memory_reference())
right_operand = _to_rs_arithmetic_operand(right)
return super().__new__(cls, cls.op, left_operand, right_operand)
@classmethod
def _from_rs_arithmetic(cls, arithmetic: quil_rs.Arithmetic) -> "ArithmeticBinaryOp":
return super().__new__(cls, arithmetic.operator, arithmetic.destination, arithmetic.source)
@property
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().destination.to_memory_reference())
@left.setter
def left(self, left: MemoryReference) -> None:
quil_rs.Arithmetic.destination.__set__( # type: ignore[attr-defined]
self, quil_rs.ArithmeticOperand.from_memory_reference(left._to_rs_memory_reference())
)
@property
def right(self) -> Union[MemoryReference, int, float]:
return _to_py_arithmetic_operand(super().source)
@right.setter
def right(self, right: Union[MemoryReference, int, float]) -> None:
quil_rs.Arithmetic.source.__set__(self, _to_rs_arithmetic_operand(right)) # type: ignore[attr-defined]
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ArithmeticBinaryOp":
copy = ArithmeticBinaryOp._from_rs_arithmetic(super().__deepcopy__(memo))
copy.__class__ = self.__class__
return copy
[docs]class ClassicalAdd(ArithmeticBinaryOp):
"""
The ADD instruction.
"""
op = quil_rs.ArithmeticOperator.Add
[docs]class ClassicalSub(ArithmeticBinaryOp):
"""
The SUB instruction.
"""
op = quil_rs.ArithmeticOperator.Subtract
[docs]class ClassicalMul(ArithmeticBinaryOp):
"""
The MUL instruction.
"""
op = quil_rs.ArithmeticOperator.Multiply
[docs]class ClassicalDiv(ArithmeticBinaryOp):
"""
The DIV instruction.
"""
op = quil_rs.ArithmeticOperator.Divide
[docs]class ClassicalMove(quil_rs.Move, AbstractInstruction):
"""
The MOVE instruction.
"""
def __new__(cls, left: MemoryReference, right: Union[MemoryReference, int, float]) -> "ClassicalMove":
return super().__new__(cls, left._to_rs_memory_reference(), _to_rs_arithmetic_operand(right))
@classmethod
def _from_rs_move(cls, move: quil_rs.Move) -> Self:
return super().__new__(cls, move.destination, move.source)
@property
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().destination)
@left.setter
def left(self, left: MemoryReference) -> None:
quil_rs.Move.destination.__set__(self, left._to_rs_memory_reference()) # type: ignore
@property
def right(self) -> Union[MemoryReference, int, float]:
return _to_py_arithmetic_operand(super().source)
@right.setter
def right(self, right: Union[MemoryReference, int, float]) -> None:
quil_rs.Move.source.__set__(self, _to_rs_arithmetic_operand(right)) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ClassicalMove":
return ClassicalMove._from_rs_move(super().__deepcopy__(memo))
[docs]class ClassicalExchange(quil_rs.Exchange, AbstractInstruction):
"""
The EXCHANGE instruction.
"""
def __new__(
cls,
left: MemoryReference,
right: MemoryReference,
) -> "ClassicalExchange":
return super().__new__(cls, left._to_rs_memory_reference(), right._to_rs_memory_reference())
@classmethod
def _from_rs_exchange(cls, exchange: quil_rs.Exchange) -> Self:
return super().__new__(cls, exchange.left, exchange.right)
@property # type: ignore[override]
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().left)
@left.setter
def left(self, left: MemoryReference) -> None:
quil_rs.Exchange.left.__set__(self, left._to_rs_memory_reference()) # type: ignore
@property # type: ignore[override]
def right(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().right)
@right.setter
def right(self, right: MemoryReference) -> None:
quil_rs.Exchange.right.__set__(self, right._to_rs_memory_reference()) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ClassicalExchange":
return ClassicalExchange._from_rs_exchange(super().__deepcopy__(memo))
[docs]class ClassicalConvert(quil_rs.Convert, AbstractInstruction):
"""
The CONVERT instruction.
"""
def __new__(cls, left: MemoryReference, right: MemoryReference) -> "ClassicalConvert":
return super().__new__(cls, left._to_rs_memory_reference(), right._to_rs_memory_reference())
@classmethod
def _from_rs_convert(cls, convert: quil_rs.Convert) -> Self:
return super().__new__(cls, convert.destination, convert.source)
@property
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().destination)
@left.setter
def left(self, memory_reference: MemoryReference) -> None:
quil_rs.Convert.destination.__set__(self, memory_reference._to_rs_memory_reference()) # type: ignore
@property
def right(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().source)
@right.setter
def right(self, memory_reference: MemoryReference) -> None:
quil_rs.Convert.source.__set__(self, memory_reference._to_rs_memory_reference()) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ClassicalConvert":
return ClassicalConvert._from_rs_convert(super().__deepcopy__(memo))
[docs]class ClassicalLoad(quil_rs.Load, AbstractInstruction):
"""
The LOAD instruction.
"""
def __new__(cls, target: MemoryReference, left: str, right: MemoryReference) -> "ClassicalLoad":
return super().__new__(cls, target._to_rs_memory_reference(), left, right._to_rs_memory_reference())
@classmethod
def _from_rs_load(cls, load: quil_rs.Load) -> Self:
return super().__new__(cls, load.destination, load.source, load.offset)
@property
def target(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().destination)
@target.setter
def target(self, target: MemoryReference) -> None:
quil_rs.Load.destination.__set__(self, target._to_rs_memory_reference()) # type: ignore
@property
def left(self) -> str:
return super().source
@left.setter
def left(self, left: str) -> None:
quil_rs.Load.source.__set__(self, left) # type: ignore
@property
def right(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().offset)
@right.setter
def right(self, right: MemoryReference) -> None:
quil_rs.Load.offset.__set__(self, right._to_rs_memory_reference()) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ClassicalLoad":
return ClassicalLoad._from_rs_load(super().__deepcopy__(memo))
def _to_rs_arithmetic_operand(operand: Union[MemoryReference, int, float]) -> quil_rs.ArithmeticOperand:
if isinstance(operand, MemoryReference):
return quil_rs.ArithmeticOperand.from_memory_reference(operand._to_rs_memory_reference())
if isinstance(operand, int):
return quil_rs.ArithmeticOperand.from_literal_integer(operand)
if isinstance(operand, float):
return quil_rs.ArithmeticOperand.from_literal_real(operand)
raise TypeError(f"{type(operand)} is not a valid ArithmeticOperand")
def _to_py_arithmetic_operand(operand: quil_rs.ArithmeticOperand) -> Union[MemoryReference, int, float]:
if not isinstance(operand, quil_rs.ArithmeticOperand):
raise TypeError(f"{type(operand)} is not an ArithmeticOperand")
inner = operand.inner()
if isinstance(inner, quil_rs.MemoryReference):
return MemoryReference._from_rs_memory_reference(inner)
return inner
[docs]class ClassicalStore(quil_rs.Store, AbstractInstruction):
"""
The STORE instruction.
"""
def __new__(cls, target: str, left: MemoryReference, right: Union[MemoryReference, int, float]) -> "ClassicalStore":
rs_right = _to_rs_arithmetic_operand(right)
return super().__new__(cls, target, left._to_rs_memory_reference(), rs_right)
@classmethod
def _from_rs_store(cls, store: quil_rs.Store) -> Self:
return super().__new__(cls, store.destination, store.offset, store.source)
@property
def target(self) -> str:
return super().destination
@target.setter
def target(self, target: str) -> None:
quil_rs.Store.destination.__set__(self, target) # type: ignore
@property
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().offset)
@left.setter
def left(self, left: MemoryReference) -> None:
quil_rs.Store.offset.__set__(self, left._to_rs_memory_reference()) # type: ignore
@property
def right(self) -> Union[MemoryReference, int, float]:
return _to_py_arithmetic_operand(super().source)
@right.setter
def right(self, right: Union[MemoryReference, int, float]) -> None:
quil_rs.Store.source.__set__(self, _to_rs_arithmetic_operand(right)) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ClassicalStore":
return ClassicalStore._from_rs_store(super().__deepcopy__(memo))
[docs]class ClassicalComparison(quil_rs.Comparison, AbstractInstruction):
"""
Abstract class for ternary comparison instructions.
"""
op: ClassVar[quil_rs.ComparisonOperator]
def __new__(
cls,
target: MemoryReference,
left: MemoryReference,
right: Union[MemoryReference, int, float],
) -> "ClassicalComparison":
operands = (target._to_rs_memory_reference(), left._to_rs_memory_reference(), cls._to_comparison_operand(right))
return super().__new__(cls, cls.op, operands)
@classmethod
def _from_rs_comparison(cls, comparison: quil_rs.Comparison) -> Self:
return super().__new__(cls, comparison.operator, comparison.operands)
@staticmethod
def _to_comparison_operand(operand: Union[MemoryReference, int, float]) -> quil_rs.ComparisonOperand:
if isinstance(operand, MemoryReference):
return quil_rs.ComparisonOperand.from_memory_reference(operand._to_rs_memory_reference())
elif isinstance(operand, int):
return quil_rs.ComparisonOperand.from_literal_integer(operand)
elif isinstance(operand, float):
return quil_rs.ComparisonOperand.from_literal_real(operand)
raise TypeError(f"{type(operand)} is not a valid ComparisonOperand")
@staticmethod
def _to_py_operand(operand: quil_rs.ComparisonOperand) -> Union[MemoryReference, int, float]:
if not isinstance(operand, quil_rs.ComparisonOperand):
raise TypeError(f"{type(operand)} is not an ComparisonOperand")
inner = operand.inner()
if isinstance(inner, quil_rs.MemoryReference):
return MemoryReference._from_rs_memory_reference(inner)
return inner
@property
def target(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().operands[0])
@target.setter
def target(self, target: MemoryReference) -> None:
operands = list(super().operands)
operands[0] = target._to_rs_memory_reference()
quil_rs.Comparison.operands.__set__(self, tuple(operands)) # type: ignore
@property
def left(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().operands[1])
@left.setter
def left(self, left: MemoryReference) -> None:
operands = list(super().operands)
operands[1] = left._to_rs_memory_reference()
quil_rs.Comparison.operands.__set__(self, tuple(operands)) # type: ignore
@property
def right(self) -> Union[MemoryReference, int, float]:
return self._to_py_operand(super().operands[2])
@right.setter
def right(self, right: MemoryReference) -> None:
operands = list(super().operands)
operands[2] = self._to_comparison_operand(right)
quil_rs.Comparison.operands.__set__(self, tuple(operands)) # type: ignore
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ClassicalComparison":
copy = ClassicalComparison._from_rs_comparison(super().__deepcopy__(memo))
copy.__class__ = self.__class__
return copy
[docs]class ClassicalEqual(ClassicalComparison):
"""
The EQ comparison instruction.
"""
op = quil_rs.ComparisonOperator.Equal
[docs]class ClassicalLessThan(ClassicalComparison):
"""
The LT comparison instruction.
"""
op = quil_rs.ComparisonOperator.LessThan
[docs]class ClassicalLessEqual(ClassicalComparison):
"""
The LE comparison instruction.
"""
op = quil_rs.ComparisonOperator.LessThanOrEqual
[docs]class ClassicalGreaterThan(ClassicalComparison):
"""
The GT comparison instruction.
"""
op = quil_rs.ComparisonOperator.GreaterThan
[docs]class ClassicalGreaterEqual(ClassicalComparison):
"""
The GE comparison instruction.
"""
op = quil_rs.ComparisonOperator.GreaterThanOrEqual
[docs]class Jump(quil_rs.Jump, AbstractInstruction):
"""
Representation of an unconditional jump instruction (JUMP).
"""
def __new__(cls, target: Union[Label, LabelPlaceholder]) -> Self:
return super().__new__(cls, target.target)
@classmethod
def _from_rs_jump(cls, jump: quil_rs.Jump) -> Self:
return super().__new__(cls, jump.target)
@property # type: ignore[override]
def target(self) -> Union[Label, LabelPlaceholder]:
if super().target.is_placeholder():
return LabelPlaceholder._from_rs_target(super().target)
return Label._from_rs_target(super().target)
@target.setter
def target(self, target: Union[Label, LabelPlaceholder]) -> None:
quil_rs.Jump.target.__set__(self, target.target) # type: ignore[attr-defined]
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Jump":
return Jump._from_rs_jump(super().__deepcopy__(memo))
[docs]class Pragma(quil_rs.Pragma, AbstractInstruction):
"""
A PRAGMA instruction.
This is printed in QUIL as:
PRAGMA <command> <arg1> <arg2> ... <argn> "<freeform_string>"
"""
def __new__(
cls,
command: str,
args: Sequence[Union[Qubit, FormalArgument, int, str]] = (),
freeform_string: str = "",
) -> Self:
data = freeform_string or None
return super().__new__(cls, command, Pragma._to_pragma_arguments(args), data)
@classmethod
def _from_rs_pragma(cls, pragma: quil_rs.Pragma) -> "Pragma":
return super().__new__(cls, pragma.name, pragma.arguments, pragma.data)
@staticmethod
def _to_pragma_arguments(args: Sequence[Union[QubitDesignator, str]]) -> List[quil_rs.PragmaArgument]:
pragma_arguments = []
for arg in args:
if isinstance(arg, Qubit):
pragma_arguments.append(quil_rs.PragmaArgument.from_integer(arg.index))
elif isinstance(arg, int):
pragma_arguments.append(quil_rs.PragmaArgument.from_integer(arg))
elif isinstance(arg, (str, FormalArgument)):
pragma_arguments.append(quil_rs.PragmaArgument.from_identifier(str(arg)))
else:
raise TypeError(f"{type(arg)} isn't a valid PRAGMA argument")
return pragma_arguments
@staticmethod
def _to_py_arguments(args: List[quil_rs.PragmaArgument]) -> List[QubitDesignator]:
arguments: List[QubitDesignator] = []
for arg in args:
if arg.is_integer():
arguments.append(Qubit(arg.to_integer()))
else:
arguments.append(FormalArgument(arg.to_identifier()))
return arguments
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property
def command(self) -> str:
return super().name
@command.setter
def command(self, command: str) -> None:
quil_rs.Pragma.name.__set__(self, command) # type: ignore[attr-defined]
@property
def args(self) -> Tuple[QubitDesignator]:
return tuple(Pragma._to_py_arguments(super().arguments)) # type: ignore[return-value]
@args.setter
def args(self, args: Sequence[Union[QubitDesignator, str]]) -> None:
quil_rs.Pragma.arguments.__set__(self, Pragma._to_pragma_arguments(args)) # type: ignore[attr-defined]
@property
def freeform_string(self) -> str:
return super().data or ""
@freeform_string.setter
def freeform_string(self, freeform_string: str) -> None:
quil_rs.Pragma.data.__set__(self, freeform_string) # type: ignore[attr-defined]
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Pragma":
return Pragma._from_rs_pragma(super().__deepcopy__(memo))
[docs]class Declare(quil_rs.Declaration, AbstractInstruction):
"""
A DECLARE directive.
This is printed in Quil as::
DECLARE <name> <memory-type> (SHARING <other-name> (OFFSET <amount> <type>)* )?
"""
def __new__(
cls,
name: str,
memory_type: str,
memory_size: int = 1,
shared_region: Optional[str] = None,
offsets: Optional[Sequence[Tuple[int, str]]] = None,
) -> Self:
vector = quil_rs.Vector(Declare._memory_type_to_scalar_type(memory_type), memory_size)
sharing = None
if shared_region is not None:
sharing = quil_rs.Sharing(shared_region, Declare._to_rs_offsets(offsets))
return super().__new__(cls, name, vector, sharing)
@classmethod
def _from_rs_declaration(cls, declaration: quil_rs.Declaration) -> "Declare":
return super().__new__(cls, declaration.name, declaration.size, declaration.sharing)
@staticmethod
def _memory_type_to_scalar_type(memory_type: str) -> quil_rs.ScalarType:
memory_type = memory_type.upper()
if memory_type == "BIT":
return quil_rs.ScalarType.Bit
if memory_type == "INTEGER":
return quil_rs.ScalarType.Integer
if memory_type == "REAL":
return quil_rs.ScalarType.Real
if memory_type == "OCTET":
return quil_rs.ScalarType.Octet
raise ValueError(f"{memory_type} is not a valid scalar type.")
@staticmethod
def _to_rs_offsets(offsets: Optional[Sequence[Tuple[int, str]]]) -> List[quil_rs.Offset]:
if offsets is None:
return []
return [
quil_rs.Offset(offset, Declare._memory_type_to_scalar_type(memory_type)) for offset, memory_type in offsets
]
@property
def memory_type(self) -> str:
return str(super().size.data_type).upper()
@memory_type.setter
def memory_type(self, memory_type: str) -> None:
vector = super().size
vector.data_type = Declare._memory_type_to_scalar_type(memory_type)
quil_rs.Declaration.size.__set__(self, vector) # type: ignore[attr-defined]
@property
def memory_size(self) -> int:
return super().size.length
@memory_size.setter
def memory_size(self, memory_size: int) -> None:
vector = super().size
vector.length = memory_size
quil_rs.Declaration.size.__set__(self, vector) # type: ignore[attr-defined]
@property
def shared_region(self) -> Optional[str]:
sharing = super().sharing
if sharing is None:
return None
return sharing.name
@shared_region.setter
def shared_region(self, shared_region: Optional[str]) -> None:
sharing = None if not shared_region else quil_rs.Sharing(shared_region, [])
current_sharing = super().sharing
if sharing and isinstance(current_sharing, quil_rs.Sharing):
sharing.offsets = current_sharing.offsets
quil_rs.Declaration.sharing.__set__(self, sharing) # type: ignore[attr-defined]
@property
def offsets(self) -> List[Tuple[int, str]]:
sharing = super().sharing
if sharing is None:
return []
return [(offset.offset, str(offset.data_type).upper()) for offset in sharing.offsets]
@offsets.setter
def offsets(self, offsets: Optional[List[Tuple[int, str]]]) -> None:
sharing = super().sharing
if sharing is None:
raise ValueError("DECLARE without a shared region cannot use offsets")
sharing.offsets = Declare._to_rs_offsets(offsets)
quil_rs.Declaration.sharing.__set__(self, sharing) # type: ignore[attr-defined]
[docs] def asdict(self) -> Dict[str, Union[Sequence[Tuple[int, str]], Optional[str], int]]:
return {
"name": self.name,
"memory_type": self.memory_type,
"memory_size": self.memory_size,
"shared_region": self.shared_region,
"offsets": self.offsets,
}
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Declare":
return Declare._from_rs_declaration(super().__deepcopy__(memo))
[docs]class Include(quil_rs.Include, AbstractInstruction):
[docs] def out(self) -> str:
return super().to_quil()
@classmethod
def _from_rs_include(cls, include: quil_rs.Include) -> "Include":
return super().__new__(cls, include.filename)
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Include":
return Include._from_rs_include(super().__deepcopy__(memo))
[docs]class Pulse(quil_rs.Pulse, AbstractInstruction):
def __new__(cls, frame: Frame, waveform: Waveform, nonblocking: bool = False) -> Self:
return super().__new__(cls, not nonblocking, frame, waveform)
@classmethod
def _from_rs_pulse(cls, pulse: quil_rs.Pulse) -> "Pulse":
return super().__new__(cls, pulse.blocking, pulse.frame, pulse.waveform)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
else:
return set(_convert_to_py_qubits(super().frame.qubits))
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.Pulse.frame.__set__(self, frame) # type: ignore[attr-defined]
@property # type: ignore[override]
def waveform(self) -> Waveform:
return _convert_to_py_waveform(super().waveform)
@waveform.setter
def waveform(self, waveform: Waveform) -> None:
quil_rs.Pulse.waveform.__set__(self, waveform) # type: ignore[attr-defined]
@property
def nonblocking(self) -> bool:
return not super().blocking
@nonblocking.setter
def nonblocking(self, nonblocking: bool) -> None:
quil_rs.Pulse.blocking.__set__(self, not nonblocking) # type: ignore[attr-defined]
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Pulse":
return Pulse._from_rs_pulse(super().__deepcopy__(memo))
[docs]class SetFrequency(quil_rs.SetFrequency, AbstractInstruction):
def __new__(cls, frame: Frame, freq: ParameterDesignator) -> Self:
return super().__new__(cls, frame, _convert_to_rs_expression(freq))
@classmethod
def _from_rs_set_frequency(cls, set_frequency: quil_rs.SetFrequency) -> "SetFrequency":
return super().__new__(cls, set_frequency.frame, set_frequency.frequency)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.SetFrequency.frame.__set__(self, frame) # type: ignore[attr-defined]
@property
def freq(self) -> ParameterDesignator:
return _convert_to_py_expression(super().frequency)
@freq.setter
def freq(self, freq: ParameterDesignator) -> None:
quil_rs.SetFrequency.frequency.__set__(self, _convert_to_rs_expression(freq)) # type: ignore[attr-defined]
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
return set(self.frame.qubits)
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "SetFrequency":
return SetFrequency._from_rs_set_frequency(super().__deepcopy__(memo))
[docs]class ShiftFrequency(quil_rs.ShiftFrequency, AbstractInstruction):
def __new__(cls, frame: Frame, freq: ParameterDesignator) -> Self:
return super().__new__(cls, frame, _convert_to_rs_expression(freq))
@classmethod
def _from_rs_shift_frequency(cls, shift_frequency: quil_rs.ShiftFrequency) -> "ShiftFrequency":
return super().__new__(cls, shift_frequency.frame, shift_frequency.frequency)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.ShiftFrequency.frame.__set__(self, frame) # type: ignore[attr-defined]
@property
def freq(self) -> ParameterDesignator:
return _convert_to_py_expression(super().frequency)
@freq.setter
def freq(self, freq: ParameterDesignator) -> None:
quil_rs.ShiftFrequency.frequency.__set__(self, _convert_to_rs_expression(freq)) # type: ignore[attr-defined]
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
return set(self.frame.qubits)
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ShiftFrequency":
return ShiftFrequency._from_rs_shift_frequency(super().__deepcopy__(memo))
[docs]class SetPhase(quil_rs.SetPhase, AbstractInstruction):
def __new__(cls, frame: Frame, phase: ParameterDesignator) -> Self:
return super().__new__(cls, frame, _convert_to_rs_expression(phase))
@classmethod
def _from_rs_set_phase(cls, set_phase: quil_rs.SetPhase) -> "SetPhase":
return super().__new__(cls, set_phase.frame, set_phase.phase)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.SetPhase.frame.__set__(self, frame) # type: ignore[attr-defined]
@property # type: ignore[override]
def phase(self) -> ParameterDesignator:
return _convert_to_py_expression(super().phase)
@phase.setter
def phase(self, phase: ParameterDesignator) -> None:
quil_rs.SetPhase.phase.__set__(self, _convert_to_rs_expression(phase)) # type: ignore[attr-defined]
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
return set(self.frame.qubits)
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "SetPhase":
return SetPhase._from_rs_set_phase(super().__deepcopy__(memo))
[docs]class ShiftPhase(quil_rs.ShiftPhase, AbstractInstruction):
def __new__(cls, frame: Frame, phase: ParameterDesignator) -> Self:
return super().__new__(cls, frame, _convert_to_rs_expression(phase))
@classmethod
def _from_rs_shift_phase(cls, shift_phase: quil_rs.ShiftPhase) -> "ShiftPhase":
return super().__new__(cls, shift_phase.frame, shift_phase.phase)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.ShiftPhase.frame.__set__(self, frame) # type: ignore[attr-defined]
@property # type: ignore[override]
def phase(self) -> ParameterDesignator:
return _convert_to_py_expression(super().phase)
@phase.setter
def phase(self, phase: ParameterDesignator) -> None:
quil_rs.ShiftPhase.phase.__set__(self, _convert_to_rs_expression(phase)) # type: ignore[attr-defined]
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
return set(self.frame.qubits)
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "ShiftPhase":
return ShiftPhase._from_rs_shift_phase(super().__deepcopy__(memo))
[docs]class SwapPhases(quil_rs.SwapPhases, AbstractInstruction):
def __new__(cls, frameA: Frame, frameB: Frame) -> Self:
return super().__new__(cls, frameA, frameB)
@classmethod
def _from_rs_swap_phases(cls, swap_phases: quil_rs.SwapPhases) -> "SwapPhases":
return super().__new__(cls, swap_phases.frame_1, swap_phases.frame_2)
@property
def frameA(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame_1)
@frameA.setter
def frameA(self, frame: Frame) -> None:
quil_rs.SwapPhases.frame_1.__set__(self, frame) # type: ignore[attr-defined]
@property
def frameB(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame_2)
@frameB.setter
def frameB(self, frame: Frame) -> None:
quil_rs.SwapPhases.frame_2.__set__(self, frame) # type: ignore[attr-defined]
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
return set(self.frameA.qubits) | set(self.frameB.qubits)
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame_1.qubits + super().frame_2.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "SwapPhases":
return SwapPhases._from_rs_swap_phases(super().__deepcopy__(memo))
[docs]class SetScale(quil_rs.SetScale, AbstractInstruction):
def __new__(cls, frame: Frame, scale: ParameterDesignator) -> Self:
return super().__new__(cls, frame, _convert_to_rs_expression(scale))
@classmethod
def _from_rs_set_scale(cls, set_scale: quil_rs.SetScale) -> "SetScale":
return super().__new__(cls, set_scale.frame, set_scale.scale)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.SetScale.frame.__set__(self, frame) # type: ignore[attr-defined]
@property # type: ignore[override]
def scale(self) -> ParameterDesignator:
return _convert_to_py_expression(super().scale)
@scale.setter
def scale(self, scale: ParameterDesignator) -> None:
quil_rs.SetScale.scale.__set__(self, _convert_to_rs_expression(scale)) # type: ignore[attr-defined]
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
return set(self.frame.qubits)
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "SetScale":
return SetScale._from_rs_set_scale(super().__deepcopy__(memo))
[docs]class Capture(quil_rs.Capture, AbstractInstruction):
def __new__(
cls,
frame: Frame,
kernel: Waveform,
memory_region: MemoryReference,
nonblocking: bool = False,
) -> Self:
rs_memory_reference = _convert_to_rs_expression(memory_region).to_address()
return super().__new__(cls, not nonblocking, frame, rs_memory_reference, kernel)
@classmethod
def _from_rs_capture(cls, capture: quil_rs.Capture) -> "Capture":
return super().__new__(cls, capture.blocking, capture.frame, capture.memory_reference, capture.waveform)
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.Capture.frame.__set__(self, frame) # type: ignore[attr-defined]
@property
def kernel(self) -> Waveform:
return _convert_to_py_waveform(super().waveform)
@kernel.setter
def kernel(self, kernel: Waveform) -> None:
quil_rs.Capture.waveform.__set__(self, kernel) # type: ignore[attr-defined]
@property
def memory_region(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().memory_reference)
@memory_region.setter
def memory_region(self, memory_region: MemoryReference) -> None:
rs_memory_reference = _convert_to_rs_expression(memory_region).to_address()
quil_rs.Capture.memory_reference.__set__(self, rs_memory_reference) # type: ignore[attr-defined]
@property
def nonblocking(self) -> bool:
return not super().blocking
@nonblocking.setter
def nonblocking(self, nonblocking: bool) -> None:
quil_rs.Capture.blocking.__set__(self, not nonblocking) # type: ignore[attr-defined]
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
else:
return set(_convert_to_py_qubits(super().frame.qubits))
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Capture":
return Capture._from_rs_capture(super().__deepcopy__(memo))
[docs]class RawCapture(quil_rs.RawCapture, AbstractInstruction):
def __new__(
cls,
frame: Frame,
duration: float,
memory_region: MemoryReference,
nonblocking: bool = False,
) -> Self:
rs_duration = _convert_to_rs_expression(duration)
rs_memory_reference = _convert_to_rs_expression(memory_region).to_address()
return super().__new__(cls, not nonblocking, frame, rs_duration, rs_memory_reference)
@classmethod
def _from_rs_raw_capture(cls, raw_capture: quil_rs.RawCapture) -> "RawCapture":
return super().__new__(
cls, raw_capture.blocking, raw_capture.frame, raw_capture.duration, raw_capture.memory_reference
)
@property # type: ignore[override]
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().frame)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.RawCapture.frame.__set__(self, frame) # type: ignore[attr-defined]
@property # type: ignore[override]
def duration(self) -> complex:
return super().duration.to_number()
@duration.setter
def duration(self, duration: float) -> None:
rs_duration = _convert_to_rs_expression(duration)
quil_rs.RawCapture.duration.__set__(self, rs_duration) # type: ignore[attr-defined]
@property
def memory_region(self) -> MemoryReference:
return MemoryReference._from_rs_memory_reference(super().memory_reference)
@memory_region.setter
def memory_region(self, memory_region: MemoryReference) -> None:
rs_memory_reference = _convert_to_rs_expression(memory_region).to_address()
quil_rs.RawCapture.memory_reference.__set__(self, rs_memory_reference) # type: ignore[attr-defined]
@property
def nonblocking(self) -> bool:
return not super().blocking
@nonblocking.setter
def nonblocking(self, nonblocking: bool) -> None:
quil_rs.RawCapture.blocking.__set__(self, not nonblocking) # type: ignore[attr-defined]
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
[docs] @deprecated(
version="4.0",
reason="The indices flag will be removed, use get_qubit_indices() instead.",
)
def get_qubits(self, indices: bool = True) -> Union[Set[QubitDesignator], Set[int]]:
if indices:
return self.get_qubit_indices()
else:
return set(_convert_to_py_qubits(super().frame.qubits))
[docs] def get_qubit_indices(self) -> Set[int]:
return {qubit.to_fixed() for qubit in super().frame.qubits}
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "RawCapture":
return RawCapture._from_rs_raw_capture(super().__deepcopy__(memo))
[docs]class Delay(quil_rs.Delay, AbstractInstruction):
def __new__(cls, frames: List[Frame], qubits: Sequence[Union[int, Qubit, FormalArgument]], duration: float) -> Self:
frame_names = [frame.name for frame in frames]
rs_qubits = _convert_to_rs_qubits(Delay._join_frame_qubits(frames, list(qubits)))
expression = quil_rs_expr.Expression.from_number(complex(duration))
return super().__new__(cls, expression, frame_names, rs_qubits)
@classmethod
def _from_rs_delay(cls, delay: quil_rs.Delay) -> "Delay":
return super().__new__(cls, delay.duration, delay.frame_names, delay.qubits)
@staticmethod
def _join_frame_qubits(
frames: Sequence[Frame], qubits: Sequence[Union[int, Qubit, FormalArgument]]
) -> List[Union[int, Qubit, FormalArgument]]:
merged_qubits = set(qubits)
for frame in frames:
merged_qubits.update(frame.qubits) # type: ignore
return list(merged_qubits)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def qubits(self) -> List[QubitDesignator]:
return _convert_to_py_qubits(super().qubits)
@qubits.setter
def qubits(self, qubits: Sequence[Union[int, Qubit, FormalArgument]]) -> None:
quil_rs.Delay.qubits.__set__(self, _convert_to_rs_qubits(qubits)) # type: ignore
@property
def frames(self) -> List[Frame]:
return [Frame(self.qubits, name) for name in super().frame_names]
@frames.setter
def frames(self, frames: List[Frame]) -> None:
new_qubits = Delay._join_frame_qubits(frames, [])
frame_names = [frame.name for frame in frames]
quil_rs.Delay.qubits.__set__(self, _convert_to_rs_qubits(new_qubits)) # type: ignore[attr-defined]
quil_rs.Delay.frame_names.__set__(self, frame_names) # type: ignore[attr-defined]
@property # type: ignore[override]
def duration(self) -> float:
return super().duration.to_real()
@duration.setter
def duration(self, duration: float) -> None:
expression = quil_rs_expr.Expression.from_number(complex(duration))
quil_rs.Delay.duration.__set__(self, expression) # type: ignore[attr-defined]
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Delay":
copy = Delay._from_rs_delay(super().__deepcopy__(memo))
copy.__class__ = self.__class__
return copy
[docs]class DelayFrames(Delay):
def __new__(cls, frames: List[Frame], duration: float) -> Self:
return super().__new__(cls, frames, [], duration)
@classmethod
def _from_rs_delay(cls, delay: quil_rs.Delay) -> "DelayFrames":
return Delay._from_rs_delay.__func__(cls, delay) # type: ignore
[docs]class DelayQubits(Delay):
def __new__(cls, qubits: Sequence[Union[Qubit, FormalArgument]], duration: float) -> Self:
return super().__new__(cls, [], qubits, duration)
@classmethod
def _from_rs_delay(cls, delay: quil_rs.Delay) -> "DelayQubits":
return Delay._from_rs_delay.__func__(cls, delay) # type: ignore
[docs]class Fence(quil_rs.Fence, AbstractInstruction):
def __new__(cls, qubits: List[Union[Qubit, FormalArgument]]) -> Self:
return super().__new__(cls, _convert_to_rs_qubits(qubits))
@classmethod
def _from_rs_fence(cls, fence: quil_rs.Fence) -> "Fence":
return super().__new__(cls, fence.qubits)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def qubits(self) -> List[QubitDesignator]:
return _convert_to_py_qubits(super().qubits)
@qubits.setter
def qubits(self, qubits: List[Union[Qubit, FormalArgument]]) -> None:
quil_rs.Fence.qubits.__set__(self, _convert_to_rs_qubits(qubits)) # type: ignore[attr-defined]
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "Fence":
return Fence._from_rs_fence(super().__deepcopy__(memo))
[docs]class FenceAll(Fence):
"""
The FENCE instruction.
"""
def __new__(cls) -> Self:
return super().__new__(cls, [])
[docs]class DefCircuit(quil_rs.CircuitDefinition, AbstractInstruction):
def __new__(
cls,
name: str,
parameters: List[Parameter],
qubits: List[FormalArgument],
instructions: List[AbstractInstruction],
) -> Self:
rs_parameters = [parameter.name for parameter in parameters]
rs_qubits = [qubit.name for qubit in qubits]
rs_instructions = _convert_to_rs_instructions(instructions)
return super().__new__(cls, name, rs_parameters, rs_qubits, rs_instructions)
@classmethod
def _from_rs_circuit_definition(cls, circuit_definition: quil_rs.CircuitDefinition) -> "DefCircuit":
return super().__new__(
cls,
circuit_definition.name,
circuit_definition.parameters,
circuit_definition.qubit_variables,
circuit_definition.instructions,
)
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property # type: ignore[override]
def parameters(self) -> List[Parameter]:
return [Parameter(parameter) for parameter in super().parameters]
@parameters.setter
def parameters(self, parameters: List[Parameter]) -> None:
rs_parameters = [parameter.name for parameter in parameters]
quil_rs.CircuitDefinition.parameters.__set__(self, rs_parameters) # type: ignore[attr-defined]
@property # type: ignore[override]
def qubit_variables(self) -> List[FormalArgument]:
return [FormalArgument(qubit) for qubit in super().qubit_variables]
@qubit_variables.setter
def qubit_variables(self, qubits: List[FormalArgument]) -> None:
rs_qubits = [qubit.name for qubit in qubits]
quil_rs.CircuitDefinition.qubit_variables.__set__(self, rs_qubits) # type: ignore[attr-defined]
@property # type: ignore[override]
def instructions(self) -> List[AbstractInstruction]:
return _convert_to_py_instructions(super().instructions)
@instructions.setter
def instructions(self, instructions: List[AbstractInstruction]) -> None:
rs_instructions = _convert_to_rs_instructions(instructions)
quil_rs.CircuitDefinition.instructions.__set__(self, rs_instructions) # type: ignore[attr-defined]
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "DefCircuit":
return DefCircuit._from_rs_circuit_definition(super().__deepcopy__(memo))
[docs]class DefCalibration(quil_rs.Calibration, AbstractInstruction):
def __new__(
cls,
name: str,
parameters: Sequence[ParameterDesignator],
qubits: Sequence[Union[Qubit, FormalArgument]],
instrs: Sequence[AbstractInstruction],
modifiers: Optional[List[quil_rs.GateModifier]] = None,
) -> Self:
return super().__new__(
cls,
name,
_convert_to_rs_expressions(parameters),
_convert_to_rs_qubits(qubits),
_convert_to_rs_instructions(instrs),
modifiers or [],
)
@classmethod
def _from_rs_calibration(cls, calibration: quil_rs.Calibration) -> "DefCalibration":
return super().__new__(
cls,
calibration.name,
calibration.parameters,
calibration.qubits,
calibration.instructions,
calibration.modifiers,
)
@property # type: ignore[override]
def parameters(self) -> Sequence[ParameterDesignator]:
return _convert_to_py_expressions(super().parameters)
@parameters.setter
def parameters(self, parameters: Sequence[ParameterDesignator]) -> None:
quil_rs.Calibration.parameters.__set__(self, _convert_to_rs_expressions(parameters)) # type: ignore[attr-defined] # noqa
@property # type: ignore[override]
def qubits(self) -> List[QubitDesignator]:
return _convert_to_py_qubits(super().qubits)
@qubits.setter
def qubits(self, qubits: Sequence[QubitDesignator]) -> None:
quil_rs.Calibration.qubits.__set__(self, _convert_to_rs_qubits(qubits)) # type: ignore[attr-defined]
@property
def instrs(self) -> List[AbstractInstruction]:
return _convert_to_py_instructions(super().instructions)
@instrs.setter
def instrs(self, instrs: Sequence[AbstractInstruction]) -> None:
quil_rs.Calibration.instructions.__set__(self, _convert_to_rs_instructions(instrs)) # type: ignore[attr-defined] # noqa
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "DefCalibration":
return DefCalibration._from_rs_calibration(super().__deepcopy__(memo))
[docs]class DefMeasureCalibration(quil_rs.MeasureCalibrationDefinition, AbstractInstruction):
def __new__(
cls,
qubit: Optional[Union[Qubit, FormalArgument]],
memory_reference: MemoryReference,
instrs: List[AbstractInstruction],
) -> Self:
rs_qubit = None if not qubit else _convert_to_rs_qubit(qubit)
return super().__new__(
cls,
rs_qubit,
memory_reference.name,
_convert_to_rs_instructions(instrs),
)
@classmethod
def _from_rs_measure_calibration_definition(
cls, calibration: quil_rs.MeasureCalibrationDefinition
) -> "DefMeasureCalibration":
return super().__new__(cls, calibration.qubit, calibration.parameter, calibration.instructions)
@property # type: ignore[override]
def qubit(self) -> Optional[QubitDesignator]:
qubit = super().qubit
if not qubit:
return None
return _convert_to_py_qubit(qubit)
@qubit.setter
def qubit(self, qubit: QubitDesignator) -> None:
quil_rs.MeasureCalibrationDefinition.qubit.__set__(self, _convert_to_rs_qubit(qubit)) # type: ignore[attr-defined] # noqa
@property
def memory_reference(self) -> Optional[MemoryReference]:
return MemoryReference._from_parameter_str(super().parameter)
@memory_reference.setter
def memory_reference(self, memory_reference: MemoryReference) -> None:
quil_rs.MeasureCalibrationDefinition.parameter.__set__(self, memory_reference.name) # type: ignore[attr-defined] # noqa
@property
def instrs(self) -> List[AbstractInstruction]:
return _convert_to_py_instructions(super().instructions)
@instrs.setter
def instrs(self, instrs: List[AbstractInstruction]) -> None:
quil_rs.MeasureCalibrationDefinition.instructions.__set__(self, _convert_to_rs_instructions(instrs)) # type: ignore[attr-defined] # noqa
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "DefMeasureCalibration":
return DefMeasureCalibration._from_rs_measure_calibration_definition(super().__deepcopy__(memo))
[docs]class DefFrame(quil_rs.FrameDefinition, AbstractInstruction):
def __new__(
cls,
frame: Frame,
direction: Optional[str] = None,
initial_frequency: Optional[float] = None,
hardware_object: Optional[str] = None,
sample_rate: Optional[float] = None,
center_frequency: Optional[float] = None,
enable_raw_capture: Optional[str] = None,
channel_delay: Optional[float] = None,
) -> Self:
attributes = {
key: DefFrame._to_attribute_value(value)
for key, value in zip(
[
"DIRECTION",
"INITIAL-FREQUENCY",
"HARDWARE-OBJECT",
"SAMPLE-RATE",
"CENTER-FREQUENCY",
"ENABLE-RAW-CAPTURE",
"CHANNEL-DELAY",
],
[
direction,
initial_frequency,
hardware_object,
sample_rate,
center_frequency,
enable_raw_capture,
channel_delay,
],
)
if value is not None
}
return super().__new__(cls, frame, attributes)
@classmethod
def _from_rs_frame_definition(cls, def_frame: quil_rs.FrameDefinition) -> "DefFrame":
return super().__new__(cls, def_frame.identifier, def_frame.attributes)
@classmethod
def _from_rs_attribute_values(
cls, frame: quil_rs.FrameIdentifier, attributes: Dict[str, quil_rs.AttributeValue]
) -> "DefFrame":
return super().__new__(cls, frame, attributes)
@staticmethod
def _to_attribute_value(value: Union[str, float]) -> quil_rs.AttributeValue:
if isinstance(value, str):
return quil_rs.AttributeValue.from_string(value)
if isinstance(value, (int, float, complex)):
return quil_rs.AttributeValue.from_expression(quil_rs_expr.Expression.from_number(complex(value)))
raise ValueError(f"{type(value)} is not a valid AttributeValue")
[docs] def out(self) -> str:
return super().to_quil()
def __str__(self) -> str:
return super().to_quil_or_debug()
@property
def frame(self) -> Frame:
return Frame._from_rs_frame_identifier(super().identifier)
@frame.setter
def frame(self, frame: Frame) -> None:
quil_rs.FrameDefinition.identifier.__set__(self, frame) # type: ignore[attr-defined]
[docs] def set_attribute(self, name: str, value: Union[str, float]) -> None:
updated = super().attributes
updated.update({name: DefFrame._to_attribute_value(value)})
quil_rs.FrameDefinition.attributes.__set__(self, updated) # type: ignore[attr-defined]
[docs] def get_attribute(self, name: str) -> Optional[Union[str, float]]:
value = super().attributes.get(name, None)
if value is None:
return None
if value.is_string():
return value.to_string()
return value.to_expression().to_number().real
def __getitem__(self, name: str) -> Union[str, float]:
if not isinstance(name, str):
raise TypeError("Frame attribute keys must be strings")
value = self.get_attribute(name)
if value is None:
raise AttributeError(f"Attribute {name} not found")
return value
def __setitem__(self, name: str, value: Union[str, float]) -> None:
if not isinstance(name, str):
raise TypeError("Frame attribute keys must be strings")
self.set_attribute(name, value)
@property
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use get_attribute('DIRECTION') instead.",
)
def direction(self) -> Optional[str]:
return self.get_attribute("DIRECTION") # type: ignore
@direction.setter
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('DIRECTION') instead.",
)
def direction(self, direction: str) -> None:
self.set_attribute("DIRECTION", direction)
@property
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('INITIAL-FREQUENCY') instead.", # noqa: E501
)
def initial_frequency(self) -> Optional[float]:
return self.get_attribute("INITIAL-FREQUENCY") # type: ignore
@initial_frequency.setter
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('INITIAL-FREQUENCY') instead.", # noqa: E501
)
def initial_frequency(self, initial_frequency: float) -> None:
self.set_attribute("INITIAL-FREQUENCY", initial_frequency)
@property
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use get_attribute('HARDWARE-OBJECT') instead.",
)
def hardware_object(self) -> Optional[str]:
return self.get_attribute("HARDWARE-OBJECT") # type: ignore
@hardware_object.setter
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('HARDWARE-OBJECT') instead.",
)
def hardware_object(self, hardware_object: str) -> None:
self.set_attribute("HARDWARE-OBJECT", hardware_object)
@property
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use get_attribute('SAMPLE-RATE') instead.",
)
def sample_rate(self) -> Frame:
return self.get_attribute("SAMPLE-RATE") # type: ignore
@sample_rate.setter
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('SAMPLE-RATE') instead.",
)
def sample_rate(self, sample_rate: float) -> None:
self.set_attribute("SAMPLE-RATE", sample_rate)
@property
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use get_attribute('CENTER-FREQUENCY') instead.",
)
def center_frequency(self) -> Frame:
return self.get_attribute("CENTER-FREQUENCY") # type: ignore
@center_frequency.setter
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('CENTER-FREQUENCY') instead.",
)
def center_frequency(self, center_frequency: float) -> None:
self.set_attribute("CENTER-FREQUENCY", center_frequency)
@property
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use get_attribute('CHANNEL-DELAY') instead.",
)
def channel_delay(self) -> Frame:
return self.get_attribute("CHANNEL-DELAY") # type: ignore
@channel_delay.setter
@deprecated(
version="4.0",
reason="Quil now supports generic key/value pairs in DEFFRAMEs. Use set_attribute('CHANNEL-DELAY') instead.",
)
def channel_delay(self, channel_delay: float) -> None:
self.set_attribute("CHANNEL-DELAY", channel_delay)
def __copy__(self) -> Self:
return self
def __deepcopy__(self, memo: Dict) -> "DefFrame":
return DefFrame._from_rs_frame_definition(super().__deepcopy__(memo))