

# Run your circuits with OpenQASM 3.0
<a name="braket-openqasm"></a>

 Amazon Braket now supports [OpenQASM 3.0](https://openqasm.com/) for gate-based quantum devices and simulators. This user guide provides information about the subset of OpenQASM 3.0 supported by Braket. Braket customers now have the choice of submitting Braket circuits with the [SDK](braket-constructing-circuit.md) or by directly providing OpenQASM 3.0 strings to all gate-based devices with the [Amazon Braket API](https://docs.aws.amazon.com/braket/latest/APIReference/Welcome.html) and the [Amazon Braket Python SDK](https://github.com/aws/amazon-braket-sdk-python).

The topics in this guide walk you through various examples of how to complete the following quantum tasks.
+  [Create and submit OpenQASM quantum tasks on different Braket devices](braket-openqasm-create-submit-task.md) 
+  [Access the supported operations and result types](braket-openqasm-device-support.md#braket-openqasm-supported-operations-results-result-types) 
+  [Simulate noise with OpenQASM](braket-openqasm-noise-simulation.md) 
+  [Use verbatim compilation with OpenQASM](braket-openqasm-verbatim-compilation.md) 
+  [Troubleshoot OpenQASM issues](https://docs.aws.amazon.com/braket/latest/developerguide/braket-troubleshooting-openqasm.html) 

This guide also provides an introduction to certain hardware-specific features that can be implemented with OpenQASM 3.0 on Braket and links to further resources.

**Topics**
+ [What is OpenQASM 3.0?](#braket-openqasm-what-is)
+ [When to use OpenQASM 3.0](#braket-openqasm-when-to-use)
+ [How OpenQASM 3.0 works](#braket-openqasm-how-it-works)
+ [Prerequisites](#braket-openqasm-prerequisites)
+ [What OpenQASM features does Braket support?](braket-openqasm-supported-features.md)
+ [Create and submit an example OpenQASM 3.0 quantum task](braket-openqasm-create-submit-task.md)
+ [Support for OpenQASM on different Braket devices](braket-openqasm-device-support.md)
+ [Simulate noise with OpenQASM 3.0](braket-openqasm-noise-simulation.md)
+ [Qubit rewiring with OpenQASM 3.0](braket-openqasm-rewire-qubits.md)
+ [Verbatim compilation with OpenQASM 3.0](braket-openqasm-verbatim-compilation.md)
+ [The Braket console](#braket-openqasm-braket-console)
+ [Additional resources](#braket-openqasm-more-resources)
+ [Computing gradients with OpenQASM 3.0](braket-openqasm-computing-gradients.md)
+ [Measuring specific qubits with OpenQASM 3.0](braket-openqasm-measure-qubits.md)

## What is OpenQASM 3.0?
<a name="braket-openqasm-what-is"></a>

The Open Quantum Assembly Language (OpenQASM) is an [intermediate representation](https://en.wikipedia.org/wiki/Intermediate_representation) for quantum instructions. OpenQASM is an open-source framework and is widely used for the specification of quantum programs for gate-based devices. With OpenQASM, users can program the quantum gates and measurement operations that form the building blocks of quantum computation. The previous version of OpenQASM (2.0) was used by a number of quantum programming libraries to describe basic programs.

The new version of OpenQASM (3.0) extends the previous version to include more features, such as pulse-level control, gate timing, and classical control flow to bridge the gap between end-user interface and hardware description language. Details and specification on the current version 3.0 are available on the GitHub [OpenQASM 3.x Live Specification](https://github.com/openqasm/openqasm). OpenQASM's future development is governed by the OpenQASM 3.0 [Technical Steering Committee](https://aws.amazon.com/blogs/quantum-computing/aws-joins-the-openqasm-3-0-technical-steering-committee/), of which AWS is a member alongside IBM, Microsoft, and the University of Innsbruck.

## When to use OpenQASM 3.0
<a name="braket-openqasm-when-to-use"></a>

OpenQASM provides an expressive framework to specify quantum programs through low-level controls that are not architecture specific, making it well suited as a representation across multiple gate-based devices. The Braket support for OpenQASM furthers its adoption as a consistent approach to developing gate-based quantum algorithms, reducing the need for users to learn and maintain libraries in multiple frameworks.

If you have existing libraries of programs in OpenQASM 3.0, you can adapt them for use with Braket rather than completely rewriting these circuits. Researchers and developers should also benefit from an increasing number of available third-party libraries with support for algorithm development in OpenQASM.

## How OpenQASM 3.0 works
<a name="braket-openqasm-how-it-works"></a>

Support for OpenQASM 3.0 from Braket provides feature parity with the current Intermediate Representation. This means that anything you can do today on hardware devices and on-demand simulators with Braket, you can do with OpenQASM using the Braket API. You can run OpenQASM 3.0 programs by directly supplying OpenQASM strings to all gate-based devices in a manner that is similar to how circuits are currently supplied to devices on Braket. Braket users can also integrate third-party libraries that support OpenQASM 3.0. The rest of this guide details how to develop OpenQASM representations for use with Braket.

## Prerequisites
<a name="braket-openqasm-prerequisites"></a>

To use OpenQASM 3.0 on Amazon Braket, you must have version v1.8.0 of the [Amazon Braket Python Schemas](https://github.com/aws/amazon-braket-schemas-python) and v1.17.0 or higher of the [Amazon Braket Python SDK](https://github.com/aws/amazon-braket-sdk-python).

If you are a first time user of Amazon Braket, you need to enable Amazon Braket. For instructions, see [Enable Amazon Braket](https://docs.aws.amazon.com/braket/latest/developerguide/braket-enable-overview.html).

# What OpenQASM features does Braket support?
<a name="braket-openqasm-supported-features"></a>

The following section lists the OpenQASM 3.0 data types, statements, and pragma instructions supported by Braket.

**Topics**
+ [Supported OpenQASM data types](#braket-openqasm-supported-features-datatypes)
+ [Supported OpenQASM statements](#braket-openqasm-supported-features-statements)
+ [Braket OpenQASM pragmas](#braket-openqasm-supported-features-pragmas)
+ [Advanced feature support for OpenQASM on the Local Simulator](#braket-openqasm-supported-features-advanced-feature-local-simulator)
+ [Supported operations and grammar with OpenPulse](#braket-openpulse-supported-operations-grammar)

## Supported OpenQASM data types
<a name="braket-openqasm-supported-features-datatypes"></a>

The following OpenQASM data types are supported by Amazon Braket.
+ Non-negative integers are used for (virtual and physical) qubit indices:
  +  `cnot q[0], q[1];` 
  +  `h $0;` 
+ Floating-point numbers or constants may be used for gate rotation angles:
  +  `rx(-0.314) $0;` 
  +  `rx(pi/4) $0;` 

**Note**  
pi is a built-in constant in OpenQASM and cannot be used as a parameter name.
+ Arrays of complex numbers (with the OpenQASM `im` notation for imaginary part) are allowed in result type pragmas for defining general hermitian observables and in unitary pragmas:
  +  `#pragma braket unitary [[0, -1im], [1im, 0]] q[0]` 
  +  `#pragma braket result expectation hermitian([[0, -1im], [1im, 0]]) q[0]` 

## Supported OpenQASM statements
<a name="braket-openqasm-supported-features-statements"></a>

The following OpenQASM statements are supported by Amazon Braket.
+  `Header: OPENQASM 3;` 
+ Classic bit declarations:
  +  `bit b1;` (equivalently, `creg b1;`)
  +  `bit[10] b2;` (equivalently, `creg b2[10];`)
+ Qubit declarations:
  +  `qubit b1;` (equivalently, `qreg b1;`)
  +  `qubit[10] b2;` (equivalently, `qreg b2[10];`)
+ Indexing within arrays: `q[0]` 
+ Input: `input float alpha;` 
+ specification of physical qubits: `$0` 
+ Supported gates and operations on a device:
  +  `h $0;` 
  +  `iswap q[0], q[1];` 

**Note**  
A device's supported gates can be found in the device properties for OpenQASM actions; no gate definitions are needed to use these gates.
+ Verbatim box statements. Currently, we do not support box duration notation. Native gates and physical qubits are required in verbatim boxes.

```
#pragma braket verbatim
box{
    rx(0.314) $0;
}
```
+ Measurement and measurement assignment on qubits or a whole qubit register.
  +  `measure $0;` 
  +  `measure q;` 
  +  `measure q[0];` 
  +  `b = measure q;` 
  +  `measure q → b;` 
+ Barrier statements provide explicit control over circuit compilation and execution by preventing gate reordering and optimizations across barrier boundaries. They also enforce strict temporal ordering during execution, ensuring all operations before a barrier complete before subsequent operations begin.
  +  `barrier;` 
  +  `barrier q[0], q[1];` 
  +  `barrier $3, $6;` 

## Braket OpenQASM pragmas
<a name="braket-openqasm-supported-features-pragmas"></a>

The following OpenQASM pragma instructions are supported by Amazon Braket.
+ Noise pragmas
  +  `#pragma braket noise bit_flip(0.2) q[0]` 
  +  `#pragma braket noise phase_flip(0.1) q[0]` 
  +  `#pragma braket noise pauli_channel` 
+ Verbatim pragmas
  +  `#pragma braket verbatim` 
+ Result type pragmas
  + Basis invariant result types:
    + State vector: `#pragma braket result state_vector` 
    + Density matrix: `#pragma braket result density_matrix` 
  + Gradient computation pragmas:
    + Adjoint gradient: `#pragma braket result adjoint_gradient expectation(2.2 * x[0] @ x[1]) all` 
  + Z basis result types:
    + Amplitude: `#pragma braket result amplitude "01"` 
    + Probability: `#pragma braket result probability q[0], q[1]` 
  + Basis rotated result types
    + Expectation: `#pragma braket result expectation x(q[0]) @ y([q1])` 
    + Variance: `#pragma braket result variance hermitian([[0, -1im], [1im, 0]]) $0` 
    + Sample: `#pragma braket result sample h($1)` 

**Note**  
OpenQASM 3.0 is backwards compatible with OpenQASM 2.0, so programs written using 2.0 can run on Braket. However the features of OpenQASM 3.0 supported by Braket do have some minor syntax differences, such as `qreg` vs `creg` and `qubit` vs `bit`. There are also differences in measurement syntax, and these need to be supported with their correct syntax.

## Advanced feature support for OpenQASM on the Local Simulator
<a name="braket-openqasm-supported-features-advanced-feature-local-simulator"></a>

The `LocalSimulator` supports advanced OpenQASM features which are not offered as part of Braket's QPU's or on-demand simulators. The following list of features are only supported in the `LocalSimulator`:
+ Gate modifiers
+ OpenQASM built-in gates
+ Classical variables
+ Classical operations
+ Custom gates
+ Classical control
+ QASM files
+ Subroutines

For examples of each advanced feature, see this [sample notebook](https://github.com/aws/amazon-braket-examples/blob/main/examples/braket_features/Simulating_Advanced_OpenQASM_Programs_with_the_Local_Simulator.ipynb). For the full OpenQASM specification, see the [OpenQASM website](https://openqasm.com/language/index.html).

## Supported operations and grammar with OpenPulse
<a name="braket-openpulse-supported-operations-grammar"></a>

 **Supported OpenPulse Data Types** 

Cal blocks:

```
cal {
    ...
}
```

Defcal blocks:

```
// 1 qubit
defcal x $0 {
...
}

// 1 qubit w. input parameters as constants
defcal my_rx(pi) $0 {
...
}

// 1 qubit w. input parameters as free parameters
defcal my_rz(angle theta) $0 {
...
}

// 2 qubit (above gate args are also valid)
defcal cz $1, $0 {
...
}
```

Frames:

```
frame my_frame = newframe(port_0, 4.5e9, 0.0);
```

Waveforms:

```
// prebuilt
waveform my_waveform_1 = constant(1e-6, 1.0);

//arbitrary
waveform my_waveform_2 = {0.1 + 0.1im, 0.1 + 0.1im, 0.1, 0.1};
```

 **Custom Gate Calibration Example:** 

```
cal {
    waveform wf1 = constant(1e-6, 0.25);
}

defcal my_x $0 {
   play(wf1, q0_rf_frame);
}

defcal my_cz $1, $0 {
    barrier q0_q1_cz_frame, q0_rf_frame;
    play(q0_q1_cz_frame, wf1);
    delay[300ns] q0_rf_frame
    shift_phase(q0_rf_frame, 4.366186381749424);
    delay[300ns] q0_rf_frame;
    shift_phase(q0_rf_frame.phase, 5.916747563126659);
    barrier q0_q1_cz_frame, q0_rf_frame;
    shift_phase(q0_q1_cz_frame, 2.183093190874712);
}

bit[2] ro;
my_x $0;
my_cz $1,$0;
c[0] = measure $0;
```

 **Arbitrary pulse example:** 

```
bit[2] ro;
cal {
    waveform wf1 = {0.1 + 0.1im, 0.1 + 0.1im, 0.1, 0.1};
    barrier q0_drive, q0_q1_cross_resonance;
    play(q0_q1_cross_resonance, wf1);
    delay[300ns] q0_drive;
    shift_phase(q0_drive, 4.366186381749424);
    delay[300dt] q0_drive;
   barrier q0_drive, q0_q1_cross_resonance;
   play(q0_q1_cross_resonance, wf1);
    ro[0] = capture_v0(r0_measure);
    ro[1] = capture_v0(r1_measure);
}
```

# Create and submit an example OpenQASM 3.0 quantum task
<a name="braket-openqasm-create-submit-task"></a>

You can use the Amazon Braket Python SDK, Boto3, or the AWS CLI to submit OpenQASM 3.0 quantum tasks to an Amazon Braket device.

**Topics**
+ [An example OpenQASM 3.0 program](#braket-openqasm-example-program)
+ [Use the Python SDK to create OpenQASM 3.0 quantum tasks](#braket-openqasm-create-tasks-with-python-sdk)
+ [Use Boto3 to create OpenQASM 3.0 quantum tasks](#braket-openqasm-create-tasks-with-boto3)
+ [Use the AWS CLI to create OpenQASM 3.0 tasks](#braket-openqasm-create-tasks-with-aws-cli)

## An example OpenQASM 3.0 program
<a name="braket-openqasm-example-program"></a>

To create an OpenQASM 3.0 task, you can start with a basic OpenQASM 3.0 program (ghz.qasm) that prepares a [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) as shown in the following example.

```
// ghz.qasm
// Prepare a GHZ state
OPENQASM 3;

qubit[3] q;
bit[3] c;

h q[0];
cnot q[0], q[1];
cnot q[1], q[2];

c = measure q;
```

## Use the Python SDK to create OpenQASM 3.0 quantum tasks
<a name="braket-openqasm-create-tasks-with-python-sdk"></a>

You can use the [Amazon Braket Python SDK](https://github.com/aws/amazon-braket-sdk-python) to submit this program to an Amazon Braket device with the following code. Be sure to replace the example Amazon S3 bucket location “amzn-s3-demo-bucket” with your own Amazon S3 bucket name.

```
with open("ghz.qasm", "r") as ghz:
    ghz_qasm_string = ghz.read()

# Import the device module
from braket.aws import AwsDevice
# Choose the Rigetti device
device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3")
from braket.ir.openqasm import Program

program = Program(source=ghz_qasm_string)
my_task = device.run(program)

# Specify an optional s3 bucket location and number of shots
s3_location = ("amzn-s3-demo-bucket", "openqasm-tasks")
my_task = device.run(
    program,
    s3_location,
    shots=100,
)
```

## Use Boto3 to create OpenQASM 3.0 quantum tasks
<a name="braket-openqasm-create-tasks-with-boto3"></a>

You can also use [AWS Python SDK for Braket (Boto3)](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/braket.html) to create the quantum tasks using OpenQASM 3.0 strings, as shown in the following example. The following code snippet references ghz.qasm that prepares a [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) as shown above.

```
import boto3
import json

my_bucket = "amzn-s3-demo-bucket"
s3_prefix = "openqasm-tasks"

with open("ghz.qasm") as f:
    source = f.read()

action = {
    "braketSchemaHeader": {
        "name": "braket.ir.openqasm.program",
        "version": "1"
    },
    "source": source
}
device_parameters = {}
device_arn = "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3"
shots = 100

braket_client = boto3.client('braket', region_name='us-west-1')
rsp = braket_client.create_quantum_task(
    action=json.dumps(
        action
    ),
    deviceParameters=json.dumps(
        device_parameters
    ),
    deviceArn=device_arn,
    shots=shots,
    outputS3Bucket=my_bucket,
    outputS3KeyPrefix=s3_prefix,
)
```

## Use the AWS CLI to create OpenQASM 3.0 tasks
<a name="braket-openqasm-create-tasks-with-aws-cli"></a>

The [AWS Command Line Interface (CLI)](https://aws.amazon.com/cli/) can also be used to submit OpenQASM 3.0 programs, as shown in the following example.

```
aws braket create-quantum-task \
    --region "us-west-1" \
    --device-arn "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3" \
    --shots 100 \
    --output-s3-bucket "amzn-s3-demo-bucket" \
    --output-s3-key-prefix "openqasm-tasks" \
    --action '{
        "braketSchemaHeader": {
            "name": "braket.ir.openqasm.program",
            "version": "1"
        },
        "source": $(cat ghz.qasm)
    }'
```

# Support for OpenQASM on different Braket devices
<a name="braket-openqasm-device-support"></a>

For devices supporting OpenQASM 3.0, the `action` field supports a new action through the `GetDevice` response, as shown in the following example for the Rigetti and IonQ devices.

```
//OpenQASM as available with the Rigetti device capabilities
{
    "braketSchemaHeader": {
        "name": "braket.device_schema.rigetti.rigetti_device_capabilities",
        "version": "1"
    },
    "service": {...},
    "action": {
        "braket.ir.jaqcd.program": {...},
        "braket.ir.openqasm.program": {
            "actionType": "braket.ir.openqasm.program",
            "version": [
                "1"
            ],
            ….
        }
    }
}

//OpenQASM as available with the IonQ device capabilities
{
    "braketSchemaHeader": {
        "name": "braket.device_schema.ionq.ionq_device_capabilities",
        "version": "1"
    },
    "service": {...},
    "action": {
        "braket.ir.jaqcd.program": {...},
        "braket.ir.openqasm.program": {
            "actionType": "braket.ir.openqasm.program",
            "version": [
                "1"
            ],
            ….
        }
    }
}
```

For devices that support pulse control, the `pulse` field is displayed in the `GetDevice` response. The following example show this `pulse` field for the Rigetti device.

```
// Rigetti
{
  "pulse": {
    "braketSchemaHeader": {
      "name": "braket.device_schema.pulse.pulse_device_action_properties",
      "version": "1"
    },
    "supportedQhpTemplateWaveforms": {
      "constant": {
        "functionName": "constant",
        "arguments": [
          {
            "name": "length",
            "type": "float",
            "optional": false
          },
          {
            "name": "iq",
            "type": "complex",
            "optional": false
          }
        ]
      },
      ...
    },
    "ports": {
      "q0_ff": {
        "portId": "q0_ff",
        "direction": "tx",
        "portType": "ff",
        "dt": 1e-9,
        "centerFrequencies": [
          375000000
        ]
      },
      ...
    },
    "supportedFunctions": {
      "shift_phase": {
        "functionName": "shift_phase",
        "arguments": [
          {
            "name": "frame",
            "type": "frame",
            "optional": false
          },
          {
            "name": "phase",
            "type": "float",
            "optional": false
          }
        ]
      },
     ...
    },
    "frames": {
      "q0_q1_cphase_frame": {
        "frameId": "q0_q1_cphase_frame",
        "portId": "q0_ff",
        "frequency": 462475694.24460185,
        "centerFrequency": 375000000,
        "phase": 0,
        "associatedGate": "cphase",
        "qubitMappings": [
          0,
          1
        ]
      },
      ...
    },
    "supportsLocalPulseElements": false,
    "supportsDynamicFrames": false,
    "supportsNonNativeGatesWithPulses": false,
    "validationParameters": {
      "MAX_SCALE": 4,
      "MAX_AMPLITUDE": 1,
      "PERMITTED_FREQUENCY_DIFFERENCE": 400000000
    }
  }
}
```

The preceding fields detail the following:

 **Ports:** 

Describes pre-made external (`extern`) device ports declared on the QPU in addition to the associated properties of the given port. All ports listed in this structure are pre-declared as valid identifiers within the `OpenQASM 3.0` program submitted by the user. The additional properties for a port include:
+ Port id (portId)
  + The port name declared as an identifier in OpenQASM 3.0.
+ Direction (direction)
  + The direction of the port. Drive ports transmit pulses (direction “tx”), while measurement ports receive pulses (direction “rx”).
+ Port type (portType)
  + The type of action for which this port is responsible (for example, drive, capture, or ff - fast-flux).
+ Dt (dt)
  + The time in seconds that represents a single sample time step on the given port.
+ Qubit mappings (qubitMappings)
  + The qubits associated with the given port.
+ Center frequencies (centerFrequencies)
  + A list of the associated center frequencies for all pre-declared or user-defined frames on the port. For more information, refer to Frames.
+ QHP Specific Properties (qhpSpecificProperties)
  + An optional map detailing existing properties about the port specific to the QHP.

 **Frames:** 

Describes pre-made external frames declared on the QPU as well as associated properties about the frames. All frames listed in this structure are pre-declared as valid identifiers within the `OpenQASM 3.0` program submitted by the user. The additional properties for a frame include:
+ Frame Id (frameId)
  + The frame name declared as an identifier in OpenQASM 3.0.
+ Port Id (portId)
  + The associated hardware port for the frame.
+ Frequency (frequency)
  + The default initial frequency of the frame.
+ Center Frequency (centerFrequency)
  + The center of the frequency bandwidth for the frame. Typically, frames may only be adjusted to a certain bandwidth around the center frequency. As a result, frequency adjustments should stay within a given delta of the center frequency. You can find the bandwidth value in the validation parameters.
+ Phase (phase)
  + The default initial phase of the frame.
+ Associated Gate (associatedGate)
  + The gates associated with the given frame.
+ Qubit Mappings (qubitMappings)
  + The qubits associated with the given frame.
+ QHP Specific Properties (qhpSpecificProperties)
  + An optional map detailing existing properties about the frame specific to the QHP.

 **SupportsDynamicFrames:** 

Describes whether a frame can be declared in `cal` or `defcal` blocks through the OpenPulse `newframe` function. If this is false, only frames listed in the frame structure may be used within the program.

 **SupportedFunctions:** 

Describes the OpenPulse functions that are supported for the device in addition to the associated arguments, argument types, and return types for the given functions. To see examples of using the OpenPulse functions, see the [OpenPulse specification](https://openqasm.com/language/openpulse.html). At this time, Braket supports:
+ shift\$1phase
  + Shifts the phase of a frame by a specified value
+ set\$1phase
  + Sets the phase of frame to the specified value
+ swap\$1phases
  + Swaps the phases between two frames.
+ shift\$1frequency
  + Shifts the frequency of a frame by a specified value
+ set\$1frequency
  + Sets the frequency of frame to the specified value
+ play
  + Schedules a waveform
+ capture\$1v0
  + Returns the value on a capture frame to a bit register

 **SupportedQhpTemplateWaveforms:** 

Describes the pre-built waveform functions available on the device and the associated arguments and types. By default, Braket Pulse offers pre-built waveform routines on all devices, which are:

 ** *Constant* ** 

![\[Mathematical equation showing a constant function with parameters t, tau, and iq where the output is always equal to iq.\]](http://docs.aws.amazon.com/braket/latest/developerguide/images/ConstantFunction.png)


 `τ` is the length of the waveform and `iq` is a complex number.

```
def constant(length, iq)
```

 ** *Gaussian* ** 

![\[Mathematical equation showing the Gaussian function with parameters t, tau, sigma, A=1, and ZaE=0.\]](http://docs.aws.amazon.com/braket/latest/developerguide/images/GaussianFunction.png)


 `τ` is the length of the waveform, `σ` is the width of the Gaussian, and `A` is the amplitude. If setting `ZaE` to `True`, the Gaussian is offset and rescaled such that it is equal to zero at the start and end of the waveform, and reaches `A` at maximum.

```
def gaussian(length, sigma, amplitude=1, zero_at_edges=False)
```

 ** *DRAG Gaussian* ** 

![\[Mathematical equation for DRAG Gaussian distribution with parameters t, tau, sigma, beta, A=1, and ZaE=0.\]](http://docs.aws.amazon.com/braket/latest/developerguide/images/DRAGGaussianFunction.png)


 `τ` is the length of the waveform, `σ` is the width of the gaussian, `β` is a free parameter, and `A` is the amplitude. If setting `ZaE` to `True`, the Derivative Removal by Adiabatic Gate (DRAG) Gaussian is offset and rescaled such that it is equal to zero at the start and end of the waveform, and the real part reaches `A` at maximum. For more information about the DRAG waveform, see the paper [Simple Pulses for Elimination of Leakage in Weakly Nonlinear Qubits](https://doi.org/10.1103/PhysRevLett.103.110501).

```
def drag_gaussian(length, sigma, beta, amplitude=1, zero_at_edges=False)
```

 ** *Erf Square* ** 

![\[Mathematical equation for Erf Square distribution with parameters t, Length, Width, sigma, A=1, and ZaE=0.\]](http://docs.aws.amazon.com/braket/latest/developerguide/images/ErfSquareFunction.PNG)


Where `L` is the length, `W` is the width of the waveform, `σ` defines how fast the edges rise and fall, `t1​=(L−W)/2` and `t22=(L+W)/2`, `A` is the amplitude. If setting `ZaE` to `True`, the Gaussian is offset and rescaled such that it is equal to zero at the start and end of the waveform, and reaches `A` at maximum. The following equation is the rescaled version of the waveform.

![\[Mathematical equation for the rescaled Erf Square distribution with parameters ZaE=1.\]](http://docs.aws.amazon.com/braket/latest/developerguide/images/RescaledErfSquareFunction.PNG)


Where `a=erf(W/2σ)`and `b=erf(-t1​/σ)/2+erf(t2​/σ)/2`.

```
def erf_square(length, width, sigma, amplitude=1, zero_at_edges=False)
```

 **SupportsLocalPulseElements:** 

Describes whether pulse elements, such as ports, frames, and waveforms may be defined locally in `defcal` blocks. If the value is `false`, elements must be defined in `cal` blocks.

 **SupportsNonNativeGatesWithPulses:** 

Describes whether we can or cannot use non-native gates in combination with pulse programs. For example, you cannot use a non-native gate like an `H` gate in a program without first defining the gate through `defcal` for the used qubit. You can find the list of native gates `nativeGateSet` key under the device capabilities.

 **ValidationParameters:** 

Describes pulse element validation boundaries, including:
+ Maximum Scale / Maximum Amplitude values for waveforms (arbitrary and pre-built)
+ Maximum frequency bandwidth from supplied center frequency in Hz
+ Minimum pulse length/duration in seconds
+ Maximum pulse length/duration in seconds

## Supported Operations, Results and Result Types with OpenQASM
<a name="braket-openqasm-supported-operations-results-result-types"></a>

To find out which OpenQASM 3.0 features each device supports, you can refer to the `braket.ir.openqasm.program` key in the `action` field on the device capabilities output. For example, the following are the supported operations and result types available for the Braket State Vector simulator SV1.

```
...
  "action": {
    "braket.ir.jaqcd.program": {
      ...
    },
 "braket.ir.openqasm.program": {
      "version": [
        "1.0"
      ],
      "actionType": "braket.ir.openqasm.program",
      "supportedOperations": [
        "ccnot",
        "cnot",
        "cphaseshift",
        "cphaseshift00",
        "cphaseshift01",
        "cphaseshift10",
        "cswap",
        "cy",
        "cz",
        "h",
        "i",
        "iswap",
        "pswap",
        "phaseshift",
        "rx",
        "ry",
        "rz",
        "s",
        "si",
        "swap",
        "t",
        "ti",
        "v",
        "vi",
        "x",
        "xx",
        "xy",
        "y",
        "yy",
        "z",
        "zz"
      ],
      "supportedPragmas": [
        "braket_unitary_matrix"
      ],
      "forbiddenPragmas": [],
      "maximumQubitArrays": 1,
      "maximumClassicalArrays": 1,
      "forbiddenArrayOperations": [
        "concatenation",
        "negativeIndex",
        "range",
        "rangeWithStep",
        "slicing",
        "selection"
      ],
      "requiresAllQubitsMeasurement": true,
      "supportsPhysicalQubits": false,
      "requiresContiguousQubitIndices": true,
      "disabledQubitRewiringSupported": false,
      "supportedResultTypes": [
        {
          "name": "Sample",
          "observables": [
            "x",
            "y",
            "z",
            "h",
            "i",
            "hermitian"
          ],
          "minShots": 1,
          "maxShots": 100000
        },
        {
          "name": "Expectation",
          "observables": [
            "x",
            "y",
            "z",
            "h",
            "i",
            "hermitian"
          ],
          "minShots": 0,
          "maxShots": 100000
        },
        {
          "name": "Variance",
          "observables": [
            "x",
            "y",
            "z",
            "h",
            "i",
            "hermitian"
          ],
          "minShots": 0,
          "maxShots": 100000
        },
        {
          "name": "Probability",
          "minShots": 1,
          "maxShots": 100000
        },
        {
          "name": "Amplitude",
          "minShots": 0,
          "maxShots": 0
        }
        {
          "name": "AdjointGradient",
          "minShots": 0,
          "maxShots": 0
        }
      ]
    }
  },
...
```

# Simulate noise with OpenQASM 3.0
<a name="braket-openqasm-noise-simulation"></a>

To simulate noise with OpenQASM3, you use *pragma* instructions to add noise operators. For example, to simulate the noisy version of the [GHZ program](braket-openqasm-create-submit-task.md#braket-openqasm-example-program) provided previously, you can submit the following OpenQASM program.

```
// ghz.qasm
// Prepare a GHZ state
OPENQASM 3;

qubit[3] q;
bit[3] c;

h q[0];
#pragma braket noise depolarizing(0.75) q[0] cnot q[0], q[1];
#pragma braket noise depolarizing(0.75) q[0]
#pragma braket noise depolarizing(0.75) q[1] cnot q[1], q[2];
#pragma braket noise depolarizing(0.75) q[0]
#pragma braket noise depolarizing(0.75) q[1]

c = measure q;
```

Specifications for all supported pragma noise operators are provided in the following list.

```
#pragma braket noise bit_flip(<float in [0,1/2]>) <qubit>
#pragma braket noise phase_flip(<float in [0,1/2]>) <qubit>
#pragma braket noise pauli_channel(<float>, <float>, <float>)  <qubit>
#pragma braket noise depolarizing(<float in [0,3/4]>) <qubit>
#pragma braket noise two_qubit_depolarizing(<float in [0,15/16]>) <qubit>, <qubit>
#pragma braket noise two_qubit_dephasing(<float in [0,3/4]>) <qubit>, <qubit>
#pragma braket noise amplitude_damping(<float in [0,1]>) <qubit>
#pragma braket noise generalized_amplitude_damping(<float in [0,1]> <float in [0,1]>)  <qubit>
#pragma braket noise phase_damping(<float in [0,1]>) <qubit>
#pragma braket noise kraus([[<complex m0_00>, ], ...], [[<complex m1_00>, ], ...], ...) <qubit>[, <qubit>]     // maximum of 2 qubits and maximum of 4 matrices for 1 qubit, 16 for 2
```

## Kraus operator
<a name="braket-openqasm-kraus-operator"></a>

To generate a Kraus operator, you can iterate through a list of matrices, printing each element of the matrix as a complex expression.

When using Kraus operators, remember the following:
+ The number of qubits must not exceed 2. The [current definition in the schemas](https://github.com/aws/amazon-braket-sdk-python/blob/0d28a8fa89263daf5d88bc706e79200d8dc091a8/src/braket/circuits/noises.py#L811-L814)) sets this limit.
+ The length of the argument list must be a multiple of 8. This means it must be composed only of 2x2 matrices.
+ The total length does not exceed 22\$1num\$1qubits matrices. This means 4 matrices for 1 qubit and 16 for 2 qubits.
+ All supplied matrices are [completely positive trace preserving (CPTP)](https://github.com/aws/amazon-braket-sdk-python/blob/0d28a8fa89263daf5d88bc706e79200d8dc091a8/src/braket/circuits/quantum_operator_helpers.py#L94-L108).
+ The product of the Kraus operators with their transpose conjugates need to add up to an identity matrix.

# Qubit rewiring with OpenQASM 3.0
<a name="braket-openqasm-rewire-qubits"></a>

Amazon Braket supports the physical qubit notation within OpenQASM on Rigetti devices (to learn more see this [page](https://github.com/openqasm/openqasm/blob/main/source/language/types.rst)). When using physical qubits with the [naive rewiring strategy](https://pyquil-docs.rigetti.com/en/v2.28.1/compiler.html#naive), ensure that the qubits are connected on the selected device. Alternatively, if qubit registers are used instead, the PARTIAL rewiring strategy is enabled by default on Rigetti devices.

```
// ghz.qasm
// Prepare a GHZ state
OPENQASM 3;

h $0;
cnot $0, $1;
cnot $1, $2;

measure $0;
measure $1;
measure $2;
```

# Verbatim compilation with OpenQASM 3.0
<a name="braket-openqasm-verbatim-compilation"></a>

When you run a quantum circuit on quantum computers provided by vendors such as Rigetti, and IonQ, you can direct the compiler to run your circuits exactly as defined, without any modifications. This feature is known as *verbatim compilation*. With Rigetti devices, you can specify precisely what gets preserved-either an entire circuit or only specific parts of it. To preserve only specific parts of a circuit, you will need to use native gates within the preserved regions. Currently, IonQ only supports verbatim compilation for the entire circuit, so every instruction in the circuit needs to be enclosed in a verbatim box.

With OpenQASM, you can explicitly specify a verbatim pragma around a box of code that is then left untouched and not optimized by the low-level compilation routine of the hardware. The following code example shows how to use the `#pragma braket verbatim` directive to achieve this.

```
OPENQASM 3;

bit[2] c;

#pragma braket verbatim
box{
    rx(0.314159) $0;
    rz(0.628318) $0, $1;
    cz $0, $1;
}

c[0] = measure $0;
c[1] = measure $1;
```

For more detailed information on the process of verbatim compilation, including examples and best practices, see the [Verbatim compilation](https://github.com/aws/amazon-braket-examples/blob/main/examples/braket_features/Verbatim_Compilation.ipynb) sample notebook available in the amazon-braket-examples github repository.

## The Braket console
<a name="braket-openqasm-braket-console"></a>

OpenQASM 3.0 tasks are available and can be managed within the Amazon Braket console. On the console, you have the same experience submitting quantum tasks in OpenQASM 3.0 as you had submitting existing quantum tasks.

## Additional resources
<a name="braket-openqasm-more-resources"></a>

OpenQASM is available in all Amazon Braket Regions.

For an example notebook for getting started with OpenQASM on Amazon Braket, see [Braket Tutorials GitHub](https://github.com/aws/amazon-braket-examples/blob/main/examples/braket_features/Getting_Started_with_OpenQASM_on_Braket.ipynb).

# Computing gradients with OpenQASM 3.0
<a name="braket-openqasm-computing-gradients"></a>

Amazon Braket supports the computation of gradients on both on-demand and local simulators when running in the `shots=0` (exact) mode. This is achieved through the use of the adjoint differentiation method. To specify the gradient you want to compute, you can provide the appropriate pragma, as demonstrated in code in the following example.

```
OPENQASM 3.0;
input float alpha;

bit[2] b;
qubit[2] q;

h q[0];
h q[1];
rx(alpha) q[0];
rx(alpha) q[1];
b[0] = measure q[0];
b[1] = measure q[1];

#pragma braket result adjoint_gradient h(q[0]) @ i(q[1]) alpha
```

Instead of listing all the individual parameters explicitly, you can also specify the `all` keyword within the pragma. This will compute the gradient with respect to all of the `input` parameters listed, which can be a convenient option when the number of parameters is very large. In this case, the pragma will look like the code in the following example.

```
#pragma braket result adjoint_gradient h(q[0]) @ i(q[1]) all
```

All observable types are supported in Amazon Braket's OpenQASM 3.0 implementation, including individual operators, tensor products, Hermitian observables, and `Sum` observables. The specific operator you want to use when computing gradients must be wrapped within the `expectation()` function, and the qubits that each term of the observable acts upon must be explicitly specified.

# Measuring specific qubits with OpenQASM 3.0
<a name="braket-openqasm-measure-qubits"></a>

The local state vector simulator and local density matrix simulator provided by Amazon Braket support the submission of OpenQASM programs where a subset of the circuit's qubits can be selectively measured. This capability, often referred to as partial measurement, allows for more targeted and efficient quantum computations. For example, in the following code snippet, you can create a two-qubit circuit and choose to only measure the first qubit, while leaving the second qubit unmeasured.

```
partial_measure_qasm = """
OPENQASM 3.0;
bit[1] b;
qubit[2] q;
h q[0];
cnot q[0], q[1];
b[0] = measure q[0];
"""
```

In this example, we have a quantum circuit with two qubits, `q[0]` and `q[1]`, but we are only interested in measuring the state of the first qubit. This is achieved by the line `b[0] = measure q[0]`, which measures the state of qubit[0] and stores the result in the classical bit b[0]. To run this partial measurement scenario, we can run the following code on the local state vector simulator provided by Amazon Braket.

```
from braket.devices import LocalSimulator

local_sim = LocalSimulator()
partial_measure_local_sim_task = local_sim.run(OpenQASMProgram(source=partial_measure_qasm), shots = 10)
partial_measure_local_sim_result = partial_measure_local_sim_task.result()
print(partial_measure_local_sim_result.measurement_counts)
print("Measured qubits: ", partial_measure_local_sim_result.measured_qubits)
```

You can check whether a device supports partial measurement by inspecting the `requiresAllQubitsMeasurement` field in its action properties; if it is `False`, then partial measurement is supported.

```
from braket.devices import Devices
            
AwsDevice(Devices.Rigetti.Ankaa3).properties.action['braket.ir.openqasm.program'].requiresAllQubitsMeasurement
```

Here, `requiresAllQubitsMeasurement` is `False`, which indicates that not all qubits must be measured.