# AutoQASM

[![Latest Version](https://img.shields.io/pypi/v/autoqasm.svg)](https://pypi.python.org/pypi/autoqasm)
[![Supported Python Versions](https://img.shields.io/pypi/pyversions/autoqasm.svg)](https://pypi.python.org/pypi/autoqasm)
[![Build status](https://github.com/amazon-braket/autoqasm/actions/workflows/python-package.yml/badge.svg?branch=main)](https://github.com/amazon-braket/autoqasm/actions/workflows/python-package.yml)
[![codecov](https://codecov.io/gh/amazon-braket/autoqasm/graph/badge.svg?token=oO44oCLtPu)](https://codecov.io/gh/amazon-braket/autoqasm)
[![Documentation Status](https://readthedocs.org/projects/autoqasm/badge/?version=latest)](https://autoqasm.readthedocs.io/en/latest/?badge=latest)

**AutoQASM is not an officially supported AWS product.**

This experimental module offers a new quantum-imperative programming experience embedded in Python
for developing quantum programs. AutoQASM is _experimental_ software. We may change, remove, or
deprecate parts of the AutoQASM API without notice. The name AutoQASM is a working title and is
also subject to change.

For a fully supported quantum development experience, please use the Amazon Braket Python SDK by following
[these instructions](https://github.com/amazon-braket/amazon-braket-sdk-python#installing-the-amazon-braket-python-sdk).
If you are interested in our active development efforts on AutoQASM, and you are not
afraid of a few bugs, please keep on reading!

## Why AutoQASM?

AutoQASM provides a Pythonic developer experience for writing quantum programs. The working title "AutoQASM" is derived from the name of the [AutoGraph module of TensorFlow](https://www.tensorflow.org/api_docs/python/tf/autograph). AutoQASM uses AutoGraph to construct quantum assembly (QASM) programs rather than TensorFlow graphs.

AutoQASM provides a natural interface for expressing quantum programs with mid-circuit measurements
and classical control flow using native Python language features. It allows the construction of
modular programs consisting of common programming constructs such as loops and subroutines. This
enables a more imperative programming style than constructing programs via a series of function calls
on a circuit object.

AutoQASM programs can be serialized to OpenQASM. This textual representation for quantum programs is widely supported and enables interoperability among various frameworks. A crucial part of our serialization process is that modular structures within the program, such as loops and subroutines, are preserved when serializing to OpenQASM.

Although it is still a work in progress, the intent is that AutoQASM will support any quantum programming paradigm which falls into the [OpenQASM 3.0](https://openqasm.com) language scope. AutoQASM supports serializing quantum programs to OpenQASM, which allows the programs to interoperate with any library or service that supports OpenQASM programs, such as Amazon Braket.

See the [Quick Start](#quick-start) section below, as well as the AutoQASM [example notebooks](examples), for examples of AutoQASM usage.


## Installation

To install the latest experimental release of AutoQASM, use `pip`:
```
pip install autoqasm
```

Alternatively, to use AutoQASM in development mode, install from a local clone of this GitHub repository:
```
git clone https://github.com/amazon-braket/autoqasm.git
cd autoqasm
pip install -e .
```

## Quick start

In this section, we will show how to get started with AutoQASM. AutoQASM allows you to build
quantum programs with a simplified syntax and run the programs on the service. It uses the circuit
model programming paradigm that is also used in the Amazon Braket SDK.

First, import the following modules and functions:
```
import autoqasm as aq
from autoqasm.instructions import h, cnot, measure
```

To create a quantum program using the AutoQASM experience, you decorate a function with `@aq.main`.
This allows AutoQASM to hook into the program definition and generate an output format that is accepted
by quantum devices.

For instance, we can create a Bell state like so:
```
# A program that generates a maximally entangled state
@aq.main
def bell_state():
    h(0)
    cnot(0, 1)
```

You can view the output format, which is OpenQASM, by running `bell_state.build().display()`.

AutoQASM enables users to use more complicated program constructs with a compact and readable
structure. We can demonstrate this with a program that conditionally prepares multiple Bell states
on qubit pairs (1, 2) and (3, 4).
```
@aq.main(num_qubits=5)
def conditional_multi_bell_states() -> None:
    h(0)
    if measure(0):
        for i in aq.range(2):
            qubit = 2 * i + 1
            h(qubit)
            cnot(qubit, qubit+1)

    measure([0,1,2,3,4])
```

AutoQASM can support subroutines and complex control flow. You can use the Python runtime
and quantum runtime side-by-side. There are rough edges at the moment, but we're actively smoothing
them out!

AutoQASM includes a simulator which can be accessed using the Amazon Braket local simulator interface.
Let's simulate the `conditional_multi_bell_states` program:

```
from braket.devices import LocalSimulator

device = LocalSimulator("autoqasm")
task = device.run(conditional_multi_bell_states, shots=100)
result = task.result()
```

Read more about AutoQASM decorators like `@aq.main` [here](doc/decorators.md).

Read more about using AutoQASM with Amazon Braket Hybrid Jobs [here](doc/hybrid_jobs.md).

For more example usage of AutoQASM, visit the [example notebooks](examples).

## Architecture

AutoQASM is built on top of the `autograph` component of TensorFlow. A quantum program is
written as a Python function which is decorated with `@aq.main`. When calling this
decorated function, the user’s Python function is converted into a transformed Python function
by `autograph`. This transformed function is then executed to produce an AutoQASM `Program`
object which can be simulated and/or serialized to OpenQASM.

The conversion process allows AutoQASM to provide custom handling for native Python control
flow keywords such as `if`, `for`, and `while` and to preserve this control flow in the resulting
quantum program in order to realize functionality such as classical feedback on mid-circuit
measurement, efficient representation of loops, and modularity of subroutine definitions.

## Plans

The AutoQASM project is undergoing rapid development.
The current status and future plans are tracked in
the [AutoQASM GitHub project](https://github.com/orgs/amazon-braket/projects/2/).

## Contributing and sharing feedback

We welcome feature requests, bug reports, or
general feedback, which you can share with us by
[opening up an issue](https://github.com/amazon-braket/autoqasm/issues/new/choose). We also
welcome pull requests, examples, and documentation -- please open an issue describing your work
when you get started, or comment on an existing issue with your intentions.
For more details on contributing to AutoQASM, please read the
[contributing guidelines](CONTRIBUTING.md).

For questions, you can get help via the Quantum Technologies section of
[AWS RePost](https://repost.aws/topics/TAxin6L9GYR5a3NElq8AHIqQ/quantum-technologies).
Please tag your question with "Amazon Braket" and mention AutoQASM in the question title.

## Tests

To run AutoQASM unit tests, run:
```
tox -e unit-tests
```

## Frequently asked questions

###  1. Will AutoQASM be extended to contain a library of quantum algorithms or quantum applications?

No, we are focused on AutoQASM as an interface for low-level expression of
quantum programs: circuits, gates and pulses. Higher-level algorithm
libraries could be implemented using AutoQASM and benefit from modular
AutoQASM functionality such as subroutines.

### 2. What is the relationship between AutoQASM and OpenQASM?

AutoQASM is a quantum programming interface built in Python.
OpenQASM is a quantum assembly language, often used as a serialization format
for quantum programming frameworks and quantum hardware providers. We can
represent a quantum program equivalently in either format, but using AutoQASM
allows one to also make use of Python, including the Amazon Braket SDK.

AutoQASM can be seen as implementing a builder pattern for OpenQASM. It
allows you serialize your program to OpenQASM by calling `to_ir()` on the
built program. The interface is not strongly tied to OpenQASM, so we could
serialize to other formats in the future.

### 3. What is the relationship between AutoQASM and the Amazon Braket SDK?

AutoQASM lives alongside the Amazon Braket SDK as an experimental package.
It supplements the program building experience and integrates with
Amazon Braket SDK features. For instance, one can build a program through
AutoQASM, and then use the SDK to run the program on a local simulator or on
an Amazon Braket device.

### 4. Does AutoQASM support other providers beyond Amazon Braket?

Yes. AutoQASM serializes to OpenQASM, and so it is applicable to any library
or QPU that supports OpenQASM. AutoQASM does have some features that use the Amazon Braket
SDK, such as [device-specific validation](examples/4_Native_programming.ipynb).
Because AutoQASM is open-source, anyone could build similar integrations for another service.
Reach out if you're interested in doing this and would like support.

### 5. Does AutoQASM offer special support for device-specific programming?

Yes, AutoQASM has device-specific validation to support native programming.
We plan to expand this functionality in the future. Learn more with our
[native programming example notebook](examples/4_Native_programming.ipynb).

### 6. Do the devices available through Amazon Braket support all of AutoQASM's features?

No, for example, the `reset` instruction is not supported by all devices. In
general, different QPUs and QHPs support different sets of features, so
AutoQASM will often support features that a particular device doesn't
support. We intend that AutoQASM will eventually be able to generate any
program representable by OpenQASM 3.0, with additional Python-side features
such as validation and visualization.
