2–3 hours (one-time setup) ~6 min read

Appendix A — AWS Braket Setup & Cost Guardrails

Do this once, early — before Term 1 · The Qubit's first hands-on code. Everything in this program runs on the free local simulator by default; you only need an AWS account when you progress to on-demand simulators (SV1/DM1/TN1) and QPUs in Term 5.

Learning Objectives

By the end of this appendix you will be able to:

  1. Install amazon-braket-sdk-python and run a circuit on the local simulator with no AWS account.
  2. Create and configure AWS credentials, choose a Braket-supported region, and enable the service.
  3. Set up an IAM identity with least-privilege Braket permissions.
  4. Explain Braket's pricing model and put cost guardrails (budgets, alarms, tags) in place.
  5. List available devices programmatically and read their properties.

1. Install the SDK (no AWS account needed)

amazon-braket-sdk requires Python 3.11 or greater. Always work inside a virtual environment.

# Create and activate an isolated environment
python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

# Install the SDK (pulls in braket-default-simulator, boto3, etc.)
pip install --upgrade pip
pip install amazon-braket-sdk

# Optional extras you will use later in the program:
pip install amazon-braket-pennylane-plugin   # Term 5.6 (PennyLane integration)
pip install matplotlib networkx              # plotting + graph problems (QAOA)

Verify the install and run your first quantum circuit — a Bell state on the local simulator. This costs nothing and touches no AWS service:

# bell_local.py — runs entirely on your machine, free, no AWS account required.
from braket.circuits import Circuit
from braket.devices import LocalSimulator

# Build a 2-qubit Bell circuit: H on qubit 0, then CNOT(control=0, target=1).
bell = Circuit().h(0).cnot(0, 1)
print(bell)                       # ASCII circuit diagram

# The default LocalSimulator backend is the state-vector simulator ("braket_sv").
device = LocalSimulator()
result = device.run(bell, shots=1000).result()

# Expect roughly half "00" and half "11" — the signature of an entangled Bell state.
print(result.measurement_counts)  # e.g. Counter({'11': 507, '00': 493})
T  : |0|1|
q0 : -H-C-
        |
q1 : ---X-

Counter({'00': 503, '11': 497})

Checkpoint: if you see roughly-balanced 00/11 counts and no 01/10, your SDK works. You can complete all of Terms 0–4's hands-on code on LocalSimulator alone.

Local simulator backends

LocalSimulator accepts a backend name; you will meet all three in this program:

Constructor Backend Use it for
LocalSimulator() or LocalSimulator("braket_sv") State vector Noiseless circuits (Terms 2–3).
LocalSimulator("braket_dm") Density matrix Noisy circuits (Term 4).
LocalSimulator("braket_ahs") Analog Hamiltonian Neutral-atom analog programs (Term 4.4 / 5).

2. AWS Account & Credentials (needed for cloud devices only)

You only need this section when you reach Term 5 (or want to run SV1/DM1/TN1/QPUs earlier). Local-simulator lessons need none of it.

2.1 Create an account and an IAM user

  1. Create an AWS account at https://aws.amazon.com/ (a payment method is required even for the free tier).
  2. Do not use your root account for day-to-day work. In the IAM console, create a user (or an IAM Identity Center user) for yourself.
  3. Attach a Braket policy. The AWS-managed AmazonBraketFullAccess policy is the simplest starting point; it grants Braket actions plus the S3/CloudWatch/IAM-passrole permissions Braket needs to store results and run jobs. For least privilege in shared accounts, scope a custom policy down to specific device ARNs and a single results bucket.

2.2 Install and configure the AWS CLI

# macOS (Homebrew); see docs for other platforms
brew install awscli

# Configure a named profile with your IAM access key, secret, and a Braket region.
aws configure --profile braket
# AWS Access Key ID     [None]: AKIA....
# AWS Secret Access Key [None]: ....
# Default region name   [None]: us-east-1
# Default output format [None]: json

This writes ~/.aws/credentials and ~/.aws/config. The Braket SDK uses boto3, which picks up these credentials automatically. To select your named profile in a session:

export AWS_PROFILE=braket        # Windows: set AWS_PROFILE=braket

🔐 Security: never hard-code keys in source. Prefer short-lived credentials via IAM Identity Center / SSO (aws sso login) or, on EC2/SageMaker, an attached IAM role. Rotate keys regularly.

2.3 Regions

Braket is available in a subset of AWS regions, and specific devices are tied to specific regions (a QPU offered in us-east-1 may not exist in eu-west-2). Pick a region that hosts the device you need. Because availability changes, enumerate devices programmatically rather than hard-coding (see §4). The on-demand simulators SV1/DM1/TN1 are offered in several regions.

2.4 Enable the service and run remotely

First-time use: open the Braket console and accept the terms to enable the service. Then the same Bell circuit on the on-demand state-vector simulator SV1 (⚠️ this one is billed — see §5):

# bell_sv1.py — ⚠️ INCURS AWS CHARGES (SV1 is a paid managed simulator).
from braket.aws import AwsDevice
from braket.devices import Devices
from braket.circuits import Circuit

bell = Circuit().h(0).cnot(0, 1)

# The Devices enum gives readable, current references to managed devices.
device = AwsDevice(Devices.Amazon.SV1)        # equivalently AwsDevice(<SV1 ARN>)

# Managed/QPU runs are asynchronous: run() returns a task you poll for results.
task = device.run(bell, shots=1000)
print("Task ARN:", task.id)                   # also visible in the console
result = task.result()                        # blocks until the task completes
print(result.measurement_counts)

