From b095710bcd0d1deb305287eaf2d10e7b81ee76f0 Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Tue, 20 Aug 2024 13:36:03 -0700 Subject: [PATCH 01/39] feat: Allow early qubit binding of observables (#1022) --- examples/bell_result_types.py | 10 +- examples/hybrid_job.py | 4 +- examples/hybrid_job_script.py | 4 +- examples/local_noise_simulation.py | 4 +- src/braket/circuits/observable.py | 56 +++-- src/braket/circuits/observables.py | 204 ++++++++++++------ src/braket/circuits/result_types.py | 71 +++--- .../braket/circuits/test_observables.py | 91 ++++++-- 8 files changed, 311 insertions(+), 133 deletions(-) diff --git a/examples/bell_result_types.py b/examples/bell_result_types.py index 2bcb87b79..9271d09fc 100644 --- a/examples/bell_result_types.py +++ b/examples/bell_result_types.py @@ -11,7 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -from braket.circuits import Circuit, Observable +from braket.circuits import Circuit, observables from braket.devices import LocalSimulator device = LocalSimulator() @@ -24,7 +24,7 @@ .h(0) .cnot(0, 1) .probability(target=[0]) - .expectation(observable=Observable.Z(), target=[1]) + .expectation(observable=observables.Z(1)) .amplitude(state=["00"]) .state_vector() ) @@ -45,9 +45,9 @@ Circuit() .h(0) .cnot(0, 1) - .expectation(observable=Observable.Y() @ Observable.X(), target=[0, 1]) - .variance(observable=Observable.Y() @ Observable.X(), target=[0, 1]) - .sample(observable=Observable.Y() @ Observable.X(), target=[0, 1]) + .expectation(observable=observables.Y(0) @ observables.X(1)) + .variance(observable=observables.Y(0) @ observables.X(1)) + .sample(observable=observables.Y(0) @ observables.X(1)) ) # When shots>0 for a simulator, probability, expectation, variance are calculated from measurements diff --git a/examples/hybrid_job.py b/examples/hybrid_job.py index 7f54c9955..545c0505c 100644 --- a/examples/hybrid_job.py +++ b/examples/hybrid_job.py @@ -12,7 +12,7 @@ # language governing permissions and limitations under the License. from braket.aws import AwsDevice -from braket.circuits import Circuit, FreeParameter, Observable +from braket.circuits import Circuit, FreeParameter, observables from braket.devices import Devices from braket.jobs import get_job_device_arn, hybrid_job from braket.jobs.metrics import log_metric @@ -34,7 +34,7 @@ def run_hybrid_job(num_tasks=1): circ = Circuit() circ.rx(0, FreeParameter("theta")) circ.cnot(0, 1) - circ.expectation(observable=Observable.X(), target=0) + circ.expectation(observable=observables.X(0)) # initial parameter theta = 0.0 diff --git a/examples/hybrid_job_script.py b/examples/hybrid_job_script.py index b544ff9df..f7db6df94 100644 --- a/examples/hybrid_job_script.py +++ b/examples/hybrid_job_script.py @@ -13,7 +13,7 @@ from braket.aws import AwsDevice, AwsQuantumJob -from braket.circuits import Circuit, FreeParameter, Observable +from braket.circuits import Circuit, FreeParameter, observables from braket.devices import Devices from braket.jobs import get_job_device_arn, save_job_result from braket.jobs.metrics import log_metric @@ -27,7 +27,7 @@ def run_hybrid_job(num_tasks: int): circ = Circuit() circ.rx(0, FreeParameter("theta")) circ.cnot(0, 1) - circ.expectation(observable=Observable.X(), target=0) + circ.expectation(observable=observables.X(0)) # initial parameter theta = 0.0 diff --git a/examples/local_noise_simulation.py b/examples/local_noise_simulation.py index 0857bfd0c..8c173dd51 100644 --- a/examples/local_noise_simulation.py +++ b/examples/local_noise_simulation.py @@ -11,7 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -from braket.circuits import Circuit, Noise +from braket.circuits import Circuit, noises from braket.devices import LocalSimulator device = LocalSimulator("braket_dm") @@ -23,7 +23,7 @@ circuit = Circuit().x(0).x(1) -noise = Noise.BitFlip(probability=0.1) +noise = noises.BitFlip(probability=0.1) circuit.apply_gate_noise(noise) print("Second example: ") print(circuit) diff --git a/src/braket/circuits/observable.py b/src/braket/circuits/observable.py index d3f3fc862..11ed02eb6 100644 --- a/src/braket/circuits/observable.py +++ b/src/braket/circuits/observable.py @@ -16,7 +16,6 @@ import numbers from collections.abc import Sequence from copy import deepcopy -from typing import Union import numpy as np @@ -27,7 +26,7 @@ OpenQASMSerializationProperties, SerializationProperties, ) -from braket.registers.qubit_set import QubitSet +from braket.registers import QubitInput, QubitSet, QubitSetInput class Observable(QuantumOperator): @@ -37,23 +36,36 @@ class Observable(QuantumOperator): `ResultType.Expectation` to specify the measurement basis. """ - def __init__(self, qubit_count: int, ascii_symbols: Sequence[str]): + def __init__( + self, qubit_count: int, ascii_symbols: Sequence[str], targets: QubitSetInput | None = None + ): super().__init__(qubit_count=qubit_count, ascii_symbols=ascii_symbols) + if targets is not None: + targets = QubitSet(targets) + if (num_targets := len(targets)) != qubit_count: + raise ValueError( + f"Length of target {num_targets} does not match qubit count {qubit_count}" + ) + self._targets = targets + else: + self._targets = None self._coef = 1 def _unscaled(self) -> Observable: - return Observable(qubit_count=self.qubit_count, ascii_symbols=self.ascii_symbols) + return Observable( + qubit_count=self.qubit_count, ascii_symbols=self.ascii_symbols, targets=self.targets + ) def to_ir( self, - target: QubitSet | None = None, + target: QubitSetInput | None = None, ir_type: IRType = IRType.JAQCD, serialization_properties: SerializationProperties | None = None, - ) -> Union[str, list[Union[str, list[list[list[float]]]]]]: + ) -> str | list[str | list[list[list[float]]]]: """Returns the IR representation for the observable Args: - target (QubitSet | None): target qubit(s). Defaults to None. + target (QubitSetInput | None): target qubit(s). Defaults to None. ir_type(IRType) : The IRType to use for converting the result type object to its IR representation. Defaults to IRType.JAQCD. serialization_properties (SerializationProperties | None): The serialization properties @@ -61,7 +73,7 @@ def to_ir( properties supplied must correspond to the supplied `ir_type`. Defaults to None. Returns: - Union[str, list[Union[str, list[list[list[float]]]]]]: The IR representation for + str | list[str | list[list[list[float]]]]: The IR representation for the observable. Raises: @@ -84,27 +96,35 @@ def to_ir( else: raise ValueError(f"Supplied ir_type {ir_type} is not supported.") - def _to_jaqcd(self) -> list[Union[str, list[list[list[float]]]]]: + def _to_jaqcd(self) -> list[str | list[list[list[float]]]]: """Returns the JAQCD representation of the observable.""" raise NotImplementedError("to_jaqcd has not been implemented yet.") def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, - target: QubitSet | None = None, + targets: QubitSetInput | None = None, ) -> str: """Returns the openqasm string representation of the result type. Args: serialization_properties (OpenQASMSerializationProperties): The serialization properties to use while serializing the object to the IR representation. - target (QubitSet | None): target qubit(s). Defaults to None. + targets (QubitSetInput | None): target qubit(s). Defaults to None. Returns: str: Representing the openqasm representation of the result type. """ raise NotImplementedError("to_openqasm has not been implemented yet.") + @property + def targets(self) -> QubitSet | None: + """QubitSet | None: The target qubits of this observable + + If `None`, this is provided by the enclosing result type. + """ + return self._targets + @property def coefficient(self) -> int: """The coefficient of the observable. @@ -185,7 +205,11 @@ def __sub__(self, other: Observable): return self + (-1 * other) def __repr__(self) -> str: - return f"{self.name}('qubit_count': {self.qubit_count})" + return ( + f"{self.name}('qubit_count': {self._qubit_count})" + if self._targets is None + else f"{self.name}('qubit_count': {self._qubit_count}, 'target': {self._targets})" + ) def __eq__(self, other: Observable) -> bool: if isinstance(other, Observable): @@ -198,8 +222,12 @@ class StandardObservable(Observable): eigenvalues of (+1, -1). """ - def __init__(self, ascii_symbols: Sequence[str]): - super().__init__(qubit_count=1, ascii_symbols=ascii_symbols) + def __init__(self, ascii_symbols: Sequence[str], target: QubitInput | None = None): + super().__init__( + qubit_count=1, + ascii_symbols=ascii_symbols, + targets=[target] if target is not None else None, + ) self._eigenvalues = (1.0, -1.0) # immutable def _unscaled(self) -> StandardObservable: diff --git a/src/braket/circuits/observables.py b/src/braket/circuits/observables.py index ae4f36a09..9346435a2 100644 --- a/src/braket/circuits/observables.py +++ b/src/braket/circuits/observables.py @@ -30,20 +30,28 @@ verify_quantum_operator_matrix_dimensions, ) from braket.circuits.serialization import IRType, OpenQASMSerializationProperties -from braket.registers.qubit_set import QubitSet +from braket.registers import QubitInput, QubitSet, QubitSetInput class H(StandardObservable): """Hadamard operation as an observable.""" - def __init__(self): - """Examples: - >>> Observable.H() + def __init__(self, target: QubitInput | None = None): + """Initializes Hadamard observable. + + Args: + target (QubitInput | None): The target qubit to measure the observable on. + If not provided, this needs to be provided from the enclosing result type. + Default: `None`. + + Examples: + >>> observables.H(0) + >>> observables.H() """ - super().__init__(ascii_symbols=["H"]) + super().__init__(ascii_symbols=["H"], target=target) def _unscaled(self) -> StandardObservable: - return H() + return H(self._targets) def _to_jaqcd(self) -> list[str]: if self.coefficient != 1: @@ -54,11 +62,11 @@ def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, target: QubitSet = None ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" - if target: - qubit_target = serialization_properties.format_target(int(target[0])) - return f"{coef_prefix}h({qubit_target})" - else: - return f"{coef_prefix}h all" + targets = target or self._targets + qubit_target = int(targets[0]) if targets else None + if qubit_target is not None: + return f"{coef_prefix}h({serialization_properties.format_target(qubit_target)})" + return f"{coef_prefix}h all" def to_matrix(self) -> np.ndarray: return self.coefficient * ( @@ -76,14 +84,22 @@ def basis_rotation_gates(self) -> tuple[Gate, ...]: class I(Observable): # noqa: E742 """Identity operation as an observable.""" - def __init__(self): - """Examples: - >>> Observable.I() + def __init__(self, target: QubitInput | None = None): + """Initializes Identity observable. + + Args: + target (QubitInput | None): The target qubit to measure the observable on. + If not provided, this needs to be provided from the enclosing result type. + Default: `None`. + + Examples: + >>> observables.I(0) + >>> observables.I() """ - super().__init__(qubit_count=1, ascii_symbols=["I"]) + super().__init__(qubit_count=1, ascii_symbols=["I"], targets=target) def _unscaled(self) -> Observable: - return I() + return I(self._targets) def _to_jaqcd(self) -> list[str]: if self.coefficient != 1: @@ -94,11 +110,11 @@ def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, target: QubitSet = None ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" - if target: - qubit_target = serialization_properties.format_target(int(target[0])) - return f"{coef_prefix}i({qubit_target})" - else: - return f"{coef_prefix}i all" + targets = target or self._targets + qubit_target = int(targets[0]) if targets else None + if qubit_target is not None: + return f"{coef_prefix}i({serialization_properties.format_target(qubit_target)})" + return f"{coef_prefix}i all" def to_matrix(self) -> np.ndarray: return self.coefficient * np.eye(2, dtype=complex) @@ -126,14 +142,22 @@ def eigenvalue(self, index: int) -> float: class X(StandardObservable): """Pauli-X operation as an observable.""" - def __init__(self): - """Examples: - >>> Observable.X() + def __init__(self, target: QubitInput | None = None): + """Initializes Pauli-X observable. + + Args: + target (QubitInput | None): The target qubit to measure the observable on. + If not provided, this needs to be provided from the enclosing result type. + Default: `None`. + + Examples: + >>> observables.X(0) + >>> observables.X() """ - super().__init__(ascii_symbols=["X"]) + super().__init__(ascii_symbols=["X"], target=target) def _unscaled(self) -> StandardObservable: - return X() + return X(self._targets) def _to_jaqcd(self) -> list[str]: if self.coefficient != 1: @@ -144,11 +168,11 @@ def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, target: QubitSet = None ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" - if target: - qubit_target = serialization_properties.format_target(int(target[0])) - return f"{coef_prefix}x({qubit_target})" - else: - return f"{coef_prefix}x all" + targets = target or self._targets + qubit_target = int(targets[0]) if targets else None + if qubit_target is not None: + return f"{coef_prefix}x({serialization_properties.format_target(qubit_target)})" + return f"{coef_prefix}x all" def to_matrix(self) -> np.ndarray: return self.coefficient * np.array([[0.0, 1.0], [1.0, 0.0]], dtype=complex) @@ -164,14 +188,22 @@ def basis_rotation_gates(self) -> tuple[Gate, ...]: class Y(StandardObservable): """Pauli-Y operation as an observable.""" - def __init__(self): - """Examples: - >>> Observable.Y() + def __init__(self, target: QubitInput | None = None): + """Initializes Pauli-Y observable. + + Args: + target (QubitInput | None): The target qubit to measure the observable on. + If not provided, this needs to be provided from the enclosing result type. + Default: `None`. + + Examples: + >>> observables.Y(0) + >>> observables.Y() """ - super().__init__(ascii_symbols=["Y"]) + super().__init__(ascii_symbols=["Y"], target=target) def _unscaled(self) -> StandardObservable: - return Y() + return Y(self._targets) def _to_jaqcd(self) -> list[str]: if self.coefficient != 1: @@ -182,11 +214,11 @@ def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, target: QubitSet = None ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" - if target: - qubit_target = serialization_properties.format_target(int(target[0])) - return f"{coef_prefix}y({qubit_target})" - else: - return f"{coef_prefix}y all" + targets = target or self._targets + qubit_target = int(targets[0]) if targets else None + if qubit_target is not None: + return f"{coef_prefix}y({serialization_properties.format_target(qubit_target)})" + return f"{coef_prefix}y all" def to_matrix(self) -> np.ndarray: return self.coefficient * np.array([[0.0, -1.0j], [1.0j, 0.0]], dtype=complex) @@ -202,14 +234,22 @@ def basis_rotation_gates(self) -> tuple[Gate, ...]: class Z(StandardObservable): """Pauli-Z operation as an observable.""" - def __init__(self): - """Examples: - >>> Observable.Z() + def __init__(self, target: QubitInput | None = None): + """Initializes Pauli-Z observable. + + Args: + target (QubitInput | None): The target qubit to measure the observable on. + If not provided, this needs to be provided from the enclosing result type. + Default: `None`. + + Examples: + >>> observables.Z(0) + >>> observables.Z() """ - super().__init__(ascii_symbols=["Z"]) + super().__init__(ascii_symbols=["Z"], target=target) def _unscaled(self) -> StandardObservable: - return Z() + return Z(self._targets) def _to_jaqcd(self) -> list[str]: if self.coefficient != 1: @@ -220,11 +260,11 @@ def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, target: QubitSet = None ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" - if target: - qubit_target = serialization_properties.format_target(int(target[0])) - return f"{coef_prefix}z({qubit_target})" - else: - return f"{coef_prefix}z all" + targets = target or self._targets + qubit_target = int(targets[0]) if targets else None + if qubit_target is not None: + return f"{coef_prefix}z({serialization_properties.format_target(qubit_target)})" + return f"{coef_prefix}z all" def to_matrix(self) -> np.ndarray: return self.coefficient * np.array([[1.0, 0.0], [0.0, -1.0]], dtype=complex) @@ -247,13 +287,13 @@ def __init__(self, observables: list[Observable]): observables (list[Observable]): List of observables for tensor product Examples: - >>> t1 = Observable.Y() @ Observable.X() + >>> t1 = Observable.Y(0) @ Observable.X(1) >>> t1.to_matrix() array([[0.+0.j, 0.+0.j, 0.-0.j, 0.-1.j], [0.+0.j, 0.+0.j, 0.-1.j, 0.-0.j], [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j], [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j]]) - >>> t2 = Observable.Z() @ t1 + >>> t2 = Observable.Z(3) @ t1 >>> t2.factors (Z('qubit_count': 1), Y('qubit_count': 1), X('qubit_count': 1)) @@ -281,7 +321,22 @@ def __init__(self, observables: list[Observable]): f"{coefficient if coefficient != 1 else ''}" f"{'@'.join([obs.ascii_symbols[0] for obs in unscaled_factors])}" ) - super().__init__(qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count) + all_targets = [factor.targets for factor in unscaled_factors] + if all(targets is None for targets in all_targets): + merged_targets = None + elif all(targets is not None for targets in all_targets): + flat_targets = [qubit for target in all_targets for qubit in target] + merged_targets = QubitSet(flat_targets) + if len(merged_targets) != len(flat_targets): + raise ValueError("Cannot have repeated target qubits") + else: + raise ValueError("Cannot mix factors with and without targets") + + super().__init__( + qubit_count=qubit_count, + ascii_symbols=[display_name] * qubit_count, + targets=merged_targets, + ) self._coef = coefficient self._factors = unscaled_factors self._factor_dimensions = tuple( @@ -316,7 +371,7 @@ def _to_openqasm( ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" factors = [] - use_qubits = iter(target) + use_qubits = iter(target or self._targets) for obs in self._factors: obs_target = QubitSet() num_qubits = int(np.log2(obs.to_matrix().shape[0])) @@ -438,7 +493,7 @@ def __init__(self, observables: list[Observable], display_name: str = "Hamiltoni observable for circuit diagrams. Defaults to `Hamiltonian`. Examples: - >>> t1 = -3 * Observable.Y() + 2 * Observable.X() + >>> t1 = -3 * Observable.Y(0) + 2 * Observable.X(0) Sum(X('qubit_count': 1), Y('qubit_count': 1)) >>> t1.summands (X('qubit_count': 1), Y('qubit_count': 1)) @@ -452,7 +507,15 @@ def __init__(self, observables: list[Observable], display_name: str = "Hamiltoni self._summands = tuple(flattened_observables) qubit_count = max(flattened_observables, key=lambda obs: obs.qubit_count).qubit_count + all_targets = [observable.targets for observable in flattened_observables] + if all(targets is None for targets in all_targets): + targets = None + elif all(targets is not None for targets in all_targets): + targets = all_targets + else: + raise ValueError("Cannot mix terms with and without targets") super().__init__(qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count) + self._targets = targets def __mul__(self, other: numbers.Number) -> Observable: """Scalar multiplication""" @@ -469,8 +532,9 @@ def _to_jaqcd(self) -> list[str]: def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, - target: list[QubitSet] = None, + target: list[QubitSetInput] = None, ) -> str: + target = target or self._targets if len(self.summands) != len(target): raise ValueError( f"Invalid target of length {len(target)} for Sum with {len(self.summands)} terms" @@ -529,21 +593,30 @@ class Hermitian(Observable): # Cache of eigenpairs _eigenpairs: ClassVar = {} - def __init__(self, matrix: np.ndarray, display_name: str = "Hermitian"): + def __init__( + self, + matrix: np.ndarray, + display_name: str = "Hermitian", + targets: QubitSetInput | None = None, + ): """Inits a `Hermitian`. Args: matrix (np.ndarray): Hermitian matrix that defines the observable. display_name (str): Name to use for an instance of this Hermitian matrix observable for circuit diagrams. Defaults to `Hermitian`. + targets (QubitSetInput | None): The target qubits to measure the observable on. + If not provided, this needs to be provided from the enclosing result type. + Default: `None`. Raises: ValueError: If `matrix` is not a two-dimensional square matrix, - or has a dimension length that is not a positive power of 2, - or is not Hermitian. + is not Hermitian, or has a dimension length that is either not a positive power of 2 + or, if targets is supplied, doesn't match the size of targets. Examples: - >>> Observable.Hermitian(matrix=np.array([[0, 1],[1, 0]])) + >>> observables.Hermitian(matrix=np.array([[0, 1],[1, 0]]), targets=[0]) + >>> observables.Hermitian(matrix=np.array([[0, 1],[1, 0]])) """ verify_quantum_operator_matrix_dimensions(matrix) self._matrix = np.array(matrix, dtype=complex) @@ -557,10 +630,14 @@ def __init__(self, matrix: np.ndarray, display_name: str = "Hermitian"): Gate.Unitary(matrix=eigendecomposition["eigenvectors"].conj().T), ) - super().__init__(qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count) + super().__init__( + qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count, targets=targets + ) def _unscaled(self) -> Observable: - return Hermitian(matrix=self._matrix, display_name=self.ascii_symbols[0]) + return Hermitian( + matrix=self._matrix, display_name=self.ascii_symbols[0], targets=self._targets + ) def _to_jaqcd(self) -> list[list[list[list[float]]]]: if self.coefficient != 1: @@ -573,6 +650,7 @@ def _to_openqasm( self, serialization_properties: OpenQASMSerializationProperties, target: QubitSet = None ) -> str: coef_prefix = f"{self.coefficient} * " if self.coefficient != 1 else "" + target = target or self._targets if target: qubit_target = ", ".join( [serialization_properties.format_target(int(t)) for t in target] diff --git a/src/braket/circuits/result_types.py b/src/braket/circuits/result_types.py index 325fa8f46..f682b9ba1 100644 --- a/src/braket/circuits/result_types.py +++ b/src/braket/circuits/result_types.py @@ -96,7 +96,7 @@ def __init__(self, target: QubitSetInput | None = None): full density matrix is returned. Examples: - >>> ResultType.DensityMatrix(target=[0, 1]) + >>> result_types.DensityMatrix(target=[0, 1]) """ self._target = QubitSet(target) ascii_symbols = ["DensityMatrix"] * len(self._target) if self._target else ["DensityMatrix"] @@ -198,14 +198,15 @@ def __init__( Examples: - >>> ResultType.AdjointGradient(observable=Observable.Z(), + >>> result_types.AdjointGradient(observable=observables.Z(0), + parameters=["alpha", "beta"]) + >>> result_types.AdjointGradient(observable=observables.Z(), target=0, parameters=["alpha", "beta"]) - >>> tensor_product = Observable.Y() @ Observable.Z() - >>> hamiltonian = Observable.Y() @ Observable.Z() + Observable.H() - >>> ResultType.AdjointGradient( + >>> tensor_product = observables.Y(0) @ observables.Z(1) + >>> hamiltonian = observables.Y(0) @ observables.Z(1) + observables.H(0) + >>> result_types.AdjointGradient( >>> observable=tensor_product, - >>> target=[[0, 1], [2]], >>> parameters=["alpha", "beta"], >>> ) """ @@ -261,7 +262,7 @@ def adjoint_gradient( Examples: >>> alpha, beta = FreeParameter('alpha'), FreeParameter('beta') >>> circ = Circuit().h(0).h(1).rx(0, alpha).yy(0, 1, beta).adjoint_gradient( - >>> observable=Observable.Z(), target=[0], parameters=[alpha, beta] + >>> observable=observables.Z(0), parameters=[alpha, beta] >>> ) """ return ResultType.AdjointGradient( @@ -288,7 +289,7 @@ def __init__(self, state: list[str]): state is not a list of strings of '0' and '1' Examples: - >>> ResultType.Amplitude(state=['01', '10']) + >>> result_types.Amplitude(state=['01', '10']) """ if ( not state @@ -367,7 +368,7 @@ def __init__(self, target: QubitSetInput | None = None): circuit. Examples: - >>> ResultType.Probability(target=[0, 1]) + >>> result_types.Probability(target=[0, 1]) """ self._target = QubitSet(target) ascii_symbols = ["Probability"] * len(self._target) if self._target else ["Probability"] @@ -453,16 +454,18 @@ def __init__(self, observable: Observable, target: QubitSetInput | None = None): Args: observable (Observable): the observable for the result type - target (QubitSetInput | None): Target qubits that the - result type is requested for. Default is `None`, which means the observable must - operate only on 1 qubit and it is applied to all qubits in parallel. - + target (QubitSetInput | None): Target qubits that the result type is requested for. + If not provided, the observable's target will be used instead. If neither exist, + then it is applied to all qubits in parallel; in this case the observable must + operate only on 1 qubit. + Default: `None`. Examples: - >>> ResultType.Expectation(observable=Observable.Z(), target=0) + >>> result_types.Expectation(observable=observables.Z(0)) + >>> result_types.Expectation(observable=observables.Z(), target=0) - >>> tensor_product = Observable.Y() @ Observable.Z() - >>> ResultType.Expectation(observable=tensor_product, target=[0, 1]) + >>> tensor_product = observables.Y(0) @ observables.Z(1) + >>> result_types.Expectation(observable=tensor_product) """ super().__init__( ascii_symbols=[f"Expectation({obs_ascii})" for obs_ascii in observable.ascii_symbols], @@ -501,7 +504,7 @@ def expectation(observable: Observable, target: QubitSetInput | None = None) -> ResultType: expectation as a requested result type Examples: - >>> circ = Circuit().expectation(observable=Observable.Z(), target=0) + >>> circ = Circuit().expectation(observable=observables.Z(0)) """ return ResultType.Expectation(observable=observable, target=target) @@ -526,15 +529,18 @@ def __init__(self, observable: Observable, target: QubitSetInput | None = None): Args: observable (Observable): the observable for the result type - target (QubitSetInput | None): Target qubits that the - result type is requested for. Default is `None`, which means the observable must - operate only on 1 qubit and it is applied to all qubits in parallel. + target (QubitSetInput | None): Target qubits that the result type is requested for. + If not provided, the observable's target will be used instead. If neither exist, + then it is applied to all qubits in parallel; in this case the observable must + operate only on 1 qubit. + Default: `None`. Examples: - >>> ResultType.Sample(observable=Observable.Z(), target=0) + >>> result_types.Sample(observable=observables.Z(0)) + >>> result_types.Sample(observable=observables.Z(), target=0) - >>> tensor_product = Observable.Y() @ Observable.Z() - >>> ResultType.Sample(observable=tensor_product, target=[0, 1]) + >>> tensor_product = observables.Y(0) @ observables.Z(1) + >>> result_types.Sample(observable=tensor_product) """ super().__init__( ascii_symbols=[f"Sample({obs_ascii})" for obs_ascii in observable.ascii_symbols], @@ -573,7 +579,7 @@ def sample(observable: Observable, target: QubitSetInput | None = None) -> Resul ResultType: sample as a requested result type Examples: - >>> circ = Circuit().sample(observable=Observable.Z(), target=0) + >>> circ = Circuit().sample(observable=observables.Z(0)) """ return ResultType.Sample(observable=observable, target=target) @@ -599,19 +605,22 @@ def __init__(self, observable: Observable, target: QubitSetInput | None = None): Args: observable (Observable): the observable for the result type - target (QubitSetInput | None): Target qubits that the - result type is requested for. Default is `None`, which means the observable must - operate only on 1 qubit and it is applied to all qubits in parallel. + target (QubitSetInput | None): Target qubits that the result type is requested for. + If not provided, the observable's target will be used instead. If neither exist, + then it is applied to all qubits in parallel; in this case the observable must + operate only on 1 qubit. + Default: `None`. Raises: ValueError: If the observable's qubit count does not equal the number of target qubits, or if `target=None` and the observable's qubit count is not 1. Examples: - >>> ResultType.Variance(observable=Observable.Z(), target=0) + >>> result_types.Variance(observable=observables.Z(0)) + >>> result_types.Variance(observable=observables.Z(), target=0) - >>> tensor_product = Observable.Y() @ Observable.Z() - >>> ResultType.Variance(observable=tensor_product, target=[0, 1]) + >>> tensor_product = observables.Y(0) @ observables.Z(1) + >>> result_types.Variance(observable=tensor_product) """ super().__init__( ascii_symbols=[f"Variance({obs_ascii})" for obs_ascii in observable.ascii_symbols], @@ -650,7 +659,7 @@ def variance(observable: Observable, target: QubitSetInput | None = None) -> Res ResultType: variance as a requested result type Examples: - >>> circ = Circuit().variance(observable=Observable.Z(), target=0) + >>> circ = Circuit().variance(observable=observables.Z(0)) """ return ResultType.Variance(observable=observable, target=target) diff --git a/test/unit_tests/braket/circuits/test_observables.py b/test/unit_tests/braket/circuits/test_observables.py index b6430d4d8..213a29705 100644 --- a/test/unit_tests/braket/circuits/test_observables.py +++ b/test/unit_tests/braket/circuits/test_observables.py @@ -61,100 +61,116 @@ def test_to_ir(testobject, gateobject, expected_ir, basis_rotation_gates, eigenv @pytest.mark.parametrize( - "observable, serialization_properties, target, expected_ir", + "observable, observable_with_targets, serialization_properties, target, expected_ir", [ ( Observable.I(), + Observable.I(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3], "i(q[3])", ), ( Observable.I(), + Observable.I(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3], "i($3)", ), ( Observable.I(), + None, OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), None, "i all", ), ( Observable.X(), + Observable.X(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3], "x(q[3])", ), ( Observable.X(), + Observable.X(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3], "x($3)", ), ( Observable.X(), + None, OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), None, "x all", ), ( Observable.Y(), + Observable.Y(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3], "y(q[3])", ), ( Observable.Y(), + Observable.Y(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3], "y($3)", ), ( Observable.Y(), + None, OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), None, "y all", ), ( Observable.Z(), + Observable.Z(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3], "z(q[3])", ), ( Observable.Z(), + Observable.Z(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3], "z($3)", ), ( Observable.Z(), + None, OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), None, "z all", ), ( Observable.H(), + Observable.H(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3], "h(q[3])", ), ( Observable.H(), + Observable.H(3), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3], "h($3)", ), ( Observable.H(), + None, OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), None, "h all", ), ( Observable.Hermitian(np.eye(4)), + Observable.Hermitian(np.eye(4), targets=[1, 2]), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [1, 2], "hermitian([[1+0im, 0im, 0im, 0im], [0im, 1+0im, 0im, 0im], " @@ -162,6 +178,7 @@ def test_to_ir(testobject, gateobject, expected_ir, basis_rotation_gates, eigenv ), ( Observable.Hermitian(np.eye(4)), + Observable.Hermitian(np.eye(4), targets=[1, 2]), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [1, 2], "hermitian([[1+0im, 0im, 0im, 0im], [0im, 1+0im, 0im, 0im], " @@ -169,36 +186,42 @@ def test_to_ir(testobject, gateobject, expected_ir, basis_rotation_gates, eigenv ), ( Observable.Hermitian(np.eye(2)), + None, OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), None, "hermitian([[1+0im, 0im], [0im, 1+0im]]) all", ), ( Observable.H() @ Observable.Z(), + Observable.H(3) @ Observable.Z(0), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3, 0], "h(q[3]) @ z(q[0])", ), ( Observable.H() @ Observable.Z(), + Observable.H(3) @ Observable.Z(0), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3, 0], "h($3) @ z($0)", ), ( Observable.H() @ Observable.Z() @ Observable.I(), + Observable.H(3) @ Observable.Z(0) @ Observable.I(1), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3, 0, 1], "h(q[3]) @ z(q[0]) @ i(q[1])", ), ( Observable.H() @ Observable.Z() @ Observable.I(), + Observable.H(3) @ Observable.Z(0) @ Observable.I(1), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3, 0, 1], "h($3) @ z($0) @ i($1)", ), ( Observable.Hermitian(np.eye(4)) @ Observable.I(), + Observable.Hermitian(np.eye(4), targets=[3, 0]) @ Observable.I(1), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), [3, 0, 1], "hermitian([[1+0im, 0im, 0im, 0im], [0im, 1+0im, 0im, 0im], " @@ -207,32 +230,23 @@ def test_to_ir(testobject, gateobject, expected_ir, basis_rotation_gates, eigenv ), ( Observable.I() @ Observable.Hermitian(np.eye(4)), + Observable.I(3) @ Observable.Hermitian(np.eye(4), targets=[0, 1]), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3, 0, 1], "i($3) @ " "hermitian([[1+0im, 0im, 0im, 0im], [0im, 1+0im, 0im, 0im], " "[0im, 0im, 1+0im, 0im], [0im, 0im, 0im, 1+0im]]) $0, $1", ), - ( - (2 * Observable.Z()) @ (3 * Observable.H()), - OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), - [3, 3], - "6 * z($3) @ h($3)", - ), - ( - (2 * Observable.Z()) @ (3 * Observable.H()) @ (2 * Observable.Y()), - OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), - [3, 3, 1], - "12 * z($3) @ h($3) @ y($1)", - ), ( 3 * (2 * Observable.Z()), + 3 * (2 * Observable.Z(3)), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3], "6 * z($3)", ), ( (2 * Observable.I()) @ (2 * Observable.Hermitian(np.eye(4))), + (2 * Observable.I(3)) @ (2 * Observable.Hermitian(np.eye(4), targets=[0, 1])), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [3, 0, 1], "4 * i($3) @ " @@ -241,55 +255,84 @@ def test_to_ir(testobject, gateobject, expected_ir, basis_rotation_gates, eigenv ), ( Observable.Z() + 2 * Observable.H(), + Observable.Z(3) + 2 * Observable.H(4), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[3], [4]], "z($3) + 2 * h($4)", ), ( 3 * (Observable.H() + 2 * Observable.X()), + 3 * (Observable.H(3) + 2 * Observable.X(0)), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[3], [0]], "3 * h($3) + 6 * x($0)", ), ( 3 * (Observable.H() + 2 * Observable.H()), + 3 * (Observable.H(3) + 2 * Observable.H(3)), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[3], [3]], "3 * h($3) + 6 * h($3)", ), ( 3 * (Observable.H() + 2 * Observable.H()), + 3 * (Observable.H(3) + 2 * Observable.H(5)), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[3], [5]], "3 * h($3) + 6 * h($5)", ), ( (2 * Observable.Y()) @ (3 * Observable.I()) + 0.75 * Observable.Y() @ Observable.Z(), + (2 * Observable.Y(0)) @ (3 * Observable.I(1)) + + 0.75 * Observable.Y(0) @ Observable.Z(1), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[0, 1], [0, 1]], "6 * y($0) @ i($1) + 0.75 * y($0) @ z($1)", ), ( (-2 * Observable.Y()) @ (3 * Observable.I()) + -0.75 * Observable.Y() @ Observable.Z(), + (-2 * Observable.Y(0)) @ (3 * Observable.I(1)) + + -0.75 * Observable.Y(0) @ Observable.Z(1), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[0, 1], [0, 1]], "-6 * y($0) @ i($1) - 0.75 * y($0) @ z($1)", ), ( 4 * (2 * Observable.Z() + 2 * (3 * Observable.X() @ (2 * Observable.Y()))), + 4 * (2 * Observable.Z(0) + 2 * (3 * Observable.X(1) @ (2 * Observable.Y(2)))), OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), [[0], [1, 2]], "8 * z($0) + 48 * x($1) @ y($2)", ), + ( + 4 * (2 * Observable.Z(0) + 2 * (3 * Observable.X(1) @ (2 * Observable.Y(2)))), + None, + OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL), + [[5], [4, 3]], + "8 * z($5) + 48 * x($4) @ y($3)", + ), ], ) -def test_observables_to_ir_openqasm(observable, serialization_properties, target, expected_ir): +def test_observables_to_ir_openqasm( + observable, + observable_with_targets, + serialization_properties, + target, + expected_ir, +): assert ( observable.to_ir( target, ir_type=IRType.OPENQASM, serialization_properties=serialization_properties ) == expected_ir ) + if observable_with_targets: + assert ( + observable_with_targets.to_ir( + None, ir_type=IRType.OPENQASM, serialization_properties=serialization_properties + ) + == expected_ir + ) @pytest.mark.parametrize( @@ -458,6 +501,11 @@ def test_hermitian_eigenvalues(matrix, eigenvalues): compare_eigenvalues(Observable.Hermitian(matrix=matrix), eigenvalues) +def test_hermitian_matrix_target_mismatch(): + with pytest.raises(ValueError): + Observable.Hermitian(np.eye(4), targets=[0, 1, 2]) + + def test_flattened_tensor_product(): observable_one = Observable.Z() @ Observable.Y() observable_two = Observable.X() @ Observable.H() @@ -612,6 +660,16 @@ def test_tensor_product_basis_rotation_gates(observable, basis_rotation_gates): assert observable.basis_rotation_gates == basis_rotation_gates +def test_tensor_product_repeated_qubits(): + with pytest.raises(ValueError): + (2 * Observable.Z(3)) @ (3 * Observable.H(3)) + + +def test_tensor_product_with_and_without_targets(): + with pytest.raises(ValueError): + (2 * Observable.Z(3)) @ (3 * Observable.H()) + + def test_observable_from_ir_tensor_product(): expected_observable = Observable.TensorProduct([Observable.Z(), Observable.I(), Observable.X()]) actual_observable = observable_from_ir(["z", "i", "x"]) @@ -714,3 +772,8 @@ def test_unscaled_tensor_product(): observable = 3 * ((2 * Observable.X()) @ (5 * Observable.Y())) assert observable == 30 * (Observable.X() @ Observable.Y()) assert observable._unscaled() == Observable.X() @ Observable.Y() + + +def test_sum_with_and_without_targets(): + with pytest.raises(ValueError): + Observable.X() + 3 * Observable.Y(4) From 6c6caf355262450ade4a890626592e246748e206 Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 20 Aug 2024 21:48:18 +0000 Subject: [PATCH 02/39] prepare release v1.85.0 --- CHANGELOG.md | 6 ++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b9cebdb4..cd55752ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.85.0 (2024-08-20) + +### Features + + * Allow early qubit binding of observables + ## v1.84.0 (2024-07-30) ### Features diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 97f6351c2..8dace9a1d 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.84.1.dev0" +__version__ = "1.85.0" From f87be27d4676e07ecdc51cfc663c4f0e3c38af4b Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 20 Aug 2024 21:48:18 +0000 Subject: [PATCH 03/39] update development version to v1.85.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 8dace9a1d..7ae9064d1 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.85.0" +__version__ = "1.85.1.dev0" From a79dccc15629b130e7babb5dc1e75a5fa4a1752e Mon Sep 17 00:00:00 2001 From: "Tim (Yi-Ting)" Date: Thu, 22 Aug 2024 21:07:06 -0400 Subject: [PATCH 04/39] feat: add off_center to erf_square (#1023) --- src/braket/pulse/waveforms.py | 20 +++++-- .../pulse/ast/test_approximation_parser.py | 41 ++++++++++++++- .../braket/pulse/test_pulse_sequence.py | 52 ++++++++++++++++++- .../unit_tests/braket/pulse/test_waveforms.py | 41 +++++++++++---- 4 files changed, 134 insertions(+), 20 deletions(-) diff --git a/src/braket/pulse/waveforms.py b/src/braket/pulse/waveforms.py index 582592dc8..9da7bee4c 100644 --- a/src/braket/pulse/waveforms.py +++ b/src/braket/pulse/waveforms.py @@ -510,6 +510,7 @@ def __init__( length: Union[float, FreeParameterExpression], width: Union[float, FreeParameterExpression], sigma: Union[float, FreeParameterExpression], + off_center: Union[float, FreeParameterExpression] = 0, amplitude: Union[float, FreeParameterExpression] = 1, zero_at_edges: bool = False, id: Optional[str] = None, @@ -529,6 +530,9 @@ def __init__( half height of the two edges. sigma (Union[float, FreeParameterExpression]): A characteristic time of how quickly the edges rise and fall. + off_center (Union[float, FreeParameterExpression]): Shift the smoothed square waveform + earlier or later in time. When positive, the smoothed square is shifted later + (to the right), otherwise earlier (to the left). Defaults to 0. amplitude (Union[float, FreeParameterExpression]): The amplitude of the waveform envelope. Defaults to 1. zero_at_edges (bool): Whether the waveform is scaled such that it has zero value at the @@ -539,6 +543,7 @@ def __init__( self.length = length self.width = width self.sigma = sigma + self.off_center = off_center self.amplitude = amplitude self.zero_at_edges = zero_at_edges self.id = id or _make_identifier_name() @@ -546,8 +551,8 @@ def __init__( def __repr__(self) -> str: return ( f"ErfSquareWaveform('id': {self.id}, 'length': {self.length}, " - f"'width': {self.width}, 'sigma': {self.sigma}, 'amplitude': {self.amplitude}, " - f"'zero_at_edges': {self.zero_at_edges})" + f"'width': {self.width}, 'sigma': {self.sigma}, 'off_center': {self.off_center}, " + f"'amplitude': {self.amplitude}, 'zero_at_edges': {self.zero_at_edges})" ) @property @@ -555,7 +560,7 @@ def parameters(self) -> list[Union[FreeParameterExpression, FreeParameter, float """Returns the parameters associated with the object, either unbound free parameter expressions or bound values. """ - return [self.length, self.width, self.sigma, self.amplitude] + return [self.length, self.width, self.sigma, self.off_center, self.amplitude] def bind_values(self, **kwargs: Union[FreeParameter, str]) -> ErfSquareWaveform: """Takes in parameters and returns an object with specified parameters @@ -571,6 +576,7 @@ def bind_values(self, **kwargs: Union[FreeParameter, str]) -> ErfSquareWaveform: "length": subs_if_free_parameter(self.length, **kwargs), "width": subs_if_free_parameter(self.width, **kwargs), "sigma": subs_if_free_parameter(self.sigma, **kwargs), + "off_center": subs_if_free_parameter(self.off_center, **kwargs), "amplitude": subs_if_free_parameter(self.amplitude, **kwargs), "zero_at_edges": self.zero_at_edges, "id": self.id, @@ -582,6 +588,7 @@ def __eq__(self, other: ErfSquareWaveform): self.length, self.width, self.sigma, + self.off_center, self.amplitude, self.zero_at_edges, self.id, @@ -589,6 +596,7 @@ def __eq__(self, other: ErfSquareWaveform): other.length, other.width, other.sigma, + other.off_center, other.amplitude, other.zero_at_edges, other.id, @@ -606,6 +614,7 @@ def _to_oqpy_expression(self) -> OQPyExpression: ("length", duration), ("width", duration), ("sigma", duration), + ("off_center", duration), ("amplitude", float64), ("zero_at_edges", bool_), ], @@ -615,6 +624,7 @@ def _to_oqpy_expression(self) -> OQPyExpression: self.length, self.width, self.sigma, + self.off_center, self.amplitude, self.zero_at_edges, ), @@ -631,8 +641,8 @@ def sample(self, dt: float) -> np.ndarray: np.ndarray: The sample amplitudes for this waveform. """ sample_range = np.arange(0, self.length, dt) - t1 = (self.length - self.width) / 2 - t2 = (self.length + self.width) / 2 + t1 = (self.length - self.width) / 2 + self.off_center + t2 = (self.length + self.width) / 2 + self.off_center samples = ( sp.special.erf((sample_range - t1) / self.sigma) + sp.special.erf(-(sample_range - t2) / self.sigma) diff --git a/test/unit_tests/braket/pulse/ast/test_approximation_parser.py b/test/unit_tests/braket/pulse/ast/test_approximation_parser.py index 479a3b53e..4c0e2105c 100644 --- a/test/unit_tests/braket/pulse/ast/test_approximation_parser.py +++ b/test/unit_tests/braket/pulse/ast/test_approximation_parser.py @@ -696,7 +696,7 @@ def test_play_drag_gaussian_waveforms(port): def test_play_erf_square_waveforms(port): frame1 = Frame(frame_id="frame1", port=port, frequency=1e8, phase=0, is_predefined=False) erf_square_wf_ZaE_False = ErfSquareWaveform( - length=1e-8, width=8e-9, sigma=1e-9, amplitude=0.8, zero_at_edges=False + length=1e-8, width=8e-9, sigma=1e-9, off_center=0.0, amplitude=0.8, zero_at_edges=False ) pulse_seq = PulseSequence().play(frame1, erf_square_wf_ZaE_False) @@ -733,7 +733,7 @@ def test_play_erf_square_waveforms(port): def test_play_erf_square_waveforms_zero_at_edges(port): frame1 = Frame(frame_id="frame1", port=port, frequency=1e8, phase=0, is_predefined=False) erf_square_wf_ZaE_True = ErfSquareWaveform( - length=1e-8, width=8e-9, sigma=1e-9, amplitude=0.8, zero_at_edges=True + length=1e-8, width=8e-9, sigma=1e-9, off_center=0.0, amplitude=0.8, zero_at_edges=True ) pulse_seq = PulseSequence().play(frame1, erf_square_wf_ZaE_True) @@ -767,6 +767,43 @@ def test_play_erf_square_waveforms_zero_at_edges(port): verify_results(parser, expected_amplitudes, expected_frequencies, expected_phases) +def test_play_erf_square_waveforms_off_center(port): + frame1 = Frame(frame_id="frame1", port=port, frequency=1e8, phase=0, is_predefined=False) + erf_square_wf_ZaE_False = ErfSquareWaveform( + length=1e-8, width=8e-9, sigma=1e-9, off_center=-2e-9, amplitude=0.8, zero_at_edges=False + ) + pulse_seq = PulseSequence().play(frame1, erf_square_wf_ZaE_False) + + times = np.arange(0, 1e-8, port.dt) + values = np.array( + [ + complex(0.7370803285436436), + complex(0.7981289183125405), + complex(0.7999911761342559), + complex(0.8), + complex(0.7999911761342559), + complex(0.7981289183125405), + complex(0.7370803285436436), + complex(0.4000000061669036), + complex(0.0629196837901632), + complex(0.0018710940212660543), + ], + dtype=np.complex128, + ) + + expected_amplitudes = {"frame1": TimeSeries()} + expected_frequencies = {"frame1": TimeSeries()} + expected_phases = {"frame1": TimeSeries()} + + for t, v in zip(times, values): + expected_amplitudes["frame1"].put(t, v) + expected_frequencies["frame1"].put(t, 1e8) + expected_phases["frame1"].put(t, 0) + + parser = _ApproximationParser(program=pulse_seq._program, frames=to_dict(frame1)) + verify_results(parser, expected_amplitudes, expected_frequencies, expected_phases) + + def test_barrier_same_dt(port): frame1 = Frame(frame_id="frame1", port=port, frequency=1e8, phase=0, is_predefined=False) frame2 = Frame(frame_id="frame2", port=port, frequency=1e8, phase=0, is_predefined=False) diff --git a/test/unit_tests/braket/pulse/test_pulse_sequence.py b/test/unit_tests/braket/pulse/test_pulse_sequence.py index 9b6092db1..fa6eca395 100644 --- a/test/unit_tests/braket/pulse/test_pulse_sequence.py +++ b/test/unit_tests/braket/pulse/test_pulse_sequence.py @@ -18,6 +18,7 @@ ArbitraryWaveform, ConstantWaveform, DragGaussianWaveform, + ErfSquareWaveform, Frame, GaussianWaveform, Port, @@ -119,6 +120,16 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined predefined_frame_2, ArbitraryWaveform([complex(1, 0.4), 0, 0.3, complex(0.1, 0.2)], id="arb_wf"), ) + .play( + predefined_frame_1, + ErfSquareWaveform( + length=FreeParameter("length_es"), + width=FreeParameter("width_es"), + sigma=2e-9, + off_center=8e-9, + id="erf_square_wf", + ), + ) .capture_v0(predefined_frame_2) ) expected_str_unbound = "\n".join( @@ -135,6 +146,8 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined " sigma_dg * 1s, 0.2, 1, false);", " waveform constant_wf = constant(length_c * 1s, 2.0 + 0.3im);", " waveform arb_wf = {1.0 + 0.4im, 0, 0.3, 0.1 + 0.2im};", + " waveform erf_square_wf = erf_square(length_es * 1s, width_es * 1s, 2.0ns," + " 8.0ns, 1, false);", " set_frequency(predefined_frame_1, a + 2.0 * c);", " shift_frequency(predefined_frame_1, a + 2.0 * c);", " set_phase(predefined_frame_1, a + 2.0 * c);", @@ -149,6 +162,7 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined " play(predefined_frame_2, drag_gauss_wf);", " play(predefined_frame_1, constant_wf);", " play(predefined_frame_2, arb_wf);", + " play(predefined_frame_1, erf_square_wf);", " psb[1] = capture_v0(predefined_frame_2);", "}", ] @@ -162,11 +176,29 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined FreeParameter("sigma_g"), FreeParameter("sigma_dg"), FreeParameter("length_c"), + FreeParameter("width_es"), + FreeParameter("length_es"), } b_bound = pulse_sequence.make_bound_pulse_sequence( - {"c": 2, "length_g": 1e-3, "length_dg": 3e-3, "sigma_dg": 0.4, "length_c": 4e-3} + { + "c": 2, + "length_g": 1e-3, + "length_dg": 3e-3, + "sigma_dg": 0.4, + "length_c": 4e-3, + "length_es": 20e-9, + "width_es": 12e-9, + } + ) + b_bound_call = pulse_sequence( + c=2, + length_g=1e-3, + length_dg=3e-3, + sigma_dg=0.4, + length_c=4e-3, + length_es=20e-9, + width_es=12e-9, ) - b_bound_call = pulse_sequence(c=2, length_g=1e-3, length_dg=3e-3, sigma_dg=0.4, length_c=4e-3) expected_str_b_bound = "\n".join( [ "OPENQASM 3.0;", @@ -177,6 +209,7 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined " waveform drag_gauss_wf = drag_gaussian(3.0ms, 400.0ms, 0.2, 1, false);", " waveform constant_wf = constant(4.0ms, 2.0 + 0.3im);", " waveform arb_wf = {1.0 + 0.4im, 0, 0.3, 0.1 + 0.2im};", + " waveform erf_square_wf = erf_square(20.0ns, 12.0ns, 2.0ns, 8.0ns, 1, false);", " set_frequency(predefined_frame_1, a + 4.0);", " shift_frequency(predefined_frame_1, a + 4.0);", " set_phase(predefined_frame_1, a + 4.0);", @@ -191,6 +224,7 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined " play(predefined_frame_2, drag_gauss_wf);", " play(predefined_frame_1, constant_wf);", " play(predefined_frame_2, arb_wf);", + " play(predefined_frame_1, erf_square_wf);", " psb[1] = capture_v0(predefined_frame_2);", "}", ] @@ -209,6 +243,7 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined " waveform drag_gauss_wf = drag_gaussian(3.0ms, 400.0ms, 0.2, 1, false);", " waveform constant_wf = constant(4.0ms, 2.0 + 0.3im);", " waveform arb_wf = {1.0 + 0.4im, 0, 0.3, 0.1 + 0.2im};", + " waveform erf_square_wf = erf_square(20.0ns, 12.0ns, 2.0ns, 8.0ns, 1, false);", " set_frequency(predefined_frame_1, 5.0);", " shift_frequency(predefined_frame_1, 5.0);", " set_phase(predefined_frame_1, 5.0);", @@ -223,6 +258,7 @@ def test_pulse_sequence_make_bound_pulse_sequence(predefined_frame_1, predefined " play(predefined_frame_2, drag_gauss_wf);", " play(predefined_frame_1, constant_wf);", " play(predefined_frame_2, arb_wf);", + " play(predefined_frame_1, erf_square_wf);", " psb[1] = capture_v0(predefined_frame_2);", "}", ] @@ -302,6 +338,16 @@ def test_pulse_sequence_to_ir(predefined_frame_1, predefined_frame_2): predefined_frame_2, ArbitraryWaveform([complex(1, 0.4), 0, 0.3, complex(0.1, 0.2)], id="arb_wf"), ) + .play( + predefined_frame_1, + ErfSquareWaveform( + length=32e-9, + width=20e-9, + sigma=2e-9, + off_center=8e-9, + id="erf_square_wf", + ), + ) .capture_v0(predefined_frame_2) ) expected_str = "\n".join( @@ -313,6 +359,7 @@ def test_pulse_sequence_to_ir(predefined_frame_1, predefined_frame_2): " waveform drag_gauss_wf = drag_gaussian(3.0ms, 400.0ms, 0.2, 1, false);", " waveform constant_wf = constant(4.0ms, 2.0 + 0.3im);", " waveform arb_wf = {1.0 + 0.4im, 0, 0.3, 0.1 + 0.2im};", + " waveform erf_square_wf = erf_square(32.0ns, 20.0ns, 2.0ns, 8.0ns, 1, false);", " set_frequency(predefined_frame_1, 3000000000.0);", " shift_frequency(predefined_frame_1, 1000000000.0);", " set_phase(predefined_frame_1, -0.5);", @@ -328,6 +375,7 @@ def test_pulse_sequence_to_ir(predefined_frame_1, predefined_frame_2): " play(predefined_frame_2, drag_gauss_wf);", " play(predefined_frame_1, constant_wf);", " play(predefined_frame_2, arb_wf);", + " play(predefined_frame_1, erf_square_wf);", " psb[1] = capture_v0(predefined_frame_2);", "}", ] diff --git a/test/unit_tests/braket/pulse/test_waveforms.py b/test/unit_tests/braket/pulse/test_waveforms.py index 636cb27af..5654762fa 100644 --- a/test/unit_tests/braket/pulse/test_waveforms.py +++ b/test/unit_tests/braket/pulse/test_waveforms.py @@ -304,26 +304,29 @@ def test_erf_square_waveform(): length = 4e-9 width = 0.3 sigma = 0.2 + off_center = 1e-9 amplitude = 0.4 zero_at_edges = False id = "erf_square_wf" - wf = ErfSquareWaveform(length, width, sigma, amplitude, zero_at_edges, id) + wf = ErfSquareWaveform(length, width, sigma, off_center, amplitude, zero_at_edges, id) assert wf.id == id assert wf.zero_at_edges == zero_at_edges assert wf.amplitude == amplitude assert wf.width == width assert wf.sigma == sigma assert wf.length == length + assert wf.off_center == off_center def test_erf_square_waveform_repr(): length = 4e-9 width = 0.3 sigma = 0.2 + off_center = 1e-9 amplitude = 0.4 zero_at_edges = False id = "erf_square_wf" - wf = ErfSquareWaveform(length, width, sigma, amplitude, zero_at_edges, id) + wf = ErfSquareWaveform(length, width, sigma, off_center, amplitude, zero_at_edges, id) repr(wf) @@ -331,20 +334,24 @@ def test_erf_square_waveform_default_params(): length = 4e-9 width = 0.3 sigma = 0.2 - wf = ErfSquareWaveform(length, width, sigma) + off_center = 1e-9 + wf = ErfSquareWaveform(length, width, sigma, off_center) assert re.match(r"[A-Za-z]{10}", wf.id) assert wf.zero_at_edges is False assert wf.amplitude == 1 assert wf.width == width assert wf.sigma == sigma assert wf.length == length + assert wf.off_center == off_center def test_erf_square_wf_eq(): - wf = ErfSquareWaveform(4e-9, 0.3, 0.2, 0.7, True, "wf_es") - wf_2 = ErfSquareWaveform(wf.length, wf.width, wf.sigma, wf.amplitude, wf.zero_at_edges, wf.id) + wf = ErfSquareWaveform(4e-9, 0.3, 0.2, 1e-9, 0.7, True, "wf_es") + wf_2 = ErfSquareWaveform( + wf.length, wf.width, wf.sigma, wf.off_center, wf.amplitude, wf.zero_at_edges, wf.id + ) assert wf_2 == wf - for att in ["length", "width", "sigma", "amplitude", "zero_at_edges", "id"]: + for att in ["length", "width", "sigma", "off_center", "amplitude", "zero_at_edges", "id"]: wfc = deepcopy(wf_2) setattr(wfc, att, "wrong_value") assert wf != wfc @@ -355,6 +362,7 @@ def test_erf_square_wf_free_params(): FreeParameter("length_v"), FreeParameter("width_x"), FreeParameter("sigma_y"), + FreeParameter("off_center_x"), FreeParameter("amp_z"), id="erf_square_wf", ) @@ -362,20 +370,29 @@ def test_erf_square_wf_free_params(): FreeParameter("length_v"), FreeParameter("width_x"), FreeParameter("sigma_y"), + FreeParameter("off_center_x"), FreeParameter("amp_z"), ] wf_2 = wf.bind_values(length_v=0.6, width_x=0.4) - assert wf_2.parameters == [0.6, 0.4, FreeParameter("sigma_y"), FreeParameter("amp_z")] + assert wf_2.parameters == [ + 0.6, + 0.4, + FreeParameter("sigma_y"), + FreeParameter("off_center_x"), + FreeParameter("amp_z"), + ] _assert_wf_qasm( wf_2, - "waveform erf_square_wf = erf_square(600.0ms, 400.0ms, sigma_y * 1s, amp_z, false);", + "waveform erf_square_wf = erf_square(600.0ms, 400.0ms, sigma_y * 1s, off_center_x * 1s," + " amp_z, false);", ) - wf_3 = wf.bind_values(length_v=0.6, width_x=0.3, sigma_y=0.1) - assert wf_3.parameters == [0.6, 0.3, 0.1, FreeParameter("amp_z")] + wf_3 = wf.bind_values(length_v=0.6, width_x=0.3, sigma_y=0.1, off_center_x=0.05) + assert wf_3.parameters == [0.6, 0.3, 0.1, 0.05, FreeParameter("amp_z")] _assert_wf_qasm( - wf_3, "waveform erf_square_wf = erf_square(600.0ms, 300.0ms, 100.0ms, amp_z, false);" + wf_3, + "waveform erf_square_wf = erf_square(600.0ms, 300.0ms, 100.0ms, 50.0ms, amp_z, false);", ) @@ -450,6 +467,7 @@ def _assert_wf_qasm(waveform, expected_qasm): {"name": "length", "value": 6.000000000000001e-8, "type": "float"}, {"name": "width", "value": 3.000000000000000e-8, "type": "float"}, {"name": "sigma", "value": 5.000000000060144e-9, "type": "float"}, + {"name": "off_center", "value": 4.000000000000000e-9, "type": "float"}, {"name": "amplitude", "value": 0.4549282253548838, "type": "float"}, ], }, @@ -458,6 +476,7 @@ def _assert_wf_qasm(waveform, expected_qasm): length=6.000000000000001e-8, width=3.000000000000000e-8, sigma=5.000000000060144e-9, + off_center=4.000000000000000e-9, amplitude=0.4549282253548838, ), ), From 7e478ce12596f433fc0dcfa04eff569b7f72b241 Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Mon, 26 Aug 2024 08:28:52 -0700 Subject: [PATCH 05/39] feat: Rigetti Ankaa (#1024) Co-authored-by: Tim --- src/braket/aws/aws_device.py | 1 + src/braket/devices/devices.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/braket/aws/aws_device.py b/src/braket/aws/aws_device.py index 041098f5a..598271424 100644 --- a/src/braket/aws/aws_device.py +++ b/src/braket/aws/aws_device.py @@ -76,6 +76,7 @@ class AwsDevice(Device): "Cz": "CZ", "Cphaseshift": "CPhaseShift", "Xy": "XY", + "Iswap": "ISwap", } def __init__( diff --git a/src/braket/devices/devices.py b/src/braket/devices/devices.py index 86a32a142..ff2529234 100644 --- a/src/braket/devices/devices.py +++ b/src/braket/devices/devices.py @@ -50,6 +50,7 @@ class _Rigetti(str, Enum): _AspenM1 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-1" _AspenM2 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-2" AspenM3 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + Ankaa2 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2" class _Xanadu(str, Enum): _Borealis = "arn:aws:braket:us-east-1::device/qpu/xanadu/Borealis" From 4f4f3a56d6210d54fb09235b6cb13bf879132bc2 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 26 Aug 2024 15:51:46 +0000 Subject: [PATCH 06/39] prepare release v1.86.0 --- CHANGELOG.md | 7 +++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd55752ab..d443de044 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v1.86.0 (2024-08-26) + +### Features + + * Rigetti Ankaa + * add off_center to erf_square + ## v1.85.0 (2024-08-20) ### Features diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 7ae9064d1..09c7a8289 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.85.1.dev0" +__version__ = "1.86.0" From 93f450b23f36b1455cad39543f6d4dda45284941 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 26 Aug 2024 15:51:46 +0000 Subject: [PATCH 07/39] update development version to v1.86.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 09c7a8289..518841c5e 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.86.0" +__version__ = "1.86.1.dev0" From 8f4e88f3a6389306fdfb6f64866b0eea9ebe8db4 Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Wed, 28 Aug 2024 12:16:04 -0700 Subject: [PATCH 08/39] fix: Use observable targets for targetless results (#1025) --- src/braket/circuits/result_type.py | 42 +++++++++---------- src/braket/circuits/result_types.py | 8 +--- .../braket/circuits/test_result_types.py | 19 +++++++++ 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/braket/circuits/result_type.py b/src/braket/circuits/result_type.py index 3e9f0dfad..a7ce2436c 100644 --- a/src/braket/circuits/result_type.py +++ b/src/braket/circuits/result_type.py @@ -209,32 +209,32 @@ def __init__( super().__init__(ascii_symbols) self._observable = observable self._target = QubitSet(target) - if not self._target: - if self._observable.qubit_count != 1: - raise ValueError( - f"Observable {self._observable} must only operate on 1 qubit for target=None" - ) - elif isinstance(observable, Sum): # nested target - if len(target) != len(observable.summands): - raise ValueError( - "Sum observable's target shape must be a nested list where each term's " - "target length is equal to the observable term's qubits count." - ) - self._target = [QubitSet(term_target) for term_target in target] - for term_target, obs in zip(self._target, observable.summands): - if obs.qubit_count != len(term_target): + if self._target: + if isinstance(observable, Sum): # nested target + if len(target) != len(observable.summands): raise ValueError( "Sum observable's target shape must be a nested list where each term's " "target length is equal to the observable term's qubits count." ) - elif self._observable.qubit_count != len(self._target): - raise ValueError( - f"Observable's qubit count {self._observable.qubit_count} and " - f"the size of the target qubit set {self._target} must be equal" - ) - elif self._observable.qubit_count != len(self.ascii_symbols): + self._target = [QubitSet(term_target) for term_target in target] + for term_target, obs in zip(self._target, observable.summands): + if obs.qubit_count != len(term_target): + raise ValueError( + "Sum observable's target shape must be a nested list where each term's " + "target length is equal to the observable term's qubits count." + ) + elif self._observable.qubit_count != len(self._target): + raise ValueError( + f"Observable's qubit count {self._observable.qubit_count} and " + f"the size of the target qubit set {self._target} must be equal" + ) + elif self._observable.qubit_count != len(self.ascii_symbols): + raise ValueError( + "Observable's qubit count and the number of ASCII symbols must be equal" + ) + elif (not self._observable.targets) and self._observable.qubit_count != 1: raise ValueError( - "Observable's qubit count and the number of ASCII symbols must be equal" + f"Observable {self._observable} must only operate on 1 qubit for target=None" ) @property diff --git a/src/braket/circuits/result_types.py b/src/braket/circuits/result_types.py index f682b9ba1..8af36ab4a 100644 --- a/src/braket/circuits/result_types.py +++ b/src/braket/circuits/result_types.py @@ -14,14 +14,12 @@ from __future__ import annotations import re -from functools import reduce from typing import Union import braket.ir.jaqcd as ir from braket.circuits import circuit from braket.circuits.free_parameter import FreeParameter from braket.circuits.observable import Observable -from braket.circuits.observables import Sum from braket.circuits.result_type import ( ObservableParameterResultType, ObservableResultType, @@ -210,11 +208,7 @@ def __init__( >>> parameters=["alpha", "beta"], >>> ) """ - if isinstance(observable, Sum): - target_qubits = reduce(QubitSet.union, map(QubitSet, target), QubitSet()) - else: - target_qubits = QubitSet(target) - + target_qubits = QubitSet(target if target is not None else observable.targets) super().__init__( ascii_symbols=[f"AdjointGradient({observable.ascii_symbols[0]})"] * len(target_qubits), observable=observable, diff --git a/test/unit_tests/braket/circuits/test_result_types.py b/test/unit_tests/braket/circuits/test_result_types.py index 5f76eeaf9..422fed7a4 100644 --- a/test/unit_tests/braket/circuits/test_result_types.py +++ b/test/unit_tests/braket/circuits/test_result_types.py @@ -272,6 +272,25 @@ def test_ir_result_level(testclass, subroutine_name, irclass, input, ir_input): "#pragma braket result adjoint_gradient expectation(hermitian([[1+0im, 0im], " "[0im, 1+0im]]) q[0]) all", ), + ( + ResultType.AdjointGradient( + Observable.H(0) @ Observable.I(1) + 2 * Observable.Z(2), + parameters=[FreeParameter("alpha"), "beta", FreeParameter("gamma")], + ), + OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), + "#pragma braket result adjoint_gradient expectation(h(q[0]) @ i(q[1]) + 2 * z(q[2])) " + "alpha, beta, gamma", + ), + ( + ResultType.AdjointGradient( + Observable.H(0) @ Observable.I(1) + 2 * Observable.Z(2), + target=[[3, 4], [5]], + parameters=[FreeParameter("alpha"), "beta", FreeParameter("gamma")], + ), + OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL), + "#pragma braket result adjoint_gradient expectation(h(q[3]) @ i(q[4]) + 2 * z(q[5])) " + "alpha, beta, gamma", + ), ], ) def test_result_to_ir_openqasm(result_type, serialization_properties, expected_ir): From 6cad46ee5a783ae9030917aebe016056328f10f0 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 29 Aug 2024 16:15:40 +0000 Subject: [PATCH 09/39] prepare release v1.86.1 --- CHANGELOG.md | 6 ++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d443de044..3fc1c64ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.86.1 (2024-08-29) + +### Bug Fixes and Other Changes + + * Use observable targets for targetless results + ## v1.86.0 (2024-08-26) ### Features diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 518841c5e..025231973 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.86.1.dev0" +__version__ = "1.86.1" From cbe7fc9809bce43ca2e98d0daabe7126aae41f20 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 29 Aug 2024 16:15:40 +0000 Subject: [PATCH 10/39] update development version to v1.86.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 025231973..a660f1729 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.86.1" +__version__ = "1.86.2.dev0" From 2d57c5ff9a1e92e1e4198903f499381eb8b3c52d Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Tue, 3 Sep 2024 16:45:34 -0700 Subject: [PATCH 11/39] change: Return observable target if absent for RT (#1026) --- src/braket/circuits/circuit.py | 4 ++-- src/braket/circuits/observable.py | 12 +++++------- src/braket/circuits/observables.py | 12 ++++++------ src/braket/circuits/result_type.py | 2 +- src/braket/circuits/result_types.py | 8 ++++---- test/unit_tests/braket/circuits/test_result_type.py | 10 ++++++++++ 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index 9ce7df7f8..02d419cff 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -319,8 +319,8 @@ def add_result_type( observable = Circuit._extract_observable(result_type_to_add) # We can skip this for now for AdjointGradient (the only subtype of this # type) because AdjointGradient can only be used when `shots=0`, and the - # qubit_observable_mapping is used to generate basis rotation instrunctions - # and make sure the observables are simultaneously commuting for `shots>0` mode. + # qubit_observable_mapping is used to generate basis rotation instructions + # and make sure the observables mutually commute for `shots>0` mode. supports_basis_rotation_instructions = not isinstance( result_type_to_add, ObservableParameterResultType ) diff --git a/src/braket/circuits/observable.py b/src/braket/circuits/observable.py index 11ed02eb6..e0572e3d9 100644 --- a/src/braket/circuits/observable.py +++ b/src/braket/circuits/observable.py @@ -40,20 +40,18 @@ def __init__( self, qubit_count: int, ascii_symbols: Sequence[str], targets: QubitSetInput | None = None ): super().__init__(qubit_count=qubit_count, ascii_symbols=ascii_symbols) - if targets is not None: - targets = QubitSet(targets) + targets = QubitSet(targets) + if targets: if (num_targets := len(targets)) != qubit_count: raise ValueError( f"Length of target {num_targets} does not match qubit count {qubit_count}" ) - self._targets = targets - else: - self._targets = None + self._targets = targets self._coef = 1 def _unscaled(self) -> Observable: return Observable( - qubit_count=self.qubit_count, ascii_symbols=self.ascii_symbols, targets=self.targets + qubit_count=self.qubit_count, ascii_symbols=self.ascii_symbols, targets=self._targets ) def to_ir( @@ -207,7 +205,7 @@ def __sub__(self, other: Observable): def __repr__(self) -> str: return ( f"{self.name}('qubit_count': {self._qubit_count})" - if self._targets is None + if not self._targets else f"{self.name}('qubit_count': {self._qubit_count}, 'target': {self._targets})" ) diff --git a/src/braket/circuits/observables.py b/src/braket/circuits/observables.py index 9346435a2..8249d156f 100644 --- a/src/braket/circuits/observables.py +++ b/src/braket/circuits/observables.py @@ -322,9 +322,9 @@ def __init__(self, observables: list[Observable]): f"{'@'.join([obs.ascii_symbols[0] for obs in unscaled_factors])}" ) all_targets = [factor.targets for factor in unscaled_factors] - if all(targets is None for targets in all_targets): - merged_targets = None - elif all(targets is not None for targets in all_targets): + if not any(all_targets): + merged_targets = QubitSet() + elif all(all_targets): flat_targets = [qubit for target in all_targets for qubit in target] merged_targets = QubitSet(flat_targets) if len(merged_targets) != len(flat_targets): @@ -508,9 +508,9 @@ def __init__(self, observables: list[Observable], display_name: str = "Hamiltoni self._summands = tuple(flattened_observables) qubit_count = max(flattened_observables, key=lambda obs: obs.qubit_count).qubit_count all_targets = [observable.targets for observable in flattened_observables] - if all(targets is None for targets in all_targets): - targets = None - elif all(targets is not None for targets in all_targets): + if not any(all_targets): + targets = QubitSet() + elif all(all_targets): targets = all_targets else: raise ValueError("Cannot mix terms with and without targets") diff --git a/src/braket/circuits/result_type.py b/src/braket/circuits/result_type.py index a7ce2436c..8343429e0 100644 --- a/src/braket/circuits/result_type.py +++ b/src/braket/circuits/result_type.py @@ -243,7 +243,7 @@ def observable(self) -> Observable: @property def target(self) -> QubitSet: - return self._target + return self._target or self._observable.targets @target.setter def target(self, target: QubitSetInput) -> None: diff --git a/src/braket/circuits/result_types.py b/src/braket/circuits/result_types.py index 8af36ab4a..6c1232b06 100644 --- a/src/braket/circuits/result_types.py +++ b/src/braket/circuits/result_types.py @@ -218,7 +218,7 @@ def __init__( def _to_openqasm(self, serialization_properties: OpenQASMSerializationProperties) -> str: observable_ir = self.observable.to_ir( - target=self.target, + target=self._target, ir_type=IRType.OPENQASM, serialization_properties=serialization_properties, ) @@ -477,7 +477,7 @@ def _to_jaqcd(self) -> ir.Expectation: def _to_openqasm(self, serialization_properties: OpenQASMSerializationProperties) -> str: observable_ir = self.observable.to_ir( - target=self.target, + target=self._target, ir_type=IRType.OPENQASM, serialization_properties=serialization_properties, ) @@ -552,7 +552,7 @@ def _to_jaqcd(self) -> ir.Sample: def _to_openqasm(self, serialization_properties: OpenQASMSerializationProperties) -> str: observable_ir = self.observable.to_ir( - target=self.target, + target=self._target, ir_type=IRType.OPENQASM, serialization_properties=serialization_properties, ) @@ -632,7 +632,7 @@ def _to_jaqcd(self) -> ir.Variance: def _to_openqasm(self, serialization_properties: OpenQASMSerializationProperties) -> str: observable_ir = self.observable.to_ir( - target=self.target, + target=self._target, ir_type=IRType.OPENQASM, serialization_properties=serialization_properties, ) diff --git a/test/unit_tests/braket/circuits/test_result_type.py b/test/unit_tests/braket/circuits/test_result_type.py index bc7cc0909..bb543b7c0 100644 --- a/test/unit_tests/braket/circuits/test_result_type.py +++ b/test/unit_tests/braket/circuits/test_result_type.py @@ -18,6 +18,7 @@ from braket.circuits.free_parameter import FreeParameter from braket.circuits.result_type import ObservableParameterResultType from braket.circuits.serialization import IRType +from braket.registers import QubitSet @pytest.fixture @@ -168,6 +169,15 @@ def test_obs_rt_repr(): ) +def test_obs_rt_target(): + assert ObservableResultType( + ascii_symbols=["Obs"], observable=Observable.X(), target=1 + ).target == QubitSet(1) + assert ObservableResultType( + ascii_symbols=["Obs"], observable=Observable.X(1) + ).target == QubitSet(1) + + @pytest.mark.parametrize( "ir_type, serialization_properties, expected_exception, expected_message", [ From 1f6bf0fc83040da58dae1f242a29fc9acf92ab61 Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Wed, 4 Sep 2024 14:45:52 -0700 Subject: [PATCH 12/39] deprecation: Retire IonQ Harmony (#1030) --- src/braket/devices/devices.py | 2 +- test/integ_tests/test_device_creation.py | 2 +- test/integ_tests/test_measure.py | 2 +- test/integ_tests/test_reservation_arn.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/braket/devices/devices.py b/src/braket/devices/devices.py index ff2529234..0af058d42 100644 --- a/src/braket/devices/devices.py +++ b/src/braket/devices/devices.py @@ -31,7 +31,7 @@ class _IQM(str, Enum): Garnet = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet" class _IonQ(str, Enum): - Harmony = "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + _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" diff --git a/test/integ_tests/test_device_creation.py b/test/integ_tests/test_device_creation.py index c7183c3e6..2b718c211 100644 --- a/test/integ_tests/test_device_creation.py +++ b/test/integ_tests/test_device_creation.py @@ -18,7 +18,7 @@ from braket.devices import Devices 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" +IONQ_ARN = "arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1" IQM_ARN = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet" SIMULATOR_ARN = "arn:aws:braket:::device/quantum-simulator/amazon/sv1" PULSE_ARN = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" diff --git a/test/integ_tests/test_measure.py b/test/integ_tests/test_measure.py index 9c8fdc02c..8fd72e6bf 100644 --- a/test/integ_tests/test_measure.py +++ b/test/integ_tests/test_measure.py @@ -23,7 +23,7 @@ DEVICE = LocalSimulator() SHOTS = 8000 -IONQ_ARN = "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" +IONQ_ARN = "arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1" SIMULATOR_ARN = "arn:aws:braket:::device/quantum-simulator/amazon/sv1" IQM_ARN = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet" diff --git a/test/integ_tests/test_reservation_arn.py b/test/integ_tests/test_reservation_arn.py index 64135f76e..57833a840 100644 --- a/test/integ_tests/test_reservation_arn.py +++ b/test/integ_tests/test_reservation_arn.py @@ -33,7 +33,7 @@ def reservation_arn(aws_session): def test_create_task_via_invalid_reservation_arn_on_qpu(reservation_arn): circuit = Circuit().h(0) - device = AwsDevice(Devices.IonQ.Harmony) + device = AwsDevice(Devices.IonQ.Aria1) with pytest.raises(ClientError, match="Reservation arn is invalid"): device.run(circuit, shots=10, reservation_arn=reservation_arn) From 6236d632560c87cd19f5bda511c5035f07601c05 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 5 Sep 2024 18:38:00 +0000 Subject: [PATCH 13/39] prepare release v1.87.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 3fc1c64ef..18bde840f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.87.0 (2024-09-05) + +### Deprecations and Removals + + * Retire IonQ Harmony + +### Bug Fixes and Other Changes + + * Return observable target if absent for RT + ## v1.86.1 (2024-08-29) ### Bug Fixes and Other Changes diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index a660f1729..7f61b52dd 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.86.2.dev0" +__version__ = "1.87.0" From 42d0ef8fc275b0dfbb560ac573846192a20e1587 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 5 Sep 2024 18:38:00 +0000 Subject: [PATCH 14/39] update development version to v1.87.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 7f61b52dd..2deedb28a 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.87.0" +__version__ = "1.87.1.dev0" From 2ddb3d2c1663befe4f004020ab50e6514efdba8d Mon Sep 17 00:00:00 2001 From: Abe Coull <85974725+math411@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:29:30 -0700 Subject: [PATCH 15/39] infra: update to cloudpickle 3.x (#1032) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bf429b266..45cc590bd 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ "backoff", "boltons", "boto3>=1.28.53", - "cloudpickle==2.2.1", + "cloudpickle>=3", "nest-asyncio", "networkx", "numpy", From fd597d6d1fe2f38dc14e7e2fbf6a72657cf0f3b5 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:43:07 -0400 Subject: [PATCH 16/39] fix: Pass through inputs for SerializableProgram simulation (#1033) --- src/braket/devices/local_simulator.py | 5 +++-- .../braket/devices/test_local_simulator.py | 21 +++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/braket/devices/local_simulator.py b/src/braket/devices/local_simulator.py index 02b379596..f9e70a1ea 100644 --- a/src/braket/devices/local_simulator.py +++ b/src/braket/devices/local_simulator.py @@ -290,8 +290,9 @@ def _(self, program: OpenQASMProgram, inputs: Optional[dict[str, float]], _shots return program @_construct_payload.register - def _(self, program: SerializableProgram, _inputs, _shots): - return OpenQASMProgram(source=program.to_ir(ir_type=IRType.OPENQASM)) + def _(self, program: SerializableProgram, inputs: Optional[dict[str, float]], _shots): + inputs_copy = inputs.copy() if inputs is not None else {} + return OpenQASMProgram(source=program.to_ir(ir_type=IRType.OPENQASM), inputs=inputs_copy) @_construct_payload.register def _(self, program: AnalogHamiltonianSimulation, _inputs, _shots): diff --git a/test/unit_tests/braket/devices/test_local_simulator.py b/test/unit_tests/braket/devices/test_local_simulator.py index 451553f02..6c2976812 100644 --- a/test/unit_tests/braket/devices/test_local_simulator.py +++ b/test/unit_tests/braket/devices/test_local_simulator.py @@ -588,10 +588,8 @@ def test_run_serializable_program_model(): source=""" qubit[2] q; bit[2] c; - h q[0]; cnot q[0], q[1]; - c = measure q; """ ) @@ -599,6 +597,25 @@ def test_run_serializable_program_model(): assert task.result() == GateModelQuantumTaskResult.from_object(GATE_MODEL_RESULT) +def test_run_serializable_program_model_with_inputs(): + dummy = DummySerializableProgramSimulator() + sim = LocalSimulator(dummy) + task = sim.run( + DummySerializableProgram( + source=""" +input float a; +qubit[2] q; +bit[2] c; +h q[0]; +cnot q[0], q[1]; +c = measure q; +""" + ), + inputs={"a": 0.1}, + ) + assert task.result() == GateModelQuantumTaskResult.from_object(GATE_MODEL_RESULT) + + @pytest.mark.xfail(raises=ValueError) def test_run_gate_model_value_error(): dummy = DummyCircuitSimulator() From d3c0ec262e1667d7d90638401d2070b0c85700b1 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 23 Sep 2024 21:12:42 +0000 Subject: [PATCH 17/39] prepare release v1.87.1 --- CHANGELOG.md | 6 ++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18bde840f..1a7be1b4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.87.1 (2024-09-23) + +### Bug Fixes and Other Changes + + * Pass through inputs for SerializableProgram simulation + ## v1.87.0 (2024-09-05) ### Deprecations and Removals diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 2deedb28a..f716aaca9 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.87.1.dev0" +__version__ = "1.87.1" From d45958b774757274f2cb6008eaf049bf1ee1d644 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 23 Sep 2024 21:12:42 +0000 Subject: [PATCH 18/39] update development version to v1.87.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 f716aaca9..33c9067cd 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.87.1" +__version__ = "1.87.2.dev0" From b076fdad598a7603f66778528645715566711773 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:12:04 -0400 Subject: [PATCH 19/39] deprecation: Mark Aspen-M-3 as deprecated, replace with Ankaa-2 in tests (#1034) --- README.md | 2 +- src/braket/devices/devices.py | 2 +- test/integ_tests/test_cost_tracking.py | 2 +- test/integ_tests/test_device_creation.py | 4 ++-- test/integ_tests/test_pulse.py | 2 +- test/unit_tests/braket/aws/common_test_utils.py | 2 +- test/unit_tests/braket/aws/test_aws_device.py | 4 ++-- test/unit_tests/braket/aws/test_aws_quantum_job.py | 2 +- test/unit_tests/braket/jobs/test_quantum_job_creation.py | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 415a18c25..3c3e85d51 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ import boto3 from braket.circuits import Circuit from braket.aws import AwsDevice -device = AwsDevice("arn:aws:braket:::device/qpu/rigetti/Aspen-8") +device = AwsDevice("arn:aws:braket:::device/qpu/rigetti/Ankaa-2") bell = Circuit().h(0).cnot(0, 1) task = device.run(bell) diff --git a/src/braket/devices/devices.py b/src/braket/devices/devices.py index 0af058d42..44d6edb13 100644 --- a/src/braket/devices/devices.py +++ b/src/braket/devices/devices.py @@ -49,7 +49,7 @@ class _Rigetti(str, Enum): _Aspen11 = "arn:aws:braket:::device/qpu/rigetti/Aspen-11" _AspenM1 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-1" _AspenM2 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-2" - AspenM3 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + _AspenM3 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" Ankaa2 = "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2" class _Xanadu(str, Enum): diff --git a/test/integ_tests/test_cost_tracking.py b/test/integ_tests/test_cost_tracking.py index f493c9779..c2c590331 100644 --- a/test/integ_tests/test_cost_tracking.py +++ b/test/integ_tests/test_cost_tracking.py @@ -29,7 +29,7 @@ [ "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet", - "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2", ], ) def test_qpu_tracking(qpu): diff --git a/test/integ_tests/test_device_creation.py b/test/integ_tests/test_device_creation.py index 2b718c211..58bdb35a1 100644 --- a/test/integ_tests/test_device_creation.py +++ b/test/integ_tests/test_device_creation.py @@ -17,11 +17,11 @@ from braket.aws import AwsDevice from braket.devices import Devices -RIGETTI_ARN = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" +RIGETTI_ARN = "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2" IONQ_ARN = "arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1" IQM_ARN = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet" SIMULATOR_ARN = "arn:aws:braket:::device/quantum-simulator/amazon/sv1" -PULSE_ARN = "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" +PULSE_ARN = "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2" @pytest.mark.parametrize( diff --git a/test/integ_tests/test_pulse.py b/test/integ_tests/test_pulse.py index 4eb3ffa93..5f6c7b5d1 100644 --- a/test/integ_tests/test_pulse.py +++ b/test/integ_tests/test_pulse.py @@ -11,7 +11,7 @@ @pytest.fixture def device(): - return AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3") + return AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2") @pytest.fixture diff --git a/test/unit_tests/braket/aws/common_test_utils.py b/test/unit_tests/braket/aws/common_test_utils.py index aaca559f5..0e1fd4d48 100644 --- a/test/unit_tests/braket/aws/common_test_utils.py +++ b/test/unit_tests/braket/aws/common_test_utils.py @@ -17,7 +17,7 @@ from braket.aws import AwsQuantumTaskBatch DWAVE_ARN = "arn:aws:braket:::device/qpu/d-wave/Advantage_system1" -RIGETTI_ARN = "arn:aws:braket:::device/qpu/rigetti/Aspen-10" +RIGETTI_ARN = "arn:aws:braket:::device/qpu/rigetti/Ankaa-2" IONQ_ARN = "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" OQC_ARN = "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" SV1_ARN = "arn:aws:braket:::device/quantum-simulator/amazon/sv1" diff --git a/test/unit_tests/braket/aws/test_aws_device.py b/test/unit_tests/braket/aws/test_aws_device.py index a778dfb5f..3fed52aa2 100644 --- a/test/unit_tests/braket/aws/test_aws_device.py +++ b/test/unit_tests/braket/aws/test_aws_device.py @@ -216,7 +216,7 @@ def test_mock_rigetti_schema_1(): MOCK_GATE_MODEL_QPU_1 = { - "deviceName": "Aspen-10", + "deviceName": "Ankaa-2", "deviceType": "QPU", "providerName": "Rigetti", "deviceStatus": "OFFLINE", @@ -1451,7 +1451,7 @@ def test_run_device_poll_interval_kwargs( capabilities = MOCK_GATE_MODEL_QPU_CAPABILITIES_1 capabilities.service.getTaskPollIntervalMillis = poll_interval_seconds properties = { - "deviceName": "Aspen-10", + "deviceName": "Ankaa-2", "deviceType": "QPU", "providerName": "provider1", "deviceStatus": "OFFLINE", 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 67ca98228..028ad3cc4 100644 --- a/test/unit_tests/braket/aws/test_aws_quantum_job.py +++ b/test/unit_tests/braket/aws/test_aws_quantum_job.py @@ -70,7 +70,7 @@ def _get_job_response(**kwargs): }, "createdAt": datetime.datetime(2021, 6, 28, 21, 4, 51), "deviceConfig": { - "device": "arn:aws:braket:::device/qpu/rigetti/Aspen-10", + "device": "arn:aws:braket:::device/qpu/rigetti/Ankaa-2", }, "hyperParameters": { "foo": "bar", 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 d12a29b00..39cb94c5d 100644 --- a/test/unit_tests/braket/jobs/test_quantum_job_creation.py +++ b/test/unit_tests/braket/jobs/test_quantum_job_creation.py @@ -198,7 +198,7 @@ def _get_job_response(**kwargs): }, "createdAt": datetime.datetime(2021, 6, 28, 21, 4, 51), "deviceConfig": { - "device": "arn:aws:braket:::device/qpu/rigetti/Aspen-10", + "device": "arn:aws:braket:::device/qpu/rigetti/Ankaa-2", }, "hyperParameters": { "foo": "bar", From 71dc33b2769f547690c7ef6962858eb3b917fa6d Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:32:38 -0400 Subject: [PATCH 20/39] fix: Update pulse integration tests for Ankaa-2 device (#1035) --- test/integ_tests/test_pulse.py | 63 +++++++++++++++------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/test/integ_tests/test_pulse.py b/test/integ_tests/test_pulse.py index 5f6c7b5d1..e5f42bcd3 100644 --- a/test/integ_tests/test_pulse.py +++ b/test/integ_tests/test_pulse.py @@ -174,7 +174,7 @@ def h_gate(q0): return Circuit().rz(q0, np.pi).rx(q0, np.pi / 2).rz(q0, np.pi / 2).rx(q0, -np.pi / 2) -def cz_pulse( +def make_pulse( q0: str, q1: str, shift_phases_q0: float, @@ -182,30 +182,22 @@ def cz_pulse( waveform: ArbitraryWaveform, device: AwsDevice, ): - q0_rf_frame = device.frames[f"q{q0}_rf_frame"] - q1_rf_frame = device.frames[f"q{q1}_rf_frame"] - q0_q1_cz_frame = device.frames[f"q{q0}_q{q1}_cz_frame"] - frames = [q0_rf_frame, q1_rf_frame, q0_q1_cz_frame] + q0_drive_frame = device.frames[f"Transmon_{q0}_charge_tx"] + q1_drive_frame = device.frames[f"Transmon_{q1}_charge_tx"] + frames = [q0_drive_frame, q1_drive_frame] - dt = device.properties.pulse.ports[q0_q1_cz_frame.port.id].dt + dt = device.properties.pulse.ports[q0_drive_frame.port.id].dt wfm_duration = len(waveform.amplitudes) * dt pulse_sequence = ( PulseSequence() .barrier(frames) - .play(q0_q1_cz_frame, waveform) - .delay(q0_rf_frame, wfm_duration) - .shift_phase(q0_rf_frame, shift_phases_q0) - .delay(q1_rf_frame, wfm_duration) - .shift_phase(q1_rf_frame, shift_phases_q1) + .delay(q0_drive_frame, wfm_duration) + .shift_phase(q0_drive_frame, shift_phases_q0) + .delay(q1_drive_frame, wfm_duration) + .shift_phase(q1_drive_frame, shift_phases_q1) .barrier(frames) ) - for phase, q in [(shift_phases_q0 * 0.5, q0), (-shift_phases_q1 * 0.5, q1)]: - for neighbor in device.properties.paradigm.connectivity.connectivityGraph[str(q)]: - xy_frame_name = f"q{min(q, int(neighbor))}_q{max(q, int(neighbor))}_xy_frame" - if xy_frame_name in device.frames: - xy_frame = device.frames[xy_frame_name] - pulse_sequence.shift_phase(xy_frame, phase) return pulse_sequence @@ -216,17 +208,17 @@ def test_pulse_bell(arbitrary_waveform, device): a, b, ) = ( - 10, - 113, + 26, + 33, ) # qubits used p0, p1 = 1.1733407221086924, 6.269846678712192 theta_0, theta_1 = FreeParameter("theta_0"), FreeParameter("theta_1") - a_b_cz_waveform = arbitrary_waveform - cz = cz_pulse(a, b, theta_0, theta_1, a_b_cz_waveform, device) + a_b_waveform = arbitrary_waveform + pulse = make_pulse(a, b, theta_0, theta_1, a_b_waveform, device) - bell_pair_with_gates = Circuit().h(a).h(b).cz(a, b).h(b) + bell_pair_with_gates = Circuit().h(a).h(b).iswap(a, b).h(b) bell_pair_with_pulses_unbound = ( - h_gate(a) + h_gate(b) + Circuit().pulse_gate([a, b], cz) + h_gate(b) + h_gate(a) + h_gate(b) + Circuit().pulse_gate([a, b], pulse) + h_gate(b) ) bell_pair_with_pulses = bell_pair_with_pulses_unbound(theta_0=p0, theta_1=p1) @@ -266,27 +258,27 @@ def test_pulse_sequence(arbitrary_waveform, device): a, b, ) = ( - 10, - 113, + 26, + 33, ) # qubits used p0, p1 = 1.1733407221086924, 6.269846678712192 theta_0, theta_1 = FreeParameter("theta_0"), FreeParameter("theta_1") - a_b_cz_waveform = arbitrary_waveform + a_b_waveform = arbitrary_waveform - cz_with_pulses_unbound = cz_pulse(a, b, theta_0, theta_1, a_b_cz_waveform, device) + pulse_unbound = make_pulse(a, b, theta_0, theta_1, a_b_waveform, device) - q0_readout_frame = device.frames[f"q{a}_ro_rx_frame"] - q1_readout_frame = device.frames[f"q{b}_ro_rx_frame"] - cz_with_pulses = ( - cz_with_pulses_unbound(theta_0=p0, theta_1=p1) + q0_readout_frame = device.frames[f"Transmon_{a}_readout_rx"] + q1_readout_frame = device.frames[f"Transmon_{b}_readout_rx"] + pulses = ( + pulse_unbound(theta_0=p0, theta_1=p1) .capture_v0(q0_readout_frame) .capture_v0(q1_readout_frame) ) - cz_with_gates = Circuit().cz(a, b) + circuit_with_gates = Circuit().iswap(a, b) num_shots = 1000 - gate_task = device.run(cz_with_gates, shots=num_shots, disable_qubit_rewiring=True) - pulse_task = device.run(cz_with_pulses, shots=num_shots) + gate_task = device.run(circuit_with_gates, shots=num_shots, disable_qubit_rewiring=True) + pulse_task = device.run(pulses, shots=num_shots) if not device.is_available: try: @@ -313,12 +305,13 @@ def test_pulse_sequence(arbitrary_waveform, device): assert chi_squared < 10 # adjust this threshold if test is flaky +@pytest.mark.skip(reason="needs to be updated to work correctly on Ankaa-2") def test_gate_calibration_run(device, pulse_sequence): if device.status == "OFFLINE": pytest.skip("Device offline") user_gate_calibrations = GateCalibrations({(Gate.Rx(math.pi / 2), QubitSet(0)): pulse_sequence}) num_shots = 50 - bell_circuit = Circuit().rx(0, math.pi / 2).rx(1, math.pi / 2).cz(0, 1).rx(1, -math.pi / 2) + bell_circuit = Circuit().rx(0, math.pi / 2).rx(1, math.pi / 2).iswap(0, 1).rx(1, -math.pi / 2) user_calibration_task = device.run( bell_circuit, gate_definitions=user_gate_calibrations.pulse_sequences, From 5870ea64d8f5785207bda300b037f98703f2696e Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 27 Sep 2024 20:47:30 +0000 Subject: [PATCH 21/39] prepare release v1.88.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 1a7be1b4f..e23ddae20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.88.0 (2024-09-27) + +### Deprecations and Removals + + * Mark Aspen-M-3 as deprecated, replace with Ankaa-2 in tests + +### Bug Fixes and Other Changes + + * Update pulse integration tests for Ankaa-2 device + ## v1.87.1 (2024-09-23) ### Bug Fixes and Other Changes diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 33c9067cd..4c391e2c1 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.87.2.dev0" +__version__ = "1.88.0" From 43d0c7ebe64a9871416bcac16fbb6085ca4beb7d Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 27 Sep 2024 20:47:30 +0000 Subject: [PATCH 22/39] update development version to v1.88.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 4c391e2c1..a4bd9b268 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.88.0" +__version__ = "1.88.1.dev0" From 5534034b3091d221b338b044f55610266b020fb3 Mon Sep 17 00:00:00 2001 From: Abe Coull <85974725+math411@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:52:04 -0700 Subject: [PATCH 23/39] =?UTF-8?q?infra:=20remove=20doc=20dependencies=20fr?= =?UTF-8?q?om=20the=20test=20list=20and=20add=20to=20their=20ow=E2=80=A6?= =?UTF-8?q?=20(#1037)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Coull --- setup.py | 6 ++++-- tox.ini | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 45cc590bd..18bc591e1 100644 --- a/setup.py +++ b/setup.py @@ -55,11 +55,13 @@ "pytest-cov", "pytest-rerunfailures", "pytest-xdist[psutil]", + "tox", + ], + "docs": [ "sphinx", "sphinx-rtd-theme", "sphinxcontrib-apidoc", - "tox", - ] + ], }, include_package_data=True, url="https://github.com/amazon-braket/amazon-braket-sdk-python", diff --git a/tox.ini b/tox.ini index 95c862106..f8da75234 100644 --- a/tox.ini +++ b/tox.ini @@ -107,11 +107,9 @@ commands = basepython = python3 deps = {[test-deps]deps} - sphinx - sphinx-rtd-theme - sphinxcontrib-apidoc commands = sphinx-build -E -T -b html doc build/documentation/html -j auto +extras = docs [testenv:serve-docs] basepython = python3 From 36e32f63d33a97b8b17addb0e90b692cda93b4ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 13:07:00 -0400 Subject: [PATCH 24/39] infra: bump pypa/gh-action-pypi-publish from 1.9.0 to 1.10.0 (#1027) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ryan Shaffer <3620100+rmshaffer@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 942974db7..00d746acb 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@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # release/v1 + uses: pypa/gh-action-pypi-publish@8a08d616893759ef8e1aa1f2785787c0b97e20d6 # release/v1 with: password: ${{ secrets.pypi_token }} From cc3698cc6d92e2fda18f6be951cabea5dc3fb6bf Mon Sep 17 00:00:00 2001 From: Abe Coull <85974725+math411@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:48:49 -0700 Subject: [PATCH 25/39] fix: correct typing for task results methods (#1039) --- .coveragerc | 5 ++++ src/braket/aws/aws_quantum_task_batch.py | 29 ++++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/.coveragerc b/.coveragerc index fe9662c0a..22cb4caeb 100644 --- a/.coveragerc +++ b/.coveragerc @@ -32,6 +32,11 @@ exclude_lines = # Avoid situation where system version causes coverage issues if sys.version_info.minor == 9: + # Avoid type checking import conditionals + if TYPE_CHECKING: + + + [html] directory = build/coverage diff --git a/src/braket/aws/aws_quantum_task_batch.py b/src/braket/aws/aws_quantum_task_batch.py index 300963a6f..30c3a8658 100644 --- a/src/braket/aws/aws_quantum_task_batch.py +++ b/src/braket/aws/aws_quantum_task_batch.py @@ -16,7 +16,7 @@ import time from concurrent.futures.thread import ThreadPoolExecutor from itertools import repeat -from typing import Any, Union +from typing import TYPE_CHECKING, Any, Union from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation from braket.annealing import Problem @@ -30,6 +30,14 @@ from braket.registers.qubit_set import QubitSet from braket.tasks.quantum_task_batch import QuantumTaskBatch +if TYPE_CHECKING: + from braket.tasks.analog_hamiltonian_simulation_quantum_task_result import ( + AnalogHamiltonianSimulationQuantumTaskResult, + ) + from braket.tasks.annealing_quantum_task_result import AnnealingQuantumTaskResult + from braket.tasks.gate_model_quantum_task_result import GateModelQuantumTaskResult + from braket.tasks.photonic_model_quantum_task_result import PhotonicModelQuantumTaskResult + class AwsQuantumTaskBatch(QuantumTaskBatch): """Executes a batch of quantum tasks in parallel. @@ -331,7 +339,12 @@ def results( fail_unsuccessful: bool = False, max_retries: int = MAX_RETRIES, use_cached_value: bool = True, - ) -> list[AwsQuantumTask]: + ) -> list[ + GateModelQuantumTaskResult + | AnnealingQuantumTaskResult + | PhotonicModelQuantumTaskResult + | AnalogHamiltonianSimulationQuantumTaskResult + ]: """Retrieves the result of every quantum task in the batch. Polling for results happens in parallel; this method returns when all quantum tasks @@ -348,7 +361,8 @@ def results( even when results have already been cached. Default: `True`. Returns: - list[AwsQuantumTask]: The results of all of the quantum tasks in the batch. + list[GateModelQuantumTaskResult | AnnealingQuantumTaskResult | PhotonicModelQuantumTaskResult | AnalogHamiltonianSimulationQuantumTaskResult]: The # noqa: E501 + results of all of the quantum tasks in the batch. `FAILED`, `CANCELLED`, or timed out quantum tasks will have a result of None """ if not self._results or not use_cached_value: @@ -369,7 +383,14 @@ def results( return self._results @staticmethod - def _retrieve_results(tasks: list[AwsQuantumTask], max_workers: int) -> list[AwsQuantumTask]: + def _retrieve_results( + tasks: list[AwsQuantumTask], max_workers: int + ) -> list[ + GateModelQuantumTaskResult + | AnnealingQuantumTaskResult + | PhotonicModelQuantumTaskResult + | AnalogHamiltonianSimulationQuantumTaskResult + ]: with ThreadPoolExecutor(max_workers=max_workers) as executor: result_futures = [executor.submit(task.result) for task in tasks] return [future.result() for future in result_futures] From 447c87d2fa648937bc8331f790a0b9fc6959e520 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 21 Oct 2024 16:14:56 +0000 Subject: [PATCH 26/39] prepare release v1.88.1 --- CHANGELOG.md | 6 ++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e23ddae20..34565b899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.88.1 (2024-10-21) + +### Bug Fixes and Other Changes + + * correct typing for task results methods + ## v1.88.0 (2024-09-27) ### Deprecations and Removals diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index a4bd9b268..0020ca15e 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.88.1.dev0" +__version__ = "1.88.1" From 90ca19645e91d949d9c38c133d4a899118384c25 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 21 Oct 2024 16:14:56 +0000 Subject: [PATCH 27/39] update development version to v1.88.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 0020ca15e..86ce67991 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.88.1" +__version__ = "1.88.2.dev0" From a7348c681bc97e10c14edf69196f06b8d010e8d4 Mon Sep 17 00:00:00 2001 From: Jeff Heckey Date: Mon, 18 Nov 2024 12:55:34 -0800 Subject: [PATCH 28/39] fix: Pin cloudpickle==2.2.1 (#1044) --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 18bc591e1..2e1afe1c7 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,9 @@ "backoff", "boltons", "boto3>=1.28.53", - "cloudpickle>=3", + # SageMaker pinned cloudpickle==2.2.1 + # see https://github.com/aws/sagemaker-python-sdk/issues/4871 + "cloudpickle==2.2.1", "nest-asyncio", "networkx", "numpy", From 0644b0a9e79d0d13eb8bb6aff5be4a18216b529d Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 18 Nov 2024 21:13:46 +0000 Subject: [PATCH 29/39] prepare release v1.88.2 --- CHANGELOG.md | 6 ++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34565b899..7f7e8e7db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.88.2 (2024-11-18) + +### Bug Fixes and Other Changes + + * Pin cloudpickle==2.2.1 + ## v1.88.1 (2024-10-21) ### Bug Fixes and Other Changes diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 86ce67991..987a33464 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.88.2.dev0" +__version__ = "1.88.2" From e6775d54f45917c8b28919cbea84bf2c50b103c8 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 18 Nov 2024 21:13:46 +0000 Subject: [PATCH 30/39] update development version to v1.88.3.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 987a33464..3a2292d9b 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.88.2" +__version__ = "1.88.3.dev0" From 5cb4a31759f13cd724610b7fd8e156086577db14 Mon Sep 17 00:00:00 2001 From: Abe Coull <85974725+AbeCoull@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:25:16 -0800 Subject: [PATCH 31/39] doc: add dual navigation buttons and cleanup some docstrings (#758) --- doc/conf.py | 7 ++++++- src/braket/circuits/circuit.py | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 8a16ca231..b5eae7acc 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -19,18 +19,23 @@ ] source_suffix = ".rst" -master_doc = "index" +root_doc = "index" autoclass_content = "both" autodoc_member_order = "bysource" default_role = "py:obj" html_theme = "sphinx_rtd_theme" +html_theme_options = { + "prev_next_buttons_location": "both", +} htmlhelp_basename = f"{project}doc" language = "en" napoleon_use_rtype = False +napoleon_google_docstring = True +napoleon_numpy_docstring = False apidoc_module_dir = "../src/braket" apidoc_output_dir = "_apidoc" diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index 02d419cff..e3181a603 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -1537,9 +1537,9 @@ def to_unitary(self) -> np.ndarray: `qubit count` > 10. Returns: - np.ndarray: A numpy array with shape (2^qubit_count, 2^qubit_count) representing the - circuit as a unitary. For an empty circuit, an empty numpy array is returned - (`array([], dtype=complex)`) + np.ndarray: A numpy array with shape (2 :sup:`qubit_count`, 2 :sup:`qubit_count`) + representing the circuit as a unitary. For an empty circuit, an empty numpy array + is returned (`array([], dtype=complex)`) Raises: TypeError: If circuit is not composed only of `Gate` instances, From cfe02145a2a88b9433bda4588eeb98897ef4fc93 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 25 Nov 2024 16:14:20 +0000 Subject: [PATCH 32/39] prepare release v1.88.2.post0 --- CHANGELOG.md | 6 ++++++ src/braket/_sdk/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f7e8e7db..78fe9797d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.88.2.post0 (2024-11-25) + +### Documentation Changes + + * add dual navigation buttons and cleanup some docstrings + ## v1.88.2 (2024-11-18) ### Bug Fixes and Other Changes diff --git a/src/braket/_sdk/_version.py b/src/braket/_sdk/_version.py index 3a2292d9b..997180b39 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.88.3.dev0" +__version__ = "1.88.2.post0" From b378184d99350c9447377b8fab3410fe062aba91 Mon Sep 17 00:00:00 2001 From: ci Date: Mon, 25 Nov 2024 16:14:20 +0000 Subject: [PATCH 33/39] update development version to v1.88.3.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 997180b39..3a2292d9b 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.88.2.post0" +__version__ = "1.88.3.dev0" From 7966a3d3228d25fc9b6380b69639f6960fec70aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 12:39:20 -0800 Subject: [PATCH 34/39] infra: bump pypa/gh-action-pypi-publish from 1.10.0 to 1.11.0 (#1042) --- .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 00d746acb..cfd03b7a4 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@8a08d616893759ef8e1aa1f2785787c0b97e20d6 # release/v1 + uses: pypa/gh-action-pypi-publish@fb13cb306901256ace3dab689990e13a5550ffaa # release/v1 with: password: ${{ secrets.pypi_token }} From 509bad6ac813a965d59cc03475f0e5a3424ac65b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:35:34 -0500 Subject: [PATCH 35/39] infra: bump pypa/gh-action-pypi-publish from 1.11.0 to 1.12.2 (#1047) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@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 cfd03b7a4..20acaf742 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@fb13cb306901256ace3dab689990e13a5550ffaa # release/v1 + uses: pypa/gh-action-pypi-publish@15c56dba361d8335944d31a2ecd17d700fc7bcbc # release/v1 with: password: ${{ secrets.pypi_token }} From daab5540821c71b17f124817ac7e9e9188a0feae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:12:02 -0500 Subject: [PATCH 36/39] infra: bump codecov/codecov-action from 4.5.0 to 5.0.7 (#1045) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 8ce80816f..79430846b 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -36,7 +36,7 @@ jobs: run: | tox -e unit-tests - name: Upload coverage report to Codecov - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # v5.0.7 with: token: ${{ secrets.CODECOV_TOKEN }} if: ${{ strategy.job-index }} == 0 From 2e8a1be6b96ef749a99fb8dca3becd3453cd0f98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:18:31 -0500 Subject: [PATCH 37/39] infra: bump thehanimo/pr-title-checker from 1.4.2 to 1.4.3 (#1046) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> --- .github/workflows/pr-title-checker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml index 78126bdce..a0f103127 100644 --- a/.github/workflows/pr-title-checker.yml +++ b/.github/workflows/pr-title-checker.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Check PR Title" - uses: thehanimo/pr-title-checker@v1.4.2 + uses: thehanimo/pr-title-checker@v1.4.3 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} pass_on_octokit_error: false From 13fef326a46641d22f410c4d91683e05bee2174b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:46:22 -0500 Subject: [PATCH 38/39] infra: bump actions/checkout from 4.1.7 to 4.2.0 (#1036) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacob Feldman Co-authored-by: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> --- .github/workflows/check-format.yml | 2 +- .github/workflows/dependent-tests.yml | 2 +- .github/workflows/publish-to-pypi.yml | 2 +- .github/workflows/python-package.yml | 2 +- .github/workflows/twine-check.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml index e047484ad..de07350a7 100644 --- a/.github/workflows/check-format.yml +++ b/.github/workflows/check-format.yml @@ -16,7 +16,7 @@ jobs: check-code-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: diff --git a/.github/workflows/dependent-tests.yml b/.github/workflows/dependent-tests.yml index ab2656bc0..e386207fc 100644 --- a/.github/workflows/dependent-tests.yml +++ b/.github/workflows/dependent-tests.yml @@ -21,7 +21,7 @@ jobs: - amazon-braket-pennylane-plugin-python steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 20acaf742..9e74d72bc 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -12,7 +12,7 @@ jobs: name: Build and publish distribution to PyPi runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 79430846b..5556836de 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -24,7 +24,7 @@ jobs: python-version: ["3.9", "3.10", "3.11"] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: diff --git a/.github/workflows/twine-check.yml b/.github/workflows/twine-check.yml index 3b439db6d..2e5def62c 100644 --- a/.github/workflows/twine-check.yml +++ b/.github/workflows/twine-check.yml @@ -14,7 +14,7 @@ jobs: name: Check long description runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: From aead183e7c133a7cf1079aa931dc6aad4d1ae7a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:58:50 -0500 Subject: [PATCH 39/39] infra: bump actions/setup-python from 5.1.0 to 5.2.0 (#1028) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Co-authored-by: Abe Coull <85974725+math411@users.noreply.github.com> --- .github/workflows/check-format.yml | 2 +- .github/workflows/dependent-tests.yml | 2 +- .github/workflows/publish-to-pypi.yml | 2 +- .github/workflows/python-package.yml | 2 +- .github/workflows/twine-check.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml index de07350a7..cf5f05bae 100644 --- a/.github/workflows/check-format.yml +++ b/.github/workflows/check-format.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: python-version: '3.9' - name: Install dependencies diff --git a/.github/workflows/dependent-tests.yml b/.github/workflows/dependent-tests.yml index e386207fc..f3cac948c 100644 --- a/.github/workflows/dependent-tests.yml +++ b/.github/workflows/dependent-tests.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 9e74d72bc..334a2b5b5 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: python-version: '3.x' - name: Install wheel diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 5556836de..9d06d53c0 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.github/workflows/twine-check.yml b/.github/workflows/twine-check.yml index 2e5def62c..8fbb96e09 100644 --- a/.github/workflows/twine-check.yml +++ b/.github/workflows/twine-check.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: python-version: '3.x' - name: Install wheel