Skip to content

Commit

Permalink
Merge branch 'main' into jcjaskula-aws/fix_gate_calibration_filter
Browse files Browse the repository at this point in the history
  • Loading branch information
speller26 authored Dec 6, 2023
2 parents af37398 + dedfb72 commit 3d61d9f
Show file tree
Hide file tree
Showing 33 changed files with 1,404 additions and 115 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/code-freeze.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Code Freeze

on:
pull_request:
branches:
- main
workflow_dispatch:

permissions:
contents: read

env:
FROZEN: ${{ vars.FROZEN }}
UNFROZEN_PREFIX: ${{ vars.UNFROZEN_PREFIX }}

jobs:
check-pr-frozen-status:
runs-on: ubuntu-latest
steps:
- name: Fetch PR data and check if merge allowed
if: env.FROZEN == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_DATA=$(curl -s \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }})
BRANCH_NAME=$(echo $PR_DATA | jq .head.ref -r)
PR_TITLE=$(echo $PR_DATA | jq .title -r)
echo $BRANCH_NAME
echo $PR_TITLE
# if it's not a critical fix
if ! [[ "$PR_TITLE" == fix\(critical\):* ]]; then
# and there's an unfrozen prefix
if ! [[ -z $UNFROZEN_PREFIX ]]; then
# check if the branch matches unfrozen prefix
if [[ "$BRANCH_NAME" != $UNFROZEN_PREFIX* ]]; then
echo "Error: You can only merge from branches that start with '$UNFROZEN_PREFIX', or PRs titled with prefix 'fix(critical): '."
exit 1
fi
# repo is fully frozen
else
echo "Error: You can only merge PRs titled with prefix 'fix(critical): '."
exit 1
fi
fi
2 changes: 1 addition & 1 deletion .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
- name: Build a binary wheel and a source tarball
run: python setup.py sdist bdist_wheel
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e # release/v1
uses: pypa/gh-action-pypi-publish@2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf # release/v1
with:
password: ${{ secrets.pypi_token }}
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# Changelog

## v1.63.0 (2023-12-05)

### Features

* Allow reservation ARN in task and job creation

### Bug Fixes and Other Changes

* Add Forte 1 device

## v1.62.1 (2023-11-17)

### Bug Fixes and Other Changes

* Fix broken link to example notebook
* update: default no longer returning RETIRED devices from get_devices

### Documentation Changes

* Add matrix expressions to docstrings

## v1.62.0 (2023-11-09)

### Features

* Add get_compiled_circuit convenience method

## v1.61.0.post0 (2023-11-07)

### Documentation Changes

* Improve docstring for make_bound_circuit

## v1.61.0 (2023-11-06)

### Features
Expand Down
2 changes: 1 addition & 1 deletion doc/examples-hybrid-jobs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Learn more about hybrid jobs on Amazon Braket.
:maxdepth: 2

************************************************************************************************************************************************************************************************
`Creating your first Hybrid Job <https://github.com/amazon-braket/amazon-braket-examples/blob/main/examples/hybrid_jobs/0_Creating_your_first_Hybrid_Job/Creating_your_first_Hybrid_Job.ipynb>`_
`Creating your first Hybrid Job <https://github.com/amazon-braket/amazon-braket-examples/blob/main/examples/hybrid_jobs/0_Creating_your_first_Hybrid_Job/0_Creating_your_first_Hybrid_Job.ipynb>`_
************************************************************************************************************************************************************************************************

This tutorial shows how to run your first Amazon Braket Hybrid Job.
Expand Down
9 changes: 8 additions & 1 deletion examples/hybrid_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
from braket.jobs.metrics import log_metric


@hybrid_job(device=Devices.Amazon.SV1, wait_until_complete=True)
@hybrid_job(
device=Devices.Amazon.SV1,
wait_until_complete=True,
# If you want to run the job in a device reservation window,
# change the device to the one you've reserved,
# uncomment the following line and fill in your reservation ARN
# reservation_arn="<reservation ARN>"
)
def run_hybrid_job(num_tasks=1):
# declare AwsDevice within the hybrid job
device = AwsDevice(get_job_device_arn())
Expand Down
24 changes: 24 additions & 0 deletions examples/reservation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