Results are written to a default Amazon S3 bucket that Braket manages for you (amazon-braket-<region>-<accountId>); you no longer need to pre-create or pass a bucket for basic runs. You can override the destination with the s3_destination_folder argument if your org requires a specific bucket.


3. Quotas, Tasks, and Asynchrony (mental model)

  • A quantum task is one submission of a circuit (with a shot count) to a device.
  • Local runs are synchronous and free. Managed runs (SV1/DM1/TN1/QPU) are asynchronous: run() returns immediately with a task you later .result() on; results persist in S3.
  • QPUs run only during device-specific availability windows and may queue. Check a device's status and window in the console or via its properties (see §4) before submitting.
  • Default result-polling timeout is 5 days; adjust with poll_timeout_seconds.

4. Discovering Devices Programmatically

Never hard-code device ARNs from a tutorial — availability drifts. Ask the service:

# list_devices.py — read-only metadata calls; listing/searching devices is not billed.
from braket.aws import AwsDevice

# All ONLINE devices visible to your account/region (simulators + QPUs).
for dev in AwsDevice.get_devices(statuses=["ONLINE"]):
    print(f"{dev.name:24s}  type={dev.type:10s}  arn={dev.arn}")

# Inspect a specific device's capabilities, native gates, connectivity, and shot limits.
from braket.devices import Devices
sv1 = AwsDevice(Devices.Amazon.SV1)
print(sv1.properties.action)        # supported program/result types
print(sv1.status)                   # ONLINE / OFFLINE / RETIRED

For a QPU you will also inspect properties.paradigm (qubit count, connectivity graph), properties.provider (calibration/fidelity data), and the device's execution window. We do this in detail in Term 5.3 · Devices & Paradigms.


5. Cost Guardrails

This section is mandatory reading before you run anything outside LocalSimulator.

5.1 How Braket bills (the shape, not the prices)

Pricing changes; confirm current numbers on the Braket pricing page. The structure is stable:

Resource Billing shape
LocalSimulator Free (runs on your machine).
On-demand simulators (SV1, DM1, TN1) Per minute of simulation time (a small per-minute rate, billed by the millisecond, with a per-task minimum). Big circuits / many shots = more minutes.
QPUs Per-shot fee plus a per-task fee. Cost scales with shots. A few thousand shots on a QPU is real money.
Hybrid Jobs The above device costs plus the cost of the classical instance running your job.

Implications for how you work in this program:

  • Develop and debug on LocalSimulator (free). Only promote to a managed device when the circuit is correct and you actually need it.
  • Treat shots as a budget knob. Don't run 100,000 shots on a QPU "to be safe."
  • TN1 is only economical for circuits with favorable tensor-network structure; SV1 for general circuits up to ~34 qubits; DM1 for noisy circuits up to ~17 qubits. (Limits are approximate and evolve — verify in the console.)

5.2 Put hard guardrails in place (do this now)

  1. AWS Budgets: create a monthly cost budget (e.g. $20) with email alerts at 50%/80%/100%. Console → Billing → Budgets → Create budget.
  2. CloudWatch billing alarm: add a billing-metric alarm as a second safety net.
  3. Cost allocation tags: tag every task/job (e.g. Project=qc-degree) so you can attribute and filter spend in Cost Explorer:
    task = device.run(bell, shots=100, tags={"Project": "qc-degree", "Lesson": "appendixA"})
  4. Confirm before paid runs: keep a habit (and we enforce it in lessons) of a guard like:
    import os
    ALLOW_PAID = os.environ.get("BRAKET_ALLOW_PAID") == "1"
    assert ALLOW_PAID, "Refusing to submit a paid task. Set BRAKET_ALLOW_PAID=1 to override."

⚠️ The single most common surprise bill is a large shot count on a QPU inside a loop (e.g. a variational optimizer calling the device hundreds of times). When you reach Term 5.5 · Hybrid Jobs, you will learn to estimate cost before launching such loops.


6. Optional: Braket-Hosted Notebooks

Amazon Braket offers managed Jupyter notebook instances (a SageMaker notebook with the SDK pre-installed). They are convenient but the notebook instance itself is billed while running — stop it when idle. For this self-paced program, a local virtual environment is the cheapest and recommended setup; use hosted notebooks only if you prefer not to manage Python locally.


Checkpoint

  1. Can you run the local Bell circuit and explain why only 00/11 appear?
  2. What are the three LocalSimulator backends and when do you use each?
  3. Which two cost components dominate a QPU task, and which knob most directly controls cost?
  4. Why should you enumerate devices with AwsDevice.get_devices() instead of copying an ARN?
  5. Name two guardrails you put in place before running any paid task.
Answers
  1. The Bell state is 12(00+11)\frac{1}{\sqrt2}(\lvert 00\rangle + \lvert 11\rangle) — the two qubits are perfectly correlated, so measurement yields 00 or 11 with ~50% each and never 01/10.
  2. braket_sv (state vector, noiseless), braket_dm (density matrix, for noise), braket_ahs (analog Hamiltonian simulation for neutral-atom programs).
  3. A per-shot fee and a per-task fee; shots most directly controls cost.
  4. Device availability and ARNs change over time and by region; querying the service avoids stale, broken, or region-mismatched ARNs.
  5. Any two of: an AWS Budget with alerts, a CloudWatch billing alarm, cost-allocation tags, and an explicit BRAKET_ALLOW_PAID guard before submission.

Further Reading


← Back to Program Index · Next: Appendix B — Python/NumPy Refresher