# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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.
from enum import Enum
from braket.ir.jaqcd.shared_models import (
Angle,
CompilerDirective,
DampingProbability,
DampingSingleProbability,
DoubleControl,
DoubleTarget,
MultiProbability,
MultiTarget,
SingleControl,
SingleProbability,
SingleProbability_34,
SingleProbability_1516,
SingleTarget,
TripleProbability,
TwoDimensionalMatrix,
TwoDimensionalMatrixList,
)
"""
Instructions that can be supplied to the braket.ir.jaqcd.Program.
To add a new instruction:
- Implement a class in this module.
- Class must contain a property, "type", that is an enum of the class implemented in the
next step.
- Implement a subclass, "Type", within this class that extends [str, enum].
All enum values must be unique across all instructions, otherwise de-serialization
will have undeterministic behaviors. These enums will be used to determine what type
the instruction is, i.e. what class to use for deserializing.
- NOTE: Due to how multiple inhertiance works in Python it is easiest to define a
type enum class within each instruction, instead of calling the relevant parent
constructors to initialize it correctly.
- Inherit any classes from braket.ir.jaqcd.shared_models.
- Write up docstrings to define the instruction, properties, and examples.
"""
[docs]class H(SingleTarget):
"""
Hadamard gate.
Attributes:
type (str): The instruction type. default = "h". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> H(target=1)
"""
[docs] class Type(str, Enum):
h = "h"
type = Type.h
[docs]class I(SingleTarget): # noqa: E742, E261
"""
Identity gate.
Attributes:
type (str): The instruction type. default = "i". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> I(target=1)
"""
[docs] class Type(str, Enum):
i = "i"
type = Type.i
[docs]class X(SingleTarget):
"""
Pauli-X gate.
Attributes:
type (str): The instruction type. default = "x". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> X(target=0)
"""
[docs] class Type(str, Enum):
x = "x"
type = Type.x
[docs]class Y(SingleTarget):
"""
Pauli-Y gate.
Attributes:
type (str): The instruction type. default = "y". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> Y(target=0)
"""
[docs] class Type(str, Enum):
y = "y"
type = Type.y
[docs]class Z(SingleTarget):
"""
Pauli-Z gate.
Attributes:
type (str): The instruction type. default = "z". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> Z(target=0)
"""
[docs] class Type(str, Enum):
z = "z"
type = Type.z
[docs]class Rx(SingleTarget, Angle):
"""
X-axis rotation gate.
Attributes:
type (str): The instruction type. default = "rx". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
Examples:
>>> Rx(target=0, angle=0.15)
"""
[docs] class Type(str, Enum):
rx = "rx"
type = Type.rx
[docs]class Ry(SingleTarget, Angle):
"""
Y-axis rotation gate.
Attributes:
type (str): The instruction type. default = "ry". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
Examples:
>>> Ry(target=0, angle=0.15)
"""
[docs] class Type(str, Enum):
ry = "ry"
type = Type.ry
[docs]class Rz(SingleTarget, Angle):
"""
Z-axis rotation gate.
Attributes:
type (str): The instruction type. default = "rz". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
Examples:
>>> Rz(target=0, angle=0.15)
"""
[docs] class Type(str, Enum):
rz = "rz"
type = Type.rz
[docs]class S(SingleTarget):
"""
S gate. Applies a 90 degree rotation around the Z-axis.
Attributes:
type (str): The instruction type. default = "s". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> S(target=0)
"""
[docs] class Type(str, Enum):
s = "s"
type = Type.s
[docs]class T(SingleTarget):
"""
T gate. Applies a 45 degree rotation around the Z-axis.
Attributes:
type (str): The instruction type. default = "t". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> T(target=0)
"""
[docs] class Type(str, Enum):
t = "t"
type = Type.t
[docs]class Si(SingleTarget):
"""
Si gate. Conjugate transpose of S gate.
Attributes:
type (str): The instruction type. default = "si". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> Si(target=0)
"""
[docs] class Type(str, Enum):
si = "si"
type = Type.si
[docs]class Ti(SingleTarget):
"""
Ti gate. Conjugate transpose of T gate.
Attributes:
type (str): The instruction type. default = "ti". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> Ti(target=0)
"""
[docs] class Type(str, Enum):
ti = "ti"
type = Type.ti
[docs]class Swap(DoubleTarget):
"""
Swap gate. Swaps the state of the two qubits.
Attributes:
type (str): The instruction type. default = "swap". (type) is optional.
This should be unique among all instruction types.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> Swap(targets=[0, 1])
"""
[docs] class Type(str, Enum):
swap = "swap"
type = Type.swap
[docs]class CSwap(SingleControl, DoubleTarget):
"""
Controlled swap gate.
Attributes:
type (str): The instruction type. default = "cswap". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> Swap(control=0, targets=[1, 2])
"""
[docs] class Type(str, Enum):
cswap = "cswap"
type = Type.cswap
[docs]class ISwap(DoubleTarget):
"""
ISwap gate. Swaps the state of two qubits, applying a -i phase to q1 when it is in the 1 state
and a -i phase to q2 when it is in the 0 state.
This is equivalent to XY(pi)
Attributes:
type (str): The instruction type. default = "iswap". (type) is optional.
This should be unique among all instruction types.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> ISwap(targets=[0, 1])
"""
[docs] class Type(str, Enum):
iswap = "iswap"
type = Type.iswap
[docs]class PSwap(DoubleTarget, Angle):
"""
Parameterized swap gate that takes in the angle of the phase to apply to the swapped gates.
Attributes:
type (str): The instruction type. default = "pswap". (type) is optional.
This should be unique among all instruction types.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> PSwap(targets=[0, 1], angle=0.15)
"""
[docs] class Type(str, Enum):
pswap = "pswap"
type = Type.pswap
[docs]class XY(DoubleTarget, Angle):
"""
Rotates between \\|01> and \\|10> by the given angle.
Attributes:
type (str): The instruction type. default = "xy". (type) is optional.
This should be unique among all instruction types.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> XY(targets=[0, 1], angle=0.15)
"""
[docs] class Type(str, Enum):
xy = "xy"
type = Type.xy
[docs]class PhaseShift(SingleTarget, Angle):
"""
Phase shift gate. Shifts the phase between \\|0> and \\|1> by a given angle.
Attributes:
type (str): The instruction type. default = "phaseshift". (type) is optional.
This should be unique among all instruction types.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> PhaseShift(target=1, angle=0.15)
"""
[docs] class Type(str, Enum):
phaseshift = "phaseshift"
type = Type.phaseshift
[docs]class CPhaseShift(SingleTarget, SingleControl, Angle):
"""
Controlled phase shift gate.
Attributes:
type (str): The instruction type. default = "cphaseshift". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CPhaseShift(control=0, target=1, angle=0.15)
"""
[docs] class Type(str, Enum):
cphaseshift = "cphaseshift"
type = Type.cphaseshift
[docs]class CPhaseShift00(SingleTarget, SingleControl, Angle):
"""
Controlled phase shift gate that phases the \\|00> state.
Attributes:
type (str): The instruction type. default = "cphaseshift00". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CPhaseShift00(control=0, target=1, angle=0.15)
"""
[docs] class Type(str, Enum):
cphaseshift00 = "cphaseshift00"
type = Type.cphaseshift00
[docs]class CPhaseShift01(SingleTarget, SingleControl, Angle):
"""
Controlled phase shift gate that phases the \\|01> state.
Attributes:
type (str): The instruction type. default = "cphaseshift01". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CPhaseShift01(control=0, target=1, angle=0.15)
"""
[docs] class Type(str, Enum):
cphaseshift01 = "cphaseshift01"
type = Type.cphaseshift01
[docs]class CPhaseShift10(SingleTarget, SingleControl, Angle):
"""
Controlled phase shift gate that phases the \\|10> state.
Attributes:
type (str): The instruction type. default = "cphaseshift10". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CPhaseShift10(control=0, target=1, angle=0.15)
"""
[docs] class Type(str, Enum):
cphaseshift10 = "cphaseshift10"
type = Type.cphaseshift10
[docs]class CNot(SingleTarget, SingleControl):
"""
Controlled not gate. Also known as the CX gate.
Attributes:
type (str): The instruction type. default = "cnot". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CNot(control=0, target=1)
"""
[docs] class Type(str, Enum):
cnot = "cnot"
type = Type.cnot
[docs]class CCNot(SingleTarget, DoubleControl):
"""
Doubly-controlled NOT gate. Also known as the Toffoli gate.
Attributes:
type (str): The instruction type. default = "ccnot". (type) is optional.
This should be unique among all instruction types.
controls (int): The control qubits.
This is a list with two items and all items are int >= 0.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CCNot(control=[0,1], target=1)
"""
[docs] class Type(str, Enum):
ccnot = "ccnot"
type = Type.ccnot
[docs]class CV(SingleTarget, SingleControl):
"""
Controlled sqrt(NOT) gate. Also known as the CV gate.
Attributes:
type (str): The instruction type. default = "cv". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CV(control=0, target=1)
"""
[docs] class Type(str, Enum):
cv = "cv"
type = Type.cv
[docs]class CY(SingleTarget, SingleControl):
"""
Controlled Y-gate.
Attributes:
type (str): The instruction type. default = "cy". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CY(control=0, target=1)
"""
[docs] class Type(str, Enum):
cy = "cy"
type = Type.cy
[docs]class CZ(SingleTarget, SingleControl):
"""
Controlled Z-gate.
Attributes:
type (str): The instruction type. default = "cz". (type) is optional.
This should be unique among all instruction types.
control (int): The control qubit. This is an int >= 0.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> CZ(control=0, target=1)
"""
[docs] class Type(str, Enum):
cz = "cz"
type = Type.cz
[docs]class ECR(DoubleTarget):
"""
An echoed RZX(pi/2) gate.
Attributes:
type (str): The instruction type. default = "ecr". (type) is optional.
This should be unique among all instruction types.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> ECR(targets=[0, 1])
"""
[docs] class Type(str, Enum):
ecr = "ecr"
type = Type.ecr
[docs]class XX(DoubleTarget, Angle):
"""
The Ising (XX) gate.
Attributes:
type (str): The instruction type. default = "xx". (type) is optional.
This should be unique among all instruction types.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> XX(targets=[0, 1], angle=0.15)
"""
[docs] class Type(str, Enum):
xx = "xx"
type = Type.xx
[docs]class YY(DoubleTarget, Angle):
"""
The Ising (YY) gate.
Attributes:
type (str): The instruction type. default = "yy". (type) is optional.
This should be unique among all instruction types.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> YY(targets=[0, 1], angle=0.15)
"""
[docs] class Type(str, Enum):
yy = "yy"
type = Type.yy
[docs]class ZZ(DoubleTarget, Angle):
"""
The Ising (ZZ) gate.
Attributes:
type (str): The instruction type. default = "zz". (type) is optional.
This should be unique among all instruction types.
angle (float): The angle in radians.
inf, -inf, and NaN are not allowable inputs.
targets (List[int]): The target qubits.
This is a list with two items and all items are int >= 0.
Examples:
>>> ZZ(targets=[0, 1], angle=0.15)
"""
[docs] class Type(str, Enum):
zz = "zz"
type = Type.zz
[docs]class V(SingleTarget):
"""
Square root of NOT gate.
Attributes:
type (str): The instruction type. default = "v". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> V(target=0)
"""
[docs] class Type(str, Enum):
v = "v"
type = Type.v
[docs]class Vi(SingleTarget):
"""
Conjugate transpose of square root of NOT gate.
Attributes:
type (str): The instruction type. default = "vi". (type) is optional.
This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> Vi(target=0)
"""
[docs] class Type(str, Enum):
vi = "vi"
type = Type.vi
[docs]class Unitary(TwoDimensionalMatrix, MultiTarget):
"""
Arbitrary unitary matrix gate
Attributes:
type (str): The instruction type. default = "unitary". (type) is optional.
This should be unique among all instruction types.
targets (List[int]): The target qubits. This is a list with ints and all ints >= 0.
matrix (List[List[List[float]]]): The unitary matrix specifying the behavior of the gate.
Examples:
>>> Unitary(targets=[0], matrix=[[[0, 0], [1, 0]],[[1, 0], [0, 1]]])
"""
[docs] class Type(str, Enum):
unitary = "unitary"
type = Type.unitary
[docs]class BitFlip(SingleTarget, SingleProbability):
"""
Bit Flip noise channel.
Attributes:
type (str): The instruction type. default = "bit_flip". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> BitFlip(target=1, probability=0.1)
"""
[docs] class Type(str, Enum):
bit_flip = "bit_flip"
type = Type.bit_flip
[docs]class PhaseFlip(SingleTarget, SingleProbability):
"""
Phase Flip noise channel.
Attributes:
type (str): The instruction type. default = "phase_flip". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> PhaseFlip(target=1, probability=0.1)
"""
[docs] class Type(str, Enum):
phase_flip = "phase_flip"
type = Type.phase_flip
[docs]class PauliChannel(SingleTarget, TripleProbability):
"""
A single qubit Pauli noise channel.
Attributes:
type (str): The instruction type. default = "pauli_channel". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> PauliChannel(target=1, probX=0.1, probY=0.2, probZ=0.3)
"""
[docs] class Type(str, Enum):
pauli_channel = "pauli_channel"
type = Type.pauli_channel
[docs]class MultiQubitPauliChannel(MultiTarget, MultiProbability):
"""
Multi-qubit Pauli noise channel.
Attributes:
type (str): The instruction type. default = "multi_qubit_pauli_channel". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit(s). This is list of intergers >= 0.
The length of the list must match the length of the Pauli strings provided.
Examples:
>>> MultiQubitPauliChannel(target=1, probabilities={"X": 0.1})
>>> MultiQubitPauliChannel(target=[0,1], probabilities={"XY": 0.1})
>>> MultiQubitPauliChannel(target=[0,1,2], probabilities={"XYZ": 0.1})
"""
[docs] class Type(str, Enum):
multi_qubit_pauli_channel = "multi_qubit_pauli_channel"
type = Type.multi_qubit_pauli_channel
[docs]class Depolarizing(SingleTarget, SingleProbability_34):
"""
Depolarizing noise channel.
Attributes:
type (str): The instruction type. default = "depolarizing". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> Depolarizing(target=1, probability=0.1)
"""
[docs] class Type(str, Enum):
depolarizing = "depolarizing"
type = Type.depolarizing
[docs]class TwoQubitDepolarizing(DoubleTarget, SingleProbability_1516):
"""
Two-Qubit Depolarizing noise channel.
Attributes:
type (str): The instruction type. default = "two_qubit_depolarizing".
(type) is optional. This should be unique among all instruction types.
target (int): The target qubits. This is an int >= 0.
Examples:
>>> TwoQubitDepolarizing(target1=0, target2=1, probability=0.1)
"""
[docs] class Type(str, Enum):
two_qubit_depolarizing = "two_qubit_depolarizing"
type = Type.two_qubit_depolarizing
[docs]class TwoQubitDephasing(DoubleTarget, SingleProbability_34):
"""
Two-Qubit Dephasing noise channel.
Attributes:
type (str): The instruction type. default = "two_qubit_dephasing".
(type) is optional. This should be unique among all instruction types.
target (int): The target qubits. This is an int >= 0.
Examples:
>>> TwoQubitDephasing(target1=0, target2=1, probability=0.1)
"""
[docs] class Type(str, Enum):
two_qubit_dephasing = "two_qubit_dephasing"
type = Type.two_qubit_dephasing
[docs]class AmplitudeDamping(SingleTarget, DampingProbability):
"""
Amplitude Damping noise channel.
Attributes:
type (str): The instruction type. default = "amplitude_damping". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> AmplitudeDamping(target=1, gamma=0.1)
"""
[docs] class Type(str, Enum):
amplitude_damping = "amplitude_damping"
type = Type.amplitude_damping
[docs]class GeneralizedAmplitudeDamping(SingleTarget, DampingProbability, DampingSingleProbability):
"""
Generalized Amplitude Damping noise channel.
Attributes:
type (str): The instruction type. default = "generalized_amplitude_damping". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> GeneralizedAmplitudeDamping(target=1, gamma=0.1, probability=0.9)
"""
[docs] class Type(str, Enum):
generalized_amplitude_damping = "generalized_amplitude_damping"
type = Type.generalized_amplitude_damping
[docs]class PhaseDamping(SingleTarget, DampingProbability):
"""
Phase Damping noise channel.
Attributes:
type (str): The instruction type. default = "phase_damping". (type) is
optional. This should be unique among all instruction types.
target (int): The target qubit. This is an int >= 0.
Examples:
>>> PhaseDamping(target=1, gamma=0.1)
"""
[docs] class Type(str, Enum):
phase_damping = "phase_damping"
type = Type.phase_damping
[docs]class Kraus(TwoDimensionalMatrixList, MultiTarget):
"""
Arbitrary quantum channel defined by the input matrices.
Attributes:
type (str): The instruction type. default = "kraus". (type) is optional.
This should be unique among all instruction types.
targets (List[int]): The target qubits. This is a list with ints and all ints >= 0.
matrices (List[List[List[List[float]]]]): A list of matrices specifying
the quantum channel. A complex number is represented as a list of 2
real numbers. So each matrix has type List[List[List[float]]].
Examples:
>>> matrix1 = [[[1/sqrt(2), 0],[0, 0]],[[0, 0],[1/sqrt(2), 0]]]
>>> matrix2 = [[[0, 0],[1/sqrt(2), 0]],[[1/sqrt(2), 0],[0, 0]]]
>>> matrices = [matrix1, matrix2]
>>> Kraus(targets=[0], matrices=matrices)
"""
[docs] class Type(str, Enum):
kraus = "kraus"
type = Type.kraus
[docs]class StartVerbatimBox(CompilerDirective):
"""
StartVerbatimBox is a compiler instruction to start a portion of code that
will preserve the instruction within StartVerbatimBox and EndVerbatimBox
from being modified in any way by the compiler.
Attributes:
type (str): The instruction type. default = "start_verbatim_box". (type) is optional.
This should be unique among all instruction types.
Examples:
>>> StartVerbatimBox()
"""
[docs] class Type(str, Enum):
start_verbatim_box = "start_verbatim_box"
type = Type.start_verbatim_box
directive: str = "StartVerbatimBox"
[docs]class EndVerbatimBox(CompilerDirective):
"""
EndVerbatimBox is a compiler instruction to mark the end of a portion of code
that preserves the instruction within StartVerbatimBox and EndVerbatimBox
from being modified in any way by the compiler.
Attributes:
type (str): The instruction type. default = "end_verbatim_box". (type) is optional.
This should be unique among all instruction types.
Examples:
>>> EndVerbatimBox()
"""
[docs] class Type(str, Enum):
end_verbatim_box = "end_verbatim_box"
type = Type.end_verbatim_box
directive: str = "EndVerbatimBox"