from braket.aws import AwsDevice
from braket.circuits import Circuit
from braket.devices import Devices

bell = Circuit().h(0).cnot(0, 1)
device = AwsDevice(Devices.IonQ.Aria1)

# To run a task in a device reservation, change the device to the one you reserved
# and fill in your reservation ARN
task = device.run(bell, shots=100, reservation_arn="reservation ARN")
print(task.result().measurement_counts)
2 changes: 1 addition & 1 deletion src/braket/_sdk/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "1.61.1.dev0"
__version__ = "1.63.1.dev0"
27 changes: 21 additions & 6 deletions src/braket/aws/aws_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def run(
poll_interval_seconds: Optional[float] = None,
inputs: Optional[dict[str, float]] = None,
gate_definitions: Optional[dict[tuple[Gate, QubitSet], PulseSequence]] = None,
reservation_arn: str | None = None,
*aws_quantum_task_args,
**aws_quantum_task_kwargs,
) -> AwsQuantumTask:
Expand Down Expand Up @@ -150,6 +151,11 @@ def run(
The calibration is defined for a particular `Gate` on a particular `QubitSet`
and is represented by a `PulseSequence`.
Default: None.
reservation_arn (str | None): The reservation ARN provided by Braket Direct
to reserve exclusive usage for the device to run the quantum task on.
Note: If you are creating tasks in a job that itself was created reservation ARN,
those tasks do not need to be created with the reservation ARN.
Default: None.
Returns:
AwsQuantumTask: An AwsQuantumTask that tracks the execution on the device.
Expand Down Expand Up @@ -199,6 +205,7 @@ def run(
poll_interval_seconds=poll_interval_seconds or self._poll_interval_seconds,
inputs=inputs,
gate_definitions=gate_definitions,
reservation_arn=reservation_arn,
*aws_quantum_task_args,
**aws_quantum_task_kwargs,
)
Expand Down Expand Up @@ -233,6 +240,7 @@ def run_batch(
poll_interval_seconds: float = AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL,
inputs: Optional[Union[dict[str, float], list[dict[str, float]]]] = None,
gate_definitions: Optional[dict[tuple[Gate, QubitSet], PulseSequence]] = None,
reservation_arn: Optional[str] = None,
*aws_quantum_task_args,
**aws_quantum_task_kwargs,
) -> AwsQuantumTaskBatch:
Expand Down Expand Up @@ -263,7 +271,11 @@ def run_batch(
gate_definitions (Optional[dict[tuple[Gate, QubitSet], PulseSequence]]): A
`dict[tuple[Gate, QubitSet], PulseSequence]]` for a user defined gate calibration.
The calibration is defined for a particular `Gate` on a particular `QubitSet`
and is represented by a `PulseSequence`.
and is represented by a `PulseSequence`. Default: None.
reservation_arn (Optional[str]): The reservation ARN provided by Braket Direct
to reserve exclusive usage for the device to run the quantum task on.
Note: If you are creating tasks in a job that itself was created reservation ARN,
those tasks do not need to be created with the reservation ARN.
Default: None.
Returns:
Expand All @@ -290,6 +302,7 @@ def run_batch(
poll_interval_seconds=poll_interval_seconds or self._poll_interval_seconds,
inputs=inputs,
gate_definitions=gate_definitions,
reservation_arn=reservation_arn,
*aws_quantum_task_args,
**aws_quantum_task_kwargs,
)
Expand Down Expand Up @@ -564,13 +577,15 @@ def get_devices(
>>> AwsDevice.get_devices(types=['SIMULATOR'])
Args:
arns (Optional[list[str]]): device ARN list, default is `None`
names (Optional[list[str]]): device name list, default is `None`
types (Optional[list[AwsDeviceType]]): device type list, default is `None`
arns (Optional[list[str]]): device ARN filter, default is `None`
names (Optional[list[str]]): device name filter, default is `None`
types (Optional[list[AwsDeviceType]]): device type filter, default is `None`
QPUs will be searched for all regions and simulators will only be
searched for the region of the current session.
statuses (Optional[list[str]]): device status list, default is `None`
provider_names (Optional[list[str]]): provider name list, default is `None`
statuses (Optional[list[str]]): device status filter, default is `None`. When `None`
is used, RETIRED devices will not be returned. To include RETIRED devices in
the results, use a filter that includes "RETIRED" for this parameter.
provider_names (Optional[list[str]]): provider name filter, default is `None`
order_by (str): field to order result by, default is `name`.
Accepted values are ['arn', 'name', 'type', 'provider_name', 'status']
aws_session (Optional[AwsSession]): An AWS session object.
Expand Down
6 changes: 6 additions & 0 deletions src/braket/aws/aws_quantum_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def create(
aws_session: AwsSession | None = None,
tags: dict[str, str] | None = None,
logger: Logger = getLogger(__name__),
reservation_arn: str | None = None,
) -> AwsQuantumJob:
"""Creates a hybrid job by invoking the Braket CreateJob API.
Expand Down Expand Up @@ -175,6 +176,10 @@ def create(
while waiting for quantum task to be in a terminal state. Default is
`getLogger(__name__)`
reservation_arn (str | None): the reservation window arn provided by Braket
Direct to reserve exclusive usage for the device to run the hybrid job on.
Default: None.
Returns:
AwsQuantumJob: Hybrid job tracking the execution on Amazon Braket.
Expand All @@ -201,6 +206,7 @@ def create(
checkpoint_config=checkpoint_config,
aws_session=aws_session,
tags=tags,
reservation_arn=reservation_arn,
)

job_arn = aws_session.create_job(**create_job_kwargs)
Expand Down
32 changes: 31 additions & 1 deletion src/braket/aws/aws_quantum_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def create(
tags: dict[str, str] | None = None,
inputs: dict[str, float] | None = None,
gate_definitions: Optional[dict[tuple[Gate, QubitSet], PulseSequence]] | None = None,
reservation_arn: str | None = None,
*args,
**kwargs,
) -> AwsQuantumTask:
Expand Down Expand Up @@ -151,6 +152,12 @@ def create(
a `PulseSequence`.
Default: None.
reservation_arn (str | None): The reservation ARN provided by Braket Direct
to reserve exclusive usage for the device to run the quantum task on.
Note: If you are creating tasks in a job that itself was created reservation ARN,
those tasks do not need to be created with the reservation ARN.
Default: None.
Returns:
AwsQuantumTask: AwsQuantumTask tracking the quantum task execution on the device.
Expand Down Expand Up @@ -179,6 +186,18 @@ def create(
create_task_kwargs.update({"tags": tags})
inputs = inputs or {}

if reservation_arn:
create_task_kwargs.update(
{
"associations": [
{
"arn": reservation_arn,
"type": "RESERVATION_TIME_WINDOW_ARN",
}
]
}
)

if isinstance(task_specification, Circuit):
param_names = {param.name for param in task_specification.parameters}
unbounded_parameters = param_names - set(inputs.keys())
Expand Down Expand Up @@ -477,6 +496,12 @@ async def _wait_for_completion(
self._result = None
return None

def _has_reservation_arn_from_metadata(self, current_metadata: dict[str, Any]) -> bool:
for association in current_metadata.get("associations", []):
if association.get("type") == "RESERVATION_TIME_WINDOW_ARN":
return True
return False

def _download_result(
self,
) -> Union[
Expand All @@ -488,7 +513,12 @@ def _download_result(
current_metadata["outputS3Directory"] + f"/{AwsQuantumTask.RESULTS_FILENAME}",
)
self._result = _format_result(BraketSchemaBase.parse_raw_schema(result_string))
task_event = {"arn": self.id, "status": self.state(), "execution_duration": None}
task_event = {
"arn": self.id,
"status": self.state(),
"execution_duration": None,
"has_reservation_arn": self._has_reservation_arn_from_metadata(current_metadata),
}
try:
task_event[
"execution_duration"
Expand Down
Loading

0 comments on commit 3d61d9f

Please sign in to comment.