From f1a549a678a057c5c1341d5099a7e7cdac7db333 Mon Sep 17 00:00:00 2001 From: Milan <30416311+krneta@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:00:39 -0800 Subject: [PATCH 01/11] update: default no longer returning RETIRED devices from get_devices (#796) --- src/braket/aws/aws_device.py | 12 +++++++----- src/braket/aws/aws_session.py | 12 ++++++++---- test/integ_tests/test_device_creation.py | 2 +- .../unit_tests/braket/aws/test_aws_session.py | 19 +++++++++++++++++++ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/braket/aws/aws_device.py b/src/braket/aws/aws_device.py index c9a208411..0cff446db 100644 --- a/src/braket/aws/aws_device.py +++ b/src/braket/aws/aws_device.py @@ -564,13 +564,15 @@ def get_devices( >>> AwsDevice.get_devices(types=['SIMULATOR']) Args: - arns (Optional[list[str]]): device ARN list, default is `None` - names (Optional[list[str]]): device name list, default is `None` - types (Optional[list[AwsDeviceType]]): device type list, default is `None` + arns (Optional[list[str]]): device ARN filter, default is `None` + names (Optional[list[str]]): device name filter, default is `None` + types (Optional[list[AwsDeviceType]]): device type filter, default is `None` QPUs will be searched for all regions and simulators will only be searched for the region of the current session. - statuses (Optional[list[str]]): device status list, default is `None` - provider_names (Optional[list[str]]): provider name list, default is `None` + statuses (Optional[list[str]]): device status filter, default is `None`. When `None` + is used, RETIRED devices will not be returned. To include RETIRED devices in + the results, use a filter that includes "RETIRED" for this parameter. + provider_names (Optional[list[str]]): provider name filter, default is `None` order_by (str): field to order result by, default is `name`. Accepted values are ['arn', 'name', 'type', 'provider_name', 'status'] aws_session (Optional[AwsSession]): An AWS session object. diff --git a/src/braket/aws/aws_session.py b/src/braket/aws/aws_session.py index 9523f0573..2ebc3c8d2 100644 --- a/src/braket/aws/aws_session.py +++ b/src/braket/aws/aws_session.py @@ -622,10 +622,12 @@ def search_devices( all the filters `arns`, `names`, `types`, `statuses`, `provider_names`. Args: - arns (Optional[list[str]]): device ARN list, default is `None`. - names (Optional[list[str]]): device name list, default is `None`. - types (Optional[list[str]]): device type list, default is `None`. - statuses (Optional[list[str]]): device status list, default is `None`. + arns (Optional[list[str]]): device ARN filter, default is `None`. + names (Optional[list[str]]): device name filter, default is `None`. + types (Optional[list[str]]): device type filter, default is `None`. + statuses (Optional[list[str]]): device status filter, default is `None`. When `None` + is used, RETIRED devices will not be returned. To include RETIRED devices in + the results, use a filter that includes "RETIRED" for this parameter. provider_names (Optional[list[str]]): provider name list, default is `None`. Returns: @@ -645,6 +647,8 @@ def search_devices( continue if statuses and result["deviceStatus"] not in statuses: continue + if statuses is None and result["deviceStatus"] == "RETIRED": + continue if provider_names and result["providerName"] not in provider_names: continue results.append(result) diff --git a/test/integ_tests/test_device_creation.py b/test/integ_tests/test_device_creation.py index decd7d876..4cb7de2b1 100644 --- a/test/integ_tests/test_device_creation.py +++ b/test/integ_tests/test_device_creation.py @@ -18,7 +18,7 @@ from braket.aws import AwsDevice from braket.devices import Devices -RIGETTI_ARN = "arn:aws:braket:::device/qpu/rigetti/Aspen-10" +RIGETTI_ARN = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" IONQ_ARN = "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" SIMULATOR_ARN = "arn:aws:braket:::device/quantum-simulator/amazon/sv1" OQC_ARN = "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" diff --git a/test/unit_tests/braket/aws/test_aws_session.py b/test/unit_tests/braket/aws/test_aws_session.py index d2ee45a3a..c61d22606 100644 --- a/test/unit_tests/braket/aws/test_aws_session.py +++ b/test/unit_tests/braket/aws/test_aws_session.py @@ -673,6 +673,18 @@ def test_cancel_job_surfaces_errors(exception_type, aws_session): }, ], ), + ( + {"statuses": ["RETIRED"]}, + [ + { + "deviceArn": "arn4", + "deviceName": "name4", + "deviceType": "QPU", + "deviceStatus": "RETIRED", + "providerName": "pname3", + }, + ], + ), ( {"provider_names": ["pname2"]}, [ @@ -745,6 +757,13 @@ def test_search_devices(input, output, aws_session): "deviceStatus": "ONLINE", "providerName": "pname2", }, + { + "deviceArn": "arn4", + "deviceName": "name4", + "deviceType": "QPU", + "deviceStatus": "RETIRED", + "providerName": "pname3", + }, ] } ] From 0485562077c83eec9c2780f78c8ec44995d6d684 Mon Sep 17 00:00:00 2001 From: ykharkov <112575584+ykharkov@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:02:29 -0500 Subject: [PATCH 02/11] doc: Add matrix expressions to docstrings (#756) * Add matrix expressions to docstrings * linter * fix r-strings * Capitalize H gate * Rename theta->phi * Address comments * Update src/braket/circuits/gates.py Co-authored-by: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> * add matrices to subrountines * Remove [Registers this function into the circuit class] line from docstrings --------- Co-authored-by: Abe Coull <85974725+math411@users.noreply.github.com> Co-authored-by: Cody Wang Co-authored-by: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Co-authored-by: Abe Coull Co-authored-by: Aaron Berdy --- src/braket/circuits/gates.py | 719 +++++++++++++++++++++++++++++++---- 1 file changed, 639 insertions(+), 80 deletions(-) diff --git a/src/braket/circuits/gates.py b/src/braket/circuits/gates.py index dbc2e1a0b..9a4214c37 100644 --- a/src/braket/circuits/gates.py +++ b/src/braket/circuits/gates.py @@ -60,7 +60,14 @@ class H(Gate): - """Hadamard gate.""" + r"""Hadamard gate. + + Unitary matrix: + + .. math:: \mathtt{H} = \frac{1}{\sqrt{2}} \begin{bmatrix} + 1 & 1 \\ + 1 & -1 \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["H"]) @@ -91,7 +98,13 @@ def h( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Hadamard gate. + + Unitary matrix: + + .. math:: \mathtt{H} = \frac{1}{\sqrt{2}} \begin{bmatrix} + 1 & 1 \\ + 1 & -1 \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -125,7 +138,14 @@ def h( class I(Gate): # noqa: E742, E261 - """Identity gate.""" + r"""Identity gate. + + Unitary matrix: + + .. math:: \mathtt{I} = \begin{bmatrix} + 1 & 0 \\ + 0 & 1 \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["I"]) @@ -156,7 +176,13 @@ def i( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Identity gate. + + Unitary matrix: + + .. math:: \mathtt{I} = \begin{bmatrix} + 1 & 0 \\ + 0 & 1 \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -190,7 +216,15 @@ def i( class X(Gate): - """Pauli-X gate.""" + r"""Pauli-X gate. + + Unitary matrix: + + .. math:: \mathtt{X} = \begin{bmatrix} + 0 & 1 \\ + 1 & 0 + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["X"]) @@ -221,7 +255,14 @@ def x( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Pauli-X gate. + + Unitary matrix: + + .. math:: \mathtt{X} = \begin{bmatrix} + 0 & 1 \\ + 1 & 0 + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -255,7 +296,15 @@ def x( class Y(Gate): - """Pauli-Y gate.""" + r"""Pauli-Y gate. + + Unitary matrix: + + .. math:: \mathtt{Y} = \begin{bmatrix} + 0 & -i \\ + i & 0 + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["Y"]) @@ -286,7 +335,14 @@ def y( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Pauli-Y gate. + + Unitary matrix: + + .. math:: \mathtt{Y} = \begin{bmatrix} + 0 & -i \\ + i & 0 + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -320,7 +376,15 @@ def y( class Z(Gate): - """Pauli-Z gate.""" + r"""Pauli-Z gate. + + Unitary matrix: + + .. math:: \mathtt{Z} = \begin{bmatrix} + 1 & 0 \\ + 0 & -1 + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["Z"]) @@ -351,7 +415,12 @@ def z( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Pauli-Z gate. + + .. math:: \mathtt{Z} = \begin{bmatrix} + 1 & 0 \\ + 0 & -1 + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -385,7 +454,15 @@ def z( class S(Gate): - """S gate.""" + r"""S gate. + + Unitary matrix: + + .. math:: \mathtt{S} = \begin{bmatrix} + 1 & 0 \\ + 0 & i + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["S"]) @@ -416,7 +493,12 @@ def s( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""S gate. + + .. math:: \mathtt{S} = \begin{bmatrix} + 1 & 0 \\ + 0 & i + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -450,7 +532,15 @@ def s( class Si(Gate): - """Conjugate transpose of S gate.""" + r"""Conjugate transpose of S gate. + + Unitary matrix: + + .. math:: \mathtt{S}^\dagger = \begin{bmatrix} + 1 & 0 \\ + 0 & -i + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["Si"]) @@ -481,7 +571,12 @@ def si( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Conjugate transpose of S gate. + + .. math:: \mathtt{S}^\dagger = \begin{bmatrix} + 1 & 0 \\ + 0 & -i + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -515,7 +610,15 @@ def si( class T(Gate): - """T gate.""" + r"""T gate. + + Unitary matrix: + + .. math:: \mathtt{T} = \begin{bmatrix} + 1 & 0 \\ + 0 & e^{i \pi/4} + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["T"]) @@ -546,7 +649,12 @@ def t( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""T gate. + + .. math:: \mathtt{T} = \begin{bmatrix} + 1 & 0 \\ + 0 & e^{i \pi/4} + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -580,7 +688,15 @@ def t( class Ti(Gate): - """Conjugate transpose of T gate.""" + r"""Conjugate transpose of T gate. + + Unitary matrix: + + .. math:: \mathtt{T}^\dagger = \begin{bmatrix} + 1 & 0 \\ + 0 & e^{-i \pi/4} + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["Ti"]) @@ -611,7 +727,12 @@ def ti( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Conjugate transpose of T gate. + + .. math:: \mathtt{T}^\dagger = \begin{bmatrix} + 1 & 0 \\ + 0 & e^{-i \pi/4} + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -645,7 +766,15 @@ def ti( class V(Gate): - """Square root of not gate.""" + r"""Square root of X gate (V gate). + + Unitary matrix: + + .. math:: \mathtt{V} = \frac{1}{2}\begin{bmatrix} + 1+i & 1-i \\ + 1-i & 1+i + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["V"]) @@ -676,7 +805,12 @@ def v( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Square root of X gate (V gate). + + .. math:: \mathtt{V} = \frac{1}{2}\begin{bmatrix} + 1+i & 1-i \\ + 1-i & 1+i + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -710,7 +844,15 @@ def v( class Vi(Gate): - """Conjugate transpose of square root of not gate.""" + r"""Conjugate transpose of square root of X gate (conjugate transpose of V). + + Unitary matrix: + + .. math:: \mathtt{V}^\dagger = \frac{1}{2}\begin{bmatrix} + 1-i & 1+i \\ + 1+i & 1-i + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["Vi"]) @@ -741,7 +883,12 @@ def vi( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Conjugate transpose of square root of X gate (conjugate transpose of V). + + .. math:: \mathtt{V}^\dagger = \frac{1}{2}\begin{bmatrix} + 1-i & 1+i \\ + 1+i & 1-i + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s) @@ -778,7 +925,14 @@ def vi( class Rx(AngledGate): - """X-axis rotation gate. + r"""X-axis rotation gate. + + Unitary matrix: + + .. math:: \mathtt{R_x}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & -i \sin{(\phi/2)} \\ + -i \sin{(\phi/2)} & \cos{(\phi/2)} + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -799,7 +953,7 @@ def _to_jaqcd(self, target: QubitSet, **kwargs) -> Any: return ir.Rx.construct(target=target[0], angle=self.angle) def to_matrix(self) -> np.ndarray: - """Returns a matrix representation of this gate. + r"""Returns a matrix representation of this gate. Returns: ndarray: The matrix representation of this gate. """ @@ -824,7 +978,12 @@ def rx( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""X-axis rotation gate. + + .. math:: \mathtt{R_x}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & -i \sin{(\phi/2)} \\ + -i \sin{(\phi/2)} & \cos{(\phi/2)} + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s). @@ -858,7 +1017,14 @@ def rx( class Ry(AngledGate): - """Y-axis rotation gate. + r"""Y-axis rotation gate. + + Unitary matrix: + + .. math:: \mathtt{R_y}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & -\sin{(\phi/2)} \\ + \sin{(\phi/2)} & \cos{(\phi/2)} + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -879,7 +1045,7 @@ def _to_jaqcd(self, target: QubitSet) -> Any: return ir.Ry.construct(target=target[0], angle=self.angle) def to_matrix(self) -> np.ndarray: - """Returns a matrix representation of this gate. + r"""Returns a matrix representation of this gate. Returns: ndarray: The matrix representation of this gate. """ @@ -904,7 +1070,12 @@ def ry( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Y-axis rotation gate. + + .. math:: \mathtt{R_y}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & -\sin{(\phi/2)} \\ + \sin{(\phi/2)} & \cos{(\phi/2)} + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s). @@ -923,6 +1094,7 @@ def ry( Returns: Iterable[Instruction]: Rx instruction. + Examples: >>> circ = Circuit().ry(0, 0.15) """ @@ -938,7 +1110,14 @@ def ry( class Rz(AngledGate): - """Z-axis rotation gate. + r"""Z-axis rotation gate. + + Unitary matrix: + + .. math:: \mathtt{R_z}(\phi) = \begin{bmatrix} + e^{-i \phi/2} & 0 \\ + 0 & e^{i \phi/2} + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -980,7 +1159,12 @@ def rz( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Z-axis rotation gate. + + .. math:: \mathtt{R_z}(\phi) = \begin{bmatrix} + e^{-i \phi/2} & 0 \\ + 0 & e^{i \phi/2} + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s). @@ -1014,7 +1198,14 @@ def rz( class PhaseShift(AngledGate): - """Phase shift gate. + r"""Phase shift gate. + + Unitary matrix: + + .. math:: \mathtt{PhaseShift}(\phi) = \begin{bmatrix} + 1 & 0 \\ + 0 & e^{i \phi} + \end{bmatrix} Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -1054,7 +1245,12 @@ def phaseshift( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""Phase shift gate. + + .. math:: \mathtt{PhaseShift}(\phi) = \begin{bmatrix} + 1 & 0 \\ + 0 & e^{i \phi} + \end{bmatrix} Args: target (QubitSetInput): Target qubit(s). @@ -1095,7 +1291,17 @@ def phaseshift( class CNot(Gate): - """Controlled NOT gate.""" + r"""Controlled NOT gate. + + Unitary matrix: + + .. math:: \mathtt{CNOT} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 \\ + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["C", "X"]) @@ -1128,7 +1334,14 @@ def fixed_qubit_count() -> int: @staticmethod @circuit.subroutine(register=True) def cnot(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled NOT gate. + + .. math:: \mathtt{CNOT} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 \\ + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1155,7 +1368,17 @@ def cnot(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instru class Swap(Gate): - """Swap gate.""" + r"""Swap gate. + + Unitary matrix: + + .. math:: \mathtt{SWAP} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["SWAP", "SWAP"]) @@ -1195,7 +1418,14 @@ def swap( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Swap gate. + + .. math:: \mathtt{SWAP} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -1230,7 +1460,17 @@ def swap( class ISwap(Gate): - """ISwap gate.""" + r"""ISwap gate. + + Unitary matrix: + + .. math:: \mathtt{iSWAP} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & i & 0 \\ + 0 & i & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["ISWAP", "ISWAP"]) @@ -1270,7 +1510,14 @@ def iswap( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""ISwap gate. + + .. math:: \mathtt{iSWAP} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & i & 0 \\ + 0 & i & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -1305,7 +1552,16 @@ def iswap( class PSwap(AngledGate): - """PSwap gate. + r"""PSwap gate. + + Unitary matrix: + + .. math:: \mathtt{PSWAP}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & e^{i \phi} & 0 \\ + 0 & e^{i \phi} & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -1357,7 +1613,14 @@ def pswap( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""PSwap gate. + + .. math:: \mathtt{PSWAP}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 0 & e^{i \phi} & 0 \\ + 0 & e^{i \phi} & 0 & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -1393,10 +1656,20 @@ def pswap( class XY(AngledGate): - """XY gate. + r"""XY gate. + + Unitary matrix: + + .. math:: \mathtt{XY}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & \cos{(\phi/2)} & i\sin{(\phi/2)} & 0 \\ + 0 & i\sin{(\phi/2)} & \cos{(\phi/2)} & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Reference: https://arxiv.org/abs/1912.04424v1 + Args: angle (Union[FreeParameterExpression, float]): angle in radians. """ @@ -1419,7 +1692,7 @@ def _to_jaqcd(self, target: QubitSet) -> Any: return ir.XY.construct(targets=[target[0], target[1]], angle=self.angle) def to_matrix(self) -> np.ndarray: - """Returns a matrix representation of this gate. + r"""Returns a matrix representation of this gate. Returns: ndarray: The matrix representation of this gate. """ @@ -1453,7 +1726,14 @@ def xy( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""XY gate. + + .. math:: \mathtt{XY}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & \cos{(\phi/2)} & i\sin{(\phi/2)} & 0 \\ + 0 & i\sin{(\phi/2)} & \cos{(\phi/2)} & 0 \\ + 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -1489,7 +1769,16 @@ def xy( class CPhaseShift(AngledGate): - """Controlled phase shift gate. + r"""Controlled phase shift gate. + + Unitary matrix: + + .. math:: \mathtt{CPhaseShift}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & e^{i \phi} + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -1527,7 +1816,14 @@ def cphaseshift( angle: Union[FreeParameterExpression, float], power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled phase shift gate. + + .. math:: \mathtt{CPhaseShift}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & e^{i \phi} + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1558,7 +1854,16 @@ def cphaseshift( class CPhaseShift00(AngledGate): - """Controlled phase shift gate for phasing the \\|00> state. + r"""Controlled phase shift gate for phasing the \|00> state. + + Unitary matrix: + + .. math:: \mathtt{CPhaseShift00}(\phi) = \begin{bmatrix} + e^{i \phi} & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -1596,7 +1901,14 @@ def cphaseshift00( angle: Union[FreeParameterExpression, float], power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled phase shift gate for phasing the \|00> state. + + .. math:: \mathtt{CPhaseShift00}(\phi) = \begin{bmatrix} + e^{i \phi} & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1627,7 +1939,16 @@ def cphaseshift00( class CPhaseShift01(AngledGate): - """Controlled phase shift gate for phasing the \\|01> state. + r"""Controlled phase shift gate for phasing the \|01> state. + + Unitary matrix: + + .. math:: \mathtt{CPhaseShift01}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & e^{i \phi} & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -1665,7 +1986,14 @@ def cphaseshift01( angle: Union[FreeParameterExpression, float], power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled phase shift gate for phasing the \|01> state. + + .. math:: \mathtt{CPhaseShift01}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & e^{i \phi} & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1696,7 +2024,16 @@ def cphaseshift01( class CPhaseShift10(AngledGate): - """Controlled phase shift gate for phasing the \\|10> state. + r"""Controlled phase shift gate for phasing the \\|10> state. + + Unitary matrix: + + .. math:: \mathtt{CPhaseShift10}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & e^{i \phi} & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -1734,7 +2071,14 @@ def cphaseshift10( angle: Union[FreeParameterExpression, float], power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled phase shift gate for phasing the \\|10> state. + + .. math:: \mathtt{CPhaseShift10}(\phi) = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & e^{i \phi} & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1765,7 +2109,17 @@ def cphaseshift10( class CV(Gate): - """Controlled Sqrt of NOT gate.""" + r"""Controlled Sqrt of X gate. + + Unitary matrix: + + .. math:: \mathtt{CV} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0.5+0.5i & 0.5-0.5i \\ + 0 & 0 & 0.5-0.5i & 0.5+0.5i + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["C", "V"]) @@ -1798,7 +2152,14 @@ def fixed_qubit_count() -> int: @staticmethod @circuit.subroutine(register=True) def cv(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled Sqrt of X gate. + + .. math:: \mathtt{CV} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0.5+0.5i & 0.5-0.5i \\ + 0 & 0 & 0.5-0.5i & 0.5+0.5i + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1825,7 +2186,17 @@ def cv(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruct class CY(Gate): - """Controlled Pauli-Y gate.""" + r"""Controlled Pauli-Y gate. + + Unitary matrix: + + .. math:: \mathtt{CY} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & -i \\ + 0 & 0 & i & 0 + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["C", "Y"]) @@ -1858,7 +2229,14 @@ def fixed_qubit_count() -> int: @staticmethod @circuit.subroutine(register=True) def cy(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled Pauli-Y gate. + + .. math:: \mathtt{CY} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & -i \\ + 0 & 0 & i & 0 + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1885,7 +2263,17 @@ def cy(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruct class CZ(Gate): - """Controlled Pauli-Z gate.""" + r"""Controlled Pauli-Z gate. + + Unitary matrix: + + .. math:: \mathtt{CZ} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & -1 + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["C", "Z"]) @@ -1910,7 +2298,14 @@ def fixed_qubit_count() -> int: @staticmethod @circuit.subroutine(register=True) def cz(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled Pauli-Z gate. + + .. math:: \mathtt{CZ} = \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & -1 + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -1937,7 +2332,17 @@ def cz(control: QubitSetInput, target: QubitInput, power: float = 1) -> Instruct class ECR(Gate): - """An echoed RZX(pi/2) gate.""" + r"""An echoed RZX(pi/2) gate (ECR gate). + + Unitary matrix: + + .. math:: \mathtt{ECR} = \begin{bmatrix} + 0 & 0 & 1 & i \\ + 0 & 0 & i & 1 \\ + 1 & -i & 0 & 0 \\ + -i & 1 & 0 & 0 + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["ECR", "ECR"]) @@ -1976,7 +2381,14 @@ def ecr( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""An echoed RZX(pi/2) gate (ECR gate). + + .. math:: \mathtt{ECR} = \begin{bmatrix} + 0 & 0 & 1 & i \\ + 0 & 0 & i & 1 \\ + 1 & -i & 0 & 0 \\ + -i & 1 & 0 & 0 + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -2011,7 +2423,16 @@ def ecr( class XX(AngledGate): - """Ising XX coupling gate. + r"""Ising XX coupling gate. + + Unitary matrix: + + .. math:: \mathtt{XX}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & 0 & 0 & -i \sin{(\phi/2)} \\ + 0 & \cos{(\phi/2)} & -i \sin{(\phi/2)} & 0 \\ + 0 & -i \sin{(\phi/2)} & \cos{(\phi/2)} & 0 \\ + -i \sin{(\phi/2)} & 0 & 0 & \cos{(\phi/2)} + \end{bmatrix}. Reference: https://arxiv.org/abs/1707.06356 @@ -2037,7 +2458,7 @@ def _to_jaqcd(self, target: QubitSet) -> Any: return ir.XX.construct(targets=[target[0], target[1]], angle=self.angle) def to_matrix(self) -> np.ndarray: - """Returns a matrix representation of this gate. + r"""Returns a matrix representation of this gate. Returns: ndarray: The matrix representation of this gate. """ @@ -2071,7 +2492,14 @@ def xx( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Ising XX coupling gate. + + .. math:: \mathtt{XX}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & 0 & 0 & -i \sin{(\phi/2)} \\ + 0 & \cos{(\phi/2)} & -i \sin{(\phi/2)} & 0 \\ + 0 & -i \sin{(\phi/2)} & \cos{(\phi/2)} & 0 \\ + -i \sin{(\phi/2)} & 0 & 0 & \cos{(\phi/2)} + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -2107,7 +2535,16 @@ def xx( class YY(AngledGate): - """Ising YY coupling gate. + r"""Ising YY coupling gate. + + Unitary matrix: + + .. math:: \mathtt{YY}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & 0 & 0 & i \sin{(\phi/2)} \\ + 0 & \cos{(\phi/2)} & -i \sin{(\phi/2)} & 0 \\ + 0 & -i \sin{(\phi/2)} & \cos{(\phi/2)} & 0 \\ + i \sin{(\phi/2)} & 0 & 0 & \cos{(\phi/2)} + \end{bmatrix}. Reference: https://arxiv.org/abs/1707.06356 @@ -2133,7 +2570,7 @@ def _to_jaqcd(self, target: QubitSet) -> Any: return ir.YY.construct(targets=[target[0], target[1]], angle=self.angle) def to_matrix(self) -> np.ndarray: - """Returns a matrix representation of this gate. + r"""Returns a matrix representation of this gate. Returns: ndarray: The matrix representation of this gate. """ @@ -2167,7 +2604,14 @@ def yy( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Ising YY coupling gate. + + .. math:: \mathtt{YY}(\phi) = \begin{bmatrix} + \cos{(\phi/2)} & 0 & 0 & i \sin{(\phi/2)} \\ + 0 & \cos{(\phi/2)} & -i \sin{(\phi/2)} & 0 \\ + 0 & -i \sin{(\phi/2)} & \cos{(\phi/2)} & 0 \\ + i \sin{(\phi/2)} & 0 & 0 & \cos{(\phi/2)} + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -2203,7 +2647,16 @@ def yy( class ZZ(AngledGate): - """Ising ZZ coupling gate. + r"""Ising ZZ coupling gate. + + Unitary matrix: + + .. math:: \mathtt{ZZ}(\phi) = \begin{bmatrix} + e^{-i\phi/2} & 0 & 0 & 0 \\ + 0 & e^{i\phi/2} & 0 & 0 \\ + 0 & 0 & e^{i\phi/2} & 0 \\ + 0 & 0 & 0 & e^{-i\phi/2} + \end{bmatrix}. Reference: https://arxiv.org/abs/1707.06356 @@ -2257,7 +2710,14 @@ def zz( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Ising ZZ coupling gate. + + .. math:: \mathtt{ZZ}(\phi) = \begin{bmatrix} + e^{-i\phi/2} & 0 & 0 & 0 \\ + 0 & e^{i\phi/2} & 0 & 0 \\ + 0 & 0 & e^{i\phi/2} & 0 \\ + 0 & 0 & 0 & e^{-i\phi/2} + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -2296,7 +2756,21 @@ def zz( class CCNot(Gate): - """CCNOT gate or Toffoli gate.""" + r"""CCNOT gate or Toffoli gate. + + Unitary matrix: + + .. math:: \mathtt{CCNOT} = \begin{bmatrix} + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["C", "C", "X"]) @@ -2341,7 +2815,18 @@ def ccnot( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""CCNOT gate or Toffoli gate. + + .. math:: \mathtt{CCNOT} = \begin{bmatrix} + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ + \end{bmatrix}. Args: control1 (QubitInput): Control qubit 1 index. @@ -2379,7 +2864,21 @@ def ccnot( class CSwap(Gate): - """Controlled Swap gate.""" + r"""Controlled Swap gate. + + Unitary matrix: + + .. math:: \mathtt{CSWAP} = \begin{bmatrix} + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ + \end{bmatrix}. + """ def __init__(self): super().__init__(qubit_count=None, ascii_symbols=["C", "SWAP", "SWAP"]) @@ -2421,7 +2920,18 @@ def cswap( target2: QubitInput, power: float = 1, ) -> Instruction: - """Registers this function into the circuit class. + r"""Controlled Swap gate. + + .. math:: \mathtt{CSWAP} = \begin{bmatrix} + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ + \end{bmatrix}. Args: control (QubitSetInput): Control qubit(s). The last control qubit @@ -2452,7 +2962,14 @@ def cswap( class GPi(AngledGate): - """IonQ GPi gate. + r"""IonQ GPi gate. + + Unitary matrix: + + .. math:: \mathtt{GPi}(\phi) = \begin{bmatrix} + 0 & e^{-i \phi} \\ + e^{i \phi} & 0 + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -2497,7 +3014,12 @@ def gpi( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""IonQ GPi gate. + + .. math:: \mathtt{GPi}(\phi) = \begin{bmatrix} + 0 & e^{-i \phi} \\ + e^{i \phi} & 0 + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s). @@ -2531,7 +3053,14 @@ def gpi( class GPi2(AngledGate): - """IonQ GPi2 gate. + r"""IonQ GPi2 gate. + + Unitary matrix: + + .. math:: \mathtt{GPi2}(\phi) = \begin{bmatrix} + 1 & -i e^{-i \phi} \\ + -i e^{i \phi} & 1 + \end{bmatrix}. Args: angle (Union[FreeParameterExpression, float]): angle in radians. @@ -2576,7 +3105,12 @@ def gpi2( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""IonQ GPi2 gate. + + .. math:: \mathtt{GPi2}(\phi) = \begin{bmatrix} + 1 & -i e^{-i \phi} \\ + -i e^{i \phi} & 1 + \end{bmatrix}. Args: target (QubitSetInput): Target qubit(s). @@ -2610,12 +3144,26 @@ def gpi2( class MS(TripleAngledGate): - """IonQ Mølmer-Sørenson gate. + r"""IonQ Mølmer-Sørensen gate. + + Unitary matrix: + + .. math:: &\mathtt{MS}(\phi_0, \phi_1, \theta) =\\ &\begin{bmatrix} + \cos{\frac{\theta}{2}} & 0 & + 0 & -ie^{-i (\phi_0 + \phi_1)}\sin{\frac{\theta}{2}} \\ + 0 & \cos{\frac{\theta}{2}} & + -ie^{-i (\phi_0 - \phi_1)}\sin{\frac{\theta}{2}} & 0 \\ + 0 & -ie^{i (\phi_0 - \phi_1)}\sin{\frac{\theta}{2}} & + \cos{\frac{\theta}{2}} & 0 \\ + -ie^{i (\phi_0 + \phi_1)}\sin{\frac{\theta}{2}} & 0 + & 0 & \cos{\frac{\theta}{2}} + \end{bmatrix}. Args: angle_1 (Union[FreeParameterExpression, float]): angle in radians. angle_2 (Union[FreeParameterExpression, float]): angle in radians. angle_3 (Union[FreeParameterExpression, float]): angle in radians. + Default value is angle_3=pi/2. """ def __init__( @@ -2689,7 +3237,18 @@ def ms( control_state: Optional[BasisStateInput] = None, power: float = 1, ) -> Iterable[Instruction]: - """Registers this function into the circuit class. + r"""IonQ Mølmer-Sørensen gate. + + .. math:: &\mathtt{MS}(\phi_0, \phi_1, \theta) =\\ &\begin{bmatrix} + \cos{\frac{\theta}{2}} & 0 & + 0 & -ie^{-i (\phi_0 + \phi_1)}\sin{\frac{\theta}{2}} \\ + 0 & \cos{\frac{\theta}{2}} & + -ie^{-i (\phi_0 - \phi_1)}\sin{\frac{\theta}{2}} & 0 \\ + 0 & -ie^{i (\phi_0 - \phi_1)}\sin{\frac{\theta}{2}} & + \cos{\frac{\theta}{2}} & 0 \\ + -ie^{i (\phi_0 + \phi_1)}\sin{\frac{\theta}{2}} & 0 + & 0 & \cos{\frac{\theta}{2}} + \end{bmatrix}. Args: target1 (QubitInput): Target qubit 1 index. @@ -2729,7 +3288,7 @@ def ms( class Unitary(Gate): - """Arbitrary unitary gate + """Arbitrary unitary gate. Args: matrix (numpy.ndarray): Unitary matrix which defines the gate. @@ -2792,7 +3351,7 @@ def _transform_matrix_to_ir(matrix: np.ndarray) -> list: @staticmethod @circuit.subroutine(register=True) def unitary(targets: QubitSet, matrix: np.ndarray, display_name: str = "U") -> Instruction: - """Registers this function into the circuit class. + r"""Arbitrary unitary gate. Args: targets (QubitSet): Target qubits. @@ -2849,7 +3408,7 @@ def pulse_sequence(self) -> PulseSequence: @property def parameters(self) -> list[FreeParameter]: - """Returns the list of `FreeParameter` s associated with the gate.""" + r"""Returns the list of `FreeParameter` s associated with the gate.""" return list(self._pulse_sequence.parameters) def bind_values(self, **kwargs) -> PulseGate: From 20ac4e468e03cbb24ea43b619804e0fa9734b2dc Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 16 Nov 2023 19:46:06 -0500 Subject: [PATCH 03/11] Fix broken link to example notebook (#802) --- doc/examples-hybrid-jobs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples-hybrid-jobs.rst b/doc/examples-hybrid-jobs.rst index af873407c..56a1d9ecf 100644 --- a/doc/examples-hybrid-jobs.rst +++ b/doc/examples-hybrid-jobs.rst @@ -8,7 +8,7 @@ Learn more about hybrid jobs on Amazon Braket. :maxdepth: 2 ************************************************************************************************************************************************************************************************ -`Creating your first Hybrid Job `_ +`Creating your first Hybrid Job `_ ************************************************************************************************************************************************************************************************ This tutorial shows how to run your first Amazon Braket Hybrid Job. From 176c6a79393373c853de25d83665f2f7bd451f38 Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 17 Nov 2023 04:07:56 +0000 Subject: [PATCH 04/11] prepare release v1.62.1 --- CHANGELOG.md | 11 +++++++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19b0fba87..876595e2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v1.62.1 (2023-11-17) + +### Bug Fixes and Other Changes + + * Fix broken link to example notebook + * update: default no longer returning RETIRED devices from get_devices + +### Documentation Changes + + * Add matrix expressions to docstrings + ## v1.62.0 (2023-11-09) ### Features diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 8cc1a9a43..26e9bb0a8 100644 --- a/src/braket/_sdk/_version.py +++ b/src/braket/_sdk/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.62.1.dev0" +__version__ = "1.62.1" From 44a2bbb39d0142e74a4e39c3bf5aca0cf2785cfe Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 17 Nov 2023 04:07:56 +0000 Subject: [PATCH 05/11] update development version to v1.62.2.dev0 --- src/braket/_sdk/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 26e9bb0a8..c0e18d0a0 100644 --- a/src/braket/_sdk/_version.py +++ b/src/braket/_sdk/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.62.1" +__version__ = "1.62.2.dev0" From 5d8e38c3807d41631450af494b0d65db2b745f2f Mon Sep 17 00:00:00 2001 From: Aaron Berdy Date: Mon, 20 Nov 2023 10:52:30 -0800 Subject: [PATCH 06/11] infra: code freeze workflow (#767) Co-authored-by: Abe Coull <85974725+math411@users.noreply.github.com> --- .github/workflows/code-freeze.yml | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/code-freeze.yml diff --git a/.github/workflows/code-freeze.yml b/.github/workflows/code-freeze.yml new file mode 100644 index 000000000..5aff0abc7 --- /dev/null +++ b/.github/workflows/code-freeze.yml @@ -0,0 +1,39 @@ +name: Code Freeze + +on: + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +env: + FROZEN: ${{ vars.FROZEN }} + UNFROZEN_PREFIX: ${{ vars.UNFROZEN_PREFIX }} + +jobs: + check-pr-frozen-status: + runs-on: ubuntu-latest + steps: + - name: Fetch PR data and check if merge allowed + if: env.FROZEN == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_DATA=$(curl -s \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}) + BRANCH_NAME=$(echo $PR_DATA | jq .head.ref -r) + PR_TITLE=$(echo $PR_DATA | jq .title -r) + + echo $BRANCH_NAME + echo $PR_TITLE + + if [[ "$BRANCH_NAME" != $UNFROZEN_PREFIX* ]] && + [[ "$PR_TITLE" != fix:* && "$PR_TITLE" != *"[critical]"* ]]; then + echo "Error: You can only merge from branches that start with '$UNFROZEN_PREFIX', or PRs titled with 'fix: ' and containing '[critical]'." + exit 1 + fi From 8e8cdaa5cd1c62befafafd6621f8700ce64369f6 Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Mon, 4 Dec 2023 16:44:08 -0800 Subject: [PATCH 07/11] Add Forte 1 device (#827) --- src/braket/devices/devices.py | 1 + test/integ_tests/test_cost_tracking.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/braket/devices/devices.py b/src/braket/devices/devices.py index 8f8730336..f4fe8ff8d 100644 --- a/src/braket/devices/devices.py +++ b/src/braket/devices/devices.py @@ -31,6 +31,7 @@ class _IonQ(str, Enum): Harmony = "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" Aria1 = "arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1" Aria2 = "arn:aws:braket:us-east-1::device/qpu/ionq/Aria-2" + Forte1 = "arn:aws:braket:us-east-1::device/qpu/ionq/Forte-1" class _OQC(str, Enum): Lucy = "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" diff --git a/test/integ_tests/test_cost_tracking.py b/test/integ_tests/test_cost_tracking.py index 60ddc1b52..7e97c6f78 100644 --- a/test/integ_tests/test_cost_tracking.py +++ b/test/integ_tests/test_cost_tracking.py @@ -20,9 +20,12 @@ from braket.aws import AwsDevice, AwsSession from braket.circuits import Circuit +from braket.devices import Devices from braket.tracking import Tracker from braket.tracking.tracker import MIN_SIMULATOR_DURATION +_RESERVATION_ONLY_DEVICES = {Devices.IonQ.Forte1} + @pytest.mark.parametrize( "qpu", @@ -91,7 +94,7 @@ def test_all_devices_price_search(): tasks = {} for region in AwsDevice.REGIONS: s = AwsSession(boto3.Session(region_name=region)) - for device in devices: + for device in [device for device in devices if device.arn not in _RESERVATION_ONLY_DEVICES]: try: s.get_device(device.arn) From 8a8ef4ed00fed48c5a173fc28060a3ee9d530de4 Mon Sep 17 00:00:00 2001 From: Angela Guo Date: Tue, 5 Dec 2023 05:41:30 -0800 Subject: [PATCH 08/11] feat: Allow reservation ARN in task and job creation (#826) --- examples/hybrid_job.py | 9 +- examples/reservation.py | 24 +++++ src/braket/aws/aws_device.py | 15 ++- src/braket/aws/aws_quantum_job.py | 6 ++ src/braket/aws/aws_quantum_task.py | 32 ++++++- src/braket/aws/aws_quantum_task_batch.py | 13 +++ src/braket/jobs/hybrid_job.py | 6 ++ src/braket/jobs/quantum_job_creation.py | 18 ++++ src/braket/tracking/tracker.py | 18 +++- src/braket/tracking/tracking_events.py | 1 + test/integ_tests/test_reservation_arn.py | 91 +++++++++++++++++++ .../braket/aws/common_test_utils.py | 10 ++ test/unit_tests/braket/aws/test_aws_device.py | 63 +++++++++++-- .../braket/aws/test_aws_quantum_job.py | 10 +- .../braket/aws/test_aws_quantum_task.py | 60 ++++++++++++ .../braket/aws/test_aws_quantum_task_batch.py | 52 ++++++++++- .../unit_tests/braket/jobs/test_hybrid_job.py | 5 + .../braket/jobs/test_quantum_job_creation.py | 20 ++++ .../braket/tracking/test_tracker.py | 31 ++++++- 19 files changed, 463 insertions(+), 21 deletions(-) create mode 100644 examples/reservation.py create mode 100644 test/integ_tests/test_reservation_arn.py diff --git a/examples/hybrid_job.py b/examples/hybrid_job.py index 2e09d6463..7f54c9955 100644 --- a/examples/hybrid_job.py +++ b/examples/hybrid_job.py @@ -18,7 +18,14 @@ from braket.jobs.metrics import log_metric -@hybrid_job(device=Devices.Amazon.SV1, wait_until_complete=True) +@hybrid_job( + device=Devices.Amazon.SV1, + wait_until_complete=True, + # If you want to run the job in a device reservation window, + # change the device to the one you've reserved, + # uncomment the following line and fill in your reservation ARN + # reservation_arn="" +) def run_hybrid_job(num_tasks=1): # declare AwsDevice within the hybrid job device = AwsDevice(get_job_device_arn()) diff --git a/examples/reservation.py b/examples/reservation.py new file mode 100644 index 000000000..682f71f50 --- /dev/null +++ b/examples/reservation.py @@ -0,0 +1,24 @@ +# 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 braket.aws import AwsDevice +from braket.circuits import Circuit +from braket.devices import Devices + +bell = Circuit().h(0).cnot(0, 1) +device = AwsDevice(Devices.IonQ.Aria1) + +# To run a task in a device reservation, change the device to the one you reserved +# and fill in your reservation ARN +task = device.run(bell, shots=100, reservation_arn="reservation ARN") +print(task.result().measurement_counts) diff --git a/src/braket/aws/aws_device.py b/src/braket/aws/aws_device.py index 0cff446db..503834dd8 100644 --- a/src/braket/aws/aws_device.py +++ b/src/braket/aws/aws_device.py @@ -121,6 +121,7 @@ def run( poll_interval_seconds: Optional[float] = None, inputs: Optional[dict[str, float]] = None, gate_definitions: Optional[dict[tuple[Gate, QubitSet], PulseSequence]] = None, + reservation_arn: str | None = None, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) -> AwsQuantumTask: @@ -150,6 +151,11 @@ def run( The calibration is defined for a particular `Gate` on a particular `QubitSet` and is represented by a `PulseSequence`. Default: None. + reservation_arn (str | None): The reservation ARN provided by Braket Direct + to reserve exclusive usage for the device to run the quantum task on. + Note: If you are creating tasks in a job that itself was created reservation ARN, + those tasks do not need to be created with the reservation ARN. + Default: None. Returns: AwsQuantumTask: An AwsQuantumTask that tracks the execution on the device. @@ -199,6 +205,7 @@ def run( poll_interval_seconds=poll_interval_seconds or self._poll_interval_seconds, inputs=inputs, gate_definitions=gate_definitions, + reservation_arn=reservation_arn, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) @@ -233,6 +240,7 @@ def run_batch( poll_interval_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, inputs: Optional[Union[dict[str, float], list[dict[str, float]]]] = None, gate_definitions: Optional[dict[tuple[Gate, QubitSet], PulseSequence]] = None, + reservation_arn: Optional[str] = None, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) -> AwsQuantumTaskBatch: @@ -263,7 +271,11 @@ def run_batch( gate_definitions (Optional[dict[tuple[Gate, QubitSet], PulseSequence]]): A `dict[tuple[Gate, QubitSet], PulseSequence]]` for a user defined gate calibration. The calibration is defined for a particular `Gate` on a particular `QubitSet` - and is represented by a `PulseSequence`. + and is represented by a `PulseSequence`. Default: None. + reservation_arn (Optional[str]): The reservation ARN provided by Braket Direct + to reserve exclusive usage for the device to run the quantum task on. + Note: If you are creating tasks in a job that itself was created reservation ARN, + those tasks do not need to be created with the reservation ARN. Default: None. Returns: @@ -290,6 +302,7 @@ def run_batch( poll_interval_seconds=poll_interval_seconds or self._poll_interval_seconds, inputs=inputs, gate_definitions=gate_definitions, + reservation_arn=reservation_arn, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) diff --git a/src/braket/aws/aws_quantum_job.py b/src/braket/aws/aws_quantum_job.py index 8ae4bc129..1e929e857 100644 --- a/src/braket/aws/aws_quantum_job.py +++ b/src/braket/aws/aws_quantum_job.py @@ -81,6 +81,7 @@ def create( aws_session: AwsSession | None = None, tags: dict[str, str] | None = None, logger: Logger = getLogger(__name__), + reservation_arn: str | None = None, ) -> AwsQuantumJob: """Creates a hybrid job by invoking the Braket CreateJob API. @@ -175,6 +176,10 @@ def create( while waiting for quantum task to be in a terminal state. Default is `getLogger(__name__)` + reservation_arn (str | None): the reservation window arn provided by Braket + Direct to reserve exclusive usage for the device to run the hybrid job on. + Default: None. + Returns: AwsQuantumJob: Hybrid job tracking the execution on Amazon Braket. @@ -201,6 +206,7 @@ def create( checkpoint_config=checkpoint_config, aws_session=aws_session, tags=tags, + reservation_arn=reservation_arn, ) job_arn = aws_session.create_job(**create_job_kwargs) diff --git a/src/braket/aws/aws_quantum_task.py b/src/braket/aws/aws_quantum_task.py index fa58d911d..c490a4190 100644 --- a/src/braket/aws/aws_quantum_task.py +++ b/src/braket/aws/aws_quantum_task.py @@ -105,6 +105,7 @@ def create( tags: dict[str, str] | None = None, inputs: dict[str, float] | None = None, gate_definitions: Optional[dict[tuple[Gate, QubitSet], PulseSequence]] | None = None, + reservation_arn: str | None = None, *args, **kwargs, ) -> AwsQuantumTask: @@ -151,6 +152,12 @@ def create( a `PulseSequence`. Default: None. + reservation_arn (str | None): The reservation ARN provided by Braket Direct + to reserve exclusive usage for the device to run the quantum task on. + Note: If you are creating tasks in a job that itself was created reservation ARN, + those tasks do not need to be created with the reservation ARN. + Default: None. + Returns: AwsQuantumTask: AwsQuantumTask tracking the quantum task execution on the device. @@ -179,6 +186,18 @@ def create( create_task_kwargs.update({"tags": tags}) inputs = inputs or {} + if reservation_arn: + create_task_kwargs.update( + { + "associations": [ + { + "arn": reservation_arn, + "type": "RESERVATION_TIME_WINDOW_ARN", + } + ] + } + ) + if isinstance(task_specification, Circuit): param_names = {param.name for param in task_specification.parameters} unbounded_parameters = param_names - set(inputs.keys()) @@ -477,6 +496,12 @@ async def _wait_for_completion( self._result = None return None + def _has_reservation_arn_from_metadata(self, current_metadata: dict[str, Any]) -> bool: + for association in current_metadata.get("associations", []): + if association.get("type") == "RESERVATION_TIME_WINDOW_ARN": + return True + return False + def _download_result( self, ) -> Union[ @@ -488,7 +513,12 @@ def _download_result( current_metadata["outputS3Directory"] + f"/{AwsQuantumTask.RESULTS_FILENAME}", ) self._result = _format_result(BraketSchemaBase.parse_raw_schema(result_string)) - task_event = {"arn": self.id, "status": self.state(), "execution_duration": None} + task_event = { + "arn": self.id, + "status": self.state(), + "execution_duration": None, + "has_reservation_arn": self._has_reservation_arn_from_metadata(current_metadata), + } try: task_event[ "execution_duration" diff --git a/src/braket/aws/aws_quantum_task_batch.py b/src/braket/aws/aws_quantum_task_batch.py index adf15bda3..24ff15530 100644 --- a/src/braket/aws/aws_quantum_task_batch.py +++ b/src/braket/aws/aws_quantum_task_batch.py @@ -61,6 +61,7 @@ def __init__( poll_timeout_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, poll_interval_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, inputs: Union[dict[str, float], list[dict[str, float]]] | None = None, + reservation_arn: str | None = None, *aws_quantum_task_args, **aws_quantum_task_kwargs, ): @@ -91,6 +92,11 @@ def __init__( inputs (Union[dict[str, float], list[dict[str, float]]] | None): Inputs to be passed along with the IR. If the IR supports inputs, the inputs will be updated with this value. Default: {}. + reservation_arn (str | None): The reservation ARN provided by Braket Direct + to reserve exclusive usage for the device to run the quantum task on. + Note: If you are creating tasks in a job that itself was created reservation ARN, + those tasks do not need to be created with the reservation ARN. + Default: None. """ self._tasks = AwsQuantumTaskBatch._execute( aws_session, @@ -103,6 +109,7 @@ def __init__( poll_timeout_seconds, poll_interval_seconds, inputs, + reservation_arn, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) @@ -120,6 +127,7 @@ def __init__( self._poll_timeout_seconds = poll_timeout_seconds self._poll_interval_seconds = poll_interval_seconds self._inputs = inputs + self._reservation_arn = reservation_arn self._aws_quantum_task_args = aws_quantum_task_args self._aws_quantum_task_kwargs = aws_quantum_task_kwargs @@ -197,6 +205,7 @@ def _execute( poll_timeout_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, poll_interval_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, inputs: Union[dict[str, float], list[dict[str, float]]] = None, + reservation_arn: str | None = None, *args, **kwargs, ) -> list[AwsQuantumTask]: @@ -217,6 +226,7 @@ def _execute( poll_timeout_seconds=poll_timeout_seconds, poll_interval_seconds=poll_interval_seconds, inputs=input_map, + reservation_arn=reservation_arn, *args, **kwargs, ) @@ -248,6 +258,7 @@ def _create_task( shots: int, poll_interval_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, inputs: dict[str, float] = None, + reservation_arn: str | None = None, *args, **kwargs, ) -> AwsQuantumTask: @@ -259,6 +270,7 @@ def _create_task( shots, poll_interval_seconds=poll_interval_seconds, inputs=inputs, + reservation_arn=reservation_arn, *args, **kwargs, ) @@ -347,6 +359,7 @@ def retry_unsuccessful_tasks(self) -> bool: self._max_workers, self._poll_timeout_seconds, self._poll_interval_seconds, + self._reservation_arn, *self._aws_quantum_task_args, **self._aws_quantum_task_kwargs, ) diff --git a/src/braket/jobs/hybrid_job.py b/src/braket/jobs/hybrid_job.py index ae17c2715..707f18fd5 100644 --- a/src/braket/jobs/hybrid_job.py +++ b/src/braket/jobs/hybrid_job.py @@ -63,6 +63,7 @@ def hybrid_job( aws_session: AwsSession | None = None, tags: dict[str, str] | None = None, logger: Logger = getLogger(__name__), + reservation_arn: str | None = None, ) -> Callable: """Defines a hybrid job by decorating the entry point function. The job will be created when the decorated function is called. @@ -152,6 +153,10 @@ def hybrid_job( logger (Logger): Logger object with which to write logs, such as task statuses while waiting for task to be in a terminal state. Default: `getLogger(__name__)` + reservation_arn (str | None): the reservation window arn provided by Braket + Direct to reserve exclusive usage for the device to run the hybrid job on. + Default: None. + Returns: Callable: the callable for creating a Hybrid Job. """ @@ -205,6 +210,7 @@ def job_wrapper(*args, **kwargs) -> Callable: "output_data_config": output_data_config, "aws_session": aws_session, "tags": tags, + "reservation_arn": reservation_arn, } for key, value in optional_args.items(): if value is not None: diff --git a/src/braket/jobs/quantum_job_creation.py b/src/braket/jobs/quantum_job_creation.py index b935de7eb..657ed0829 100644 --- a/src/braket/jobs/quantum_job_creation.py +++ b/src/braket/jobs/quantum_job_creation.py @@ -55,6 +55,7 @@ def prepare_quantum_job( checkpoint_config: CheckpointConfig | None = None, aws_session: AwsSession | None = None, tags: dict[str, str] | None = None, + reservation_arn: str | None = None, ) -> dict: """Creates a hybrid job by invoking the Braket CreateJob API. @@ -140,6 +141,10 @@ def prepare_quantum_job( hybrid job. Default: {}. + reservation_arn (str | None): the reservation window arn provided by Braket + Direct to reserve exclusive usage for the device to run the hybrid job on. + Default: None. + Returns: dict: Hybrid job tracking the execution on Amazon Braket. @@ -174,6 +179,7 @@ def prepare_quantum_job( job_name, "script", ) + if AwsSession.is_s3_uri(source_module): _process_s3_source_module(source_module, entry_point, aws_session, code_location) else: @@ -230,6 +236,18 @@ def prepare_quantum_job( "tags": tags, } + if reservation_arn: + create_job_kwargs.update( + { + "associations": [ + { + "arn": reservation_arn, + "type": "RESERVATION_TIME_WINDOW_ARN", + } + ] + } + ) + return create_job_kwargs diff --git a/src/braket/tracking/tracker.py b/src/braket/tracking/tracker.py index c30fc774e..84b294ad2 100644 --- a/src/braket/tracking/tracker.py +++ b/src/braket/tracking/tracker.py @@ -159,8 +159,12 @@ def quantum_tasks_statistics(self) -> dict[str, dict[str, Any]]: + details["execution_duration"] ) billed_duration = ( - device_stats.get("billed_execution_duration", timedelta(0)) - + details["billed_duration"] + timedelta(0) + if details.get("has_reservation_arn") + else ( + device_stats.get("billed_execution_duration", timedelta(0)) + + details["billed_duration"] + ) ) device_stats["execution_duration"] = duration @@ -196,14 +200,20 @@ def _(self, event: _TaskCompletionEvent) -> None: # Update task completion data corresponding to the arn only if it exists in resources if event.arn in resources: resources[event.arn]["status"] = event.status + has_reservation_arn = event.has_reservation_arn + resources[event.arn]["has_reservation_arn"] = has_reservation_arn if event.execution_duration: duration = timedelta(milliseconds=event.execution_duration) resources[event.arn]["execution_duration"] = duration - resources[event.arn]["billed_duration"] = max(duration, MIN_SIMULATOR_DURATION) + resources[event.arn]["billed_duration"] = ( + timedelta(milliseconds=0) + if has_reservation_arn + else max(duration, MIN_SIMULATOR_DURATION) + ) def _get_qpu_task_cost(task_arn: str, details: dict) -> Decimal: - if details["status"] in ["FAILED", "CANCELLED"]: + if details["status"] in ["FAILED", "CANCELLED"] or details.get("has_reservation_arn"): return Decimal(0) task_region = task_arn.split(":")[3] diff --git a/src/braket/tracking/tracking_events.py b/src/braket/tracking/tracking_events.py index 6f37183c0..793ff038c 100644 --- a/src/braket/tracking/tracking_events.py +++ b/src/braket/tracking/tracking_events.py @@ -33,6 +33,7 @@ class _TaskCreationEvent(_TrackingEvent): class _TaskCompletionEvent(_TrackingEvent): execution_duration: Optional[float] status: str + has_reservation_arn: bool = False @dataclass diff --git a/test/integ_tests/test_reservation_arn.py b/test/integ_tests/test_reservation_arn.py new file mode 100644 index 000000000..e0736f802 --- /dev/null +++ b/test/integ_tests/test_reservation_arn.py @@ -0,0 +1,91 @@ +# 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. + +import sys + +import pytest +from botocore.exceptions import ClientError +from test_create_quantum_job import decorator_python_version + +from braket.aws import AwsDevice +from braket.aws.aws_quantum_job import AwsQuantumJob +from braket.circuits import Circuit +from braket.devices import Devices +from braket.jobs import get_job_device_arn, hybrid_job + + +@pytest.fixture +def reservation_arn(aws_session): + return ( + f"arn:aws:braket:{aws_session.region}" + f":{aws_session.account_id}:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ) + + +def test_create_task_via_invalid_reservation_arn_on_qpu(reservation_arn): + circuit = Circuit().h(0) + device = AwsDevice(Devices.IonQ.Harmony) + + with pytest.raises(ClientError, match="Reservation arn is invalid"): + device.run( + circuit, + shots=10, + reservation_arn=reservation_arn, + ) + + +def test_create_task_via_reservation_arn_on_simulator(reservation_arn): + circuit = Circuit().h(0) + device = AwsDevice(Devices.Amazon.SV1) + + with pytest.raises(ClientError, match="Braket Direct is not supported for"): + device.run( + circuit, + shots=10, + reservation_arn=reservation_arn, + ) + + +def test_create_job_via_invalid_reservation_arn_on_qpu(aws_session, reservation_arn): + with pytest.raises(ClientError, match="Reservation arn is invalid"): + AwsQuantumJob.create( + device=Devices.IonQ.Harmony, + source_module="test/integ_tests/job_test_script.py", + entry_point="job_test_script:start_here", + wait_until_complete=True, + aws_session=aws_session, + hyperparameters={"test_case": "completed"}, + reservation_arn=reservation_arn, + ) + + +@pytest.mark.xfail( + (sys.version_info.major, sys.version_info.minor) != decorator_python_version(), + raises=RuntimeError, + reason="Python version mismatch", +) +def test_create_job_with_decorator_via_invalid_reservation_arn(reservation_arn): + with pytest.raises(ClientError, match="Reservation arn is invalid"): + + @hybrid_job( + device=Devices.IonQ.Aria1, + reservation_arn=reservation_arn, + ) + def hello_job(): + device = AwsDevice(get_job_device_arn()) + bell = Circuit().h(0).cnot(0, 1) + task = device.run(bell, shots=10) + measurements = task.result().measurements + return measurements + + hello_job() diff --git a/test/unit_tests/braket/aws/common_test_utils.py b/test/unit_tests/braket/aws/common_test_utils.py index 5dcec5fbc..2975912f1 100644 --- a/test/unit_tests/braket/aws/common_test_utils.py +++ b/test/unit_tests/braket/aws/common_test_utils.py @@ -201,6 +201,7 @@ def run_and_assert( poll_interval_seconds, # Treated as positional arg inputs, # Treated as positional arg gate_definitions, # Treated as positional arg + reservation_arn, # Treated as positional arg extra_args, extra_kwargs, ): @@ -222,6 +223,8 @@ def run_and_assert( run_args.append(gate_definitions) run_args += extra_args if extra_args else [] run_kwargs = extra_kwargs or {} + if reservation_arn: + run_kwargs.update({"reservation_arn": reservation_arn}) task = device.run(circuit, *run_args, **run_kwargs) assert task == task_mock @@ -237,6 +240,7 @@ def run_and_assert( poll_interval_seconds, inputs, gate_definitions, + reservation_arn, extra_args, extra_kwargs, ) @@ -263,6 +267,7 @@ def run_batch_and_assert( poll_interval_seconds, inputs, gate_definitions, + reservation_arn, extra_args, extra_kwargs, ): @@ -291,6 +296,8 @@ def run_batch_and_assert( run_args.append(gate_definitions) run_args += extra_args if extra_args else [] run_kwargs = extra_kwargs or {} + if reservation_arn: + run_kwargs.update({"reservation_arn": reservation_arn}) batch = device.run_batch(circuits, *run_args, **run_kwargs) assert batch.tasks == [task_mock for _ in range(len(circuits))] @@ -306,6 +313,7 @@ def run_batch_and_assert( poll_interval_seconds, inputs, gate_definitions, + reservation_arn, extra_args, extra_kwargs, ) @@ -333,6 +341,7 @@ def _create_task_args_and_kwargs( poll_interval_seconds, inputs, gate_definitions, + reservation_arn, extra_args, extra_kwargs, ): @@ -352,6 +361,7 @@ def _create_task_args_and_kwargs( else default_poll_interval, "inputs": inputs, "gate_definitions": gate_definitions, + "reservation_arn": reservation_arn, } ) return create_args, create_kwargs diff --git a/test/unit_tests/braket/aws/test_aws_device.py b/test/unit_tests/braket/aws/test_aws_device.py index 3770d38a2..29adf2517 100644 --- a/test/unit_tests/braket/aws/test_aws_device.py +++ b/test/unit_tests/braket/aws/test_aws_device.py @@ -987,6 +987,16 @@ def test_run_no_extra(aws_quantum_task_mock, device, circuit): ) +@patch("braket.aws.aws_quantum_task.AwsQuantumTask.create") +def test_run_with_reservation_arn(aws_quantum_task_mock, device, circuit): + _run_and_assert( + aws_quantum_task_mock, + device, + circuit, + reservation_arn="arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9", + ) + + @patch("braket.aws.aws_quantum_task.AwsQuantumTask") def test_run_param_circuit_with_no_inputs( aws_quantum_task_mock, single_circuit_input, device, s3_destination_folder @@ -1024,6 +1034,38 @@ def test_run_param_circuit_with_inputs( ) +@patch("braket.aws.aws_session.boto3.Session") +@patch("braket.aws.aws_session.AwsSession") +@patch("braket.aws.aws_quantum_task.AwsQuantumTask.create") +def test_run_param_circuit_with_reservation_arn_batch_task( + aws_quantum_task_mock, + aws_session_mock, + boto_session_mock, + single_circuit_input, + device, + s3_destination_folder, +): + inputs = {"theta": 0.2} + circ_1 = Circuit().rx(angle=0.2, target=0) + circuits = [circ_1, single_circuit_input] + + _run_batch_and_assert( + aws_quantum_task_mock, + aws_session_mock, + device, + circuits, + s3_destination_folder, + 10, + 20, + 50, + 43200, + 0.25, + inputs, + None, + reservation_arn="arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9", + ) + + @patch("braket.aws.aws_session.boto3.Session") @patch("braket.aws.aws_session.AwsSession") @patch("braket.aws.aws_quantum_task.AwsQuantumTask.create") @@ -1308,13 +1350,14 @@ def test_default_bucket_not_called(aws_quantum_task_mock, device, circuit, s3_de AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, circuit, s3_destination_folder, - None, - None, - None, - None, - None, - None, - None, + shots=None, + poll_timeout_seconds=None, + poll_interval_seconds=None, + inputs=None, + gate_definitions=None, + reservation_arn=None, + extra_args=None, + extra_kwargs=None, ) device._aws_session.default_bucket.assert_not_called() @@ -1375,6 +1418,8 @@ def test_run_with_positional_args_and_kwargs( 0.25, {}, ["foo"], + "arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9", + None, {"bar": 1, "baz": 2}, ) @@ -1489,6 +1534,7 @@ def _run_and_assert( poll_interval_seconds=None, # Treated as positional arg inputs=None, # Treated as positional arg gate_definitions=None, # Treated as positional arg + reservation_arn=None, # Treated as positional arg extra_args=None, extra_kwargs=None, ): @@ -1506,6 +1552,7 @@ def _run_and_assert( poll_interval_seconds, inputs, gate_definitions, + reservation_arn, extra_args, extra_kwargs, ) @@ -1524,6 +1571,7 @@ def _run_batch_and_assert( poll_interval_seconds=None, # Treated as positional arg inputs=None, # Treated as positional arg gate_definitions=None, # Treated as positional arg + reservation_arn=None, # Treated as positional arg extra_args=None, extra_kwargs=None, ): @@ -1544,6 +1592,7 @@ def _run_batch_and_assert( poll_interval_seconds, inputs, gate_definitions, + reservation_arn, extra_args, extra_kwargs, ) diff --git a/test/unit_tests/braket/aws/test_aws_quantum_job.py b/test/unit_tests/braket/aws/test_aws_quantum_job.py index 19b46d72b..3a36d8e75 100644 --- a/test/unit_tests/braket/aws/test_aws_quantum_job.py +++ b/test/unit_tests/braket/aws/test_aws_quantum_job.py @@ -516,7 +516,12 @@ def device_arn(request): @pytest.fixture -def prepare_job_args(aws_session, device_arn): +def reservation_arn(): + return "arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + + +@pytest.fixture +def prepare_job_args(aws_session, device_arn, reservation_arn): return { "device": device_arn, "source_module": Mock(), @@ -535,6 +540,7 @@ def prepare_job_args(aws_session, device_arn): "checkpoint_config": Mock(), "aws_session": aws_session, "tags": Mock(), + "reservation_arn": reservation_arn, } @@ -1027,7 +1033,7 @@ def test_initialize_session_local_device(mock_new_session, aws_session): assert AwsQuantumJob._initialize_session(None, device, logger) == mock_new_session() -def test_bad_arn_format(aws_session): +def test_bad_device_arn_format(aws_session): logger = logging.getLogger(__name__) device_not_found = ( "Device ARN is not a valid format: bad-arn-format. For valid Braket ARNs, " diff --git a/test/unit_tests/braket/aws/test_aws_quantum_task.py b/test/unit_tests/braket/aws/test_aws_quantum_task.py index 99270ad25..656c37dcf 100644 --- a/test/unit_tests/braket/aws/test_aws_quantum_task.py +++ b/test/unit_tests/braket/aws/test_aws_quantum_task.py @@ -203,6 +203,29 @@ def test_metadata_call_if_none(quantum_task): quantum_task._aws_session.get_quantum_task.assert_called_with(quantum_task.id) +def test_has_reservation_arn_from_metadata(quantum_task): + metadata_true = { + "associations": [ + { + "arn": "123", + "type": "RESERVATION_TIME_WINDOW_ARN", + } + ] + } + assert quantum_task._has_reservation_arn_from_metadata(metadata_true) + + metadata_false = { + "status": "RUNNING", + "associations": [ + { + "arn": "123", + "type": "other", + } + ], + } + assert not quantum_task._has_reservation_arn_from_metadata(metadata_false) + + def test_queue_position(quantum_task): state_1 = "QUEUED" _mock_metadata(quantum_task._aws_session, state_1) @@ -560,6 +583,31 @@ def test_create_ahs_problem(aws_session, arn, ahs_problem): ) +def test_create_task_with_reservation_arn(aws_session, arn, ahs_problem): + aws_session.create_quantum_task.return_value = arn + shots = 21 + reservation_arn = ( + "arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ) + AwsQuantumTask.create( + aws_session, + SIMULATOR_ARN, + ahs_problem, + S3_TARGET, + shots, + reservation_arn=reservation_arn, + ) + + _assert_create_quantum_task_called_with( + aws_session, + SIMULATOR_ARN, + ahs_problem.to_ir().json(), + S3_TARGET, + shots, + reservation_arn=reservation_arn, + ) + + def test_create_pulse_sequence(aws_session, arn, pulse_sequence): expected_openqasm = "\n".join( [ @@ -1098,6 +1146,7 @@ def _assert_create_quantum_task_called_with( shots, device_parameters=None, tags=None, + reservation_arn=None, ): test_kwargs = { "deviceArn": arn, @@ -1111,6 +1160,17 @@ def _assert_create_quantum_task_called_with( test_kwargs.update({"deviceParameters": device_parameters.json(exclude_none=True)}) if tags is not None: test_kwargs.update({"tags": tags}) + if reservation_arn: + test_kwargs.update( + { + "associations": [ + { + "arn": reservation_arn, + "type": "RESERVATION_TIME_WINDOW_ARN", + } + ] + } + ) aws_session.create_quantum_task.assert_called_with(**test_kwargs) diff --git a/test/unit_tests/braket/aws/test_aws_quantum_task_batch.py b/test/unit_tests/braket/aws/test_aws_quantum_task_batch.py index 5802db110..2c748ecea 100644 --- a/test/unit_tests/braket/aws/test_aws_quantum_task_batch.py +++ b/test/unit_tests/braket/aws/test_aws_quantum_task_batch.py @@ -34,7 +34,16 @@ def test_creation(mock_create): batch_size = 10 batch = AwsQuantumTaskBatch( - Mock(), "foo", _circuits(batch_size), S3_TARGET, 1000, max_parallel=10 + Mock(), + "foo", + _circuits(batch_size), + S3_TARGET, + 1000, + max_parallel=10, + reservaion_arn=( + "arn:aws:braket:us-west-2:123456789123:" + "reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ), ) assert batch.size == batch_size assert batch.tasks == [task_mock for _ in range(batch_size)] @@ -53,7 +62,16 @@ def test_successful(mock_create): batch_size = 15 batch = AwsQuantumTaskBatch( - Mock(), "foo", _circuits(batch_size), S3_TARGET, 1000, max_parallel=10 + Mock(), + "foo", + _circuits(batch_size), + S3_TARGET, + 1000, + max_parallel=10, + reservaion_arn=( + "arn:aws:braket:us-west-2:123456789123:" + "reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ), ) assert batch.size == batch_size assert not batch.unfinished @@ -71,7 +89,16 @@ def test_unsuccessful(mock_create): mock_create.return_value = task_mock batch = AwsQuantumTaskBatch( - Mock(), "foo", [Circuit().h(0).cnot(0, 1)], S3_TARGET, 1000, max_parallel=10 + Mock(), + "foo", + [Circuit().h(0).cnot(0, 1)], + S3_TARGET, + 1000, + max_parallel=10, + reservaion_arn=( + "arn:aws:braket:us-west-2:123456789123:" + "reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ), ) assert not batch.unfinished assert batch.unsuccessful == {task_id} @@ -106,6 +133,10 @@ def test_retry(mock_create): S3_TARGET, 1000, max_parallel=10, + reservaion_arn=( + "arn:aws:braket:us-west-2:123456789123:" + "reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ), ) assert not batch.unfinished assert batch.results(max_retries=0) == [None, result] @@ -142,6 +173,10 @@ def test_abort(mock_threadpool): S3_TARGET, 1000, max_parallel=num_workers, + reservaion_arn=( + "arn:aws:braket:us-west-2:123456789123:" + "reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ), ) @@ -153,7 +188,16 @@ def test_early_abort(mock_submit): with pytest.raises(KeyboardInterrupt): AwsQuantumTaskBatch( - Mock(), "foo", _circuits(batch_size), S3_TARGET, 1000, max_parallel=num_workers + Mock(), + "foo", + _circuits(batch_size), + S3_TARGET, + 1000, + max_parallel=num_workers, + reservaion_arn=( + "arn:aws:braket:us-west-2:123456789123:" + "reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ), ) diff --git a/test/unit_tests/braket/jobs/test_hybrid_job.py b/test/unit_tests/braket/jobs/test_hybrid_job.py index b7b7485d7..e757c6a69 100644 --- a/test/unit_tests/braket/jobs/test_hybrid_job.py +++ b/test/unit_tests/braket/jobs/test_hybrid_job.py @@ -105,6 +105,9 @@ def test_decorator_non_defaults( output_data_config = OutputDataConfig(s3Path="s3") aws_session = MagicMock() tags = {"my_tag": "my_value"} + reservation_arn = ( + "arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + ) logger = getLogger(__name__) with tempfile.TemporaryDirectory() as tempdir: @@ -135,6 +138,7 @@ def test_decorator_non_defaults( output_data_config=output_data_config, aws_session=aws_session, tags=tags, + reservation_arn=reservation_arn, logger=logger, ) def my_entry(a, b: int, c=0, d: float = 1.0, **extras) -> str: @@ -184,6 +188,7 @@ def my_entry(a, b: int, c=0, d: float = 1.0, **extras) -> str: aws_session=aws_session, tags=tags, logger=logger, + reservation_arn=reservation_arn, ) included_module = importlib.import_module("job_module") mock_register.assert_called_with(included_module) diff --git a/test/unit_tests/braket/jobs/test_quantum_job_creation.py b/test/unit_tests/braket/jobs/test_quantum_job_creation.py index 1b2c6b5b4..bef4fd643 100644 --- a/test/unit_tests/braket/jobs/test_quantum_job_creation.py +++ b/test/unit_tests/braket/jobs/test_quantum_job_creation.py @@ -175,6 +175,11 @@ def checkpoint_config(bucket, s3_prefix): ) +@pytest.fixture +def reservation_arn(): + return "arn:aws:braket:us-west-2:123456789123:reservation/a1b123cd-45e6-789f-gh01-i234567jk8l9" + + @pytest.fixture def generate_get_job_response(): def _get_job_response(**kwargs): @@ -247,6 +252,7 @@ def create_job_args( output_data_config, checkpoint_config, tags, + reservation_arn, ): if request.param == "fixtures": return dict( @@ -268,6 +274,7 @@ def create_job_args( "checkpoint_config": checkpoint_config, "aws_session": aws_session, "tags": tags, + "reservation_arn": reservation_arn, }.items() if value is not None ) @@ -325,6 +332,7 @@ def _translate_creation_args(create_job_args): hyperparameters = {str(key): str(value) for key, value in hyperparameters.items()} input_data = create_job_args["input_data"] or {} instance_config = create_job_args["instance_config"] or InstanceConfig() + reservation_arn = create_job_args["reservation_arn"] if create_job_args["distribution"] == "data_parallel": distributed_hyperparams = { "sagemaker_distributed_dataparallel_enabled": "true", @@ -367,6 +375,18 @@ def _translate_creation_args(create_job_args): "tags": tags, } + if reservation_arn: + test_kwargs.update( + { + "associations": [ + { + "arn": reservation_arn, + "type": "RESERVATION_TIME_WINDOW_ARN", + } + ] + } + ) + return test_kwargs diff --git a/test/unit_tests/braket/tracking/test_tracker.py b/test/unit_tests/braket/tracking/test_tracker.py index fc660b809..a97ce57bc 100644 --- a/test/unit_tests/braket/tracking/test_tracker.py +++ b/test/unit_tests/braket/tracking/test_tracker.py @@ -85,6 +85,18 @@ def test_receive_fake_event(empty_tracker): _TaskCreationEvent( arn="no_price:::region", shots=1000, is_job_task=False, device="something_else" ), + _TaskCreationEvent( + arn="unbilled_task0:::region", + shots=100, + is_job_task=True, + device="qpu/foo", + ), + _TaskCreationEvent( + arn="unbilled_task1:::region", + shots=100, + is_job_task=True, + device="qpu/foo", + ), ] GET_EVENTS = [ @@ -101,6 +113,18 @@ def test_receive_fake_event(empty_tracker): ), _TaskCompletionEvent(arn="task_fail:::region", execution_duration=12345, status="FAILED"), _TaskCompletionEvent(arn="task_cancel:::region", execution_duration=None, status="CANCELLED"), + _TaskCompletionEvent( + arn="unbilled_task0:::region", + execution_duration=123, + status="COMPLETED", + has_reservation_arn=True, + ), + _TaskCompletionEvent( + arn="unbilled_task1:::region", + execution_duration=123, + status="COMPLETED", + has_reservation_arn=True, + ), ] @@ -174,7 +198,12 @@ def test_simulator_task_cost(price_mock, completed_tracker): def test_quantum_task_statistics(completed_tracker): stats = completed_tracker.quantum_tasks_statistics() expected = { - "qpu/foo": {"shots": 200, "tasks": {"COMPLETED": 1, "FAILED": 1}}, + "qpu/foo": { + "shots": 400, + "tasks": {"COMPLETED": 3, "FAILED": 1}, + "execution_duration": timedelta(microseconds=246000), + "billed_execution_duration": timedelta(0), + }, "simulator/bar": { "shots": 1000, "tasks": {"COMPLETED": 2, "CREATED": 1}, From c6ff90fc297d47ae9a7af2b0131948f2a0119269 Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 5 Dec 2023 18:17:00 +0000 Subject: [PATCH 09/11] prepare release v1.63.0 --- CHANGELOG.md | 10 ++++++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 876595e2d..7f3514294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.63.0 (2023-12-05) + +### Features + + * Allow reservation ARN in task and job creation + +### Bug Fixes and Other Changes + + * Add Forte 1 device + ## v1.62.1 (2023-11-17) ### Bug Fixes and Other Changes diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index c0e18d0a0..f9e931cef 100644 --- a/src/braket/_sdk/_version.py +++ b/src/braket/_sdk/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.62.2.dev0" +__version__ = "1.63.0" From 75e0bfd20abe69577248da749936dc29633426ab Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 5 Dec 2023 18:17:00 +0000 Subject: [PATCH 10/11] update development version to v1.63.1.dev0 --- src/braket/_sdk/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index f9e931cef..70ca418cd 100644 --- a/src/braket/_sdk/_version.py +++ b/src/braket/_sdk/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.63.0" +__version__ = "1.63.1.dev0" From aea53ae66f9dc23e78cdd31aaf30654fc21c005b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:30:14 -0800 Subject: [PATCH 11/11] infra: bump pypa/gh-action-pypi-publish from 1.8.10 to 1.8.11 (#825) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.10 to 1.8.11. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/b7f401de30cb6434a1e19f805ff006643653240e...2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Abe Coull <85974725+math411@users.noreply.github.com> --- .github/workflows/publish-to-pypi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 10aef9c29..e4d4e68c5 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -26,6 +26,6 @@ jobs: - name: Build a binary wheel and a source tarball run: python setup.py sdist bdist_wheel - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e # release/v1 + uses: pypa/gh-action-pypi-publish@2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf # release/v1 with: password: ${{ secrets.pypi_token }}