{ "cells": [ { "cell_type": "markdown", "id": "2a6852ac-a3b9-4114-85ac-2be21c6633b0", "metadata": {}, "source": [ "# Register and Rydberg-Atom Interactions" ] }, { "cell_type": "markdown", "id": "e6b26e9c", "metadata": {}, "source": [ "*What you will learn:*\n", "- what is a `Register` and how to create it;\n", "- why the relative position of the atoms in a `Register` is important;\n", "- what is the Rydberg blockade;\n", "- how the design of the `Register` may be influenced by the rest of the `Sequence`;\n", "- tips on how to design a `Register` for different applications." ] }, { "cell_type": "markdown", "id": "979ebffc-2017-4b9c-8aa3-27bceda01d38", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "## The `Register`\n", "\n", "The `Register` is a group of cold atoms placed in space according to a user-defined configuration. Each atom is in a quantum state encoded in [specific electronic levels](conventions.md#states-and-bases). Usually these are two-level systems and we refer to them as **qubits**.\n", "\n", "### Standard definition\n", "\n", "There are multiple ways to define a `Register`, the most customizable one being to create a dictionary that associates a name (the key) to a cooordinate (the value).\n", "\n", "
\n", "\n", "Despite being given as a mapping to `Register`, **the order of the qubits matters** and is preserved. In particular, this order is respected in the [representation of multi-partite quantum states](conventions.md#multi-partite-states). When in doubt, it can be accessed via `Register.qubit_ids`. \n", "\n", "
" ] }, { "cell_type": "code", "execution_count": null, "id": "6b039af2-22d5-47ad-bc8a-97ef57737b08", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "import pulser\n", "\n", "# Manually generate the IDs and coordinates of a 2x2 square with 5μm spacing\n", "qubits = {\"q0\": [0, 0], \"q1\": [5, 0], \"q2\": [0, 5], \"q3\": [5, 5]}\n", "reg = pulser.Register(qubits)\n", "reg.draw()" ] }, { "cell_type": "markdown", "id": "66df3519-7d33-4557-8d6d-ac9fb179b380", "metadata": {}, "source": [ "### From coordinates\n", "\n", "When it is convenient to label the qubits automatically, the `Register` can also be created from a list of coordinates (using the `Register.from_coordinates` class method). In this case, the qubit ID's are just numbered, starting from 0, in the order they are provided in, with the option of adding a common prefix before each number. Also, it automatically centers the entire array around the origin, an option that can be disabled if desired." ] }, { "cell_type": "code", "execution_count": null, "id": "0a265ebd-d379-4ba3-b735-bae87216c176", "metadata": {}, "outputs": [], "source": [ "import pulser\n", "\n", "reg2 = pulser.Register.from_coordinates(\n", " [[0, 0], [5, 0], [0, 5], [5, 5]], # Takes just the coordinates\n", " prefix=\"q\", # All qubit IDs will start with 'q'\n", " center=True,\n", ")\n", "print(\"(Centered) qubits:\", reg2.qubits)" ] }, { "cell_type": "markdown", "id": "5fac062c-b653-4c32-84c9-f72b3b8e8334", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### From common patterns\n", "\n", "Furthermore, there are built-in class methods for creation of common array patterns - for instance, `Register.square()` offers a convenient shortcut to make a register in a centered square configuration, so it does not have to be done manually as done above." ] }, { "cell_type": "raw", "id": "38dd64e4-472b-46f7-8617-dbdbcbadb160", "metadata": { "editable": true, "raw_mimetype": "text/restructuredtext", "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ ".. currentmodule:: pulser.register.register\n", "\n", ".. autosummary::\n", "\n", " Register.square\n", " Register.rectangle\n", " Register.rectangular_lattice\n", " Register.triangular_lattice\n", " Register.hexagon" ] }, { "cell_type": "markdown", "id": "a05f8e2d", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "For more information on all the `Register` methods, please refer to the [Register API reference](apidoc/_autosummary/pulser.register.Register.rst#register)." ] }, { "cell_type": "markdown", "id": "cd280505", "metadata": {}, "source": [ "## Rydberg-Atom Interactions\n", "\n", "When an atom is excited to a Rydberg state, nearby atoms interact according to the [interaction Hamiltonian](programming.md#interaction-hamiltonian). The interaction strength is always dependent on the distance between atoms and is stronger the closer they are. Therefore, appropriately selecting the atoms' relative positions is a crucial step in the programming of neutral-atom QPUs. \n", "\n", "In the most common case of the [Ising Hamiltonian](programming.md#ising-hamiltonian), the interaction operator is given by\n", "\n", "$$\n", "\\hat{U}_{ij} = \\frac{C_6}{R_{ij}^6} \\hat{n}_i \\hat{n}_j,\n", "$$\n", "\n", "where \n", "\n", "- the interaction strength is $\\frac{C_6}{R_{ij}^6}$, where $C_6$ is a coefficient that depends on the principal quantum number of the Rydberg state the atoms are excited to;\n", "- 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$. \n", "\n", "Note that:\n", "\n", "1. The interaction strength scales with $R_{ij}^{-6}$, so it decays rapidly when the distance between the atoms increases.\n", "2. There is only an interaction when both atoms are excited to their respective Rydberg states, $|r\\rangle_i$ and $|r\\rangle_j$." ] }, { "cell_type": "markdown", "id": "7023920c", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "## The Rydberg Blockade \n", "\n", "Consider a system of two atoms, $R$ distance apart, that we want to excite from the $|gg\\rangle$ state to the $|rr\\rangle$ state. To keep things simple, we'll use a global resonant pulse (i.e.$\\delta=0$) with constant Rabi frequency $\\Omega(t) = \\Omega$ and phase $\\phi=0$, so that the [full Hamiltonian](programming.md#hamiltonian-evolves-the-state) is\n", "\n", "$$H = \\frac{\\hbar\\Omega}{2}\\left[\\mathbb{I} \\otimes \\sigma_x + \\sigma_x \\otimes \\mathbb{I} \\right] + \\frac{C_6}{R^6} |rr\\rangle\\langle rr|,$$\n", "\n", "where $\\sigma_x = |g\\rangle\\langle r| + |r\\rangle\\langle g|$.\n", "\n", "The interaction Hamiltonian dictates that there is an additional energy of $C_6/R^6$ for being in the $|rr\\rangle$ state - that is to say, the energy of the $|rr\\rangle$ state is shifted by this amount.\n", "\n", "When we try to drive the transition to the $|rr\\rangle$ state, the excitation does not occur when $\\hbar\\Omega \\ll C_6/R^6$, i.e the energy of the drive is not sufficient to overcome the extra cost of having the system in in the $|rr\\rangle$ state - this is the so-called *Rydberg blockade*. Instead, the system is excited to $(|gr\\rangle + |rg\\rangle)/\\sqrt{2}$ (notably, an entangled state) with effective Rabi frequency $\\sqrt{2}\\Omega$. \n", "\n", "From the Rydberg blockade condition, we define the **Rydberg blockade radius** as\n", "\n", "$$R_b = \\left(\\frac{C_6}{\\hbar\\Omega}\\right)^{(1/6)}$$\n", "\n", "For any pair of atoms $i$ and $j$ in a system under a global resonant drive:\n", "- When $R_{ij} \\ll R_b$, the excitation to $|rr\\rangle$ is suppressed.\n", "- When $R_{ij} \\gg R_b$, the excitation to $|rr\\rangle$ occurs.\n", "\n", "
\n", " \"Rydberg\n", "
The Rydberg blockade: The energy of the $|rr\\rangle$ state (blue line) increases signficantly for atoms less than a blockade radius ($R_\\text{Blockade}$ in this picture, $R_b$ elsewhere this document) away. As such, the transition to $|rr\\rangle$ is suppressed when $R_{ij} \\ll R_b$. Source: Quantum 6, 629 (2022)\n", "
\n", "
\n", "\n", "
\n", "\n", "**Important notes**:\n", "\n", "- The Rydberg blockade radius is only a useful approximation to reason about whether two atoms interact significantly; it *should not* be interpreted as a discrete threshold beyond which there are no interactions.\n", "- In fact, the approximation is least adequate for values of $R_{ij} \\approx R_b$, so placing atoms at distances close to $R_b$ should be done extra carefully.\n", "- Furthermore, $R_b$ depends on the Rabi frequency $\\Omega$; as such, **fixing** $R_b$ **also determines** $\\Omega$ and vice-versa. \n", "\n", "
" ] }, { "cell_type": "markdown", "id": "935fb6c0", "metadata": {}, "source": [ "### Estimating the Rydberg blockade radius\n", "\n", "The `Device` class includes methods to calculate the Rydberg blockade radius for a given value of Rabi frequency and vice-versa." ] }, { "cell_type": "code", "execution_count": null, "id": "164cde0c", "metadata": {}, "outputs": [], "source": [ "import pulser\n", "\n", "# Blockade radius from Rabi frequency\n", "omega = 1 # rad/μs\n", "rb = pulser.AnalogDevice.rydberg_blockade_radius(omega) # μm\n", "print(f\"Rydberg blockade radius for Ω={omega} rad/μs: {rb} μm\")\n", "\n", "# Rabi frequency from Blockade radius\n", "rb = 8 # μm\n", "omega = pulser.AnalogDevice.rabi_from_blockade(rb) # rad/μs\n", "print(f\"Rydberg blockade radius for Ω={omega} rad/μs: {rb} μm\")" ] }, { "cell_type": "markdown", "id": "4c39956e", "metadata": {}, "source": [ "### Visualising interactions\n", "\n", "The `Register.draw()` method includes options to plot the Rydberg blockade radius and identifiy interacting atoms. By specifying a value for `blockade_radius`,\n", "- `draw_half_radius=True` draws a circle with **half** the Rydberg blockade radius on each atom; when two circles overlap, the atoms are within a blockade radius of each other.\n", "- `draw_graph=True` draws connections between the atoms within a blockade radius of each other." ] }, { "cell_type": "code", "execution_count": null, "id": "6d1aa660", "metadata": {}, "outputs": [], "source": [ "from pulser import Register\n", "\n", "# 4x3 triangular lattice with 6μm spacing\n", "tri_reg = Register.triangular_lattice(\n", " rows=4, atoms_per_row=3, spacing=6.0, prefix=\"q\"\n", ")\n", "# Draw the interactions for Rb=7 μm\n", "tri_reg.draw(\n", " blockade_radius=7, # μm\n", " draw_half_radius=True, # Draws circles with radius Rb/2\n", " draw_graph=True, # Draws edges between interacting atoms\n", ")" ] }, { "cell_type": "markdown", "id": "ce1defb6", "metadata": {}, "source": [ "## Tips for `Register` design" ] }, { "cell_type": "markdown", "id": "12f85b91", "metadata": {}, "source": [ "Choosing the best position for the atoms in a `Register` is generally a hard problem and depends heavily on the application. In this section, we provide some strategies that, while far from exhaustive, may help in the `Register` creation process in specfic cases." ] }, { "cell_type": "markdown", "id": "40247508", "metadata": {}, "source": [ "### Think of the full Hamiltonian\n", "\n", "When using a neutral-atom QPU to simulate a quantum many-body system, it is important to remember that the interaction Hamiltonian is but one part of the full Hamiltonian. In particular, the strength of the interaction terms must always be considered in relation to the driving Hamiltonian terms (i.e. $\\Omega$ and $\\delta$) - in fact, the interdependence between $R_b$ and $\\Omega$ is itself a prime example as to why these terms should not be designed in isolation.\n", "\n", "Take the example of [AFM state preparation](tutorials/creating.nblink#Adiabatic-preparation-of-an-Anti-Ferromagnetic-State), where the interaction strength must be balanced with the appropriate value of $\\delta>0$; without taking the full Hamiltonian into account, we could end up with:\n", "- $\\delta$ too low, which would not promote atoms to the $|r\\rangle$ state, or\n", "- $\\delta$ too high, which would make all atoms go to the $|r\\rangle$ state, regardless of their nearest neighbours being also in $|r\\rangle$.\n", "\n", "In these cases, it is only by first considering the full Hamiltonian that we are able to correctly design the register." ] }, { "cell_type": "markdown", "id": "c05632f6", "metadata": {}, "source": [ "### Encode a cost function\n", "\n", "Akin to a penalty term in a cost function, the interaction Hamiltonian makes some quantum states energetically less favourable. By appropriately adjusting the distances between atoms, the penalty of specific candidate solutions can sometimes be replicated in the interaction Hamiltonian.\n", "\n", "Examples where this approach is useful include:\n", "- some instances of [QUBO](https://en.wikipedia.org/wiki/Quadratic_unconstrained_binary_optimization) problems,\n", "- other optimization problems where the ground-state of the Hamiltonian encodes a minimizer of the cost function.\n" ] }, { "cell_type": "markdown", "id": "bc0b100b", "metadata": {}, "source": [ "### Start from a connectivity graph\n", "\n", "In the formulation of some problems, the exact value of the interaction strength between two atoms is not relevant; instead, all that matters is the presence or absence of interactions. As such, we can express these interactions through a so-called *connectivity graph*, where a node is an atom and an edge connects interacting atoms (as drawn in [this section](#Visualising-interactions)).\n", "\n", "In these cases, the [Rydberg blockade radius](#The-Rydberg-Blockade) provides a useful approximation by allowing us to place interacting atoms well within a blockade radius of each other and non-interacting atoms well outside it. Turning a connectivity graph into a `Register` is particularly straigthfoward when the connectivity graph can be represented as a [Unit-Disk graph](https://en.wikipedia.org/wiki/Unit_disk_graph). \n", "\n", "Examples where this approach is useful include:\n", "- finding the Maximum Independent Set of a Unit-Disk graph,\n", "- placing atoms for execution of multi-qubit gates." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 5 }