From c0d4838501a6b223e855818e457f058bbd11e674 Mon Sep 17 00:00:00 2001 From: HGSilveri Date: Mon, 9 Dec 2024 10:54:24 +0100 Subject: [PATCH 01/44] Setting up Markdown support --- docs/requirements.txt | 1 + docs/source/conf.py | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 9a81cc89c..5c9ef500f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,6 +5,7 @@ sphinx_autodoc_typehints == 1.21.3 nbsphinx nbsphinx-link ipython >= 8.10 # Avoids bug with code highlighting +myst-parser # Not on PyPI # pandoc diff --git a/docs/source/conf.py b/docs/source/conf.py index 507fb0657..3e4e9f502 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -34,6 +34,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "myst_parser", "nbsphinx", "nbsphinx_link", "sphinx.ext.autodoc", From 82c2070b086db5aa1466a45980eac44da9b4362d Mon Sep 17 00:00:00 2001 From: HGSilveri Date: Mon, 9 Dec 2024 14:09:11 +0100 Subject: [PATCH 02/44] Convert Conventions page to markdown --- docs/source/conf.py | 17 +++ docs/source/conventions.md | 260 ++++++++++++++++++++++++++++++++++++ docs/source/conventions.rst | 246 ---------------------------------- 3 files changed, 277 insertions(+), 246 deletions(-) create mode 100644 docs/source/conventions.md delete mode 100644 docs/source/conventions.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 3e4e9f502..410bd7f33 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,6 +43,23 @@ "sphinx_autodoc_typehints", ] +myst_enable_extensions = [ + "amsmath", + "attrs_inline", + "colon_fence", + "deflist", + "dollarmath", + # "fieldlist", + # "html_admonition", + "html_image", + # "linkify", + # "replacements", + # "smartquotes", + # "strikethrough", + # "substitution", + # "tasklist", +] + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/docs/source/conventions.md b/docs/source/conventions.md new file mode 100644 index 000000000..73c7e3b34 --- /dev/null +++ b/docs/source/conventions.md @@ -0,0 +1,260 @@ +# Conventions + +## States and Bases + +### Bases + +A basis refers to a set of two eigenstates. The transition between +these two states is said to be addressed by a channel that targets that basis. Namely: + +```{eval-rst} +.. list-table:: + :align: center + :widths: 50 35 35 + :header-rows: 1 + + * - Basis + - Eigenstates + - ``Channel`` type + * - ``ground-rydberg`` + - :math:`|g\rangle,~|r\rangle` + - ``Rydberg`` + * - ``digital`` + - :math:`|g\rangle,~|h\rangle` + - ``Raman`` + * - ``XY`` + - :math:`|0\rangle,~|1\rangle` + - ``Microwave`` + + +``` + +### Qutrit state + +The qutrit state combines the basis states of the `ground-rydberg` and `digital` bases, +which share the same ground state, $|g\rangle$. This qutrit state comes into play +in the digital approach, where the qubit state is encoded in $|g\rangle$ and +$|h\rangle$ but then the Rydberg state $|r\rangle$ is accessed in multi-qubit +gates. + +The qutrit state's basis vectors are defined as: + +$$ +|r\rangle = (1, 0, 0)^T,~~|g\rangle = (0, 1, 0)^T, ~~|h\rangle = (0, 0, 1)^T. +$$ + +### Qubit states + +:::{caution} +There is no implicit relationship between a state's vector representation and its +associated measurement value. To see the measurement value of a state for each +measurement basis, see {ref}`spam-table` . +::: + +When using only the `ground-rydberg` or `digital` basis, the qutrit state is not +needed and is thus reduced to a qubit state. This reduction is made simply by tracing-out +the extra basis state, so we obtain + +- `ground-rydberg`: $|r\rangle = (1, 0)^T,~~|g\rangle = (0, 1)^T$ +- `digital`: $|g\rangle = (1, 0)^T,~~|h\rangle = (0, 1)^T$ + +On the other hand, the `XY` basis uses an independent set of qubit states that are +labelled $|0\rangle$ and $|1\rangle$ and follow the standard convention: + +- `XY`: $|0\rangle = (1, 0)^T,~~|1\rangle = (0, 1)^T$ + +### Multi-partite states + +The combined quantum state of multiple atoms respects their order in the `Register`. +For a register with ordered atoms `(q0, q1, q2, ..., qn)`, the full quantum state will be + +$$ +|q_0, q_1, q_2, ...\rangle = |q_0\rangle \otimes |q_1\rangle \otimes |q_2\rangle \otimes ... \otimes |q_n\rangle +$$ + +:::{note} +The atoms may be labelled arbitrarily without any inherent order, it's only the +order with which they are stored in the `Register` (as returned by +`Register.qubit_ids`) that matters . +::: + + +## State Preparation and Measurement + +```{eval-rst} +.. list-table:: Initial State and Measurement Conventions + :name: spam-table + :align: center + :widths: 60 40 75 + :header-rows: 1 + + * - Basis + - Initial state + - Measurement + * - ``ground-rydberg`` + - :math:`|g\rangle` + - | + | :math:`|r\rangle \rightarrow 1` + | :math:`|g\rangle,|h\rangle \rightarrow 0` + * - ``digital`` + - :math:`|g\rangle` + - | + | :math:`|h\rangle \rightarrow 1` + | :math:`|g\rangle,|r\rangle \rightarrow 0` + * - ``XY`` + - :math:`|0\rangle` + - | + | :math:`|1\rangle \rightarrow 1` + | :math:`|0\rangle \rightarrow 0` +``` + +### Measurement samples order + +Measurement samples are returned as a sequence of 0s and 1s, in +the same order as the atoms in the `Register` and in the multi-partite state. + +For example, a four-qutrit state $|q_0, q_1, q_2, q_3\rangle$ that's +projected onto $|g, r, h, r\rangle$ when measured will record a count to +sample + +- `0101`, if measured in the `ground-rydberg` basis +- `0010`, if measured in the `digital` basis + +## Hamiltonians + +Independently of the mode of operation, the Hamiltonian describing the system +can be written as + +$$ +H(t) = \sum_i \left (H^D_i(t) + \sum_{j Date: Mon, 9 Dec 2024 14:42:30 +0100 Subject: [PATCH 03/44] Attempt to use auto-generated labels --- docs/source/conf.py | 2 ++ .../advanced_features/State Preparation with the SLM Mask.ipynb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 410bd7f33..e40503e2a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,6 +60,8 @@ # "tasklist", ] +myst_heading_anchors = 3 + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/tutorials/advanced_features/State Preparation with the SLM Mask.ipynb b/tutorials/advanced_features/State Preparation with the SLM Mask.ipynb index 807cd2c9f..a4826cede 100644 --- a/tutorials/advanced_features/State Preparation with the SLM Mask.ipynb +++ b/tutorials/advanced_features/State Preparation with the SLM Mask.ipynb @@ -154,7 +154,7 @@ "id": "21c01972", "metadata": {}, "source": [ - "Now let's see how the system evolves under this masked pulse. Since the pulse only acts on the first qubit, we expect the final state to be $\\left| 100 \\right\\rangle$, or, according to [Pulser's conventions for XY basis states](../conventions.rst#qubit-states), $(0,1)^T \\otimes (1,0)^T \\otimes (1,0)^T$ in the Hilbert space $C^8$:" + "Now let's see how the system evolves under this masked pulse. Since the pulse only acts on the first qubit, we expect the final state to be $\\left| 100 \\right\\rangle$, or, according to [Pulser's conventions for XY basis states](../conventions.md#qubit-states), $(0,1)^T \\otimes (1,0)^T \\otimes (1,0)^T$ in the Hilbert space $C^8$:" ] }, { From d62edaf39adf043d1ce8f53ccd89f661cc0668db Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 12 Dec 2024 11:01:48 +0100 Subject: [PATCH 04/44] Introduce section about hardware --- docs/source/hardware.md | 62 +++++++++++++++++++++++++++++++++++++++++ docs/source/index.rst | 1 + 2 files changed, 63 insertions(+) create mode 100644 docs/source/hardware.md diff --git a/docs/source/hardware.md b/docs/source/hardware.md new file mode 100644 index 000000000..919d4e791 --- /dev/null +++ b/docs/source/hardware.md @@ -0,0 +1,62 @@ +# Neutral-atom Hardware + +## How does a neutral-atom Quantum Computer work ? + +A neutral-atom Quantum Computer is composed of neutral-atoms (typically, atoms of Rubidium or Cesium that belong to the first column of the Mendeleiev table, but quantum computing platforms have also been built using atoms of Ytterbium and Dysprosium that belong to the second column of the Mendeleiev table). To perform quantum computations with these atoms, we "cool" them down to very small temperatures (typically, $`10\mu`K) using lasers. Note: The neutral-atoms are in fact slowed down, and the temperature here is associated to their speed. Neutral-atom Quantum Computers are sometimes named cold-atom Quantum Computers because the atoms are "cold", ie there associated temperature is small. + +Since these atoms are cold, they can be trapped in space using another kind of lasers (see the `RegisterLayout` object in the extended section). They can then be rearranged and re-trapped in a specific pattern, that we name the register (see the `Register` section of the fundamentals). The atoms spend enough time trapped such that we are sure they are all in the ground state (the initial state for the computations, see the [conventions page](conventions.md)). + +The computation in itself can then happen: a serie of laser pulses are applied on the atoms to modify their state. The laser pulses can target different transition, each transition being associated to a different laser channel (see below). + +Once the computation is over, the state of the atoms is measured. Here as well, this is done using lasers: some light is shine on the atoms, the atoms that re-emit this light are measured in the ground-state and are labelled `0`, the others are described as being in an excited state and are labelled `1` (see the [convention page](conventions.md) for more). + +## Physical parameters to take into account in quantum computations + +As sketched in the above section, making a quantum computation with a neutral-atom device involves multiple steps and the use of multiple lasers. At each step and laser used, the physics of the device constrains the displacement of the atoms. In `Pulser`, all the physical constrains are stored in the `Device` object. + +### Device + +The `Device` class stores all the physical constrains the quantum computations should match. To perform any computation using Pulser, it is necessary to provide a device. For convenience, some examples of typical physical devices are included and can be accessed via `pulser.devices`. These devices are instances of the `Device` class. They are constrained by physical considerations and all their parameters are defined. An example of such a `Device`, the `pulser.AnalogDevice`, is provided below. + +If we go back to the timeline of a quantum computation using a neutral-atom device, the first step is the trapping of atoms in space and their rearrangement into a defined register. The first constraints concern the definition of the layout of traps and the register. They can be defined in 2D or 3D (check the `dimensions` attribute) but the register of atoms must be a subset of the layout of traps. Therefore, some constrains apply to both: the distance between each traps/atoms must be greater than the distance `min_atom_distance`, the traps/atoms should not be defined at a distance greater than `max_radial_distance` from the center. + +The register is a subset of the number of traps because by default some stochastical effects are at play, such that in theory a trap has a probability 1/2 to be filled by an atom. That way, there is a maximum number of traps of the layout that can be filled by an atom from the register (given by `max_layout_filling`), and there is also an optimal for this filling, (given by `optimal_layout_filling`). + +In terms of performance, there is a maximum number of atoms that can be trapped and rearranged in the register (`max_atom_num`) and a maximum number of traps that can be defined in the layout (`max_layout_traps`). From the considerations above, these two numbers are different. There is also a minimum number of traps to have in the layout (`min_layout_traps`). + +The considerations about the layout are unnessary if the device does not require one to be associated with the `Register`, which is given by the `requires_layout` parameter. If `requires_layout` is True, then the `Register` must have a layout associated to it. We invite you to check the layout section in the advanced features to see how to attach a layout to a register in detail. Generating a layout spatially is a complex operation that needs some calibrations. Some devices provide a bank of pre-calibrated layouts in the `pre_calibrated_layouts` attribute, for which the calibration has already been performed (meaning, the computations will be faster than for a non-calibrated layout). If the device does not accept new layouts (`accepts_new_layouts` is False), then the register must be a subset of one of the pre-calibrated layouts. + +Now that we have seen all the constraints regarding the definition of the register of atoms, the next step of a quantum computation is to apply a sequence of pulses targeting a specific transition using `Channels`. The list of channels available in the device are accessible via the `channels` property. Some specific `Channels` are the `DetuningMapModulator` channels, that are listed in the `dmm_channels` property. These specific channels are further detailed in [their section in the extended features](tutorials/dmm.nblink). They are associated with the concept of SLM mask that some device supports (the `supports_slm_mask` attribute, check [the section on SLM](tutorials/slm_mask.nblink) to learn more). + +The physical constraints applied by a `Channel` are described below. More globally than a channel, the duration of the sequence of pulses should not be longer than `max_sequence_duration`. When a pulse is applied on a `Channel`, the atoms can interact between each other depending on the transition targeted by the `Channel`. When the channel aims at exciting the atoms to the rydberg state, then the Rydberg coefficient is defined from a `rydberg_level` defined in the device (see the [conventions page](conventions.md)). When using the `Microwave` channel, the `C_3` coefficient is defined by the `interaction_coeff_xy`. + +The device can also define some parameters used at execution on the backend. A backend can be a QPU (it should then have an associated device) or an emulator. In either case, the maximum number of runs, that is, the maximum number of times the cycle register-pulser-measurement can be performed for a quantum program, can be defined in the device (`max_runs`). The device also contains all the information about the noise to model the device (like, the temperature of the atoms) in `default_noise_model`. You can read more about the backends and the noise model in the [backend section](./tutorials/backends.nblink). + +### Channels + +Each pulse modifying the state of the atoms is applied via a laser channel. A channel targets a specific transition between two states, named the eigenstates. These two eigenstates form a basis. You can check the basis currently implemented in Pulser and their associated eigenstates in the [conventions page](./conventions.md). A laser channel can address the atoms globally (all the atoms are addressed at the same time) or locally (atoms are targeted separately). This is described by the `addressing` attribute of the `Channel` object. + +The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst##pulse)). The laser channels constrain these parameters: +- the duration must to be longer than `min_duration` but shorter than `max_duration`. It also has to be a multiple of `clock_duration`. +- the amplitude must be between 0 and `max_amp`. If the amplitude of a pulse is not constant equal to zero, its average must be higher than `min_avg_amp`. +- the detuning must be between -`max_abs_detuning` and `max_abs_detuning`. + +When using channels having a local `addressing`, other constraints emerge. For instance, there is a maximum number of atoms that can be targeted by each pulse (`max_targets`). Changing the atoms targeted by the channel takes also some time. This time must be greater than `min_retarget_interval` and is sometimes forced to be `fixed_retarget_t`. However, these channels are hard to implement in hardware and a prefered way to program local channels must be the `DMM` channels, `DMM` meaning Detuning-Map Modulator, which is explained in [another section](./tutorials/dmm.nblink). + +All the channels have a modulation bandwidth (`mod_bandwidth`), which impacts the shape of the pulses programmed by the users. This arises from the optical elements we use to control the amplitude, detuning, phase of the pulses. We detail the influence of this modulation bandwidth in the [extended features](./tutorials/output_mod_eom.nblink), but it means that the effective duration of the pulses seen by the atoms is longer than what was programmed. A remedy to this can be to use other optical elements, that have a longer modulation bandwidth (i.e. better response time) but can only take constant pulses. These optical elements are named the `EOM`, and one can activate an "EOM mode" on a channel that has an `eom_config`. To check whether or not a channel supports this operation, one can call the `supports_eom()` method of the `Channel`. To read more about EOM and its configuration in a `Channel`, please refer to the [EOM section](./tutorials/output_mod_eom.nblink). + +Finally, the laser channel applied on the atoms has a propagation direction (`propagation_dir`). This information is only relevant for emulation purposes. + +### Conclusion and extension + +The `Device` object stores all the physical information to take into account when making a quantum computation using a neutral-atom Quantum Processing Unit. An example of such a `Device` is detailed below with the `AnalogDevice`. As we have seen above, there are lots of physical constraints that are taken into account when you add an operation to your `Sequence`. However, for development perspectives, you could want to relax some conditions: what if there was no condition on the duration of the sequence ? or on the amplitude of the pulses applied to a specific channel ? You can work with a `VirtualDevice`, a kind of device that allows some of the physical constraints to not be defined. Check the [section on `VirtualDevice`](./tutorials/virtual_devices.nblink) to learn more. + + + + + + + + + + diff --git a/docs/source/index.rst b/docs/source/index.rst index bdccc5b32..8301ca9d2 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -61,6 +61,7 @@ computers and simulators, check the pages in :doc:`review`. review conventions + hardware .. toctree:: :maxdepth: 2 From 17b333b629640acd22ef22a4cce75daf9328e6dd Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 12 Dec 2024 11:32:55 +0100 Subject: [PATCH 05/44] Redirect api core --- docs/source/hardware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.md b/docs/source/hardware.md index 919d4e791..6bab1834a 100644 --- a/docs/source/hardware.md +++ b/docs/source/hardware.md @@ -36,7 +36,7 @@ The device can also define some parameters used at execution on the backend. A b Each pulse modifying the state of the atoms is applied via a laser channel. A channel targets a specific transition between two states, named the eigenstates. These two eigenstates form a basis. You can check the basis currently implemented in Pulser and their associated eigenstates in the [conventions page](./conventions.md). A laser channel can address the atoms globally (all the atoms are addressed at the same time) or locally (atoms are targeted separately). This is described by the `addressing` attribute of the `Channel` object. -The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst##pulse)). The laser channels constrain these parameters: +The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst)). The laser channels constrain these parameters: - the duration must to be longer than `min_duration` but shorter than `max_duration`. It also has to be a multiple of `clock_duration`. - the amplitude must be between 0 and `max_amp`. If the amplitude of a pulse is not constant equal to zero, its average must be higher than `min_avg_amp`. - the detuning must be between -`max_abs_detuning` and `max_abs_detuning`. From b3ca064c9036d63d688e3679af42c74439eff33a Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 12 Dec 2024 11:36:44 +0100 Subject: [PATCH 06/44] Add pulse section --- docs/source/hardware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.md b/docs/source/hardware.md index 6bab1834a..db9841566 100644 --- a/docs/source/hardware.md +++ b/docs/source/hardware.md @@ -36,7 +36,7 @@ The device can also define some parameters used at execution on the backend. A b Each pulse modifying the state of the atoms is applied via a laser channel. A channel targets a specific transition between two states, named the eigenstates. These two eigenstates form a basis. You can check the basis currently implemented in Pulser and their associated eigenstates in the [conventions page](./conventions.md). A laser channel can address the atoms globally (all the atoms are addressed at the same time) or locally (atoms are targeted separately). This is described by the `addressing` attribute of the `Channel` object. -The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst)). The laser channels constrain these parameters: +The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst#pulse)). The laser channels constrain these parameters: - the duration must to be longer than `min_duration` but shorter than `max_duration`. It also has to be a multiple of `clock_duration`. - the amplitude must be between 0 and `max_amp`. If the amplitude of a pulse is not constant equal to zero, its average must be higher than `min_avg_amp`. - the detuning must be between -`max_abs_detuning` and `max_abs_detuning`. From aec311f276e3e2e780e43692d2eb8c261de7a9fc Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 12 Dec 2024 11:59:13 +0100 Subject: [PATCH 07/44] Direct to API core instead of pulse --- docs/source/hardware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.md b/docs/source/hardware.md index db9841566..6bab1834a 100644 --- a/docs/source/hardware.md +++ b/docs/source/hardware.md @@ -36,7 +36,7 @@ The device can also define some parameters used at execution on the backend. A b Each pulse modifying the state of the atoms is applied via a laser channel. A channel targets a specific transition between two states, named the eigenstates. These two eigenstates form a basis. You can check the basis currently implemented in Pulser and their associated eigenstates in the [conventions page](./conventions.md). A laser channel can address the atoms globally (all the atoms are addressed at the same time) or locally (atoms are targeted separately). This is described by the `addressing` attribute of the `Channel` object. -The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst#pulse)). The laser channels constrain these parameters: +The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst)). The laser channels constrain these parameters: - the duration must to be longer than `min_duration` but shorter than `max_duration`. It also has to be a multiple of `clock_duration`. - the amplitude must be between 0 and `max_amp`. If the amplitude of a pulse is not constant equal to zero, its average must be higher than `min_avg_amp`. - the detuning must be between -`max_abs_detuning` and `max_abs_detuning`. From 3cd70f04a97d65d8b0651e2c9d10f4da55af3bc0 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 12 Dec 2024 18:05:06 +0100 Subject: [PATCH 08/44] Add some elements about pulser.devices --- docs/source/hardware.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/hardware.md b/docs/source/hardware.md index 6bab1834a..8ba9b6293 100644 --- a/docs/source/hardware.md +++ b/docs/source/hardware.md @@ -51,8 +51,15 @@ Finally, the laser channel applied on the atoms has a propagation direction (`pr The `Device` object stores all the physical information to take into account when making a quantum computation using a neutral-atom Quantum Processing Unit. An example of such a `Device` is detailed below with the `AnalogDevice`. As we have seen above, there are lots of physical constraints that are taken into account when you add an operation to your `Sequence`. However, for development perspectives, you could want to relax some conditions: what if there was no condition on the duration of the sequence ? or on the amplitude of the pulses applied to a specific channel ? You can work with a `VirtualDevice`, a kind of device that allows some of the physical constraints to not be defined. Check the [section on `VirtualDevice`](./tutorials/virtual_devices.nblink) to learn more. +## Example of devices +### pulser.devices +Each QPU has a different `Device` associated to it. This `Device` is accessible via the `Backend` that represents that QPU. The `Device` object fetched from the QPU varies along time: sometimes, the performance of the QPU can be enhanced (more atoms can be available for instance), sometimes the performance can be a bit downgraded (the maximum amplitude a laser can be a bit below what is used to be for instance). + +However, pulser provides examples of devices that present relevant values for neutral-atom QPUs. Even though these values are relevant, they are set to be ideal values for the QPUs, meaning that we cannot garantee that a Sequence built with this examples of device can work on a QPU, but we can garantee that a device built with the constrains of a QPU is to valid under the constrains of these QPU examples. + +We provide three examples of Device. The `AnalogDevice`, that is detailed below, the `DigitalAnalogDevice` and the `MockDevice`. The `AnalogDevice` represents a device with the minimum elements to perform analog computations with the Rydberg interaction. The `DigitalAnalogDevice` represents a device to perform analog computations with either the Rydberg or the XY interaction. digital computations using From 4274836a460b25101417e15e0de8d193c9a47b85 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 16 Jan 2025 18:36:47 +0100 Subject: [PATCH 09/44] Creating notebook for hardware section, reorganising specs display in Device, adding the presence of EOM in Channel display --- docs/source/hardware.ipynb | 207 ++++++++++++++++++ docs/source/hardware.md | 69 ------ pulser-core/pulser/channels/base_channel.py | 1 + pulser-core/pulser/devices/_device_datacls.py | 22 +- 4 files changed, 219 insertions(+), 80 deletions(-) create mode 100644 docs/source/hardware.ipynb delete mode 100644 docs/source/hardware.md diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb new file mode 100644 index 000000000..f6d7e3d3f --- /dev/null +++ b/docs/source/hardware.ipynb @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Neutral-atom Hardware" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What you will learn in this section:\n", + "- What are the constraints introduced by a `Device` ? by a `Channel` ?\n", + "- What are the examples of `Device` in Pulser ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The `Device`: An object to store all the hardware constraints" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As presented in the [introduction to programming a neutral-atom QPU](programming.md#programming-a-neutral-atom-qpu), the first step to [writing a Pulser program](programming.md#writing-a-pulser-program) is the selection of a `Device`. The `Device` object \n", + "stores all the physical constraints a quantum program written with `Pulser` should verify, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Where to find the `Devices` that can be used for your quantum program" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{important}\n", + "The `Device` represents the physics of a neutral-atom QPU but is not the QPU itself. A QPU must be accessed via a `Backend`, which is presented [in this notebook](./apidoc/backend.rst).\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want to run a quantum program on a QPU, start by selecting the `Backend` associated with this QPU. From this `Backend` the `Device` associated with the QPU can be accessed via the `get_available_devices` method.\n", + "\n", + "If you don't have access to a QPU or don't have particular QPU in mind, `Pulser` provides examples of typical physical devices in `pulser.devices`. Notably, `pulser.AnalogDevice` is an example of a QPU implementing an [Ising Hamiltonian](./programming.md#ising-hamiltonian). \n", + "\n", + "If you want don't want to be bothered by any or part of the physical constraints during the writing of your quantum program, you can use a `VirtualDevice`. An example of such a `VirtualDevice` is the `MockDevice` provided in the `pulser.devices`, which gives full liberty to write a quantum program. `VirtualDevice` is detailed in [an advanced tutorial](./tutorials/virtual_devices.nblink)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{note}\n", + "It is possible to change the set of constraints with which a `Sequence` was built, by using `Sequence.switch_device`. This is especially useful if you built your `Sequence` with an example of a `Device` like `AnalogDevice`, and now want to run it on a QPU, or if you want to run it on a different QPU than initially planned.\n", + "::: " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{figure} files/decision_diagram_device.png\n", + ":align: center\n", + ":alt: Decision Diagram to select a Device for the computation\n", + ":width: 600\n", + ":::\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### How to select your `Device`: Specifications of a `Device`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that you know where to look for `Devices`, you might want know how to choose the one matching your usecase. The device specifications are here to guide your choice:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pulser\n", + "\n", + "print(pulser.AnalogDevice.specs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", + "\n", + "- \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented [here](./register.md). If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", + "\n", + "- Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", + "\n", + "- The \"Channels\" are going to determine what [`Channels` are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", + "\n", + "- The \"Maximum sequence duration\" constrains the duration of the [`Pulses` you can add](programming.md#4-add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", + "\n", + "- The \"Maximum number of runs\" limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\". It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian), that can be defined between 0 and 4000ns max. The `Channel` can be declared using its name \"rydberg_global\", but this object contains a lot more constraints. Let's dive into them. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{note}\n", + "Other parameters are being defined in the `Device`. You can see the effect of each them in the [API documentation](./apidoc/core.rst#Devices).\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Channels" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The channels available for selection are stored in the `channels` property of the `Device`. Let's have a look at the only channel available in `AnalogDevice`, the \"rydberg_global\" channel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(pulser.AnalogDevice.channels[\"rydberg_global\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The channel is characterized by:\n", + "\n", + "- Its type, `Rydberg`, that defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#21-driving-hamiltonian) if this channel is picked. The `Rydberg` channel defines $\\left|b\\right>=\\left|r\\right>$ and $\\left|a\\right>=\\left|g\\right>$. All the type of channels can be found [here](conventions.md#bases).\n", + "- Its addressing, `Global`, which means that any Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", + "- Other parameters, that are going to set constraints on the quantities of the `Pulses` that can be added to the channel:\n", + " - the **duration** of the pulse is constrained by the minimum and maximum pulse duration, as well as the clock period (it has to be a multiple of the clock period).\n", + " - the **amplitude** is limited by the maximum amplitude.\n", + " - the **detuning** is limited by the maximum absolute detuning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{note}\n", + "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.rst#base-channels).\n", + ":::" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pulserenv", + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/source/hardware.md b/docs/source/hardware.md deleted file mode 100644 index 8ba9b6293..000000000 --- a/docs/source/hardware.md +++ /dev/null @@ -1,69 +0,0 @@ -# Neutral-atom Hardware - -## How does a neutral-atom Quantum Computer work ? - -A neutral-atom Quantum Computer is composed of neutral-atoms (typically, atoms of Rubidium or Cesium that belong to the first column of the Mendeleiev table, but quantum computing platforms have also been built using atoms of Ytterbium and Dysprosium that belong to the second column of the Mendeleiev table). To perform quantum computations with these atoms, we "cool" them down to very small temperatures (typically, $`10\mu`K) using lasers. Note: The neutral-atoms are in fact slowed down, and the temperature here is associated to their speed. Neutral-atom Quantum Computers are sometimes named cold-atom Quantum Computers because the atoms are "cold", ie there associated temperature is small. - -Since these atoms are cold, they can be trapped in space using another kind of lasers (see the `RegisterLayout` object in the extended section). They can then be rearranged and re-trapped in a specific pattern, that we name the register (see the `Register` section of the fundamentals). The atoms spend enough time trapped such that we are sure they are all in the ground state (the initial state for the computations, see the [conventions page](conventions.md)). - -The computation in itself can then happen: a serie of laser pulses are applied on the atoms to modify their state. The laser pulses can target different transition, each transition being associated to a different laser channel (see below). - -Once the computation is over, the state of the atoms is measured. Here as well, this is done using lasers: some light is shine on the atoms, the atoms that re-emit this light are measured in the ground-state and are labelled `0`, the others are described as being in an excited state and are labelled `1` (see the [convention page](conventions.md) for more). - -## Physical parameters to take into account in quantum computations - -As sketched in the above section, making a quantum computation with a neutral-atom device involves multiple steps and the use of multiple lasers. At each step and laser used, the physics of the device constrains the displacement of the atoms. In `Pulser`, all the physical constrains are stored in the `Device` object. - -### Device - -The `Device` class stores all the physical constrains the quantum computations should match. To perform any computation using Pulser, it is necessary to provide a device. For convenience, some examples of typical physical devices are included and can be accessed via `pulser.devices`. These devices are instances of the `Device` class. They are constrained by physical considerations and all their parameters are defined. An example of such a `Device`, the `pulser.AnalogDevice`, is provided below. - -If we go back to the timeline of a quantum computation using a neutral-atom device, the first step is the trapping of atoms in space and their rearrangement into a defined register. The first constraints concern the definition of the layout of traps and the register. They can be defined in 2D or 3D (check the `dimensions` attribute) but the register of atoms must be a subset of the layout of traps. Therefore, some constrains apply to both: the distance between each traps/atoms must be greater than the distance `min_atom_distance`, the traps/atoms should not be defined at a distance greater than `max_radial_distance` from the center. - -The register is a subset of the number of traps because by default some stochastical effects are at play, such that in theory a trap has a probability 1/2 to be filled by an atom. That way, there is a maximum number of traps of the layout that can be filled by an atom from the register (given by `max_layout_filling`), and there is also an optimal for this filling, (given by `optimal_layout_filling`). - -In terms of performance, there is a maximum number of atoms that can be trapped and rearranged in the register (`max_atom_num`) and a maximum number of traps that can be defined in the layout (`max_layout_traps`). From the considerations above, these two numbers are different. There is also a minimum number of traps to have in the layout (`min_layout_traps`). - -The considerations about the layout are unnessary if the device does not require one to be associated with the `Register`, which is given by the `requires_layout` parameter. If `requires_layout` is True, then the `Register` must have a layout associated to it. We invite you to check the layout section in the advanced features to see how to attach a layout to a register in detail. Generating a layout spatially is a complex operation that needs some calibrations. Some devices provide a bank of pre-calibrated layouts in the `pre_calibrated_layouts` attribute, for which the calibration has already been performed (meaning, the computations will be faster than for a non-calibrated layout). If the device does not accept new layouts (`accepts_new_layouts` is False), then the register must be a subset of one of the pre-calibrated layouts. - -Now that we have seen all the constraints regarding the definition of the register of atoms, the next step of a quantum computation is to apply a sequence of pulses targeting a specific transition using `Channels`. The list of channels available in the device are accessible via the `channels` property. Some specific `Channels` are the `DetuningMapModulator` channels, that are listed in the `dmm_channels` property. These specific channels are further detailed in [their section in the extended features](tutorials/dmm.nblink). They are associated with the concept of SLM mask that some device supports (the `supports_slm_mask` attribute, check [the section on SLM](tutorials/slm_mask.nblink) to learn more). - -The physical constraints applied by a `Channel` are described below. More globally than a channel, the duration of the sequence of pulses should not be longer than `max_sequence_duration`. When a pulse is applied on a `Channel`, the atoms can interact between each other depending on the transition targeted by the `Channel`. When the channel aims at exciting the atoms to the rydberg state, then the Rydberg coefficient is defined from a `rydberg_level` defined in the device (see the [conventions page](conventions.md)). When using the `Microwave` channel, the `C_3` coefficient is defined by the `interaction_coeff_xy`. - -The device can also define some parameters used at execution on the backend. A backend can be a QPU (it should then have an associated device) or an emulator. In either case, the maximum number of runs, that is, the maximum number of times the cycle register-pulser-measurement can be performed for a quantum program, can be defined in the device (`max_runs`). The device also contains all the information about the noise to model the device (like, the temperature of the atoms) in `default_noise_model`. You can read more about the backends and the noise model in the [backend section](./tutorials/backends.nblink). - -### Channels - -Each pulse modifying the state of the atoms is applied via a laser channel. A channel targets a specific transition between two states, named the eigenstates. These two eigenstates form a basis. You can check the basis currently implemented in Pulser and their associated eigenstates in the [conventions page](./conventions.md). A laser channel can address the atoms globally (all the atoms are addressed at the same time) or locally (atoms are targeted separately). This is described by the `addressing` attribute of the `Channel` object. - -The pulses that are applied on these laser channels are defined by four parameters: their duration, amplitude, detuning and phase (learn more about pulses [here](./apidoc/core.rst)). The laser channels constrain these parameters: -- the duration must to be longer than `min_duration` but shorter than `max_duration`. It also has to be a multiple of `clock_duration`. -- the amplitude must be between 0 and `max_amp`. If the amplitude of a pulse is not constant equal to zero, its average must be higher than `min_avg_amp`. -- the detuning must be between -`max_abs_detuning` and `max_abs_detuning`. - -When using channels having a local `addressing`, other constraints emerge. For instance, there is a maximum number of atoms that can be targeted by each pulse (`max_targets`). Changing the atoms targeted by the channel takes also some time. This time must be greater than `min_retarget_interval` and is sometimes forced to be `fixed_retarget_t`. However, these channels are hard to implement in hardware and a prefered way to program local channels must be the `DMM` channels, `DMM` meaning Detuning-Map Modulator, which is explained in [another section](./tutorials/dmm.nblink). - -All the channels have a modulation bandwidth (`mod_bandwidth`), which impacts the shape of the pulses programmed by the users. This arises from the optical elements we use to control the amplitude, detuning, phase of the pulses. We detail the influence of this modulation bandwidth in the [extended features](./tutorials/output_mod_eom.nblink), but it means that the effective duration of the pulses seen by the atoms is longer than what was programmed. A remedy to this can be to use other optical elements, that have a longer modulation bandwidth (i.e. better response time) but can only take constant pulses. These optical elements are named the `EOM`, and one can activate an "EOM mode" on a channel that has an `eom_config`. To check whether or not a channel supports this operation, one can call the `supports_eom()` method of the `Channel`. To read more about EOM and its configuration in a `Channel`, please refer to the [EOM section](./tutorials/output_mod_eom.nblink). - -Finally, the laser channel applied on the atoms has a propagation direction (`propagation_dir`). This information is only relevant for emulation purposes. - -### Conclusion and extension - -The `Device` object stores all the physical information to take into account when making a quantum computation using a neutral-atom Quantum Processing Unit. An example of such a `Device` is detailed below with the `AnalogDevice`. As we have seen above, there are lots of physical constraints that are taken into account when you add an operation to your `Sequence`. However, for development perspectives, you could want to relax some conditions: what if there was no condition on the duration of the sequence ? or on the amplitude of the pulses applied to a specific channel ? You can work with a `VirtualDevice`, a kind of device that allows some of the physical constraints to not be defined. Check the [section on `VirtualDevice`](./tutorials/virtual_devices.nblink) to learn more. - -## Example of devices - -### pulser.devices - -Each QPU has a different `Device` associated to it. This `Device` is accessible via the `Backend` that represents that QPU. The `Device` object fetched from the QPU varies along time: sometimes, the performance of the QPU can be enhanced (more atoms can be available for instance), sometimes the performance can be a bit downgraded (the maximum amplitude a laser can be a bit below what is used to be for instance). - -However, pulser provides examples of devices that present relevant values for neutral-atom QPUs. Even though these values are relevant, they are set to be ideal values for the QPUs, meaning that we cannot garantee that a Sequence built with this examples of device can work on a QPU, but we can garantee that a device built with the constrains of a QPU is to valid under the constrains of these QPU examples. - -We provide three examples of Device. The `AnalogDevice`, that is detailed below, the `DigitalAnalogDevice` and the `MockDevice`. The `AnalogDevice` represents a device with the minimum elements to perform analog computations with the Rydberg interaction. The `DigitalAnalogDevice` represents a device to perform analog computations with either the Rydberg or the XY interaction. digital computations using - - - - - - - diff --git a/pulser-core/pulser/channels/base_channel.py b/pulser-core/pulser/channels/base_channel.py index f3fb11433..a90219d6e 100644 --- a/pulser-core/pulser/channels/base_channel.py +++ b/pulser-core/pulser/channels/base_channel.py @@ -663,6 +663,7 @@ def __str__(self) -> str: config += f", Maximum pulse duration: {self.max_duration} ns" if self.mod_bandwidth: config += f", Modulation Bandwidth: {self.mod_bandwidth} MHz" + config += f", Supports EOM: {self.supports_eom()}" config += f", Basis: '{self.basis}')" return self.name + config diff --git a/pulser-core/pulser/devices/_device_datacls.py b/pulser-core/pulser/devices/_device_datacls.py index 01b0181d0..82faf652f 100644 --- a/pulser-core/pulser/devices/_device_datacls.py +++ b/pulser-core/pulser/devices/_device_datacls.py @@ -615,7 +615,6 @@ def _register_lines(self) -> list[str]: register_lines = [ "\nRegister parameters:", f" - Dimensions: {self.dimensions}D", - f" - Rydberg level: {self.rydberg_level}", self._param_check_none(self.max_atom_num)( " - Maximum number of atoms: {}" ), @@ -624,7 +623,6 @@ def _register_lines(self) -> list[str]: ), " - Minimum distance between neighbouring atoms: " + f"{self.min_atom_distance} μm", - f" - SLM Mask: {self._param_yes_no(self.supports_slm_mask)}", ] return [line for line in register_lines if line != ""] @@ -647,22 +645,24 @@ def _device_lines(self) -> list[str]: device_lines = [ "\nDevice parameters:", - self._param_check_none(self.max_runs)( - " - Maximum number of runs: {}" + f" - Rydberg level: {self.rydberg_level}", + self._param_check_none(self.interaction_coeff)( + " - Ising interaction coefficient: {}", ), - self._param_check_none(self.max_sequence_duration)( - " - Maximum sequence duration: {} ns", + self._param_check_none(self.interaction_coeff_xy)( + " - XY interaction coefficient: {}", ), " - Channels can be reused: " + self._param_yes_no(self.reusable_channels), f" - Supported bases: {', '.join(self.supported_bases)}", f" - Supported states: {', '.join(self.supported_states)}", - self._param_check_none(self.interaction_coeff)( - " - Ising interaction coefficient: {}", - ), - self._param_check_none(self.interaction_coeff_xy)( - " - XY interaction coefficient: {}", + f" - SLM Mask: {self._param_yes_no(self.supports_slm_mask)}", + self._param_check_none(self.max_sequence_duration)( + " - Maximum sequence duration: {} ns", ), + self._param_check_none(self.max_runs)( + " - Maximum number of runs: {}" + ), self._param_check_none(self.default_noise_model)( " - Default noise model: {}", ), From 2027b6adfca5a1948f67b09ee78db83fdb82e172 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 16 Jan 2025 18:37:18 +0100 Subject: [PATCH 10/44] Fix typing --- pulser-core/pulser/devices/_device_datacls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pulser-core/pulser/devices/_device_datacls.py b/pulser-core/pulser/devices/_device_datacls.py index 82faf652f..26cc03098 100644 --- a/pulser-core/pulser/devices/_device_datacls.py +++ b/pulser-core/pulser/devices/_device_datacls.py @@ -662,7 +662,7 @@ def _device_lines(self) -> list[str]: ), self._param_check_none(self.max_runs)( " - Maximum number of runs: {}" - ), + ), self._param_check_none(self.default_noise_model)( " - Default noise model: {}", ), From 0605ad0739afe0d99c9a18a7bea65ad22668d9fb Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 16 Jan 2025 18:52:30 +0100 Subject: [PATCH 11/44] Fix build --- docs/source/hardware.ipynb | 2 +- tests/test_channels.py | 4 ++-- tests/test_devices.py | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index f6d7e3d3f..76d0c7a26 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -109,7 +109,7 @@ "source": [ "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", "\n", - "- \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented [here](./register.md). If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", + "- \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", "\n", "- Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", "\n", diff --git a/tests/test_channels.py b/tests/test_channels.py index 582deb23b..0f7477e1b 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -190,7 +190,7 @@ def test_repr(): "Raman.Local(Max Absolute Detuning: None, Max Amplitude: " "2 rad/µs, Minimum retarget time: 1000 ns, " "Fixed retarget time: 200 ns, Max targets: 4, Clock period: 4 ns, " - "Minimum pulse duration: 16 ns, Basis: 'digital')" + "Minimum pulse duration: 16 ns, Supports EOM: False, Basis: 'digital')" ) assert raman.__str__() == r1 @@ -200,7 +200,7 @@ def test_repr(): "Max Amplitude: None, Clock period: 1 ns, " "Minimum pulse duration: 1 ns, " "Maximum pulse duration: 100000000 ns, " - "Modulation Bandwidth: 4 MHz, Basis: 'ground-rydberg')" + "Modulation Bandwidth: 4 MHz, Supports EOM: False, Basis: 'ground-rydberg')" ) assert ryd.__str__() == r2 diff --git a/tests/test_devices.py b/tests/test_devices.py index df473a895..1fc750d5b 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -281,7 +281,6 @@ def specs(dev): register_str = ( "\nRegister parameters:\n" + f" - Dimensions: {dev.dimensions}D\n" - + f" - Rydberg level: {dev.rydberg_level}\n" + check_none_fn(dev, "max_atom_num", "Maximum number of atoms: {}") + check_none_fn( dev, @@ -290,7 +289,6 @@ def specs(dev): ) + " - Minimum distance between neighbouring atoms: " + f"{dev.min_atom_distance} μm\n" - + yes_no_fn(dev, "supports_slm_mask", "SLM Mask") ) layout_str = ( @@ -312,19 +310,21 @@ def specs(dev): device_str = ( "\nDevice parameters:\n" - + check_none_fn(dev, "max_runs", "Maximum number of runs: {}") + + f" - Rydberg level: {dev.rydberg_level}\n" + + f" - Ising interaction coefficient: {dev.interaction_coeff}\n" + check_none_fn( - dev, - "max_sequence_duration", - "Maximum sequence duration: {} ns", + dev, "interaction_coeff_xy", "XY interaction coefficient: {}" ) + yes_no_fn(dev, "reusable_channels", "Channels can be reused") + f" - Supported bases: {', '.join(dev.supported_bases)}\n" + f" - Supported states: {', '.join(dev.supported_states)}\n" - + f" - Ising interaction coefficient: {dev.interaction_coeff}\n" + + yes_no_fn(dev, "supports_slm_mask", "SLM Mask") + check_none_fn( - dev, "interaction_coeff_xy", "XY interaction coefficient: {}" - ) + dev, + "max_sequence_duration", + "Maximum sequence duration: {} ns", + ) + + check_none_fn(dev, "max_runs", "Maximum number of runs: {}") ) channel_str = "\nChannels:\n" + "\n".join( From 03015f53d0320a3c6d9eae606d7c9e14bb7e6b0e Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 16 Jan 2025 18:55:19 +0100 Subject: [PATCH 12/44] fix typing --- tests/test_devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_devices.py b/tests/test_devices.py index 1fc750d5b..388a397f6 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -323,7 +323,7 @@ def specs(dev): dev, "max_sequence_duration", "Maximum sequence duration: {} ns", - ) + ) + check_none_fn(dev, "max_runs", "Maximum number of runs: {}") ) From 72c51f0bf39ed3a8d70c9837e00f6d766e49feff Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 16 Jan 2025 18:56:19 +0100 Subject: [PATCH 13/44] Fix flake8 --- tests/test_channels.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_channels.py b/tests/test_channels.py index 0f7477e1b..21908a006 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -200,7 +200,8 @@ def test_repr(): "Max Amplitude: None, Clock period: 1 ns, " "Minimum pulse duration: 1 ns, " "Maximum pulse duration: 100000000 ns, " - "Modulation Bandwidth: 4 MHz, Supports EOM: False, Basis: 'ground-rydberg')" + "Modulation Bandwidth: 4 MHz, Supports EOM: False, " + "Basis: 'ground-rydberg')" ) assert ryd.__str__() == r2 From 40e68bd355a9d75482f0b71bd67af6eae01701ee Mon Sep 17 00:00:00 2001 From: a_corni Date: Fri, 17 Jan 2025 09:04:39 +0100 Subject: [PATCH 14/44] Fix reference --- docs/source/hardware.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 76d0c7a26..6e21845f2 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -156,6 +156,8 @@ "metadata": {}, "outputs": [], "source": [ + "import pulser\n", + "\n", "print(pulser.AnalogDevice.channels[\"rydberg_global\"])" ] }, @@ -165,7 +167,7 @@ "source": [ "The channel is characterized by:\n", "\n", - "- Its type, `Rydberg`, that defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#21-driving-hamiltonian) if this channel is picked. The `Rydberg` channel defines $\\left|b\\right>=\\left|r\\right>$ and $\\left|a\\right>=\\left|g\\right>$. All the type of channels can be found [here](conventions.md#bases).\n", + "- Its type, `Rydberg`, that defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. The `Rydberg` channel defines $\\left|b\\right>=\\left|r\\right>$ and $\\left|a\\right>=\\left|g\\right>$. All the type of channels can be found [here](conventions.md#bases).\n", "- Its addressing, `Global`, which means that any Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", "- Other parameters, that are going to set constraints on the quantities of the `Pulses` that can be added to the channel:\n", " - the **duration** of the pulse is constrained by the minimum and maximum pulse duration, as well as the clock period (it has to be a multiple of the clock period).\n", @@ -178,7 +180,7 @@ "metadata": {}, "source": [ ":::{note}\n", - "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.rst#base-channels).\n", + "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.html#base-channels).\n", ":::" ] } From 13897e6729c4952286c96ec29c8e29f45b1f89e1 Mon Sep 17 00:00:00 2001 From: a_corni Date: Fri, 17 Jan 2025 10:36:07 +0100 Subject: [PATCH 15/44] Fix ref --- docs/source/hardware.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 6e21845f2..25e0fabe0 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -180,7 +180,7 @@ "metadata": {}, "source": [ ":::{note}\n", - "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.html#base-channels).\n", + "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.rst#channels).\n", ":::" ] } From 05b25ad4244f8f0f3ef11f7134fe2c8b3e83f495 Mon Sep 17 00:00:00 2001 From: a_corni Date: Fri, 17 Jan 2025 10:45:50 +0100 Subject: [PATCH 16/44] Fix figure --- docs/source/hardware.ipynb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 25e0fabe0..e9338740e 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -71,11 +71,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - ":::{figure} files/decision_diagram_device.png\n", - ":align: center\n", - ":alt: Decision Diagram to select a Device for the computation\n", - ":width: 600\n", - ":::\n" + "
\n", + "\"Decision\n", + "
\n" ] }, { From 9e95e0cea57c85b9aea5dc0bd10c1a8f4261f563 Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 20 Jan 2025 10:13:47 +0100 Subject: [PATCH 17/44] Re-reading myself --- docs/source/hardware.ipynb | 82 ++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index e9338740e..cc93f97f0 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -4,47 +4,53 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Neutral-atom Hardware" + "# Hardware constraints in Pulser Sequence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "What you will learn in this section:\n", - "- What are the constraints introduced by a `Device` ? by a `Channel` ?\n", - "- What are the examples of `Device` in Pulser ?" + "*What you will learn:*\n", + "- what are the constraints introduced by a `Device` ? by a `Channel` ?\n", + "- how to pick the `Device` to program your pulser `Sequence` ? " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## The `Device`: An object to store all the hardware constraints" + "## The `Device`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "As presented in the [introduction to programming a neutral-atom QPU](programming.md#programming-a-neutral-atom-qpu), the first step to [writing a Pulser program](programming.md#writing-a-pulser-program) is the selection of a `Device`. The `Device` object \n", - "stores all the physical constraints a quantum program written with `Pulser` should verify, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " + "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a `Device`](programming.md#pick-a-device). \n", + "\n", + "The `Device` object stores **all the physical constraints a quantum program written with `Pulser` should verify**, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Where to find the `Devices` that can be used for your quantum program" + "### Where to look for a `Device`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - ":::{important}\n", + "
\n", + "\n", + "**Important notes**:\n", + "\n", + "\n", "The `Device` represents the physics of a neutral-atom QPU but is not the QPU itself. A QPU must be accessed via a `Backend`, which is presented [in this notebook](./apidoc/backend.rst).\n", - ":::" + "\n", + "
" ] }, { @@ -62,9 +68,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - ":::{note}\n", + "
\n", + "\n", + "**Note**:\n", + "\n", "It is possible to change the set of constraints with which a `Sequence` was built, by using `Sequence.switch_device`. This is especially useful if you built your `Sequence` with an example of a `Device` like `AnalogDevice`, and now want to run it on a QPU, or if you want to run it on a different QPU than initially planned.\n", - "::: " + "\n", + "
" ] }, { @@ -80,7 +90,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### How to select your `Device`: Specifications of a `Device`\n" + "### Selecting your `Device`" ] }, { @@ -109,7 +119,7 @@ "\n", "- \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", "\n", - "- Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", + "- Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", "\n", "- The \"Channels\" are going to determine what [`Channels` are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", @@ -122,30 +132,54 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Here, `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\". It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian), that can be defined between 0 and 4000ns max. The `Channel` can be declared using its name \"rydberg_global\", but this object contains a lot more constraints. Let's dive into them. " + "
\n", + "\n", + "**Note**:\n", + "\n", + "Other parameters are being defined in the `Device`. You can see the effect of each them in the [API documentation](./apidoc/core.rst#Devices).\n", + "\n", + "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - ":::{note}\n", - "Other parameters are being defined in the `Device`. You can see the effect of each them in the [API documentation](./apidoc/core.rst#Devices).\n", - ":::" + "### The `AnalogDevice`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Channels" + "The `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\". It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian), that can be defined between 0 and 4000ns max. \n", + "\n", + "$$\\frac{H}{\\hbar}(t) = \\sum_i \\left (\\frac{\\Omega(t)}{2} e^{-j\\phi} |g\\rangle\\langle r|_i + \\frac{\\Omega(t)}{2} e^{j\\phi} |r\\rangle\\langle g|_i - \\delta(t) |r\\rangle\\langle r|_i(t) + \\sum_{j\n", + "\n", + "**Note**:\n", + "\n", "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.rst#channels).\n", - ":::" + "\n", + "" ] } ], From 1deefd72be3436e3128efcdbeefff0e5671a3232 Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 20 Jan 2025 10:54:43 +0100 Subject: [PATCH 18/44] Fix rendering --- docs/source/hardware.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index cc93f97f0..53d5396a4 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -27,7 +27,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a `Device`](programming.md#pick-a-device). \n", + "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a Device](programming.md#pick-a-device). \n", "\n", "The `Device` object stores **all the physical constraints a quantum program written with `Pulser` should verify**, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " ] @@ -43,7 +43,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", + "
\n", "\n", "**Important notes**:\n", "\n", @@ -68,7 +68,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", + "
\n", "\n", "**Note**:\n", "\n", @@ -132,7 +132,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", + "
\n", "\n", "**Note**:\n", "\n", @@ -211,7 +211,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", + "
\n", "\n", "**Note**:\n", "\n", From 6909b60d6058589b39943ceb9dab80eb17d78994 Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 20 Jan 2025 11:09:57 +0100 Subject: [PATCH 19/44] Fix rendering --- docs/source/hardware.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 53d5396a4..51ae436fc 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -29,7 +29,7 @@ "source": [ "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a Device](programming.md#pick-a-device). \n", "\n", - "The `Device` object stores **all the physical constraints a quantum program written with `Pulser` should verify**, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " + "The `Device` object stores **all the physical constraints a quantum program written with Pulser should verify**, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " ] }, { @@ -45,7 +45,7 @@ "source": [ "
\n", "\n", - "**Important notes**:\n", + "**Important note**:\n", "\n", "\n", "The `Device` represents the physics of a neutral-atom QPU but is not the QPU itself. A QPU must be accessed via a `Backend`, which is presented [in this notebook](./apidoc/backend.rst).\n", @@ -121,9 +121,9 @@ "\n", "- Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", "\n", - "- The \"Channels\" are going to determine what [`Channels` are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", + "- The \"Channels\" are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", - "- The \"Maximum sequence duration\" constrains the duration of the [`Pulses` you can add](programming.md#4-add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", + "- The \"Maximum sequence duration\" constrains the duration of the [Pulses you can add](programming.md#4-add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", "\n", "- The \"Maximum number of runs\" limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." ] @@ -171,7 +171,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The third step to writing a Pulser program is [the selection of `Channels` among the `Device`](programming.md#pick-a-device).\n", + "The third step to writing a Pulser program is [the selection of Channels among the Device](programming.md#pick-a-device).\n", "\n", "As a reminder, the selection of a `Channel` defines the [interaction Hamiltonian](programming.md#interaction-hamiltonian) and [the driving Hamiltonian](programming.md#driving-hamiltonian) $H_D$.\n", "\n", From 3933ba51f2dcde9c645e71db25f503549b625b14 Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 20 Jan 2025 11:16:19 +0100 Subject: [PATCH 20/44] Fix build --- docs/source/hardware.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 51ae436fc..00d849c7a 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -29,7 +29,7 @@ "source": [ "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a Device](programming.md#pick-a-device). \n", "\n", - "The `Device` object stores **all the physical constraints a quantum program written with Pulser should verify**, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " + "The `Device` object stores **all** the physical constraints a quantum program written with Pulser should verify, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " ] }, { @@ -123,7 +123,7 @@ "\n", "- The \"Channels\" are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", - "- The \"Maximum sequence duration\" constrains the duration of the [Pulses you can add](programming.md#4-add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", + "- The \"Maximum sequence duration\" constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", "\n", "- The \"Maximum number of runs\" limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." ] From 4d9c33dc5426f00f493d50170596fd36239874cd Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 21 Jan 2025 09:46:46 +0100 Subject: [PATCH 21/44] Available devices --- docs/source/hardware.ipynb | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 00d849c7a..74799b14a 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Hardware constraints in Pulser Sequence" + "# Hardware specifications" ] }, { @@ -12,8 +12,10 @@ "metadata": {}, "source": [ "*What you will learn:*\n", - "- what are the constraints introduced by a `Device` ? by a `Channel` ?\n", - "- how to pick the `Device` to program your pulser `Sequence` ? " + "- what is a Device and why is a Device needed;\n", + "- what are the available devices and where to find them;\n", + "- what do a Device and a Channel enforce; \n", + "- tips on how to pick a `Device`;" ] }, { @@ -29,14 +31,7 @@ "source": [ "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a Device](programming.md#pick-a-device). \n", "\n", - "The `Device` object stores **all** the physical constraints a quantum program written with Pulser should verify, for it to be run on a neutral-atom QPU. The quantum programs, the `pulser.Sequence`, verify that each operation added to them are valid with respect to the constraints of the `Device`. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Where to look for a `Device`" + "The `Device` is an object that stores **all** the physical constraints a quantum program written with Pulser should verify. The `Device` enforces that each operation added to the quantum program (i.e. the `pulser.Sequence`) respects its constraints. " ] }, { @@ -48,7 +43,7 @@ "**Important note**:\n", "\n", "\n", - "The `Device` represents the physics of a neutral-atom QPU but is not the QPU itself. A QPU must be accessed via a `Backend`, which is presented [in this notebook](./apidoc/backend.rst).\n", + "The `Device` represents the physics of a neutral-atom QPU but is not the QPU itself. A QPU must be accessed via a `Backend`, which is presented [in this section](./tutorials/backends.nblink).\n", "\n", "
" ] @@ -57,11 +52,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "If you want to run a quantum program on a QPU, start by selecting the `Backend` associated with this QPU. From this `Backend` the `Device` associated with the QPU can be accessed via the `get_available_devices` method.\n", + "### Available `Devices` and where to find them" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **When it comes to running a program on a QPU**: Each QPU has an associated `Device`, which you can [get from the cloud provider you use to access this QPU](tutorials/backends.nblink#1.2.-Preparation-for-execution-on-QPUBackend).\n", "\n", - "If you don't have access to a QPU or don't have particular QPU in mind, `Pulser` provides examples of typical physical devices in `pulser.devices`. Notably, `pulser.AnalogDevice` is an example of a QPU implementing an [Ising Hamiltonian](./programming.md#ising-hamiltonian). \n", + "- **For sole designing purposes**: `Pulser` provides examples of typical physical devices in `pulser.devices`. Notably, `pulser.AnalogDevice` is an example of a QPU implementing an [Ising Hamiltonian](./programming.md#ising-hamiltonian). \n", "\n", - "If you want don't want to be bothered by any or part of the physical constraints during the writing of your quantum program, you can use a `VirtualDevice`. An example of such a `VirtualDevice` is the `MockDevice` provided in the `pulser.devices`, which gives full liberty to write a quantum program. `VirtualDevice` is detailed in [an advanced tutorial](./tutorials/virtual_devices.nblink)." + "- **For designing without physical constraints** during the writing of your quantum program, you can use a `VirtualDevice`. An example of such a `VirtualDevice` is the `MockDevice` provided in the `pulser.devices`, which gives full liberty to write a quantum program. `VirtualDevice` is detailed in [an advanced tutorial](./tutorials/virtual_devices.nblink)." ] }, { From 727b10f9bf14e4f565aa636fb5b91da935ed5b83 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 23 Jan 2025 18:18:04 +0100 Subject: [PATCH 22/44] Address review comments --- docs/source/hardware.ipynb | 113 ++++++++++++++++++++++++------------- docs/source/programming.md | 2 +- 2 files changed, 75 insertions(+), 40 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 74799b14a..dc96b915a 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -52,54 +52,64 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Available `Devices` and where to find them" + "### Choosing a `Device`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "- **When it comes to running a program on a QPU**: Each QPU has an associated `Device`, which you can [get from the cloud provider you use to access this QPU](tutorials/backends.nblink#1.2.-Preparation-for-execution-on-QPUBackend).\n", - "\n", - "- **For sole designing purposes**: `Pulser` provides examples of typical physical devices in `pulser.devices`. Notably, `pulser.AnalogDevice` is an example of a QPU implementing an [Ising Hamiltonian](./programming.md#ising-hamiltonian). \n", - "\n", - "- **For designing without physical constraints** during the writing of your quantum program, you can use a `VirtualDevice`. An example of such a `VirtualDevice` is the `MockDevice` provided in the `pulser.devices`, which gives full liberty to write a quantum program. `VirtualDevice` is detailed in [an advanced tutorial](./tutorials/virtual_devices.nblink)." + "
\n", + "\"Decision\n", + "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", + "To choose a `Device` for your `Sequence`, the first question you should ask yourself is \"How close do I want the physical constraints I program with to be to the one of a QPU ?\" ?\n", "\n", - "**Note**:\n", + "**If you want to program with the physical constraints of a QPU**: Each QPU has an associated `Device`, which you can [get from the cloud provider you use to access this QPU](tutorials/backends.nblink#1.2.-Preparation-for-execution-on-QPUBackend).\n", "\n", - "It is possible to change the set of constraints with which a `Sequence` was built, by using `Sequence.switch_device`. This is especially useful if you built your `Sequence` with an example of a `Device` like `AnalogDevice`, and now want to run it on a QPU, or if you want to run it on a different QPU than initially planned.\n", + "There are several reasons for which you might want to feel less constrained by the features currently supported by real QPUs. For instance, you might want to design an algorithm for a QPU having better performances (supporting more qubits, longer sequences, ...) or hardware components that have not been installed.\n", "\n", - "
" + "Pulser enables you to define your own devices, but a `Device` object takes as input lots of parameters that have all to be defined. Therefore, for user convenience, `Pulser` provides:\n", + "\n", + "- **Examples of typical physical devices** in `pulser.devices`. Notably, `pulser.AnalogDevice` is an example of a QPU implementing an [Ising Hamiltonian](./programming.md#ising-hamiltonian).\n", + "\n", + "- **The possibility to define a device without some physical constraints** using the `VirtualDevice` class. An example of such a virtual device is the `MockDevice` provided in the `pulser.devices`, which gives full liberty to write a quantum program. `VirtualDevice` is detailed in [an advanced tutorial](./tutorials/virtual_devices.nblink)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", - "\"Decision\n", - "
\n" + "
\n", + "\n", + "**Note**:\n", + "\n", + "The selection of a device in a Pulser program does not enforce any choice on the [backend](tutorials/backends.nblink). No matter the device you used to program your `Sequence`, you can always submit it to any QPU: if the values of the `Sequence` match the constraints of the `QPU`, it will be executed. \n", + "\n", + "**Tip**:\n", + "\n", + "It is possible to change the device with which a `Sequence` was built, by using `Sequence.switch_device`. This is especially useful to check if the values of the `Sequence` match the constraints of the `QPU` prior to submitting to the `QPU` (for instance, you could have built your `Sequence` with an example of a `Device` like `AnalogDevice`, and now want to run it on a QPU, or the specifications of your QPU might have changed between your design and submission).\n", + "\n", + "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Selecting your `Device`" + "### Reading through the `Device`'s specifications" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Now that you know where to look for `Devices`, you might want know how to choose the one matching your usecase. The device specifications are here to guide your choice:" + "The second question you should ask yourself to choose your `Device` is \"Do its constraints allow me to program my `Sequence` ?\". The device specifications are here to guide your choice:" ] }, { @@ -119,15 +129,15 @@ "source": [ "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", "\n", - "- \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", + "1) \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", "\n", - "- Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", + "2) Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", "\n", - "- The \"Channels\" are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", + "3) The \"Channels\" are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", - "- The \"Maximum sequence duration\" constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", + "4) The \"Maximum sequence duration\" constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", "\n", - "- The \"Maximum number of runs\" limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." + "5) The \"Maximum number of runs\" limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." ] }, { @@ -143,25 +153,6 @@ "
" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### The `AnalogDevice`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\". It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian), that can be defined between 0 and 4000ns max. \n", - "\n", - "$$\\frac{H}{\\hbar}(t) = \\sum_i \\left (\\frac{\\Omega(t)}{2} e^{-j\\phi} |g\\rangle\\langle r|_i + \\frac{\\Omega(t)}{2} e^{j\\phi} |r\\rangle\\langle g|_i - \\delta(t) |r\\rangle\\langle r|_i(t) + \\sum_{j" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The `AnalogDevice`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pulser\n", + "\n", + "print(pulser.AnalogDevice.specs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\" (that can be declared using its name \"rydberg_global\"). It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian): \n", + "\n", + "$$\\frac{H}{\\hbar}(t) = \\sum_{i=1}^N \\left (\\frac{\\Omega(t)}{2} e^{-j\\phi(t)} |g\\rangle\\langle r|_i + \\frac{\\Omega(t)}{2} e^{j\\phi(t)} |r\\rangle\\langle g|_i - \\delta(t) |r\\rangle\\langle r|_i(t) + \\sum_{jInteraction strength and entangling operator -- The interaction strength is $\frac{C_6}{R_{ij}^6}$, with $C_6$ a coefficient that depends on the principal quantum number of the Rydberg state. +- 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$. From 728b954d6274d00689db2b734799550ed8d580ee Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 27 Jan 2025 14:42:38 +0100 Subject: [PATCH 23/44] Shuffle the description of the arguments --- docs/source/hardware.ipynb | 202 +++++++++++++++--- pulser-core/pulser/devices/_device_datacls.py | 130 +++++------ 2 files changed, 242 insertions(+), 90 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index dc96b915a..db8f847b8 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -68,7 +68,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To choose a `Device` for your `Sequence`, the first question you should ask yourself is \"How close do I want the physical constraints I program with to be to the one of a QPU ?\" ?\n", + "To choose a `Device` for your `Sequence`, the first question you should ask yourself is:\n", + "\n", + "
\"How close do I want the physical constraints I program with to be to the QPU's?\"
\n", "\n", "**If you want to program with the physical constraints of a QPU**: Each QPU has an associated `Device`, which you can [get from the cloud provider you use to access this QPU](tutorials/backends.nblink#1.2.-Preparation-for-execution-on-QPUBackend).\n", "\n", @@ -85,15 +87,25 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
\n", + "
\n", "\n", "**Note**:\n", "\n", "The selection of a device in a Pulser program does not enforce any choice on the [backend](tutorials/backends.nblink). No matter the device you used to program your `Sequence`, you can always submit it to any QPU: if the values of the `Sequence` match the constraints of the `QPU`, it will be executed. \n", "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "\n", "**Tip**:\n", "\n", - "It is possible to change the device with which a `Sequence` was built, by using `Sequence.switch_device`. This is especially useful to check if the values of the `Sequence` match the constraints of the `QPU` prior to submitting to the `QPU` (for instance, you could have built your `Sequence` with an example of a `Device` like `AnalogDevice`, and now want to run it on a QPU, or the specifications of your QPU might have changed between your design and submission).\n", + "It is possible to change the device with which a `Sequence` was built, by using `Sequence.switch_device`. This is especially useful to check if the values of the `Sequence` match the constraints of the `QPU` prior to submitting to the `QPU`. For instance, you could have built your `Sequence` with an example of a `Device` like `AnalogDevice`, and now want to run it on a QPU, or the specifications of your QPU might have changed between your design and submission.\n", "\n", "
" ] @@ -109,35 +121,95 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The second question you should ask yourself to choose your `Device` is \"Do its constraints allow me to program my `Sequence` ?\". The device specifications are here to guide your choice:" + "The second question you should ask yourself to choose your `Device` is: \n", + "\n", + "
\"Do its constraints allow me to program my `Sequence` ?\"
\n", + "\n", + "The device specifications are here to guide your choice. You can display them in the `specs` property of the device." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Register parameters:\n", + " - Dimensions: 2D\n", + " - Maximum number of atoms: 25\n", + " - Maximum distance from origin: 35 µm\n", + " - Minimum distance between neighbouring atoms: 5 μm\n", + "\n", + "Layout parameters:\n", + " - Requires layout: Yes\n", + " - Accepts new layout: No\n", + " - Minimal number of traps: 1\n", + " - Maximum layout filling fraction: 0.5\n", + "\n", + "Device parameters:\n", + " - Rydberg level: 60\n", + " - Ising interaction coefficient: 865723.02\n", + " - Channels can be reused: No\n", + " - Supported bases: ground-rydberg\n", + " - Supported states: r, g\n", + " - SLM Mask: No\n", + " - Maximum sequence duration: 4000 ns\n", + " - Maximum number of runs: 2000\n", + "\n", + "Channels:\n", + " - 'rydberg_global': Rydberg(addressing='Global', max_abs_detuning=125.66370614359172, max_amp=12.566370614359172, min_retarget_interval=None, fixed_retarget_t=None, max_targets=None, clock_period=4, min_duration=16, max_duration=100000000, min_avg_amp=0, mod_bandwidth=8, custom_phase_jump_time=None, eom_config=RydbergEOM(limiting_beam=, max_limiting_amp=188.49555921538757, intermediate_detuning=2827.4333882308138, controlled_beams=(,), mod_bandwidth=40, custom_buffer_time=240, multiple_beam_control=True, blue_shift_coeff=1.0, red_shift_coeff=1.0), propagation_dir=None)\n" + ] + } + ], "source": [ "import pulser\n", "\n", "print(pulser.AnalogDevice.specs)" ] }, + { + "cell_type": "raw", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "Here is what each parameter refer to:\n", + "\n", + ".. autoclass:: pulser.devices._device_datacls.Device\n", + " :no-members:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tips on `Device` selection" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", "\n", - "1) \"Register\" and \"Layout\" parameters are going to constrain the creation of your `Register`, that is, the number of atoms you can use and how you can place them in place. [As a reminder](programming.md#create-the-register), this impacts the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", + "1) _Register_ and _Layout parameters_ are going to constrain [the creation of your `Register`](programming.md/#create-the-register), and therefore, the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). These parameters will constrain:\n", + " - the number of atoms you can use.\n", + " - how you can position them in place.\n", + "The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", "\n", - "2) Among the \"Device\" parameters, the \"Rydberg level\" is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the \"Ising interaction coefficient\", which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via `pulser.AnalogDevice.interaction_coeff`.\n", + "2) Among the _Device parameters_, the _Rydberg level_ is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the _Ising interaction coefficient_, which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via the `interaction_coeff` attribute of the `Device`.\n", "\n", - "3) The \"Channels\" are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the \"supported bases\" and \"supported states\" among the Device parameters. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", + "3) The _Channels_ are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the _supported bases_ and _supported states_ among the _Device parameters_. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", - "4) The \"Maximum sequence duration\" constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", + "4) The _Maximum sequence duration_ constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", "\n", - "5) The \"Maximum number of runs\" limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." + "5) The _Maximum number of runs_ limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." ] }, { @@ -172,14 +244,22 @@ "H^D(t) / \\hbar = \\frac{\\Omega(t)}{2} e^{-j\\phi} |a\\rangle\\langle b| + \\frac{\\Omega(t)}{2} e^{j\\phi} |b\\rangle\\langle a| - \\delta(t) |b\\rangle\\langle b|\n", "$$\n", "\n", - "The `Channel`s available for selection are stored in the `channels` property of the `Device`, a dictionnary associating a name to a `Channel`. Let's have a look at the only channel available in `AnalogDevice`, the \"rydberg_global\" channel:" + "The `Channel`s available for selection are stored in the `channels` property of the `Device`, a dictionnary associating a name to a `Channel`. Let's have a look at the only channel available in `AnalogDevice`, the `\"rydberg_global\"` channel:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Rydberg.Global(Max Absolute Detuning: 125.66370614359172 rad/µs, Max Amplitude: 12.566370614359172 rad/µs, Clock period: 4 ns, Minimum pulse duration: 16 ns, Maximum pulse duration: 100000000 ns, Modulation Bandwidth: 8 MHz, Supports EOM: True, Basis: 'ground-rydberg')\n" + ] + } + ], "source": [ "import pulser\n", "\n", @@ -193,13 +273,27 @@ "### Reading through the `Channel`'s specifications" ] }, + { + "cell_type": "raw", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "The `Channel` is determined by:\n", + "\n", + ".. autoclass:: pulser.devices._device_datacls.Device\n", + " :no-members:" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "The channel is characterized by:\n", "\n", - "- Its type, `Rydberg`, that defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. The `Rydberg` channel defines $\\left|b\\right>=\\left|r\\right>$ and $\\left|a\\right>=\\left|g\\right>$. All the type of channels can be found [here](conventions.md#bases).\n", + "- Its type, `Rydberg`, that defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the type of channels can be found [here](conventions.md#bases).\n", "- Its addressing, `Global`, which means that any Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", "- Other parameters, that are going to set constraints on the quantities of the `Pulses` that can be added to the channel:\n", " - the **duration** of the pulse is constrained by the minimum and maximum pulse duration, as well as the clock period (it has to be a multiple of the clock period).\n", @@ -229,9 +323,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Register parameters:\n", + " - Dimensions: 2D\n", + " - Maximum number of atoms: 25\n", + " - Maximum distance from origin: 35 µm\n", + " - Minimum distance between neighbouring atoms: 5 μm\n", + "\n", + "Layout parameters:\n", + " - Requires layout: Yes\n", + " - Accepts new layout: No\n", + " - Minimal number of traps: 1\n", + " - Maximum layout filling fraction: 0.5\n", + "\n", + "Device parameters:\n", + " - Rydberg level: 60\n", + " - Ising interaction coefficient: 865723.02\n", + " - Channels can be reused: No\n", + " - Supported bases: ground-rydberg\n", + " - Supported states: r, g\n", + " - SLM Mask: No\n", + " - Maximum sequence duration: 4000 ns\n", + " - Maximum number of runs: 2000\n", + "\n", + "Channels:\n", + " - 'rydberg_global': Rydberg(addressing='Global', max_abs_detuning=125.66370614359172, max_amp=12.566370614359172, min_retarget_interval=None, fixed_retarget_t=None, max_targets=None, clock_period=4, min_duration=16, max_duration=100000000, min_avg_amp=0, mod_bandwidth=8, custom_phase_jump_time=None, eom_config=RydbergEOM(limiting_beam=, max_limiting_amp=188.49555921538757, intermediate_detuning=2827.4333882308138, controlled_beams=(,), mod_bandwidth=40, custom_buffer_time=240, multiple_beam_control=True, blue_shift_coeff=1.0, red_shift_coeff=1.0), propagation_dir=None)\n" + ] + } + ], "source": [ "import pulser\n", "\n", @@ -247,14 +373,40 @@ "$$\\frac{H}{\\hbar}(t) = \\sum_{i=1}^N \\left (\\frac{\\Omega(t)}{2} e^{-j\\phi(t)} |g\\rangle\\langle r|_i + \\frac{\\Omega(t)}{2} e^{j\\phi(t)} |r\\rangle\\langle g|_i - \\delta(t) |r\\rangle\\langle r|_i(t) + \\sum_{jjQuery(function() {if (jQuery(\"body.notebook_app\").length == 0) { jQuery(\".input_area\").toggle(); jQuery(\".prompt\").toggle();}});" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Markdown as md\n", + "import IPython.core.display as di # Example: di.display_html('

%s:

' % str, raw=True)\n", + "mylist = [\n", + " r\"- The maximum number of atoms $N$ is %i.\"%(pulser.AnalogDevice.max_atom_num),\n", + " r\"- The distance between the atoms $R_{ij}$ is at least %i µm and at most %i µm (twice the maximum distance). The distances are defined by placing the atoms in a 2D-plane, constrained by certain positions defined in a [layout](tutorials/reg_layouts.nblink).\"%(pulser.AnalogDevice.min_atom_distance, 2*pulser.AnalogDevice.max_radial_distance),\n", + " r\"- $C_6$ is the Ising interaction coefficient: %f.\"%(pulser.AnalogDevice.interaction_coeff),\n", + " r'- The `\"rydberg_global\"` being a `\"Global\"` channel, each pulse added to this channel is applied on all the atoms (the quantities $\\Omega$, $\\delta$, $\\phi$ are the same for each atom).',\n", + " r\"- The Hamiltonian (and the pulses with their time-dependent quantities $\\Omega$, $\\delta$, $\\phi$) can be defined between 0 and %i (the minimum of the maximum Sequence duration in the Device specifications and the `maximum_duration` of the channel).\"%(pulser.AnalogDevice.max_sequence_duration),\n", + " rf\"- The value of $\\Omega$ can go between 0 and {pulser.AnalogDevice.channels[\"rydberg_global\"].max_amp} and the value of $\\delta$ can go between -{pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning} and {pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning}.\"\n", + "\n", + "]\n", + "md(\"\\n\".join(mylist))\n", + "di.display_html(\n", + " '', raw=True\n", + ")\n" ] } ], diff --git a/pulser-core/pulser/devices/_device_datacls.py b/pulser-core/pulser/devices/_device_datacls.py index 26cc03098..514d66aeb 100644 --- a/pulser-core/pulser/devices/_device_datacls.py +++ b/pulser-core/pulser/devices/_device_datacls.py @@ -67,34 +67,36 @@ class BaseDevice(ABC): Attributes: name: The name of the device. dimensions: Whether it supports 2D or 3D arrays. - channel_objects: The Channel subclass instances specifying each - channel in the device. - channel_ids: Custom IDs for each channel object. When defined, - an ID must be given for each channel. If not defined, the IDs are - generated internally based on the channels' names and addressing. - dmm_objects: The DMM subclass instances specifying each channel in the - device. They are referenced by their order in the list, with the ID - "dmm_[index in dmm_objects]". - rydberg_level: The value of the principal quantum number :math:`n` - when the Rydberg level used is of the form - :math:`|nS_{1/2}, m_j = +1/2\rangle`. max_atom_num: Maximum number of atoms supported in an array. max_radial_distance: The furthest away an atom can be from the center of the array (in μm). min_atom_distance: The closest together two atoms can be (in μm). + requires_layout: Whether the register used in the sequence must be + created from a register layout. Only enforced in QPU execution. + min_layout_traps: The minimum number of traps a layout can have. + max_layout_traps: An optional value for the maximum number of traps a + layout can have. + max_layout_filling: The largest fraction of a layout that can be filled + with atoms. + optimal_layout_filling: An optional value for the fraction of a layout + that should be filled with atoms. + rydberg_level: The value of the principal quantum number :math:`n` + when the Rydberg level used is of the form + :math:`|nS_{1/2}, m_j = +1/2\rangle`. interaction_coeff_xy: :math:`C_3/\hbar` (in :math:`rad \cdot \mu s^{-1} \cdot \mu m^3`), which sets the van der Waals interaction strength between atoms in different Rydberg states. Needed only if there is a Microwave channel in the device. If unsure, 3700.0 is a good default value. + channel_objects: The Channel subclass instances specifying each + channel in the device. + channel_ids: Custom IDs for each channel object. When defined, + an ID must be given for each channel. If not defined, the IDs are + generated internally based on the channels' names and addressing. + dmm_objects: The DMM subclass instances specifying each channel in the + device. They are referenced by their order in the list, with the ID + "dmm_[index in dmm_objects]". supports_slm_mask: Whether the device supports the SLM mask feature. - max_layout_filling: The largest fraction of a layout that can be filled - with atoms. - optimal_layout_filling: An optional value for the fraction of a layout - that should be filled with atoms. - min_layout_traps: The minimum number of traps a layout can have. - max_layout_traps: An optional value for the maximum number of traps a - layout can have. max_sequence_duration: The maximum allowed duration for a sequence (in ns). max_runs: The maximum number of runs allowed on the device. Only used @@ -102,8 +104,6 @@ class BaseDevice(ABC): default_noise_model: An optional noise model characterizing the default noise of the device. Can be used by emulator backends that support noise. - requires_layout: Whether the register used in the sequence must be - created from a register layout. Only enforced in QPU execution. """ name: str @@ -746,27 +746,15 @@ class Device(BaseDevice): Attributes: name: The name of the device. dimensions: Whether it supports 2D or 3D arrays. - channel_objects: The Channel subclass instances specifying each - channel in the device. - channel_ids: Custom IDs for each channel object. When defined, - an ID must be given for each channel. If not defined, the IDs are - generated internally based on the channels' names and addressing. - dmm_objects: The DMM subclass instances specifying each channel in the - device. They are referenced by their order in the list, with the ID - "dmm_[index in dmm_objects]". - rydberg_level: The value of the principal quantum number :math:`n` - when the Rydberg level used is of the form - :math:`|nS_{1/2}, m_j = +1/2\rangle`. max_atom_num: Maximum number of atoms supported in an array. max_radial_distance: The furthest away an atom can be from the center of the array (in μm). min_atom_distance: The closest together two atoms can be (in μm). - interaction_coeff_xy: :math:`C_3/\hbar` - (in :math:`rad \cdot \mu s^{-1} \cdot \mu m^3`), - which sets the van der Waals interaction strength between atoms in - different Rydberg states. Needed only if there is a Microwave - channel in the device. If unsure, 3700.0 is a good default value. - supports_slm_mask: Whether the device supports the SLM mask feature. + requires_layout: Whether the register used in the sequence must be + created from a register layout. Only enforced in QPU execution. + accepts_new_layouts: Whether registers built from register layouts + that are not already calibrated are accepted. Only enforced in + QPU execution. max_layout_filling: The largest fraction of a layout that can be filled with atoms. optimal_layout_filling: An optional value for the fraction of a layout @@ -774,6 +762,25 @@ class Device(BaseDevice): min_layout_traps: The minimum number of traps a layout can have. max_layout_traps: An optional value for the maximum number of traps a layout can have. + pre_calibrated_layouts: RegisterLayout instances that are already + available on the Device. + rydberg_level: The value of the principal quantum number :math:`n` + when the Rydberg level used is of the form + :math:`|nS_{1/2}, m_j = +1/2\rangle`. + interaction_coeff_xy: :math:`C_3/\hbar` + (in :math:`rad \cdot \mu s^{-1} \cdot \mu m^3`), + which sets the van der Waals interaction strength between atoms in + different Rydberg states. Needed only if there is a Microwave + channel in the device. If unsure, 3700.0 is a good default value. + channel_objects: The Channel subclass instances specifying each + channel in the device. + channel_ids: Custom IDs for each channel object. When defined, + an ID must be given for each channel. If not defined, the IDs are + generated internally based on the channels' names and addressing. + dmm_objects: The DMM subclass instances specifying each channel in the + device. They are referenced by their order in the list, with the ID + "dmm_[index in dmm_objects]". + supports_slm_mask: Whether the device supports the SLM mask feature. max_sequence_duration: The maximum allowed duration for a sequence (in ns). max_runs: The maximum number of runs allowed on the device. Only used @@ -781,13 +788,6 @@ class Device(BaseDevice): default_noise_model: An optional noise model characterizing the default noise of the device. Can be used by emulator backends that support noise. - requires_layout: Whether the register used in the sequence must be - created from a register layout. Only enforced in QPU execution. - pre_calibrated_layouts: RegisterLayout instances that are already - available on the Device. - accepts_new_layouts: Whether registers built from register layouts - that are not already calibrated are accepted. Only enforced in - QPU execution. """ max_atom_num: int @@ -933,27 +933,12 @@ class VirtualDevice(BaseDevice): Attributes: name: The name of the device. dimensions: Whether it supports 2D or 3D arrays. - channel_objects: The Channel subclass instances specifying each - channel in the device. - channel_ids: Custom IDs for each channel object. When defined, - an ID must be given for each channel. If not defined, the IDs are - generated internally based on the channels' names and addressing. - dmm_objects: The DMM subclass instances specifying each channel in the - device. They are referenced by their order in the list, with the ID - "dmm_[index in dmm_objects]". - rydberg_level: The value of the principal quantum number :math:`n` - when the Rydberg level used is of the form - :math:`|nS_{1/2}, m_j = +1/2\rangle`. max_atom_num: Maximum number of atoms supported in an array. max_radial_distance: The furthest away an atom can be from the center of the array (in μm). min_atom_distance: The closest together two atoms can be (in μm). - interaction_coeff_xy: :math:`C_3/\hbar` - (in :math:`rad \cdot \mu s^{-1} \cdot \mu m^3`), - which sets the van der Waals interaction strength between atoms in - different Rydberg states. Needed only if there is a Microwave - channel in the device. If unsure, 3700.0 is a good default value. - supports_slm_mask: Whether the device supports the SLM mask feature. + requires_layout: Whether the register used in the sequence must be + created from a register layout. Only enforced in QPU execution. max_layout_filling: The largest fraction of a layout that can be filled with atoms. optimal_layout_filling: An optional value for the fraction of a layout @@ -961,6 +946,25 @@ class VirtualDevice(BaseDevice): min_layout_traps: The minimum number of traps a layout can have. max_layout_traps: An optional value for the maximum number of traps a layout can have. + rydberg_level: The value of the principal quantum number :math:`n` + when the Rydberg level used is of the form + :math:`|nS_{1/2}, m_j = +1/2\rangle`. + interaction_coeff_xy: :math:`C_3/\hbar` + (in :math:`rad \cdot \mu s^{-1} \cdot \mu m^3`), + which sets the van der Waals interaction strength between atoms in + different Rydberg states. Needed only if there is a Microwave + channel in the device. If unsure, 3700.0 is a good default value. + reusable_channels: Whether each channel can be declared multiple times + on the same pulse sequence. + channel_objects: The Channel subclass instances specifying each + channel in the device. + channel_ids: Custom IDs for each channel object. When defined, + an ID must be given for each channel. If not defined, the IDs are + generated internally based on the channels' names and addressing. + dmm_objects: The DMM subclass instances specifying each channel in the + device. They are referenced by their order in the list, with the ID + "dmm_[index in dmm_objects]". + supports_slm_mask: Whether the device supports the SLM mask feature. max_sequence_duration: The maximum allowed duration for a sequence (in ns). max_runs: The maximum number of runs allowed on the device. Only used @@ -968,10 +972,6 @@ class VirtualDevice(BaseDevice): default_noise_model: An optional noise model characterizing the default noise of the device. Can be used by emulator backends that support noise. - requires_layout: Whether the register used in the sequence must be - created from a register layout. Only enforced in QPU execution. - reusable_channels: Whether each channel can be declared multiple times - on the same pulse sequence. """ min_atom_distance: float = 0 From 1383445f9aedcb49db85016c5de6d0fda29925b8 Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 27 Jan 2025 15:42:51 +0100 Subject: [PATCH 24/44] Trying new raw cells --- docs/source/hardware.ipynb | 401 ++++++++++++++++++++++++------------- 1 file changed, 261 insertions(+), 140 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index db8f847b8..dc78ded87 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -2,14 +2,26 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "# Hardware specifications" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "*What you will learn:*\n", "- what is a Device and why is a Device needed;\n", @@ -20,14 +32,26 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "## The `Device`" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "As presented in the [introduction to programming a neutral-atom QPU](programming.md#writing-a-pulser-program), the first step to writing a Pulser program is [the selection of a Device](programming.md#pick-a-device). \n", "\n", @@ -36,7 +60,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "
\n", "\n", @@ -50,14 +80,26 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "### Choosing a `Device`" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "
\n", "\"Decision\n", @@ -66,7 +108,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "To choose a `Device` for your `Sequence`, the first question you should ask yourself is:\n", "\n", @@ -85,7 +133,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "
\n", "\n", @@ -98,7 +152,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "
\n", "\n", @@ -112,14 +172,26 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "### Reading through the `Device`'s specifications" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "The second question you should ask yourself to choose your `Device` is: \n", "\n", @@ -130,80 +202,82 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Register parameters:\n", - " - Dimensions: 2D\n", - " - Maximum number of atoms: 25\n", - " - Maximum distance from origin: 35 µm\n", - " - Minimum distance between neighbouring atoms: 5 μm\n", - "\n", - "Layout parameters:\n", - " - Requires layout: Yes\n", - " - Accepts new layout: No\n", - " - Minimal number of traps: 1\n", - " - Maximum layout filling fraction: 0.5\n", - "\n", - "Device parameters:\n", - " - Rydberg level: 60\n", - " - Ising interaction coefficient: 865723.02\n", - " - Channels can be reused: No\n", - " - Supported bases: ground-rydberg\n", - " - Supported states: r, g\n", - " - SLM Mask: No\n", - " - Maximum sequence duration: 4000 ns\n", - " - Maximum number of runs: 2000\n", - "\n", - "Channels:\n", - " - 'rydberg_global': Rydberg(addressing='Global', max_abs_detuning=125.66370614359172, max_amp=12.566370614359172, min_retarget_interval=None, fixed_retarget_t=None, max_targets=None, clock_period=4, min_duration=16, max_duration=100000000, min_avg_amp=0, mod_bandwidth=8, custom_phase_jump_time=None, eom_config=RydbergEOM(limiting_beam=, max_limiting_amp=188.49555921538757, intermediate_detuning=2827.4333882308138, controlled_beams=(,), mod_bandwidth=40, custom_buffer_time=240, multiple_beam_control=True, blue_shift_coeff=1.0, red_shift_coeff=1.0), propagation_dir=None)\n" - ] - } - ], + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], "source": [ "import pulser\n", "\n", "print(pulser.AnalogDevice.specs)" ] }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Here is what each parameter refer to:" + ] + }, { "cell_type": "raw", "metadata": { + "editable": true, + "raw_mimetype": "text/restructuredtext", + "slideshow": { + "slide_type": "" + }, + "tags": [], "vscode": { "languageId": "raw" } }, "source": [ - "Here is what each parameter refer to:\n", - "\n", ".. autoclass:: pulser.devices._device_datacls.Device\n", " :no-members:" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "### Tips on `Device` selection" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", "\n", "1) _Register_ and _Layout parameters_ are going to constrain [the creation of your `Register`](programming.md/#create-the-register), and therefore, the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). These parameters will constrain:\n", " - the number of atoms you can use.\n", - " - how you can position them in place.\n", - "The creation of a `Register` is presented here. If the `Device` requires a `Layout` (as in the example here), then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", + " - how you can position them in place. If the `Device` requires a `Layout`, then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", "\n", - "2) Among the _Device parameters_, the _Rydberg level_ is going to complete the determination of the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). This level determines the _Ising interaction coefficient_, which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via the `interaction_coeff` attribute of the `Device`.\n", + "2) Among the _Device parameters_, the _Rydberg level_ determines the _Ising interaction coefficient_, which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via the `interaction_coeff` attribute of the `Device`.\n", "\n", "3) The _Channels_ are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the _supported bases_ and _supported states_ among the _Device parameters_. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", @@ -214,7 +288,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "
\n", "\n", @@ -227,21 +307,33 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "## The `Channels`" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "The third step to writing a Pulser program is [the selection of Channels among the Device](programming.md#pick-a-device).\n", "\n", "As a reminder, the selection of a `Channel` defines the [interaction Hamiltonian](programming.md#interaction-hamiltonian) and [the driving Hamiltonian](programming.md#driving-hamiltonian) $H_D$.\n", "\n", "$$\n", - "H^D(t) / \\hbar = \\frac{\\Omega(t)}{2} e^{-j\\phi} |a\\rangle\\langle b| + \\frac{\\Omega(t)}{2} e^{j\\phi} |b\\rangle\\langle a| - \\delta(t) |b\\rangle\\langle b|\n", + "H^D(t) / \\hbar = \\frac{\\Omega(t)}{2} e^{-i\\phi} |a\\rangle\\langle b| + \\frac{\\Omega(t)}{2} e^{i\\phi} |b\\rangle\\langle a| - \\delta(t) |b\\rangle\\langle b|\n", "$$\n", "\n", "The `Channel`s available for selection are stored in the `channels` property of the `Device`, a dictionnary associating a name to a `Channel`. Let's have a look at the only channel available in `AnalogDevice`, the `\"rydberg_global\"` channel:" @@ -249,17 +341,15 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Rydberg.Global(Max Absolute Detuning: 125.66370614359172 rad/µs, Max Amplitude: 12.566370614359172 rad/µs, Clock period: 4 ns, Minimum pulse duration: 16 ns, Maximum pulse duration: 100000000 ns, Modulation Bandwidth: 8 MHz, Supports EOM: True, Basis: 'ground-rydberg')\n" - ] - } - ], + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], "source": [ "import pulser\n", "\n", @@ -268,42 +358,91 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "### Reading through the `Channel`'s specifications" ] }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "The `Channel` is determined by:" + ] + }, { "cell_type": "raw", "metadata": { + "editable": true, + "raw_mimetype": "text/restructuredtext", + "slideshow": { + "slide_type": "" + }, + "tags": [], "vscode": { "languageId": "raw" } }, "source": [ - "The `Channel` is determined by:\n", - "\n", - ".. autoclass:: pulser.devices._device_datacls.Device\n", + ".. autoclass:: pulser.channels.base_channel\n", " :no-members:" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ - "The channel is characterized by:\n", - "\n", - "- Its type, `Rydberg`, that defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the type of channels can be found [here](conventions.md#bases).\n", - "- Its addressing, `Global`, which means that any Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", - "- Other parameters, that are going to set constraints on the quantities of the `Pulses` that can be added to the channel:\n", - " - the **duration** of the pulse is constrained by the minimum and maximum pulse duration, as well as the clock period (it has to be a multiple of the clock period).\n", - " - the **amplitude** is limited by the maximum amplitude.\n", - " - the **detuning** is limited by the maximum absolute detuning." + "### Tips on `Channel` selection" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "The `Channel` is going to determine the computational basis used in the driving Hamiltonian, and what is the Hamiltonian each atom sees:\n", + "\n", + "- The type of the `Channel` defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the type of channels can be found [here](conventions.md#bases).\n", + "- The addressing of the `Channel` determines what atoms experience the driving Hamiltonian. In general, physical `Channels` have a `Global` addressability, which means that a Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", + "\n", + "The `Channel` also set constraints on the next stage of your quantum program, the addition of Pulses:\n", + "- the **duration** of the pulse is constrained by the minimum and maximum pulse duration, as well as the clock period (it has to be a multiple of the clock period).\n", + "- the **amplitude** is limited by the maximum amplitude.\n", + "- the **detuning** is limited by the maximum absolute detuning." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "
\n", "\n", @@ -316,48 +455,28 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "## The `AnalogDevice`" ] }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Register parameters:\n", - " - Dimensions: 2D\n", - " - Maximum number of atoms: 25\n", - " - Maximum distance from origin: 35 µm\n", - " - Minimum distance between neighbouring atoms: 5 μm\n", - "\n", - "Layout parameters:\n", - " - Requires layout: Yes\n", - " - Accepts new layout: No\n", - " - Minimal number of traps: 1\n", - " - Maximum layout filling fraction: 0.5\n", - "\n", - "Device parameters:\n", - " - Rydberg level: 60\n", - " - Ising interaction coefficient: 865723.02\n", - " - Channels can be reused: No\n", - " - Supported bases: ground-rydberg\n", - " - Supported states: r, g\n", - " - SLM Mask: No\n", - " - Maximum sequence duration: 4000 ns\n", - " - Maximum number of runs: 2000\n", - "\n", - "Channels:\n", - " - 'rydberg_global': Rydberg(addressing='Global', max_abs_detuning=125.66370614359172, max_amp=12.566370614359172, min_retarget_interval=None, fixed_retarget_t=None, max_targets=None, clock_period=4, min_duration=16, max_duration=100000000, min_avg_amp=0, mod_bandwidth=8, custom_phase_jump_time=None, eom_config=RydbergEOM(limiting_beam=, max_limiting_amp=188.49555921538757, intermediate_detuning=2827.4333882308138, controlled_beams=(,), mod_bandwidth=40, custom_buffer_time=240, multiple_beam_control=True, blue_shift_coeff=1.0, red_shift_coeff=1.0), propagation_dir=None)\n" - ] - } - ], + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], "source": [ "import pulser\n", "\n", @@ -366,11 +485,17 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "The `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\" (that can be declared using its name \"rydberg_global\"). It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian): \n", "\n", - "$$\\frac{H}{\\hbar}(t) = \\sum_{i=1}^N \\left (\\frac{\\Omega(t)}{2} e^{-j\\phi(t)} |g\\rangle\\langle r|_i + \\frac{\\Omega(t)}{2} e^{j\\phi(t)} |r\\rangle\\langle g|_i - \\delta(t) |r\\rangle\\langle r|_i(t) + \\sum_{jjQuery(function() {if (jQuery(\"body.notebook_app\").length == 0) { jQuery(\".input_area\").toggle(); jQuery(\".prompt\").toggle();}});" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], "source": [ "from IPython.display import Markdown as md\n", "import IPython.core.display as di # Example: di.display_html('

%s:

' % str, raw=True)\n", + "di.display_html(\n", + " '', raw=True\n", + ")\n", "mylist = [\n", " r\"- The maximum number of atoms $N$ is %i.\"%(pulser.AnalogDevice.max_atom_num),\n", " r\"- The distance between the atoms $R_{ij}$ is at least %i µm and at most %i µm (twice the maximum distance). The distances are defined by placing the atoms in a 2D-plane, constrained by certain positions defined in a [layout](tutorials/reg_layouts.nblink).\"%(pulser.AnalogDevice.min_atom_distance, 2*pulser.AnalogDevice.max_radial_distance),\n", @@ -403,16 +527,13 @@ " rf\"- The value of $\\Omega$ can go between 0 and {pulser.AnalogDevice.channels[\"rydberg_global\"].max_amp} and the value of $\\delta$ can go between -{pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning} and {pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning}.\"\n", "\n", "]\n", - "md(\"\\n\".join(mylist))\n", - "di.display_html(\n", - " '', raw=True\n", - ")\n" + "md(\"\\n\".join(mylist))\n" ] } ], "metadata": { "kernelspec": { - "display_name": "pulserenv", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -430,5 +551,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } From 1858a2fd78fc2851242509a14c91d3ddf8e6972e Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 28 Jan 2025 14:22:09 +0100 Subject: [PATCH 25/44] Add remove-input tag to last cell --- docs/source/hardware.ipynb | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index dc78ded87..f19a21c0e 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -509,23 +509,20 @@ "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [ + "remove-input" + ] }, "outputs": [], "source": [ "from IPython.display import Markdown as md\n", - "import IPython.core.display as di # Example: di.display_html('

%s:

' % str, raw=True)\n", - "di.display_html(\n", - " '', raw=True\n", - ")\n", "mylist = [\n", " r\"- The maximum number of atoms $N$ is %i.\"%(pulser.AnalogDevice.max_atom_num),\n", " r\"- The distance between the atoms $R_{ij}$ is at least %i µm and at most %i µm (twice the maximum distance). The distances are defined by placing the atoms in a 2D-plane, constrained by certain positions defined in a [layout](tutorials/reg_layouts.nblink).\"%(pulser.AnalogDevice.min_atom_distance, 2*pulser.AnalogDevice.max_radial_distance),\n", " r\"- $C_6$ is the Ising interaction coefficient: %f.\"%(pulser.AnalogDevice.interaction_coeff),\n", " r'- The `\"rydberg_global\"` being a `\"Global\"` channel, each pulse added to this channel is applied on all the atoms (the quantities $\\Omega$, $\\delta$, $\\phi$ are the same for each atom).',\n", " r\"- The Hamiltonian (and the pulses with their time-dependent quantities $\\Omega$, $\\delta$, $\\phi$) can be defined between 0 and %i (the minimum of the maximum Sequence duration in the Device specifications and the `maximum_duration` of the channel).\"%(pulser.AnalogDevice.max_sequence_duration),\n", - " rf\"- The value of $\\Omega$ can go between 0 and {pulser.AnalogDevice.channels[\"rydberg_global\"].max_amp} and the value of $\\delta$ can go between -{pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning} and {pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning}.\"\n", - "\n", + " r\"- The value of $\\Omega$ can go between 0 and %f and the value of $\\delta$ can go between -%f and %f.\"%(pulser.AnalogDevice.channels[\"rydberg_global\"].max_amp, pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning, pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning)\n", "]\n", "md(\"\\n\".join(mylist))\n" ] @@ -547,7 +544,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.10.14" } }, "nbformat": 4, From ef538c81db9484aedc01f334638726a0ff99be52 Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 28 Jan 2025 14:22:42 +0100 Subject: [PATCH 26/44] Fix typing --- docs/source/hardware.ipynb | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index f19a21c0e..df8f8a238 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -516,15 +516,28 @@ "outputs": [], "source": [ "from IPython.display import Markdown as md\n", + "\n", "mylist = [\n", - " r\"- The maximum number of atoms $N$ is %i.\"%(pulser.AnalogDevice.max_atom_num),\n", - " r\"- The distance between the atoms $R_{ij}$ is at least %i µm and at most %i µm (twice the maximum distance). The distances are defined by placing the atoms in a 2D-plane, constrained by certain positions defined in a [layout](tutorials/reg_layouts.nblink).\"%(pulser.AnalogDevice.min_atom_distance, 2*pulser.AnalogDevice.max_radial_distance),\n", - " r\"- $C_6$ is the Ising interaction coefficient: %f.\"%(pulser.AnalogDevice.interaction_coeff),\n", + " r\"- The maximum number of atoms $N$ is %i.\"\n", + " % (pulser.AnalogDevice.max_atom_num),\n", + " r\"- The distance between the atoms $R_{ij}$ is at least %i µm and at most %i µm (twice the maximum distance). The distances are defined by placing the atoms in a 2D-plane, constrained by certain positions defined in a [layout](tutorials/reg_layouts.nblink).\"\n", + " % (\n", + " pulser.AnalogDevice.min_atom_distance,\n", + " 2 * pulser.AnalogDevice.max_radial_distance,\n", + " ),\n", + " r\"- $C_6$ is the Ising interaction coefficient: %f.\"\n", + " % (pulser.AnalogDevice.interaction_coeff),\n", " r'- The `\"rydberg_global\"` being a `\"Global\"` channel, each pulse added to this channel is applied on all the atoms (the quantities $\\Omega$, $\\delta$, $\\phi$ are the same for each atom).',\n", - " r\"- The Hamiltonian (and the pulses with their time-dependent quantities $\\Omega$, $\\delta$, $\\phi$) can be defined between 0 and %i (the minimum of the maximum Sequence duration in the Device specifications and the `maximum_duration` of the channel).\"%(pulser.AnalogDevice.max_sequence_duration),\n", - " r\"- The value of $\\Omega$ can go between 0 and %f and the value of $\\delta$ can go between -%f and %f.\"%(pulser.AnalogDevice.channels[\"rydberg_global\"].max_amp, pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning, pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning)\n", + " r\"- The Hamiltonian (and the pulses with their time-dependent quantities $\\Omega$, $\\delta$, $\\phi$) can be defined between 0 and %i (the minimum of the maximum Sequence duration in the Device specifications and the `maximum_duration` of the channel).\"\n", + " % (pulser.AnalogDevice.max_sequence_duration),\n", + " r\"- The value of $\\Omega$ can go between 0 and %f and the value of $\\delta$ can go between -%f and %f.\"\n", + " % (\n", + " pulser.AnalogDevice.channels[\"rydberg_global\"].max_amp,\n", + " pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning,\n", + " pulser.AnalogDevice.channels[\"rydberg_global\"].max_abs_detuning,\n", + " ),\n", "]\n", - "md(\"\\n\".join(mylist))\n" + "md(\"\\n\".join(mylist))" ] } ], From bcd339f6723d1b16fbfc23a3dac443663815ddca Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 28 Jan 2025 14:56:06 +0100 Subject: [PATCH 27/44] Add no-index --- docs/source/hardware.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index df8f8a238..a5b3730b0 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -245,7 +245,8 @@ }, "source": [ ".. autoclass:: pulser.devices._device_datacls.Device\n", - " :no-members:" + " :no-index:\n", + " :no-members:\n" ] }, { From 587cc7bb47cebecd018748054d80695cea2a4944 Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 28 Jan 2025 15:55:52 +0100 Subject: [PATCH 28/44] Delete no-members --- docs/source/hardware.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index a5b3730b0..977981b33 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -245,8 +245,7 @@ }, "source": [ ".. autoclass:: pulser.devices._device_datacls.Device\n", - " :no-index:\n", - " :no-members:\n" + " :no-index:" ] }, { @@ -398,7 +397,7 @@ }, "source": [ ".. autoclass:: pulser.channels.base_channel\n", - " :no-members:" + " :no-index:" ] }, { From 63dd0af67f894134fa48705b26919eae20016b27 Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 28 Jan 2025 16:40:13 +0100 Subject: [PATCH 29/44] Dlete no-index --- docs/source/hardware.ipynb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 977981b33..5ac48396e 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -244,8 +244,7 @@ } }, "source": [ - ".. autoclass:: pulser.devices._device_datacls.Device\n", - " :no-index:" + ".. autoclass:: pulser.devices._device_datacls.Device\n" ] }, { @@ -396,8 +395,7 @@ } }, "source": [ - ".. autoclass:: pulser.channels.base_channel\n", - " :no-index:" + ".. autoclass:: pulser.channels.base_channel\n" ] }, { From a247584bc74cbbc7fbc83933fc33124c56ce5c37 Mon Sep 17 00:00:00 2001 From: a_corni Date: Wed, 29 Jan 2025 17:14:45 +0100 Subject: [PATCH 30/44] Reintroduce :noindex: --- docs/source/hardware.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 5ac48396e..8eb30ef89 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -244,7 +244,8 @@ } }, "source": [ - ".. autoclass:: pulser.devices._device_datacls.Device\n" + ".. autoclass:: pulser.devices._device_datacls.Device\n", + " :noindex:\n" ] }, { @@ -395,7 +396,8 @@ } }, "source": [ - ".. autoclass:: pulser.channels.base_channel\n" + ".. autoclass:: pulser.channels.base_channel\n", + " :noindex:" ] }, { From 38b965c19fd45e0dc2aa05e5d236221ca82e0aed Mon Sep 17 00:00:00 2001 From: a_corni Date: Wed, 29 Jan 2025 18:29:49 +0100 Subject: [PATCH 31/44] Improve description of device --- docs/source/hardware.ipynb | 77 ++++++++++++++------------------------ 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 8eb30ef89..d018bf696 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -197,37 +197,7 @@ "\n", "
\"Do its constraints allow me to program my `Sequence` ?\"
\n", "\n", - "The device specifications are here to guide your choice. You can display them in the `specs` property of the device." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "import pulser\n", - "\n", - "print(pulser.AnalogDevice.specs)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "source": [ - "Here is what each parameter refer to:" + "The device specifications are here to guide your choice. Here are all the parameters in a `Device`:" ] }, { @@ -245,7 +215,20 @@ }, "source": [ ".. autoclass:: pulser.devices._device_datacls.Device\n", - " :noindex:\n" + " :noindex:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "**Tip**:\n", + "\n", + "It is possible to display some of the specifications of the `Device` with `Device.specs`. See an example with `AnalogDevice.specs` [in the section below](#the-analogdevice).\n", + "\n", + "
" ] }, { @@ -273,34 +256,30 @@ "source": [ "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", "\n", - "1) _Register_ and _Layout parameters_ are going to constrain [the creation of your `Register`](programming.md/#create-the-register), and therefore, the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). These parameters will constrain:\n", - " - the number of atoms you can use.\n", - " - how you can position them in place. If the `Device` requires a `Layout`, then you have to associate a `RegisterLayout` to the `Register`, which adds more constraints. Check [this tutorial](./tutorials/reg_layouts.nblink) to see how to do it.\n", + "1) Some parameters are going to constrain [the creation of your Register](programming.md/#create-the-register), and therefore, the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). Some of these parameters are:\n", + " - `dimensions`\n", + " - `max_atom_num`\n", + " - `max_radial_distance`\n", + " - `min_atom_distance`\n", "\n", - "2) Among the _Device parameters_, the _Rydberg level_ determines the _Ising interaction coefficient_, which is the $C_6$ coefficient of the [Ising Hamiltonian](./programming.md#ising-hamiltonian). The quantity $\\frac{C_6}{\\hbar}$ is accessible via the `interaction_coeff` attribute of the `Device`.\n", + "2) The `rydberg_level` determines the [Ising interaction coefficient](./programming.md#ising-hamiltonian) $C_6$ of the Ising Hamiltonian. The quantity $\\frac{C_6}{\\hbar}$ is accessible via the `interaction_coeff` attribute of the `Device`.\n", "\n", - "3) The _Channels_ are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). The type of the available channels are going to define the _supported bases_ and _supported states_ among the _Device parameters_. Knowing what states you want to use in your computation, you can first check that they are among the \"supported states\", then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", + "3) The `Channels` in the `channel_objects` parameter are going to determine what [Channels are available for the computation](programming.md#pick-the-channels). Knowing what states you want to use in your computation, you can first check that they are among the `Device.supported_states`, then find the bases and their associated channel that enable to use these states using [the conventions page](conventions.md#bases).\n", "\n", - "4) The _Maximum sequence duration_ constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", + "4) The `max_sequence_duration` constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", "\n", - "5) The _Maximum number of runs_ limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." + "5) The `max_runs` limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." ] }, { "cell_type": "markdown", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, + "metadata": {}, "source": [ "
\n", "\n", "**Note**:\n", "\n", - "Other parameters are being defined in the `Device`. You can see the effect of each them in the [API documentation](./apidoc/core.rst#Devices).\n", + "If the properties `requires_layout` is set to `True`, then you have to define the `Register` from a layout. This adds more constraints to the creation of your `Register`, and is [presented in an advanced tutorial](./tutorials/reg_layouts.nblink).\n", "\n", "
" ] @@ -379,7 +358,7 @@ "tags": [] }, "source": [ - "The `Channel` is determined by:" + "The `Channel` is defined by:" ] }, { @@ -396,7 +375,7 @@ } }, "source": [ - ".. autoclass:: pulser.channels.base_channel\n", + ".. autoclass:: pulser.channels.base_channel.Channel\n", " :noindex:" ] }, From 65f494d7d65f1ffabc692d5939b7ddb613534d63 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 30 Jan 2025 09:24:20 +0100 Subject: [PATCH 32/44] Try fixing link to --- docs/source/hardware.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index d018bf696..1674173be 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -256,7 +256,7 @@ "source": [ "The `Device` is going to constrain the next steps of your [quantum program](./programming.md#writing-a-pulser-program):\n", "\n", - "1) Some parameters are going to constrain [the creation of your Register](programming.md/#create-the-register), and therefore, the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). Some of these parameters are:\n", + "1) Some parameters are going to constrain [the creation of your Register](./programming.md#create-the-register), and therefore, the [interaction strength in the interaction Hamiltonian](programming.md#interaction-hamiltonian). Some of these parameters are:\n", " - `dimensions`\n", " - `max_atom_num`\n", " - `max_radial_distance`\n", From a6567398a219630d01fe349a1166aa89c24f81c1 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 30 Jan 2025 10:16:09 +0100 Subject: [PATCH 33/44] Fix device and channel description, try hidding the input --- docs/source/hardware.ipynb | 37 ++++++++++++------------------------- docs/source/programming.md | 6 +++--- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 1674173be..5f671fe85 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -279,7 +279,7 @@ "\n", "**Note**:\n", "\n", - "If the properties `requires_layout` is set to `True`, then you have to define the `Register` from a layout. This adds more constraints to the creation of your `Register`, and is [presented in an advanced tutorial](./tutorials/reg_layouts.nblink).\n", + "If the Device associated with a QPU has `requires_layout=True`, then you have to define the `Register` from a layout. This adds more constraints to the creation of your `Register`, and is [presented in an advanced tutorial](./tutorials/reg_layouts.nblink).\n", "\n", "
" ] @@ -309,30 +309,13 @@ "source": [ "The third step to writing a Pulser program is [the selection of Channels among the Device](programming.md#pick-a-device).\n", "\n", - "As a reminder, the selection of a `Channel` defines the [interaction Hamiltonian](programming.md#interaction-hamiltonian) and [the driving Hamiltonian](programming.md#driving-hamiltonian) $H_D$.\n", + "As a reminder, the selection of a `Channel` defines the [interaction Hamiltonian](programming.md#interaction-hamiltonian) and [the driving Hamiltonian](programming.md#driving-hamiltonian) $H^D$.\n", "\n", "$$\n", "H^D(t) / \\hbar = \\frac{\\Omega(t)}{2} e^{-i\\phi} |a\\rangle\\langle b| + \\frac{\\Omega(t)}{2} e^{i\\phi} |b\\rangle\\langle a| - \\delta(t) |b\\rangle\\langle b|\n", "$$\n", "\n", - "The `Channel`s available for selection are stored in the `channels` property of the `Device`, a dictionnary associating a name to a `Channel`. Let's have a look at the only channel available in `AnalogDevice`, the `\"rydberg_global\"` channel:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "import pulser\n", - "\n", - "print(pulser.AnalogDevice.channels[\"rydberg_global\"])" + "The `Channels` available for selection are stored in the `channels` property of the `Device`, a dictionnary associating a `channel_id` to each `Channel` in `channel_objects`. For instance, `AnalogDevice` only contains one channel, the `rydberg_global` channel, which can be accessed with `AnalogDevice.channels[\"rydberg_global\"]`. " ] }, { @@ -404,13 +387,13 @@ "source": [ "The `Channel` is going to determine the computational basis used in the driving Hamiltonian, and what is the Hamiltonian each atom sees:\n", "\n", - "- The type of the `Channel` defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the type of channels can be found [here](conventions.md#bases).\n", + "- The type of the `Channel` defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the child classes of `Channel` can be found [here](./apidoc/core.rst#available-channels).\n", "- The addressing of the `Channel` determines what atoms experience the driving Hamiltonian. In general, physical `Channels` have a `Global` addressability, which means that a Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", "\n", "The `Channel` also set constraints on the next stage of your quantum program, the addition of Pulses:\n", - "- the **duration** of the pulse is constrained by the minimum and maximum pulse duration, as well as the clock period (it has to be a multiple of the clock period).\n", - "- the **amplitude** is limited by the maximum amplitude.\n", - "- the **detuning** is limited by the maximum absolute detuning." + "- the **duration** of the pulse is constrained by `min_duration` and `max_duration`, as well as `clock_period` (it has to be a multiple of the clock period).\n", + "- the **amplitude** is limited by the maximum amplitude `max_amp` and `min_avg_amp`.\n", + "- the **detuning** is limited by the maximum absolute detuning `max_abs_det`. It has to be between -`max_abs_det` and `max_abs_det`." ] }, { @@ -427,7 +410,7 @@ "\n", "**Note**:\n", "\n", - "The modulation bandwidth and the EOM support are associated with more advanced features explained [in this tutorial](./tutorials/output_mod_eom.nblink). For a full list of the parameters of a `Channel` and the constraints they set, please check the [API documentation](./apidoc/core.rst#channels).\n", + "The modulation bandwidth `mod_bandwidth` impacts the duration, the amplitude, the detuning and the phase of the Pulses. It is a more advanced feature explained [in this tutorial](./tutorials/output_mod_eom.nblink).\n", "\n", "
" ] @@ -485,6 +468,10 @@ "execution_count": null, "metadata": { "editable": true, + "jupyter": { + "source_hidden": true + }, + "remove-input": true, "slideshow": { "slide_type": "" }, diff --git a/docs/source/programming.md b/docs/source/programming.md index 374a5709b..f311a33e7 100644 --- a/docs/source/programming.md +++ b/docs/source/programming.md @@ -169,7 +169,7 @@ As outlined above, Pulser lets you program an Hamiltonian ([the Hamiltonian $H$] :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. For a complete view of the constraints introduced by the device, [check its description](./apidoc/core.rst). +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. For a complete view of the constraints introduced by the device, [check its description](./hardware.ipynb). ### 2. Create the Register @@ -233,7 +233,7 @@ We have successfully defined the [Hamiltonian](programming.md#2-hamiltonian-evol 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](apidoc/core.rst) 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). +- 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`](apidoc/core.rst). +- 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). \ No newline at end of file From 3b93cd58bb2baddd219f47234c9fd00ad7e1d540 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 30 Jan 2025 10:49:42 +0100 Subject: [PATCH 34/44] Try fixing build --- docs/source/hardware.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 5f671fe85..cb5b9f7f8 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -387,7 +387,7 @@ "source": [ "The `Channel` is going to determine the computational basis used in the driving Hamiltonian, and what is the Hamiltonian each atom sees:\n", "\n", - "- The type of the `Channel` defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the child classes of `Channel` can be found [here](./apidoc/core.rst#available-channels).\n", + "- The type of the `Channel` defines the [states](conventions.md#bases) that can be addressed by the [driving Hamiltonian](programming.md#driving-hamiltonian) if this channel is picked. All the child classes of `Channel` can be found [here](./apidoc/core.rst#module-pulser.channels.channels).\n", "- The addressing of the `Channel` determines what atoms experience the driving Hamiltonian. In general, physical `Channels` have a `Global` addressability, which means that a Pulse added to this channel will implement the same driving Hamiltonian on all the atoms.\n", "\n", "The `Channel` also set constraints on the next stage of your quantum program, the addition of Pulses:\n", From 9804aa2ab52f74e7ea67df3ec661b03072b58b5e Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 30 Jan 2025 11:33:21 +0100 Subject: [PATCH 35/44] Fix tags to hide_input --- docs/source/hardware.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index cb5b9f7f8..c33dba211 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -471,12 +471,12 @@ "jupyter": { "source_hidden": true }, - "remove-input": true, + "hide_input": true, "slideshow": { "slide_type": "" }, "tags": [ - "remove-input" + "hide-input" ] }, "outputs": [], From d934bfe7e664b53773214fa82a5c35f6c00c1f23 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 30 Jan 2025 13:27:37 +0100 Subject: [PATCH 36/44] Change device descr to "Args", stop trying to mask input --- docs/source/hardware.ipynb | 53 ++++--------------- pulser-core/pulser/devices/_device_datacls.py | 2 +- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index c33dba211..204922a71 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -458,52 +458,21 @@ "The `pulser.AnalogDevice` only supports the $\\left|r\\right>$ and $\\left|g\\right>$ states, because it only supports one channel of type \"Rydberg\" (that can be declared using its name \"rydberg_global\"). It implements the [Ising Hamiltonian](programming.md#ising-hamiltonian): \n", "\n", "$$\\frac{H}{\\hbar}(t) = \\sum_{k=1}^N \\left (\\frac{\\Omega(t)}{2} e^{-i\\phi(t)} |g\\rangle\\langle r|_k + \\frac{\\Omega(t)}{2} e^{i\\phi(t)} |r\\rangle\\langle g|_k - \\delta(t) |r\\rangle\\langle r|_k(t) + \\sum_{j Date: Thu, 30 Jan 2025 14:56:24 +0100 Subject: [PATCH 37/44] Add link to backend --- docs/source/hardware.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index 204922a71..fd3783522 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -268,7 +268,7 @@ "\n", "4) The `max_sequence_duration` constrains the duration of the [Pulses you can add](programming.md#add-the-pulses), and therefore the Hamiltonian describing the system can at most be defined between 0 and this value.\n", "\n", - "5) The `max_runs` limits the number of runs a quantum program can be executed on the QPU. See the section on `Backends` to read more about this." + "5) The `max_runs` limits the number of runs a quantum program can be executed on the QPU. See [the section on Backends](./tutorials/backends.nblink) to read more about this." ] }, { From c8b948e6aab47c6959d9e1d1d4c6f57760ae62f2 Mon Sep 17 00:00:00 2001 From: a_corni Date: Thu, 30 Jan 2025 15:06:51 +0100 Subject: [PATCH 38/44] Move Attributes to Args in Device --- pulser-core/pulser/devices/_device_datacls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pulser-core/pulser/devices/_device_datacls.py b/pulser-core/pulser/devices/_device_datacls.py index 0c12cf9f5..1103d72bf 100644 --- a/pulser-core/pulser/devices/_device_datacls.py +++ b/pulser-core/pulser/devices/_device_datacls.py @@ -64,7 +64,7 @@ class BaseDevice(ABC): r"""Base class of a neutral-atom device. - Args: + Attributes: name: The name of the device. dimensions: Whether it supports 2D or 3D arrays. max_atom_num: Maximum number of atoms supported in an array. @@ -743,7 +743,7 @@ class Device(BaseDevice): For usage in emulations, it can be converted to a VirtualDevice through the `Device.to_virtual()` method. - Attributes: + Args: name: The name of the device. dimensions: Whether it supports 2D or 3D arrays. max_atom_num: Maximum number of atoms supported in an array. From e2802c051cf50e8b3199307e9d3292bca5b841ae Mon Sep 17 00:00:00 2001 From: a_corni Date: Fri, 31 Jan 2025 20:30:53 +0100 Subject: [PATCH 39/44] Add mention to API doc --- docs/source/hardware.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/hardware.ipynb b/docs/source/hardware.ipynb index fd3783522..5b2f5ce9e 100644 --- a/docs/source/hardware.ipynb +++ b/docs/source/hardware.ipynb @@ -224,9 +224,9 @@ "source": [ "
\n", "\n", - "**Tip**:\n", + "**Note**:\n", "\n", - "It is possible to display some of the specifications of the `Device` with `Device.specs`. See an example with `AnalogDevice.specs` [in the section below](#the-analogdevice).\n", + "The `Device` object has many useful properties and methods, that you can check in the [API documentation](./apidoc/core.rst#devices). For instance, it is possible to display some of the specifications of the `Device` with `Device.specs`. See an example with `AnalogDevice.specs` [in the section below](#the-analogdevice).\n", "\n", "
" ] From 05df83e3f21df468fe25e6548acab49e33498234 Mon Sep 17 00:00:00 2001 From: a_corni Date: Mon, 3 Feb 2025 18:00:58 +0100 Subject: [PATCH 40/44] Add seealso sections in programming --- docs/source/programming.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/source/programming.md b/docs/source/programming.md index f311a33e7..b51d4aff8 100644 --- a/docs/source/programming.md +++ b/docs/source/programming.md @@ -169,7 +169,11 @@ As outlined above, Pulser lets you program an Hamiltonian ([the Hamiltonian $H$] :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. For a complete view of the constraints introduced by the device, [check its description](./hardware.ipynb). +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 @@ -214,6 +218,10 @@ The addressing of a `Channel` defines the number of atoms whose transition will The most common addressing for a `Channel` is the `Global` one: all the atoms evolve under the same [driving Hamiltonian](programming.md#21-driving-hamiltonian). ::: +:::{seealso} +For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb#the-channels). +::: + ### 4. Add the Pulses By adding pulses to a channel, we incrementally construct the [driving Hamiltonian](programming.md#21-driving-hamiltonian): From dc2b6ee1bc6f363782d7d904f514d07742a24da8 Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 4 Feb 2025 11:21:37 +0100 Subject: [PATCH 41/44] Deleting the-channels --- docs/source/programming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/programming.md b/docs/source/programming.md index b51d4aff8..88f34df5a 100644 --- a/docs/source/programming.md +++ b/docs/source/programming.md @@ -219,7 +219,7 @@ The most common addressing for a `Channel` is the `Global` one: all the atoms ev ::: :::{seealso} -For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb#the-channels). +For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb). ::: ### 4. Add the Pulses From 8524d9db82977572b5287097c684b958aed2441e Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 4 Feb 2025 11:30:54 +0100 Subject: [PATCH 42/44] Tag The-Channels --- docs/source/programming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/programming.md b/docs/source/programming.md index 88f34df5a..fe7f2eddb 100644 --- a/docs/source/programming.md +++ b/docs/source/programming.md @@ -219,7 +219,7 @@ The most common addressing for a `Channel` is the `Global` one: all the atoms ev ::: :::{seealso} -For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb). +For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb#The-Channels). ::: ### 4. Add the Pulses From 6e4cdd23033f150deb3cddf4fc4bcf019efa97b8 Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 4 Feb 2025 11:44:04 +0100 Subject: [PATCH 43/44] referencing to html instead --- docs/source/programming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/programming.md b/docs/source/programming.md index fe7f2eddb..42a2a2227 100644 --- a/docs/source/programming.md +++ b/docs/source/programming.md @@ -219,7 +219,7 @@ The most common addressing for a `Channel` is the `Global` one: all the atoms ev ::: :::{seealso} -For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb#The-Channels). +For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.html#The-Channels). ::: ### 4. Add the Pulses From 84b556c6ca7726237e03fe4e2de9e0531c0dfdb9 Mon Sep 17 00:00:00 2001 From: a_corni Date: Tue, 4 Feb 2025 11:54:46 +0100 Subject: [PATCH 44/44] Going for hardware.ipynb --- docs/source/programming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/programming.md b/docs/source/programming.md index 42a2a2227..88f34df5a 100644 --- a/docs/source/programming.md +++ b/docs/source/programming.md @@ -219,7 +219,7 @@ The most common addressing for a `Channel` is the `Global` one: all the atoms ev ::: :::{seealso} -For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.html#The-Channels). +For a thorough description of what a Channel is and some tips on how to select a Channel, [check this page](./hardware.ipynb). ::: ### 4. Add the Pulses