# Programming a neutral-atom QPU
Pulser establishes a framework for programming Quantum Processing Units (QPUs) based on neutral atoms (also named _cold-atom Quantum Processing Units_). In this page, you will learn:
- [**What mathematical objects are you programming with Pulser?**](programming.md#introduction) In quantum computing, the evolution of a quantum state is defined by an Hamiltonian. What is a quantum state in Pulser? What are the Hamiltonians that can be defined in Pulser?
- [**How to program these mathematical objects with Pulser?**](programming.md#writing-a-pulser-program) How do you define the quantum state in Pulser? How do you define the Hamiltonian? We give you a step-by-step guide on how to create a quantum program using Pulser.
## Introduction
### 1. Atoms encode the state
Neutral atoms store the quantum information in their energy levels (also known as [_eigenstates_](./conventions.md)). When only two eigenstates are used to encode information, each atom is a qubit. If these eigenstates are $\left|a\right>$ and $\left|b\right>$, then the state of an atom is described by $\left|\psi\right> = \alpha \left|a\right> + \beta \left|b\right>$, with $|\alpha|^2 + |\beta|^2 = 1$.
Definition of a quantum state with multiple atoms
When multiple atoms are used, the state of the system is described by a linear combination of the _eigenstates_ of the multi-atom system, whose set is obtained by making the cross product of the set of eigenstate of each atom. If each atom is described by $d$ eigenstates labelled ${\left|a_1\right>, \left|a_2\right>...\left|a_d\right>}$ (each atom is a _qudit_), and if there are $N$ atoms in the system, then the state of the whole system is provided by
$$
\begin{align}
\left|\Psi\right> &= \sum_{i_1, ..., i_N \in [1, ..., d]} c_{i_1, ..., i_N} \left|a_{i_1}...a_{i_N}\right> \\
&= c_{1, 1, ..., 1}\left|a_{1}a_{1}...a_{1}\right> + ... + c_{1, 1, ..., d}\left|a_{1}a_{1}...a_{d}\right> + ... + c_{d, d, ..., d}\left|a_{d}a_{d}...a_{d}\right>
\end{align}
$$
where $\sum_{i_1, ..., i_N \in [1, ..., d]} |c_{i_1, ..., i_N}|^2 = 1$. If $d=2$, then this becomes
$$
\left|\Psi\right> = c_{1, 1, ..., 1}\left|a_{1}a_{1}...a_{1}\right> + c_{1, 1, ..., 2}\left|a_{1}a_{1}...a_{2}\right> + ... + c_{2, 2, ..., 2}\left|a_{2}a_{2}...a_{2}\right>
$$
If $d=2$ and $N=1$, you have the state of a qubit as above $\left|\Psi\right> = c_{1}\left|a_{1}\right> + c_{2}\left|a_{2}\right>$.
### 2. Hamiltonian evolves the state
In quantum physics, the state of a quantum system evolves along time following the Schrödinger equation:
$$i\frac{d\left|\Psi\right>(t)}{dt} = \frac{H(t)}{\hbar} \left|\Psi\right>(t)$$
Here $H(t)$ is the Hamiltonian describing the evolution of the system. For a system of atoms in the initial state $\left|\Psi_0\right>$, the final state of the system after a time $\Delta t$ is:
$$ \left|\Psi_f\right> = \mathcal{T}\exp\left(-\frac{i}{\hbar}\int_0^{\Delta t} H(t) dt\right)\left|\Psi_0\right>$$
:::{tip}
The equation below uses the [Indexed Operator](conventions.md#indexed-operator) notation.
:::
The Hamiltonian describing the evolution of the system can be written as
$$
H(t) = \sum_i \left (H^D_i(t) + \sum_{j
Rotations on the Bloch sphere
In the Bloch sphere representation, this Hamiltonian describes a rotation around the axis $\overrightarrow{\Omega}(t) = (\Omega(t)\cos(\phi), -\Omega(t)\sin(\phi), -\delta(t))^T$, with angular velocity $\Omega_{eff}(t) = |\overrightarrow{\Omega}(t)| = \sqrt{\Omega^2(t) + \delta^2(t)}$.
For a resonant pulse ($\delta(t)=0$) of duration $\Delta t$, we rotate of an angle $\int_0^{\Delta t} \Omega (t) dt$ around the fixed axis $(\cos(\phi), -\sin(\phi), 0)$ (on the equator of the Bloch sphere).
:::{figure} files/bloch_rotation_a_b.png
:align: center
:alt: Representation of the drive Hamiltonian's dynamics as a rotation in the Bloch sphere.
:width: 300
Representation of the drive Hamiltonian's dynamics as a rotation in the Bloch sphere. The coherent excitation is driven between a lower energy level, $|a\rangle$, and a higher energy level,
$|b\rangle$, with Rabi frequency $\Omega(t)$, detuning $\delta(t)$ and phase $\phi$.
:::
:::{important}
With Pulser, you program the driving Hamiltonian by setting $\Omega(t)$, $\delta(t)$ and $\phi(t)$, all the while Pulser ensures that you respect the constraints of your chosen device.
:::
#### 2.2. Interaction Hamiltonian
The interaction Hamiltonian depends on the distance between the atoms $i$ and $j$, $R_{ij}$, and the energy levels in which the information is encoded in these atoms, that define the interaction between the atoms $\hat{U}_{ij}$
$$
H^\text{int}_{ij} = \hat{U}_{ij}(R_{ij})
$$
The interaction operator $\hat{U}_{ij}$ is composed of an entangling operator and an interaction strength.
:::{note}
The interaction Hamiltonian is constant over time. It is always on, no matter the values of the drive Hamiltonian (even if the values of the parameters $\Omega$, $\delta$, $\phi$ are equal to $0$ over a time $\Delta t$).
:::
##### Ising Hamiltonian
If the Rydberg state $\left|r\right>$ is involved in the computation, then
$$
\hat{U}_{ij}(R_{ij}) = \frac{C_6}{R_{ij}^6} \hat{n}_i \hat{n}_j
$$
Interaction strength and entangling operator
- The interaction strength is $\frac{C_6}{R_{ij}^6}$, with $C_6$ the Ising interaction coefficient that depends on the principal quantum number of the Rydberg state.
- The entangling operator between atom $i$ and $j$ is $\hat{n}_i\hat{n}_j = |r\rangle\langle r|_i |r\rangle\langle r|_j$.
Together with the driving Hamiltonian, this interaction encodes the _Ising Hamiltonian_ and is the **most common choice in neutral-atom devices.**
##### XY Hamiltonian
If the information is stored in the Rydberg states $\left|0\right>$ and $\left|1\right>$ (the so-called `XY` basis), then
$$
\hat{U}_{ij}(R_{ij}) =\frac{C_3}{R_{ij}^3} (|1\rangle\langle 0|_i |0\rangle\langle 1|_j + |0\rangle\langle 1|_i |1\rangle\langle 0|_j)
$$
Interaction strength in the XY Hamiltonian
- The interaction strength is $\frac{C_3}{R_{ij}^3}$, with $C_3$ a coefficient that depends on the energy levels used to encode $\left|0\right>$ and $\left|1\right>$.
This interaction hamiltonian is associated with the _XY Hamiltonian_ and is a less common mode of operation, usually accessible only in select neutral-atom devices.
:::{important}
With Pulser, you program the interaction Hamiltonian by setting the distance between atoms, $R_{ij}$. Additionally, the choice of eigenstates used in the computation and the Rydberg level(s) targeted by the device fully determine the interaction strength. Most commonly, the ground and Rydberg states ($\left|g\right>$ and $\left|r\right>$) are used, such that
$$H^\text{int}_{ij} = \frac{C_6}{R_{ij}^6} \hat{n}_i\hat{n}_j$$
When providing the distance between atoms, Pulser ensures that you respect the constraints of your chosen device.
:::
## Writing a Pulser program
As outlined above, Pulser lets you program an Hamiltonian ([the Hamiltonian $H$](programming.md#2-hamiltonian-evolves-the-state)) so that you can manipulate the quantum state of a system of atoms. The series of necessary instructions is encapsulated in the so-called Pulser `Sequence`. Here is a step-by-step guide to create your own Pulser `Sequence`.
### 1. Pick a Device
:::{figure} files/decision_diagram_device.png
:align: center
:alt: Decision Diagram to select a Device for the computation
:width: 600
:::
The `Device` you select will dictate some parameters and constrain others. For instance, the value of the $C_6$ and $C_3$ coefficients of the [interaction Hamiltonian](programming.md#22-interaction-hamiltonian) are defined by the device. Notably, the `Device` defines the list of `Channels` that can be used in the computation, which have a direct impact on the Hamiltonian that can be implemented.
:::{seealso}
For a complete view of the constraints introduced by the device, [check its description](./hardware.ipynb).
:::
### 2. Create the Register
The `Register` defines the position of the atoms. This determines:
- the number of atoms to use in the quantum computation, i.e, the size of the system (let's note it $N$).
- the distance between the atoms, the $R_{ij}\ (1\le i, j\le N)$ parameters in the [interaction Hamiltonian](programming.md#22-interaction-hamiltonian).
:::{seealso}
For an in-depth view on Register creation, check out [this page](register.ipynb).
:::
### 3. Pick the Channels
A `Channel` targets the transition between two energy levels. Therefore, picking channels defines the energy levels that will be used in the computation. The channels must be picked from the `Device.channels`, so your device selection should take into account the channels it supports.
Picking the channel will initialize the state of the system, and fully determine the [interaction Hamiltonian](programming.md#22-interaction-hamiltonian):
- If the selected Channel is the `Rydberg` or the `Raman` channel, the system is initialized in $\left|gg...g\right>$ and the interaction Hamiltonian is the [Ising Hamiltonian](programming.md#ising-hamiltonian)
$$H^\text{int}_{ij} =\frac{C_6}{R_{ij}^6}|r\rangle\langle r|_i |r\rangle\langle r|_j$$
- If the selected Channel is the `Microwave` channel, the system is initialized in $\left|00...0\right>$ and the interaction Hamiltonian is the [XY Hamiltonian](programming.md#xy-hamiltonian)
$$H^\text{int}_{ij} =\frac{C_3}{R_{ij}^3}|1\rangle\langle 0|_i |0\rangle\langle 1|_j + |0\rangle\langle 1|_i |1\rangle\langle 0|_j$$
:::{important}
At this stage, the [interaction Hamiltonian](programming.md#22-interaction-hamiltonian) is fully determined.
:::
A `Channel` is also characterized by its addressing, which defines the number of atoms that are going to be targeted by a pulse. If the addressing of a `Channel` is `Global`, all the atoms will experience the same pulse targetting the same transition. In the [Hamiltonian $H$](programming.md#2-hamiltonian-evolves-the-state), all the driving Hamiltonians $H^D_i$ are expressed as
$$
H^D_i(t) / \hbar = \frac{\Omega(t)}{2} e^{-j\phi(t)} |a\rangle_i \langle b|_i + \frac{\Omega(t)}{2} e^{j\phi(t)} |b\rangle_i\langle a|_i - \delta(t) |b\rangle_i\langle b|_i
$$
If the addressing of a `Channel` is `Local`, then only certain atoms (the "targets") will experience the pulse and have their evolution follow $H^D_i$. The driving Hamiltonian of the other atoms is $H^D_i = \hat{0}_i$. The Hamiltonian $H$ can also be rewritten:
$$
H(t) = \sum_{i \in targets} H^D_i(t) + \sum_i \sum_{j$ and $\left|b\right>$ of the driving Hamiltonian.
By applying a series of pulses and delays, one defines the entire driving Hamiltonian of each atom over time.
:::{seealso}
For an in-depth view on Pulse creation, check out [this page](pulses.ipynb).
:::
## Conclusion
We have successfully defined the [Hamiltonian](programming.md#2-hamiltonian-evolves-the-state) $H$ describing the evolution of the system over time, by:
- Picking a `Device`, which defines the value of the $C_6$ or $C_3$ coefficients.
- Creating a `Register` of atoms, which defines the number of atoms used and the distance between them, $R_{ij}$.
- Selecting the `Channels` of the `Device` to use, which define the energy levels of the atoms to use - this step completely defines the [interaction Hamiltonian](programming.md#22-interaction-hamiltonian). The addressing property of each `Channel` also dictates the atoms that will be targeted by the `Pulse`.
- Adding `Pulse` and delays to the `Channel`s defines the [driving Hamiltonian](programming.md#21-driving-hamiltonian) of each atom along time.
You can now simulate your first Hamiltonian by programming your first `Sequence`! [In this tutorial](tutorials/creating.nblink), you will simulate the evolution of the state of an atom initialized in $\left|g\right>$ under a Hamiltonian $H(t)=\frac{\Omega(t)}{2} |g\rangle \langle r|+\frac{\Omega(t)}{2} |r\rangle\langle g|$, with $\Omega$ chosen such that the final state of the atom is the excited state $\left|r\right>$.
Many concepts have been introduced here and you might want further explanations.
- The `Device` object contains all the constraints and physical quantities that are defined in a QPU. [This section in the fundamentals](./hardware.ipynb) details these and provides examples of `Devices`. The `VirtualDevices` were also mentioned in this document ([here](programming.md#1-pick-a-device)), which is a more advanced feature described [here](tutorials/virtual_devices.nblink).
- There are multiple ways of defining a `Register`, as is further detailed [in this section](tutorials/reg_layouts.nblink).
- The energy levels associated with each `Channel` and the interaction Hamiltonian they implement are summed up in [the conventions page](conventions.md). The channels contain lots of constraints and physical informations, they are detailed in [the same section as the `Device`](./hardware.ipynb).
- The quantities in a `Pulse` are defined using `Waveform`s, you can read more about these [on this page](tutorials/composite_wfs.nblink).