diff --git a/pr-preview/pr-1009/home/migration/index.html b/pr-preview/pr-1009/home/migration/index.html index 5c27ce5e9..67e5d8208 100644 --- a/pr-preview/pr-1009/home/migration/index.html +++ b/pr-preview/pr-1009/home/migration/index.html @@ -1,18 +1,20 @@ - Migration Guide to Bloqade Analog - The Neutral Atom SDK
Skip to content

Migrating to Bloqade Analog

Introduction

In order to make room for more features inside the Bloqade ecosystem, we have created a new package to take the place of the old bloqade package. The new package is called bloqade-analog. The old package bloqade will house a namespace package for other features such as our new Bloqade Digital package with support for circuit-based quantum computers!

Installation

You can install the package with pip in your Python environment of choice via:

pip install bloqade-analog
+ Migration Guide to Bloqade Analog - The Neutral Atom SDK      

Migrating to Bloqade Analog

Introduction

In order to make room for more features inside the Bloqade ecosystem, we have created a new package to take the place of the old bloqade package. The new package is called bloqade-analog. The old package bloqade will house a namespace package for other features such as our new Bloqade Digital package with support for circuit-based quantum computers!

Installation

You can install the package with pip in your Python environment of choice via:

pip install bloqade-analog
 

Migration

The new package is a drop-in replacement for the old one. You can simply replace import bloqade with import bloqade.analog or from bloqade.analog import ... in your code. Everything else should work as before.

Example

lets say your header of your python script looks like this:

from bloqade import var
 from bloqade.atom_arrangement import Square
 ...
 
You can simply replace it with:

from bloqade.analog import var
 from bloqade.analog.atom_arrangement import Square
 ...
-

Migrating old bloqade json files

If you have old bloqade json files, you will not be able to directly deserialize them anymore because of the package restructuring. Howver we have provided some tools to migrate those JSON files to be compatible with bloqade-analog. You can do this by running the following command in the command line for a single file:

python -m bloqade.analog.migrate <path_to_old_json_file>
-
This will create a new file with the same name as the old file, but with _analog appended to the end of the filename. For example, if you have a file called my_bloqade.json, the new file will be called my_bloqade_analog.json. You can then use load to deserialize this file with the bloqade-analog package.

Another option is to use the migration tool in a python script:

from bloqade.analog.migrate import migrate
-
- # set the indent level for the output file
-indent: int = ...
-# set to True if you want to overwrite the old file, otherwise the new file will be created with -analog appended to the end of the filename
-overwrite: bool = ...
-f
-or filename in ["file1.json", "file2.json", ...]:
-    migrate(filename, indent=indent, overwrite=overwrite)
+

Migrating old bloqade JSON files

If you have old bloqade JSON files, you will not be able to directly deserialize them anymore because of the package restructuring. Howver we have provided some tools to migrate those JSON files to be compatible with bloqade-analog. You can do this by running the following command in the command line for a single file:

python -m bloqade.analog.migrate <path_to_old_json_file>
+
This will create a new file with the same name as the old file, but with _analog appended to the end of the filename. For example, if you have a file called my_bloqade.json, the new file will be called my_bloqade-analog.json. You can then use load to deserialize this file with the bloqade-analog package. There are other options for converting the file, such as setting the indent level for the output file or overwriting the old file. You can see all the options by running:

python -m bloqade.analog.migrate --help
+
You can also migrate multiple files at once by running:

python -m bloqade.analog.migrate <path_to_old_json_file1> <path_to_old_json_file2> ...
+

Another option is to use the migration tool in a python script:

from bloqade.analog.migrate import migrate
+
+ # set the indent level for the output file
+indent: int = ...
+# set to True if you want to overwrite the old file, otherwise the new file will be created with -analog appended to the end of the filename
+overwrite: bool = ...
+f
+or filename in ["file1.json", "file2.json", ...]:
+    migrate(filename, indent=indent, overwrite=overwrite)
 
This will migrate all the files in the list to the new format.

Having trouble, comments, or concerns?

Please open an issue on our GitHub

\ No newline at end of file diff --git a/pr-preview/pr-1009/search/search_index.json b/pr-preview/pr-1009/search/search_index.json index 683f6c55b..a2bef693b 100644 --- a/pr-preview/pr-1009/search/search_index.json +++ b/pr-preview/pr-1009/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-,:!=\\[\\: )\"`/]+|\\.(?!\\d)|&[lg]t;|(?!\\b)(?=[A-Z][a-z])","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Index","text":"

[!IMPORTANT]

Bloqade has been restructured to make room for new features and improvements. Please refer to the migration guide for more information.

"},{"location":"#welcome-to-bloqade-queras-neutral-atom-sdk","title":"Welcome to Bloqade: QuEra's Neutral Atom SDK","text":""},{"location":"#what-is-bloqade","title":"What is Bloqade?","text":"

Bloqade is a Python SDK for QuEra's neutral atom quantum computer Aquila (check out our paper!). It's designed to make writing and analyzing the results of analog quantum programs on Aquila as easy as possible. It features custom atom geometries and flexible waveform definitions in both emulation and real hardware. Bloqade interfaces with the AWS Braket cloud service where Aquila is hosted, enabling you to submit programs as well as retrieve and analyze real hardware results all-in-one.

"},{"location":"#installation","title":"Installation","text":"

You can install the package with pip in your Python environment of choice via:

pip install bloqade\n
"},{"location":"#a-glimpse-of-bloqade","title":"A Glimpse of Bloqade","text":"

Let's try a simple example where we drive a Rabi oscillation on a single neutral atom. Don't worry if you're unfamiliar with neutral atom physics, (you can check out our Background for more information!) the goal here is to just give you a taste of what Bloqade can do.

We start by defining where our atoms go, otherwise known as the atom geometry. In this particular example we will use a small Honeycomb lattice:

from bloqade.analog.atom_arrangement import Honeycomb\n\ngeometry = Honeycomb(2, lattice_spacing = 10.0)\n

We can verify what the atom geometry looks like by .show()'ing it:

geometry.show()\n

We now define what the time evolution looks like using a pulse sequence. The pulse sequence here is the time profile of the Rabi Drive targeting the ground-Rydberg two level transition, which causes the Rabi oscillations. We choose a constant waveform with a value of \\(\\frac{\\pi}{2} \\text{rad}/\\text{us}\\) and a duration of \\(1.0 \\,\\text{us}\\). This produces a \\(\\frac{\\pi}{2}\\) rotation on the Bloch sphere meaning our final measurements should be split 50/50 between the ground and Rydberg state.

from math import pi\nrabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .constant(value=pi/2, duration=1.0)\n)\n

Here rabi.amplitude means exactly what it is, the Rabi amplitude term of the Hamiltonian. uniform refers to applying the waveform uniformly across all the atom locations.

We can visualize what our program looks like again with .show():

We can now run the program through Bloqade's built-in emulator to get some results. We designate that we want the program to be run and measurements performed 100 times:

emulation_results = rabi_program.bloqade.python().run(100)\n

With the results we can generate a report object that contains a number of methods for analyzing our data, including the number of counts per unique bitstring:

bitstring_counts = emulation_results.report().counts()\n

Which gives us:

[OrderedDict([('0', 55), ('1', 45)])]\n

If we want to submit our program to hardware we'll need to adjust the waveform as there is a constraint the Rabi amplitude waveform must start and end at zero. This is easy to do as we can build off the atom geometry we saved previously but apply a piecewise linear waveform:

hardware_rabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .piecewise_linear(values = [0, pi/2, pi/2, 0], durations = [0.06, 1.0, 0.06])\n)\n\nhardware_rabi_program.show()\n

Now instead of using the built-in Bloqade emulator we submit the program to Aquila. You will need to use the AWS CLI to obtain credentials from your AWS account or set the proper environment variables before hand.

hardware_results = hardware_rabi_program.braket.aquila.run_async(100)\n

.run_async is a non-blocking version of the standard .run method, allowing you to continue work while waiting for results from Aquila. .run_async immediately returns an object you can query for the status of your tasks in the queue as well.

You can do the exact same analysis you do on emulation results with hardware results too:

hardware_bitstring_counts = hardware_results.report().counts()\n

If you want to try the above at once, we collected the above steps into the snippet below:

from math import pi\nfrom bloqade.analog.atom_arrangement import Honeycomb\n\ngeometry = Honeycomb(2, lattice_spacing = 10.0)\nrabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .constant(value=pi/2, duration=1.0)\n)\nemulation_results = rabi_program.bloqade.python().run(100)\nbitstring_counts = emulation_results.report().counts()\n\nhardware_rabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .piecewise_linear(values = [0, pi/2, pi/2, 0], durations = [0.06, 1.0, 0.06])\n)\nhardware_results = hardware_rabi_program.braket.aquila.run_async(100)\nhardware_bitstring_counts = hardware_results.report().counts()\n

"},{"location":"#features","title":"Features","text":""},{"location":"#customizable-atom-geometries","title":"Customizable Atom Geometries","text":"

You can easily explore a number of common geometric lattices with Bloqade's atom_arrangement's:

from bloqade.analog.atom_arrangement import Lieb, Square, Chain, Kagome\n\ngeometry_1 = Lieb(3)\ngeometry_2 = Square(2)\ngeometry_3 = Chain(5)\ngeometry_4 = Kagome(3)\n

If you're not satisfied with the Bravais lattices we also allow you to modify existing Bravais lattices as follows:

geometry_5 = Kagome(3).add_position((10,11))\n

You can also build your geometry completely from scratch:

from bloqade import start\n\ngeometry = start.add_positions([(0,0), (6,0), (12,0)])\n
"},{"location":"#flexible-pulse-sequence-construction","title":"Flexible Pulse Sequence Construction","text":"

Define waveforms for pulse sequences any way you like by either building (and chaining!) them immediately as part of your program:

from bloqade.analog.atom_arrangement import Square\n\ngeometry = Square(2)\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\ncustom_rabi_amp_waveform = (\n  target_rabi_amplitude\n  .piecewise_linear(values=[0, 10, 10, 0], durations=[0.1, 3.5, 0.1])\n  .piecewise_linear(values=[0, 5, 3, 0], durations=[0.2, 2.0, 0.2])\n)\n

Or building them separately and applying them later:

from bloqade.analog.atom_arrangement import Square, Chain\n\ngeometry_1 = Square(3)\ngeometry_2 = Chain(5)\n\ntarget_rabi_amplitude = start.rydberg.rabi.amplitude.uniform\npulse_sequence = target_rabi_amplitude.uniform.constant(value=2.0, duration=1.5).parse_sequence()\n\nprogram_1 = geometry_1.apply(pulse_sequence)\nprogram_2 = geometry_2.apply(pulse_sequence)\n
"},{"location":"#hardware-and-emulation-backends","title":"Hardware and Emulation Backends","text":"

Go from a fast and powerful emulator:

from bloqade.analog.atom_arrangement import Square\nfrom math import pi\n\ngeometry = Square(3, lattice_spacing = 6.5)\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nprogram = (\n  target_rabi_amplitude\n  .piecewise_linear(values = [0, pi/2, pi/2, 0], durations = [0.06, 1.0, 0.06])\n)\nemulation_results = program.bloqade.python().run(100)\n

To real quantum hardware in a snap:

hardware_results = program.braket.aquila().run_async(100)\n
"},{"location":"#simple-parameter-sweeps","title":"Simple Parameter Sweeps","text":"

Use variables to make parameter sweeps easy on both emulation and hardware:

from bloqade import start\nimport numpy as np\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nrabi_oscillation_program = (\n  target_rabi_amplitude\n  .piecewise_linear(durations = [0.06, \"run_time\", 0.06], values = [0, 15, 15, 0])\n)\nrabi_oscillation_job = rabi_oscillation_program.batch_assign(run_time=np.linspace(0, 3, 101))\n\nemulation_results = rabi_oscillation_job.bloqade.python().run(100)\nhardware_results = rabi_oscillation_job.braket.aquila().run(100)\n
emulation_results.report().rydberg_densities()\n                0\ntask_number\n0            0.16\n1            0.35\n2            0.59\n3            0.78\n4            0.96\n...           ...\n96           0.01\n97           0.09\n98           0.24\n99           0.49\n100          0.68\n\n[101 rows x 1 columns]\n
"},{"location":"#quick-results-analysis","title":"Quick Results Analysis","text":"

Want to just see some plots of your results? .show() will show you the way!

from bloqade.analog.atom_arrangement import Square\n\nrabi_amplitude_values = [0.0, 15.8, 15.8, 0.0]\nrabi_detuning_values = [-16.33, -16.33, 42.66, 42.66]\ndurations = [0.8, 2.4, 0.8]\n\ngeometry = Square(3, lattice_spacing=5.9)\nrabi_amplitude_waveform = (\n  geometry\n  .rydberg.rabi.amplitude.uniform.piecewise_linear(durations, rabi_amplitude_values)\n)\nprogram = (\n  rabi_amplitude_waveform\n  .detuning.uniform.piecewise_linear(durations, rabi_detuning_values)\n)\nemulation_results = program.bloqade.python().run(100)\nemulation_results.report().show()\n

"},{"location":"#contributing-to-bloqade","title":"Contributing to Bloqade","text":"

Bloqade is released under the Apache License, Version 2.0. If you'd like the chance to shape the future of neutral atom quantum computation, see our Contributing Guide for more info!

"},{"location":"contributing/","title":"Contributing","text":"

Thank you for your interest in contributing to the project! We welcome all contributions. There are many different ways to contribute to Bloqade, and we are always looking for more help. We accept contributions in the form of bug reports, feature requests, documentation improvements, and code contributions. For more information about how to contribute, please read the following sections.

"},{"location":"contributing/#table-of-contents","title":"Table of Contents","text":"
  • Reporting a Bug
  • Reporting Documentation Issues
  • Feature Requests
  • Developing Bloqade
  • Design Philosophy and Architecture
  • Community Slack
  • Ask a Question
  • Providing Feedback
"},{"location":"contributing/asking-a-question/","title":"Ask a Question","text":"

If you're interested in contributing to Bloqade, or just want to discuss the project, join the discussion on GitHub Discussions at https://github.com/QuEraComputing/bloqade-analog/discussions

"},{"location":"contributing/code-of-conduct/","title":"Design Philosophy and Architecture","text":"

Given the heterogeneous nature of the hardware we target, We have decided to use a compiler-based approach to our software stack, allowing us to target different hardware backends with the same high-level language. Below is a diagram of the software stack in Bloqade.

graph TD\n    Builder[\"Builder Representation\"]\n    PythonAST[\"Bloqade AST Python\"]\n    JuliaAST[\"Bloqade AST Julia\"]\n\n    EmulatorPy[\"Emulator IR Python\"]\n    EmulatorJL[\"Emulator IR Julia\"]\n\n    QuEra[\"QuEra IR\"]\n    Braket[\"Braket IR\"]\n    JuliaEmulator[\"Bloqade.jl\"]\n    PythonEmulator[\"Python Emulator\"]\n\n    Aquila[\"Aquila\"]\n\n    Builder -->|parse| PythonAST\n    PythonAST -->|lower| EmulatorPy\n    PythonAST -->|lower| QuEra\n    PythonAST -->|lower| Braket\n    PythonAST -->|transpile| JuliaAST\n\n    QuEra -->|execute| Aquila\n    Braket -->|execute| Aquila\n\n    JuliaAST -->|lower| EmulatorJL\n    EmulatorPy -->|execute| PythonEmulator\n    EmulatorJL -->|execute| JuliaEmulator\n
"},{"location":"contributing/code-of-conduct/#high-level-builder-representation","title":"High-Level Builder Representation","text":"

When programming Bloqade using the Python API, the user constructs a representation of an analog quantum circuit. This representation is a flattened version of the actual analog circuit. Flattened means that the user input is a linear sequence of operations where the context of neighboring nodes in the sequence of instructions can determine the program tree structure. The Bloqade AST describes the actual analog circuit.

"},{"location":"contributing/code-of-conduct/#bloqade-ast","title":"Bloqade AST","text":"

The Bloqade AST is a representation of a quantum analog circuit for neutral atom computing. It is a directed acyclic graph (DAG) with nodes for different hierarchical levels of the circuit. The base node is the AnalogCircuit which contains the geometry of the atoms stored as a AtomArragment or ParallelRegister objects. The other part of the circuit is the Sequence, which contains the waveforms that describe the drives for the Ryberg/Hyperfine transitions of each Rydberg atom. Each transition is represented by a Pulse including a Field for the drive's detuning, Rabi amplitude, and Rabi phase . A Field relates the spatial and temporal dependence of a drive. The spatial modulates the temporal dependence of the waveform. A DAG also describes the Waveform object. Finally, we have basic Scalar expressions as well for describing the syntax of real-valued continuous numbers.

"},{"location":"contributing/code-of-conduct/#bloqade-compilers-and-transpilers","title":"Bloqade Compilers and Transpilers","text":"

Given a user program expressed as the Bloqade AST, we can target various backends by transforming from the Bloqade AST to other kinds of IR. For example, when submitting a task to QuEra's hardware, we transform the Bloqade AST to the IR that describes a valid program for the hardware.

This process is referred to as lowering, which in a general sense is a transformation that takes you from one IR to another where the target IR is specialized or has a smaller syntactical structure. Transpiling corresponds to a transformation that takes you from one language to equivalent expressions in another. For example, we can transpile from the Bloqade AST in Python to the Bloqade AST in Julia. The generic term for both of these types of transformation in Bloqade is Code Generation. You will find various code generation implementations in various codegen modules.

"},{"location":"contributing/community-slack/","title":"Community Slack","text":"

You can join QuEra's Slack workspace with this link. Join the #bloqade channel to discuss anything related to Bloqade.

"},{"location":"contributing/design-philosophy-and-architecture/","title":"Design Philosophy and Architecture","text":"

Given the heterogeneous nature of the hardware we target, We have decided to use a compiler-based approach to our software stack, allowing us to target different hardware backends with the same high-level language. Below is a diagram of the software stack in Bloqade.

graph TD\n    Builder[\"Builder Representation\"]\n    PythonAST[\"Bloqade AST Python\"]\n    JuliaAST[\"Bloqade AST Julia\"]\n\n    EmulatorPy[\"Emulator IR Python\"]\n    EmulatorJL[\"Emulator IR Julia\"]\n\n    QuEra[\"QuEra IR\"]\n    Braket[\"Braket IR\"]\n    JuliaEmulator[\"Bloqade.jl\"]\n    PythonEmulator[\"Python Emulator\"]\n\n    Aquila[\"Aquila\"]\n\n    Builder -->|parse| PythonAST\n    PythonAST -->|lower| EmulatorPy\n    PythonAST -->|lower| QuEra\n    PythonAST -->|lower| Braket\n    PythonAST -->|transpile| JuliaAST\n\n    QuEra -->|execute| Aquila\n    Braket -->|execute| Aquila\n\n    JuliaAST -->|lower| EmulatorJL\n    EmulatorPy -->|execute| PythonEmulator\n    EmulatorJL -->|execute| JuliaEmulator\n
"},{"location":"contributing/design-philosophy-and-architecture/#high-level-builder-representation","title":"High-Level Builder Representation","text":"

When programming Bloqade using the Python API, the user constructs a representation of an analog quantum circuit. This representation is a flattened version of the actual analog circuit. Flattened means that the user input is a linear sequence of operations where the context of neighboring nodes in the sequence of instructions can determine the program tree structure. The Bloqade AST describes the actual analog circuit.

"},{"location":"contributing/design-philosophy-and-architecture/#bloqade-ast","title":"Bloqade AST","text":"

The Bloqade AST is a representation of a quantum analog circuit for neutral atom computing. It is a directed acyclic graph (DAG) with nodes for different hierarchical levels of the circuit. The base node is the AnalogCircuit which contains the geometry of the atoms stored as a AtomArragment or ParallelRegister objects. The other part of the circuit is the Sequence, which contains the waveforms that describe the drives for the Ryberg/Hyperfine transitions of each Rydberg atom. Each transition is represented by a Pulse including a Field for the drive's detuning, Rabi amplitude, and Rabi phase . A Field relates the spatial and temporal dependence of a drive. The spatial modulates the temporal dependence of the waveform. A DAG also describes the Waveform object. Finally, we have basic Scalar expressions as well for describing the syntax of real-valued continuous numbers.

"},{"location":"contributing/design-philosophy-and-architecture/#bloqade-compilers-and-transpilers","title":"Bloqade Compilers and Transpilers","text":"

Given a user program expressed as the Bloqade AST, we can target various backends by transforming from the Bloqade AST to other kinds of IR. For example, when submitting a task to QuEra's hardware, we transform the Bloqade AST to the IR that describes a valid program for the hardware.

This process is referred to as lowering, which in a general sense is a transformation that takes you from one IR to another where the target IR is specialized or has a smaller syntactical structure. Transpiling corresponds to a transformation that takes you from one language to equivalent expressions in another. For example, we can transpile from the Bloqade AST in Python to the Bloqade AST in Julia. The generic term for both of these types of transformation in Bloqade is Code Generation. You will find various code generation implementations in various codegen modules.

"},{"location":"contributing/developing-bloqade/","title":"Setting up your Development Environment","text":"

Before You Get Started

Depending on the complexity of the contribution you'd like to make to Bloqade, it may be worth reading the Design Philosophy and Architecture section to get an idea of why Bloqade is structured the way that it is and how to make your contribution adhere to this philosophy.

Our development environment contains a set of tools we use for development, testing, and documentation. This section describes how to set up the development environment. We primarily use pdm to manage python environments and dependencies.

"},{"location":"contributing/developing-bloqade/#setting-up-python","title":"Setting up Python","text":"

We use pdm to manage dependencies and virtual environment. After cloning the repository, run the following command to install dependencies:

pdm install\n

You can also install different dependency groups:

  • dev: dependencies for development
pdm install --dev\n# or\npdm install -d\n
  • doc: dependencies for building documentation
pdm install -G doc\n
"},{"location":"contributing/developing-bloqade/#useful-pdm-scripts","title":"Useful PDM scripts","text":""},{"location":"contributing/developing-bloqade/#tests","title":"Tests","text":"

You can run tests via

pdm run test\n

Or run tests and generate coverage via

pdm run coverage\n

will print out the coverage file level report in terminal.

pdm run coverage-html\n

This command generates an interactive html report in htmlcov folder. This will show which specific lines are not covered by tests.

"},{"location":"contributing/developing-bloqade/#documentation","title":"Documentation","text":"

You can build documentation via

pdm run doc_build\n

Or run a local server to preview documentation via

pdm run doc\n
"},{"location":"contributing/developing-bloqade/#jupytext","title":"Jupytext","text":"

You can sync jupyter notebooks and python scripts via

pdm run jupytext\n

this will help you development examples in jupyter notebook and python scripts simultaneously.

"},{"location":"contributing/developing-bloqade/#lint","title":"Lint","text":"

We primarily use ruff - an extremely fast linter for Python, and black as formatter. These have been configured into pre-commit hooks. After installing pre-commit on your own system, you can install pre-commit hooks to git via

pre-commit install\n
"},{"location":"contributing/documentation-issues/","title":"Reporting a Documentation Issue","text":"

We are always looking to improve our documentation. If you find a typo or think something is unclear, please open an issue on our GitHub page: https://github.com/QuEraComputing/bloqade-analog/issues

For typos or other minor problems, create an issue that contains a link to the specific page that includes the problem, along with a description of the problem and possibly a solution.

For a request for new documentation content, please open up an issue and describe what you think is missing from the documentation.

"},{"location":"contributing/feature-requests/","title":"Requesting new Features","text":"

Given that we are currently at the beginning of the development of the Bloqade python interface, we are open to suggestions about what features would be helpful to include in future package iterations. If you have a request for a new feature, please open an issue on our GitHub page: https://github.com/QuEraComputing/bloqade-analog/issues

We ask that the feature requests be as specific as possible. Please include the following information in your feature request:

  1. A short, descriptive title.

  2. A detailed description of the feature, including your attempt to solve the problem with the current version of Bloqade.

  3. A minimal code example that demonstrates the need for the feature.

  4. The version of Bloqade you are using.

  5. The version of Python you are using.

  6. The version of your operating system.

"},{"location":"contributing/providing-feedback/","title":"Providing Feedback","text":"

While Github Issues are a great way for us to better understand any issues your having with Bloqade as well as provide us with feature requests, we're always looking for ways to collect more general feedback about what the user experience with Bloqade is like.

To do that we have this form where you can provide your thoughts after using/experimenting/tinkering/hacking with Bloqade.

Your feedback will help guide the future of Bloqade's design so be honest and know that you're contributing to the future of Quantum Computing with Neutral Atoms!

"},{"location":"contributing/reporting-a-bug/","title":"Reporting a Bug","text":"

Bloqade is currently in the alpha phase of development, meaning bugs most likely exist in the current implementation. We are continuously striving to improve the stability of Bloqade. As such, we encourage our users to report all bugs they find. To do this, we ask you to submit an issue to our GitHub page: https://github.com/QuEraComputing/bloqade-analog/issues

Please include the following information in your bug report:

  1. A short, descriptive title.

  2. A detailed description of the bug, including the expected behavior and what happened.

  3. A minimal code example that reproduces the bug.

  4. The version of Bloqade you are using.

  5. The version of Python you are using.

  6. The version of your operating system.

"},{"location":"home/background/","title":"Background","text":""},{"location":"home/background/#neutral-atom-qubits","title":"Neutral Atom Qubits","text":"

The qubits that QuEra's neutral atom computer Aquila and Bloqade are designed to emulate are based on neutral atoms. As the name implies they are atoms that are neutrally charged but are also capable of achieving a Rydberg state where a single electron can be excited to an incredibly high energy level without ionizing the atom.

This incredibly excited electron energy level \\(|r\\rangle\\) and its default ground state \\(|g\\rangle\\) create a two-level system where superposition can occur. For enabling interaction between two or more qubits and achieving entanglement, when the neutral atoms are in the Rydberg state a phenomenon known as the Rydberg blockade can occur where an atom in the Rydberg state prevents a neighboring atom from also being excited to the same state.

For a more nuanced and in-depth read about the neutral atoms that Bloqade and Aquila use, refer to QuEra's qBook section on Qubits by puffing up atoms.

"},{"location":"home/background/#analog-vs-digital-quantum-computing","title":"Analog vs Digital Quantum Computing","text":"

There are two modes of quantum computation that neutral atoms are capable of: Analog and Digital.

You can find a brief explanation of the distinction below but for a more in-depth explanation you can refer to QuEra's qBook section on Analog vs Digital Quantum Computing

"},{"location":"home/background/#analog-mode","title":"Analog Mode","text":"

In the analog mode (supported by Bloqade and Aquila) you control your computation through the parameters of a time-dependent Hamiltonian that influences all the qubits at once. There are options for local control of the Hamiltonian on certain qubits however.

"},{"location":"home/background/#digital-mode","title":"Digital Mode","text":"

In the Digital Mode individual or multiple groups of qubits are controlled by applying gates (individual unitary operations). For neutral atoms, this digital mode can be accomplished with the introduction of hyperfine coupling, enabling a quantum state to be stored for long periods of time while also allowing for multi-qubit gates.

"},{"location":"home/background/#rydberg-many-body-hamiltonian","title":"Rydberg Many-Body Hamiltonian","text":"

When you emulate a program in Bloqade, you are emulating the time evolution of the Rydberg many-body Hamiltonian which looks like this:

\\[ i \\hbar \\dfrac{\\partial}{\\partial t} | \\psi \\rangle = \\hat{\\mathcal{H}}(t) | \\psi \\rangle, \\\\ \\] \\[ \\frac{\\mathcal{H}(t)}{\\hbar} = \\sum_j \\frac{\\Omega_j(t)}{2} \\left( e^{i \\phi_j(t) } | g_j \\rangle \\langle r_j | + e^{-i \\phi_j(t) } | r_j \\rangle \\langle g_j | \\right) - \\sum_j \\Delta_j(t) \\hat{n}_j + \\sum_{j < k} V_{jk} \\hat{n}_j \\hat{n}_k, \\]

where: \\(\\Omega_j\\), \\(\\phi_j\\), and \\(\\Delta_j\\) denote the Rabi frequency amplitude, laser phase, and the detuning of the driving laser field on atom (qubit) \\(j\\) coupling the two states \\(| g_j \\rangle\\) (ground state) and \\(| r_j \\rangle\\) (Rydberg state); \\(\\hat{n}_j = |r_j\\rangle \\langle r_j|\\) is the number operator, and \\(V_{jk} = C_6/|\\mathbf{x}_j - \\mathbf{x}_k|^6\\) describes the Rydberg interaction (van der Waals interaction) between atoms \\(j\\) and \\(k\\) where \\(\\mathbf{x}_j\\) denotes the position of the atom \\(j\\); \\(C_6\\) is the Rydberg interaction constant that depends on the particular Rydberg state used. For Bloqade, the default \\(C_6 = 862690 \\times 2\\pi \\text{ MHz \u03bcm}^6\\) for \\(|r \\rangle = \\lvert 70S_{1/2} \\rangle\\) of the \\(^{87}\\)Rb atoms; \\(\\hbar\\) is the reduced Planck's constant.

"},{"location":"home/background/#local-control","title":"Local Control","text":"

The Rydberg Many-Body Hamiltonian already implies from its subscripts that you can also have local control over your atoms. In Bloqade this local control extends to any term in the Hamiltonian while on Aquila this is currently restricted to the \\(\\Delta_j\\) laser detuning term.

Fields in Bloqade give you local (single-atom) control over the many-body Rydberg Hamiltonian.

They are a sum of one or more spatial modulations, which allows you to scale the amplitude of the waveform across the different sites in the system:

\\[ F_{i}(t) = \\sum_{\\alpha} C_{i}^{\\alpha}f_{\\alpha}(t) \\] \\[ C_{i}^{\\alpha} \\in \\mathbb{R} \\] \\[ f_{\\alpha}(t) \\colon \\mathbb{R} \\to \\mathbb{R} \\]

The \\(i\\)-th component of the field is used to generate the drive at the \\(i\\)-th site.

Note that the drive is only applied if the \\(i\\)-th site is filled with an atom.

You build fields in Bloqade by first specifying the spatial modulation followed by the waveform it should be multiplied by.

In the case of a uniform spatial modulation, it can be interpreted as a constant scaling factor where \\(C_{i}^{\\alpha} = 1.0\\).

"},{"location":"home/emulation/","title":"Emulation","text":"

This page is a work in progress!

"},{"location":"home/geometry/","title":"Geometry","text":"

This page is a work in progress!

"},{"location":"home/gotchas/","title":"Bloqade Gotchas: Common Mistakes in Using Bloqade","text":"

It is tempting when coming from different quantum SDKs and frameworks to apply the same pattern of thought to Bloqade. However, a lot of practices from those prior tools end up being anti-patterns in Bloqade. While you can use those patterns and they can still work, it ends up causing you the developer to write unnecessarily verbose, complex, and hard-to-read code as well as preventing you from reaping the full benefits of what Bloqade has to offer.

This page is dedicated to cataloguing those anti-patterns and what you can do instead to maximize the benefit Bloqade can offer you.

"},{"location":"home/gotchas/#redefining-lattices-and-common-atom-arrangements","title":"Redefining Lattices and Common Atom Arrangements","text":"

You might be tempted to define lattice-based geometries through the following means:

from bloqade import start\n\nspacing = 4.0\ngeometry = start.add_positions(\n    [(i * spacing, j * spacing) for i in range(4) for j in range(4)]\n)\n

This is quite redundant and verbose, especially considering Bloqade offers a large number of pre-defined lattices you can customize the spacing of in bloqade.atom_arrangement. In the code above, we're just defining a 4x4 square lattice of atoms with 4.0 micrometers of spacing between them. This can be expressed as follows

from bloqade.analog.atom_arrangement import Square\n\nspacing = 4.0\ngeometry = Square(4, lattice_spacing = spacing)\n
"},{"location":"home/gotchas/#copying-a-program-to-create-new-ones","title":"Copying a Program to create New Ones","text":"

Many gate-based SDKs rely on having a mutable object representing your circuit. This means if you want to build on top of some base circuit without mutating it, you have to copy it:

import copy\n\nbase_circuit = qubits.x(0)....\n# make copy of base circuit\ncustom_circuit_1 = copy(base_circuit)\n# build on top of copy of base circuit\ncustom_circuit_1.x(0).z(5)...\n# create a new circuit by copying the base again\ncustom_circuit_2 = copy(base_circuit)\n# build on top of that copy again\ncustom_circuit_2.y(5).cz(0,2)...\n

In Bloqade Python this is unnecessary because at every step of your program an immutable object is returned which means you can save it and not have to worry about mutating any internal state.

from bloqade import start\nbase_program = start.add_position((0,0)).rydberg.rabi.amplitude.uniform\n# Just recycle your base program! No `copy` needed!\nnew_program_1 = base_program.constant(duration=5.0, value=5.0)\nnew_program_2 = base_program.piecewise_linear(\n    durations=[5.0], values = [0.0, 5.0]\n)\n
"},{"location":"home/gotchas/#creating-new-programs-instead-of-using-batch_assign","title":"Creating New Programs Instead of Using .batch_assign","text":"

If you have a set of parameters you'd like to test your program on versus a single parameter, don't generate a new program for each value:

rabi_values = [2.0, 4.7, 6.1]\nprograms_with_different_rabi_values = []\n\nfor rabi_value in rabi_values:\n    program = start.add_position((0, 0)).rydberg.rabi.amplitude.uniform.constant(\n        duration=5.0, value=rabi_value\n    )\n    programs_with_different_rabi_values.append(program)\n\nresults = []\n\nfor program in programs_with_different_rabi_values:\n    result = program.bloqade.python().run(100)\n    results.append(result)\n

Instead take advantage of the fact Bloqade has facilities specifically designed to make trying out multiple values in your program without needing to make individual copies via .batch_assign. The results are also automatically handled for you so each value you test has its own set of results, but all collected in a singular dataframe versus the above where you'd have to keep track of individual results.

rabi_values = [2.0, 4.7, 6.1]\n# place a variable for the Rabi Value and then batch assign values to it\nprogram_with_rabi_values = start.add_position(\n    0, 0\n).rydberg.rabi.amplitude.uniform.constant(duration=5.0, value=\"rabi_value\")\nprogram_with_assignments = program_with_rabi_values.batch_assign(\n    rabi_value=rabi_values\n)\n\n# get your results in one dataframe versus having to keep track of a\n# bunch of individual programs and their individual results\nbatch = program_with_assignments.bloqade.python().run(100)\nresults_dataframe = batch.report().dataframe\n
"},{"location":"home/migration/","title":"Migrating to Bloqade Analog","text":""},{"location":"home/migration/#introduction","title":"Introduction","text":"

In order to make room for more features inside the Bloqade ecosystem, we have created a new package to take the place of the old bloqade package. The new package is called bloqade-analog. The old package bloqade will house a namespace package for other features such as our new Bloqade Digital package with support for circuit-based quantum computers!

"},{"location":"home/migration/#installation","title":"Installation","text":"

You can install the package with pip in your Python environment of choice via:

pip install bloqade-analog\n
"},{"location":"home/migration/#migration","title":"Migration","text":"

The new package is a drop-in replacement for the old one. You can simply replace import bloqade with import bloqade.analog or from bloqade.analog import ... in your code. Everything else should work as before.

"},{"location":"home/migration/#example","title":"Example","text":"

lets say your header of your python script looks like this:

from bloqade import var\nfrom bloqade.atom_arrangement import Square\n...\n
You can simply replace it with:

from bloqade.analog import var\nfrom bloqade.analog.atom_arrangement import Square\n...\n
"},{"location":"home/migration/#migrating-old-bloqade-json-files","title":"Migrating old bloqade json files","text":"

If you have old bloqade json files, you will not be able to directly deserialize them anymore because of the package restructuring. Howver we have provided some tools to migrate those JSON files to be compatible with bloqade-analog. You can do this by running the following command in the command line for a single file:

python -m bloqade.analog.migrate <path_to_old_json_file>\n
This will create a new file with the same name as the old file, but with _analog appended to the end of the filename. For example, if you have a file called my_bloqade.json, the new file will be called my_bloqade_analog.json. You can then use load to deserialize this file with the bloqade-analog package.

Another option is to use the migration tool in a python script:

from bloqade.analog.migrate import migrate\n\n # set the indent level for the output file\nindent: int = ...\n# set to True if you want to overwrite the old file, otherwise the new file will be created with -analog appended to the end of the filename\noverwrite: bool = ...\nf\nor filename in [\"file1.json\", \"file2.json\", ...]:\n    migrate(filename, indent=indent, overwrite=overwrite)\n
This will migrate all the files in the list to the new format.

"},{"location":"home/migration/#having-trouble-comments-or-concerns","title":"Having trouble, comments, or concerns?","text":"

Please open an issue on our GitHub

"},{"location":"home/quick_start/","title":"Quick Start","text":"

All the sections below are self-contained, you can click on the links in the Table of Contents to read the relevant parts.

"},{"location":"home/quick_start/#navigating-the-bloqade-api","title":"Navigating the Bloqade API","text":"

As you develop your Bloqade program, you are expected to rely on pop-up \"hints\" provided in your development environment to help you determine what the next part of your program should be.

"},{"location":"home/quick_start/#vs-code","title":"VS Code","text":"

In VS Code this is automatic, just type the . and see what options pop up:

"},{"location":"home/quick_start/#jetbrains-pycharm","title":"JetBrains PyCharm","text":"

The same goes for JetBrains PyCharm:

"},{"location":"home/quick_start/#jupyter-notebook","title":"Jupyter Notebook","text":"

In a Jupyter Notebook you'll need to type . and then hit tab for the hints to appear:

"},{"location":"home/quick_start/#ipython","title":"IPython","text":"

The same goes for IPython:

"},{"location":"home/quick_start/#defining-atom-geometry","title":"Defining Atom Geometry","text":"

You can import pre-defined geometries based on Bravais lattices from bloqade.atom_arrangement. You may also specify a lattice spacing which dictates the spacing between the atoms as well as the number of atom sites in a certain direction.

from bloqade.analog.atom_arrangement import Square, Kagome\n\nsimple_geometry = Square(2, 4, lattice_spacing = 4.0)\nmore_complex_geometry = Kagome(2, 2, lattice_spacing = 2.0)\n

You can easily visualize your geometries as well with .show():

more_complex_geometry.show()\n

You can also add positions to a pre-defined geometry:

from bloqade.analog.atom_arrangement import Square\n\nbase_geometry = Square(2)\ngeometry_with_my_positions = base_geometry.add_position([(10,10), (20,20)])\n

As well as apply defects via .apply_defect_density. In the example below we apply a defect with a probability of 0.2:

from bloqade.analog.atom_arrangement import Square, Kagome\n\nmore_complex_geometry = Kagome(2, 2, lattice_spacing = 2.0)\ndefective_geometry = more_complex_geometry.apply_defect_density(0.2)\n

Or if you want to completely roll out your own atom geometry from scratch just use add_position by itself:

from bloqade import start\n\nmy_geometry = start.add_position([(1,2), (3,4), (5,6)])\n
"},{"location":"home/quick_start/#building-waveforms","title":"Building Waveforms","text":"

After you've defined a geometry you:

  • Specify which level coupling to drive: rydberg or hyperfine
  • Specify detuning, rabi.amplitude or rabi.phase
  • Specify the spatial modulation

Which then leads you to the ability to specify a waveform of interest and begin constructing your pulse sequence. In the example below, we target the ground-Rydberg level coupling to drive with uniform spatial modulation for the Rabi amplitude. Our waveform is a piecewise linear one which ramps from \\(0\\) to \\(5 \\,\\text{rad/us}\\), holds that value for \\(1 \\,\\text{us}\\) and then ramps back down to \\(0 \\,\\text{rad/us}\\).

from bloqade import start\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nwaveform_applied = (\n    target_rabi_amplitude\n    .piecewise_linear(durations = [0.06, 1, 0.06], values = [0, 5, 5, 0])\n)\n

You aren't restricted to just piecewise linear waveforms however, you can also specify:

  • linear - Define a transition from one value to another over a duration
  • constant - Define a fixed value over a duration
  • piecewise_constant - Define a step-wise function with specific durations for each step
  • poly - Define a polynomial waveform using coefficients over a duration
"},{"location":"home/quick_start/#arbitrary-functions-as-waveforms","title":"Arbitrary Functions as Waveforms","text":"

For more complex waveforms it may provide to be tedious trying to chain together a large number of piecewise_constant or piecewise_linear methods and instead easier to just define the waveform as a function of time.

Bloqade lets you easily plug in an arbitrary function with .fn:

from bloqade import start\nfrom math import sin\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\n\ndef custom_waveform(t):\n    return 2.0 * sin(t)\n\ncustom_waveform_applied = (\n    target_rabi_amplitude\n    .fn(custom_waveform, duration = 3.0)\n)\n

In this form you can immediately emulate it if you'd like but to run this on hardware you need to discretize it. The waveform on hardware has to either be:

  • Piecewise linear for Rabi amplitude and detuning terms of the Hamiltonian
  • Piecewise constant for the Phase term of the Hamiltonian

Bloqade can automatically perform this conversion with sample(), all you need to do is specify the kind of interpolation and the size of the discretization step in time. Below we set the step duration to be \\(0.05 \\,\\text{us}\\) with \"linear\" interpolation to give us a resulting piecewise linear waveform.

custom_discretized_waveform_applied = (\n    target_rabi_amplitude\n    .fn(custom_waveform, duration = 3.0)\n    .sample(0.05, \"linear\")\n)\n

Note

Programs that have custom functions as waveforms are not fully serializable. This means that when you are saving and reloading results, the original embedded program will be missing that custom waveform. You will still be able to analyze the saved results!

"},{"location":"home/quick_start/#slicing-and-recording-waveforms","title":"Slicing and Recording Waveforms","text":"

When you conduct parameter sweeps with your program, you may want to sweep over your program across time. This will require \"slicing\" your waveforms, where you define the waveform of interest and then, using a variable with .slice, indicate the times at which the waveform duration should be cut short.

In the example below we define a simple piecewise linear waveform but slice it starting from a time duration of \\(0 \\,\\text{us}\\) to values between \\(1\\) to \\(2 \\,\\text{us}\\).

from bloqade import start\nimport numpy as np\n\nsliced_program = (\n    start.add_position((0, 0))\n    .rydberg.rabi.amplitude.uniform.piecewise_linear(\n        durations=[0.5, 2.5, 0.5], values=[0, 3.0, 3.0, 0]\n    ).slice(start=0, stop=\"run_time\")\n)\n\nrun_times = np.linspace(1.0, 2.0, 10)\nvars_assigned_program = sliced_program.batch_assign(run_time=run_times)\n

This program will run fine in emulation but due to hardware constraints certain waveforms (such as those targeting the Rabi Amplitude), the waveform needs to start and end at \\(0 \\,\\text{rad}/\\text{us}\\). Thus, there needs to be a way to slice our waveform but also add an end component to that waveform. .record in Bloqade lets you literally \"record\" the value at the end of a .slice and then use it to construct further parts of the waveform.

In the program below the waveform is still sliced but with the help of .record a linear segment that pulls the waveform down to \\(0.0 \\,\\text{rad}/\\text{us}\\) from whatever its current value at the slice is in \\(0.7 \\,\\text{us}\\) is added.

from bloqade import start\nimport numpy as np\n\nsliced_program = (\n    start.add_position((0, 0))\n    .rydberg.rabi.amplitude.uniform.piecewise_linear(\n        durations=[0.5, 2.5, 0.5], values=[0, 3.0, 3.0, 0]\n    ).slice(start=0, stop=\"run_time\")\n    .record(\"waveform_value\")\n    .linear(\"rabi_value\", 0.0, 0.7)\n)\n\nrun_times = np.linspace(1.0, 2.0, 10)\nvars_assigned_program = sliced_program.batch_assign(run_time=run_times)\n
"},{"location":"home/quick_start/#waveforms-with-no-geometry","title":"Waveforms with No Geometry","text":"

If you have multiple atom geometries you'd like to apply a pulse sequence to or you simply don't want to worry about what atom geometry to start with, you can just build straight off of start:

from bloqade import start\n\npulse_sequence = (\n    start\n    .rydberg.rabi.amplitude.uniform\n    .constant(value=1.0, duration=1.0)\n    .parse_sequence()\n)\n

You can visualize your sequence as well with .show():

pulse_sequence.show()\n

And when you're content with it you just .apply() it on the geometries of your choice:

from bloqade.analog.atom_arrangement import Honeycomb, Kagome\n\ngeometry_1 = Honeycomb(2, lattice_spacing = 6.0)\ngeometry_2 = Kagome(2, lattice_spacing = 6.0)\n\nprogram_1  = geometry_1.apply(pulse_sequence)\nprogram_2  = geometry_2.apply(pulse_sequence)\n
"},{"location":"home/quick_start/#emulation","title":"Emulation","text":"

When you've completed the definition of your program you can use Bloqade's own emulator to get results. The emulation performs the time evolution of the analog Rydberg Hamiltonian. Here we say we want to the program to be run and measurements obtained 1000 times.

results = your_program.bloqade.python().run(1000)\n

Note

If your atoms are particularly close together or the ODE solver gives you the following message:

RuntimeError: DOP853/DOPRI5: Problem is probably stiff (interrupted).\n

In which case you will need to specify the interaction_picture=True argument:

results = your_program.bloqade.python().run(1000, interaction_picture=True)\n
"},{"location":"home/quick_start/#submitting-to-hardware","title":"Submitting to Hardware","text":"

To submit your program to hardware ensure you have your AWS Braket credentials loaded. You will need to use the AWS CLI to do this.

Then it's just a matter of selecting the Aquila on Braket backend. Before going any further Bloqade provides two options for running your program on actual hardware:

  • Using .run is blocking, meaning you will not be able to execute anything else while Bloqade waits for results
  • Using .run_async lets you submit to hardware and continue any further execution, while also letting you query the status of your program in the queue.

In the example below we use .run_async to specify the program should be run and measurements obtained 1000 times.

async_results = your_program.braket.aquila().run_async(1000)\n

We can see the status of our program via:

async_results.fetch()\n
Which gives us the Task ID, a unique identifier for the task as well as the status of the task. In the example below the task is Enqueued meaning it has been successfully created and is awaiting execution on the cloud. When the task is actually running on hardware, the status will change to Running.
                                             task ID    status  shots\n0  arn:aws:braket:us-east-1:XXXXXXXXXXXX:quantum-...  Enqueued    100\n

"},{"location":"home/quick_start/#analyzing-results","title":"Analyzing Results","text":"

When you've retrieved your results from either emulation or hardware you can generate a .report():

report = results.report()\n

For the examples below we analyze the results of a two atom program.

The report contains useful information such as:

  • The raw bitstrings measured per each execution of the program

    report.bitstrings()\n
    [array([[1, 1],\n        [1, 1],\n        [1, 1],\n        ...,\n        [1, 1],\n        [1, 1],\n        [1, 0]], dtype=int8)]\n

  • The number of times each unique bitstring occurred:

    report.counts()\n
    [OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n

  • The Rydberg Density for each atom

    report.rydberg_densities()\n
                     0      1\ntask_number\n0            0.053  0.054\n

And can also provide useful visual information such as the state of your atoms and the bitstring distribution via:

report.show()\n

"},{"location":"home/quick_start/#parameter-sweeps","title":"Parameter Sweeps","text":"

You can easily do parameter sweeps in emulation and on Aquila with variables. Bloqade automatically detects strings in your program as variables that you can later assign singular or multiple values to.

In the example below, we define a program with a singular variable that controls the amplitude of the waveform.

from bloqade import start\n\nrabi_oscillations_program = (\n    start.add_position((0, 0))\n    .rydberg.rabi.amplitude.uniform.piecewise_linear(\n        durations=[0.06, 3, 0.06],\n        values=[0, \"rabi_amplitude\", \"rabi_amplitude\", 0]\n    )\n)\n

We can assign a single fixed value to the variable:

single_value_assignment = rabi_oscillations_program.assign(rabi_amplitude=3.5)\n

Or, to perform a sweep, we use .batch_assign:

import numpy as np\nrabi_amplitudes = np.linspace(1.0, 2.0, 20)\n\nmultiple_value_assignment = rabi_oscillations_program.batch_assign(rabi_amplitude=rabi_amplitudes)\n

This will actually create multiple versions of the program internally, with each program assigned a fixed value from the sweep. Bloqade will automatically handle the compilation of results from these multiple programs in order, meaning there is no major departure from what you saw in analyzing the results of your program.

You can also delay assignment of a value to a variable by first declaring it in .args() and then passing a value when you call run:

delayed_assignment_program = rabi_oscillations_program.args([\"rabi_amplitude\"])\nresults = delayed_assignment_program.bloqade.python().run(100, args=(1.0,))\n

You can alternatively treat the program as a callable after using .args() (note the inverted order of arguments in the call!):

delayed_assignment_program = rabi_oscillations_program.args([\"rabi_amplitude\"])\ncallable_program = delayed_assignment_program.bloqade.python()\nresults = callable_program(1.0, shots=100)\n

Variables aren't just restricted to having values assigned to them, you can also symbolically manipulate them!

"},{"location":"home/quick_start/#symbolic-parameters","title":"Symbolic Parameters","text":"

Variables in Bloqade can also be symbolically manipulated, giving you even more flexibility when you construct your program.

In the example below, we externally declare a variable my_var that then has some arithmetic done on it to allow it to have a different value in a later part of the program:

from bloqade import start, var\n\nmy_var = var(\"my_variable\")\nwaveform_durations = [0.6, 1.0, 0.6]\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nrabi_waveform = (\n    target_rabi_amplitude\n    .piecewise_linear(durations=waveform_durations,\n                      values=[0.0, my_var, my_var, 0.0])\n)\ntarget_detuning = rabi_waveform.detuning.uniform\ndetuning_waveform = (\n    target_detuning\n    .piecewise_linear(durations=waveform_durations,\n                      values=[my_var-1.0, my_var*0.5, my_var/2, my_var+1.0 ])\n)\n

You still perform variable assignment just like you normally would:

program = detuning_waveform.assign(my_variable=1.0)\n

You can also use Python's built-in sum if you want the sum of multiple variables as a value in your program. This is quite useful when it comes to needing to indicate a full duration for a waveform that doesn't need to be split up:

from bloqade import start, var\n\nvariable_durations = var([\"a\", \"b\", \"c\"])\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nrabi_waveform = (\n    target_rabi_amplitude\n    .piecewise_linear(durations=variable_durations,\n                      values=[0.0, 1.5, 1.5, 0.0])\n)\ntarget_detuning = rabi_waveform.detuning.uniform\ndetuning_waveform = (\n    target_detuning\n    .constant(duration=sum(variable_durations),\n              value=16.2)\n)\n
We later assign values and Bloqade will automatically handle the summation:

program = detuning_waveform.assign(a=0.5, b=1.2, c=0.5)\n
"},{"location":"home/quick_start/#saving-and-loading-results","title":"Saving and Loading Results","text":"

You can save your results in JSON format using Bloqade's save function:

from bloqade import start, save\n\nyour_program = ...\nemulation_results = your_program.bloqade.python().run(100)\nhardware_results = your_program.braket.aquila.run_async(100)\n\nsave(emulation_results, \"emulation_results.json\")\nsave(hardware_results, \"hardware_results.json\")\n

And later reload them into Python using the load function:

from bloqade import load\nemulation_results = load(\"emulation_results.json\")\nhardware_results = load(\"hardware_results.json\")\n
"},{"location":"home/submission/","title":"Submission","text":"

This page is a work in progress!

"},{"location":"home/visualization/","title":"Visualization","text":"

This page is a work in progress!

"},{"location":"home/waveforms/","title":"Waveforms","text":"

This page is a work in progress!

"},{"location":"reference/hardware-capabilities/","title":"Hardware Capabilities","text":"

During program development, it can be quite handy to know what true hardware capabilities are and incorporate that information programmaticaly. Bloqade offers the ability to do this via get_capabilities().

"},{"location":"reference/hardware-capabilities/#programmatic-access","title":"Programmatic Access","text":"

get_capabilities() (importable directly from bloqade) returns a QuEraCapabilities object. This object contains all the hardware constraints in Decimal format for the Aquila machine, our publically-accessible QPU on AWS Braket.

An example of using get_capabilities() is presented below:

from bloqade import get_capabilities, piecewise_linear\n\n# get capabilities for Aquila\naquila_capabilities = get_capabilities()\n\n# obtain maximum Rabi frequency as Decimal\nmax_rabi = aquila_capabilities.capabilities.rydberg.global_.rabi_frequency_max\n\n# use that value in constructing a neat Rabi waveform\nrabi_wf = piecewise_linear(durations = [0.5, 1.0, 0.5], values = [0, max_rabi, max_rabi, 0])\n

The attribute names for each value have been provided below but will require you to provide the proper prefix like in the example above (e.g. the maximum number of qubits lives under the number_qubits_max attribute which can be navigated to via *your_QuEra_Capabilities_Object*.lattice.number_qubits_max).

"},{"location":"reference/hardware-capabilities/#aquila-capabilities","title":"Aquila Capabilities","text":""},{"location":"reference/hardware-capabilities/#task","title":"Task","text":"
  • Use prefix your_capabilities_object.capabilities.task for:
    • minimum number of shots
    • maximum number of shots
Capability Attribute Value Minimum Number of Shots number_shots_min 1 Maximum Number of Shots number_shots_max 1000"},{"location":"reference/hardware-capabilities/#lattice-geometry","title":"Lattice Geometry","text":"
  • Use prefix your_capabilities_object.capabilities.lattice for:
    • maximum number of qubits
  • Use prefix your_capabilities_object.capabilities.lattice.area for:
    • maximum lattice area width
    • maximum lattice area height
  • Use prefix your_capabilities_object.capabilities.lattice.geometry for:
    • maximum number of sites
    • position resolution
    • minimum radial spacing
    • minimum vertical spacing
Capability Attribute Value Maximum Number of Qubits number_qubits_max 256 Maximum Lattice Area Width width 75.0 \u00b5m Maximum Lattice Area Height height 76.0 \u00b5m Minimum Radial Spacing between Qubits spacing_radial_min 4.0 \u00b5m Minimum Vertical Spacing between Qubits spacing_vertical_min 4.0 \u00b5m Position Resolution position_resolution 0.1 \u00b5m Maximum Number of Sites number_sites_max 256"},{"location":"reference/hardware-capabilities/#global-rydberg-values","title":"Global Rydberg Values","text":"
  • Use prefix your_capabilities_object.capabilities.rydberg for:
    • C6 Coefficient
  • Use prefix your_capabilities_object.capabilities.rydberg.global_ for:
    • Everything else related to global (applied to all atom) capabilities
Capability Attribute Value Rydberg Interaction Constant c6_coefficient 5.42\u00d710\u2076 rad/\u03bcs \u00d7 \u00b5m\u2076 Minimum Rabi Frequency rabi_frequency_min 0.00 rad/\u03bcs Maximum Rabi Frequency rabi_frequency_max 15.8 rad/\u03bcs Rabi Frequency Resolution rabi_frequency_resolution 0.0004 rad/\u03bcs Maximum Rabi Frequency Slew Rate rabi_frequency_slew_rate_max 250.0 rad/\u00b5s\u00b2 Minimum Detuning detuning_min -125.0 rad/\u03bcs Maximum Detuning detuning_max 125.0 rad/\u03bcs Detuning Resolution detuning_resolution 2.0\u00d710\u207b\u2077 rad/\u03bcs Maximum Detuning Slew Rate detuning_slew_rate_max 2500.0 rad/\u00b5s\u00b2 Minimum Phase phase_min -99.0 rad Maximum Phase phase_max 99.0 rad Phase Resolution phase_resolution 5.0\u00d710\u207b\u2077 rad Minimum Time time_min 0.0 \u00b5s Maximum Time time_max 4.0 \u00b5s Time Resolution time_resolution 0.001 \u00b5s Minimum \u0394t time_delta_min 0.05 \u00b5s"},{"location":"reference/hardware-capabilities/#local-detuning-values","title":"Local Detuning Values","text":"
  • Use prefix your_capabilities_object.capabilities.rydberg.local for the following values:
Capability Attribute Value Maximum Detuning detuning_max 125.0 rad/\u03bcs Minimum Detuning detuning_min 0 rad/\u03bcs Maximum Detuning Slew Rate detuning_slew_rate_max 1256.0 rad/\u00b5s\u00b2 Maximum Number of Local Detuning Sites number_local_detuning_sites 200 Maximum Site Coefficient site_coefficient_max 1.0 Minimum Site Coefficient site_ceofficient_min 0.0 Minimum Radial Spacing spacing_radial_min 5 \u00b5m Minimum \u0394t time_delta_min 0.05 \u03bcs Time Resolution time_resolution 0.001 \u00b5s"},{"location":"reference/overview/","title":"Builder Overview","text":"

You may have noticed from the Getting Started and Tutorials that Bloqade uses this interesting, dot-intensive syntax.

from bloqade import start\n\nprog = start.add_position((0,0)).rydberg.rabi.amplitude.uniform.constant(1,1)\n
Exhibit A: Lots of Dots

In fact, it might look remniscent of what you see in some gate-based Quantum Computing SDKs:

# this is strictly pseudocode\ncircuit = init_qubits(n_qubits)\n# note the dots!\ncircuit.x(0).z(1).cnot(0, 1)...\n

What's the deal with that?

"},{"location":"reference/overview/#syntax-motivations","title":"Syntax Motivations","text":"

We call this syntax the builder or builder syntax and as its name implies, it is designed to let you build programs for Analog Hamiltonian Simulation hardware as easily and as straightforward as possible.

The linear structure implies a natural hierarchy in how you think about targeting the various degrees of freedom (detuning, atom positions, Rabi amplitude, etc.) your program will have. In the beginning you have unrestricted access to all these degrees of freedom but in order to do something useful you need to:

  1. Narrow down and explicitly identify what you want to control
  2. Provide the instructions on how you want to control what your focused on

Context is a strong component of the builder syntax, as you are both actively restricted from doing certain things that can introduce ambiguity based on where you are in your program and repeating the same action in different parts of the program yields different results.

"},{"location":"reference/overview/#visual-guides","title":"Visual Guides","text":"

While we hope the Smart Documentation (the ability to instantly see all your next possible steps and their capabilities in your favorite IDE/IPython) is sufficient to get you where you need to go, we undestand it's particularly beneficial to get a high-level overview of things before diving in.

The Standard Representation is a nice flow chart that gives a high-level overview of the different steps and components in the builder syntax.

"},{"location":"reference/standard/","title":"Build Workflow","text":"
\nflowchart TD\n  ProgramStart([\"start\"])\n\n  Geometry(\"Geometry or Lattice\")\n\n  Coupling[\"Coupling\n  -----------\n  rydberg\n  hyperfine\"]\n\n  Detuning[\"detuning\"]\n  Rabi[\"rabi\"]\n\n  Amplitude[\"amplitude\"]\n  Phase[\"phase\"]\n\n  SpaceModulation(\"SpatialModulation\n  ----------------------\n  uniform\n  scale\n  location\n  \")\n  Waveform{\"Waveform\n  ------------\n  piecewise_linear\n  piecewise_constant\n  constant\n  linear\n  poly\n  fn\n  \"}\n\n  Options([\"Options\n  ---------\n  assign\n  batch_assign\n  args\n  parallelize\n  \"])\n\n  Services([\"Services\n  ----------\n  bloqade\n  quera\n  braket\"])\n\n  QuEraBackends([\"Backends\n  ------------\n  mock\n  cloud_mock\n  aquila\n  device\"])\n\n  BraketBackends([\"Backends\n  ------------\n  aquila\n  local_emulator\"])\n\n  BloqadeBackends([\"Backends\n  ------------\n  python\n  julia\"])\n\n  Execution(\"\n  Execution hardware only\n  -------------------------------\n  run_async()\n\n  Hardware and simulation\n  -------------------------------\n  run()\n  __call__\")\n\n  ProgramStart -->|add_position| Geometry;\n  Geometry --> Coupling;\n  ProgramStart --> Coupling;\n\n  Coupling --> Detuning;\n  Coupling --> Rabi;\n\n  Rabi --> Amplitude;\n  Rabi --> Phase;\n\n  Detuning --> SpaceModulation;\n  Amplitude --> SpaceModulation;\n  Phase --> SpaceModulation;\n\n  SpaceModulation --> Waveform;\n\n  Waveform --> Coupling;\n  Waveform --> Services;\n  Waveform --> Options;\n  Options --> Services;\n\n  Services -->|quera| QuEraBackends;\n  Services -->|braket| BraketBackends;\n  Services -->|bloqade| BloqadeBackends;\n  QuEraBackends --> Execution;\n  BraketBackends --> Execution;\n  BloqadeBackends --> Execution;\n\n  click ProgramStart \"../bloqade/#bloqade.start\";\n  click Geometry \"../bloqade/atom_arrangement/\";\n  click Coupling \"../bloqade/builder/drive/\";\n  click Detuning \"../bloqade/builder/field/#bloqade.builder.field.Detuning\";\n  click Rabi \"../bloqade/builder/field/#bloqade.builder.field.Rabi\";\n  click Amplitude \"../bloqade/builder/field/#bloqade.builder.field.Amplitude\";\n  click Phase \"../bloqade/builder/field/#bloqade.builder.field.Phase\";\n  click SpaceModulation \"../bloqade/builder/spatial/\";\n  click Waveform \"../bloqade/builder/waveform/\";\n  click Options \"../bloqade/builder/pragmas/\";\n  click Services \"../bloqade/builder/backend/\";\n  click QuEraBackends \"../bloqade/builder/backend/quera/#bloqade.builder.backend.quera.QuEraDeviceRoute\";\n  click BraketBackends \"../bloqade/builder/backend/braket/#bloqade.builder.backend.braket.BraketDeviceRoute\";\n  click BloqadeBackends \"../bloqade/builder/backend/bloqade/#bloqade.builder.backend.bloqade.BloqadeBackend\";\n  click Execution \"../bloqade/ir/routine/braket/#bloqade.ir.routine.braket.BraketRoutine\";\n
"},{"location":"reference/bloqade/analog/","title":"Index","text":""},{"location":"reference/bloqade/analog/#bloqade.analog.RB_C6","title":"RB_C6 module-attribute","text":"
RB_C6 = 2 * pi * 862690\n

The C6 constant for the Rydberg Interaction of two Rubidium atoms in units of: rad \u03bcm^6/\u03bcs

"},{"location":"reference/bloqade/analog/#bloqade.analog.start","title":"start module-attribute","text":"
start = ListOfLocations()\n

A Program starting point, alias of empty ListOfLocations.

  • Next possible steps to build your program are:
  • Specify which level coupling to address with:
    • start.rydberg: for Rydberg Level coupling
    • start.hyperfine: for Hyperfine Level coupling
    • LOCKOUT: You cannot add atoms to your geometry after specifying level coupling.
  • continue/start building your geometry with:
    • start.add_position(): to add atom(s) to current register. It will accept:
      • A single coordinate, represented as a tuple (e.g. (5,6)) with a value that can either be:
        • integers: (5,6)
        • floats: (5.1, 2.5)
        • strings (for later variable assignment): (\"x\", \"y\")
        • Scalar objects: (2*cast(\"x\"), 5+cast(\"y\"))
      • A list of coordinates, represented as a list of types mentioned previously.
      • A numpy array with shape (n, 2) where n is the total number of atoms
"},{"location":"reference/bloqade/analog/#bloqade.analog.Literal","title":"Literal","text":"

Bases: Real

"},{"location":"reference/bloqade/analog/#bloqade.analog.Literal.value","title":"value instance-attribute","text":"
value\n

Scalar Literal, which stores a decimaal value instance.

Parameters:

Name Type Description Default value Decimal

decimal value instance

required"},{"location":"reference/bloqade/analog/#bloqade.analog.Variable","title":"Variable","text":"

Bases: Real

Variable, which stores a variable name.

Parameters:

Name Type Description Default name str

variable instance.

required"},{"location":"reference/bloqade/analog/#bloqade.analog.cast","title":"cast","text":"
cast(py)\n
  1. cast Real number (or list/tuple of Real numbers) to Scalar Literal.

  2. cast str (or list/tuple of Real numbers) to Scalar Variable.

Parameters:

Name Type Description Default py Union[str, Real, Tuple[Real], List[Real]]

python object to cast

required

Returns:

Type Description Scalar

Scalar

Source code in src/bloqade/analog/ir/scalar.py
def cast(py) -> \"Scalar\":\n    \"\"\"\n    1. cast Real number (or list/tuple of Real numbers)\n    to [`Scalar Literal`][bloqade.ir.scalar.Literal].\n\n    2. cast str (or list/tuple of Real numbers)\n    to [`Scalar Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str,Real,Tuple[Real],List[Real]]): python object to cast\n\n    Returns:\n        Scalar\n    \"\"\"\n    ret = trycast(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Scalar Literal\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.constant","title":"constant","text":"
constant(duration, value)\n

Create a Constant waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of the Constant waveform.

required value ScalarType

Value of the Constant waveform.s

required

Returns:

Name Type Description Constant Constant

A Constant waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef constant(duration: ScalarType, value: ScalarType) -> Constant:\n    \"\"\"Create a Constant waveform.\n\n    Args:\n        duration (ScalarType): Duration of the Constant waveform.\n        value (ScalarType): Value of the Constant waveform.s\n\n    Returns:\n        Constant: A Constant waveform.\n    \"\"\"\n    return Constant(value, duration)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.dumps","title":"dumps","text":"
dumps(o, use_decimal=True, **json_kwargs)\n

Serialize object to string

Parameters:

Name Type Description Default o Any

the object to serialize

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dumps

{}

Returns:

Name Type Description str str

the serialized object as a string

Source code in src/bloqade/analog/serialize.py
@beartype\ndef dumps(\n    o: Any,\n    use_decimal: bool = True,\n    **json_kwargs,\n) -> str:\n    \"\"\"Serialize object to string\n\n    Args:\n        o (Any): the object to serialize\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dumps\n\n    Returns:\n        str: the serialized object as a string\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    return json.dumps(o, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.get_capabilities","title":"get_capabilities","text":"
get_capabilities(use_experimental=False)\n

Get the device capabilities for Aquila

Parameters:

Name Type Description Default use_experimental bool

Get experimental capabilities instead of standard ones. By default value is False.

False

Returns:

Name Type Description QuEraCapabilities QuEraCapabilities

capabilities object for Aquila device.

Note

Units of time, distance, and energy are microseconds (us), micrometers (um), and rad / us, respectively.

For a comprehensive list of capabilities, see the Hardware Reference page

Source code in src/bloqade/analog/factory.py
def get_capabilities(use_experimental: bool = False) -> \"QuEraCapabilities\":\n    \"\"\"Get the device capabilities for Aquila\n\n    Args:\n        use_experimental (bool): Get experimental capabilities instead of\n            standard ones. By default value is False.\n\n    Returns:\n        QuEraCapabilities: capabilities object for Aquila device.\n\n\n    Note:\n        Units of time, distance, and energy are microseconds (us),\n        micrometers (um), and rad / us, respectively.\n\n        For a comprehensive list of capabilities,\n        see the [Hardware Reference](../../reference/hardware-capabilities.md)\n        page\n    \"\"\"\n\n    from bloqade.analog.submission.capabilities import get_capabilities\n\n    # manually convert to units\n    return get_capabilities(use_experimental=use_experimental).scale_units(\n        Decimal(\"1e6\"), Decimal(\"1e-6\")\n    )\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.linear","title":"linear","text":"
linear(duration, start, stop)\n

Create a Linear waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of linear waveform

required start ScalarType

Starting value of linear waveform

required stop ScalarType

Ending value of linear waveform

required

Returns:

Name Type Description Linear Linear

Linear waveform

Source code in src/bloqade/analog/factory.py
@beartype\ndef linear(duration: ScalarType, start: ScalarType, stop: ScalarType) -> Linear:\n    \"\"\"Create a Linear waveform.\n\n    Args:\n        duration (ScalarType): Duration of linear waveform\n        start (ScalarType): Starting value of linear waveform\n        stop (ScalarType): Ending value of linear waveform\n\n    Returns:\n        Linear: Linear waveform\n    \"\"\"\n    return Linear(start, stop, duration)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.load","title":"load","text":"
load(fp, use_decimal=True, **json_kwargs)\n

Load object from file

Parameters:

Name Type Description Default fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.load

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef load(fp: Union[TextIO, str], use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from file\n\n    Args:\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.load\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    if isinstance(fp, str):\n        with open(fp, \"r\") as f:\n            return json.load(\n                f,\n                object_hook=Serializer.object_hook,\n                use_decimal=use_decimal,\n                **json_kwargs,\n            )\n    else:\n        return json.load(\n            fp,\n            object_hook=Serializer.object_hook,\n            use_decimal=use_decimal,\n            **json_kwargs,\n        )\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.loads","title":"loads","text":"
loads(s, use_decimal=True, **json_kwargs)\n

Load object from string

Parameters:

Name Type Description Default s str

the string to load

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.loads

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef loads(s: str, use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from string\n\n    Args:\n        s (str): the string to load\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.loads\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    return json.loads(\n        s, object_hook=Serializer.object_hook, use_decimal=use_decimal, **json_kwargs\n    )\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.piecewise_constant","title":"piecewise_constant","text":"
piecewise_constant(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise constant waveform from a list of durations and values. The value duration[i] corresponds to the length of time for the i'th segment with a value of values[i].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not the same as the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_constant(\n    durations: List[ScalarType], values: List[ScalarType]\n) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise constant waveform from a list of durations and values. The\n    value `duration[i]` corresponds to the length of time for the i'th segment\n    with a value of `values[i]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not the same as the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n    if len(durations) != len(values):\n        raise ValueError(\n            \"The length of values must be the same as the length of durations\"\n        )\n\n    pwc_wf = None\n    for duration, value in zip(durations, values):\n        if pwc_wf is None:\n            pwc_wf = Constant(value, duration)\n        else:\n            pwc_wf = pwc_wf.append(Constant(value, duration))\n\n    return pwc_wf\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.piecewise_linear","title":"piecewise_linear","text":"
piecewise_linear(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise linear waveform from a list of durations and values. The value duration[i] is of the linear segment between values[i] and values[i+1].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not one greater than the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_linear(durations: List[ScalarType], values: List[ScalarType]) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise linear waveform from a list of durations and values. The\n    value `duration[i]` is of the linear segment between `values[i]` and `values[i+1]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not one greater than the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n\n    if len(durations) + 1 != len(values):\n        raise ValueError(\n            \"The length of values must be one greater than the length of durations\"\n        )\n\n    pwl_wf = None\n    for duration, start, stop in zip(durations, values[:-1], values[1:]):\n        if pwl_wf is None:\n            pwl_wf = Linear(start, stop, duration)\n        else:\n            pwl_wf = pwl_wf.append(Linear(start, stop, duration))\n\n    return pwl_wf\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.rydberg_h","title":"rydberg_h","text":"
rydberg_h(\n    atoms_positions,\n    detuning=None,\n    amplitude=None,\n    phase=None,\n    static_params={},\n    batch_params=[],\n    args=[],\n)\n

Create a rydberg program with uniform detuning, amplitude, and phase.

Parameters:

Name Type Description Default atoms_positions Any

Description of geometry of atoms in system.

required detuning Optional[Waveform]

Waveform for detuning. Defaults to None.

None amplitude Optional[Waveform]

Waveform describing the amplitude of the rabi term. Defaults to None.

None phase Optional[Waveform]

Waveform describing the phase of rabi term. Defaults to None.

None static_params Dict[str, Any]

Define static parameters of your program. Defaults to {}.

{} batch_params Union[List[Dict[str, Any]], Dict[str, Any]]

Parmaters for a batch of tasks. Defaults to [].

[] args List[str]

List of arguments to leave till runtime. Defaults to [].

[]

Returns:

Name Type Description Routine Routine

An object that can be used to dispatch a rydberg program to multiple backends.

Source code in src/bloqade/analog/factory.py
@beartype\ndef rydberg_h(\n    atoms_positions: Any,\n    detuning: Optional[Waveform] = None,\n    amplitude: Optional[Waveform] = None,\n    phase: Optional[Waveform] = None,\n    static_params: Dict[str, Any] = {},\n    batch_params: Union[List[Dict[str, Any]], Dict[str, Any]] = [],\n    args: List[str] = [],\n) -> Routine:\n    \"\"\"Create a rydberg program with uniform detuning, amplitude, and phase.\n\n    Args:\n        atoms_positions (Any): Description of geometry of atoms in system.\n        detuning (Optional[Waveform], optional): Waveform for detuning.\n            Defaults to None.\n        amplitude (Optional[Waveform], optional): Waveform describing the amplitude of\n            the rabi term. Defaults to None.\n        phase (Optional[Waveform], optional): Waveform describing the phase of rabi\n            term. Defaults to None.\n        static_params (Dict[str, Any], optional): Define static parameters of your\n            program. Defaults to {}.\n        batch_params (Union[List[Dict[str, Any]], Dict[str, Any]], optional):\n            Parmaters for a batch of tasks. Defaults to [].\n        args (List[str], optional): List of arguments to leave till runtime.\n            Defaults to [].\n\n    Returns:\n        Routine: An object that can be used to dispatch a rydberg program to\n            multiple backends.\n    \"\"\"\n    from bloqade.analog import start\n    from bloqade.analog.atom_arrangement import AtomArrangement\n\n    if isinstance(atoms_positions, AtomArrangement):\n        prog = atoms_positions\n    else:\n        prog = start.add_position(atoms_positions)\n\n    if detuning is not None:\n        prog = prog.rydberg.detuning.uniform.apply(detuning)\n\n    if amplitude is not None:\n        prog = prog.amplitude.uniform.apply(amplitude)\n\n    if phase is not None:\n        prog = prog.phase.uniform.apply(phase)\n\n    prog = prog.assign(**static_params)\n\n    if isinstance(batch_params, dict):\n        prog = prog.batch_assign(**batch_params)\n    else:\n        prog = prog.batch_assign(batch_params)\n\n    prog = prog.args(args)\n\n    return prog.parse()\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.save","title":"save","text":"
save(o, fp, use_decimal=True, **json_kwargs)\n

Serialize object to file

Parameters:

Name Type Description Default o Any

the object to serialize

required fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dump

{}

Returns:

Type Description None

None

Source code in src/bloqade/analog/serialize.py
@beartype\ndef save(\n    o: Any,\n    fp: Union[TextIO, str],\n    use_decimal=True,\n    **json_kwargs,\n) -> None:\n    \"\"\"Serialize object to file\n\n    Args:\n        o (Any): the object to serialize\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dump\n\n    Returns:\n        None\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    if isinstance(fp, str):\n        with open(fp, \"w\") as f:\n            json.dump(o, f, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n    else:\n        json.dump(o, fp, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.tree_depth","title":"tree_depth","text":"
tree_depth(depth=None)\n

Setting globally maximum depth for tree printing

If depth=None, return current depth. If depth is provided, setting current depth to depth

Parameters:

Name Type Description Default depth int

the user specified depth. Defaults to None.

None

Returns:

Name Type Description int

current updated depth

Source code in src/bloqade/analog/__init__.py
def tree_depth(depth: int = None):\n    \"\"\"Setting globally maximum depth for tree printing\n\n    If `depth=None`, return current depth.\n    If `depth` is provided, setting current depth to `depth`\n\n    Args:\n        depth (int, optional): the user specified depth. Defaults to None.\n\n    Returns:\n        int: current updated depth\n    \"\"\"\n    if depth is not None:\n        _ir.tree_print.MAX_TREE_DEPTH = depth\n    return _ir.tree_print.MAX_TREE_DEPTH\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.var","title":"var","text":"
var(py)\n

cast string (or list/tuple of strings) to Variable.

Parameters:

Name Type Description Default py Union[str, List[str]]

a string or list/tuple of strings

required

Returns:

Type Description Variable

Union[Variable]

Source code in src/bloqade/analog/ir/scalar.py
def var(py: str) -> \"Variable\":\n    \"\"\"cast string (or list/tuple of strings)\n    to [`Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str, List[str]]): a string or list/tuple of strings\n\n    Returns:\n       Union[Variable]\n    \"\"\"\n    ret = tryvar(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Variable\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/atom_arrangement/","title":"Atom arrangement","text":""},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/constants/","title":"Constants","text":""},{"location":"reference/bloqade/analog/constants/#bloqade.analog.constants.RB_C6","title":"RB_C6 module-attribute","text":"
RB_C6 = 2 * pi * 862690\n

The C6 constant for the Rydberg Interaction of two Rubidium atoms in units of: rad \u03bcm^6/\u03bcs

"},{"location":"reference/bloqade/analog/factory/","title":"Factory","text":""},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.constant","title":"constant","text":"
constant(duration, value)\n

Create a Constant waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of the Constant waveform.

required value ScalarType

Value of the Constant waveform.s

required

Returns:

Name Type Description Constant Constant

A Constant waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef constant(duration: ScalarType, value: ScalarType) -> Constant:\n    \"\"\"Create a Constant waveform.\n\n    Args:\n        duration (ScalarType): Duration of the Constant waveform.\n        value (ScalarType): Value of the Constant waveform.s\n\n    Returns:\n        Constant: A Constant waveform.\n    \"\"\"\n    return Constant(value, duration)\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.get_capabilities","title":"get_capabilities","text":"
get_capabilities(use_experimental=False)\n

Get the device capabilities for Aquila

Parameters:

Name Type Description Default use_experimental bool

Get experimental capabilities instead of standard ones. By default value is False.

False

Returns:

Name Type Description QuEraCapabilities QuEraCapabilities

capabilities object for Aquila device.

Note

Units of time, distance, and energy are microseconds (us), micrometers (um), and rad / us, respectively.

For a comprehensive list of capabilities, see the Hardware Reference page

Source code in src/bloqade/analog/factory.py
def get_capabilities(use_experimental: bool = False) -> \"QuEraCapabilities\":\n    \"\"\"Get the device capabilities for Aquila\n\n    Args:\n        use_experimental (bool): Get experimental capabilities instead of\n            standard ones. By default value is False.\n\n    Returns:\n        QuEraCapabilities: capabilities object for Aquila device.\n\n\n    Note:\n        Units of time, distance, and energy are microseconds (us),\n        micrometers (um), and rad / us, respectively.\n\n        For a comprehensive list of capabilities,\n        see the [Hardware Reference](../../reference/hardware-capabilities.md)\n        page\n    \"\"\"\n\n    from bloqade.analog.submission.capabilities import get_capabilities\n\n    # manually convert to units\n    return get_capabilities(use_experimental=use_experimental).scale_units(\n        Decimal(\"1e6\"), Decimal(\"1e-6\")\n    )\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.linear","title":"linear","text":"
linear(duration, start, stop)\n

Create a Linear waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of linear waveform

required start ScalarType

Starting value of linear waveform

required stop ScalarType

Ending value of linear waveform

required

Returns:

Name Type Description Linear Linear

Linear waveform

Source code in src/bloqade/analog/factory.py
@beartype\ndef linear(duration: ScalarType, start: ScalarType, stop: ScalarType) -> Linear:\n    \"\"\"Create a Linear waveform.\n\n    Args:\n        duration (ScalarType): Duration of linear waveform\n        start (ScalarType): Starting value of linear waveform\n        stop (ScalarType): Ending value of linear waveform\n\n    Returns:\n        Linear: Linear waveform\n    \"\"\"\n    return Linear(start, stop, duration)\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.piecewise_constant","title":"piecewise_constant","text":"
piecewise_constant(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise constant waveform from a list of durations and values. The value duration[i] corresponds to the length of time for the i'th segment with a value of values[i].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not the same as the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_constant(\n    durations: List[ScalarType], values: List[ScalarType]\n) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise constant waveform from a list of durations and values. The\n    value `duration[i]` corresponds to the length of time for the i'th segment\n    with a value of `values[i]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not the same as the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n    if len(durations) != len(values):\n        raise ValueError(\n            \"The length of values must be the same as the length of durations\"\n        )\n\n    pwc_wf = None\n    for duration, value in zip(durations, values):\n        if pwc_wf is None:\n            pwc_wf = Constant(value, duration)\n        else:\n            pwc_wf = pwc_wf.append(Constant(value, duration))\n\n    return pwc_wf\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.piecewise_linear","title":"piecewise_linear","text":"
piecewise_linear(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise linear waveform from a list of durations and values. The value duration[i] is of the linear segment between values[i] and values[i+1].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not one greater than the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_linear(durations: List[ScalarType], values: List[ScalarType]) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise linear waveform from a list of durations and values. The\n    value `duration[i]` is of the linear segment between `values[i]` and `values[i+1]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not one greater than the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n\n    if len(durations) + 1 != len(values):\n        raise ValueError(\n            \"The length of values must be one greater than the length of durations\"\n        )\n\n    pwl_wf = None\n    for duration, start, stop in zip(durations, values[:-1], values[1:]):\n        if pwl_wf is None:\n            pwl_wf = Linear(start, stop, duration)\n        else:\n            pwl_wf = pwl_wf.append(Linear(start, stop, duration))\n\n    return pwl_wf\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.rydberg_h","title":"rydberg_h","text":"
rydberg_h(\n    atoms_positions,\n    detuning=None,\n    amplitude=None,\n    phase=None,\n    static_params={},\n    batch_params=[],\n    args=[],\n)\n

Create a rydberg program with uniform detuning, amplitude, and phase.

Parameters:

Name Type Description Default atoms_positions Any

Description of geometry of atoms in system.

required detuning Optional[Waveform]

Waveform for detuning. Defaults to None.

None amplitude Optional[Waveform]

Waveform describing the amplitude of the rabi term. Defaults to None.

None phase Optional[Waveform]

Waveform describing the phase of rabi term. Defaults to None.

None static_params Dict[str, Any]

Define static parameters of your program. Defaults to {}.

{} batch_params Union[List[Dict[str, Any]], Dict[str, Any]]

Parmaters for a batch of tasks. Defaults to [].

[] args List[str]

List of arguments to leave till runtime. Defaults to [].

[]

Returns:

Name Type Description Routine Routine

An object that can be used to dispatch a rydberg program to multiple backends.

Source code in src/bloqade/analog/factory.py
@beartype\ndef rydberg_h(\n    atoms_positions: Any,\n    detuning: Optional[Waveform] = None,\n    amplitude: Optional[Waveform] = None,\n    phase: Optional[Waveform] = None,\n    static_params: Dict[str, Any] = {},\n    batch_params: Union[List[Dict[str, Any]], Dict[str, Any]] = [],\n    args: List[str] = [],\n) -> Routine:\n    \"\"\"Create a rydberg program with uniform detuning, amplitude, and phase.\n\n    Args:\n        atoms_positions (Any): Description of geometry of atoms in system.\n        detuning (Optional[Waveform], optional): Waveform for detuning.\n            Defaults to None.\n        amplitude (Optional[Waveform], optional): Waveform describing the amplitude of\n            the rabi term. Defaults to None.\n        phase (Optional[Waveform], optional): Waveform describing the phase of rabi\n            term. Defaults to None.\n        static_params (Dict[str, Any], optional): Define static parameters of your\n            program. Defaults to {}.\n        batch_params (Union[List[Dict[str, Any]], Dict[str, Any]], optional):\n            Parmaters for a batch of tasks. Defaults to [].\n        args (List[str], optional): List of arguments to leave till runtime.\n            Defaults to [].\n\n    Returns:\n        Routine: An object that can be used to dispatch a rydberg program to\n            multiple backends.\n    \"\"\"\n    from bloqade.analog import start\n    from bloqade.analog.atom_arrangement import AtomArrangement\n\n    if isinstance(atoms_positions, AtomArrangement):\n        prog = atoms_positions\n    else:\n        prog = start.add_position(atoms_positions)\n\n    if detuning is not None:\n        prog = prog.rydberg.detuning.uniform.apply(detuning)\n\n    if amplitude is not None:\n        prog = prog.amplitude.uniform.apply(amplitude)\n\n    if phase is not None:\n        prog = prog.phase.uniform.apply(phase)\n\n    prog = prog.assign(**static_params)\n\n    if isinstance(batch_params, dict):\n        prog = prog.batch_assign(**batch_params)\n    else:\n        prog = prog.batch_assign(batch_params)\n\n    prog = prog.args(args)\n\n    return prog.parse()\n
"},{"location":"reference/bloqade/analog/migrate/","title":"Migrate","text":""},{"location":"reference/bloqade/analog/serialize/","title":"Serialize","text":""},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize._import_submodules","title":"_import_submodules","text":"
_import_submodules(package, recursive=True)\n

Import all submodules of a module, recursively, including subpackages

:param package: package (name or actual module) :type package: str | module :rtype: dict[str, types.ModuleType]

Source code in src/bloqade/analog/serialize.py
def _import_submodules(package, recursive=True):\n    \"\"\"Import all submodules of a module, recursively,\n    including subpackages\n\n    :param package: package (name or actual module)\n    :type package: str | module\n    :rtype: dict[str, types.ModuleType]\n    \"\"\"\n\n    if isinstance(package, str):\n        package = importlib.import_module(package)\n\n    for loader, name, is_pkg in pkgutil.walk_packages(package.__path__):\n        full_name = package.__name__ + \".\" + name\n        try:\n            importlib.import_module(full_name)\n        except ModuleNotFoundError:\n            continue\n        if recursive and is_pkg:\n            _import_submodules(full_name)\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.dumps","title":"dumps","text":"
dumps(o, use_decimal=True, **json_kwargs)\n

Serialize object to string

Parameters:

Name Type Description Default o Any

the object to serialize

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dumps

{}

Returns:

Name Type Description str str

the serialized object as a string

Source code in src/bloqade/analog/serialize.py
@beartype\ndef dumps(\n    o: Any,\n    use_decimal: bool = True,\n    **json_kwargs,\n) -> str:\n    \"\"\"Serialize object to string\n\n    Args:\n        o (Any): the object to serialize\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dumps\n\n    Returns:\n        str: the serialized object as a string\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    return json.dumps(o, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.load","title":"load","text":"
load(fp, use_decimal=True, **json_kwargs)\n

Load object from file

Parameters:

Name Type Description Default fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.load

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef load(fp: Union[TextIO, str], use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from file\n\n    Args:\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.load\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    if isinstance(fp, str):\n        with open(fp, \"r\") as f:\n            return json.load(\n                f,\n                object_hook=Serializer.object_hook,\n                use_decimal=use_decimal,\n                **json_kwargs,\n            )\n    else:\n        return json.load(\n            fp,\n            object_hook=Serializer.object_hook,\n            use_decimal=use_decimal,\n            **json_kwargs,\n        )\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.loads","title":"loads","text":"
loads(s, use_decimal=True, **json_kwargs)\n

Load object from string

Parameters:

Name Type Description Default s str

the string to load

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.loads

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef loads(s: str, use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from string\n\n    Args:\n        s (str): the string to load\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.loads\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    return json.loads(\n        s, object_hook=Serializer.object_hook, use_decimal=use_decimal, **json_kwargs\n    )\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.save","title":"save","text":"
save(o, fp, use_decimal=True, **json_kwargs)\n

Serialize object to file

Parameters:

Name Type Description Default o Any

the object to serialize

required fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dump

{}

Returns:

Type Description None

None

Source code in src/bloqade/analog/serialize.py
@beartype\ndef save(\n    o: Any,\n    fp: Union[TextIO, str],\n    use_decimal=True,\n    **json_kwargs,\n) -> None:\n    \"\"\"Serialize object to file\n\n    Args:\n        o (Any): the object to serialize\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dump\n\n    Returns:\n        None\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    if isinstance(fp, str):\n        with open(fp, \"w\") as f:\n            json.dump(o, f, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n    else:\n        json.dump(o, fp, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/builder/","title":"Index","text":""},{"location":"reference/bloqade/analog/builder/args/","title":"Args","text":""},{"location":"reference/bloqade/analog/builder/assign/","title":"Assign","text":""},{"location":"reference/bloqade/analog/builder/coupling/","title":"Coupling","text":""},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Hyperfine","title":"Hyperfine","text":"
Hyperfine(parent=None)\n

Bases: LevelCoupling

This node represents level coupling between hyperfine states.

Examples:

- To reach the node from the start node:\n\n>>> node = bloqade.start.hyperfine\n>>> type(node)\n<class 'bloqade.builder.coupling.Hyperfine'>\n\n- Hyperfine level coupling has two reachable field nodes:\n\n    - detuning term (See also [`Detuning`][bloqade.builder.field.Detuning])\n    - rabi term (See also [`Rabi`][bloqade.builder.field.Rabi])\n\n>>> hyp_detune = bloqade.start.hyperfine.detuning\n>>> hyp_rabi = bloqade.start.hyperfine.rabi\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Hyperfine.__bloqade_ir__","title":"__bloqade_ir__","text":"
__bloqade_ir__()\n

Generate the intermediate representation (IR) for the Hyperfine level coupling.

Returns:

Name Type Description IR

An intermediate representation of the Hyperfine level coupling sequence.

Note

This method is used internally by the Bloqade framework.

Source code in src/bloqade/analog/builder/coupling.py
def __bloqade_ir__(self):\n    \"\"\"\n    Generate the intermediate representation (IR) for the Hyperfine level coupling.\n\n    Args:\n        None\n\n    Returns:\n        IR: An intermediate representation of the Hyperfine level coupling sequence.\n\n    Raises:\n        None\n\n    Note:\n        This method is used internally by the Bloqade framework.\n    \"\"\"\n    from bloqade.analog.ir.control.sequence import hyperfine\n\n    return hyperfine\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.LevelCoupling","title":"LevelCoupling","text":"
LevelCoupling(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.LevelCoupling.detuning","title":"detuning property","text":"
detuning\n

Specify the Detuning Field of your program. You will be able to specify the spatial modulation afterwards.

Returns:

Type Description Detuning

Detuning: A program node representing the detuning field.

Note

The detuning specifies how off-resonant the laser being applied to the atoms is from the atomic energy transition, driven by the Rabi frequency.

Example:

from bloqade import start\ngeometry = start.add_position((0,0))\ncoupling = geometry.rydberg\ncoupling.detuning\n

  • Next Possible Steps You may continue building your program via:
  • uniform: To address all atoms in the field
  • location(locations, scales): To address atoms at specific locations via indices
  • scale(coeffs): To address all atoms with an individual scale factor
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.LevelCoupling.rabi","title":"rabi property","text":"
rabi\n

Specify the complex-valued Rabi field of your program.

The Rabi field is composed of a real-valued Amplitude and Phase field.

Returns:

Name Type Description Rabi Rabi

A program node representing the Rabi field.

Note

Next possible steps to build your program are creating the RabiAmplitude field and RabiPhase field of the field: - ...rabi.amplitude: To create the Rabi amplitude field - ...rabi.phase: To create the Rabi phase field

"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Rydberg","title":"Rydberg","text":"
Rydberg(parent=None)\n

Bases: LevelCoupling

This node represents level coupling of the Rydberg state.

Examples:

- To reach the node from the start node:\n\n>>> node = bloqade.start.rydberg\n>>> type(node)\n<class 'bloqade.builder.coupling.Rydberg'>\n\n- Rydberg level coupling has two reachable field nodes:\n\n    - detuning term (See also [`Detuning`][bloqade.builder.field.Detuning])\n    - rabi term (See also [`Rabi`][bloqade.builder.field.Rabi])\n\n>>> ryd_detune = bloqade.start.rydberg.detuning\n>>> ryd_rabi = bloqade.start.rydberg.rabi\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Rydberg.__bloqade_ir__","title":"__bloqade_ir__","text":"
__bloqade_ir__()\n

Generate the intermediate representation (IR) for the Rydberg level coupling.

Returns:

Name Type Description IR

An intermediate representation of the Rydberg level coupling sequence.

Note

This method is used internally by the Bloqade framework.

Source code in src/bloqade/analog/builder/coupling.py
def __bloqade_ir__(self):\n    \"\"\"\n    Generate the intermediate representation (IR) for the Rydberg level coupling.\n\n    Args:\n        None\n\n    Returns:\n        IR: An intermediate representation of the Rydberg level coupling sequence.\n\n    Raises:\n        None\n\n    Note:\n        This method is used internally by the Bloqade framework.\n    \"\"\"\n    from bloqade.analog.ir.control.sequence import rydberg\n\n    return rydberg\n
"},{"location":"reference/bloqade/analog/builder/drive/","title":"Drive","text":""},{"location":"reference/bloqade/analog/builder/drive/#bloqade.analog.builder.drive.Drive","title":"Drive","text":""},{"location":"reference/bloqade/analog/builder/drive/#bloqade.analog.builder.drive.Drive.hyperfine","title":"hyperfine property","text":"
hyperfine\n

Address the Hyperfine level coupling in your program.

  • Next possible steps to build your program are specifying the Rabi field or Detuning field.
    • ...hyperfine.rabi: for Rabi field
    • ...hyperfine.detuning: for Detuning field
  • In the absence of a field you the value is set to zero by default.
"},{"location":"reference/bloqade/analog/builder/drive/#bloqade.analog.builder.drive.Drive.rydberg","title":"rydberg property","text":"
rydberg\n

Address the Rydberg level coupling in your program.

  • Next possible steps to build your program are specifying the Rabi field or Detuning field.
    • ...rydberg.rabi: for Rabi field
    • ...rydberg.detuning: for Detuning field
  • In the absence of a field you the value is set to zero by default.
"},{"location":"reference/bloqade/analog/builder/field/","title":"Field","text":""},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Detuning","title":"Detuning","text":"
Detuning(parent=None)\n

Bases: Field

This node represent detuning field of a specified level coupling (rydberg or hyperfine) type.

Examples:

- To specify detuning of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.detuning\n>>> type(node)\n<class 'bloqade.builder.field.Detuning'>\n\n- To specify detuning of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.detuning\n>>> type(node)\n<class 'bloqade.builder.field.Detuning'>\n
Note

This node is a SpatialModulation node. See SpatialModulation for additional options.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field","title":"Field","text":"
Field(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.uniform","title":"uniform property","text":"
uniform\n

Address all atoms as part of defining the spatial modulation component of a drive.

Next steps to build your program include choosing the waveform that will be summed with the spatial modulation to create a drive.

The drive by itself, or the sum of subsequent drives (created by just chaining the construction of drives) will become the field (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.).

  • You can now do:
    • ...uniform.linear(start, stop, duration) : to apply a linear waveform
    • ...uniform.constant(value, duration) : to apply a constant waveform
    • ...uniform.poly([coefficients], duration) : to apply a polynomial waveform
    • ...uniform.apply(wf:bloqade.ir.Waveform): to apply a pre-defined waveform
    • ...uniform.piecewise_linear([durations], [values]): to apply a piecewise linear waveform
    • ...uniform.piecewise_constant([durations], [values]): to apply a piecewise constant waveform
    • ...uniform.fn(f(t,...)): to apply a function as a waveform
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.location","title":"location","text":"
location(labels, scales=None)\n

Address a single atom (or multiple) atoms.

Address a single atom (or multiple) as part of defining the spatial modulation component of a drive. You can specify the atoms to target as a list of labels and a list of scales. The scales are used to multiply the waveform that is applied to the atom. You can also specify a single label and scale to target a single atom.

Next steps to build your program include choosing the waveform that will be summed with the spatial modulation to create a drive.

The drive by itself, or the sum of subsequent drives (created by just chaining the construction of drives) will become the field. (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)

"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.location--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n# to target a single atom with a waveform\n>>> one_location_prog = prog.location(0)\n# to target a single atom with a scale\n>>> one_location_prog = prog.location(0, 0.5)\n# to target multiple atoms with same waveform\n>>> multi_location_prog = prog.location([0, 2])\n# to target multiple atoms with different scales\n>>> multi_location_prog = prog.location([0, 2], [0.5, \"scale\"])\n
  • You can now do:
    • ...location(labels, scales).linear(start, stop, duration) : to apply a linear waveform
    • ...location(labels, scales).constant(value, duration) : to apply a constant waveform
    • ...location(labels, scales).poly([coefficients], duration) : to apply a polynomial waveform
    • ...location(labels, scales).apply(wf:bloqade.ir.Waveform): to apply a pre-defined waveform
    • ...location(labels, scales).piecewise_linear([durations], [values]): to apply a piecewise linear waveform
    • ...location(labels, scales).piecewise_constant([durations], [values]): to apply a piecewise constant waveform
    • ...location(labels, scales).fn(f(t,..)): to apply a function as a waveform
Source code in src/bloqade/analog/builder/field.py
def location(\n    self,\n    labels: Union[List[int], int],\n    scales: Union[List[ScalarType], ScalarType, None] = None,\n) -> \"Location\":\n    \"\"\"Address a single atom (or multiple) atoms.\n\n    Address a single atom (or multiple) as part of defining the spatial\n    modulation component of a drive. You can specify the atoms to target\n    as a list of labels and a list of scales. The scales are used to\n    multiply the waveform that is applied to the atom. You can also specify\n    a single label and scale to target a single atom.\n\n    Next steps to build your program include choosing the waveform that\n    will be summed with the spatial modulation to create a drive.\n\n    The drive by itself, or the sum of subsequent drives (created by just\n    chaining the construction of drives) will become the field.\n    (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n    # to target a single atom with a waveform\n    >>> one_location_prog = prog.location(0)\n    # to target a single atom with a scale\n    >>> one_location_prog = prog.location(0, 0.5)\n    # to target multiple atoms with same waveform\n    >>> multi_location_prog = prog.location([0, 2])\n    # to target multiple atoms with different scales\n    >>> multi_location_prog = prog.location([0, 2], [0.5, \"scale\"])\n    ```\n\n    - You can now do:\n        - `...location(labels, scales).linear(start, stop, duration)` : to apply\n            a linear waveform\n        - `...location(labels, scales).constant(value, duration)` : to apply\n            a constant waveform\n        - `...location(labels, scales).poly([coefficients], duration)` : to apply\n            a polynomial waveform\n        - `...location(labels, scales).apply(wf:bloqade.ir.Waveform)`: to apply\n            a pre-defined waveform\n        - `...location(labels, scales).piecewise_linear([durations], [values])`:\n            to apply\n            a piecewise linear waveform\n        - `...location(labels, scales).piecewise_constant([durations], [values])`:\n            to apply\n            a piecewise constant waveform\n        - `...location(labels, scales).fn(f(t,..))`: to apply a function as a\n            waveform\n\n    \"\"\"\n    return self._location(labels, scales)\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.scale","title":"scale","text":"
scale(coeffs)\n

Address all the atoms scaling each atom with an element of the list or define a variable name for the scale list to be assigned later by defining a name and using assign or batch_assign later.

Next steps to build your program include choosing the waveform that will be summed with the spatial modulation to create a drive.

The drive by itself, or the sum of subsequent drives (created by just chaining the construction of drives) will become the field (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)

"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.scale--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n\n# assign a literal list of values to scale each atom\n>>> one_location_prog = prog.scale([0.1, 0.2, 0.3])\n# assign a variable name to be assigned later\n>>> one_location_prog = prog.scale(\"a\")\n# \"a\" can be assigned in the END of the program during variable assignment\n# using a list of values, indicating the scaling for each atom\n>>> single_assignment = ...assign(a = [0.1, 0.2, 0.3])\n# a list of lists, indicating a set of atoms should be targeted\n# for each task in a batch.\n>>> batch_assignment = ...batch_assign(a = [list_1, list_2, list_3,...])\n
  • You can now do:
    • ...scale(coeffs).linear(start, stop, duration) : to apply a linear waveform
    • ...scale(coeffs).constant(value, duration) : to apply a constant waveform
    • ...scale(coeffs).poly([coefficients], duration) : to apply a polynomial waveform
    • ...scale(coeffs).apply(wf:bloqade.ir.Waveform): to apply a pre-defined waveform
    • ...scale(coeffs).piecewise_linear(durations, values): to apply a piecewise linear waveform
    • ...scale(coeffs).piecewise_constant(durations, values): to apply a piecewise constant waveform
    • ...scale(coeffs).fn(f(t,..)): to apply a function as a waveform
Source code in src/bloqade/analog/builder/field.py
def scale(self, coeffs: Union[str, List[ScalarType]]) -> \"Scale\":\n    \"\"\"\n    Address all the atoms scaling each atom with an element of the list\n    or define a variable name for the scale list to be assigned later by\n    defining a `name` and using `assign` or `batch_assign` later.\n\n    Next steps to build your program include choosing the waveform that\n    will be summed with the spatial modulation to create a drive.\n\n    The drive by itself, or the sum of subsequent drives (created by just\n    chaining the construction of drives) will become the field\n    (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n\n    # assign a literal list of values to scale each atom\n    >>> one_location_prog = prog.scale([0.1, 0.2, 0.3])\n    # assign a variable name to be assigned later\n    >>> one_location_prog = prog.scale(\"a\")\n    # \"a\" can be assigned in the END of the program during variable assignment\n    # using a list of values, indicating the scaling for each atom\n    >>> single_assignment = ...assign(a = [0.1, 0.2, 0.3])\n    # a list of lists, indicating a set of atoms should be targeted\n    # for each task in a batch.\n    >>> batch_assignment = ...batch_assign(a = [list_1, list_2, list_3,...])\n\n    ```\n\n    - You can now do:\n        - `...scale(coeffs).linear(start, stop, duration)` : to apply\n            a linear waveform\n        - `...scale(coeffs).constant(value, duration)` : to apply\n            a constant waveform\n        - `...scale(coeffs).poly([coefficients], duration)` : to apply\n            a polynomial waveform\n        - `...scale(coeffs).apply(wf:bloqade.ir.Waveform)`: to apply\n            a pre-defined waveform\n        - `...scale(coeffs).piecewise_linear(durations, values)`:  to\n            apply a piecewise linear waveform\n        - `...scale(coeffs).piecewise_constant(durations, values)`: to\n            apply a piecewise constant waveform\n        - `...scale(coeffs).fn(f(t,..))`: to apply a function as a waveform\n\n    \"\"\"\n    from bloqade.analog.builder.spatial import Scale\n\n    return Scale(coeffs, self)\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Rabi","title":"Rabi","text":"
Rabi(parent=None)\n

Bases: Builder

This node represent rabi field of a specified level coupling (rydberg or hyperfine) type.

Examples:

- To specify rabi of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.rabi\n<class 'bloqade.builder.field.Rabi'>\n\n- To specify rabi of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.rabi\n>>> type(node)\n<class 'bloqade.builder.field.Rabi'>\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Rabi.amplitude","title":"amplitude property","text":"
amplitude\n

Specify the real-valued Rabi Amplitude field.

Next steps to build your program focus on specifying a spatial modulation.

The spatial modulation, when coupled with a waveform, completes the specification of a \"Drive\". One or more drives can be summed together automatically to create a field such as the Rabi Amplitude here.

  • You can now
    • ...amplitude.uniform: Address all atoms in the field
    • ...amplitude.location(...): Scale atoms by their indices
    • ...amplitude.scale(...): Scale each atom with a value from a list or assign a variable name to be assigned later
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Rabi.phase","title":"phase property","text":"
phase\n

Specify the real-valued Rabi Phase field.

Next steps to build your program focus on specifying a spatial modulation.

The spatial modulation, when coupled with a waveform, completes the specification of a \"Drive\". One or more drives can be summed together automatically to create a field such as the Rabi Phase here.

  • You can now
    • ...amplitude.uniform: Address all atoms in the field
    • ...amplitude.location(...): Scale atoms by their indices
    • ...amplitude.scale(...): Scale each atom with a value from a list or assign a variable name to be assigned later
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.RabiAmplitude","title":"RabiAmplitude","text":"
RabiAmplitude(parent=None)\n

Bases: Field

This node represent amplitude of a rabi field.

Examples:

- To specify rabi amplitude of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.rabi.amplitude\n>>> type(node)\n<class 'bloqade.builder.field.Amplitude'>\n\n- To specify rabi amplitude of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.rabi.amplitude\n>>> type(node)\n<class 'bloqade.builder.field.Amplitude'>\n
Note

This node is a SpatialModulation node. See SpatialModulation for additional options.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.RabiPhase","title":"RabiPhase","text":"
RabiPhase(parent=None)\n

Bases: Field

This node represent phase of a rabi field.

Examples:

- To specify rabi phase of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.rabi.phase\n>>> type(node)\n<class 'bloqade.builder.field.Phase'>\n\n- To specify rabi phase of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.rabi.phase\n>>> type(node)\n<class 'bloqade.builder.field.Phase'>\n
Note

This node is a SpatialModulation node. See SpatialModulation for additional options.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/parallelize/","title":"Parallelize","text":""},{"location":"reference/bloqade/analog/builder/pragmas/","title":"Pragmas","text":"

This module provides classes for building and managing quantum programs using the Bloqade library.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.AddArgs","title":"AddArgs","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.AddArgs.args","title":"args","text":"
args(args_list)\n

Add arguments to the current program.

Parameters:

Name Type Description Default args_list List[Union[str, Variable]]

List of argument names or Variable objects to be added.

required

Returns:

Name Type Description Args Args

A new instance of the Args class with the specified arguments.

Raises:

Type Description TypeError

If args_list contains invalid types.

Note

This method is useful for deferring the value assignment of certain variables to runtime.

Source code in src/bloqade/analog/builder/pragmas.py
def args(self, args_list: List[Union[str, Variable]]) -> \"Args\":\n    \"\"\"\n    Add arguments to the current program.\n\n    Args:\n        args_list (List[Union[str, Variable]]): List of argument names or Variable\n            objects to be added.\n\n    Returns:\n        Args: A new instance of the Args class with the specified arguments.\n\n    Raises:\n        TypeError: If args_list contains invalid types.\n\n    Note:\n        This method is useful for deferring the value assignment of certain\n        variables to runtime.\n    \"\"\"\n    from bloqade.analog.builder.args import Args\n\n    return Args(args_list, self)\n
"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Assignable","title":"Assignable","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Assignable.assign","title":"assign","text":"
assign(**assignments)\n

Assign values to variables declared previously in the program.

Parameters:

Name Type Description Default **assignments

Key-value pairs where the key is the variable name and the value is the value to assign.

{}

Returns:

Name Type Description Assign Assign

A new instance of the Assign class with the specified assignments.

Raises:

Type Description ValueError

If an invalid assignment is provided.

Note

This is reserved for variables that should take single values or for spatial modulations created with .scale(str). After assigning values, you can choose a backend for emulation or execution.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Assignable.assign--usage-examples","title":"Usage Examples:","text":"
# define geometry\n>>> reg = bloqade.start\n...       .add_position([(0,0),(1,1),(2,2),(3,3)])\n# define variables in program\n>>> seq = reg.rydberg.detuning.uniform\n...       .linear(start=\"ival\", stop=1, duration=\"span_time\")\n# assign values to variables\n>>> seq = seq.assign(span_time=0.5, ival=0.0)\n
  • Next steps:
    • ...assign(assignments).bloqade: select the bloqade local emulator backend
    • ...assign(assignments).braket: select braket local emulator or QuEra hardware
    • ...assign(assignments).device(specifier_string): select backend by specifying a string
    • ...assign(assignments).batch_assign(assignments): assign multiple values for a parameter sweep
    • ...assign(assignments).parallelize(cluster_spacing): parallelize the program register
    • ...assign(assignments).args([previously_defined_vars]): defer value assignment to runtime
Source code in src/bloqade/analog/builder/pragmas.py
def assign(self, **assignments) -> \"Assign\":\n    \"\"\"\n    Assign values to variables declared previously in the program.\n\n    Args:\n        **assignments: Key-value pairs where the key is the variable name and\n            the value is the value to assign.\n\n    Returns:\n        Assign: A new instance of the Assign class with the specified\n            assignments.\n\n    Raises:\n        ValueError: If an invalid assignment is provided.\n\n    Note:\n        This is reserved for variables that should take single values or for\n        spatial modulations created with `.scale(str)`. After assigning values,\n        you can choose a backend for emulation or execution.\n\n    ### Usage Examples:\n    ```\n    # define geometry\n    >>> reg = bloqade.start\n    ...       .add_position([(0,0),(1,1),(2,2),(3,3)])\n    # define variables in program\n    >>> seq = reg.rydberg.detuning.uniform\n    ...       .linear(start=\"ival\", stop=1, duration=\"span_time\")\n    # assign values to variables\n    >>> seq = seq.assign(span_time=0.5, ival=0.0)\n    ```\n\n    - Next steps:\n        - `...assign(assignments).bloqade`: select the bloqade local emulator backend\n        - `...assign(assignments).braket`: select braket local emulator or QuEra hardware\n        - `...assign(assignments).device(specifier_string)`: select backend by specifying a\n        string\n        - `...assign(assignments).batch_assign(assignments)`: assign multiple values for a\n        parameter sweep\n        - `...assign(assignments).parallelize(cluster_spacing)`: parallelize the program\n        register\n        - `...assign(assignments).args([previously_defined_vars])`: defer value assignment to\n        runtime\n    \"\"\"\n    from bloqade.analog.builder.assign import Assign\n\n    return Assign(assignments, parent=self)\n
"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.BatchAssignable","title":"BatchAssignable","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.BatchAssignable.batch_assign","title":"batch_assign","text":"
batch_assign(__batch_params=[], **assignments)\n

Assign multiple values to variables for creating a parameter sweep.

Parameters:

Name Type Description Default __batch_params List[Dict[str, ParamType]]

List of dictionaries where each dictionary contains variable assignments for one set of parameters.

[] **assignments List[ParamType]

Key-value pairs where the key is the variable name and the value is a list of values to assign.

{}

Returns:

Type Description Union[BatchAssign, ListAssign]

Union[BatchAssign, ListAssign]: A new instance of BatchAssign or ListAssign class with the specified assignments.

Raises:

Type Description ValueError

If both __batch_params and assignments are provided.

Note

Bloqade handles the multiple programs generated by this method and treats them as a unified object for easy post-processing. Ensure all lists of values are of the same length as Bloqade will not perform a Cartesian product.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.BatchAssignable.batch_assign--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (0, \"atom_distance\")])\n>>> prog = reg.rydberg.rabi.amplitude.uniform.constant(\"value\", 5.0)\n>>> var_assigned_prog = prog.batch_assign(value=[1.0, 2.0, 3.0],\natom_distance=[1.0, 2.0, 3.0])\n
  • Next steps:
    • ...batch_assign(assignments).bloqade: select the bloqade local emulator backend
    • ...batch_assign(assignments).braket: select braket local emulator or QuEra hardware
    • ...batch_assign(assignments).device(specifier_string): select backend by specifying a string
    • ...batch_assign(assignments).parallelize(cluster_spacing): parallelize the program register
    • ...batch_assign(assignments).args([previously_defined_vars]): defer value assignment to runtime
Source code in src/bloqade/analog/builder/pragmas.py
def batch_assign(\n    self,\n    __batch_params: List[Dict[str, ParamType]] = [],\n    **assignments: List[ParamType],\n) -> Union[\"BatchAssign\", \"ListAssign\"]:\n    \"\"\"\n    Assign multiple values to variables for creating a parameter sweep.\n\n    Args:\n        __batch_params (List[Dict[str, ParamType]], optional): List of dictionaries\n            where each dictionary contains variable assignments for one set of parameters.\n        **assignments (List[ParamType]): Key-value pairs where the key is the variable\n            name and the value is a list of values to assign.\n\n    Returns:\n        Union[BatchAssign, ListAssign]: A new instance of BatchAssign or ListAssign\n            class with the specified assignments.\n\n    Raises:\n        ValueError: If both __batch_params and assignments are provided.\n\n    Note:\n        Bloqade handles the multiple programs generated by this method and treats them\n        as a unified object for easy post-processing. Ensure all lists of values are of\n        the same length as Bloqade will not perform a Cartesian product.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (0, \"atom_distance\")])\n    >>> prog = reg.rydberg.rabi.amplitude.uniform.constant(\"value\", 5.0)\n    >>> var_assigned_prog = prog.batch_assign(value=[1.0, 2.0, 3.0],\n    atom_distance=[1.0, 2.0, 3.0])\n    ```\n\n    - Next steps:\n        - `...batch_assign(assignments).bloqade`: select the bloqade local emulator backend\n        - `...batch_assign(assignments).braket`: select braket local emulator or QuEra hardware\n        - `...batch_assign(assignments).device(specifier_string)`: select backend by specifying\n        a string\n        - `...batch_assign(assignments).parallelize(cluster_spacing)`: parallelize the program\n        register\n        - `...batch_assign(assignments).args([previously_defined_vars])`: defer value assignment\n        to runtime\n    \"\"\"\n    from bloqade.analog.builder.assign import ListAssign, BatchAssign\n\n    if len(__batch_params) > 0 and assignments:\n        raise ValueError(\"batch_params and assignments cannot be used together.\")\n\n    if len(__batch_params) > 0:\n        return ListAssign(__batch_params, parent=self)\n    else:\n        return BatchAssign(assignments, parent=self)\n
"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Parallelizable","title":"Parallelizable","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Parallelizable.parallelize","title":"parallelize","text":"
parallelize(cluster_spacing)\n

Parallelize the current problem by duplicating the geometry to utilize all available space/qubits on hardware.

Parameters:

Name Type Description Default cluster_spacing LiteralType

Specifies the spacing between clusters in micrometers.

required

Returns:

Name Type Description Parallelize Parallelize

A new instance of the Parallelize class with the specified cluster spacing.

Raises:

Type Description ValueError

If the cluster_spacing is not a valid value.

Note

After calling this method, you can choose a backend for emulation or execution. Options include bloqade for a local emulator, braket for a local emulator or QuEra hardware on the cloud, or specifying a device with a string.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Parallelizable.parallelize--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position((0,0)).rydberg.rabi.uniform.amplitude.constant(1.0, 1.0)\n# copy-paste the geometry and waveforms\n>>> parallelized_prog = reg.parallelize(24)\n
  • Next steps:
    • ...parallelize(cluster_spacing).bloqade: select the bloqade local emulator backend
    • ...parallelize(cluster_spacing).braket: select braket local emulator or QuEra hardware on the cloud
    • ...parallelize(cluster_spacing).device(specifier_string): select backend by specifying a string
Source code in src/bloqade/analog/builder/pragmas.py
def parallelize(self, cluster_spacing: LiteralType) -> \"Parallelize\":\n    \"\"\"\n    Parallelize the current problem by duplicating the geometry to utilize\n    all available space/qubits on hardware.\n\n    Args:\n        cluster_spacing (LiteralType): Specifies the spacing between clusters\n            in micrometers.\n\n    Returns:\n        Parallelize: A new instance of the Parallelize class with the specified\n            cluster spacing.\n\n    Raises:\n        ValueError: If the cluster_spacing is not a valid value.\n\n    Note:\n        After calling this method, you can choose a backend for emulation or\n        execution. Options include `bloqade` for a local emulator, `braket` for\n        a local emulator or QuEra hardware on the cloud, or specifying a device\n        with a string.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position((0,0)).rydberg.rabi.uniform.amplitude.constant(1.0, 1.0)\n    # copy-paste the geometry and waveforms\n    >>> parallelized_prog = reg.parallelize(24)\n    ```\n\n    - Next steps:\n        - `...parallelize(cluster_spacing).bloqade`: select the bloqade local emulator backend\n        - `...parallelize(cluster_spacing).braket`: select braket local emulator or QuEra\n        hardware on the cloud\n        - `...parallelize(cluster_spacing).device(specifier_string)`: select backend by\n        specifying a string\n    \"\"\"\n    from bloqade.analog.builder.parallelize import Parallelize\n\n    return Parallelize(cluster_spacing, self)\n
"},{"location":"reference/bloqade/analog/builder/route/","title":"Route","text":""},{"location":"reference/bloqade/analog/builder/sequence_builder/","title":"Sequence builder","text":""},{"location":"reference/bloqade/analog/builder/spatial/","title":"Spatial","text":""},{"location":"reference/bloqade/analog/builder/spatial/#bloqade.analog.builder.spatial.Uniform","title":"Uniform","text":"
Uniform(parent=None)\n

Bases: SpatialModulation

The node specify a uniform spacial modulation. Which is ready to apply waveform (See Waveform for available waveform options)

Examples:

- To hit this node from the start node:\n\n>>> reg = bloqade.start.add_position([(0,0),(1,1),(2,2),(3,3)])\n>>> loc = reg.rydberg.detuning.uniform\n\n- Apply Linear waveform:\n\n>>> wv = bloqade.ir.Linear(start=0,stop=1,duration=0.5)\n>>> reg = bloqade.start.add_position([(0,0),(1,1),(2,2),(3,3)])\n>>> loc = reg.rydberg.detuning.uniform.apply(wv)\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/start/","title":"Start","text":""},{"location":"reference/bloqade/analog/builder/start/#bloqade.analog.builder.start.ProgramStart","title":"ProgramStart","text":"
ProgramStart(parent=None)\n

Bases: Drive, Builder

ProgramStart is the base class for a starting/entry node for building a program.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/start/#bloqade.analog.builder.start.ProgramStart.apply","title":"apply","text":"
apply(sequence)\n

Apply a pre-built sequence to a program.

This allows you to build a program independent of any geometry and then apply the program to said geometry. Or, if you have a program you would like to try on multiple geometries you can trivially do so with this.

Example Usage:

>>> from numpy import pi\n>>> seq = start.rydberg.rabi.amplitude.constant(2.0 * pi, 4.5)\n# choose a geometry of interest to apply the program on\n>>> from bloqade.analog.atom_arrangement import Chain, Kagome\n>>> complete_program = Chain(10).apply(seq)\n# you can .apply to as many geometries as you like\n>>> another_complete_program = Kagome(3).apply(seq)\n

  • From here you can now do:
    • ...assign(assignments).bloqade: select the bloqade local emulator backend
    • ...assign(assignments).braket: select braket local emulator or QuEra hardware
    • ...assign(assignments).device(specifier_string): select backend by specifying a string
  • Assign multiple values to a single variable for a parameter sweep:
    • ...assign(assignments).batch_assign(assignments):
  • Parallelize the program register, duplicating the geometry and waveform sequence to take advantage of all available space/qubits on the QPU:
    • ...assign(assignments).parallelize(cluster_spacing)
  • Defer value assignment of certain variables to runtime:
    • ...assign(assignments).args([previously_defined_vars])
Source code in src/bloqade/analog/builder/start.py
@beartype\ndef apply(self, sequence: SequenceExpr) -> SequenceBuilder:\n    \"\"\"\n    Apply a pre-built sequence to a program.\n\n    This allows you to build a program independent of any geometry\n    and then `apply` the program to said geometry. Or, if you have a\n    program you would like to try on multiple geometries you can\n    trivially do so with this.\n\n    Example Usage:\n    ```\n    >>> from numpy import pi\n    >>> seq = start.rydberg.rabi.amplitude.constant(2.0 * pi, 4.5)\n    # choose a geometry of interest to apply the program on\n    >>> from bloqade.analog.atom_arrangement import Chain, Kagome\n    >>> complete_program = Chain(10).apply(seq)\n    # you can .apply to as many geometries as you like\n    >>> another_complete_program = Kagome(3).apply(seq)\n    ```\n\n    - From here you can now do:\n        - `...assign(assignments).bloqade`: select the bloqade\n            local emulator backend\n        - `...assign(assignments).braket`: select braket\n            local emulator or QuEra hardware\n        - `...assign(assignments).device(specifier_string)`: select\n            backend by specifying a string\n    - Assign multiple values to a single variable for a parameter sweep:\n        - `...assign(assignments).batch_assign(assignments)`:\n    - Parallelize the program register, duplicating the geometry and waveform\n        sequence to take advantage of all available\n      space/qubits on the QPU:\n        - `...assign(assignments).parallelize(cluster_spacing)`\n    - Defer value assignment of certain variables to runtime:\n        - `...assign(assignments).args([previously_defined_vars])`\n\n    \"\"\"\n    return SequenceBuilder(sequence, self)\n
"},{"location":"reference/bloqade/analog/builder/typing/","title":"Typing","text":""},{"location":"reference/bloqade/analog/builder/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Recordable","title":"Recordable","text":""},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Recordable.record","title":"record","text":"
record(name)\n

Copy or \"record\" the value at the end of the waveform into a variable so that it can be used in another place.

A common design pattern is to couple this with .slice() considering you may not know exactly what the end value of a .slice() is, especially in parameter sweeps where it becomes cumbersome to handle.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Recordable.record--usage-example","title":"Usage Example:","text":"
# define program of interest\n>>> from bloqade import start\n>>> prog = start.rydberg.rabi.amplitude.uniform\n>>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n# We now slice the piecewise_linear from above and record the\n# value at the end of that slice. We then use that value\n# to construct a new waveform that can be appended to the previous\n# one without introducing discontinuity (refer to the\n# \"Quantum Scar Dynamics\" tutorial for how this could be handy)\n>>> prog_with_record = prog_with_wf.slice(0.0, 1.0).record(\"end_of_wf\")\n>>> record_applied_prog = prog_with_record.linear(start=\"end_of_wf\"\n, stop=0.0, duration=0.3)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...slice(start, stop).linear(start, stop, duration): to append another linear waveform
    • ...slice(start, stop).constant(value, duration): to append a constant waveform
    • ...slice(start, stop).piecewise_linear(): to append a piecewise linear waveform
    • ...slice(start, stop).piecewise_constant(): to append a piecewise constant waveform
    • ...slice(start, stop).poly([coefficients], duration): to append a polynomial waveform
    • ...slice(start, stop).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...slilce(start, stop).fn(f(t,...)): to append a waveform defined by a python function
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...slice(start, stop).uniform: To address all atoms in the field
    • ...slice(start, stop).location(int): To address an atom at a specific location via index
    • ...slice(start, stop).scale(str)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...slice(start, stop).assign(variable_name = value): to assign a single value to a variable
    • ...slice(start, stop) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...slice(start, stop).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...slice(start, stop).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...slice(start, stop).bloqade: to run on the Bloqade local emulator
    • ...slice(start, stop).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...slice(start, stop).parallelize(spacing)
  • Start targeting another level coupling
    • ...slice(start, stop).rydberg: to target the Rydberg level coupling
    • ...slice(start, stop).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...slice(start, stop).amplitude: to target the real-valued Rabi Amplitude field
    • ...slice(start, stop).phase: to target the real-valued Rabi Phase field
    • ...slice(start, stop).detuning: to target the Detuning field
    • ...slice(start, stop).rabi: to target the complex-valued Rabi field ```
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef record(self, name: str) -> \"Record\":\n    \"\"\"\n    Copy or \"record\" the value at the end of the waveform into a variable\n    so that it can be used in another place.\n\n    A common design pattern is to couple this with `.slice()` considering\n    you may not know exactly what the end value of a `.slice()` is,\n    especially in parameter sweeps where it becomes cumbersome to handle.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    # define program of interest\n    >>> from bloqade import start\n    >>> prog = start.rydberg.rabi.amplitude.uniform\n    >>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    # We now slice the piecewise_linear from above and record the\n    # value at the end of that slice. We then use that value\n    # to construct a new waveform that can be appended to the previous\n    # one without introducing discontinuity (refer to the\n    # \"Quantum Scar Dynamics\" tutorial for how this could be handy)\n    >>> prog_with_record = prog_with_wf.slice(0.0, 1.0).record(\"end_of_wf\")\n    >>> record_applied_prog = prog_with_record.linear(start=\"end_of_wf\"\n    , stop=0.0, duration=0.3)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...slice(start, stop).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...slice(start, stop).constant(value, duration)`:\n            to append a constant waveform\n        - `...slice(start, stop).piecewise_linear()`:\n            to append a piecewise linear waveform\n        - `...slice(start, stop).piecewise_constant()`:\n            to append a piecewise constant waveform\n        - `...slice(start, stop).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...slice(start, stop).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...slilce(start, stop).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...slice(start, stop).uniform`:\n            To address all atoms in the field\n        - `...slice(start, stop).location(int)`:\n            To address an atom at a specific location via index\n        - `...slice(start, stop).scale(str)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...slice(start, stop).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...slice(start, stop)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...slice(start, stop).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...slice(start, stop).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...slice(start, stop).bloqade`:\n            to run on the Bloqade local emulator\n        - `...slice(start, stop).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...slice(start, stop).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...slice(start, stop).rydberg`:\n            to target the Rydberg level coupling\n        - `...slice(start, stop).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...slice(start, stop).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...slice(start, stop).phase`:\n            to target the real-valued Rabi Phase field\n        - `...slice(start, stop).detuning`:\n            to target the Detuning field\n        - `...slice(start, stop).rabi`:\n            to target the complex-valued Rabi field\n    ```\n    \"\"\"\n    return Record(name, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Sliceable","title":"Sliceable","text":""},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Sliceable.slice","title":"slice","text":"
slice(start=None, stop=None)\n

Indicate that you only want a portion of your waveform to be used in the program.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Sliceable.slice--usage-example","title":"Usage Example:","text":"
# define a program with a waveform of interest\n>>> from bloqade import start\n>>> prog = start.add_position((0,0)).rydberg.rabi.amplitude.uniform\n>>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n# instead of using the full waveform we opt to only take the first 1 us\n>>> prog_with_slice = prog_with_wf.slice(0.0, 1.0)\n# you may use variables as well\n>>> prog_with_slice = prog_with_wf.slice(\"start\", \"end\")\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...slice(start, stop).linear(start, stop, duration): to append another linear waveform
    • ...slice(start, stop).constant(value, duration): to append a constant waveform
    • ...slice(start, stop).piecewise_linear(): to append a piecewise linear waveform
    • ...slice(start, stop).piecewise_constant(): to append a piecewise constant waveform
    • ...slice(start, stop).poly([coefficients], duration): to append a polynomial waveform
    • ...slice(start, stop).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...slilce(start, stop).fn(f(t,...)): to append a waveform defined by a python function
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...slice(start, stop).uniform: To address all atoms in the field
    • ...slice(start, stop).location(int): To address an atom at a specific location via index
    • ...slice(start, stop).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...slice(start, stop).assign(variable_name = value): to assign a single value to a variable
    • ...slice(start, stop) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...slice(start, stop).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...slice(start, stop).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...slice(start, stop).bloqade: to run on the Bloqade local emulator
    • ...slice(start, stop).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...slice(start, stop).parallelize(spacing)
  • Start targeting another level coupling
    • ...slice(start, stop).rydberg: to target the Rydberg level coupling
    • ...slice(start, stop).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...slice(start, stop).amplitude: to target the real-valued Rabi Amplitude field
    • ...slice(start, stop).phase: to target the real-valued Rabi Phase field
    • ...slice(start, stop).detuning: to target the Detuning field
    • ...slice(start, stop).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef slice(\n    self,\n    start: Optional[ScalarType] = None,\n    stop: Optional[ScalarType] = None,\n) -> \"Slice\":\n    \"\"\"\n    Indicate that you only want a portion of your waveform to be used in\n    the program.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n\n    ### Usage Example:\n    ```\n    # define a program with a waveform of interest\n    >>> from bloqade import start\n    >>> prog = start.add_position((0,0)).rydberg.rabi.amplitude.uniform\n    >>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    # instead of using the full waveform we opt to only take the first 1 us\n    >>> prog_with_slice = prog_with_wf.slice(0.0, 1.0)\n    # you may use variables as well\n    >>> prog_with_slice = prog_with_wf.slice(\"start\", \"end\")\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...slice(start, stop).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...slice(start, stop).constant(value, duration)`:\n            to append a constant waveform\n        - `...slice(start, stop).piecewise_linear()`:\n            to append a piecewise linear waveform\n        - `...slice(start, stop).piecewise_constant()`:\n            to append a piecewise constant waveform\n        - `...slice(start, stop).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...slice(start, stop).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...slilce(start, stop).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...slice(start, stop).uniform`:\n            To address all atoms in the field\n        - `...slice(start, stop).location(int)`:\n            To address an atom at a specific location via index\n        - `...slice(start, stop).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...slice(start, stop).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...slice(start, stop)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...slice(start, stop).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...slice(start, stop).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...slice(start, stop).bloqade`:\n            to run on the Bloqade local emulator\n        - `...slice(start, stop).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...slice(start, stop).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...slice(start, stop).rydberg`:\n            to target the Rydberg level coupling\n        - `...slice(start, stop).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...slice(start, stop).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...slice(start, stop).phase`:\n            to target the real-valued Rabi Phase field\n        - `...slice(start, stop).detuning`:\n            to target the Detuning field\n        - `...slice(start, stop).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return Slice(start, stop, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable","title":"WaveformAttachable","text":"
WaveformAttachable(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.apply","title":"apply","text":"
apply(wf)\n

Apply a Waveform built previously to current location(s).

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.apply--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# build our waveform independently of the main program\n>>> from bloqade import piecewise_linear\n>>> wf = piecewise_linear(durations=[0.3, 2.5, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n>>> prog.apply(wf)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...apply(waveform).linear(start, stop, duration): to append another linear waveform
    • ...apply(waveform).constant(value, duration): to append a constant waveform
    • ...apply(waveform).piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...apply(waveform).piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...apply(waveform).poly([coefficients], duration): to append a polynomial waveform
    • ...apply(waveform).apply(waveform): to append a pre-defined waveform
    • ...apply(waveform).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...apply(waveform).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...apply(waveform).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...apply(waveform).uniform: To address all atoms in the field
    • ...apply(waveform).location(int): To address an atom at a specific location via index
    • ...apply(waveform).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...apply(waveform).assign(variable_name = value): to assign a single value to a variable
    • ...apply(waveform).batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...apply(waveform).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...apply(waveform).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...apply(waveform).bloqade: to run on the Bloqade local emulator
    • ...apply(waveform).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...apply(waveform).parallelize(spacing)
  • Start targeting another level coupling
    • ...apply(waveform).rydberg: to target the Rydberg level coupling
    • ...apply(waveform).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...apply(waveform).amplitude: to target the real-valued Rabi Amplitude field
    • ...apply(waveform).phase: to target the real-valued Rabi Phase field
    • ...apply(waveform).detuning: to target the Detuning field
    • ...apply(waveform).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef apply(self, wf: ir.Waveform) -> \"Apply\":\n    \"\"\"\n    Apply a [`Waveform`][bloqade.ir.control.Waveform] built previously to\n    current location(s).\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # build our waveform independently of the main program\n    >>> from bloqade import piecewise_linear\n    >>> wf = piecewise_linear(durations=[0.3, 2.5, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    >>> prog.apply(wf)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...apply(waveform).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...apply(waveform).constant(value, duration)`:\n            to append a constant waveform\n        - `...apply(waveform).piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...apply(waveform).piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...apply(waveform).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...apply(waveform).apply(waveform)`:\n            to append a pre-defined waveform\n        - `...apply(waveform).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...apply(waveform).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...apply(waveform).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...apply(waveform).uniform`: To address all atoms in the field\n        - `...apply(waveform).location(int)`:\n            To address an atom at a specific location via index\n        - `...apply(waveform).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying a\n                single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...apply(waveform).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...apply(waveform).batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...apply(waveform).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...apply(waveform).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...apply(waveform).bloqade`:\n            to run on the Bloqade local emulator\n        - `...apply(waveform).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...apply(waveform).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...apply(waveform).rydberg`: to target the Rydberg level coupling\n        - `...apply(waveform).hyperfine`: to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...apply(waveform).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...apply(waveform).phase`:\n            to target the real-valued Rabi Phase field\n        - `...apply(waveform).detuning`:\n            to target the Detuning field\n        - `...apply(waveform).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return Apply(wf, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.constant","title":"constant","text":"
constant(value, duration)\n

Append or assign a constant waveform to the current location(s).

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.constant--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# apply a constant waveform of 1.9 radians/us for 0.5 us\n>>> prog.constant(value=1.9,duration=0.5)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...constant(value, duration).linear(start, stop, duration): to append another linear waveform
    • ...constant(value, duration).constant(value, duration): to append a constant waveform
    • ...constant(value, duration) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...constant(value, duration) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...constant(value, duration).poly([coefficients], duration): to append a polynomial waveform
    • ...constant(value, duration).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...constant(value, duration).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...constant(value, duration).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...constant(value, duration).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...constant(value, duration).uniform: To address all atoms in the field
    • ...constant(value, duration).scale(...): To address an atom at a specific location via index
    • ...constant(value, duration).location(int)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...constant(value, duration).assign(variable_name = value): to assign a single value to a variable
    • ...constant(value, duration) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...constant(value, duration).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...constant(value, duration).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...constant(value, duration).bloqade: to run on the Bloqade local emulator
    • ...constant(value, duration).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...constant(start, stop, duration).parallelize(spacing)
  • Start targeting another level coupling
    • ...constant(value, duration).rydberg: to target the Rydberg level coupling
    • ...constant(value, duration).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...constant(value, duration).amplitude: to target the real-valued Rabi Amplitude field
    • ...constant(value, duration).phase: to target the real-valued Rabi Phase field
    • ...constant(value, duration).detuning: to target the Detuning field
    • ...constant(value, duration).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef constant(self, value: ScalarType, duration: ScalarType) -> \"Constant\":\n    \"\"\"\n    Append or assign a constant waveform to the current location(s).\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # apply a constant waveform of 1.9 radians/us for 0.5 us\n    >>> prog.constant(value=1.9,duration=0.5)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...constant(value, duration).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...constant(value, duration).constant(value, duration)`:\n            to append a constant waveform\n        - `...constant(value, duration)\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...constant(value, duration)\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...constant(value, duration).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...constant(value, duration).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...constant(value, duration).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...constant(value, duration).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...constant(value, duration).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...constant(value, duration).uniform`:\n            To address all atoms in the field\n        - `...constant(value, duration).scale(...)`:\n            To address an atom at a specific location via index\n        - `...constant(value, duration).location(int)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...constant(value, duration).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...constant(value, duration)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...constant(value, duration).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...constant(value, duration).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...constant(value, duration).bloqade`:\n            to run on the Bloqade local emulator\n        - `...constant(value, duration).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...constant(start, stop, duration).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...constant(value, duration).rydberg`:\n            to target the Rydberg level coupling\n        - `...constant(value, duration).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current\n      level coupling (previously selected as `rydberg` or `hyperfine`):\n        - `...constant(value, duration).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...constant(value, duration).phase`:\n            to target the real-valued Rabi Phase field\n        - `...constant(value, duration).detuning`:\n            to target the Detuning field\n        - `...constant(value, duration).rabi`:\n            to target the complex-valued Rabi field\n\n    \"\"\"\n    return Constant(value, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.fn","title":"fn","text":"
fn(fn, duration)\n

Append or assign a custom function as a waveform.

The function must have its first argument be that of time but can also have other arguments which are treated as variables. You can assign values to later in the program via .assign or .batch_assign.

The function must also return a singular float value.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.fn--usage-examples","title":"### Usage Examples:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# define our custom waveform. It must have one argument\n# be time followed by any other number of arguments that can\n# be assigned a value later in the program via `.assign` or `.batch_assign`\n>>> def custom_waveform_function(t, arg1, arg2):\n        return arg1*t + arg2\n>>> prog = prog.fn(custom_waveform_function, duration = 0.5)\n# assign values\n>>> assigned_vars_prog = prog.assign(arg1 = 1.0, arg2 = 2.0)\n# or go for batching!\n>>> assigned_vars_batch_prog = prog.assign(arg1 = 1.0, arg2 = [1.0, 2.0, 3.0])\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...fn(f(t,...)) .linear(start, stop, duration): to append another linear waveform
    • ...fn(f(t,...)) .constant(value, duration): to append a constant waveform
    • ...fn(f(t,...)) .piecewise_linear(durations, values): to append a piecewise linear waveform
    • ...fn(f(t,...)) .piecewise_constant(durations, values): to append a piecewise constant waveform
    • ...fn(f(t,...)) .poly([coefficients], duration): to append a polynomial waveform
    • ...fn(f(t,...)) .apply(waveform): to append a pre-defined waveform
    • ...fn(f(t,...)) .fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...fn(f(t,...)).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...fn(f(t,...)).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...fn(f(t,...)).uniform: To address all atoms in the field
    • ...fn(f(t,...)).scale(...): To address an atom at a specific location via index
    • ...fn(f(t,...)).location(int)`
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...fn(f(t,...)) .assign(variable_name = value): to assign a single value to a variable
    • ...fn(f(t,...)) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...fn(f(t,...)) .args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...fn(f(t,...)).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...fn(f(t,...)).bloqade: to run on the Bloqade local emulator
    • ...fn(f(t,...)).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...fn(f(t,...)).parallelize(spacing)
  • Start targeting another level coupling
    • ...fn(f(t,...)).rydberg: to target the Rydberg level coupling
    • ...fn(f(t,...)).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...fn(f(t,...)).amplitude: to target the real-valued Rabi Amplitude field
    • ...fn(f(t,...)).phase: to target the real-valued Rabi Phase field
    • ...fn(f(t,...)).detuning: to target the Detuning field
    • ...fn(f(t,...)).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef fn(self, fn: Callable, duration: ScalarType) -> \"Fn\":\n    \"\"\"\n    Append or assign a custom function as a waveform.\n\n    The function must have its first argument be that of time but\n    can also have other arguments which are treated as variables.\n    You can assign values to later in the program via `.assign` or `.batch_assign`.\n\n    The function must also return a singular float value.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### ### Usage Examples:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # define our custom waveform. It must have one argument\n    # be time followed by any other number of arguments that can\n    # be assigned a value later in the program via `.assign` or `.batch_assign`\n    >>> def custom_waveform_function(t, arg1, arg2):\n            return arg1*t + arg2\n    >>> prog = prog.fn(custom_waveform_function, duration = 0.5)\n    # assign values\n    >>> assigned_vars_prog = prog.assign(arg1 = 1.0, arg2 = 2.0)\n    # or go for batching!\n    >>> assigned_vars_batch_prog = prog.assign(arg1 = 1.0, arg2 = [1.0, 2.0, 3.0])\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...fn(f(t,...))\n            .linear(start, stop, duration)`: to append another linear waveform\n        - `...fn(f(t,...))\n            .constant(value, duration)`: to append a constant waveform\n        - `...fn(f(t,...))\n            .piecewise_linear(durations, values)`:\n            to append a piecewise linear waveform\n        - `...fn(f(t,...))\n            .piecewise_constant(durations, values)`:\n            to append a piecewise constant waveform\n        - `...fn(f(t,...))\n            .poly([coefficients], duration)`: to append a polynomial waveform\n        - `...fn(f(t,...))\n            .apply(waveform)`: to append a pre-defined waveform\n        - `...fn(f(t,...))\n            .fn(f(t,...))`: to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...fn(f(t,...)).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...fn(f(t,...)).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...fn(f(t,...)).uniform`:\n            To address all atoms in the field\n        - `...fn(f(t,...)).scale(...)`:\n            To address an atom at a specific location via index\n        - ...fn(f(t,...)).location(int)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning it a\n                list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...fn(f(t,...))\n            .assign(variable_name = value)`: to assign a single value to a variable\n        - `...fn(f(t,...))\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...fn(f(t,...))\n            .args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...fn(f(t,...)).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...fn(f(t,...)).bloqade`:\n            to run on the Bloqade local emulator\n        - `...fn(f(t,...)).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...fn(f(t,...)).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...fn(f(t,...)).rydberg`:\n            to target the Rydberg level coupling\n        - `...fn(f(t,...)).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...fn(f(t,...)).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...fn(f(t,...)).phase`:\n            to target the real-valued Rabi Phase field\n        - `...fn(f(t,...)).detuning`:\n            to target the Detuning field\n        - `...fn(f(t,...)).rabi`:\n            to target the complex-valued Rabi field\n\n    \"\"\"\n    return Fn(fn, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.linear","title":"linear","text":"
linear(start, stop, duration)\n

Append or assign a linear waveform to the current location(s).

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.linear--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# apply a linear waveform that goes from 0 to 1 radians/us in 0.5 us\n>>> prog.linear(start=0,stop=1,duration=0.5)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...linear(start, stop, duration).linear(start, stop, duration): to append another linear waveform
    • ...linear(start, stop, duration).constant(value, duration): to append a constant waveform
    • ...linear(start, stop, duration) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...linear(start, stop, duration) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...linear(start, stop, duration).poly([coefficients], duration): to append a polynomial waveform
    • ...linear(start, stop, duration).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...linear(start, stop, duration).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...linear(start, stop, duration).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...linear(start, stop, duration).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...linear(start, stop, duration).uniform: To address all atoms in the field
    • ...linear(start, stop, duration).location(int): To address atoms at specific location with scaling
    • ...linear(start, stop, duration).scale(...)
      • To address atoms at specific location with scaling
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...linear(start, stop, duration).assign(variable_name = value): to assign a single value to a variable
    • ...linear(start, stop, duration) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...linear(start, stop, duration).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...linear(start, stop, duration).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...linear(start, stop, duration).bloqade: to run on the Bloqade local emulator
    • ...linear(start, stop, duration).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...linear(start, stop, duration).parallelize(spacing)
  • Start targeting another level coupling
    • ...linear(start, stop, duration).rydberg: to target the Rydberg level coupling
    • ...linear(start, stop, duration).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...linear(start, stop, duration).amplitude: to target the real-valued Rabi Amplitude field
    • ...linear(start, stop, duration).phase: to target the real-valued Rabi Phase field
    • ...linear(start, stop, duration).detuning: to target the Detuning field
    • ...linear(start, stop, duration).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef linear(\n    self, start: ScalarType, stop: ScalarType, duration: ScalarType\n) -> \"Linear\":\n    \"\"\"\n\n    Append or assign a linear waveform to the current location(s).\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # apply a linear waveform that goes from 0 to 1 radians/us in 0.5 us\n    >>> prog.linear(start=0,stop=1,duration=0.5)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...linear(start, stop, duration).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...linear(start, stop, duration).constant(value, duration)`:\n            to append a constant waveform\n        - `...linear(start, stop, duration)\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...linear(start, stop, duration)\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...linear(start, stop, duration).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...linear(start, stop, duration).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...linear(start, stop, duration).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...linear(start, stop, duration).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...linear(start, stop, duration).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...linear(start, stop, duration).uniform`:\n            To address all atoms in the field\n        - `...linear(start, stop, duration).location(int)`:\n            To address atoms at specific location with scaling\n        - `...linear(start, stop, duration).scale(...)`\n            - To address atoms at specific location with scaling\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...linear(start, stop, duration).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...linear(start, stop, duration)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...linear(start, stop, duration).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...linear(start, stop, duration).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...linear(start, stop, duration).bloqade`:\n            to run on the Bloqade local emulator\n        - `...linear(start, stop, duration).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...linear(start, stop, duration).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...linear(start, stop, duration).rydberg`:\n            to target the Rydberg level coupling\n        - `...linear(start, stop, duration).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...linear(start, stop, duration).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...linear(start, stop, duration).phase`:\n            to target the real-valued Rabi Phase field\n        - `...linear(start, stop, duration).detuning`:\n            to target the Detuning field\n        - `...linear(start, stop, duration).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n\n    return Linear(start, stop, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_constant","title":"piecewise_constant","text":"
piecewise_constant(durations, values)\n

Append or assign a piecewise constant waveform to current location(s).

The durations argument should have number of elements = len(values). durations should be the duration PER section of the waveform, NON-CUMULATIVE.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_constant--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.rabi.phase.uniform\n# create a staircase, we hold 0.0 rad/us for 1.0 us, then\n# to 1.0 rad/us for 0.5 us before stopping at 0.8 rad/us for 0.9 us.\n>>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3], values=[1.0, 0.5, 0.9])\n
  • Your next steps including:
  • Continue building your waveform via:
    • ...piecewise_constant([durations], [values]) .linear(start, stop, duration): to append another linear waveform
    • ...piecewise_constant([durations], [values]) .constant(value, duration): to append a constant waveform
    • ...piecewise_constant([durations], [values]) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...piecewise_constant([durations], [values]) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...piecewise_constant([durations], [values]) .poly([coefficients], duration): to append a polynomial waveform
    • ...piecewise_constant([durations], [values]) .apply(waveform): to append a pre-defined waveform
    • ...piecewise_constant([durations], [values]).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...piecewise_constant([durations], [values]) .slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...piecewise_constant([durations], [values]) .record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...piecewise_constant([durations], [values]).uniform: To address all atoms in the field
    • ...piecewise_constant([durations], [values]).location(int): To address an atom at a specific location via index
    • ...piecewise_constant([durations], [values]).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...piecewise_constant([durations], [values]) .assign(variable_name = value): to assign a single value to a variable
    • ...piecewise_constant([durations], [values]) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...piecewise_constant([durations], [values]) .args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...piecewise_constant([durations], [values]).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...piecewise_constant([durations], [values]).bloqade: to run on the Bloqade local emulator
    • ...piecewise_constant([durations], [values]).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...piecewise_constat([durations], [values]).parallelize(spacing)
  • Start targeting another level coupling
    • ...piecewise_constant([durations], [values]).rydberg: to target the Rydberg level coupling
    • ...piecewise_constant([durations], [values]).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...piecewise_constant(durations, values).amplitude: to target the real-valued Rabi Amplitude field
    • ...piecewise_constant([durations], [values]).phase: to target the real-valued Rabi Phase field
    • ...piecewise_constant([durations], [values]).detuning: to target the Detuning field
    • ...piecewise_constant([durations], [values]).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef piecewise_constant(\n    self, durations: List[ScalarType], values: List[ScalarType]\n) -> \"PiecewiseConstant\":\n    \"\"\"\n    Append or assign a piecewise constant waveform to current location(s).\n\n    The `durations` argument should have number of elements = len(values).\n    `durations` should be the duration PER section of the waveform,\n    NON-CUMULATIVE.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.rabi.phase.uniform\n    # create a staircase, we hold 0.0 rad/us for 1.0 us, then\n    # to 1.0 rad/us for 0.5 us before stopping at 0.8 rad/us for 0.9 us.\n    >>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3], values=[1.0, 0.5, 0.9])\n    ```\n\n    - Your next steps including:\n    - Continue building your waveform via:\n        - `...piecewise_constant([durations], [values])\n            .linear(start, stop, duration)`: to append another linear waveform\n        - `...piecewise_constant([durations], [values])\n            .constant(value, duration)`: to append a constant waveform\n        - `...piecewise_constant([durations], [values])\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...piecewise_constant([durations], [values])\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...piecewise_constant([durations], [values])\n            .poly([coefficients], duration)`: to append a polynomial waveform\n        - `...piecewise_constant([durations], [values])\n            .apply(waveform)`: to append a pre-defined waveform\n        - `...piecewise_constant([durations], [values]).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...piecewise_constant([durations], [values])\n            .slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...piecewise_constant([durations], [values])\n            .record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...piecewise_constant([durations], [values]).uniform`:\n            To address all atoms in the field\n        - `...piecewise_constant([durations], [values]).location(int)`:\n            To address an atom at a specific location via index\n        - `...piecewise_constant([durations], [values]).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning it a\n                list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...piecewise_constant([durations], [values])\n            .assign(variable_name = value)`: to assign a single value to a variable\n        - `...piecewise_constant([durations], [values])\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...piecewise_constant([durations], [values])\n            .args([\"previously_defined_var\"])`: to defer assignment\n            of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...piecewise_constant([durations], [values]).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...piecewise_constant([durations], [values]).bloqade`:\n            to run on the Bloqade local emulator\n        - `...piecewise_constant([durations], [values]).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...piecewise_constat([durations], [values]).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...piecewise_constant([durations], [values]).rydberg`:\n            to target the Rydberg level coupling\n        - `...piecewise_constant([durations], [values]).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...piecewise_constant(durations, values).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...piecewise_constant([durations], [values]).phase`:\n            to target the real-valued Rabi Phase field\n        - `...piecewise_constant([durations], [values]).detuning`:\n            to target the Detuning field\n        - `...piecewise_constant([durations], [values]).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return PiecewiseConstant(durations, values, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_linear","title":"piecewise_linear","text":"
piecewise_linear(durations, values)\n

Append or assign a piecewise linear waveform to current location(s), where the waveform is formed by connecting values[i], values[i+1] with linear segments.

The durations argument should have # of elements = len(values) - 1. durations should be the duration PER section of the waveform, NON-CUMULATIVE.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_linear--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# ramp our waveform up to a certain value, hold it\n# then ramp down. In this case, we ramp up to 2.0 rad/us in 0.3 us,\n# then hold it for 1.5 us before ramping down in 0.3 us back to 0.0 rad/us.\n>>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...piecewise_linear([durations], [values]) .linear(start, stop, duration): to append another linear waveform
    • ...piecewise_linear([durations], [values]).constant(value, duration): to append a constant waveform
    • ...piecewise_linear([durations], [values]) .piecewise_linear(durations, values): to append a piecewise linear waveform
    • ...piecewise_linear([durations], [values]) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...piecewise_linear([durations], [values]) .poly([coefficients], duration): to append a polynomial waveform
    • ...piecewise_linear([durations], [values]).apply(waveform): to append a pre-defined waveform
    • ...piecewise_linear([durations], [values]).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...piecewise_linear([durations], [values]) .slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...piecewise_linear([durations], [values]) .record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...piecewise_linear([durations], [values]).uniform: To address all atoms in the field
    • ...piecewise_linear([durations], [values]).scale(...): To address an atom at a specific location via index
    • ...piecewise_linear([durations], [values]).location(int)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...piecewise_linear([durations], [values]) .assign(variable_name = value): to assign a single value to a variable
    • ...piecewise_linear([durations], [values]) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...piecewise_linear([durations], [values]) .args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...piecewise_linear([durations], [values]).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...piecewise_linear([durations], [values]).bloqade: to run on the Bloqade local emulator
    • ...piecewise_linear([durations], [values]).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...piecewise_linear([durations], [values]).parallelize(spacing)
  • Start targeting another level coupling
    • ...piecewise_linear([durations], [values]).rydberg: to target the Rydberg level coupling
    • ...piecewise_linear([durations], [values]).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...piecewise_linear([durations], [values]).amplitude: to target the real-valued Rabi Amplitude field
    • ...piecewise_linear([durations], [values]).phase: to target the real-valued Rabi Phase field
    • ...piecewise_linear([durations], [values]).detuning: to target the Detuning field
    • ....rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef piecewise_linear(\n    self, durations: List[ScalarType], values: List[ScalarType]\n) -> \"PiecewiseLinear\":\n    \"\"\"\n    Append or assign a piecewise linear waveform to current location(s),\n    where the waveform is formed by connecting `values[i], values[i+1]`\n    with linear segments.\n\n    The `durations` argument should have # of elements = len(values) - 1.\n    `durations` should be the duration PER section of the waveform, NON-CUMULATIVE.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # ramp our waveform up to a certain value, hold it\n    # then ramp down. In this case, we ramp up to 2.0 rad/us in 0.3 us,\n    # then hold it for 1.5 us before ramping down in 0.3 us back to 0.0 rad/us.\n    >>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...piecewise_linear([durations], [values])\n            .linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...piecewise_linear([durations], [values]).constant(value, duration)`:\n            to append a constant waveform\n        - `...piecewise_linear([durations], [values])\n            .piecewise_linear(durations, values)`:\n            to append a piecewise linear waveform\n        - `...piecewise_linear([durations], [values])\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...piecewise_linear([durations], [values])\n            .poly([coefficients], duration)`: to append a polynomial waveform\n        - `...piecewise_linear([durations], [values]).apply(waveform)`:\n            to append a pre-defined waveform\n        - `...piecewise_linear([durations], [values]).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...piecewise_linear([durations], [values])\n            .slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...piecewise_linear([durations], [values])\n            .record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...piecewise_linear([durations], [values]).uniform`:\n            To address all atoms in the field\n        - `...piecewise_linear([durations], [values]).scale(...)`:\n            To address an atom at a specific location via index\n        - `...piecewise_linear([durations], [values]).location(int)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning it a\n                list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...piecewise_linear([durations], [values])\n            .assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...piecewise_linear([durations], [values])\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...piecewise_linear([durations], [values])\n            .args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...piecewise_linear([durations], [values]).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...piecewise_linear([durations], [values]).bloqade`:\n            to run on the Bloqade local emulator\n        - `...piecewise_linear([durations], [values]).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...piecewise_linear([durations], [values]).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...piecewise_linear([durations], [values]).rydberg`:\n            to target the Rydberg level coupling\n        - `...piecewise_linear([durations], [values]).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...piecewise_linear([durations], [values]).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...piecewise_linear([durations], [values]).phase`:\n            to target the real-valued Rabi Phase field\n        - `...piecewise_linear([durations], [values]).detuning`:\n            to target the Detuning field\n        - `....rabi`: to target the complex-valued Rabi field\n    \"\"\"\n    return PiecewiseLinear(durations, values, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.poly","title":"poly","text":"
poly(coeffs, duration)\n

Append or assign a waveform with a polynomial profile to current location(s).

You pass in a list of coefficients and a duration to this method which obeys the following expression:

wv(t) = coeffs[0] + coeffs[1]*t + coeffs[2]*t^2 + ... + coeffs[n]*t^n

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.poly--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n>>> coeffs = [-1, 0.5, 1.2]\n# resulting polynomial is:\n# f(t) = -1 + 0.5*t + 1.2*t^2 with duration of\n# 0.5 us\n>>> prog.poly(coeffs, duration=0.5)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...poly([coeffs], duration).linear(start, stop, duration): to append another linear waveform
    • ...poly([coeffs], duration).constant(value, duration): to append a constant waveform
    • ...poly([coeffs], duration) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...poly([coeffs], duration) .piecewise_constant([durations],[values]): to append a piecewise constant waveform
    • ...poly([coeffs], duration).poly([coefficients], duration): to append a polynomial waveform
    • ...poly([coeffs], duration).apply(waveform): to append a pre-defined waveform
    • ...poly([coeffs], duration).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...poly([coeffs], duration).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...poly([coeffs], duration).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...poly([coeffs], duration).uniform: To address all atoms in the field
    • ...poly([coeffs], duration).location(int): To address an atom at a specific location via index
    • ...poly([coeffs], duration).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...poly([coeffs], duration).assign(variable_name = value): to assign a single value to a variable
    • ...poly([coeffs], duration) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...poly([coeffs], duration).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...poly([coeffs], duration).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...poly([coeffs], duration).bloqade: to run on the Bloqade local emulator
    • ...poly([coeffs], duration).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...poly([coeffs], duration).parallelize(spacing)
  • Start targeting another level coupling
    • ...poly([coeffs], duration).rydberg: to target the Rydberg level coupling
    • ...poly([coeffs], duration).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...poly([coeffs], duration).amplitude: to target the real-valued Rabi Amplitude field
    • ...poly([coeffs], duration).phase: to target the real-valued Rabi Phase field
    • ...poly([coeffs], duration).detuning: to target the Detuning field
    • ...poly([coeffs], duration).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef poly(self, coeffs: List[ScalarType], duration: ScalarType) -> \"Poly\":\n    \"\"\"\n    Append or assign a waveform with a polynomial profile to current location(s).\n\n    You pass in a list of coefficients and a duration to this method which obeys\n    the following expression:\n\n    `\n    wv(t) = coeffs[0] + coeffs[1]*t + coeffs[2]*t^2 + ... + coeffs[n]*t^n\n    `\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    >>> coeffs = [-1, 0.5, 1.2]\n    # resulting polynomial is:\n    # f(t) = -1 + 0.5*t + 1.2*t^2 with duration of\n    # 0.5 us\n    >>> prog.poly(coeffs, duration=0.5)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...poly([coeffs], duration).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...poly([coeffs], duration).constant(value, duration)`:\n            to append a constant waveform\n        - `...poly([coeffs], duration)\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...poly([coeffs], duration)\n            .piecewise_constant([durations],[values])`:\n            to append a piecewise constant waveform\n        - `...poly([coeffs], duration).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...poly([coeffs], duration).apply(waveform)`:\n            to append a pre-defined waveform\n        - `...poly([coeffs], duration).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...poly([coeffs], duration).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...poly([coeffs], duration).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...poly([coeffs], duration).uniform`:\n            To address all atoms in the field\n        - `...poly([coeffs], duration).location(int)`:\n            To address an atom at a specific location via index\n        - `...poly([coeffs], duration).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning\n                it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...poly([coeffs], duration).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...poly([coeffs], duration)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...poly([coeffs], duration).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...poly([coeffs], duration).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...poly([coeffs], duration).bloqade`:\n            to run on the Bloqade local emulator\n        - `...poly([coeffs], duration).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...poly([coeffs], duration).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...poly([coeffs], duration).rydberg`:\n            to target the Rydberg level coupling\n        - `...poly([coeffs], duration).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level\n      coupling (previously selected as `rydberg` or `hyperfine`):\n        - `...poly([coeffs], duration).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...poly([coeffs], duration).phase`:\n            to target the real-valued Rabi Phase field\n        - `...poly([coeffs], duration).detuning`:\n            to target the Detuning field\n        - `...poly([coeffs], duration).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return Poly(coeffs, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/backend/","title":"Index","text":""},{"location":"reference/bloqade/analog/builder/backend/#bloqade.analog.builder.backend.BackendRoute","title":"BackendRoute","text":"
BackendRoute(parent=None)\n

Bases: QuEraService, BraketService, BloqadeService

Specify the backend to run your program on via a string (versus more formal builder syntax) of specifying the vendor/product first (Bloqade/Braket) and narrowing it down (e.g: ...device(\"quera.aquila\") versus ...quera.aquila()) - You can pass the following arguments: - \"braket.aquila\" - \"braket.local_emulator\" - \"bloqade.python\" - \"bloqade.julia\"

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/","title":"Bloqade","text":""},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeDeviceRoute","title":"BloqadeDeviceRoute","text":"
BloqadeDeviceRoute(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeDeviceRoute.python","title":"python","text":"
python()\n

Specify the Bloqade Python backend.

  • Possible Next Steps:
    • ...python().run(shots): to submit to the python emulator and await results
Source code in src/bloqade/analog/builder/backend/bloqade.py
def python(self):\n    \"\"\"\n    Specify the Bloqade Python backend.\n\n    - Possible Next Steps:\n        - `...python().run(shots)`:\n            to submit to the python emulator and await results\n    \"\"\"\n    return self.parse().bloqade.python()\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeService","title":"BloqadeService","text":"
BloqadeService(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeService.bloqade","title":"bloqade property","text":"
bloqade\n

Specify the Bloqade backend.

  • Possible Next Steps:
    • ...bloqade.python(): target submission to the Bloqade python backend
    • ...bloqade.julia(): (CURRENTLY NOT IMPLEMENTED!)target submission to the Bloqade.jl backend
"},{"location":"reference/bloqade/analog/builder/backend/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute","title":"BraketDeviceRoute","text":"
BraketDeviceRoute(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute.aquila","title":"aquila","text":"
aquila()\n

Specify QuEra's Aquila QPU on Braket to submit your program to.

The number of shots you specify in the subsequent .run method will either: - dictate the number of times your program is run - dictate the number of times per parameter your program is run if you have a variable with batch assignments/intend to conduct a parameter sweep

  • Possible next steps are:
    • ...aquila().run(shots): To submit to hardware and WAIT for results (blocking)
    • ...aquila().run_async(shots): To submit to hardware and immediately allow for other operations to occur
Source code in src/bloqade/analog/builder/backend/braket.py
def aquila(self) -> \"BraketHardwareRoutine\":\n    \"\"\"\n    Specify QuEra's Aquila QPU on Braket to submit your program to.\n\n    The number of shots you specify in the subsequent `.run` method will either:\n        - dictate the number of times your program is run\n        - dictate the number of times per parameter your program is run if\n          you have a variable with batch assignments/intend to conduct\n          a parameter sweep\n\n\n    - Possible next steps are:\n        - `...aquila().run(shots)`: To submit to hardware and WAIT for\n            results (blocking)\n        - `...aquila().run_async(shots)`: To submit to hardware and immediately\n            allow for other operations to occur\n    \"\"\"\n    return self.parse().braket.aquila()\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute.device","title":"device","text":"
device(device_arn)\n

Specify QPU based on the device ARN on Braket to submit your program to.

The number of shots you specify in the subsequent .run method will either: - dictate the number of times your program is run - dictate the number of times per parameter your program is run if you have a variable with batch assignments/intend to conduct a parameter sweep

  • Possible next steps are:
    • ...device(arn).run(shots): To submit to hardware and WAIT for results (blocking)
    • ...device(arn).run_async(shots): To submit to hardware and immediately allow for other operations to occur
Source code in src/bloqade/analog/builder/backend/braket.py
def device(self, device_arn) -> \"BraketHardwareRoutine\":\n    \"\"\"\n    Specify QPU based on the device ARN on Braket to submit your program to.\n\n    The number of shots you specify in the subsequent `.run` method will either:\n        - dictate the number of times your program is run\n        - dictate the number of times per parameter your program is run if\n            you have a variable with batch assignments/intend to conduct\n            a parameter sweep\n\n\n    - Possible next steps are:\n        - `...device(arn).run(shots)`: To submit to hardware and WAIT for\n            results (blocking)\n        - `...device(arn).run_async(shots)`: To submit to hardware and immediately\n            allow for other operations to occur\n    \"\"\"\n    return self.parse().braket.device(device_arn)\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute.local_emulator","title":"local_emulator","text":"
local_emulator()\n

Specify the Braket local emulator to submit your program to.

  • The number of shots you specify in the subsequent .run method will either:
    • dictate the number of times your program is run
    • dictate the number of times per parameter your program is run if you have a variable with batch assignments/intend to conduct a parameter sweep
  • Possible next steps are:
    • ...local_emulator().run(shots): to submit to the emulator and await results
Source code in src/bloqade/analog/builder/backend/braket.py
def local_emulator(self) -> \"BraketLocalEmulatorRoutine\":\n    \"\"\"\n    Specify the Braket local emulator to submit your program to.\n\n    - The number of shots you specify in the subsequent `.run` method will either:\n        - dictate the number of times your program is run\n        - dictate the number of times per parameter your program is run if\n          you have a variable with batch assignments/intend to\n          conduct a parameter sweep\n    - Possible next steps are:\n        - `...local_emulator().run(shots)`: to submit to the emulator\n            and await results\n\n    \"\"\"\n    return self.parse().braket.local_emulator()\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketService","title":"BraketService","text":"
BraketService(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketService.braket","title":"braket property","text":"
braket\n

Specify the Braket backend. This allows you to access the AWS Braket local emulator OR go submit things to QuEra hardware on AWS Braket service.

  • Possible Next Steps are:
    • ...braket.aquila(): target submission to the QuEra Aquila QPU
    • ...braket.local_emulator(): target submission to the Braket local emulator
"},{"location":"reference/bloqade/analog/builder/backend/quera/","title":"Quera","text":""},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute","title":"QuEraDeviceRoute","text":"
QuEraDeviceRoute(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.aquila","title":"aquila","text":"
aquila()\n

Specify QuEra's Aquila QPU

Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...aquila().submit :: submit aync remote job

    -> ...aquila().run :: submit job and wait until job finished and results returned

    -> ...aquila().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def aquila(self):\n    \"\"\"\n    Specify QuEra's Aquila QPU\n\n    Return:\n        QuEraHardwareRoutine\n\n\n    - Possible Next:\n\n        -> `...aquila().submit`\n            :: submit aync remote job\n\n        -> `...aquila().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...aquila().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n    \"\"\"\n    return self.parse().quera.aquila()\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.cloud_mock","title":"cloud_mock","text":"
cloud_mock()\n

Specify QuEra's Remote Mock QPU

Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...aquila().submit :: submit aync remote job

    -> ...aquila().run :: submit job and wait until job finished and results returned

    -> ...aquila().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def cloud_mock(self):\n    \"\"\"\n    Specify QuEra's Remote Mock QPU\n\n    Return:\n        QuEraHardwareRoutine\n\n    - Possible Next:\n\n        -> `...aquila().submit`\n            :: submit aync remote job\n\n        -> `...aquila().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...aquila().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n\n    \"\"\"\n    return self.parse().quera.cloud_mock()\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.custom","title":"custom","text":"
custom()\n

Specify custom backend

Return

CustomSubmissionRoutine

Source code in src/bloqade/analog/builder/backend/quera.py
def custom(self):\n    \"\"\"\n    Specify custom backend\n\n    Return:\n        CustomSubmissionRoutine\n\n    \"\"\"\n\n    return self.parse().quera.custom()\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.device","title":"device","text":"
device(config_file=None, **api_config)\n

Specify QuEra's QPU device,

Parameters:

Name Type Description Default config_file str

file that speficy the target hardware

None Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...device().submit :: submit aync remote job

    -> ...device().run :: submit job and wait until job finished and results returned

    -> ...device().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def device(self, config_file: Optional[str] = None, **api_config):\n    \"\"\"\n    Specify QuEra's QPU device,\n\n    Args:\n        config_file (str): file that speficy the target hardware\n\n    Return:\n        QuEraHardwareRoutine\n\n    - Possible Next:\n\n        -> `...device().submit`\n            :: submit aync remote job\n\n        -> `...device().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...device().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n    \"\"\"\n    return self.parse().quera.device(config_file, **api_config)\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.mock","title":"mock","text":"
mock(state_file='.mock_state.txt', submission_error=False)\n

Specify mock, testing locally.

Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...aquila().submit :: submit aync remote job

    -> ...aquila().run :: submit job and wait until job finished and results returned

    -> ...aquila().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def mock(self, state_file: str = \".mock_state.txt\", submission_error: bool = False):\n    \"\"\"\n    Specify mock, testing locally.\n\n    Return:\n        QuEraHardwareRoutine\n\n    - Possible Next:\n\n        -> `...aquila().submit`\n            :: submit aync remote job\n\n        -> `...aquila().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...aquila().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n\n    \"\"\"\n    return self.parse().quera.mock(\n        state_file=state_file, submission_error=submission_error\n    )\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraService","title":"QuEraService","text":"
QuEraService(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraService.quera","title":"quera property","text":"
quera\n
  • Specify Quera backend
  • Possible Next:

    -> ...quera.aquila :: Aquila QPU

    -> ...quera.mock :: mock backend, meant for testings

    -> ...quera.device :: QuEra QPU, specifiy by config_file

"},{"location":"reference/bloqade/analog/builder/parse/","title":"Index","text":""},{"location":"reference/bloqade/analog/builder/parse/builder/","title":"Builder","text":"

Module for parsing builder definitions into intermediate representation (IR) using the bloqade library.

This module provides a Parser class for parsing various components of a quantum computing program, including atom arrangements, pulse sequences, analog circuits, and routines. It also defines utility functions for reading addresses, waveforms, drives, sequences, registers, and pragmas from a builder stream.

"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser","title":"Parser","text":"

A class for parsing quantum computing program components into intermediate representation (IR).

"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse","title":"parse","text":"
parse(builder)\n

Parse a routine from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Name Type Description Routine Routine

The parsed routine.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse(self, builder: Builder) -> \"Routine\":\n    \"\"\"\n    Parse a routine from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        Routine: The parsed routine.\n    \"\"\"\n    from bloqade.analog.ir.routine.base import Routine\n    from bloqade.analog.ir.analog_circuit import AnalogCircuit\n    from bloqade.analog.ir.routine.params import Params, ScalarArg, VectorArg\n    from bloqade.analog.compiler.analysis.common.scan_variables import ScanVariables\n\n    self.reset(builder)\n    self.read_register()\n    self.read_sequence()\n    self.read_pragmas()\n\n    circuit = AnalogCircuit(self.register, self.sequence)\n\n    var_res = ScanVariables().scan(circuit)\n    # mark vector and scalar arguments\n    args_list = [\n        (VectorArg(name) if name in var_res.vector_vars else ScalarArg(name))\n        for name in self.order\n    ]\n\n    params = Params(\n        n_sites=self.register.n_sites,\n        static_params=self.static_params,\n        batch_params=self.batch_params,\n        args_list=args_list,\n    )\n\n    return Routine(builder, circuit, params)\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse_circuit","title":"parse_circuit","text":"
parse_circuit(builder)\n

Parse an analog circuit from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Name Type Description AnalogCircuit AnalogCircuit

The parsed analog circuit.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse_circuit(self, builder: Builder) -> \"AnalogCircuit\":\n    \"\"\"\n    Parse an analog circuit from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        AnalogCircuit: The parsed analog circuit.\n    \"\"\"\n    from bloqade.analog.ir.analog_circuit import AnalogCircuit\n\n    self.reset(builder)\n    self.read_register()\n    self.read_sequence()\n\n    circuit = AnalogCircuit(self.register, self.sequence)\n\n    return circuit\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse_register","title":"parse_register","text":"
parse_register(builder)\n

Parse an atom arrangement register from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Type Description Union[AtomArrangement, ParallelRegister]

Union[ir.AtomArrangement, ir.ParallelRegister]: The parsed atom arrangement or parallel register.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse_register(\n    self, builder: Builder\n) -> Union[ir.AtomArrangement, ir.ParallelRegister]:\n    \"\"\"\n    Parse an atom arrangement register from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        Union[ir.AtomArrangement, ir.ParallelRegister]: The parsed atom arrangement or parallel register.\n    \"\"\"\n    self.reset(builder)\n    self.read_register()\n    self.read_pragmas()\n    return self.register\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse_sequence","title":"parse_sequence","text":"
parse_sequence(builder)\n

Parse a sequence from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Type Description Sequence

ir.Sequence: The parsed sequence.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse_sequence(self, builder: Builder) -> ir.Sequence:\n    \"\"\"\n    Parse a sequence from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        ir.Sequence: The parsed sequence.\n    \"\"\"\n    self.reset(builder)\n    self.read_sequence()\n    return self.sequence\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_address","title":"read_address","text":"
read_address(stream)\n

Read an address from the builder stream.

Parameters:

Name Type Description Default stream

The builder stream.

required

Returns:

Type Description Tuple[LevelCoupling, Field, BuilderNode]

Tuple[LevelCoupling, Field, BuilderNode]: A tuple containing the level coupling, field, and spatial modulation.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_address(self, stream) -> Tuple[LevelCoupling, Field, BuilderNode]:\n    \"\"\"\n    Read an address from the builder stream.\n\n    Args:\n        stream: The builder stream.\n\n    Returns:\n        Tuple[LevelCoupling, Field, BuilderNode]: A tuple containing the level coupling, field, and spatial modulation.\n    \"\"\"\n    spatial = stream.read_next([Location, Uniform, Scale])\n    curr = spatial\n\n    if curr is None:\n        return (None, None, None)\n\n    while curr.next is not None:\n        if not isinstance(curr.node, SpatialModulation):\n            break\n        curr = curr.next\n\n    if type(spatial.node.__parent__) in [Detuning, RabiAmplitude, RabiPhase]:\n        field = spatial.node.__parent__  # field is updated\n        if type(field) in [RabiAmplitude, RabiPhase]:\n            coupling = field.__parent__.__parent__  # skip Rabi\n        else:\n            coupling = field.__parent__\n\n        # coupling not updated\n        if type(coupling) not in [Rydberg, Hyperfine]:\n            coupling = None\n        return (coupling, field, spatial)\n    else:  # only spatial is updated\n        return (None, None, spatial)\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_drive","title":"read_drive","text":"
read_drive(head)\n

Read a drive from the builder stream.

Parameters:

Name Type Description Default head

The head of the builder stream.

required

Returns:

Type Description Field

ir.Field: The drive field.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_drive(self, head) -> ir.Field:\n    \"\"\"\n    Read a drive from the builder stream.\n\n    Args:\n        head: The head of the builder stream.\n\n    Returns:\n        ir.Field: The drive field.\n    \"\"\"\n    if head is None:\n        return ir.Field({})\n\n    sm = head.node.__bloqade_ir__()\n    wf, _ = self.read_waveform(head.next)\n\n    return ir.Field({sm: wf})\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_pragmas","title":"read_pragmas","text":"
read_pragmas()\n

Read pragmas from the builder stream.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_pragmas(self) -> None:\n    \"\"\"Read pragmas from the builder stream.\"\"\"\n    pragma_types = (\n        Assign,\n        BatchAssign,\n        ListAssign,\n        Args,\n        Parallelize,\n    )\n\n    stream = self.stream.copy()\n    curr = stream.read_next(pragma_types)\n\n    while curr is not None:\n        node = curr.node\n\n        if isinstance(node, Assign):\n            self.static_params = dict(node._static_params)\n        elif isinstance(node, BatchAssign) or isinstance(node, ListAssign):\n            self.batch_params = node._batch_params\n        elif isinstance(node, Args):\n            order = node._order\n\n            seen = set()\n            dup = []\n            for x in order:\n                if x not in seen:\n                    seen.add(x)\n                else:\n                    dup.append(x)\n\n            if dup:\n                raise ValueError(f\"Cannot have duplicate names {dup}.\")\n\n            self.order = order\n\n        elif isinstance(node, Parallelize):\n            self.register = ir.ParallelRegister(\n                self.register, node._cluster_spacing\n            )\n        else:\n            break\n\n        curr = curr.next\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_register","title":"read_register","text":"
read_register()\n

Read an atom arrangement register from the builder stream.

Returns:

Type Description AtomArrangement

ir.AtomArrangement: The parsed atom arrangement.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_register(self) -> ir.AtomArrangement:\n    \"\"\"\n    Read an atom arrangement register from the builder stream.\n\n    Returns:\n        ir.AtomArrangement: The parsed atom arrangement.\n    \"\"\"\n    # register is always head of the stream\n    register_node = self.stream.read()\n    self.register = register_node.node\n\n    return self.register\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_sequence","title":"read_sequence","text":"
read_sequence()\n

Read a sequence from the builder stream.

Returns:

Type Description Sequence

ir.Sequence: The parsed sequence.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_sequence(self) -> ir.Sequence:\n    \"\"\"\n    Read a sequence from the builder stream.\n\n    Returns:\n        ir.Sequence: The parsed sequence.\n    \"\"\"\n    if isinstance(self.stream.curr.node, SequenceBuilder):\n        # case with sequence builder object.\n        self.sequence = self.stream.read().node._sequence\n        return self.sequence\n\n    stream = self.stream.copy()\n    while stream.curr is not None:\n        coupling_builder, field_builder, spatial_head = self.read_address(stream)\n\n        if coupling_builder is not None:\n            # update to new pulse coupling\n            self.coupling_name = coupling_builder.__bloqade_ir__()\n\n        if field_builder is not None:\n            # update to new field coupling\n            self.field_name = field_builder.__bloqade_ir__()\n\n        if spatial_head is None:\n            break\n\n        pulse = self.sequence.pulses.get(self.coupling_name, ir.Pulse({}))\n        field = pulse.fields.get(self.field_name, ir.Field({}))\n\n        drive = self.read_drive(spatial_head)\n        field = field.add(drive)\n\n        pulse = ir.Pulse.create(pulse.fields | {self.field_name: field})\n        self.sequence = ir.Sequence.create(\n            self.sequence.pulses | {self.coupling_name: pulse}\n        )\n\n    return self.sequence\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_waveform","title":"read_waveform","text":"
read_waveform(head)\n

Read a waveform from the builder stream.

Parameters:

Name Type Description Default head BuilderNode

The head of the builder stream.

required

Returns:

Type Description Tuple[Waveform, BuilderNode]

Tuple[ir.Waveform, BuilderNode]: A tuple containing the waveform and the next builder node.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_waveform(self, head: BuilderNode) -> Tuple[ir.Waveform, BuilderNode]:\n    \"\"\"\n    Read a waveform from the builder stream.\n\n    Args:\n        head (BuilderNode): The head of the builder stream.\n\n    Returns:\n        Tuple[ir.Waveform, BuilderNode]: A tuple containing the waveform and the next builder node.\n    \"\"\"\n    curr = head\n    waveform = None\n    while curr is not None:\n        node = curr.node\n\n        if isinstance(node, Slice):\n            waveform = waveform[node._start : node._stop]\n        elif isinstance(node, Record):\n            waveform = waveform.record(node._name)\n        elif isinstance(node, Sample):\n            interpolation = node._interpolation\n            if interpolation is None:\n                if self.field_name == ir.rabi.phase:\n                    interpolation = ir.Interpolation.Constant\n                else:\n                    interpolation = ir.Interpolation.Linear\n            fn_waveform = node.__parent__.__bloqade_ir__()\n            sample_waveform = ir.Sample(fn_waveform, interpolation, node._dt)\n            if waveform is None:\n                waveform = sample_waveform\n            else:\n                waveform = waveform.append(sample_waveform)\n        elif (\n            isinstance(node, Fn)\n            and curr.next is not None\n            and isinstance(curr.next.node, Sample)\n        ):\n            pass\n        elif isinstance(node, WaveformPrimitive):\n            if waveform is None:\n                waveform = node.__bloqade_ir__()\n            else:\n                waveform = waveform.append(node.__bloqade_ir__())\n        else:\n            break\n\n        curr = curr.next\n\n    return waveform, curr\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.reset","title":"reset","text":"
reset(builder)\n

Reset the parser's state.

Source code in src/bloqade/analog/builder/parse/builder.py
def reset(self, builder: Builder):\n    \"\"\"Reset the parser's state.\"\"\"\n    self.stream = BuilderStream.create(builder)\n    self.vector_node_names = set()\n    self.sequence = ir.Sequence.create()\n    self.register = None\n    self.batch_params = [{}]\n    self.static_params = {}\n    self.order = ()\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/","title":"Stream","text":"

Module for managing a stream of builder nodes.

This module provides classes to represent builder nodes and builder streams. A builder node is a single element in the stream, representing a step in a construction process. A builder stream is a sequence of builder nodes, allowing traversal and manipulation of the construction steps.

"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderNode","title":"BuilderNode dataclass","text":"
BuilderNode(node, next=None)\n

A node in the builder stream.

"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderNode.__repr__","title":"__repr__","text":"
__repr__()\n

Representation of the BuilderNode.

Source code in src/bloqade/analog/builder/parse/stream.py
def __repr__(self) -> str:\n    \"\"\"Representation of the BuilderNode.\"\"\"\n    return repr(self.node)\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream","title":"BuilderStream dataclass","text":"
BuilderStream(head, curr=None)\n

Represents a stream of builder nodes.

"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.__iter__","title":"__iter__","text":"
__iter__()\n

Iterator method to iterate over the builder stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def __iter__(self):\n    \"\"\"Iterator method to iterate over the builder stream.\"\"\"\n    return self\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.__next__","title":"__next__","text":"
__next__()\n

Next method to get the next item in the builder stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def __next__(self):\n    \"\"\"Next method to get the next item in the builder stream.\"\"\"\n    node = self.read()\n    if node is None:\n        raise StopIteration\n    return node\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.build_nodes","title":"build_nodes staticmethod","text":"
build_nodes(node)\n

Build BuilderNode instances from the provided Builder.

Parameters:

Name Type Description Default node Builder

The root Builder instance.

required

Returns:

Name Type Description BuilderNode BuilderNode

The head of the linked list of BuilderNodes.

Source code in src/bloqade/analog/builder/parse/stream.py
@staticmethod\ndef build_nodes(node: Builder) -> \"BuilderNode\":\n    \"\"\"\n    Build BuilderNode instances from the provided Builder.\n\n    Args:\n        node (Builder): The root Builder instance.\n\n    Returns:\n        BuilderNode: The head of the linked list of BuilderNodes.\n    \"\"\"\n    curr = node\n    node = None\n    while curr is not None:\n        next = curr\n        curr = curr.__parent__ if hasattr(curr, \"__parent__\") else None\n        node = BuilderNode(next, node)\n\n    return node\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.copy","title":"copy","text":"
copy()\n

Create a copy of the builder stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def copy(self) -> \"BuilderStream\":\n    \"\"\"Create a copy of the builder stream.\"\"\"\n    return BuilderStream(head=self.head, curr=self.curr)\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.create","title":"create staticmethod","text":"
create(builder)\n

Create a BuilderStream instance from a Builder.

Parameters:

Name Type Description Default builder Builder

The root Builder instance.

required

Returns:

Name Type Description BuilderStream BuilderStream

The created BuilderStream instance.

Source code in src/bloqade/analog/builder/parse/stream.py
@staticmethod\ndef create(builder: Builder) -> \"BuilderStream\":\n    \"\"\"\n    Create a BuilderStream instance from a Builder.\n\n    Args:\n        builder (Builder): The root Builder instance.\n\n    Returns:\n        BuilderStream: The created BuilderStream instance.\n    \"\"\"\n    head = BuilderStream.build_nodes(builder)\n    return BuilderStream(head=head, curr=head)\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.eat","title":"eat","text":"
eat(types, skips=None)\n

Move the stream pointer until a node of specified types is found.

Parameters:

Name Type Description Default types List[Type[Builder]]

List of types to move the stream pointer to.

required skips List[Type[Builder]] | None

List of types to end the stream scan.

None

Returns:

Name Type Description BuilderNode BuilderNode

The beginning of the stream which matches a type in types.

Source code in src/bloqade/analog/builder/parse/stream.py
def eat(\n    self, types: List[Type[Builder]], skips: Optional[List[Type[Builder]]] = None\n) -> BuilderNode:\n    \"\"\"\n    Move the stream pointer until a node of specified types is found.\n\n    Args:\n        types (List[Type[Builder]]): List of types to move the stream pointer to.\n        skips (List[Type[Builder]] | None, optional): List of types to end the stream scan.\n\n    Returns:\n        BuilderNode: The beginning of the stream which matches a type in `types`.\n    \"\"\"\n    head = self.read_next(types)\n    curr = head\n    while curr is not None:\n        if type(curr.node) not in types:\n            if skips and type(curr.node) not in skips:\n                break\n        curr = curr.next\n    self.curr = curr\n    return head\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.read","title":"read","text":"
read()\n

Read the next builder node from the stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def read(self) -> Optional[BuilderNode]:\n    \"\"\"Read the next builder node from the stream.\"\"\"\n    if self.curr is None:\n        return None\n\n    node = self.curr\n    self.curr = self.curr.next\n    return node\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.read_next","title":"read_next","text":"
read_next(builder_types)\n

Read the next builder node of specified types from the stream.

Parameters:

Name Type Description Default builder_types List[type[Builder]]

List of builder types to read from the stream.

required

Returns:

Type Description Optional[BuilderNode]

Optional[BuilderNode]: The next builder node matching one of the specified types, or None if not found.

Source code in src/bloqade/analog/builder/parse/stream.py
def read_next(self, builder_types: List[type[Builder]]) -> Optional[BuilderNode]:\n    \"\"\"\n    Read the next builder node of specified types from the stream.\n\n    Args:\n        builder_types (List[type[Builder]]): List of builder types to read from the stream.\n\n    Returns:\n        Optional[BuilderNode]: The next builder node matching one of the specified types, or None if not found.\n    \"\"\"\n    node = self.read()\n    while node is not None:\n        if type(node.node) in builder_types:\n            return node\n        node = self.read()\n    return None\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/","title":"Trait","text":"

Module for parsing and displaying quantum computing program components using the bloqade library.

"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Parse","title":"Parse","text":"

Bases: ParseRegister, ParseSequence, ParseCircuit, ParseRoutine

A composite class inheriting from ParseRegister, ParseSequence, ParseCircuit, and ParseRoutine. Provides a unified interface for parsing different components of the program.

"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Parse.n_atoms","title":"n_atoms property","text":"
n_atoms\n

Return the number of atoms in the program.

Returns:

Name Type Description int int

The number of atoms in the parsed register.

Raises:

Type Description ValueError

If the register type is unsupported.

Note

If the register is of type ParallelRegister, the number of atoms is extracted from its internal register.

Example:

>>> class MyBuilder(Parse):\n...     pass\n>>> builder = MyBuilder()\n>>> n_atoms = builder.n_atoms\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseCircuit","title":"ParseCircuit","text":"

A class providing functionality to parse the analog circuit from the program.

Example:

>>> class MyBuilder(ParseCircuit):\n...     pass\n>>> builder = MyBuilder()\n>>> analog_circuit = builder.parse_circuit()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseCircuit.parse_circuit","title":"parse_circuit","text":"
parse_circuit()\n

Parse the analog circuit from the program.

Returns:

Name Type Description AnalogCircuit AnalogCircuit

The parsed analog circuit.

Raises:

Type Description ValueError

If the circuit cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse_circuit(self: \"Builder\") -> \"AnalogCircuit\":\n    \"\"\"\n    Parse the analog circuit from the program.\n\n    Returns:\n        AnalogCircuit: The parsed analog circuit.\n\n    Raises:\n        ValueError: If the circuit cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse_circuit(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRegister","title":"ParseRegister","text":"

A class providing functionality to parse the arrangement of atoms in the program.

Example:

>>> class MyBuilder(ParseRegister):\n...     pass\n>>> builder = MyBuilder()\n>>> atom_arrangement = builder.parse_register()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRegister.parse_register","title":"parse_register","text":"
parse_register()\n

Parse the arrangement of atoms in the program.

Returns:

Type Description Union[AtomArrangement, ParallelRegister]

Union[AtomArrangement, ParallelRegister]: The parsed atom arrangement or parallel register.

Raises:

Type Description ValueError

If the register cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse_register(self: \"Builder\") -> Union[\"AtomArrangement\", \"ParallelRegister\"]:\n    \"\"\"\n    Parse the arrangement of atoms in the program.\n\n    Returns:\n        Union[AtomArrangement, ParallelRegister]: The parsed atom arrangement or parallel register.\n\n    Raises:\n        ValueError: If the register cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse_register(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRoutine","title":"ParseRoutine","text":"

A class providing functionality to parse the program and return a Routine object.

Example:

>>> class MyBuilder(ParseRoutine):\n...     pass\n>>> builder = MyBuilder()\n>>> routine = builder.parse()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRoutine.parse","title":"parse","text":"
parse()\n

Parse the program to return a Routine object.

Returns:

Name Type Description Routine Routine

The parsed routine object.

Raises:

Type Description ValueError

If the routine cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse(self: \"Builder\") -> \"Routine\":\n    \"\"\"\n    Parse the program to return a Routine object.\n\n    Returns:\n        Routine: The parsed routine object.\n\n    Raises:\n        ValueError: If the routine cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseSequence","title":"ParseSequence","text":"

A class providing functionality to parse the pulse sequence part of the program.

Example:

>>> class MyBuilder(ParseSequence):\n...     pass\n>>> builder = MyBuilder()\n>>> sequence = builder.parse_sequence()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseSequence.parse_sequence","title":"parse_sequence","text":"
parse_sequence()\n

Parse the pulse sequence part of the program.

Returns:

Name Type Description Sequence Sequence

The parsed pulse sequence.

Raises:

Type Description ValueError

If the sequence cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse_sequence(self: \"Builder\") -> \"Sequence\":\n    \"\"\"\n    Parse the pulse sequence part of the program.\n\n    Returns:\n        Sequence: The parsed pulse sequence.\n\n    Raises:\n        ValueError: If the sequence cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse_sequence(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Show","title":"Show","text":"

A mixin class providing functionality to display the builder with given arguments and batch ID.

"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Show.show","title":"show","text":"
show(*args, batch_id=0)\n

Display the current program being defined with the given arguments and batch ID.

Parameters:

Name Type Description Default *args

Additional arguments for display.

() batch_id int

The batch ID to be displayed. Defaults to 0.

0 Note

This method uses the display_builder function to render the builder's state.

Example:

>>> class MyBuilder(Show):\n...     pass\n>>> builder = MyBuilder()\n>>> builder.show()\n>>> builder.show(batch_id=1)\n>>> builder.show('arg1', 'arg2', batch_id=2)\n
Source code in src/bloqade/analog/builder/parse/trait.py
def show(self, *args, batch_id: int = 0):\n    \"\"\"\n    Display the current program being defined with the given arguments and batch ID.\n\n    Args:\n        *args: Additional arguments for display.\n        batch_id (int, optional): The batch ID to be displayed. Defaults to 0.\n\n    Note:\n        This method uses the `display_builder` function to render the builder's state.\n\n    Example:\n\n    ```python\n    >>> class MyBuilder(Show):\n    ...     pass\n    >>> builder = MyBuilder()\n    >>> builder.show()\n    >>> builder.show(batch_id=1)\n    >>> builder.show('arg1', 'arg2', batch_id=2)\n    ```\n    \"\"\"\n    display_builder(self, batch_id, *args)\n
"},{"location":"reference/bloqade/analog/compiler/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/assignment_scan/","title":"Assignment scan","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/check_slices/","title":"Check slices","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/is_constant/","title":"Is constant","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/is_hyperfine/","title":"Is hyperfine","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/scan_channels/","title":"Scan channels","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/scan_variables/","title":"Scan variables","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/#bloqade.analog.compiler.analysis.hardware.BasicLatticeValidation","title":"BasicLatticeValidation","text":"
BasicLatticeValidation(capabilities)\n

Bases: BloqadeIRVisitor

This visitor checks that the AtomArrangement is within the bounds of the lattice and that the number of sites is within the maximum number of sites.

Source code in src/bloqade/analog/compiler/analysis/hardware/lattice.py
def __init__(self, capabilities: QuEraCapabilities):\n    self.capabilities = capabilities\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/#bloqade.analog.compiler.analysis.hardware.ValidateChannels","title":"ValidateChannels","text":"
ValidateChannels()\n

Bases: BloqadeIRVisitor

Checks to make sure the given sequence can be compiled to hardware.

This check looks at the spatial modulations and the level coupling to determine if the sequence can be compiled to hardware.

Source code in src/bloqade/analog/compiler/analysis/hardware/channels.py
def __init__(self):\n    self.field_name = None\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/channels/","title":"Channels","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/channels/#bloqade.analog.compiler.analysis.hardware.channels.ValidateChannels","title":"ValidateChannels","text":"
ValidateChannels()\n

Bases: BloqadeIRVisitor

Checks to make sure the given sequence can be compiled to hardware.

This check looks at the spatial modulations and the level coupling to determine if the sequence can be compiled to hardware.

Source code in src/bloqade/analog/compiler/analysis/hardware/channels.py
def __init__(self):\n    self.field_name = None\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/lattice/","title":"Lattice","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/lattice/#bloqade.analog.compiler.analysis.hardware.lattice.BasicLatticeValidation","title":"BasicLatticeValidation","text":"
BasicLatticeValidation(capabilities)\n

Bases: BloqadeIRVisitor

This visitor checks that the AtomArrangement is within the bounds of the lattice and that the number of sites is within the maximum number of sites.

Source code in src/bloqade/analog/compiler/analysis/hardware/lattice.py
def __init__(self, capabilities: QuEraCapabilities):\n    self.capabilities = capabilities\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/piecewise_constant/","title":"Piecewise constant","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/piecewise_linear/","title":"Piecewise linear","text":""},{"location":"reference/bloqade/analog/compiler/analysis/python/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/python/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/compiler/passes/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/passes/emulator/","title":"Emulator","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.analyze_channels","title":"analyze_channels","text":"
analyze_channels(circuit)\n
  1. Scan channels

This pass checks to make sure that: * There is no hyperfine coupling in the sequence * There are no non-uniform spatial modulation for rabi phase and amplitude * there is no more than one non-uniform spatial modulation for detuning

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to analyze

required

Returns:

Name Type Description level_couplings Dict

Dictionary containing the required channels for the sequence. Note that this will insert a uniform field for any missing channels.

Raises:

Type Description ValueError

If there is hyperfine coupling in the sequence.

ValueError

If there is more than one non-uniform spatial modulation for detuning.

ValueError

If there are non-uniform spatial modulations for rabi phase and amplitude.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def analyze_channels(circuit: analog_circuit.AnalogCircuit) -> Dict:\n    \"\"\"1. Scan channels\n\n    This pass checks to make sure that:\n    * There is no hyperfine coupling in the sequence\n    * There are no non-uniform spatial modulation for rabi phase and amplitude\n    * there is no more than one non-uniform spatial modulation for detuning\n\n    Args:\n        circuit: AnalogCircuit to analyze\n\n    Returns:\n        level_couplings: Dictionary containing the required channels for the\n            sequence. Note that this will insert a uniform field for any missing\n            channels.\n\n    Raises:\n        ValueError: If there is hyperfine coupling in the sequence.\n        ValueError: If there is more than one non-uniform spatial modulation for\n            detuning.\n        ValueError: If there are non-uniform spatial modulations for rabi phase\n            and amplitude.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import ScanChannels\n    from bloqade.analog.compiler.analysis.hardware import ValidateChannels\n\n    ValidateChannels().scan(circuit)\n    level_couplings = ScanChannels().scan(circuit)\n\n    # add missing channels\n    fields = level_couplings[sequence.rydberg]\n    # detuning, phase and amplitude are required\n    # to have at least a uniform field\n    updated_fields = {\n        field_name: fields.get(field_name, {field.Uniform}).union({field.Uniform})\n        for field_name in [pulse.detuning, pulse.rabi.amplitude, pulse.rabi.phase]\n    }\n\n    return {sequence.rydberg: updated_fields}\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.assign_circuit","title":"assign_circuit","text":"
assign_circuit(circuit, assignments)\n
  1. Assign variables and validate assignment

This pass assigns variables to the circuit and validates that all variables have been assigned.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to assign variables to

required assignments Dict[str, ParamType]

Dictionary containing the assignments for the variables in the circuit.

required

Returns:

Name Type Description assigned_circuit Tuple[AnalogCircuit, Dict]

AnalogCircuit with variables assigned.

Raises:

Type Description ValueError

If there are any variables that have not been assigned.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def assign_circuit(\n    circuit: analog_circuit.AnalogCircuit, assignments: Dict[str, ParamType]\n) -> Tuple[analog_circuit.AnalogCircuit, Dict]:\n    \"\"\"3. Assign variables and validate assignment\n\n    This pass assigns variables to the circuit and validates that all variables\n    have been assigned.\n\n    Args:\n        circuit: AnalogCircuit to assign variables to\n        assignments: Dictionary containing the assignments for the variables in\n            the circuit.\n\n    Returns:\n        assigned_circuit: AnalogCircuit with variables assigned.\n\n    Raises:\n        ValueError: If there are any variables that have not been assigned.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import AssignBloqadeIR\n    from bloqade.analog.compiler.analysis.common import ScanVariables, AssignmentScan\n\n    final_assignments = AssignmentScan(assignments).scan(circuit)\n\n    assigned_circuit = AssignBloqadeIR(final_assignments).visit(circuit)\n\n    assignment_analysis = ScanVariables().scan(assigned_circuit)\n\n    if not assignment_analysis.is_assigned:\n        missing_vars = assignment_analysis.scalar_vars.union(\n            assignment_analysis.vector_vars\n        )\n        raise ValueError(\n            \"Missing assignments for variables:\\n\"\n            + (\"\\n\".join(f\"{var}\" for var in missing_vars))\n            + \"\\n\"\n        )\n\n    return assigned_circuit, final_assignments\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.canonicalize_circuit","title":"canonicalize_circuit","text":"
canonicalize_circuit(circuit, level_couplings)\n
  1. Insert zero waveform in the explicit time intervals missing a waveform

This pass inserts a zero waveform in the explicit time intervals missing a waveform. This is required for later analysis passes to check that the waveforms are compatible with the hardware.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to add padding to

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Return circuit: AnalogCircuit with zero waveforms inserted in the explicit time intervals missing a waveform.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def canonicalize_circuit(\n    circuit: analog_circuit.AnalogCircuit, level_couplings: Dict\n) -> analog_circuit.AnalogCircuit:\n    \"\"\"2. Insert zero waveform in the explicit time intervals missing a waveform\n\n    This pass inserts a zero waveform in the explicit time intervals missing a\n    waveform. This is required for later analysis passes to check that the\n    waveforms are compatible with the hardware.\n\n    Args:\n        circuit: AnalogCircuit to add padding to\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Return\n        circuit: AnalogCircuit with zero waveforms inserted in the explicit time\n            intervals missing a waveform.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import (\n        AddPadding,\n        Canonicalizer,\n        AssignToLiteral,\n    )\n\n    circuit = AddPadding(level_couplings).visit(circuit)\n    # these two passes are equivalent to a constant propagation pass\n    circuit = AssignToLiteral().visit(circuit)\n    circuit = Canonicalizer().visit(circuit)\n\n    return circuit\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.generate_ahs_code","title":"generate_ahs_code","text":"
generate_ahs_code(capabilities, level_couplings, circuit)\n
  1. generate ahs code

Generates the AHS code for the given circuit. This includes generating the lattice data, global detuning, global amplitude, global phase, local detuning and lattice site coefficients (if applicable).

Parameters:

Name Type Description Default capabilities QuEraCapabilities | None

Capabilities of the hardware.

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required circuit AnalogCircuit

AnalogCircuit to generate AHS code for.

required

Returns:

Name Type Description ahs_components AHSComponents

A collection of the AHS components generated for the given circuit. Can be used to generate the QuEra and Braket IR.

Raises:

Type Description ValueError

If the capabilities are not provided but the circuit has a ParallelRegister. This is because the ParallelRegister requires the capabilities to generate the lattice data.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_ahs_code(\n    capabilities: Optional[QuEraCapabilities],\n    level_couplings: Dict,\n    circuit: analog_circuit.AnalogCircuit,\n) -> AHSComponents:\n    \"\"\"5. generate ahs code\n\n    Generates the AHS code for the given circuit. This includes generating the\n    lattice data, global detuning, global amplitude, global phase, local\n    detuning and lattice site coefficients (if applicable).\n\n    Args:\n        capabilities (QuEraCapabilities | None): Capabilities of the hardware.\n        level_couplings (Dict): Dictionary containing the given channels for the\n            sequence.\n        circuit (AnalogCircuit): AnalogCircuit to generate AHS code for.\n\n    Returns:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit. Can be used to generate the QuEra\n            and Braket IR.\n\n    Raises:\n        ValueError: If the capabilities are not provided but the circuit has\n            a ParallelRegister. This is because the ParallelRegister requires\n            the capabilities to generate the lattice data.\n\n    \"\"\"\n    from bloqade.analog.compiler.codegen.hardware import (\n        GenerateLattice,\n        GeneratePiecewiseLinearChannel,\n        GenerateLatticeSiteCoefficients,\n        GeneratePiecewiseConstantChannel,\n    )\n    from bloqade.analog.compiler.analysis.hardware import BasicLatticeValidation\n\n    if capabilities is not None:\n        # only validate the lattice if capabilities are provided\n        BasicLatticeValidation(capabilities).visit(circuit)\n\n    ahs_lattice_data = GenerateLattice(capabilities).emit(circuit)\n\n    global_detuning = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.detuning, field.Uniform\n    ).visit(circuit)\n\n    global_amplitude = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.rabi.amplitude, field.Uniform\n    ).visit(circuit)\n\n    global_phase = GeneratePiecewiseConstantChannel(\n        sequence.rydberg, pulse.rabi.phase, field.Uniform\n    ).visit(circuit)\n\n    local_detuning = None\n    lattice_site_coefficients = None\n\n    extra_sm = set(level_couplings[sequence.rydberg][pulse.detuning]) - {field.Uniform}\n\n    if extra_sm:\n        if capabilities is not None and capabilities.capabilities.rydberg.local is None:\n            raise ValueError(\n                \"Device does not support local detuning, but the program has a \"\n                \"non-uniform spatial modulation for detuning.\"\n            )\n\n        sm = extra_sm.pop()\n\n        lattice_site_coefficients = GenerateLatticeSiteCoefficients(\n            parallel_decoder=ahs_lattice_data.parallel_decoder\n        ).emit(circuit)\n\n        local_detuning = GeneratePiecewiseLinearChannel(\n            sequence.rydberg, pulse.detuning, sm\n        ).visit(circuit)\n\n    return AHSComponents(\n        lattice_data=ahs_lattice_data,\n        global_detuning=global_detuning,\n        global_amplitude=global_amplitude,\n        global_phase=global_phase,\n        local_detuning=local_detuning,\n        lattice_site_coefficients=lattice_site_coefficients,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.generate_braket_ir","title":"generate_braket_ir","text":"
generate_braket_ir(ahs_components, shots)\n
  1. generate braket ir

This pass takes the AHS components and generates the Braket IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification BraketTaskSpecification

Braket IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_braket_ir(\n    ahs_components: AHSComponents, shots: int\n) -> BraketTaskSpecification:\n    \"\"\"7. generate braket ir\n\n    This pass takes the AHS components and generates the Braket IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (BraketTaskSpecification): Braket IR for the given\n            circuit.\n\n    \"\"\"\n    import braket.ir.ahs as ahs\n\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    ahs_register = ahs.AtomArrangement(\n        sites=list(map(convert_coordinate_units, ahs_components.lattice_data.sites)),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning_time_series = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning_time_series = ahs.TimeSeries(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n        )\n\n    amplitude_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    phase_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = ahs.PhysicalField(\n        time_series=global_detuning_time_series,\n        pattern=\"uniform\",\n    )\n\n    amplitude = ahs.PhysicalField(\n        time_series=amplitude_time_series,\n        pattern=\"uniform\",\n    )\n\n    phase = ahs.PhysicalField(\n        time_series=phase_time_series,\n        pattern=\"uniform\",\n    )\n\n    local_detuning = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = ahs.PhysicalField(\n            time_series=local_detuning_time_series,\n            pattern=ahs_components.lattice_site_coefficients,\n        )\n\n    driving_field = ahs.DrivingField(\n        detuning=detuning,\n        amplitude=amplitude,\n        phase=phase,\n    )\n\n    shiftingFields = []\n    if ahs_components.lattice_site_coefficients is not None:\n        shiftingFields = [ahs.ShiftingField(magnitude=local_detuning)]\n\n    program = ahs.Program(\n        setup=ahs.Setup(ahs_register=ahs_register),\n        hamiltonian=ahs.Hamiltonian(\n            drivingFields=[driving_field],\n            shiftingFields=shiftingFields,\n        ),\n    )\n\n    return BraketTaskSpecification(nshots=shots, program=program)\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.generate_quera_ir","title":"generate_quera_ir","text":"
generate_quera_ir(ahs_components, shots)\n
  1. generate quera ir

This pass takes the AHS components and generates the QuEra IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification QuEraTaskSpecification

QuEra IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_quera_ir(\n    ahs_components: AHSComponents, shots: int\n) -> QuEraTaskSpecification:\n    \"\"\"7. generate quera ir\n\n    This pass takes the AHS components and generates the QuEra IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (QuEraTaskSpecification): QuEra IR for the given\n            circuit.\n\n    \"\"\"\n    import bloqade.analog.submission.ir.task_specification as task_spec\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    lattice = task_spec.Lattice(\n        sites=list(\n            map(\n                convert_coordinate_units,\n                ahs_components.lattice_data.sites,\n            )\n        ),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning = None\n\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = task_spec.LocalField(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n            lattice_site_coefficients=ahs_components.lattice_site_coefficients,\n        )\n\n    rabi_frequency_amplitude_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    rabi_frequency_phase_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = task_spec.Detuning(\n        global_=global_detuning,\n        local=local_detuning,\n    )\n\n    rabi_frequency_amplitude = task_spec.RabiFrequencyAmplitude(\n        global_=rabi_frequency_amplitude_field,\n    )\n\n    rabi_frequency_phase = task_spec.RabiFrequencyPhase(\n        global_=rabi_frequency_phase_field,\n    )\n\n    rydberg = task_spec.RydbergHamiltonian(\n        rabi_frequency_amplitude=rabi_frequency_amplitude,\n        rabi_frequency_phase=rabi_frequency_phase,\n        detuning=detuning,\n    )\n\n    effective_hamiltonian = task_spec.EffectiveHamiltonian(\n        rydberg=rydberg,\n    )\n\n    return task_spec.QuEraTaskSpecification(\n        nshots=shots,\n        lattice=lattice,\n        effective_hamiltonian=effective_hamiltonian,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.validate_waveforms","title":"validate_waveforms","text":"
validate_waveforms(level_couplings, circuit)\n
  1. validate piecewise linear and piecewise constant pieces of pulses

This pass check to make sure that the waveforms are compatible with the hardware. This includes checking that the waveforms are piecewise linear or piecewise constant. It also checks that the waveforms are compatible with the given channels.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to validate waveforms for

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Raises:

Type Description ValueError

If the waveforms are not piecewise linear or piecewise constant, e.g. the waveform is not continuous.

ValueError

If a waveform segment is not compatible with the given channels.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def validate_waveforms(\n    level_couplings: Dict, circuit: analog_circuit.AnalogCircuit\n) -> None:\n    \"\"\"4. validate piecewise linear and piecewise constant pieces of pulses\n\n    This pass check to make sure that the waveforms are compatible with the\n    hardware. This includes checking that the waveforms are piecewise linear or\n    piecewise constant. It also checks that the waveforms are compatible with\n    the given channels.\n\n    Args:\n        circuit: AnalogCircuit to validate waveforms for\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Raises:\n        ValueError: If the waveforms are not piecewise linear or piecewise\n            constant, e.g. the waveform is not continuous.\n        ValueError: If a waveform segment is not compatible with the given\n            channels.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import CheckSlices\n    from bloqade.analog.compiler.analysis.hardware import (\n        ValidatePiecewiseLinearChannel,\n        ValidatePiecewiseConstantChannel,\n    )\n\n    channel_iter = (\n        (level_coupling, field_name, sm)\n        for level_coupling, fields in level_couplings.items()\n        for field_name, spatial_modulations in fields.items()\n        for sm in spatial_modulations\n    )\n    for channel in channel_iter:\n        if channel[1] in [pulse.detuning, pulse.rabi.amplitude]:\n            ValidatePiecewiseLinearChannel(*channel).visit(circuit)\n        else:\n            ValidatePiecewiseConstantChannel(*channel).visit(circuit)\n\n    CheckSlices().visit(circuit)\n\n    if circuit.sequence.duration() == 0:\n        raise ValueError(\"Circuit Duration must be be non-zero\")\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/components/","title":"Components","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/","title":"Define","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.analyze_channels","title":"analyze_channels","text":"
analyze_channels(circuit)\n
  1. Scan channels

This pass checks to make sure that: * There is no hyperfine coupling in the sequence * There are no non-uniform spatial modulation for rabi phase and amplitude * there is no more than one non-uniform spatial modulation for detuning

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to analyze

required

Returns:

Name Type Description level_couplings Dict

Dictionary containing the required channels for the sequence. Note that this will insert a uniform field for any missing channels.

Raises:

Type Description ValueError

If there is hyperfine coupling in the sequence.

ValueError

If there is more than one non-uniform spatial modulation for detuning.

ValueError

If there are non-uniform spatial modulations for rabi phase and amplitude.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def analyze_channels(circuit: analog_circuit.AnalogCircuit) -> Dict:\n    \"\"\"1. Scan channels\n\n    This pass checks to make sure that:\n    * There is no hyperfine coupling in the sequence\n    * There are no non-uniform spatial modulation for rabi phase and amplitude\n    * there is no more than one non-uniform spatial modulation for detuning\n\n    Args:\n        circuit: AnalogCircuit to analyze\n\n    Returns:\n        level_couplings: Dictionary containing the required channels for the\n            sequence. Note that this will insert a uniform field for any missing\n            channels.\n\n    Raises:\n        ValueError: If there is hyperfine coupling in the sequence.\n        ValueError: If there is more than one non-uniform spatial modulation for\n            detuning.\n        ValueError: If there are non-uniform spatial modulations for rabi phase\n            and amplitude.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import ScanChannels\n    from bloqade.analog.compiler.analysis.hardware import ValidateChannels\n\n    ValidateChannels().scan(circuit)\n    level_couplings = ScanChannels().scan(circuit)\n\n    # add missing channels\n    fields = level_couplings[sequence.rydberg]\n    # detuning, phase and amplitude are required\n    # to have at least a uniform field\n    updated_fields = {\n        field_name: fields.get(field_name, {field.Uniform}).union({field.Uniform})\n        for field_name in [pulse.detuning, pulse.rabi.amplitude, pulse.rabi.phase]\n    }\n\n    return {sequence.rydberg: updated_fields}\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.assign_circuit","title":"assign_circuit","text":"
assign_circuit(circuit, assignments)\n
  1. Assign variables and validate assignment

This pass assigns variables to the circuit and validates that all variables have been assigned.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to assign variables to

required assignments Dict[str, ParamType]

Dictionary containing the assignments for the variables in the circuit.

required

Returns:

Name Type Description assigned_circuit Tuple[AnalogCircuit, Dict]

AnalogCircuit with variables assigned.

Raises:

Type Description ValueError

If there are any variables that have not been assigned.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def assign_circuit(\n    circuit: analog_circuit.AnalogCircuit, assignments: Dict[str, ParamType]\n) -> Tuple[analog_circuit.AnalogCircuit, Dict]:\n    \"\"\"3. Assign variables and validate assignment\n\n    This pass assigns variables to the circuit and validates that all variables\n    have been assigned.\n\n    Args:\n        circuit: AnalogCircuit to assign variables to\n        assignments: Dictionary containing the assignments for the variables in\n            the circuit.\n\n    Returns:\n        assigned_circuit: AnalogCircuit with variables assigned.\n\n    Raises:\n        ValueError: If there are any variables that have not been assigned.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import AssignBloqadeIR\n    from bloqade.analog.compiler.analysis.common import ScanVariables, AssignmentScan\n\n    final_assignments = AssignmentScan(assignments).scan(circuit)\n\n    assigned_circuit = AssignBloqadeIR(final_assignments).visit(circuit)\n\n    assignment_analysis = ScanVariables().scan(assigned_circuit)\n\n    if not assignment_analysis.is_assigned:\n        missing_vars = assignment_analysis.scalar_vars.union(\n            assignment_analysis.vector_vars\n        )\n        raise ValueError(\n            \"Missing assignments for variables:\\n\"\n            + (\"\\n\".join(f\"{var}\" for var in missing_vars))\n            + \"\\n\"\n        )\n\n    return assigned_circuit, final_assignments\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.canonicalize_circuit","title":"canonicalize_circuit","text":"
canonicalize_circuit(circuit, level_couplings)\n
  1. Insert zero waveform in the explicit time intervals missing a waveform

This pass inserts a zero waveform in the explicit time intervals missing a waveform. This is required for later analysis passes to check that the waveforms are compatible with the hardware.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to add padding to

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Return circuit: AnalogCircuit with zero waveforms inserted in the explicit time intervals missing a waveform.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def canonicalize_circuit(\n    circuit: analog_circuit.AnalogCircuit, level_couplings: Dict\n) -> analog_circuit.AnalogCircuit:\n    \"\"\"2. Insert zero waveform in the explicit time intervals missing a waveform\n\n    This pass inserts a zero waveform in the explicit time intervals missing a\n    waveform. This is required for later analysis passes to check that the\n    waveforms are compatible with the hardware.\n\n    Args:\n        circuit: AnalogCircuit to add padding to\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Return\n        circuit: AnalogCircuit with zero waveforms inserted in the explicit time\n            intervals missing a waveform.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import (\n        AddPadding,\n        Canonicalizer,\n        AssignToLiteral,\n    )\n\n    circuit = AddPadding(level_couplings).visit(circuit)\n    # these two passes are equivalent to a constant propagation pass\n    circuit = AssignToLiteral().visit(circuit)\n    circuit = Canonicalizer().visit(circuit)\n\n    return circuit\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.generate_ahs_code","title":"generate_ahs_code","text":"
generate_ahs_code(capabilities, level_couplings, circuit)\n
  1. generate ahs code

Generates the AHS code for the given circuit. This includes generating the lattice data, global detuning, global amplitude, global phase, local detuning and lattice site coefficients (if applicable).

Parameters:

Name Type Description Default capabilities QuEraCapabilities | None

Capabilities of the hardware.

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required circuit AnalogCircuit

AnalogCircuit to generate AHS code for.

required

Returns:

Name Type Description ahs_components AHSComponents

A collection of the AHS components generated for the given circuit. Can be used to generate the QuEra and Braket IR.

Raises:

Type Description ValueError

If the capabilities are not provided but the circuit has a ParallelRegister. This is because the ParallelRegister requires the capabilities to generate the lattice data.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_ahs_code(\n    capabilities: Optional[QuEraCapabilities],\n    level_couplings: Dict,\n    circuit: analog_circuit.AnalogCircuit,\n) -> AHSComponents:\n    \"\"\"5. generate ahs code\n\n    Generates the AHS code for the given circuit. This includes generating the\n    lattice data, global detuning, global amplitude, global phase, local\n    detuning and lattice site coefficients (if applicable).\n\n    Args:\n        capabilities (QuEraCapabilities | None): Capabilities of the hardware.\n        level_couplings (Dict): Dictionary containing the given channels for the\n            sequence.\n        circuit (AnalogCircuit): AnalogCircuit to generate AHS code for.\n\n    Returns:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit. Can be used to generate the QuEra\n            and Braket IR.\n\n    Raises:\n        ValueError: If the capabilities are not provided but the circuit has\n            a ParallelRegister. This is because the ParallelRegister requires\n            the capabilities to generate the lattice data.\n\n    \"\"\"\n    from bloqade.analog.compiler.codegen.hardware import (\n        GenerateLattice,\n        GeneratePiecewiseLinearChannel,\n        GenerateLatticeSiteCoefficients,\n        GeneratePiecewiseConstantChannel,\n    )\n    from bloqade.analog.compiler.analysis.hardware import BasicLatticeValidation\n\n    if capabilities is not None:\n        # only validate the lattice if capabilities are provided\n        BasicLatticeValidation(capabilities).visit(circuit)\n\n    ahs_lattice_data = GenerateLattice(capabilities).emit(circuit)\n\n    global_detuning = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.detuning, field.Uniform\n    ).visit(circuit)\n\n    global_amplitude = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.rabi.amplitude, field.Uniform\n    ).visit(circuit)\n\n    global_phase = GeneratePiecewiseConstantChannel(\n        sequence.rydberg, pulse.rabi.phase, field.Uniform\n    ).visit(circuit)\n\n    local_detuning = None\n    lattice_site_coefficients = None\n\n    extra_sm = set(level_couplings[sequence.rydberg][pulse.detuning]) - {field.Uniform}\n\n    if extra_sm:\n        if capabilities is not None and capabilities.capabilities.rydberg.local is None:\n            raise ValueError(\n                \"Device does not support local detuning, but the program has a \"\n                \"non-uniform spatial modulation for detuning.\"\n            )\n\n        sm = extra_sm.pop()\n\n        lattice_site_coefficients = GenerateLatticeSiteCoefficients(\n            parallel_decoder=ahs_lattice_data.parallel_decoder\n        ).emit(circuit)\n\n        local_detuning = GeneratePiecewiseLinearChannel(\n            sequence.rydberg, pulse.detuning, sm\n        ).visit(circuit)\n\n    return AHSComponents(\n        lattice_data=ahs_lattice_data,\n        global_detuning=global_detuning,\n        global_amplitude=global_amplitude,\n        global_phase=global_phase,\n        local_detuning=local_detuning,\n        lattice_site_coefficients=lattice_site_coefficients,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.generate_braket_ir","title":"generate_braket_ir","text":"
generate_braket_ir(ahs_components, shots)\n
  1. generate braket ir

This pass takes the AHS components and generates the Braket IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification BraketTaskSpecification

Braket IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_braket_ir(\n    ahs_components: AHSComponents, shots: int\n) -> BraketTaskSpecification:\n    \"\"\"7. generate braket ir\n\n    This pass takes the AHS components and generates the Braket IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (BraketTaskSpecification): Braket IR for the given\n            circuit.\n\n    \"\"\"\n    import braket.ir.ahs as ahs\n\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    ahs_register = ahs.AtomArrangement(\n        sites=list(map(convert_coordinate_units, ahs_components.lattice_data.sites)),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning_time_series = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning_time_series = ahs.TimeSeries(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n        )\n\n    amplitude_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    phase_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = ahs.PhysicalField(\n        time_series=global_detuning_time_series,\n        pattern=\"uniform\",\n    )\n\n    amplitude = ahs.PhysicalField(\n        time_series=amplitude_time_series,\n        pattern=\"uniform\",\n    )\n\n    phase = ahs.PhysicalField(\n        time_series=phase_time_series,\n        pattern=\"uniform\",\n    )\n\n    local_detuning = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = ahs.PhysicalField(\n            time_series=local_detuning_time_series,\n            pattern=ahs_components.lattice_site_coefficients,\n        )\n\n    driving_field = ahs.DrivingField(\n        detuning=detuning,\n        amplitude=amplitude,\n        phase=phase,\n    )\n\n    shiftingFields = []\n    if ahs_components.lattice_site_coefficients is not None:\n        shiftingFields = [ahs.ShiftingField(magnitude=local_detuning)]\n\n    program = ahs.Program(\n        setup=ahs.Setup(ahs_register=ahs_register),\n        hamiltonian=ahs.Hamiltonian(\n            drivingFields=[driving_field],\n            shiftingFields=shiftingFields,\n        ),\n    )\n\n    return BraketTaskSpecification(nshots=shots, program=program)\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.generate_quera_ir","title":"generate_quera_ir","text":"
generate_quera_ir(ahs_components, shots)\n
  1. generate quera ir

This pass takes the AHS components and generates the QuEra IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification QuEraTaskSpecification

QuEra IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_quera_ir(\n    ahs_components: AHSComponents, shots: int\n) -> QuEraTaskSpecification:\n    \"\"\"7. generate quera ir\n\n    This pass takes the AHS components and generates the QuEra IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (QuEraTaskSpecification): QuEra IR for the given\n            circuit.\n\n    \"\"\"\n    import bloqade.analog.submission.ir.task_specification as task_spec\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    lattice = task_spec.Lattice(\n        sites=list(\n            map(\n                convert_coordinate_units,\n                ahs_components.lattice_data.sites,\n            )\n        ),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning = None\n\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = task_spec.LocalField(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n            lattice_site_coefficients=ahs_components.lattice_site_coefficients,\n        )\n\n    rabi_frequency_amplitude_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    rabi_frequency_phase_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = task_spec.Detuning(\n        global_=global_detuning,\n        local=local_detuning,\n    )\n\n    rabi_frequency_amplitude = task_spec.RabiFrequencyAmplitude(\n        global_=rabi_frequency_amplitude_field,\n    )\n\n    rabi_frequency_phase = task_spec.RabiFrequencyPhase(\n        global_=rabi_frequency_phase_field,\n    )\n\n    rydberg = task_spec.RydbergHamiltonian(\n        rabi_frequency_amplitude=rabi_frequency_amplitude,\n        rabi_frequency_phase=rabi_frequency_phase,\n        detuning=detuning,\n    )\n\n    effective_hamiltonian = task_spec.EffectiveHamiltonian(\n        rydberg=rydberg,\n    )\n\n    return task_spec.QuEraTaskSpecification(\n        nshots=shots,\n        lattice=lattice,\n        effective_hamiltonian=effective_hamiltonian,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.validate_waveforms","title":"validate_waveforms","text":"
validate_waveforms(level_couplings, circuit)\n
  1. validate piecewise linear and piecewise constant pieces of pulses

This pass check to make sure that the waveforms are compatible with the hardware. This includes checking that the waveforms are piecewise linear or piecewise constant. It also checks that the waveforms are compatible with the given channels.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to validate waveforms for

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Raises:

Type Description ValueError

If the waveforms are not piecewise linear or piecewise constant, e.g. the waveform is not continuous.

ValueError

If a waveform segment is not compatible with the given channels.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def validate_waveforms(\n    level_couplings: Dict, circuit: analog_circuit.AnalogCircuit\n) -> None:\n    \"\"\"4. validate piecewise linear and piecewise constant pieces of pulses\n\n    This pass check to make sure that the waveforms are compatible with the\n    hardware. This includes checking that the waveforms are piecewise linear or\n    piecewise constant. It also checks that the waveforms are compatible with\n    the given channels.\n\n    Args:\n        circuit: AnalogCircuit to validate waveforms for\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Raises:\n        ValueError: If the waveforms are not piecewise linear or piecewise\n            constant, e.g. the waveform is not continuous.\n        ValueError: If a waveform segment is not compatible with the given\n            channels.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import CheckSlices\n    from bloqade.analog.compiler.analysis.hardware import (\n        ValidatePiecewiseLinearChannel,\n        ValidatePiecewiseConstantChannel,\n    )\n\n    channel_iter = (\n        (level_coupling, field_name, sm)\n        for level_coupling, fields in level_couplings.items()\n        for field_name, spatial_modulations in fields.items()\n        for sm in spatial_modulations\n    )\n    for channel in channel_iter:\n        if channel[1] in [pulse.detuning, pulse.rabi.amplitude]:\n            ValidatePiecewiseLinearChannel(*channel).visit(circuit)\n        else:\n            ValidatePiecewiseConstantChannel(*channel).visit(circuit)\n\n    CheckSlices().visit(circuit)\n\n    if circuit.sequence.duration() == 0:\n        raise ValueError(\"Circuit Duration must be be non-zero\")\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/units/","title":"Units","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/#bloqade.analog.compiler.rewrite.common.AssignToLiteral","title":"AssignToLiteral","text":"

Bases: BloqadeIRTransformer

Transform all assigned variables to literals.

"},{"location":"reference/bloqade/analog/compiler/rewrite/common/add_padding/","title":"Add padding","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/assign_to_literal/","title":"Assign to literal","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/assign_to_literal/#bloqade.analog.compiler.rewrite.common.assign_to_literal.AssignToLiteral","title":"AssignToLiteral","text":"

Bases: BloqadeIRTransformer

Transform all assigned variables to literals.

"},{"location":"reference/bloqade/analog/compiler/rewrite/common/assign_variables/","title":"Assign variables","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/canonicalize/","title":"Canonicalize","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/flatten/","title":"Flatten","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/python/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/python/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/emulate/","title":"Index","text":""},{"location":"reference/bloqade/analog/emulate/sparse_operator/","title":"Sparse operator","text":""},{"location":"reference/bloqade/analog/emulate/ir/","title":"Index","text":""},{"location":"reference/bloqade/analog/emulate/ir/atom_type/","title":"Atom type","text":""},{"location":"reference/bloqade/analog/emulate/ir/emulator/","title":"Emulator","text":""},{"location":"reference/bloqade/analog/emulate/ir/emulator/#bloqade.analog.emulate.ir.emulator.Register","title":"Register dataclass","text":"
Register(atom_type, sites, blockade_radius, geometry=None)\n

This class represents the of the atoms in the system.

"},{"location":"reference/bloqade/analog/emulate/ir/space/","title":"Space","text":""},{"location":"reference/bloqade/analog/emulate/ir/state_vector/","title":"State vector","text":""},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.AnalogGate","title":"AnalogGate dataclass","text":"
AnalogGate(hamiltonian)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.AnalogGate.run","title":"run","text":"
run(\n    shots=1,\n    solver_name=\"dop853\",\n    atol=1e-14,\n    rtol=1e-07,\n    nsteps=2147483647,\n    interaction_picture=False,\n    project_hyperfine=True,\n)\n

Run the emulation with all atoms in the ground state, sampling the final state vector.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef run(\n    self,\n    shots: int = 1,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-14,\n    rtol: float = 1e-7,\n    nsteps: int = 2_147_483_647,\n    interaction_picture: bool = False,\n    project_hyperfine: bool = True,\n) -> NDArray[np.uint8]:\n    \"\"\"Run the emulation with all atoms in the ground state,\n    sampling the final state vector.\"\"\"\n\n    options = dict(\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n\n    state = self.hamiltonian.space.zero_state()\n    (result,) = self.apply(state, **options)\n    result.normalize()\n\n    return result.sample(shots, project_hyperfine=project_hyperfine)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian","title":"RydbergHamiltonian dataclass","text":"
RydbergHamiltonian(\n    emulator_ir,\n    space,\n    rydberg,\n    detuning_ops=list(),\n    rabi_ops=list(),\n)\n

Hamiltonian for a given task. With the RydbergHamiltonian you can convert the Hamiltonian to CSR matrix form as well as obtaining the average energy/variance of a register.

Attributes:

Name Type Description emulator_ir EmulatorProgram

A copy of the original program used to generate the RydbergHamiltonian

space Space

The Hilbert space of the Hamiltonian, should align with the register the Hamiltonian is being applied on for average energy/variance

rydberg NDArray

Rydberg interaction operator

detuning_ops List[DetuningOperator]

Detuning Operators of the Hamiltonian

rabi_ops List[RabiOperator]

Rabi Operators of the Hamiltonian

"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.average","title":"average","text":"
average(register, time=None)\n

Get energy average from RydbergHamiltonian object at time time with register register

Parameters:

Name Type Description Default register StateVector

The state vector to take average with

required time Optional[float]

Time value to evaluate average at.

None

Returns:

Name Type Description float float

average energy at time time

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef average(\n    self,\n    register: StateVector,\n    time: Optional[float] = None,\n) -> float:\n    \"\"\"Get energy average from RydbergHamiltonian object at time `time` with\n    register `register`\n\n    Args:\n        register (StateVector): The state vector to take average with\n        time (Optional[float], optional): Time value to evaluate average at.\n        Defaults to duration of RydbergHamiltonian.\n\n    Returns:\n        float: average energy at time `time`\n    \"\"\"\n    return np.vdot(register.data, self._apply(register.data, time)).real\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.average_and_variance","title":"average_and_variance","text":"
average_and_variance(register, time=None)\n

Get energy average and variance from RydbergHamiltonian object at time time with register register

Parameters:

Name Type Description Default register StateVector

The state vector to take average and variance with

required time Optional[float]

Time value to evaluate average at.

None

Returns:

Type Description float

Tuple[float, float]: average and variance of energy at time time

float

respectively.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef average_and_variance(\n    self,\n    register: StateVector,\n    time: Optional[float] = None,\n) -> Tuple[float, float]:\n    \"\"\"Get energy average and variance from RydbergHamiltonian object at time `time`\n    with register `register`\n\n    Args:\n        register (StateVector): The state vector to take average and variance with\n        time (Optional[float], optional): Time value to evaluate average at.\n        Defaults to duration of RydbergHamiltonian.\n\n    Returns:\n        Tuple[float, float]: average and variance of energy at time `time`\n        respectively.\n    \"\"\"\n    H_register_data = self._apply(register.data, time)\n\n    average = np.vdot(register.data, H_register_data).real\n    square_average = np.vdot(H_register_data, H_register_data).real\n\n    return average, square_average - average**2\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.tocsr","title":"tocsr","text":"
tocsr(time)\n

Return the Hamiltonian as a csr matrix at time time.

Parameters:

Name Type Description Default time float

time to evaluate the Hamiltonian at.

required

Returns:

Name Type Description csr_matrix csr_matrix

The Hamiltonian as a csr matrix.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def tocsr(self, time: float) -> csr_matrix:\n    \"\"\"Return the Hamiltonian as a csr matrix at time `time`.\n\n    Args:\n        time (float): time to evaluate the Hamiltonian at.\n\n    Returns:\n        csr_matrix: The Hamiltonian as a csr matrix.\n\n    \"\"\"\n    diagonal = sum(\n        (detuning.get_diagonal(time) for detuning in self.detuning_ops),\n        start=self.rydberg,\n    )\n\n    hamiltonian = diags(diagonal).tocsr()\n    for rabi_op in self.rabi_ops:\n        hamiltonian = hamiltonian + rabi_op.tocsr(time)\n\n    return hamiltonian\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.variance","title":"variance","text":"
variance(register, time=None)\n

Get the energy variance from RydbergHamiltonian object at time time with register register

Parameters:

Name Type Description Default register StateVector

The state vector to take variance with

required time Optional[float]

Time value to evaluate average at.

None

Returns:

Name Type Description complex float

variance of energy at time time respectively.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef variance(\n    self,\n    register: StateVector,\n    time: Optional[float] = None,\n) -> float:\n    \"\"\"Get the energy variance from RydbergHamiltonian object at\n    time `time` with register `register`\n\n    Args:\n        register (StateVector): The state vector to take variance with\n        time (Optional[float], optional): Time value to evaluate average at.\n        Defaults to duration of RydbergHamiltonian.\n\n    Returns:\n        complex: variance of energy at time `time` respectively.\n    \"\"\"\n\n    _, var = self.average_and_variance(register, time)\n    return var\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector","title":"StateVector dataclass","text":"
StateVector(data, space)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.local_trace","title":"local_trace","text":"
local_trace(matrix, site_index)\n

return trace of an operator over the StateVector.

Parameters:

Name Type Description Default matrix ndarray

Square matrix representing operator in the local hilbert space.

required site_index int | Tuple[int, int]

sites to apply one body operator to.

required

Returns:

Name Type Description complex complex

the trace of the operator over the state-vector.

Raises:

Type Description ValueError

Error is raised when the dimension of operator is not

ValueError

Error is raised when the site argument is out of bounds.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@plum.dispatch\ndef local_trace(  # noqa: F811\n    self, matrix: np.ndarray, site_index: Union[int, Tuple[int, int]]\n) -> complex:  # noqa: F811\n    \"\"\"return trace of an operator over the StateVector.\n\n    Args:\n        matrix (np.ndarray): Square matrix representing operator in the local\n            hilbert space.\n        site_index (int | Tuple[int, int]): sites to apply one body operator to.\n\n    Returns:\n        complex: the trace of the operator over the state-vector.\n\n    Raises:\n        ValueError: Error is raised when the dimension of `operator` is not\n        consistent with `site` argument. The size of the operator must fit\n        the size of the local hilbert space of `site` depending on the number\n        of sites and the number of levels inside each atom, e.g. for two site\n        expectation value with a three level atom the operator must be a 9 by\n        9 array.\n\n        ValueError: Error is raised when the `site` argument is out of bounds.\n\n    \"\"\"\n    ...\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.norm","title":"norm","text":"
norm()\n

Return the norm of the state vector.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def norm(self) -> float:\n    \"\"\"Return the norm of the state vector.\"\"\"\n    return np.linalg.norm(self.data)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.normalize","title":"normalize","text":"
normalize()\n

Normalize the state vector.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def normalize(self) -> None:\n    \"\"\"Normalize the state vector.\"\"\"\n    data = self.data\n    data /= np.linalg.norm(data)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.sample","title":"sample","text":"
sample(shots, project_hyperfine=True)\n

Sample the state vector and return bitstrings.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def sample(self, shots: int, project_hyperfine: bool = True) -> NDArray:\n    \"\"\"Sample the state vector and return bitstrings.\"\"\"\n    return self.space.sample_state_vector(\n        self.data, shots, project_hyperfine=project_hyperfine\n    )\n
"},{"location":"reference/bloqade/analog/ir/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.start","title":"start module-attribute","text":"
start = ListOfLocations()\n

A Program starting point, alias of empty ListOfLocations.

  • Next possible steps to build your program are:
  • Specify which level coupling to address with:
    • start.rydberg: for Rydberg Level coupling
    • start.hyperfine: for Hyperfine Level coupling
    • LOCKOUT: You cannot add atoms to your geometry after specifying level coupling.
  • continue/start building your geometry with:
    • start.add_position(): to add atom(s) to current register. It will accept:
      • A single coordinate, represented as a tuple (e.g. (5,6)) with a value that can either be:
        • integers: (5,6)
        • floats: (5.1, 2.5)
        • strings (for later variable assignment): (\"x\", \"y\")
        • Scalar objects: (2*cast(\"x\"), 5+cast(\"y\"))
      • A list of coordinates, represented as a list of types mentioned previously.
      • A numpy array with shape (n, 2) where n is the total number of atoms
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AlignedWaveform","title":"AlignedWaveform","text":"

Bases: Waveform

<padded waveform> ::= <waveform> | <waveform> <alignment> <value>\n\n<alignment> ::= 'left aligned' | 'right aligned'\n<value> ::= 'left value' | 'right value' | <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AnalogCircuit","title":"AnalogCircuit","text":"

AnalogCircuit is a dummy type that bundle register and sequence together.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AnalogCircuit.register","title":"register property","text":"
register\n

Get the register of the program.

Returns:

Type Description

register (Union[\"AtomArrangement\", \"ParallelRegister\"])

Note

If the program is built with parallelize(), The the register will be a ParallelRegister. Otherwise it will be a AtomArrangement.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AnalogCircuit.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the program

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the program

{} Source code in src/bloqade/analog/ir/analog_circuit.py
def show(self, **assignments):\n    \"\"\"Interactive visualization of the program\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the program\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais","title":"BoundedBravais","text":"
BoundedBravais(parent=None)\n

Bases: AtomArrangement

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.__match_args__","title":"__match_args__ class-attribute instance-attribute","text":"
__match_args__ = ('shape', 'lattice_spacing')\n

Base classe for Bravais lattices AtomArrangement.

  • Square
  • Chain
  • Honeycomb
  • Triangular
  • Lieb
  • Kagome
  • Rectangular
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.n_dims","title":"n_dims property","text":"
n_dims\n

dimension of the lattice

Returns:

Name Type Description int

dimension of the lattice

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.coordinates","title":"coordinates","text":"
coordinates(index)\n

calculate the coordinates of a cell in the lattice given the cell index.

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef coordinates(self, index: List[int]) -> NDArray:\n    \"\"\"calculate the coordinates of a cell in the lattice\n    given the cell index.\n    \"\"\"\n    # damn! this is like stone age broadcasting\n    vectors = np.array(self.cell_vectors())\n    index = np.array(index)\n    pos = np.sum(vectors.T * index, axis=1)\n    return pos + np.array(self.cell_atoms())\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.scale","title":"scale","text":"
scale(factor)\n

Scale the current location with a factor.

(x,y) -> factor*(x,y)

Parameters:

Name Type Description Default factor str | Real | Decimal | Scalar

scale factor

required

Returns:

Name Type Description BoundedBravais BoundedBravais

The lattice with the scaled locations

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef scale(self, factor: ScalarType) -> \"BoundedBravais\":\n    \"\"\"Scale the current location with a factor.\n\n    (x,y) -> factor*(x,y)\n\n    Args:\n        factor (str | Real | Decimal | Scalar): scale factor\n\n    Returns:\n        BoundedBravais: The lattice with the scaled locations\n    \"\"\"\n    factor = cast(factor)\n    obj = self.__new__(type(self))\n    for f in fields(self):\n        if f.name == \"lattice_spacing\":\n            obj.lattice_spacing = factor * self.lattice_spacing\n        else:\n            setattr(obj, f.name, getattr(self, f.name))\n    return obj\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Constant","title":"Constant","text":"
Constant(value, duration)\n

Bases: Instruction

<constant> ::= 'constant' <scalar expr>\n

f(t=0:duration) = value

Parameters:

Name Type Description Default value Scalar

the constant value

required duration Scalar

the time span of the constant waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, value: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"value\", cast(value))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Field","title":"Field","text":"

Bases: FieldExpr

Field node in the IR. Which contains collection(s) of Waveform

<field> ::= ('field' <spatial modulation>  <padded waveform>)*\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Field.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Field

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Field

{} Source code in src/bloqade/analog/ir/control/field.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Field\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Field\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Linear","title":"Linear","text":"
Linear(start, stop, duration)\n

Bases: Instruction

<linear> ::= 'linear' <scalar expr> <scalar expr>\n

f(t=0:duration) = start + (stop-start)/duration * t

Parameters:

Name Type Description Default start Scalar

start value

required stop Scalar

stop value

required duration Scalar

the time span of the linear waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, start: ScalarType, stop: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"start\", cast(start))\n    object.__setattr__(self, \"stop\", cast(stop))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Literal","title":"Literal","text":"

Bases: Real

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Literal.value","title":"value instance-attribute","text":"
value\n

Scalar Literal, which stores a decimaal value instance.

Parameters:

Name Type Description Default value Decimal

decimal value instance

required"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Poly","title":"Poly","text":"
Poly(coeffs, duration)\n

Bases: Instruction

<poly> ::= <scalar>+\n

f(t=0:duration) = c[0] + c[1]t + c[2]t^2 + ... + c[n-1]t^n-1 + c[n]t^n

Parameters:

Name Type Description Default coeffs Tuple[Scalar]

the coefficients c[] of the polynomial.

required duration Scalar

the time span of the waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, coeffs: Container[ScalarType], duration: ScalarType):\n    object.__setattr__(self, \"coeffs\", tuple(map(cast, coeffs)))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Pulse","title":"Pulse","text":"

Bases: PulseExpr

<pulse> ::= (<field name> <field>)+\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Pulse.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Pulse

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Pulse

{} Source code in src/bloqade/analog/ir/control/pulse.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Pulse\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Pulse\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.PythonFn","title":"PythonFn","text":"

Bases: Instruction

<python-fn> ::= 'python-fn' <python function def> <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Record","title":"Record","text":"

Bases: Waveform

<record> ::= 'record' <waveform> <var> <side>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Sample","title":"Sample","text":"

Bases: Waveform

<sample> ::= 'sample' <waveform> <interpolation> <scalar>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Scalar","title":"Scalar","text":"

Base class for all scalar expressions.

<scalar> ::= <literal>\n| <variable>\n| <default>\n| <negative>\n| <add>\n| <mul>\n| <min>\n| <max>\n| <slice>\n| <inverval>\n\n<mul> ::= <scalar> '*' <scalar>\n<add> ::= <scalar> '+' <scalar>\n<min> ::= 'min' <scalar>+\n<max> ::= 'max' <scalar>+\n<slice> ::= <scalar expr> '[' <interval> ']'\n<interval> ::= <scalar expr> '..' <scalar expr>\n<real> ::= <literal> | <var>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Sequence","title":"Sequence","text":"

Bases: SequenceExpr

Sequence of a program, which includes pulses informations.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Sequence.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Sequence

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Sequence

{} Source code in src/bloqade/analog/ir/control/sequence.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Sequence\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Sequence\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Variable","title":"Variable","text":"

Bases: Real

Variable, which stores a variable name.

Parameters:

Name Type Description Default name str

variable instance.

required"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Waveform","title":"Waveform","text":"

Bases: HashTrait, CanonicalizeTrait

Waveform node in the IR.

  • <instruction>
  • <smooth>
  • <slice>
  • <apppend>
  • <negative>
  • <scale>
  • <add>
  • <record>
  • <sample>
<waveform> ::= <instruction>\n    | <smooth>\n    | <slice>\n    | <append>\n    | <negative>\n    | <scale>\n    | <add>\n    | <record>\n    | <sample>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Waveform.figure","title":"figure","text":"
figure(**assignments)\n

get figure of the plotting the waveform.

Returns:

Name Type Description figure

a bokeh figure

Source code in src/bloqade/analog/ir/control/waveform.py
def figure(self, **assignments):\n    \"\"\"get figure of the plotting the waveform.\n\n    Returns:\n        figure: a bokeh figure\n    \"\"\"\n    return get_ir_figure(self, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.cast","title":"cast","text":"
cast(py)\n
  1. cast Real number (or list/tuple of Real numbers) to Scalar Literal.

  2. cast str (or list/tuple of Real numbers) to Scalar Variable.

Parameters:

Name Type Description Default py Union[str, Real, Tuple[Real], List[Real]]

python object to cast

required

Returns:

Type Description Scalar

Scalar

Source code in src/bloqade/analog/ir/scalar.py
def cast(py) -> \"Scalar\":\n    \"\"\"\n    1. cast Real number (or list/tuple of Real numbers)\n    to [`Scalar Literal`][bloqade.ir.scalar.Literal].\n\n    2. cast str (or list/tuple of Real numbers)\n    to [`Scalar Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str,Real,Tuple[Real],List[Real]]): python object to cast\n\n    Returns:\n        Scalar\n    \"\"\"\n    ret = trycast(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Scalar Literal\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.var","title":"var","text":"
var(py)\n

cast string (or list/tuple of strings) to Variable.

Parameters:

Name Type Description Default py Union[str, List[str]]

a string or list/tuple of strings

required

Returns:

Type Description Variable

Union[Variable]

Source code in src/bloqade/analog/ir/scalar.py
def var(py: str) -> \"Variable\":\n    \"\"\"cast string (or list/tuple of strings)\n    to [`Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str, List[str]]): a string or list/tuple of strings\n\n    Returns:\n       Union[Variable]\n    \"\"\"\n    ret = tryvar(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Variable\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/analog_circuit/","title":"Analog circuit","text":""},{"location":"reference/bloqade/analog/ir/analog_circuit/#bloqade.analog.ir.analog_circuit.AnalogCircuit","title":"AnalogCircuit","text":"

AnalogCircuit is a dummy type that bundle register and sequence together.

"},{"location":"reference/bloqade/analog/ir/analog_circuit/#bloqade.analog.ir.analog_circuit.AnalogCircuit.register","title":"register property","text":"
register\n

Get the register of the program.

Returns:

Type Description

register (Union[\"AtomArrangement\", \"ParallelRegister\"])

Note

If the program is built with parallelize(), The the register will be a ParallelRegister. Otherwise it will be a AtomArrangement.

"},{"location":"reference/bloqade/analog/ir/analog_circuit/#bloqade.analog.ir.analog_circuit.AnalogCircuit.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the program

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the program

{} Source code in src/bloqade/analog/ir/analog_circuit.py
def show(self, **assignments):\n    \"\"\"Interactive visualization of the program\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the program\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/scalar/","title":"Scalar","text":""},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Literal","title":"Literal","text":"

Bases: Real

"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Literal.value","title":"value instance-attribute","text":"
value\n

Scalar Literal, which stores a decimaal value instance.

Parameters:

Name Type Description Default value Decimal

decimal value instance

required"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Scalar","title":"Scalar","text":"

Base class for all scalar expressions.

<scalar> ::= <literal>\n| <variable>\n| <default>\n| <negative>\n| <add>\n| <mul>\n| <min>\n| <max>\n| <slice>\n| <inverval>\n\n<mul> ::= <scalar> '*' <scalar>\n<add> ::= <scalar> '+' <scalar>\n<min> ::= 'min' <scalar>+\n<max> ::= 'max' <scalar>+\n<slice> ::= <scalar expr> '[' <interval> ']'\n<interval> ::= <scalar expr> '..' <scalar expr>\n<real> ::= <literal> | <var>\n
"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Variable","title":"Variable","text":"

Bases: Real

Variable, which stores a variable name.

Parameters:

Name Type Description Default name str

variable instance.

required"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.cast","title":"cast","text":"
cast(py)\n
  1. cast Real number (or list/tuple of Real numbers) to Scalar Literal.

  2. cast str (or list/tuple of Real numbers) to Scalar Variable.

Parameters:

Name Type Description Default py Union[str, Real, Tuple[Real], List[Real]]

python object to cast

required

Returns:

Type Description Scalar

Scalar

Source code in src/bloqade/analog/ir/scalar.py
def cast(py) -> \"Scalar\":\n    \"\"\"\n    1. cast Real number (or list/tuple of Real numbers)\n    to [`Scalar Literal`][bloqade.ir.scalar.Literal].\n\n    2. cast str (or list/tuple of Real numbers)\n    to [`Scalar Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str,Real,Tuple[Real],List[Real]]): python object to cast\n\n    Returns:\n        Scalar\n    \"\"\"\n    ret = trycast(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Scalar Literal\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.var","title":"var","text":"
var(py)\n

cast string (or list/tuple of strings) to Variable.

Parameters:

Name Type Description Default py Union[str, List[str]]

a string or list/tuple of strings

required

Returns:

Type Description Variable

Union[Variable]

Source code in src/bloqade/analog/ir/scalar.py
def var(py: str) -> \"Variable\":\n    \"\"\"cast string (or list/tuple of strings)\n    to [`Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str, List[str]]): a string or list/tuple of strings\n\n    Returns:\n       Union[Variable]\n    \"\"\"\n    ret = tryvar(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Variable\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/control/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/control/field/","title":"Field","text":""},{"location":"reference/bloqade/analog/ir/control/field/#bloqade.analog.ir.control.field.Field","title":"Field","text":"

Bases: FieldExpr

Field node in the IR. Which contains collection(s) of Waveform

<field> ::= ('field' <spatial modulation>  <padded waveform>)*\n
"},{"location":"reference/bloqade/analog/ir/control/field/#bloqade.analog.ir.control.field.Field.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Field

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Field

{} Source code in src/bloqade/analog/ir/control/field.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Field\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Field\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/","title":"Pulse","text":""},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.Append","title":"Append","text":"

Bases: AppendTrait, PulseExpr

<append> ::= <expr>+\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.Pulse","title":"Pulse","text":"

Bases: PulseExpr

<pulse> ::= (<field name> <field>)+\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.Pulse.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Pulse

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Pulse

{} Source code in src/bloqade/analog/ir/control/pulse.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Pulse\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Pulse\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.PulseExpr","title":"PulseExpr","text":"

Bases: HashTrait, CanonicalizeTrait

<expr> ::= <pulse>\n  | <append>\n  | <slice>\n  | <named>\n
"},{"location":"reference/bloqade/analog/ir/control/sequence/","title":"Sequence","text":""},{"location":"reference/bloqade/analog/ir/control/sequence/#bloqade.analog.ir.control.sequence.Sequence","title":"Sequence","text":"

Bases: SequenceExpr

Sequence of a program, which includes pulses informations.

"},{"location":"reference/bloqade/analog/ir/control/sequence/#bloqade.analog.ir.control.sequence.Sequence.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Sequence

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Sequence

{} Source code in src/bloqade/analog/ir/control/sequence.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Sequence\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Sequence\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Add","title":"Add","text":"

Bases: Waveform

<add> ::= <waveform> '+' <waveform>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.AlignedWaveform","title":"AlignedWaveform","text":"

Bases: Waveform

<padded waveform> ::= <waveform> | <waveform> <alignment> <value>\n\n<alignment> ::= 'left aligned' | 'right aligned'\n<value> ::= 'left value' | 'right value' | <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Append","title":"Append","text":"

Bases: AppendTrait, Waveform

<append> ::= <waveform>+\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Constant","title":"Constant","text":"
Constant(value, duration)\n

Bases: Instruction

<constant> ::= 'constant' <scalar expr>\n

f(t=0:duration) = value

Parameters:

Name Type Description Default value Scalar

the constant value

required duration Scalar

the time span of the constant waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, value: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"value\", cast(value))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Instruction","title":"Instruction","text":"

Bases: Waveform

Instruction node in the IR.

  • <linear>
  • <constant>
  • <poly>
  • <python-fn>
<instruction> ::= <linear>\n    | <constant>\n    | <poly>\n    | <python-fn>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Linear","title":"Linear","text":"
Linear(start, stop, duration)\n

Bases: Instruction

<linear> ::= 'linear' <scalar expr> <scalar expr>\n

f(t=0:duration) = start + (stop-start)/duration * t

Parameters:

Name Type Description Default start Scalar

start value

required stop Scalar

stop value

required duration Scalar

the time span of the linear waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, start: ScalarType, stop: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"start\", cast(start))\n    object.__setattr__(self, \"stop\", cast(stop))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Negative","title":"Negative","text":"

Bases: Waveform

<negative> ::= '-' <waveform>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Poly","title":"Poly","text":"
Poly(coeffs, duration)\n

Bases: Instruction

<poly> ::= <scalar>+\n

f(t=0:duration) = c[0] + c[1]t + c[2]t^2 + ... + c[n-1]t^n-1 + c[n]t^n

Parameters:

Name Type Description Default coeffs Tuple[Scalar]

the coefficients c[] of the polynomial.

required duration Scalar

the time span of the waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, coeffs: Container[ScalarType], duration: ScalarType):\n    object.__setattr__(self, \"coeffs\", tuple(map(cast, coeffs)))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.PythonFn","title":"PythonFn","text":"

Bases: Instruction

<python-fn> ::= 'python-fn' <python function def> <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Record","title":"Record","text":"

Bases: Waveform

<record> ::= 'record' <waveform> <var> <side>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Sample","title":"Sample","text":"

Bases: Waveform

<sample> ::= 'sample' <waveform> <interpolation> <scalar>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Scale","title":"Scale","text":"
Scale(scalar, waveform)\n

Bases: Waveform

<scale> ::= <scalar expr> '*' <waveform>\n
Source code in src/bloqade/analog/ir/control/waveform.py
def __init__(self, scalar, waveform: Waveform):\n    object.__setattr__(self, \"scalar\", cast(scalar))\n    object.__setattr__(self, \"waveform\", waveform)\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Slice","title":"Slice","text":"

Bases: SliceTrait, Waveform

<slice> ::= <waveform> <scalar.interval>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Smooth","title":"Smooth","text":"
Smooth(radius, kernel, waveform)\n

Bases: Waveform

<smooth> ::= 'smooth' <kernel> <waveform>\n
Source code in src/bloqade/analog/ir/control/waveform.py
def __init__(self, radius, kernel, waveform):\n    if isinstance(kernel, str):\n        if kernel == \"Gaussian\":\n            kernel = GaussianKernel\n        elif kernel == \"Logistic\":\n            kernel = LogisticKernel\n        elif kernel == \"Sigmoid\":\n            kernel = SigmoidKernel\n        elif kernel == \"Triangle\":\n            kernel = TriangleKernel\n        elif kernel == \"Uniform\":\n            kernel = UniformKernel\n        elif kernel == \"Parabolic\":\n            kernel = ParabolicKernel\n        elif kernel == \"Biweight\":\n            kernel = BiweightKernel\n        elif kernel == \"Triweight\":\n            kernel = TriweightKernel\n        elif kernel == \"Tricube\":\n            kernel = TricubeKernel\n        elif kernel == \"Cosine\":\n            kernel = CosineKernel\n        else:\n            raise ValueError(f\"Invalid kernel: {kernel}\")\n\n    object.__setattr__(self, \"radius\", cast(radius))\n    object.__setattr__(self, \"kernel\", kernel)\n    object.__setattr__(self, \"waveform\", waveform)\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Waveform","title":"Waveform","text":"

Bases: HashTrait, CanonicalizeTrait

Waveform node in the IR.

  • <instruction>
  • <smooth>
  • <slice>
  • <apppend>
  • <negative>
  • <scale>
  • <add>
  • <record>
  • <sample>
<waveform> ::= <instruction>\n    | <smooth>\n    | <slice>\n    | <append>\n    | <negative>\n    | <scale>\n    | <add>\n    | <record>\n    | <sample>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Waveform.figure","title":"figure","text":"
figure(**assignments)\n

get figure of the plotting the waveform.

Returns:

Name Type Description figure

a bokeh figure

Source code in src/bloqade/analog/ir/control/waveform.py
def figure(self, **assignments):\n    \"\"\"get figure of the plotting the waveform.\n\n    Returns:\n        figure: a bokeh figure\n    \"\"\"\n    return get_ir_figure(self, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/traits/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/control/traits/#bloqade.analog.ir.control.traits.SliceTrait","title":"SliceTrait","text":""},{"location":"reference/bloqade/analog/ir/control/traits/#bloqade.analog.ir.control.traits.SliceTrait.start","title":"start cached property","text":"
start\n

Start time of the sliced object

Returns:

Name Type Description Scalar Scalar

The starting time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/control/traits/#bloqade.analog.ir.control.traits.SliceTrait.stop","title":"stop cached property","text":"
stop\n

Stop time of the sliced object

Returns:

Name Type Description Scalar Scalar

The stopping time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/control/traits/append/","title":"Append","text":""},{"location":"reference/bloqade/analog/ir/control/traits/canonicalize/","title":"Canonicalize","text":""},{"location":"reference/bloqade/analog/ir/control/traits/hash/","title":"Hash","text":""},{"location":"reference/bloqade/analog/ir/control/traits/slice/","title":"Slice","text":""},{"location":"reference/bloqade/analog/ir/control/traits/slice/#bloqade.analog.ir.control.traits.slice.SliceTrait","title":"SliceTrait","text":""},{"location":"reference/bloqade/analog/ir/control/traits/slice/#bloqade.analog.ir.control.traits.slice.SliceTrait.start","title":"start cached property","text":"
start\n

Start time of the sliced object

Returns:

Name Type Description Scalar Scalar

The starting time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/control/traits/slice/#bloqade.analog.ir.control.traits.slice.SliceTrait.stop","title":"stop cached property","text":"
stop\n

Stop time of the sliced object

Returns:

Name Type Description Scalar Scalar

The stopping time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/location/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.start","title":"start module-attribute","text":"
start = ListOfLocations()\n

A Program starting point, alias of empty ListOfLocations.

  • Next possible steps to build your program are:
  • Specify which level coupling to address with:
    • start.rydberg: for Rydberg Level coupling
    • start.hyperfine: for Hyperfine Level coupling
    • LOCKOUT: You cannot add atoms to your geometry after specifying level coupling.
  • continue/start building your geometry with:
    • start.add_position(): to add atom(s) to current register. It will accept:
      • A single coordinate, represented as a tuple (e.g. (5,6)) with a value that can either be:
        • integers: (5,6)
        • floats: (5.1, 2.5)
        • strings (for later variable assignment): (\"x\", \"y\")
        • Scalar objects: (2*cast(\"x\"), 5+cast(\"y\"))
      • A list of coordinates, represented as a list of types mentioned previously.
      • A numpy array with shape (n, 2) where n is the total number of atoms
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais","title":"BoundedBravais","text":"
BoundedBravais(parent=None)\n

Bases: AtomArrangement

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.__match_args__","title":"__match_args__ class-attribute instance-attribute","text":"
__match_args__ = ('shape', 'lattice_spacing')\n

Base classe for Bravais lattices AtomArrangement.

  • Square
  • Chain
  • Honeycomb
  • Triangular
  • Lieb
  • Kagome
  • Rectangular
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.n_dims","title":"n_dims property","text":"
n_dims\n

dimension of the lattice

Returns:

Name Type Description int

dimension of the lattice

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.coordinates","title":"coordinates","text":"
coordinates(index)\n

calculate the coordinates of a cell in the lattice given the cell index.

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef coordinates(self, index: List[int]) -> NDArray:\n    \"\"\"calculate the coordinates of a cell in the lattice\n    given the cell index.\n    \"\"\"\n    # damn! this is like stone age broadcasting\n    vectors = np.array(self.cell_vectors())\n    index = np.array(index)\n    pos = np.sum(vectors.T * index, axis=1)\n    return pos + np.array(self.cell_atoms())\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.scale","title":"scale","text":"
scale(factor)\n

Scale the current location with a factor.

(x,y) -> factor*(x,y)

Parameters:

Name Type Description Default factor str | Real | Decimal | Scalar

scale factor

required

Returns:

Name Type Description BoundedBravais BoundedBravais

The lattice with the scaled locations

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef scale(self, factor: ScalarType) -> \"BoundedBravais\":\n    \"\"\"Scale the current location with a factor.\n\n    (x,y) -> factor*(x,y)\n\n    Args:\n        factor (str | Real | Decimal | Scalar): scale factor\n\n    Returns:\n        BoundedBravais: The lattice with the scaled locations\n    \"\"\"\n    factor = cast(factor)\n    obj = self.__new__(type(self))\n    for f in fields(self):\n        if f.name == \"lattice_spacing\":\n            obj.lattice_spacing = factor * self.lattice_spacing\n        else:\n            setattr(obj, f.name, getattr(self, f.name))\n    return obj\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/","title":"Bravais","text":""},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais","title":"BoundedBravais","text":"
BoundedBravais(parent=None)\n

Bases: AtomArrangement

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.__match_args__","title":"__match_args__ class-attribute instance-attribute","text":"
__match_args__ = ('shape', 'lattice_spacing')\n

Base classe for Bravais lattices AtomArrangement.

  • Square
  • Chain
  • Honeycomb
  • Triangular
  • Lieb
  • Kagome
  • Rectangular
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.n_dims","title":"n_dims property","text":"
n_dims\n

dimension of the lattice

Returns:

Name Type Description int

dimension of the lattice

"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.coordinates","title":"coordinates","text":"
coordinates(index)\n

calculate the coordinates of a cell in the lattice given the cell index.

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef coordinates(self, index: List[int]) -> NDArray:\n    \"\"\"calculate the coordinates of a cell in the lattice\n    given the cell index.\n    \"\"\"\n    # damn! this is like stone age broadcasting\n    vectors = np.array(self.cell_vectors())\n    index = np.array(index)\n    pos = np.sum(vectors.T * index, axis=1)\n    return pos + np.array(self.cell_atoms())\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.scale","title":"scale","text":"
scale(factor)\n

Scale the current location with a factor.

(x,y) -> factor*(x,y)

Parameters:

Name Type Description Default factor str | Real | Decimal | Scalar

scale factor

required

Returns:

Name Type Description BoundedBravais BoundedBravais

The lattice with the scaled locations

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef scale(self, factor: ScalarType) -> \"BoundedBravais\":\n    \"\"\"Scale the current location with a factor.\n\n    (x,y) -> factor*(x,y)\n\n    Args:\n        factor (str | Real | Decimal | Scalar): scale factor\n\n    Returns:\n        BoundedBravais: The lattice with the scaled locations\n    \"\"\"\n    factor = cast(factor)\n    obj = self.__new__(type(self))\n    for f in fields(self):\n        if f.name == \"lattice_spacing\":\n            obj.lattice_spacing = factor * self.lattice_spacing\n        else:\n            setattr(obj, f.name, getattr(self, f.name))\n    return obj\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/location/","title":"Location","text":""},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.ParallelRegisterInfo","title":"ParallelRegisterInfo","text":"
ParallelRegisterInfo(parallel_register)\n

ParallelRegisterInfo

Source code in src/bloqade/analog/ir/location/location.py
def __init__(self, parallel_register: ParallelRegister):\n    atom_arrangement = parallel_register.atom_arrangement\n    cluster_spacing = parallel_register.cluster_spacing\n\n    if atom_arrangement.n_atoms > 0:\n        # calculate bounding box\n        # of this register\n        location_iter = atom_arrangement.enumerate()\n        (x, y) = next(location_iter).position\n        x_min = x\n        x_max = x\n        y_min = y\n        y_max = y\n\n        for location_info in location_iter:\n            (x, y) = location_info.position\n            x_min = x.min(x_min)\n            x_max = x.max(x_max)\n            y_min = y.min(y_min)\n            y_max = y.max(y_max)\n\n        shift_x = (x_max - x_min) + cluster_spacing\n        shift_y = (y_max - y_min) + cluster_spacing\n\n        register_locations = [\n            list(location_info.position)\n            for location_info in atom_arrangement.enumerate()\n        ]\n        register_filling = [\n            location_info.filling.value\n            for location_info in atom_arrangement.enumerate()\n        ]\n        shift_vectors = [[shift_x, cast(0)], [cast(0), shift_y]]\n    else:\n        raise ValueError(\"No locations to parallelize.\")\n\n    self.register_locations = register_locations\n    self.register_filling = register_filling\n    self.shift_vectors = shift_vectors\n
"},{"location":"reference/bloqade/analog/ir/routine/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/routine/base/","title":"Base","text":""},{"location":"reference/bloqade/analog/ir/routine/base/#bloqade.analog.ir.routine.base.Routine","title":"Routine","text":"

Bases: RoutineBase

Result of parsing a completed Builder string.

"},{"location":"reference/bloqade/analog/ir/routine/base/#bloqade.analog.ir.routine.base.RoutineShow","title":"RoutineShow","text":"

Bases: Show

"},{"location":"reference/bloqade/analog/ir/routine/base/#bloqade.analog.ir.routine.base.RoutineShow.show","title":"show","text":"
show(*args, batch_index=0)\n

Show an interactive plot of the routine.

int

which parameter set out of the batch to use. Default is 0. If there are no batch parameters, use 0.

*args: Any Specify the parameters that are defined in the .args([...]) build step.

Source code in src/bloqade/analog/ir/routine/base.py
def show(self: \"RoutineBase\", *args, batch_index: int = 0):\n    \"\"\"Show an interactive plot of the routine.\n\n    batch_index: int\n        which parameter set out of the batch to use. Default is 0.\n        If there are no batch parameters, use 0.\n\n    *args: Any\n        Specify the parameters that are defined in the `.args([...])` build step.\n\n    \"\"\"\n    if self.source is None:\n        raise ValueError(\"Cannot show a routine without a source Builder.\")\n\n    return self.source.show(*args, batch_id=batch_index)\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/","title":"Bloqade","text":""},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation","title":"BloqadeEmulation dataclass","text":"
BloqadeEmulation(task_data, compile_cache=None)\n

Data class to hold the Hamiltonian and metadata for a given set of parameters

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.hamiltonian","title":"hamiltonian property","text":"
hamiltonian\n

Return the Hamiltonian object for the given task data.

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.metadata","title":"metadata property","text":"
metadata\n

The metadata for the given task data.

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.evolve","title":"evolve","text":"
evolve(\n    state=None,\n    solver_name=\"dop853\",\n    atol=1e-07,\n    rtol=1e-14,\n    nsteps=2147483647,\n    times=(),\n    interaction_picture=False,\n)\n

Evolve an initial state vector using the Hamiltonian

Parameters:

Name Type Description Default state Optional[StateVector]

The initial state vector to

None solver_name str

Which SciPy Solver to use. Defaults to

'dop853' atol float

Absolute tolerance for ODE solver. Defaults

1e-07 rtol float

Relative tolerance for adaptive step in

1e-14 nsteps int

Maximum number of steps allowed per integration

2147483647 times Sequence[float]

The times to evaluate the state vector

() interaction_picture bool

Use the interaction picture when

False

Returns:

Type Description Iterator[StateVector]

Iterator[StateVector]: An iterator of the state vectors at each time step.

Source code in src/bloqade/analog/ir/routine/bloqade.py
def evolve(\n    self,\n    state: Optional[StateVector] = None,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-7,\n    rtol: float = 1e-14,\n    nsteps: int = 2147483647,\n    times: Sequence[float] = (),\n    interaction_picture: bool = False,\n) -> Iterator[StateVector]:\n    \"\"\"Evolve an initial state vector using the Hamiltonian\n\n    Args:\n        state (Optional[StateVector], optional): The initial state vector to\n        evolve. if not provided, the zero state will be used. Defaults to None.\n        solver_name (str, optional): Which SciPy Solver to use. Defaults to\n        \"dop853\".\n        atol (float, optional): Absolute tolerance for ODE solver. Defaults\n        to 1e-14.\n        rtol (float, optional): Relative tolerance for adaptive step in\n        ODE solver. Defaults to 1e-7.\n        nsteps (int, optional): Maximum number of steps allowed per integration\n        step. Defaults to 2147483647.\n        times (Sequence[float], optional): The times to evaluate the state vector\n        at. Defaults to (). If not provided the state will be evaluated at\n        the end of the bloqade program.\n        interaction_picture (bool, optional): Use the interaction picture when\n        solving schrodinger equation. Defaults to False.\n\n    Returns:\n        Iterator[StateVector]: An iterator of the state vectors at each time step.\n\n    \"\"\"\n    state = self.zero_state(np.complex128) if state is None else state\n\n    U = AnalogGate(self.hamiltonian)\n\n    return U.apply(\n        state,\n        times=times,\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.fock_state","title":"fock_state","text":"
fock_state(fock_state_str, dtype=np.float64)\n

Return the fock state for the given Hamiltonian.

Source code in src/bloqade/analog/ir/routine/bloqade.py
def fock_state(\n    self, fock_state_str: str, dtype: np.dtype = np.float64\n) -> StateVector:\n    \"\"\"Return the fock state for the given Hamiltonian.\"\"\"\n    index = self.hamiltonian.space.fock_state_to_index(fock_state_str)\n    data = np.zeros(self.hamiltonian.space.size, dtype=dtype)\n    data[index] = 1\n    return StateVector(data, self.hamiltonian.space)\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.zero_state","title":"zero_state","text":"
zero_state(dtype=np.float64)\n

Return the zero state for the given Hamiltonian.

Source code in src/bloqade/analog/ir/routine/bloqade.py
def zero_state(self, dtype: np.dtype = np.float64) -> StateVector:\n    \"\"\"Return the zero state for the given Hamiltonian.\"\"\"\n    return self.hamiltonian.space.zero_state(dtype)\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine","title":"BloqadePythonRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine.hamiltonian","title":"hamiltonian","text":"
hamiltonian(\n    *args,\n    blockade_radius=0.0,\n    use_hyperfine=False,\n    waveform_runtime=\"interpret\",\n    cache_matrices=False\n)\n

Generates a list of BloqadeEmulation objects which contain the Hamiltonian of your program.

If you have a variable(s) in your program you have assigned multiple values via batch_assign() there will be multiple BloqadeEmulation objects, one for each value. On the other hand if the program only assumes a singular value per each variable, there will only be one BloqadeEmulation object but it will still be encapsulated in a list.

Parameters:

Name Type Description Default *args LiteralType

If your program has a variable that was declared as run-time assignable via .args you may pass a value to it here. If there are multiple variables declared via .args the order in which you assign values to those variables through this argument should follow the order in which the declaration occurred.

() blockade_radius float

The radius in which atoms blockade eachother. Default value is 0.0 micrometers.

0.0 use_hyperfine bool

Should the Hamiltonian account for hyperfine levels. Default value is False.

False waveform_runtime str

Specify which runtime to use for waveforms. If \"numba\" is specify the waveform is compiled, otherwise it is interpreted via the \"interpret\" argument. Defaults to \"interpret\".

'interpret' cache_matrices bool

Speed up Hamiltonian generation by reusing data (when possible) from previously generated Hamiltonians. Default value is False.

False

Returns:

Type Description List[BloqadeEmulation]

List[BloqadeEmulation]

Source code in src/bloqade/analog/ir/routine/bloqade.py
def hamiltonian(\n    self,\n    *args: LiteralType,\n    blockade_radius: float = 0.0,\n    use_hyperfine: bool = False,\n    waveform_runtime: str = \"interpret\",\n    cache_matrices: bool = False,\n) -> List[BloqadeEmulation]:\n    \"\"\"\n    Generates a list of BloqadeEmulation objects which contain the Hamiltonian of your program.\n\n    If you have a variable(s) in your program you have assigned multiple values via `batch_assign()`\n    there will be multiple `BloqadeEmulation` objects, one for each value. On the other hand\n    if the program only assumes a singular value per each variable, there will only be\n    one `BloqadeEmulation` object but it will still be encapsulated in a list.\n\n\n    Args:\n        *args (LiteralType): If your program has a variable that was declared as run-time assignable\n            via `.args` you may pass a value to it here. If there are multiple\n            variables declared via `.args` the order in which you assign values to those variables\n            through this argument should follow the order in which the declaration occurred.\n        blockade_radius (float): The radius in which atoms blockade eachother. Default value is 0.0 micrometers.\n        use_hyperfine (bool): Should the Hamiltonian account for hyperfine levels. Default value is False.\n        waveform_runtime (str): Specify which runtime to use for waveforms. If \"numba\" is specify the waveform\n            is compiled, otherwise it is interpreted via the \"interpret\" argument. Defaults to \"interpret\".\n        cache_matrices (bool): Speed up Hamiltonian generation by reusing data (when possible) from previously generated Hamiltonians.\n            Default value is False.\n\n    Returns:\n        List[BloqadeEmulation]\n\n    \"\"\"\n    ir_iter = self._generate_ir(\n        args, blockade_radius, waveform_runtime, use_hyperfine\n    )\n\n    if cache_matrices:\n        compile_cache = CompileCache()\n    else:\n        compile_cache = None\n\n    return [\n        BloqadeEmulation(task_data, compile_cache=compile_cache)\n        for task_data in ir_iter\n    ]\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine.run","title":"run","text":"
run(\n    shots,\n    args=(),\n    name=None,\n    blockade_radius=0.0,\n    waveform_runtime=\"interpret\",\n    interaction_picture=False,\n    cache_matrices=False,\n    multiprocessing=False,\n    num_workers=None,\n    solver_name=\"dop853\",\n    atol=1e-07,\n    rtol=1e-14,\n    nsteps=2147483647,\n)\n

Run the current program using bloqade python backend

Parameters:

Name Type Description Default shots int

number of shots after running state vector simulation

required args Tuple[LiteralType, ...]

The values for parameters defined

() name Optional[str]

Name to give this run. Defaults to None.

None blockade_radius float

Use the Blockade subspace given a

0.0 waveform_runtime str

(bool, optional): Use Numba to compile the waveforms,

'interpret' interaction_picture bool

Use the interaction picture when

False cache_matrices bool

Reuse previously evaluated matrcies when

False multiprocessing bool

Use multiple processes to process the

False num_workers Optional[int]

Number of processes to run with

None solver_name str

Which SciPy Solver to use. Defaults to

'dop853' atol float

Absolute tolerance for ODE solver. Defaults to

1e-07 rtol float

Relative tolerance for adaptive step in ODE solver.

1e-14 nsteps int

Maximum number of steps allowed per integration

2147483647

Raises:

Type Description ValueError

Cannot use multiprocessing and cache_matrices at the same time.

Returns:

Name Type Description LocalBatch LocalBatch

Batch of local tasks that have been executed.

Source code in src/bloqade/analog/ir/routine/bloqade.py
@beartype\ndef run(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    blockade_radius: float = 0.0,\n    waveform_runtime: str = \"interpret\",\n    interaction_picture: bool = False,\n    cache_matrices: bool = False,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-7,\n    rtol: float = 1e-14,\n    nsteps: int = 2_147_483_647,\n) -> LocalBatch:\n    \"\"\"Run the current program using bloqade python backend\n\n    Args:\n        shots (int): number of shots after running state vector simulation\n        args (Tuple[LiteralType, ...], optional): The values for parameters defined\n        in `args`. Defaults to ().\n        name (Optional[str], optional): Name to give this run. Defaults to None.\n        blockade_radius (float, optional): Use the Blockade subspace given a\n        particular radius. Defaults to 0.0.\n        waveform_runtime: (bool, optional): Use Numba to compile the waveforms,\n        Defaults to False.\n        interaction_picture (bool, optional): Use the interaction picture when\n        solving schrodinger equation. Defaults to False.\n        cache_matrices (bool, optional): Reuse previously evaluated matrcies when\n        possible. Defaults to False.\n        multiprocessing (bool, optional): Use multiple processes to process the\n        batches. Defaults to False.\n        num_workers (Optional[int], optional): Number of processes to run with\n        multiprocessing. Defaults to None.\n        solver_name (str, optional): Which SciPy Solver to use. Defaults to\n        \"dop853\".\n        atol (float, optional): Absolute tolerance for ODE solver. Defaults to\n        1e-14.\n        rtol (float, optional): Relative tolerance for adaptive step in ODE solver.\n        Defaults to 1e-7.\n        nsteps (int, optional): Maximum number of steps allowed per integration\n        step. Defaults to 2_147_483_647, the maximum value.\n\n    Raises:\n        ValueError: Cannot use multiprocessing and cache_matrices at the same time.\n\n    Returns:\n        LocalBatch: Batch of local tasks that have been executed.\n    \"\"\"\n    if multiprocessing and cache_matrices:\n        raise ValueError(\n            \"Cannot use multiprocessing and cache_matrices at the same time.\"\n        )\n\n    compile_options = dict(\n        shots=shots,\n        args=args,\n        name=name,\n        blockade_radius=blockade_radius,\n        cache_matrices=cache_matrices,\n        waveform_runtime=waveform_runtime,\n    )\n\n    solver_options = dict(\n        multiprocessing=multiprocessing,\n        num_workers=num_workers,\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n\n    batch = self._compile(**compile_options)\n    batch._run(**solver_options)\n\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine.run_callback","title":"run_callback","text":"
run_callback(\n    callback,\n    program_args=(),\n    callback_args=(),\n    ignore_exceptions=False,\n    blockade_radius=0.0,\n    waveform_runtime=\"interpret\",\n    interaction_picture=False,\n    cache_matrices=False,\n    multiprocessing=False,\n    num_workers=None,\n    solver_name=\"dop853\",\n    atol=1e-07,\n    rtol=1e-14,\n    nsteps=2147483647,\n    use_hyperfine=False,\n)\n

Run state-vector simulation with a callback to access full state-vector from emulator

Parameters:

Name Type Description Default callback Callable[[StateVector, Metadata, RydbergHamiltonian, Any], Any] required program_args Tuple[LiteralType, ...]

The values for parameters

() callback_args Tuple[Any, ...]

Extra arguments to pass into

() ignore_exceptions bool

(bool, optional) If True any exception raised during

False blockade_radius float

Use the Blockade subspace given a

0.0 waveform_runtime str

(str, optional): Specify which runtime to use for

'interpret' interaction_picture bool

Use the interaction picture when

False cache_matrices bool

Reuse previously evaluated matrcies when

False multiprocessing bool

Use multiple processes to process the

False num_workers Optional[int]

Number of processes to run with

None solver_name str

Which SciPy Solver to use. Defaults to

'dop853' atol float

Absolute tolerance for ODE solver. Defaults to

1e-07 rtol float

Relative tolerance for adaptive step in ODE solver.

1e-14 nsteps int

Maximum number of steps allowed per integration

2147483647

Returns:

Name Type Description List List

List of resulting outputs from the callbacks

Raises:

Type Description RuntimeError

Raises the first error that occurs, only if

Note

For the callback function, first argument is the many-body wavefunction as a 1D complex numpy array, the second argument is of type Metadata which is a Named Tuple where the fields correspond to the parameters of that given task, RydbergHamiltonian is the object that contains the Hamiltonian used to generate the evolution for that task, Finally any optional positional arguments are allowed after that. The return value can be anything, the results will be collected in a list for each task in the batch.

Source code in src/bloqade/analog/ir/routine/bloqade.py
@beartype\ndef run_callback(\n    self,\n    callback: Callable[[StateVector, NamedTuple, RydbergHamiltonian, Any], Any],\n    program_args: Tuple[LiteralType, ...] = (),\n    callback_args: Tuple = (),\n    ignore_exceptions: bool = False,\n    blockade_radius: float = 0.0,\n    waveform_runtime: str = \"interpret\",\n    interaction_picture: bool = False,\n    cache_matrices: bool = False,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-7,\n    rtol: float = 1e-14,\n    nsteps: int = 2_147_483_647,\n    use_hyperfine: bool = False,\n) -> List:\n    \"\"\"Run state-vector simulation with a callback to access full state-vector from\n    emulator\n\n    Args:\n        callback (Callable[[StateVector, Metadata, RydbergHamiltonian, Any], Any]):\n        The callback function to run for each task in batch. See note below for more\n        details about the signature of the function.\n        program_args (Tuple[LiteralType, ...], optional): The values for parameters\n        defined in `args`. Defaults to ().\n        callback_args (Tuple[Any,...], optional): Extra arguments to pass into\n        ignore_exceptions: (bool, optional) If `True` any exception raised during\n        a task will be saved instead of the resulting output of the callback,\n        otherwise the first exception by task number will be raised after *all*\n        tasks have executed. Defaults to False.\n        blockade_radius (float, optional): Use the Blockade subspace given a\n        particular radius. Defaults to 0.0.\n        waveform_runtime: (str, optional): Specify which runtime to use for\n        waveforms. Defaults to \"interpret\".\n        interaction_picture (bool, optional): Use the interaction picture when\n        solving schrodinger equation. Defaults to False.\n        cache_matrices (bool, optional): Reuse previously evaluated matrcies when\n        possible. Defaults to False.\n        multiprocessing (bool, optional): Use multiple processes to process the\n        batches. Defaults to False.\n        num_workers (Optional[int], optional): Number of processes to run with\n        multiprocessing. Defaults to None.\n        solver_name (str, optional): Which SciPy Solver to use. Defaults to\n        \"dop853\".\n        atol (float, optional): Absolute tolerance for ODE solver. Defaults to\n        1e-14.\n        rtol (float, optional): Relative tolerance for adaptive step in ODE solver.\n        Defaults to 1e-7.\n        nsteps (int, optional): Maximum number of steps allowed per integration\n        step. Defaults to 2_147_483_647, the maximum value.\n\n    Returns:\n        List: List of resulting outputs from the callbacks\n\n    Raises:\n        RuntimeError: Raises the first error that occurs, only if\n        `ignore_exceptions=False`.\n\n    Note:\n        For the `callback` function, first argument is the many-body wavefunction\n        as a 1D complex numpy array, the second argument is of type `Metadata` which\n        is a Named Tuple where the fields correspond to the parameters of that given\n        task, RydbergHamiltonian is the object that contains the Hamiltonian used to\n        generate the evolution for that task, Finally any optional positional\n        arguments are allowed after that. The return value can be anything, the\n        results will be collected in a list for each task in the batch.\n\n\n    \"\"\"\n    if multiprocessing:\n        from multiprocessing import Queue, Process, cpu_count\n    else:\n        from queue import Queue\n\n    if cache_matrices:\n        compile_cache = CompileCache()\n    else:\n        compile_cache = None\n\n    solver_args = dict(\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n\n    runner = self.EmuRunner(\n        compile_cache=compile_cache,\n        solver_args=solver_args,\n        callback=callback,\n        callback_args=callback_args,\n    )\n\n    tasks = Queue()\n    results = Queue()\n\n    total_tasks = 0\n    ir_iter = self._generate_ir(\n        program_args, blockade_radius, waveform_runtime, use_hyperfine\n    )\n    for task_data in ir_iter:\n        task_number = task_data.task_id\n        emulator_ir = task_data.emulator_ir\n        metadata = task_data.metadata_dict\n        total_tasks += 1\n        tasks.put((task_number, (emulator_ir, metadata)))\n\n    workers = []\n    if multiprocessing:\n        num_workers = max(int(num_workers or cpu_count()), 1)\n        num_workers = min(total_tasks, num_workers)\n\n        for _ in range(num_workers):\n            worker = Process(\n                target=BloqadePythonRoutine.process_tasks,\n                args=(runner, tasks, results),\n            )\n            worker.start()\n\n            workers.append(worker)\n    else:\n        self.process_tasks(runner, tasks, results)\n\n    # blocks until all\n    # results have been fetched\n    # from the id_results Queue\n    id_results = []\n    for i in range(total_tasks):\n        id_results.append(results.get())\n\n    if workers:\n        for worker in workers:\n            worker.join()\n\n        tasks.close()\n        results.close()\n\n    id_results.sort(key=lambda x: x[0])\n    results = []\n\n    for task_id, result in id_results:\n        if not ignore_exceptions and isinstance(result, BaseException):\n            try:\n                raise result\n            except BaseException:\n                raise RuntimeError(\n                    f\"{result.__class__.__name__} occured during child process \"\n                    f\"running for task number {task_id}:\\n{traceback.format_exc()}\"\n                )\n\n        results.append(result)\n\n    return results\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.TaskData","title":"TaskData dataclass","text":"
TaskData(task_id, emulator_ir, metadata_dict)\n

Data class to hold the program ir and metadata for a given set of parameters

"},{"location":"reference/bloqade/analog/ir/routine/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine","title":"BraketHardwareRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine.__call__","title":"__call__","text":"
__call__(\n    *args,\n    shots=1,\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain Braket backend specific tasks, run_async to Braket, and wait until the results are coming back.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

1 args LiteralType

additional arguments for args variables.

() name str

custom name of the batch

None shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef __call__(\n    self,\n    *args: LiteralType,\n    shots: int = 1,\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n):\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n    Braket backend specific tasks, run_async to Braket,\n    and wait until the results are coming back.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args: additional arguments for args variables.\n        name (str): custom name of the batch\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    return self.run(shots, args, name, use_experimental, shuffle, **kwargs)\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine.run","title":"run","text":"
run(\n    shots,\n    args=(),\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain Braket backend specific tasks, run_async to Braket, and wait until the results are coming back.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple

additional arguments

() name str

custom name of the batch

None shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef run(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n) -> RemoteBatch:\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n    Braket backend specific tasks, run_async to Braket,\n    and wait until the results are coming back.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args (Tuple): additional arguments\n        name (str): custom name of the batch\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n\n    batch = self.run_async(shots, args, name, use_experimental, shuffle, **kwargs)\n    batch.pull()\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine.run_async","title":"run_async","text":"
run_async(\n    shots,\n    args=(),\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain Braket backend specific tasks, and run_async to Braket.

Note

This is async.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple

Values of the parameter defined in args, defaults to ()

() name str | None

custom name of the batch, defaults to None

None use_experimental bool

Use experimental hardware capabilities

False shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef run_async(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n) -> RemoteBatch:\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n    Braket backend specific tasks, and run_async to Braket.\n\n    Note:\n        This is async.\n\n    Args:\n        shots (int): number of shots\n        args (Tuple): Values of the parameter defined in `args`, defaults to ()\n        name (str | None): custom name of the batch, defaults to None\n        use_experimental (bool): Use experimental hardware capabilities\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n\n    batch = self._compile(shots, use_experimental, args, name)\n    batch._submit(shuffle, **kwargs)\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketLocalEmulatorRoutine","title":"BraketLocalEmulatorRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketLocalEmulatorRoutine.__call__","title":"__call__","text":"
__call__(\n    *args,\n    shots=1,\n    name=None,\n    multiprocessing=False,\n    num_workers=None,\n    **kwargs\n)\n

Compile to a LocalBatch, and run. The LocalBatch contain tasks to run on local emulator.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

1 args LiteralType

additional arguments for args variables.

() multiprocessing bool

enable multi-process

False num_workers int

number of workers to run the emulator

None Return

LocalBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef __call__(\n    self,\n    *args: LiteralType,\n    shots: int = 1,\n    name: Optional[str] = None,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    **kwargs,\n):\n    \"\"\"\n    Compile to a LocalBatch, and run.\n    The LocalBatch contain tasks to run on local emulator.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args: additional arguments for args variables.\n        multiprocessing (bool): enable multi-process\n        num_workers (int): number of workers to run the emulator\n\n    Return:\n        LocalBatch\n\n    \"\"\"\n    return self.run(\n        shots,\n        args,\n        name,\n        multiprocessing=multiprocessing,\n        num_workers=num_workers,\n        **kwargs,\n    )\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketLocalEmulatorRoutine.run","title":"run","text":"
run(\n    shots,\n    args=(),\n    name=None,\n    multiprocessing=False,\n    num_workers=None,\n    **kwargs\n)\n

Compile to a LocalBatch, and run. The LocalBatch contain tasks to run on local emulator.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple[LiteralType, ...]

additional arguments for args variables.

() multiprocessing bool

enable multi-process

False num_workers int

number of workers to run the emulator

None Return

LocalBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef run(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    **kwargs,\n) -> LocalBatch:\n    \"\"\"\n    Compile to a LocalBatch, and run.\n    The LocalBatch contain tasks to run on local emulator.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args: additional arguments for args variables.\n        multiprocessing (bool): enable multi-process\n        num_workers (int): number of workers to run the emulator\n\n    Return:\n        LocalBatch\n\n    \"\"\"\n\n    batch = self._compile(shots, args, name)\n    batch._run(multiprocessing=multiprocessing, num_workers=num_workers, **kwargs)\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/params/","title":"Params","text":""},{"location":"reference/bloqade/analog/ir/routine/quera/","title":"Quera","text":""},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.CustomSubmissionRoutine","title":"CustomSubmissionRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.CustomSubmissionRoutine.submit","title":"submit","text":"
submit(\n    shots,\n    url,\n    json_body_template,\n    method=\"POST\",\n    args=(),\n    request_options={},\n    use_experimental=False,\n    sleep_time=0.1,\n)\n

Compile to QuEraTaskSpecification and submit to a custom service.

Parameters:

Name Type Description Default shots int

number of shots

required url str

url of the custom service

required json_body_template str

json body template, must contain '{task_ir}'

required method str

http method to be used. Defaults to \"POST\".

'POST' args Tuple[LiteralType]

additional arguments to be passed into the

() request_options Dict[str, Any]

additional options to be passed into the request method,

{} use_experimental bool

Enable experimental hardware capabilities

False sleep_time float

time to sleep between each request. Defaults to 0.1.

0.1

Returns:

Type Description List[Tuple[NamedTuple, Response]]

List[Tuple[NamedTuple, Response]]: List of parameters for each batch in

List[Tuple[NamedTuple, Response]]

the task and the response from the post request.

Examples:

Here is a simple example of how to use this method. Note the body_template has double curly braces on the outside to escape the string formatting.

>>> body_template = \"{{\"token\": \"my_token\", \"task\": {task_ir}}}\"\n>>> responses = (\n    program.quera.custom.submit(\n        100,\n        \"http://my_custom_service.com\",\n        body_template\n    )\n)\n
Source code in src/bloqade/analog/ir/routine/quera.py
def submit(\n    self,\n    shots: int,\n    url: str,\n    json_body_template: str,\n    method: str = \"POST\",\n    args: Tuple[LiteralType] = (),\n    request_options: Dict[str, Any] = {},\n    use_experimental: bool = False,\n    sleep_time: float = 0.1,\n) -> List[Tuple[NamedTuple, Response]]:\n    \"\"\"Compile to QuEraTaskSpecification and submit to a custom service.\n\n    Args:\n        shots (int): number of shots\n        url (str): url of the custom service\n        json_body_template (str): json body template, must contain '{task_ir}'\n        which is a placeholder for a string representation of the task ir.\n        The task ir string will be inserted into the template with\n        `json_body_template.format(task_ir=task_ir_string)`.\n        to be replaced by QuEraTaskSpecification\n        method (str): http method to be used. Defaults to \"POST\".\n        args (Tuple[LiteralType]): additional arguments to be passed into the\n        compiler coming from `args` option of the build. Defaults to ().\n        request_options: additional options to be passed into the request method,\n        Note the `data` option will be overwritten by the\n        `json_body_template.format(task_ir=task_ir_string)`.\n        use_experimental (bool): Enable experimental hardware capabilities\n        sleep_time (float): time to sleep between each request. Defaults to 0.1.\n\n    Returns:\n        List[Tuple[NamedTuple, Response]]: List of parameters for each batch in\n        the task and the response from the post request.\n\n    Examples:\n        Here is a simple example of how to use this method. Note the body_template\n        has double curly braces on the outside to escape the string formatting.\n\n    ```python\n    >>> body_template = \"{{\"token\": \"my_token\", \"task\": {task_ir}}}\"\n    >>> responses = (\n        program.quera.custom.submit(\n            100,\n            \"http://my_custom_service.com\",\n            body_template\n        )\n    )\n    ```\n    \"\"\"\n\n    if r\"{task_ir}\" not in json_body_template:\n        raise ValueError(r\"body_template must contain '{task_ir}'\")\n\n    partial_eval = json_body_template.format(task_ir='\"task_ir\"')\n    try:\n        _ = json.loads(partial_eval)\n    except json.JSONDecodeError as e:\n        raise ValueError(\n            \"body_template must be a valid json template. \"\n            'When evaluating template with task_ir=\"task_ir\", '\n            f\"the template evaluated to: {partial_eval!r}.\\n\"\n            f\"JSONDecodeError: {e}\"\n        )\n\n    out = []\n    for metadata, task_ir in self._compile(shots, use_experimental, args):\n        json_request_body = json_body_template.format(\n            task_ir=task_ir.json(exclude_none=True, exclude_unset=True)\n        )\n        request_options.update(data=json_request_body)\n        response = request(method, url, **request_options)\n        out.append((metadata, response))\n        time.sleep(sleep_time)\n\n    return out\n
"},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.QuEraHardwareRoutine","title":"QuEraHardwareRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.QuEraHardwareRoutine.run_async","title":"run_async","text":"
run_async(\n    shots,\n    args=(),\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain QuEra backend specific tasks, and run_async through QuEra service.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple

additional arguments

() name str

custom name of the batch

None shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/quera.py
@beartype\ndef run_async(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n) -> RemoteBatch:\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n        QuEra backend specific tasks,\n        and run_async through QuEra service.\n\n    Args:\n        shots (int): number of shots\n        args (Tuple): additional arguments\n        name (str): custom name of the batch\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    batch = self._compile(shots, use_experimental, args, name)\n    batch._submit(shuffle, **kwargs)\n    return batch\n
"},{"location":"reference/bloqade/analog/submission/","title":"Index","text":""},{"location":"reference/bloqade/analog/submission/base/","title":"Base","text":""},{"location":"reference/bloqade/analog/submission/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/submission/load_config/","title":"Load config","text":""},{"location":"reference/bloqade/analog/submission/mock/","title":"Mock","text":""},{"location":"reference/bloqade/analog/submission/quera/","title":"Quera","text":""},{"location":"reference/bloqade/analog/submission/ir/","title":"Index","text":""},{"location":"reference/bloqade/analog/submission/ir/braket/","title":"Braket","text":"

Helper functions related to IR submission co-ordinations between Bloqade and Braket

"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.BraketTaskSpecification","title":"BraketTaskSpecification","text":"

Bases: BaseModel

Class representing geometry of an atom arrangement.

Attributes:

Name Type Description nshots int

Number of shots

program Program

IR(Intermediate Representation) program suitable for braket

"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.extract_braket_program","title":"extract_braket_program","text":"
extract_braket_program(quera_task_ir)\n

Extracts the Braket program.

Parameters:

Name Type Description Default quera_task_ir QuEraTaskSpecification

Quera IR(Intermediate representation) of the task.

required Source code in src/bloqade/analog/submission/ir/braket.py
def extract_braket_program(quera_task_ir: QuEraTaskSpecification):\n    \"\"\"Extracts the Braket program.\n\n    Args:\n        quera_task_ir (QuEraTaskSpecification):\n            Quera IR(Intermediate representation) of the task.\n    \"\"\"\n    lattice = quera_task_ir.lattice\n\n    rabi_amplitude = (\n        quera_task_ir.effective_hamiltonian.rydberg.rabi_frequency_amplitude.global_\n    )\n    rabi_phase = (\n        quera_task_ir.effective_hamiltonian.rydberg.rabi_frequency_phase.global_\n    )\n    global_detuning = quera_task_ir.effective_hamiltonian.rydberg.detuning.global_\n    local_detuning = quera_task_ir.effective_hamiltonian.rydberg.detuning.local\n\n    register = AtomArrangement()\n    for site, filled in zip(lattice.sites, lattice.filling):\n        site_type = SiteType.FILLED if filled == 1 else SiteType.VACANT\n        register.add(site, site_type)\n\n    hamiltonian = DrivingField(\n        amplitude=to_braket_field(rabi_amplitude),\n        phase=to_braket_field(rabi_phase),\n        detuning=to_braket_field(global_detuning),\n    )\n\n    if local_detuning:\n        hamiltonian = hamiltonian + ShiftingField(to_braket_field(local_detuning))\n\n    return AnalogHamiltonianSimulation(\n        register=register,\n        hamiltonian=hamiltonian,\n    )\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.from_braket_status_codes","title":"from_braket_status_codes","text":"
from_braket_status_codes(braket_status)\n

Gets the QuEraTaskStatusCode object for working with Bloqade SDK.

Parameters:

Name Type Description Default braket_status str

str The value of status in metadata() in the Amazon Braket. GetQuantumTask operation. If use_cached_value is True, the value most recently returned from GetQuantumTask operation is used

required

Returns:

Type Description QuEraTaskStatusCode

An object of the type Field in Braket SDK

Source code in src/bloqade/analog/submission/ir/braket.py
def from_braket_status_codes(braket_status: str) -> QuEraTaskStatusCode:\n    \"\"\"Gets the `QuEraTaskStatusCode` object for working with Bloqade SDK.\n\n    Args:\n        braket_status: str\n            The value of status in metadata() in the Amazon Braket.\n            `GetQuantumTask` operation. If `use_cached_value` is `True`,\n            the value most recently returned from\n            `GetQuantumTask` operation is used\n\n    Returns:\n        An object of the type `Field` in Braket SDK\n    \"\"\"\n    if braket_status == str(\"QUEUED\"):\n        return QuEraTaskStatusCode.Enqueued\n    else:\n        return QuEraTaskStatusCode(braket_status.lower().capitalize())\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.from_braket_task_results","title":"from_braket_task_results","text":"
from_braket_task_results(braket_task_results)\n

Get the QuEraTaskResults object for working with Bloqade SDK.

Parameters:

Name Type Description Default braket_task_results AnalogHamiltonianSimulationTaskResult

AnalogHamiltonianSimulationTaskResult Quantum task result of braket system

required

Returns:

Type Description QuEraTaskResults

An object of the type Field in Braket SDK.

Source code in src/bloqade/analog/submission/ir/braket.py
def from_braket_task_results(\n    braket_task_results: AnalogHamiltonianSimulationTaskResult,\n) -> QuEraTaskResults:\n    \"\"\"Get the `QuEraTaskResults` object for working with Bloqade SDK.\n\n    Args:\n        braket_task_results: AnalogHamiltonianSimulationTaskResult\n            Quantum task result of braket system\n\n    Returns:\n        An object of the type `Field` in Braket SDK.\n    \"\"\"\n    shot_outputs = []\n    for measurement in braket_task_results.measurements:\n        shot_outputs.append(\n            QuEraShotResult(\n                shot_status=QuEraShotStatusCode.Completed,\n                pre_sequence=list(measurement.pre_sequence),\n                post_sequence=list(measurement.post_sequence),\n            )\n        )\n\n    return QuEraTaskResults(\n        task_status=QuEraTaskStatusCode.Completed, shot_outputs=shot_outputs\n    )\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_field","title":"to_braket_field","text":"
to_braket_field(quera_field)\n

Converts to TimeSeries object supported by Braket.

Parameters:

Name Type Description Default quera_field Union[GlobalField, LocalField)]

Field supported by Quera

required

Returns:

Type Description Field

An object of the type braket.ahs.field.Field

Raises:

Type Description TypeError

If field is not of the type GlobalField or LocalField.

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_field(quera_field: Union[GlobalField, LocalField]) -> Field:\n    \"\"\"Converts to `TimeSeries` object supported by Braket.\n\n    Args:\n        quera_field (Union[GlobalField, LocalField)]:\n            Field supported by Quera\n\n    Returns:\n        An object of the type `braket.ahs.field.Field`\n\n    Raises:\n        TypeError: If field is not of the type `GlobalField` or `LocalField`.\n    \"\"\"\n    if isinstance(quera_field, GlobalField):\n        times = quera_field.times\n        values = quera_field.values\n        time_series = to_braket_time_series(times, values)\n        return Field(pattern=\"uniform\", time_series=time_series)\n    elif isinstance(quera_field, LocalField):\n        times = quera_field.times\n        values = quera_field.values\n        pattern = quera_field.lattice_site_coefficients\n        time_series = to_braket_time_series(times, values)\n        pattern = Pattern(pattern)\n        return Field(pattern=pattern, time_series=time_series)\n    else:\n        raise TypeError\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_task","title":"to_braket_task","text":"
to_braket_task(quera_task_ir)\n

Converts to Tuple[int, AnalogHamiltonianSimulation] object supported by Braket.

Parameters:

Name Type Description Default quera_task_ir QuEraTaskSpecification

Quera IR(Intermediate representation) of the task.

required

Returns:

Type Description Tuple[int, AnalogHamiltonianSimulation]

An tuple of the type Tuple[int, AnalogHamiltonianSimulation].

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_task(\n    quera_task_ir: QuEraTaskSpecification,\n) -> Tuple[int, AnalogHamiltonianSimulation]:\n    \"\"\"Converts to `Tuple[int, AnalogHamiltonianSimulation]` object supported by Braket.\n\n    Args:\n        quera_task_ir (QuEraTaskSpecification):\n            Quera IR(Intermediate representation) of the task.\n\n    Returns:\n        An tuple  of the type `Tuple[int, AnalogHamiltonianSimulation]`.\n    \"\"\"\n    braket_ahs_program = extract_braket_program(quera_task_ir)\n    return quera_task_ir.nshots, braket_ahs_program\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_task_ir","title":"to_braket_task_ir","text":"
to_braket_task_ir(quera_task_ir)\n

Converts quera IR(Intermendiate Representation) to to BraketTaskSpecification object.

Parameters:

Name Type Description Default quera_task_ir QuEraTaskSpecification

Quera IR(Intermediate representation) of the task.

required

Returns:

Type Description BraketTaskSpecification

An object of the type BraketTaskSpecification in Braket SDK

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_task_ir(quera_task_ir: QuEraTaskSpecification) -> BraketTaskSpecification:\n    \"\"\"Converts quera IR(Intermendiate Representation) to\n    to `BraketTaskSpecification` object.\n\n    Args:\n        quera_task_ir (QuEraTaskSpecification):\n            Quera IR(Intermediate representation) of the task.\n\n    Returns:\n        An object of the type `BraketTaskSpecification` in Braket SDK\n\n    \"\"\"\n    nshots, braket_ahs_program = to_braket_task(quera_task_ir)\n    return BraketTaskSpecification(nshots=nshots, program=braket_ahs_program.to_ir())\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_time_series","title":"to_braket_time_series","text":"
to_braket_time_series(times, values)\n

Converts to TimeSeries object supported by Braket.

Parameters:

Name Type Description Default times List[Decimal]

Times of the value.

required values List[Decimal]

Corresponding values to add to the time series

required

Returns:

Type Description TimeSeries

An object of the type braket.timings.TimeSeries

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_time_series(times: List[Decimal], values: List[Decimal]) -> TimeSeries:\n    \"\"\"Converts to `TimeSeries` object supported by Braket.\n\n    Args:\n        times (List[Decimal]): Times of the value.\n        values (List[Decimal]): Corresponding values to add to the time series\n\n    Returns:\n        An object of the type `braket.timings.TimeSeries`\n    \"\"\"\n    time_series = TimeSeries()\n    for time, value in zip(times, values):\n        time_series.put(time, value)\n\n    return time_series\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_quera_capabilities","title":"to_quera_capabilities","text":"
to_quera_capabilities(paradigm)\n

Converts to QuEraCapabilities object supported by Braket.

Parameters:

Name Type Description Default paradigm

The paradigm property of the AwsDevice object for Aquila

required

Returns:

Type Description QuEraCapabilities

An object of the type QuEraCapabilities in Bloqade SDK.

Source code in src/bloqade/analog/submission/ir/braket.py
def to_quera_capabilities(paradigm) -> cp.QuEraCapabilities:\n    \"\"\"Converts to `QuEraCapabilities` object supported by Braket.\n\n    Args:\n        paradigm: The `paradigm` property of the `AwsDevice` object for Aquila\n\n    Returns:\n        An object of the type `QuEraCapabilities` in Bloqade SDK.\n    \"\"\"\n    rydberg_global = paradigm.rydberg.rydbergGlobal\n\n    return cp.QuEraCapabilities(\n        version=paradigm.braketSchemaHeader.version,\n        capabilities=cp.DeviceCapabilities(\n            task=cp.TaskCapabilities(\n                number_shots_min=1,\n                number_shots_max=1000,\n            ),\n            lattice=cp.LatticeCapabilities(\n                number_qubits_max=paradigm.qubitCount,\n                geometry=cp.LatticeGeometryCapabilities(\n                    spacing_radial_min=paradigm.lattice.geometry.spacingRadialMin,\n                    spacing_vertical_min=paradigm.lattice.geometry.spacingVerticalMin,\n                    position_resolution=paradigm.lattice.geometry.positionResolution,\n                    number_sites_max=paradigm.lattice.geometry.numberSitesMax,\n                ),\n                area=cp.LatticeAreaCapabilities(\n                    width=paradigm.lattice.area.width,\n                    height=paradigm.lattice.area.height,\n                ),\n            ),\n            rydberg=cp.RydbergCapabilities(\n                c6_coefficient=paradigm.rydberg.c6Coefficient,\n                global_=cp.RydbergGlobalCapabilities(\n                    rabi_frequency_max=rydberg_global.rabiFrequencyRange[0],\n                    rabi_frequency_min=rydberg_global.rabiFrequencyRange[1],\n                    rabi_frequency_resolution=rydberg_global.rabiFrequencyResolution,\n                    rabi_frequency_slew_rate_max=rydberg_global.rabiFrequencySlewRateMax,\n                    detuning_max=rydberg_global.detuningRange[0],\n                    detuning_min=rydberg_global.detuningRange[1],\n                    detuning_resolution=rydberg_global.detuningResolution,\n                    detuning_slew_rate_max=rydberg_global.detuningSlewRateMax,\n                    phase_min=rydberg_global.phaseRange[0],\n                    phase_max=rydberg_global.phaseRange[1],\n                    phase_resolution=rydberg_global.phaseResolution,\n                    time_min=rydberg_global.timeMin,\n                    time_max=rydberg_global.timeMax,\n                    time_resolution=rydberg_global.timeResolution,\n                    time_delta_min=rydberg_global.timeDeltaMin,\n                ),\n                local=None,\n            ),\n        ),\n    )\n
"},{"location":"reference/bloqade/analog/submission/ir/capabilities/","title":"Capabilities","text":""},{"location":"reference/bloqade/analog/submission/ir/parallel/","title":"Parallel","text":""},{"location":"reference/bloqade/analog/submission/ir/parallel/#bloqade.analog.submission.ir.parallel.ClusterLocationInfo","title":"ClusterLocationInfo","text":"

Bases: BaseModel

Class that stores the mapping of batched jobs.

Parameters:

Name Type Description Default cluster_index int

the index of the cluster a site belongs to

required global_location_index int

the index of the site in the multplexed system

required cluster_location_index int

the index of the site in the original system

required"},{"location":"reference/bloqade/analog/submission/ir/task_results/","title":"Task results","text":""},{"location":"reference/bloqade/analog/submission/ir/task_results/#bloqade.analog.submission.ir.task_results.QuEraTaskResults","title":"QuEraTaskResults","text":"

Bases: BaseModel

"},{"location":"reference/bloqade/analog/submission/ir/task_results/#bloqade.analog.submission.ir.task_results.QuEraTaskResults.export_as_probabilities","title":"export_as_probabilities","text":"
export_as_probabilities()\n

converts from shot results to probabilities

Returns:

Name Type Description TaskProbabilities TaskProbabilities

The task results as probabilties

Source code in src/bloqade/analog/submission/ir/task_results.py
def export_as_probabilities(self) -> TaskProbabilities:\n    \"\"\"converts from shot results to probabilities\n\n    Returns:\n        TaskProbabilities: The task results as probabilties\n    \"\"\"\n    counts = dict()\n    nshots = len(self.shot_outputs)\n    for shot_result in self.shot_outputs:\n        pre_sequence_str = \"\".join(str(bit) for bit in shot_result.pre_sequence)\n\n        post_sequence_str = \"\".join(str(bit) for bit in shot_result.post_sequence)\n\n        configuration = (pre_sequence_str, post_sequence_str)\n        # iterative average\n        current_count = counts.get(configuration, 0)\n        counts[configuration] = current_count + 1\n\n    probabilities = [(config, count / nshots) for config, count in counts.items()]\n    return TaskProbabilities(probabilities=probabilities)\n
"},{"location":"reference/bloqade/analog/submission/ir/task_results/#bloqade.analog.submission.ir.task_results.QuEraTaskStatusCode","title":"QuEraTaskStatusCode","text":"

Bases: str, Enum

An Enum representing the various states a task can be in within the QuEra system.

Attributes:

Name Type Description Created

The task has been created but not yet started.

Running

The task is currently running.

Completed

The task has completed successfully.

Failed

The task has failed.

Cancelled

The task has been cancelled.

Executing

The task is currently being executed.

Enqueued

The task is in the queue waiting to be executed.

Accepted

The task has been accepted for execution.

Unaccepted

The task has not been accepted for execution.

Partial

The task has partially completed.

Unsubmitted

The task has not been submitted for execution.

"},{"location":"reference/bloqade/analog/submission/ir/task_specification/","title":"Task specification","text":""},{"location":"reference/bloqade/analog/task/","title":"Index","text":""},{"location":"reference/bloqade/analog/task/base/","title":"Base","text":""},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Geometry","title":"Geometry","text":"

Class representing geometry of an atom arrangement.

Attributes:

Name Type Description sites List[Tuple[float, float]]

Atom site arrangement

filling List[int]

Which sites are filled

parallel_decoder Optional[ParallelDecoder]

Decoder object for decoding Geometry object

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.LocalTask","title":"LocalTask","text":"

Bases: Task

Task to use for local executions for simulation purposes..

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.RemoteTask","title":"RemoteTask","text":"

Bases: Task

Task to use for remote executions to run the program on Quera Quantum Computers.

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report","title":"Report","text":"
Report(data, metas, geos, name='')\n

Report is a helper class for organizing and analysing data

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report--analyzing-results","title":"Analyzing Results","text":"

When you've retrieved your results from either emulation or hardware you can generate a .report():

report = results.report()\n

For the examples below we analyze the results of a two atom program.

The report contains useful information such as:

The raw bitstrings measured per each execution of the program

>>> report.bitstrings()\n[array([[1, 1],\n        [1, 1],\n        [1, 1],\n        ...,\n        [1, 1],\n        [1, 1],\n

The number of times each unique bitstring occurred:

>>> report.counts()\n\n[OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n

The Rydberg Density for each atom

>>> report.rydberg_densities()\n\n                0      1\ntask_number\n0            0.053  0.054\n

Source code in src/bloqade/analog/task/base.py
def __init__(self, data, metas, geos, name=\"\") -> None:\n    self.dataframe = data  # df\n    self._bitstrings = None  # bitstring cache\n    self._counts = None  # counts cache\n    self.metas = metas\n    self.geos = geos\n    self.name = name + \" \" + str(datetime.datetime.now())\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.markdown","title":"markdown property","text":"
markdown\n

Get the markdown representation of the dataframe

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.bitstrings","title":"bitstrings","text":"
bitstrings(filter_perfect_filling=True, clusters=[])\n

Get the bitstrings from the data.

Parameters:

Name Type Description Default filter_perfect_filling bool

whether return will only contain perfect filling shots. Defaults to True.

True clusters Union[tuple[int, int], List[tuple[int, int]]]

(tuple[int, int], Sequence[Tuple[int, int]]): cluster index to filter shots from. If none are provided all clusters are used, defaults to [].

[]

Returns:

Name Type Description bitstrings list of ndarray

list corresponding to each task in the report. Each element is an ndarray of shape (nshots, nsites) where nshots is the number of shots for the task and nsites is the number of sites in the task. For example:

[array([[1, 1],\n        [1, 1],\n        [1, 1],\n        ...,\n        [1, 1],\n        [1, 1],\n        [1, 0]], dtype=int8)]\n

Note

Note that nshots may vary between tasks if filter_perfect_filling is set to True.

Source code in src/bloqade/analog/task/base.py
@beartype\ndef bitstrings(\n    self,\n    filter_perfect_filling: bool = True,\n    clusters: Union[tuple[int, int], List[tuple[int, int]]] = [],\n) -> List[NDArray]:\n    \"\"\"Get the bitstrings from the data.\n\n    Args:\n        filter_perfect_filling (bool): whether return will\n            only contain perfect filling shots. Defaults to True.\n        clusters: (tuple[int, int], Sequence[Tuple[int, int]]):\n            cluster index to filter shots from. If none are provided\n            all clusters are used, defaults to [].\n\n    Returns:\n        bitstrings (list of ndarray): list corresponding to each\n            task in the report. Each element is an ndarray of shape\n            (nshots, nsites) where nshots is the number of shots for\n            the task and nsites is the number of sites in the task.\n            For example:\n            ```python3\n            [array([[1, 1],\n                    [1, 1],\n                    [1, 1],\n                    ...,\n                    [1, 1],\n                    [1, 1],\n                    [1, 0]], dtype=int8)]\n            ```\n\n    Note:\n        Note that nshots may vary between tasks if filter_perfect_filling\n        is set to True.\n\n    \"\"\"\n\n    task_numbers = self.dataframe.index.get_level_values(\"task_number\").unique()\n\n    bitstrings = []\n    for task_number in task_numbers:\n        mask = self._filter(\n            task_number=task_number,\n            filter_perfect_filling=filter_perfect_filling,\n            clusters=clusters,\n        )\n        if np.any(mask):\n            bitstrings.append(self.dataframe.loc[mask].to_numpy())\n        else:\n            bitstrings.append(\n                np.zeros((0, self.dataframe.shape[1]), dtype=np.uint8)\n            )\n\n    return bitstrings\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.counts","title":"counts","text":"
counts(filter_perfect_filling=True, clusters=[])\n

Get the counts of unique bit strings.

Parameters:

Name Type Description Default filter_perfect_filling bool

whether return will only contain perfect filling shots. Defaults to True.

True clusters Union[tuple[int, int], List[tuple[int, int]]]

(tuple[int, int], Sequence[Tuple[int, int]]): cluster index to filter shots from. If none are provided all clusters are used, defaults to [].

[]

Returns:

Name Type Description counts list of OrderedDict[str, int]

list corresponding to each task in the report. Each element is an ndarray of shape (nshots, nsites) where nshots is the number of shots for the task and nsites is the number of sites in the task. For example:

    [OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n

Note

Note that nshots may vary between tasks if filter_perfect_filling is set to True.

Source code in src/bloqade/analog/task/base.py
def counts(\n    self,\n    filter_perfect_filling: bool = True,\n    clusters: Union[tuple[int, int], List[tuple[int, int]]] = [],\n) -> List[OrderedDict[str, int]]:\n    \"\"\"Get the counts of unique bit strings.\n\n    Args:\n        filter_perfect_filling (bool): whether return will\n            only contain perfect filling shots. Defaults to True.\n        clusters: (tuple[int, int], Sequence[Tuple[int, int]]):\n            cluster index to filter shots from. If none are provided\n            all clusters are used, defaults to [].\n\n    Returns:\n        counts (list of OrderedDict[str, int]): list corresponding to each\n            task in the report. Each element is an ndarray of shape\n            (nshots, nsites) where nshots is the number of shots for\n            the task and nsites is the number of sites in the task.\n            For example:\n            ```python\n                [OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n            ```\n\n    Note:\n        Note that nshots may vary between tasks if filter_perfect_filling\n        is set to True.\n\n    \"\"\"\n\n    def _generate_counts(bitstring):\n        output = np.unique(bitstring, axis=0, return_counts=True)\n\n        count_list = [\n            (\"\".join(map(str, bitstring)), int(count))\n            for bitstring, count in zip(*output)\n        ]\n        count_list.sort(key=lambda x: x[1], reverse=True)\n        count = OrderedDict(count_list)\n\n        return count\n\n    return list(\n        map(_generate_counts, self.bitstrings(filter_perfect_filling, clusters))\n    )\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.list_param","title":"list_param","text":"
list_param(field_name)\n

List the parameters associate with the given variable field_name for each tasks.

Parameters:

Name Type Description Default field_name str

variable name

required Source code in src/bloqade/analog/task/base.py
def list_param(self, field_name: str) -> List[Union[Number, None]]:\n    \"\"\"\n    List the parameters associate with the given variable field_name\n    for each tasks.\n\n    Args:\n        field_name (str): variable name\n\n    \"\"\"\n\n    def cast(x):\n        if x is None:\n            return None\n        elif isinstance(x, (list, tuple, np.ndarray)):\n            return list(map(cast, x))\n        else:\n            return float(x)\n\n    return list(map(cast, (meta.get(field_name) for meta in self.metas)))\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.rydberg_densities","title":"rydberg_densities","text":"
rydberg_densities(filter_perfect_filling=True, clusters=[])\n

Get rydberg density for each task.

Parameters:

Name Type Description Default filter_perfect_filling bool

whether return will only contain perfect filling shots. Defaults to True.

True clusters Union[tuple[int, int], List[tuple[int, int]]]

(tuple[int, int], Sequence[Tuple[int, int]]): cluster index to filter shots from. If none are provided all clusters are used, defaults to [].

[]

Returns:

Name Type Description rydberg_densities Union[Series, DataFrame]

per-site rydberg density for each task as a pandas DataFrame or Series. For example:

0      1\ntask_number\n0            0.053  0.054\n

Source code in src/bloqade/analog/task/base.py
@beartype\ndef rydberg_densities(\n    self,\n    filter_perfect_filling: bool = True,\n    clusters: Union[tuple[int, int], List[tuple[int, int]]] = [],\n) -> Union[pd.Series, pd.DataFrame]:\n    \"\"\"Get rydberg density for each task.\n\n    Args:\n        filter_perfect_filling (bool, optional): whether return will\n            only contain perfect filling shots. Defaults to True.\n        clusters: (tuple[int, int], Sequence[Tuple[int, int]]):\n            cluster index to filter shots from. If none are provided\n            all clusters are used, defaults to [].\n\n    Returns:\n        rydberg_densities (Union[pd.Series, pd.DataFrame]):\n            per-site rydberg density for each task as a pandas DataFrame or Series.\n            For example:\n            ```python\n            0      1\n            task_number\n            0            0.053  0.054\n            ```\n    \"\"\"\n    mask = self._filter(\n        filter_perfect_filling=filter_perfect_filling, clusters=clusters\n    )\n    df = self.dataframe[mask]\n    return 1 - (df.groupby(\"task_number\").mean())\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.show","title":"show","text":"
show()\n

Interactive Visualization of the Report

Source code in src/bloqade/analog/task/base.py
def show(self):\n    \"\"\"\n    Interactive Visualization of the Report\n\n    \"\"\"\n    display_report(self)\n
"},{"location":"reference/bloqade/analog/task/batch/","title":"Batch","text":""},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Filter","title":"Filter","text":""},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Filter.filter_metadata","title":"filter_metadata","text":"
filter_metadata(__match_any__=False, **metadata)\n

Create a Batch object that has tasks filtered based on the values of metadata.

Parameters:

Name Type Description Default __match_any__ bool

if True, then a task will be included if it matches any of the metadata filters. If False, then a task will be included only if it matches all of the metadata filters. Defaults to False.

False **metadata MetadataFilterType

the metadata to filter on. The keys are the metadata names and the values (as a set) are the values to filter on. The elements in the set can be Real, Decimal, Tuple[Real], or Tuple[Decimal].

{} Return

type(self): a Batch object with the filtered tasks, either LocalBatch or RemoteBatch depending on the type of self

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef filter_metadata(\n    self, __match_any__: bool = False, **metadata: MetadataFilterType\n) -> Union[\"LocalBatch\", \"RemoteBatch\"]:\n    \"\"\"Create a Batch object that has tasks filtered based on the\n    values of metadata.\n\n    Args:\n        __match_any__: if True, then a task will be included if it\n            matches any of the metadata filters. If False, then a\n            task will be included only if it matches all of the\n            metadata filters. Defaults to False.\n\n        **metadata: the metadata to filter on. The keys are the metadata\n            names and the values (as a set) are the values to filter on.\n            The elements in the set can be Real, Decimal, Tuple[Real], or\n            Tuple[Decimal].\n\n    Return:\n        type(self): a Batch object with the filtered tasks, either\n            LocalBatch or RemoteBatch depending on the type of self\n\n    \"\"\"\n\n    def convert_to_decimal(element):\n        if isinstance(element, list):\n            return list(map(convert_to_decimal, element))\n        elif isinstance(element, (Real, Decimal)):\n            return Decimal(str(element))\n        else:\n            raise ValueError(\n                f\"Invalid value {element} for metadata filter. \"\n                \"Only Real, Decimal, List[Real], and List[Decimal] \"\n                \"are supported.\"\n            )\n\n    def metadata_match_all(task):\n        return all(\n            task.metadata.get(key) in value for key, value in metadata.items()\n        )\n\n    def metadata_match_any(task):\n        return any(\n            task.metadata.get(key) in value for key, value in metadata.items()\n        )\n\n    metadata = {k: list(map(convert_to_decimal, v)) for k, v in metadata.items()}\n\n    metadata_filter = metadata_match_any if __match_any__ else metadata_match_all\n\n    new_tasks = OrderedDict(\n        [(k, v) for k, v in self.tasks.items() if metadata_filter(v)]\n    )\n\n    kw = dict(self.__dict__)\n    kw[\"tasks\"] = new_tasks\n\n    return self.__class__(**kw)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch","title":"LocalBatch dataclass","text":"
LocalBatch(source, tasks, name=None)\n

Bases: Serializable, Filter

"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch._run","title":"_run","text":"
_run(multiprocessing=False, num_workers=None, **kwargs)\n

Private method to run tasks in the batch.

Parameters:

Name Type Description Default multiprocessing bool

If True, tasks are run in parallel using multiple processes. If False, tasks are run sequentially in a single process. Defaults to False.

False num_workers Optional[int]

The maximum number of processes that can be used to execute the given calls if multiprocessing is True. If None, the number of workers will be the number of processors on the machine.

None **kwargs

Arbitrary keyword arguments passed to the task's run method.

{}

Raises:

Type Description ValueError

If num_workers is not None and multiprocessing is False.

Returns:

Name Type Description self

The instance of the batch with tasks run.

Source code in src/bloqade/analog/task/batch.py
def _run(\n    self, multiprocessing: bool = False, num_workers: Optional[int] = None, **kwargs\n):\n    \"\"\"\n    Private method to run tasks in the batch.\n\n    Args:\n        multiprocessing (bool, optional): If True, tasks are run in parallel using multiple processes.\n            If False, tasks are run sequentially in a single process. Defaults to False.\n        num_workers (Optional[int], optional): The maximum number of processes that can be used to\n            execute the given calls if multiprocessing is True. If None, the number of workers will be the number of processors on the machine.\n        **kwargs: Arbitrary keyword arguments passed to the task's run method.\n\n    Raises:\n        ValueError: If num_workers is not None and multiprocessing is False.\n\n    Returns:\n        self: The instance of the batch with tasks run.\n    \"\"\"\n    if multiprocessing:\n        from concurrent.futures import ProcessPoolExecutor as Pool\n\n        with Pool(max_workers=num_workers) as pool:\n            futures = OrderedDict()\n            for task_number, task in enumerate(self.tasks.values()):\n                futures[task_number] = pool.submit(task.run, **kwargs)\n\n            for task_number, future in futures.items():\n                self.tasks[task_number] = future.result()\n\n    else:\n        if num_workers is not None:\n            raise ValueError(\n                \"num_workers is only used when multiprocessing is enabled.\"\n            )\n        for task in self.tasks.values():\n            task.run(**kwargs)\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch.report","title":"report","text":"
report()\n

Generate analysis report base on currently completed tasks in the LocalBatch.

Return

Report

Source code in src/bloqade/analog/task/batch.py
def report(self) -> Report:\n    \"\"\"\n    Generate analysis report base on currently\n    completed tasks in the LocalBatch.\n\n    Return:\n        Report\n\n    \"\"\"\n\n    ## this potentially can be specialize/disatch\n    ## offline\n    index = []\n    data = []\n    metas = []\n    geos = []\n\n    for task_number, task in self.tasks.items():\n        geometry = task.geometry\n        perfect_sorting = \"\".join(map(str, geometry.filling))\n        parallel_decoder = geometry.parallel_decoder\n\n        if parallel_decoder:\n            cluster_indices = parallel_decoder.get_cluster_indices()\n        else:\n            cluster_indices = {(0, 0): list(range(len(perfect_sorting)))}\n\n        shot_iter = filter(\n            lambda shot: shot.shot_status == QuEraShotStatusCode.Completed,\n            task.result().shot_outputs,\n        )\n\n        for shot, (cluster_coordinate, cluster_index) in product(\n            shot_iter, cluster_indices.items()\n        ):\n            pre_sequence = \"\".join(\n                map(\n                    str,\n                    (shot.pre_sequence[index] for index in cluster_index),\n                )\n            )\n\n            post_sequence = np.asarray(\n                [shot.post_sequence[index] for index in cluster_index],\n                dtype=np.int8,\n            )\n\n            pfc_sorting = \"\".join(\n                [perfect_sorting[index] for index in cluster_index]\n            )\n\n            key = (\n                task_number,\n                cluster_coordinate,\n                pfc_sorting,\n                pre_sequence,\n            )\n\n            index.append(key)\n            data.append(post_sequence)\n\n        metas.append(task.metadata)\n        geos.append(task.geometry)\n\n    index = pd.MultiIndex.from_tuples(\n        index, names=[\"task_number\", \"cluster\", \"perfect_sorting\", \"pre_sequence\"]\n    )\n\n    df = pd.DataFrame(data, index=index)\n    df.sort_index(axis=\"index\")\n\n    rept = None\n    if self.name is None:\n        rept = Report(df, metas, geos, \"Local\")\n    else:\n        rept = Report(df, metas, geos, self.name)\n\n    return rept\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch.rerun","title":"rerun","text":"
rerun(multiprocessing=False, num_workers=None, **kwargs)\n

Rerun all the tasks in the LocalBatch.

Return

Report

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef rerun(\n    self, multiprocessing: bool = False, num_workers: Optional[int] = None, **kwargs\n):\n    \"\"\"\n    Rerun all the tasks in the LocalBatch.\n\n    Return:\n        Report\n\n    \"\"\"\n\n    return self._run(\n        multiprocessing=multiprocessing, num_workers=num_workers, **kwargs\n    )\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch","title":"RemoteBatch dataclass","text":"
RemoteBatch(source, tasks, name=None)\n

Bases: Serializable, Filter

"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.total_nshots","title":"total_nshots property","text":"
total_nshots\n

Total number of shots of all tasks in the RemoteBatch

Return

number of shots

"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch._submit","title":"_submit","text":"
_submit(\n    shuffle_submit_order=True,\n    ignore_submission_error=False,\n    **kwargs\n)\n

Private method to submit tasks in the RemoteBatch.

Parameters:

Name Type Description Default shuffle_submit_order bool

If True, tasks are submitted in a random order. If False, tasks are submitted in the order they were added to the batch. Defaults to True.

True ignore_submission_error bool

If True, submission errors are ignored and the method continues to submit the remaining tasks. If False, the method stops at the first submission error. Defaults to False.

False **kwargs

Arbitrary keyword arguments.

{}

Returns:

Name Type Description RemoteBatch RemoteBatch

The RemoteBatch instance with tasks submitted.

Source code in src/bloqade/analog/task/batch.py
def _submit(\n    self, shuffle_submit_order: bool = True, ignore_submission_error=False, **kwargs\n) -> \"RemoteBatch\":\n    \"\"\"\n    Private method to submit tasks in the RemoteBatch.\n\n    Args:\n        shuffle_submit_order (bool, optional): If True, tasks are submitted in a random order.\n            If False, tasks are submitted in the order they were added to the batch. Defaults to True.\n        ignore_submission_error (bool, optional): If True, submission errors are ignored and the method continues to submit the remaining tasks.\n            If False, the method stops at the first submission error. Defaults to False.\n        **kwargs: Arbitrary keyword arguments.\n\n    Returns:\n        RemoteBatch: The RemoteBatch instance with tasks submitted.\n    \"\"\"\n    from bloqade.analog import save\n\n    # online, non-blocking\n    if shuffle_submit_order:\n        submission_order = np.random.permutation(list(self.tasks.keys()))\n    else:\n        submission_order = list(self.tasks.keys())\n\n    # submit tasks in random order but store them\n    # in the original order of tasks.\n    # futures = OrderedDict()\n\n    ## upon submit() should validate for Both backends\n    ## and throw errors when fail.\n    errors = BatchErrors()\n    shuffled_tasks = OrderedDict()\n    for task_index in submission_order:\n        task = self.tasks[task_index]\n        shuffled_tasks[task_index] = task\n        try:\n            task.submit(**kwargs)\n        except BaseException as error:\n            # record the error in the error dict\n            errors.task_errors[int(task_index)] = TaskError(\n                exception_type=error.__class__.__name__,\n                stack_trace=traceback.format_exc(),\n            )\n\n            task.task_result_ir = QuEraTaskResults(\n                task_status=QuEraTaskStatusCode.Unaccepted\n            )\n\n    self.tasks = shuffled_tasks  # permute order using dump way\n\n    if len(errors.task_errors) > 0:\n        time_stamp = datetime.datetime.now()\n\n        if \"win\" in sys.platform:\n            time_stamp = str(time_stamp).replace(\":\", \"~\")\n\n        if self.name:\n            future_file = f\"{self.name}-partial-batch-future-{time_stamp}.json\"\n            error_file = f\"{self.name}-partial-batch-errors-{time_stamp}.json\"\n        else:\n            future_file = f\"partial-batch-future-{time_stamp}.json\"\n            error_file = f\"partial-batch-errors-{time_stamp}.json\"\n\n        cwd = os.getcwd()\n        # cloud_batch_result.save_json(future_file, indent=2)\n        # saving ?\n\n        save(errors, error_file)\n        save(self, future_file)\n\n        if ignore_submission_error:\n            warnings.warn(\n                \"One or more error(s) occured during submission, please see \"\n                \"the following files for more information:\\n\"\n                f\"  - {os.path.join(cwd, future_file)}\\n\"\n                f\"  - {os.path.join(cwd, error_file)}\\n\",\n                RuntimeWarning,\n            )\n        else:\n            raise RemoteBatch.SubmissionException(\n                str(errors)\n                + \"\\n\"\n                + \"One or more error(s) occured during submission, please see \"\n                \"the following files for more information:\\n\"\n                f\"  - {os.path.join(cwd, future_file)}\\n\"\n                f\"  - {os.path.join(cwd, error_file)}\\n\"\n            )\n\n    else:\n        # TODO: think about if we should automatically save successful submissions\n        #       as well.\n        pass\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.cancel","title":"cancel","text":"
cancel()\n

Cancel all the tasks in the Batch.

Return

self

Source code in src/bloqade/analog/task/batch.py
def cancel(self) -> \"RemoteBatch\":\n    \"\"\"\n    Cancel all the tasks in the Batch.\n\n    Return:\n        self\n\n    \"\"\"\n    # cancel all jobs\n    for task in self.tasks.values():\n        task.cancel()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.fetch","title":"fetch","text":"
fetch()\n

Fetch the tasks in the Batch.

Note

Fetching will update the status of tasks, and only pull the results for those tasks that have completed.

Return

self

Source code in src/bloqade/analog/task/batch.py
def fetch(self) -> \"RemoteBatch\":\n    \"\"\"\n    Fetch the tasks in the Batch.\n\n    Note:\n        Fetching will update the status of tasks,\n        and only pull the results for those tasks\n        that have completed.\n\n    Return:\n        self\n\n    \"\"\"\n    # online, non-blocking\n    # pull the results only when its ready\n    for task in self.tasks.values():\n        task.fetch()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_completed_tasks","title":"get_completed_tasks","text":"
get_completed_tasks()\n

Create a RemoteBatch object that contain completed tasks from current Batch.

Tasks consider completed with following status codes:

  1. Completed
  2. Partial
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def get_completed_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain completed tasks from current Batch.\n\n    Tasks consider completed with following status codes:\n\n    1. Completed\n    2. Partial\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    statuses = [\n        \"Completed\",\n        \"Partial\",\n    ]\n    return self.get_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_failed_tasks","title":"get_failed_tasks","text":"
get_failed_tasks()\n

Create a RemoteBatch object that contain failed tasks from current Batch.

failed tasks with following status codes:

  1. Failed
  2. Unaccepted
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def get_failed_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain failed tasks from current Batch.\n\n    failed tasks with following status codes:\n\n    1. Failed\n    2. Unaccepted\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # statuses that are in a state that are\n    # completed because of an error\n    statuses = [\"Failed\", \"Unaccepted\"]\n    return self.get_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_finished_tasks","title":"get_finished_tasks","text":"
get_finished_tasks()\n

Create a RemoteBatch object that contain finished tasks from current Batch.

Tasks consider finished with following status codes:

  1. Failed
  2. Unaccepted
  3. Completed
  4. Partial
  5. Cancelled
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def get_finished_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain finished tasks from current Batch.\n\n    Tasks consider finished with following status codes:\n\n    1. Failed\n    2. Unaccepted\n    3. Completed\n    4. Partial\n    5. Cancelled\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # statuses that are in a state that will\n    # not run going forward for any reason\n    statuses = [\"Completed\", \"Failed\", \"Unaccepted\", \"Partial\", \"Cancelled\"]\n    return self.get_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_tasks","title":"get_tasks","text":"
get_tasks(*status_codes)\n

Get Tasks with specify status_codes.

Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef get_tasks(self, *status_codes: str) -> \"RemoteBatch\":\n    \"\"\"\n    Get Tasks with specify status_codes.\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # offline:\n    st_codes = [QuEraTaskStatusCode(x) for x in status_codes]\n\n    new_task_results = OrderedDict()\n    for task_number, task in self.tasks.items():\n        if task.task_result_ir.task_status in st_codes:\n            new_task_results[task_number] = task\n\n    return RemoteBatch(self.source, new_task_results, name=self.name)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.pull","title":"pull","text":"
pull()\n

Pull results of the tasks in the Batch.

Note

Pulling will pull the results for the tasks. If a given task(s) has not been completed, wait until it finished.

Return

self

Source code in src/bloqade/analog/task/batch.py
def pull(self) -> \"RemoteBatch\":\n    \"\"\"\n    Pull results of the tasks in the Batch.\n\n    Note:\n        Pulling will pull the results for the tasks.\n        If a given task(s) has not been completed, wait\n        until it finished.\n\n    Return:\n        self\n    \"\"\"\n    # online, blocking\n    # pull the results. if its not ready, hanging\n    for task in self.tasks.values():\n        task.pull()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.remove_failed_tasks","title":"remove_failed_tasks","text":"
remove_failed_tasks()\n

Create a RemoteBatch object that contain tasks from current Batch, with failed tasks removed.

failed tasks with following status codes:

  1. Failed
  2. Unaccepted
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def remove_failed_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain tasks from current Batch,\n    with failed tasks removed.\n\n    failed tasks with following status codes:\n\n    1. Failed\n    2. Unaccepted\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # statuses that are in a state that will\n    # not run going forward because of an error\n    statuses = [\"Failed\", \"Unaccepted\"]\n    return self.remove_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.remove_invalid_tasks","title":"remove_invalid_tasks","text":"
remove_invalid_tasks()\n

Create a RemoteBatch object that contain tasks from current Batch, with all Unaccepted tasks removed.

Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def remove_invalid_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain tasks from current Batch,\n    with all Unaccepted tasks removed.\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    return self.remove_tasks(\"Unaccepted\")\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.remove_tasks","title":"remove_tasks","text":"
remove_tasks(*status_codes)\n

Remove Tasks with specify status_codes.

Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef remove_tasks(\n    self,\n    *status_codes: Literal[\n        \"Created\",\n        \"Running\",\n        \"Completed\",\n        \"Failed\",\n        \"Cancelled\",\n        \"Executing\",\n        \"Enqueued\",\n        \"Accepted\",\n        \"Unaccepted\",\n        \"Partial\",\n        \"Unsubmitted\",\n    ],\n) -> \"RemoteBatch\":\n    \"\"\"\n    Remove Tasks with specify status_codes.\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # offline:\n\n    st_codes = [QuEraTaskStatusCode(x) for x in status_codes]\n\n    new_results = OrderedDict()\n    for task_number, task in self.tasks.items():\n        if task.task_result_ir.task_status in st_codes:\n            continue\n\n        new_results[task_number] = task\n\n    return RemoteBatch(self.source, new_results, self.name)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.report","title":"report","text":"
report()\n

Generate analysis report base on currently completed tasks in the RemoteBatch.

Return

Report

Source code in src/bloqade/analog/task/batch.py
def report(self) -> \"Report\":\n    \"\"\"\n    Generate analysis report base on currently\n    completed tasks in the RemoteBatch.\n\n    Return:\n        Report\n\n    \"\"\"\n    ## this potentially can be specialize/disatch\n    ## offline\n    index = []\n    data = []\n    metas = []\n    geos = []\n\n    for task_number, task in self.tasks.items():\n        ## fliter not existing results tasks:\n        if (task.task_id is None) or (not task._result_exists()):\n            continue\n\n        ## filter has result but is not correctly completed.\n        if task.task_result_ir.task_status not in [\n            QuEraTaskStatusCode.Completed,\n            QuEraTaskStatusCode.Partial,\n        ]:\n            continue\n\n        geometry = task.geometry\n        perfect_sorting = \"\".join(map(str, geometry.filling))\n        parallel_decoder = geometry.parallel_decoder\n\n        if parallel_decoder:\n            cluster_indices = parallel_decoder.get_cluster_indices()\n        else:\n            cluster_indices = {(0, 0): list(range(len(perfect_sorting)))}\n\n        shot_iter = filter(\n            lambda shot: shot.shot_status == QuEraShotStatusCode.Completed,\n            task.result().shot_outputs,\n        )\n\n        for shot, (cluster_coordinate, cluster_index) in product(\n            shot_iter, cluster_indices.items()\n        ):\n            pre_sequence = \"\".join(\n                map(\n                    str,\n                    (shot.pre_sequence[index] for index in cluster_index),\n                )\n            )\n\n            post_sequence = np.asarray(\n                [shot.post_sequence[index] for index in cluster_index],\n                dtype=np.int8,\n            )\n\n            pfc_sorting = \"\".join(\n                [perfect_sorting[index] for index in cluster_index]\n            )\n\n            key = (\n                task_number,\n                cluster_coordinate,\n                pfc_sorting,\n                pre_sequence,\n            )\n\n            index.append(key)\n            data.append(post_sequence)\n\n        metas.append(task.metadata)\n        geos.append(task.geometry)\n\n    index = pd.MultiIndex.from_tuples(\n        index, names=[\"task_number\", \"cluster\", \"perfect_sorting\", \"pre_sequence\"]\n    )\n\n    df = pd.DataFrame(data, index=index)\n    df.sort_index(axis=\"index\")\n\n    rept = None\n    if self.name is None:\n        rept = Report(df, metas, geos, \"Remote\")\n    else:\n        rept = Report(df, metas, geos, self.name)\n\n    return rept\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.resubmit","title":"resubmit","text":"
resubmit(shuffle_submit_order=True)\n

Resubmit all the tasks in the RemoteBatch

Return

self

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef resubmit(self, shuffle_submit_order: bool = True) -> \"RemoteBatch\":\n    \"\"\"\n    Resubmit all the tasks in the RemoteBatch\n\n    Return:\n        self\n\n    \"\"\"\n    # online, non-blocking\n    self._submit(shuffle_submit_order, force=True)\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.retrieve","title":"retrieve","text":"
retrieve()\n

Retrieve missing task results.

Note

Retrieve will update the status of tasks, and only pull the results for those tasks that have completed.

Return

self

Source code in src/bloqade/analog/task/batch.py
def retrieve(self) -> \"RemoteBatch\":\n    \"\"\"Retrieve missing task results.\n\n    Note:\n        Retrieve will update the status of tasks,\n        and only pull the results for those tasks\n        that have completed.\n\n    Return:\n        self\n\n    \"\"\"\n    # partially online, sometimes blocking\n    # pull the results for tasks that have\n    # not been pulled already.\n    for task in self.tasks.values():\n        if not task._result_exists():\n            task.pull()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.tasks_metric","title":"tasks_metric","text":"
tasks_metric()\n

Get current tasks status metric

Return

dataframe with [\"task id\", \"status\", \"shots\"]

Source code in src/bloqade/analog/task/batch.py
def tasks_metric(self) -> pd.DataFrame:\n    \"\"\"\n    Get current tasks status metric\n\n    Return:\n        dataframe with [\"task id\", \"status\", \"shots\"]\n\n    \"\"\"\n    # [TODO] more info on current status\n    # offline, non-blocking\n    tid = []\n    data = []\n    for int, task in self.tasks.items():\n        tid.append(int)\n\n        dat = [None, None, None]\n        dat[0] = task.task_id\n        if task.task_result_ir is not None:\n            dat[1] = task.task_result_ir.task_status.name\n        dat[2] = task.task_ir.nshots\n        data.append(dat)\n\n    return pd.DataFrame(data, index=tid, columns=[\"task ID\", \"status\", \"shots\"])\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Serializable","title":"Serializable","text":""},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Serializable.json","title":"json","text":"
json(**options)\n

Serialize the object to JSON string.

Return

JSON string

Source code in src/bloqade/analog/task/batch.py
def json(self, **options) -> str:\n    \"\"\"\n    Serialize the object to JSON string.\n\n    Return:\n        JSON string\n\n    \"\"\"\n    from bloqade.analog import dumps\n\n    return dumps(self, **options)\n
"},{"location":"reference/bloqade/analog/task/bloqade/","title":"Bloqade","text":""},{"location":"reference/bloqade/analog/task/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/task/braket_simulator/","title":"Braket simulator","text":""},{"location":"reference/bloqade/analog/task/quera/","title":"Quera","text":""}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-,:!=\\[\\: )\"`/]+|\\.(?!\\d)|&[lg]t;|(?!\\b)(?=[A-Z][a-z])","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Index","text":"

[!IMPORTANT]

Bloqade has been restructured to make room for new features and improvements. Please refer to the migration guide for more information.

"},{"location":"#welcome-to-bloqade-queras-neutral-atom-sdk","title":"Welcome to Bloqade: QuEra's Neutral Atom SDK","text":""},{"location":"#what-is-bloqade","title":"What is Bloqade?","text":"

Bloqade is a Python SDK for QuEra's neutral atom quantum computer Aquila (check out our paper!). It's designed to make writing and analyzing the results of analog quantum programs on Aquila as easy as possible. It features custom atom geometries and flexible waveform definitions in both emulation and real hardware. Bloqade interfaces with the AWS Braket cloud service where Aquila is hosted, enabling you to submit programs as well as retrieve and analyze real hardware results all-in-one.

"},{"location":"#installation","title":"Installation","text":"

You can install the package with pip in your Python environment of choice via:

pip install bloqade\n
"},{"location":"#a-glimpse-of-bloqade","title":"A Glimpse of Bloqade","text":"

Let's try a simple example where we drive a Rabi oscillation on a single neutral atom. Don't worry if you're unfamiliar with neutral atom physics, (you can check out our Background for more information!) the goal here is to just give you a taste of what Bloqade can do.

We start by defining where our atoms go, otherwise known as the atom geometry. In this particular example we will use a small Honeycomb lattice:

from bloqade.analog.atom_arrangement import Honeycomb\n\ngeometry = Honeycomb(2, lattice_spacing = 10.0)\n

We can verify what the atom geometry looks like by .show()'ing it:

geometry.show()\n

We now define what the time evolution looks like using a pulse sequence. The pulse sequence here is the time profile of the Rabi Drive targeting the ground-Rydberg two level transition, which causes the Rabi oscillations. We choose a constant waveform with a value of \\(\\frac{\\pi}{2} \\text{rad}/\\text{us}\\) and a duration of \\(1.0 \\,\\text{us}\\). This produces a \\(\\frac{\\pi}{2}\\) rotation on the Bloch sphere meaning our final measurements should be split 50/50 between the ground and Rydberg state.

from math import pi\nrabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .constant(value=pi/2, duration=1.0)\n)\n

Here rabi.amplitude means exactly what it is, the Rabi amplitude term of the Hamiltonian. uniform refers to applying the waveform uniformly across all the atom locations.

We can visualize what our program looks like again with .show():

We can now run the program through Bloqade's built-in emulator to get some results. We designate that we want the program to be run and measurements performed 100 times:

emulation_results = rabi_program.bloqade.python().run(100)\n

With the results we can generate a report object that contains a number of methods for analyzing our data, including the number of counts per unique bitstring:

bitstring_counts = emulation_results.report().counts()\n

Which gives us:

[OrderedDict([('0', 55), ('1', 45)])]\n

If we want to submit our program to hardware we'll need to adjust the waveform as there is a constraint the Rabi amplitude waveform must start and end at zero. This is easy to do as we can build off the atom geometry we saved previously but apply a piecewise linear waveform:

hardware_rabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .piecewise_linear(values = [0, pi/2, pi/2, 0], durations = [0.06, 1.0, 0.06])\n)\n\nhardware_rabi_program.show()\n

Now instead of using the built-in Bloqade emulator we submit the program to Aquila. You will need to use the AWS CLI to obtain credentials from your AWS account or set the proper environment variables before hand.

hardware_results = hardware_rabi_program.braket.aquila.run_async(100)\n

.run_async is a non-blocking version of the standard .run method, allowing you to continue work while waiting for results from Aquila. .run_async immediately returns an object you can query for the status of your tasks in the queue as well.

You can do the exact same analysis you do on emulation results with hardware results too:

hardware_bitstring_counts = hardware_results.report().counts()\n

If you want to try the above at once, we collected the above steps into the snippet below:

from math import pi\nfrom bloqade.analog.atom_arrangement import Honeycomb\n\ngeometry = Honeycomb(2, lattice_spacing = 10.0)\nrabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .constant(value=pi/2, duration=1.0)\n)\nemulation_results = rabi_program.bloqade.python().run(100)\nbitstring_counts = emulation_results.report().counts()\n\nhardware_rabi_program = (\n  geometry\n  .rydberg.rabi.amplitude.uniform\n  .piecewise_linear(values = [0, pi/2, pi/2, 0], durations = [0.06, 1.0, 0.06])\n)\nhardware_results = hardware_rabi_program.braket.aquila.run_async(100)\nhardware_bitstring_counts = hardware_results.report().counts()\n

"},{"location":"#features","title":"Features","text":""},{"location":"#customizable-atom-geometries","title":"Customizable Atom Geometries","text":"

You can easily explore a number of common geometric lattices with Bloqade's atom_arrangement's:

from bloqade.analog.atom_arrangement import Lieb, Square, Chain, Kagome\n\ngeometry_1 = Lieb(3)\ngeometry_2 = Square(2)\ngeometry_3 = Chain(5)\ngeometry_4 = Kagome(3)\n

If you're not satisfied with the Bravais lattices we also allow you to modify existing Bravais lattices as follows:

geometry_5 = Kagome(3).add_position((10,11))\n

You can also build your geometry completely from scratch:

from bloqade import start\n\ngeometry = start.add_positions([(0,0), (6,0), (12,0)])\n
"},{"location":"#flexible-pulse-sequence-construction","title":"Flexible Pulse Sequence Construction","text":"

Define waveforms for pulse sequences any way you like by either building (and chaining!) them immediately as part of your program:

from bloqade.analog.atom_arrangement import Square\n\ngeometry = Square(2)\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\ncustom_rabi_amp_waveform = (\n  target_rabi_amplitude\n  .piecewise_linear(values=[0, 10, 10, 0], durations=[0.1, 3.5, 0.1])\n  .piecewise_linear(values=[0, 5, 3, 0], durations=[0.2, 2.0, 0.2])\n)\n

Or building them separately and applying them later:

from bloqade.analog.atom_arrangement import Square, Chain\n\ngeometry_1 = Square(3)\ngeometry_2 = Chain(5)\n\ntarget_rabi_amplitude = start.rydberg.rabi.amplitude.uniform\npulse_sequence = target_rabi_amplitude.uniform.constant(value=2.0, duration=1.5).parse_sequence()\n\nprogram_1 = geometry_1.apply(pulse_sequence)\nprogram_2 = geometry_2.apply(pulse_sequence)\n
"},{"location":"#hardware-and-emulation-backends","title":"Hardware and Emulation Backends","text":"

Go from a fast and powerful emulator:

from bloqade.analog.atom_arrangement import Square\nfrom math import pi\n\ngeometry = Square(3, lattice_spacing = 6.5)\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nprogram = (\n  target_rabi_amplitude\n  .piecewise_linear(values = [0, pi/2, pi/2, 0], durations = [0.06, 1.0, 0.06])\n)\nemulation_results = program.bloqade.python().run(100)\n

To real quantum hardware in a snap:

hardware_results = program.braket.aquila().run_async(100)\n
"},{"location":"#simple-parameter-sweeps","title":"Simple Parameter Sweeps","text":"

Use variables to make parameter sweeps easy on both emulation and hardware:

from bloqade import start\nimport numpy as np\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nrabi_oscillation_program = (\n  target_rabi_amplitude\n  .piecewise_linear(durations = [0.06, \"run_time\", 0.06], values = [0, 15, 15, 0])\n)\nrabi_oscillation_job = rabi_oscillation_program.batch_assign(run_time=np.linspace(0, 3, 101))\n\nemulation_results = rabi_oscillation_job.bloqade.python().run(100)\nhardware_results = rabi_oscillation_job.braket.aquila().run(100)\n
emulation_results.report().rydberg_densities()\n                0\ntask_number\n0            0.16\n1            0.35\n2            0.59\n3            0.78\n4            0.96\n...           ...\n96           0.01\n97           0.09\n98           0.24\n99           0.49\n100          0.68\n\n[101 rows x 1 columns]\n
"},{"location":"#quick-results-analysis","title":"Quick Results Analysis","text":"

Want to just see some plots of your results? .show() will show you the way!

from bloqade.analog.atom_arrangement import Square\n\nrabi_amplitude_values = [0.0, 15.8, 15.8, 0.0]\nrabi_detuning_values = [-16.33, -16.33, 42.66, 42.66]\ndurations = [0.8, 2.4, 0.8]\n\ngeometry = Square(3, lattice_spacing=5.9)\nrabi_amplitude_waveform = (\n  geometry\n  .rydberg.rabi.amplitude.uniform.piecewise_linear(durations, rabi_amplitude_values)\n)\nprogram = (\n  rabi_amplitude_waveform\n  .detuning.uniform.piecewise_linear(durations, rabi_detuning_values)\n)\nemulation_results = program.bloqade.python().run(100)\nemulation_results.report().show()\n

"},{"location":"#contributing-to-bloqade","title":"Contributing to Bloqade","text":"

Bloqade is released under the Apache License, Version 2.0. If you'd like the chance to shape the future of neutral atom quantum computation, see our Contributing Guide for more info!

"},{"location":"contributing/","title":"Contributing","text":"

Thank you for your interest in contributing to the project! We welcome all contributions. There are many different ways to contribute to Bloqade, and we are always looking for more help. We accept contributions in the form of bug reports, feature requests, documentation improvements, and code contributions. For more information about how to contribute, please read the following sections.

"},{"location":"contributing/#table-of-contents","title":"Table of Contents","text":"
  • Reporting a Bug
  • Reporting Documentation Issues
  • Feature Requests
  • Developing Bloqade
  • Design Philosophy and Architecture
  • Community Slack
  • Ask a Question
  • Providing Feedback
"},{"location":"contributing/asking-a-question/","title":"Ask a Question","text":"

If you're interested in contributing to Bloqade, or just want to discuss the project, join the discussion on GitHub Discussions at https://github.com/QuEraComputing/bloqade-analog/discussions

"},{"location":"contributing/code-of-conduct/","title":"Design Philosophy and Architecture","text":"

Given the heterogeneous nature of the hardware we target, We have decided to use a compiler-based approach to our software stack, allowing us to target different hardware backends with the same high-level language. Below is a diagram of the software stack in Bloqade.

graph TD\n    Builder[\"Builder Representation\"]\n    PythonAST[\"Bloqade AST Python\"]\n    JuliaAST[\"Bloqade AST Julia\"]\n\n    EmulatorPy[\"Emulator IR Python\"]\n    EmulatorJL[\"Emulator IR Julia\"]\n\n    QuEra[\"QuEra IR\"]\n    Braket[\"Braket IR\"]\n    JuliaEmulator[\"Bloqade.jl\"]\n    PythonEmulator[\"Python Emulator\"]\n\n    Aquila[\"Aquila\"]\n\n    Builder -->|parse| PythonAST\n    PythonAST -->|lower| EmulatorPy\n    PythonAST -->|lower| QuEra\n    PythonAST -->|lower| Braket\n    PythonAST -->|transpile| JuliaAST\n\n    QuEra -->|execute| Aquila\n    Braket -->|execute| Aquila\n\n    JuliaAST -->|lower| EmulatorJL\n    EmulatorPy -->|execute| PythonEmulator\n    EmulatorJL -->|execute| JuliaEmulator\n
"},{"location":"contributing/code-of-conduct/#high-level-builder-representation","title":"High-Level Builder Representation","text":"

When programming Bloqade using the Python API, the user constructs a representation of an analog quantum circuit. This representation is a flattened version of the actual analog circuit. Flattened means that the user input is a linear sequence of operations where the context of neighboring nodes in the sequence of instructions can determine the program tree structure. The Bloqade AST describes the actual analog circuit.

"},{"location":"contributing/code-of-conduct/#bloqade-ast","title":"Bloqade AST","text":"

The Bloqade AST is a representation of a quantum analog circuit for neutral atom computing. It is a directed acyclic graph (DAG) with nodes for different hierarchical levels of the circuit. The base node is the AnalogCircuit which contains the geometry of the atoms stored as a AtomArragment or ParallelRegister objects. The other part of the circuit is the Sequence, which contains the waveforms that describe the drives for the Ryberg/Hyperfine transitions of each Rydberg atom. Each transition is represented by a Pulse including a Field for the drive's detuning, Rabi amplitude, and Rabi phase . A Field relates the spatial and temporal dependence of a drive. The spatial modulates the temporal dependence of the waveform. A DAG also describes the Waveform object. Finally, we have basic Scalar expressions as well for describing the syntax of real-valued continuous numbers.

"},{"location":"contributing/code-of-conduct/#bloqade-compilers-and-transpilers","title":"Bloqade Compilers and Transpilers","text":"

Given a user program expressed as the Bloqade AST, we can target various backends by transforming from the Bloqade AST to other kinds of IR. For example, when submitting a task to QuEra's hardware, we transform the Bloqade AST to the IR that describes a valid program for the hardware.

This process is referred to as lowering, which in a general sense is a transformation that takes you from one IR to another where the target IR is specialized or has a smaller syntactical structure. Transpiling corresponds to a transformation that takes you from one language to equivalent expressions in another. For example, we can transpile from the Bloqade AST in Python to the Bloqade AST in Julia. The generic term for both of these types of transformation in Bloqade is Code Generation. You will find various code generation implementations in various codegen modules.

"},{"location":"contributing/community-slack/","title":"Community Slack","text":"

You can join QuEra's Slack workspace with this link. Join the #bloqade channel to discuss anything related to Bloqade.

"},{"location":"contributing/design-philosophy-and-architecture/","title":"Design Philosophy and Architecture","text":"

Given the heterogeneous nature of the hardware we target, We have decided to use a compiler-based approach to our software stack, allowing us to target different hardware backends with the same high-level language. Below is a diagram of the software stack in Bloqade.

graph TD\n    Builder[\"Builder Representation\"]\n    PythonAST[\"Bloqade AST Python\"]\n    JuliaAST[\"Bloqade AST Julia\"]\n\n    EmulatorPy[\"Emulator IR Python\"]\n    EmulatorJL[\"Emulator IR Julia\"]\n\n    QuEra[\"QuEra IR\"]\n    Braket[\"Braket IR\"]\n    JuliaEmulator[\"Bloqade.jl\"]\n    PythonEmulator[\"Python Emulator\"]\n\n    Aquila[\"Aquila\"]\n\n    Builder -->|parse| PythonAST\n    PythonAST -->|lower| EmulatorPy\n    PythonAST -->|lower| QuEra\n    PythonAST -->|lower| Braket\n    PythonAST -->|transpile| JuliaAST\n\n    QuEra -->|execute| Aquila\n    Braket -->|execute| Aquila\n\n    JuliaAST -->|lower| EmulatorJL\n    EmulatorPy -->|execute| PythonEmulator\n    EmulatorJL -->|execute| JuliaEmulator\n
"},{"location":"contributing/design-philosophy-and-architecture/#high-level-builder-representation","title":"High-Level Builder Representation","text":"

When programming Bloqade using the Python API, the user constructs a representation of an analog quantum circuit. This representation is a flattened version of the actual analog circuit. Flattened means that the user input is a linear sequence of operations where the context of neighboring nodes in the sequence of instructions can determine the program tree structure. The Bloqade AST describes the actual analog circuit.

"},{"location":"contributing/design-philosophy-and-architecture/#bloqade-ast","title":"Bloqade AST","text":"

The Bloqade AST is a representation of a quantum analog circuit for neutral atom computing. It is a directed acyclic graph (DAG) with nodes for different hierarchical levels of the circuit. The base node is the AnalogCircuit which contains the geometry of the atoms stored as a AtomArragment or ParallelRegister objects. The other part of the circuit is the Sequence, which contains the waveforms that describe the drives for the Ryberg/Hyperfine transitions of each Rydberg atom. Each transition is represented by a Pulse including a Field for the drive's detuning, Rabi amplitude, and Rabi phase . A Field relates the spatial and temporal dependence of a drive. The spatial modulates the temporal dependence of the waveform. A DAG also describes the Waveform object. Finally, we have basic Scalar expressions as well for describing the syntax of real-valued continuous numbers.

"},{"location":"contributing/design-philosophy-and-architecture/#bloqade-compilers-and-transpilers","title":"Bloqade Compilers and Transpilers","text":"

Given a user program expressed as the Bloqade AST, we can target various backends by transforming from the Bloqade AST to other kinds of IR. For example, when submitting a task to QuEra's hardware, we transform the Bloqade AST to the IR that describes a valid program for the hardware.

This process is referred to as lowering, which in a general sense is a transformation that takes you from one IR to another where the target IR is specialized or has a smaller syntactical structure. Transpiling corresponds to a transformation that takes you from one language to equivalent expressions in another. For example, we can transpile from the Bloqade AST in Python to the Bloqade AST in Julia. The generic term for both of these types of transformation in Bloqade is Code Generation. You will find various code generation implementations in various codegen modules.

"},{"location":"contributing/developing-bloqade/","title":"Setting up your Development Environment","text":"

Before You Get Started

Depending on the complexity of the contribution you'd like to make to Bloqade, it may be worth reading the Design Philosophy and Architecture section to get an idea of why Bloqade is structured the way that it is and how to make your contribution adhere to this philosophy.

Our development environment contains a set of tools we use for development, testing, and documentation. This section describes how to set up the development environment. We primarily use pdm to manage python environments and dependencies.

"},{"location":"contributing/developing-bloqade/#setting-up-python","title":"Setting up Python","text":"

We use pdm to manage dependencies and virtual environment. After cloning the repository, run the following command to install dependencies:

pdm install\n

You can also install different dependency groups:

  • dev: dependencies for development
pdm install --dev\n# or\npdm install -d\n
  • doc: dependencies for building documentation
pdm install -G doc\n
"},{"location":"contributing/developing-bloqade/#useful-pdm-scripts","title":"Useful PDM scripts","text":""},{"location":"contributing/developing-bloqade/#tests","title":"Tests","text":"

You can run tests via

pdm run test\n

Or run tests and generate coverage via

pdm run coverage\n

will print out the coverage file level report in terminal.

pdm run coverage-html\n

This command generates an interactive html report in htmlcov folder. This will show which specific lines are not covered by tests.

"},{"location":"contributing/developing-bloqade/#documentation","title":"Documentation","text":"

You can build documentation via

pdm run doc_build\n

Or run a local server to preview documentation via

pdm run doc\n
"},{"location":"contributing/developing-bloqade/#jupytext","title":"Jupytext","text":"

You can sync jupyter notebooks and python scripts via

pdm run jupytext\n

this will help you development examples in jupyter notebook and python scripts simultaneously.

"},{"location":"contributing/developing-bloqade/#lint","title":"Lint","text":"

We primarily use ruff - an extremely fast linter for Python, and black as formatter. These have been configured into pre-commit hooks. After installing pre-commit on your own system, you can install pre-commit hooks to git via

pre-commit install\n
"},{"location":"contributing/documentation-issues/","title":"Reporting a Documentation Issue","text":"

We are always looking to improve our documentation. If you find a typo or think something is unclear, please open an issue on our GitHub page: https://github.com/QuEraComputing/bloqade-analog/issues

For typos or other minor problems, create an issue that contains a link to the specific page that includes the problem, along with a description of the problem and possibly a solution.

For a request for new documentation content, please open up an issue and describe what you think is missing from the documentation.

"},{"location":"contributing/feature-requests/","title":"Requesting new Features","text":"

Given that we are currently at the beginning of the development of the Bloqade python interface, we are open to suggestions about what features would be helpful to include in future package iterations. If you have a request for a new feature, please open an issue on our GitHub page: https://github.com/QuEraComputing/bloqade-analog/issues

We ask that the feature requests be as specific as possible. Please include the following information in your feature request:

  1. A short, descriptive title.

  2. A detailed description of the feature, including your attempt to solve the problem with the current version of Bloqade.

  3. A minimal code example that demonstrates the need for the feature.

  4. The version of Bloqade you are using.

  5. The version of Python you are using.

  6. The version of your operating system.

"},{"location":"contributing/providing-feedback/","title":"Providing Feedback","text":"

While Github Issues are a great way for us to better understand any issues your having with Bloqade as well as provide us with feature requests, we're always looking for ways to collect more general feedback about what the user experience with Bloqade is like.

To do that we have this form where you can provide your thoughts after using/experimenting/tinkering/hacking with Bloqade.

Your feedback will help guide the future of Bloqade's design so be honest and know that you're contributing to the future of Quantum Computing with Neutral Atoms!

"},{"location":"contributing/reporting-a-bug/","title":"Reporting a Bug","text":"

Bloqade is currently in the alpha phase of development, meaning bugs most likely exist in the current implementation. We are continuously striving to improve the stability of Bloqade. As such, we encourage our users to report all bugs they find. To do this, we ask you to submit an issue to our GitHub page: https://github.com/QuEraComputing/bloqade-analog/issues

Please include the following information in your bug report:

  1. A short, descriptive title.

  2. A detailed description of the bug, including the expected behavior and what happened.

  3. A minimal code example that reproduces the bug.

  4. The version of Bloqade you are using.

  5. The version of Python you are using.

  6. The version of your operating system.

"},{"location":"home/background/","title":"Background","text":""},{"location":"home/background/#neutral-atom-qubits","title":"Neutral Atom Qubits","text":"

The qubits that QuEra's neutral atom computer Aquila and Bloqade are designed to emulate are based on neutral atoms. As the name implies they are atoms that are neutrally charged but are also capable of achieving a Rydberg state where a single electron can be excited to an incredibly high energy level without ionizing the atom.

This incredibly excited electron energy level \\(|r\\rangle\\) and its default ground state \\(|g\\rangle\\) create a two-level system where superposition can occur. For enabling interaction between two or more qubits and achieving entanglement, when the neutral atoms are in the Rydberg state a phenomenon known as the Rydberg blockade can occur where an atom in the Rydberg state prevents a neighboring atom from also being excited to the same state.

For a more nuanced and in-depth read about the neutral atoms that Bloqade and Aquila use, refer to QuEra's qBook section on Qubits by puffing up atoms.

"},{"location":"home/background/#analog-vs-digital-quantum-computing","title":"Analog vs Digital Quantum Computing","text":"

There are two modes of quantum computation that neutral atoms are capable of: Analog and Digital.

You can find a brief explanation of the distinction below but for a more in-depth explanation you can refer to QuEra's qBook section on Analog vs Digital Quantum Computing

"},{"location":"home/background/#analog-mode","title":"Analog Mode","text":"

In the analog mode (supported by Bloqade and Aquila) you control your computation through the parameters of a time-dependent Hamiltonian that influences all the qubits at once. There are options for local control of the Hamiltonian on certain qubits however.

"},{"location":"home/background/#digital-mode","title":"Digital Mode","text":"

In the Digital Mode individual or multiple groups of qubits are controlled by applying gates (individual unitary operations). For neutral atoms, this digital mode can be accomplished with the introduction of hyperfine coupling, enabling a quantum state to be stored for long periods of time while also allowing for multi-qubit gates.

"},{"location":"home/background/#rydberg-many-body-hamiltonian","title":"Rydberg Many-Body Hamiltonian","text":"

When you emulate a program in Bloqade, you are emulating the time evolution of the Rydberg many-body Hamiltonian which looks like this:

\\[ i \\hbar \\dfrac{\\partial}{\\partial t} | \\psi \\rangle = \\hat{\\mathcal{H}}(t) | \\psi \\rangle, \\\\ \\] \\[ \\frac{\\mathcal{H}(t)}{\\hbar} = \\sum_j \\frac{\\Omega_j(t)}{2} \\left( e^{i \\phi_j(t) } | g_j \\rangle \\langle r_j | + e^{-i \\phi_j(t) } | r_j \\rangle \\langle g_j | \\right) - \\sum_j \\Delta_j(t) \\hat{n}_j + \\sum_{j < k} V_{jk} \\hat{n}_j \\hat{n}_k, \\]

where: \\(\\Omega_j\\), \\(\\phi_j\\), and \\(\\Delta_j\\) denote the Rabi frequency amplitude, laser phase, and the detuning of the driving laser field on atom (qubit) \\(j\\) coupling the two states \\(| g_j \\rangle\\) (ground state) and \\(| r_j \\rangle\\) (Rydberg state); \\(\\hat{n}_j = |r_j\\rangle \\langle r_j|\\) is the number operator, and \\(V_{jk} = C_6/|\\mathbf{x}_j - \\mathbf{x}_k|^6\\) describes the Rydberg interaction (van der Waals interaction) between atoms \\(j\\) and \\(k\\) where \\(\\mathbf{x}_j\\) denotes the position of the atom \\(j\\); \\(C_6\\) is the Rydberg interaction constant that depends on the particular Rydberg state used. For Bloqade, the default \\(C_6 = 862690 \\times 2\\pi \\text{ MHz \u03bcm}^6\\) for \\(|r \\rangle = \\lvert 70S_{1/2} \\rangle\\) of the \\(^{87}\\)Rb atoms; \\(\\hbar\\) is the reduced Planck's constant.

"},{"location":"home/background/#local-control","title":"Local Control","text":"

The Rydberg Many-Body Hamiltonian already implies from its subscripts that you can also have local control over your atoms. In Bloqade this local control extends to any term in the Hamiltonian while on Aquila this is currently restricted to the \\(\\Delta_j\\) laser detuning term.

Fields in Bloqade give you local (single-atom) control over the many-body Rydberg Hamiltonian.

They are a sum of one or more spatial modulations, which allows you to scale the amplitude of the waveform across the different sites in the system:

\\[ F_{i}(t) = \\sum_{\\alpha} C_{i}^{\\alpha}f_{\\alpha}(t) \\] \\[ C_{i}^{\\alpha} \\in \\mathbb{R} \\] \\[ f_{\\alpha}(t) \\colon \\mathbb{R} \\to \\mathbb{R} \\]

The \\(i\\)-th component of the field is used to generate the drive at the \\(i\\)-th site.

Note that the drive is only applied if the \\(i\\)-th site is filled with an atom.

You build fields in Bloqade by first specifying the spatial modulation followed by the waveform it should be multiplied by.

In the case of a uniform spatial modulation, it can be interpreted as a constant scaling factor where \\(C_{i}^{\\alpha} = 1.0\\).

"},{"location":"home/emulation/","title":"Emulation","text":"

This page is a work in progress!

"},{"location":"home/geometry/","title":"Geometry","text":"

This page is a work in progress!

"},{"location":"home/gotchas/","title":"Bloqade Gotchas: Common Mistakes in Using Bloqade","text":"

It is tempting when coming from different quantum SDKs and frameworks to apply the same pattern of thought to Bloqade. However, a lot of practices from those prior tools end up being anti-patterns in Bloqade. While you can use those patterns and they can still work, it ends up causing you the developer to write unnecessarily verbose, complex, and hard-to-read code as well as preventing you from reaping the full benefits of what Bloqade has to offer.

This page is dedicated to cataloguing those anti-patterns and what you can do instead to maximize the benefit Bloqade can offer you.

"},{"location":"home/gotchas/#redefining-lattices-and-common-atom-arrangements","title":"Redefining Lattices and Common Atom Arrangements","text":"

You might be tempted to define lattice-based geometries through the following means:

from bloqade import start\n\nspacing = 4.0\ngeometry = start.add_positions(\n    [(i * spacing, j * spacing) for i in range(4) for j in range(4)]\n)\n

This is quite redundant and verbose, especially considering Bloqade offers a large number of pre-defined lattices you can customize the spacing of in bloqade.atom_arrangement. In the code above, we're just defining a 4x4 square lattice of atoms with 4.0 micrometers of spacing between them. This can be expressed as follows

from bloqade.analog.atom_arrangement import Square\n\nspacing = 4.0\ngeometry = Square(4, lattice_spacing = spacing)\n
"},{"location":"home/gotchas/#copying-a-program-to-create-new-ones","title":"Copying a Program to create New Ones","text":"

Many gate-based SDKs rely on having a mutable object representing your circuit. This means if you want to build on top of some base circuit without mutating it, you have to copy it:

import copy\n\nbase_circuit = qubits.x(0)....\n# make copy of base circuit\ncustom_circuit_1 = copy(base_circuit)\n# build on top of copy of base circuit\ncustom_circuit_1.x(0).z(5)...\n# create a new circuit by copying the base again\ncustom_circuit_2 = copy(base_circuit)\n# build on top of that copy again\ncustom_circuit_2.y(5).cz(0,2)...\n

In Bloqade Python this is unnecessary because at every step of your program an immutable object is returned which means you can save it and not have to worry about mutating any internal state.

from bloqade import start\nbase_program = start.add_position((0,0)).rydberg.rabi.amplitude.uniform\n# Just recycle your base program! No `copy` needed!\nnew_program_1 = base_program.constant(duration=5.0, value=5.0)\nnew_program_2 = base_program.piecewise_linear(\n    durations=[5.0], values = [0.0, 5.0]\n)\n
"},{"location":"home/gotchas/#creating-new-programs-instead-of-using-batch_assign","title":"Creating New Programs Instead of Using .batch_assign","text":"

If you have a set of parameters you'd like to test your program on versus a single parameter, don't generate a new program for each value:

rabi_values = [2.0, 4.7, 6.1]\nprograms_with_different_rabi_values = []\n\nfor rabi_value in rabi_values:\n    program = start.add_position((0, 0)).rydberg.rabi.amplitude.uniform.constant(\n        duration=5.0, value=rabi_value\n    )\n    programs_with_different_rabi_values.append(program)\n\nresults = []\n\nfor program in programs_with_different_rabi_values:\n    result = program.bloqade.python().run(100)\n    results.append(result)\n

Instead take advantage of the fact Bloqade has facilities specifically designed to make trying out multiple values in your program without needing to make individual copies via .batch_assign. The results are also automatically handled for you so each value you test has its own set of results, but all collected in a singular dataframe versus the above where you'd have to keep track of individual results.

rabi_values = [2.0, 4.7, 6.1]\n# place a variable for the Rabi Value and then batch assign values to it\nprogram_with_rabi_values = start.add_position(\n    0, 0\n).rydberg.rabi.amplitude.uniform.constant(duration=5.0, value=\"rabi_value\")\nprogram_with_assignments = program_with_rabi_values.batch_assign(\n    rabi_value=rabi_values\n)\n\n# get your results in one dataframe versus having to keep track of a\n# bunch of individual programs and their individual results\nbatch = program_with_assignments.bloqade.python().run(100)\nresults_dataframe = batch.report().dataframe\n
"},{"location":"home/migration/","title":"Migrating to Bloqade Analog","text":""},{"location":"home/migration/#introduction","title":"Introduction","text":"

In order to make room for more features inside the Bloqade ecosystem, we have created a new package to take the place of the old bloqade package. The new package is called bloqade-analog. The old package bloqade will house a namespace package for other features such as our new Bloqade Digital package with support for circuit-based quantum computers!

"},{"location":"home/migration/#installation","title":"Installation","text":"

You can install the package with pip in your Python environment of choice via:

pip install bloqade-analog\n
"},{"location":"home/migration/#migration","title":"Migration","text":"

The new package is a drop-in replacement for the old one. You can simply replace import bloqade with import bloqade.analog or from bloqade.analog import ... in your code. Everything else should work as before.

"},{"location":"home/migration/#example","title":"Example","text":"

lets say your header of your python script looks like this:

from bloqade import var\nfrom bloqade.atom_arrangement import Square\n...\n
You can simply replace it with:

from bloqade.analog import var\nfrom bloqade.analog.atom_arrangement import Square\n...\n
"},{"location":"home/migration/#migrating-old-bloqade-json-files","title":"Migrating old bloqade JSON files","text":"

If you have old bloqade JSON files, you will not be able to directly deserialize them anymore because of the package restructuring. Howver we have provided some tools to migrate those JSON files to be compatible with bloqade-analog. You can do this by running the following command in the command line for a single file:

python -m bloqade.analog.migrate <path_to_old_json_file>\n
This will create a new file with the same name as the old file, but with _analog appended to the end of the filename. For example, if you have a file called my_bloqade.json, the new file will be called my_bloqade-analog.json. You can then use load to deserialize this file with the bloqade-analog package. There are other options for converting the file, such as setting the indent level for the output file or overwriting the old file. You can see all the options by running:

python -m bloqade.analog.migrate --help\n
You can also migrate multiple files at once by running:

python -m bloqade.analog.migrate <path_to_old_json_file1> <path_to_old_json_file2> ...\n

Another option is to use the migration tool in a python script:

from bloqade.analog.migrate import migrate\n\n # set the indent level for the output file\nindent: int = ...\n# set to True if you want to overwrite the old file, otherwise the new file will be created with -analog appended to the end of the filename\noverwrite: bool = ...\nf\nor filename in [\"file1.json\", \"file2.json\", ...]:\n    migrate(filename, indent=indent, overwrite=overwrite)\n
This will migrate all the files in the list to the new format.

"},{"location":"home/migration/#having-trouble-comments-or-concerns","title":"Having trouble, comments, or concerns?","text":"

Please open an issue on our GitHub

"},{"location":"home/quick_start/","title":"Quick Start","text":"

All the sections below are self-contained, you can click on the links in the Table of Contents to read the relevant parts.

"},{"location":"home/quick_start/#navigating-the-bloqade-api","title":"Navigating the Bloqade API","text":"

As you develop your Bloqade program, you are expected to rely on pop-up \"hints\" provided in your development environment to help you determine what the next part of your program should be.

"},{"location":"home/quick_start/#vs-code","title":"VS Code","text":"

In VS Code this is automatic, just type the . and see what options pop up:

"},{"location":"home/quick_start/#jetbrains-pycharm","title":"JetBrains PyCharm","text":"

The same goes for JetBrains PyCharm:

"},{"location":"home/quick_start/#jupyter-notebook","title":"Jupyter Notebook","text":"

In a Jupyter Notebook you'll need to type . and then hit tab for the hints to appear:

"},{"location":"home/quick_start/#ipython","title":"IPython","text":"

The same goes for IPython:

"},{"location":"home/quick_start/#defining-atom-geometry","title":"Defining Atom Geometry","text":"

You can import pre-defined geometries based on Bravais lattices from bloqade.atom_arrangement. You may also specify a lattice spacing which dictates the spacing between the atoms as well as the number of atom sites in a certain direction.

from bloqade.analog.atom_arrangement import Square, Kagome\n\nsimple_geometry = Square(2, 4, lattice_spacing = 4.0)\nmore_complex_geometry = Kagome(2, 2, lattice_spacing = 2.0)\n

You can easily visualize your geometries as well with .show():

more_complex_geometry.show()\n

You can also add positions to a pre-defined geometry:

from bloqade.analog.atom_arrangement import Square\n\nbase_geometry = Square(2)\ngeometry_with_my_positions = base_geometry.add_position([(10,10), (20,20)])\n

As well as apply defects via .apply_defect_density. In the example below we apply a defect with a probability of 0.2:

from bloqade.analog.atom_arrangement import Square, Kagome\n\nmore_complex_geometry = Kagome(2, 2, lattice_spacing = 2.0)\ndefective_geometry = more_complex_geometry.apply_defect_density(0.2)\n

Or if you want to completely roll out your own atom geometry from scratch just use add_position by itself:

from bloqade import start\n\nmy_geometry = start.add_position([(1,2), (3,4), (5,6)])\n
"},{"location":"home/quick_start/#building-waveforms","title":"Building Waveforms","text":"

After you've defined a geometry you:

  • Specify which level coupling to drive: rydberg or hyperfine
  • Specify detuning, rabi.amplitude or rabi.phase
  • Specify the spatial modulation

Which then leads you to the ability to specify a waveform of interest and begin constructing your pulse sequence. In the example below, we target the ground-Rydberg level coupling to drive with uniform spatial modulation for the Rabi amplitude. Our waveform is a piecewise linear one which ramps from \\(0\\) to \\(5 \\,\\text{rad/us}\\), holds that value for \\(1 \\,\\text{us}\\) and then ramps back down to \\(0 \\,\\text{rad/us}\\).

from bloqade import start\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nwaveform_applied = (\n    target_rabi_amplitude\n    .piecewise_linear(durations = [0.06, 1, 0.06], values = [0, 5, 5, 0])\n)\n

You aren't restricted to just piecewise linear waveforms however, you can also specify:

  • linear - Define a transition from one value to another over a duration
  • constant - Define a fixed value over a duration
  • piecewise_constant - Define a step-wise function with specific durations for each step
  • poly - Define a polynomial waveform using coefficients over a duration
"},{"location":"home/quick_start/#arbitrary-functions-as-waveforms","title":"Arbitrary Functions as Waveforms","text":"

For more complex waveforms it may provide to be tedious trying to chain together a large number of piecewise_constant or piecewise_linear methods and instead easier to just define the waveform as a function of time.

Bloqade lets you easily plug in an arbitrary function with .fn:

from bloqade import start\nfrom math import sin\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\n\ndef custom_waveform(t):\n    return 2.0 * sin(t)\n\ncustom_waveform_applied = (\n    target_rabi_amplitude\n    .fn(custom_waveform, duration = 3.0)\n)\n

In this form you can immediately emulate it if you'd like but to run this on hardware you need to discretize it. The waveform on hardware has to either be:

  • Piecewise linear for Rabi amplitude and detuning terms of the Hamiltonian
  • Piecewise constant for the Phase term of the Hamiltonian

Bloqade can automatically perform this conversion with sample(), all you need to do is specify the kind of interpolation and the size of the discretization step in time. Below we set the step duration to be \\(0.05 \\,\\text{us}\\) with \"linear\" interpolation to give us a resulting piecewise linear waveform.

custom_discretized_waveform_applied = (\n    target_rabi_amplitude\n    .fn(custom_waveform, duration = 3.0)\n    .sample(0.05, \"linear\")\n)\n

Note

Programs that have custom functions as waveforms are not fully serializable. This means that when you are saving and reloading results, the original embedded program will be missing that custom waveform. You will still be able to analyze the saved results!

"},{"location":"home/quick_start/#slicing-and-recording-waveforms","title":"Slicing and Recording Waveforms","text":"

When you conduct parameter sweeps with your program, you may want to sweep over your program across time. This will require \"slicing\" your waveforms, where you define the waveform of interest and then, using a variable with .slice, indicate the times at which the waveform duration should be cut short.

In the example below we define a simple piecewise linear waveform but slice it starting from a time duration of \\(0 \\,\\text{us}\\) to values between \\(1\\) to \\(2 \\,\\text{us}\\).

from bloqade import start\nimport numpy as np\n\nsliced_program = (\n    start.add_position((0, 0))\n    .rydberg.rabi.amplitude.uniform.piecewise_linear(\n        durations=[0.5, 2.5, 0.5], values=[0, 3.0, 3.0, 0]\n    ).slice(start=0, stop=\"run_time\")\n)\n\nrun_times = np.linspace(1.0, 2.0, 10)\nvars_assigned_program = sliced_program.batch_assign(run_time=run_times)\n

This program will run fine in emulation but due to hardware constraints certain waveforms (such as those targeting the Rabi Amplitude), the waveform needs to start and end at \\(0 \\,\\text{rad}/\\text{us}\\). Thus, there needs to be a way to slice our waveform but also add an end component to that waveform. .record in Bloqade lets you literally \"record\" the value at the end of a .slice and then use it to construct further parts of the waveform.

In the program below the waveform is still sliced but with the help of .record a linear segment that pulls the waveform down to \\(0.0 \\,\\text{rad}/\\text{us}\\) from whatever its current value at the slice is in \\(0.7 \\,\\text{us}\\) is added.

from bloqade import start\nimport numpy as np\n\nsliced_program = (\n    start.add_position((0, 0))\n    .rydberg.rabi.amplitude.uniform.piecewise_linear(\n        durations=[0.5, 2.5, 0.5], values=[0, 3.0, 3.0, 0]\n    ).slice(start=0, stop=\"run_time\")\n    .record(\"waveform_value\")\n    .linear(\"rabi_value\", 0.0, 0.7)\n)\n\nrun_times = np.linspace(1.0, 2.0, 10)\nvars_assigned_program = sliced_program.batch_assign(run_time=run_times)\n
"},{"location":"home/quick_start/#waveforms-with-no-geometry","title":"Waveforms with No Geometry","text":"

If you have multiple atom geometries you'd like to apply a pulse sequence to or you simply don't want to worry about what atom geometry to start with, you can just build straight off of start:

from bloqade import start\n\npulse_sequence = (\n    start\n    .rydberg.rabi.amplitude.uniform\n    .constant(value=1.0, duration=1.0)\n    .parse_sequence()\n)\n

You can visualize your sequence as well with .show():

pulse_sequence.show()\n

And when you're content with it you just .apply() it on the geometries of your choice:

from bloqade.analog.atom_arrangement import Honeycomb, Kagome\n\ngeometry_1 = Honeycomb(2, lattice_spacing = 6.0)\ngeometry_2 = Kagome(2, lattice_spacing = 6.0)\n\nprogram_1  = geometry_1.apply(pulse_sequence)\nprogram_2  = geometry_2.apply(pulse_sequence)\n
"},{"location":"home/quick_start/#emulation","title":"Emulation","text":"

When you've completed the definition of your program you can use Bloqade's own emulator to get results. The emulation performs the time evolution of the analog Rydberg Hamiltonian. Here we say we want to the program to be run and measurements obtained 1000 times.

results = your_program.bloqade.python().run(1000)\n

Note

If your atoms are particularly close together or the ODE solver gives you the following message:

RuntimeError: DOP853/DOPRI5: Problem is probably stiff (interrupted).\n

In which case you will need to specify the interaction_picture=True argument:

results = your_program.bloqade.python().run(1000, interaction_picture=True)\n
"},{"location":"home/quick_start/#submitting-to-hardware","title":"Submitting to Hardware","text":"

To submit your program to hardware ensure you have your AWS Braket credentials loaded. You will need to use the AWS CLI to do this.

Then it's just a matter of selecting the Aquila on Braket backend. Before going any further Bloqade provides two options for running your program on actual hardware:

  • Using .run is blocking, meaning you will not be able to execute anything else while Bloqade waits for results
  • Using .run_async lets you submit to hardware and continue any further execution, while also letting you query the status of your program in the queue.

In the example below we use .run_async to specify the program should be run and measurements obtained 1000 times.

async_results = your_program.braket.aquila().run_async(1000)\n

We can see the status of our program via:

async_results.fetch()\n
Which gives us the Task ID, a unique identifier for the task as well as the status of the task. In the example below the task is Enqueued meaning it has been successfully created and is awaiting execution on the cloud. When the task is actually running on hardware, the status will change to Running.
                                             task ID    status  shots\n0  arn:aws:braket:us-east-1:XXXXXXXXXXXX:quantum-...  Enqueued    100\n

"},{"location":"home/quick_start/#analyzing-results","title":"Analyzing Results","text":"

When you've retrieved your results from either emulation or hardware you can generate a .report():

report = results.report()\n

For the examples below we analyze the results of a two atom program.

The report contains useful information such as:

  • The raw bitstrings measured per each execution of the program

    report.bitstrings()\n
    [array([[1, 1],\n        [1, 1],\n        [1, 1],\n        ...,\n        [1, 1],\n        [1, 1],\n        [1, 0]], dtype=int8)]\n

  • The number of times each unique bitstring occurred:

    report.counts()\n
    [OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n

  • The Rydberg Density for each atom

    report.rydberg_densities()\n
                     0      1\ntask_number\n0            0.053  0.054\n

And can also provide useful visual information such as the state of your atoms and the bitstring distribution via:

report.show()\n

"},{"location":"home/quick_start/#parameter-sweeps","title":"Parameter Sweeps","text":"

You can easily do parameter sweeps in emulation and on Aquila with variables. Bloqade automatically detects strings in your program as variables that you can later assign singular or multiple values to.

In the example below, we define a program with a singular variable that controls the amplitude of the waveform.

from bloqade import start\n\nrabi_oscillations_program = (\n    start.add_position((0, 0))\n    .rydberg.rabi.amplitude.uniform.piecewise_linear(\n        durations=[0.06, 3, 0.06],\n        values=[0, \"rabi_amplitude\", \"rabi_amplitude\", 0]\n    )\n)\n

We can assign a single fixed value to the variable:

single_value_assignment = rabi_oscillations_program.assign(rabi_amplitude=3.5)\n

Or, to perform a sweep, we use .batch_assign:

import numpy as np\nrabi_amplitudes = np.linspace(1.0, 2.0, 20)\n\nmultiple_value_assignment = rabi_oscillations_program.batch_assign(rabi_amplitude=rabi_amplitudes)\n

This will actually create multiple versions of the program internally, with each program assigned a fixed value from the sweep. Bloqade will automatically handle the compilation of results from these multiple programs in order, meaning there is no major departure from what you saw in analyzing the results of your program.

You can also delay assignment of a value to a variable by first declaring it in .args() and then passing a value when you call run:

delayed_assignment_program = rabi_oscillations_program.args([\"rabi_amplitude\"])\nresults = delayed_assignment_program.bloqade.python().run(100, args=(1.0,))\n

You can alternatively treat the program as a callable after using .args() (note the inverted order of arguments in the call!):

delayed_assignment_program = rabi_oscillations_program.args([\"rabi_amplitude\"])\ncallable_program = delayed_assignment_program.bloqade.python()\nresults = callable_program(1.0, shots=100)\n

Variables aren't just restricted to having values assigned to them, you can also symbolically manipulate them!

"},{"location":"home/quick_start/#symbolic-parameters","title":"Symbolic Parameters","text":"

Variables in Bloqade can also be symbolically manipulated, giving you even more flexibility when you construct your program.

In the example below, we externally declare a variable my_var that then has some arithmetic done on it to allow it to have a different value in a later part of the program:

from bloqade import start, var\n\nmy_var = var(\"my_variable\")\nwaveform_durations = [0.6, 1.0, 0.6]\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nrabi_waveform = (\n    target_rabi_amplitude\n    .piecewise_linear(durations=waveform_durations,\n                      values=[0.0, my_var, my_var, 0.0])\n)\ntarget_detuning = rabi_waveform.detuning.uniform\ndetuning_waveform = (\n    target_detuning\n    .piecewise_linear(durations=waveform_durations,\n                      values=[my_var-1.0, my_var*0.5, my_var/2, my_var+1.0 ])\n)\n

You still perform variable assignment just like you normally would:

program = detuning_waveform.assign(my_variable=1.0)\n

You can also use Python's built-in sum if you want the sum of multiple variables as a value in your program. This is quite useful when it comes to needing to indicate a full duration for a waveform that doesn't need to be split up:

from bloqade import start, var\n\nvariable_durations = var([\"a\", \"b\", \"c\"])\n\ngeometry = start.add_position((0,0))\ntarget_rabi_amplitude = geometry.rydberg.rabi.amplitude.uniform\nrabi_waveform = (\n    target_rabi_amplitude\n    .piecewise_linear(durations=variable_durations,\n                      values=[0.0, 1.5, 1.5, 0.0])\n)\ntarget_detuning = rabi_waveform.detuning.uniform\ndetuning_waveform = (\n    target_detuning\n    .constant(duration=sum(variable_durations),\n              value=16.2)\n)\n
We later assign values and Bloqade will automatically handle the summation:

program = detuning_waveform.assign(a=0.5, b=1.2, c=0.5)\n
"},{"location":"home/quick_start/#saving-and-loading-results","title":"Saving and Loading Results","text":"

You can save your results in JSON format using Bloqade's save function:

from bloqade import start, save\n\nyour_program = ...\nemulation_results = your_program.bloqade.python().run(100)\nhardware_results = your_program.braket.aquila.run_async(100)\n\nsave(emulation_results, \"emulation_results.json\")\nsave(hardware_results, \"hardware_results.json\")\n

And later reload them into Python using the load function:

from bloqade import load\nemulation_results = load(\"emulation_results.json\")\nhardware_results = load(\"hardware_results.json\")\n
"},{"location":"home/submission/","title":"Submission","text":"

This page is a work in progress!

"},{"location":"home/visualization/","title":"Visualization","text":"

This page is a work in progress!

"},{"location":"home/waveforms/","title":"Waveforms","text":"

This page is a work in progress!

"},{"location":"reference/hardware-capabilities/","title":"Hardware Capabilities","text":"

During program development, it can be quite handy to know what true hardware capabilities are and incorporate that information programmaticaly. Bloqade offers the ability to do this via get_capabilities().

"},{"location":"reference/hardware-capabilities/#programmatic-access","title":"Programmatic Access","text":"

get_capabilities() (importable directly from bloqade) returns a QuEraCapabilities object. This object contains all the hardware constraints in Decimal format for the Aquila machine, our publically-accessible QPU on AWS Braket.

An example of using get_capabilities() is presented below:

from bloqade import get_capabilities, piecewise_linear\n\n# get capabilities for Aquila\naquila_capabilities = get_capabilities()\n\n# obtain maximum Rabi frequency as Decimal\nmax_rabi = aquila_capabilities.capabilities.rydberg.global_.rabi_frequency_max\n\n# use that value in constructing a neat Rabi waveform\nrabi_wf = piecewise_linear(durations = [0.5, 1.0, 0.5], values = [0, max_rabi, max_rabi, 0])\n

The attribute names for each value have been provided below but will require you to provide the proper prefix like in the example above (e.g. the maximum number of qubits lives under the number_qubits_max attribute which can be navigated to via *your_QuEra_Capabilities_Object*.lattice.number_qubits_max).

"},{"location":"reference/hardware-capabilities/#aquila-capabilities","title":"Aquila Capabilities","text":""},{"location":"reference/hardware-capabilities/#task","title":"Task","text":"
  • Use prefix your_capabilities_object.capabilities.task for:
    • minimum number of shots
    • maximum number of shots
Capability Attribute Value Minimum Number of Shots number_shots_min 1 Maximum Number of Shots number_shots_max 1000"},{"location":"reference/hardware-capabilities/#lattice-geometry","title":"Lattice Geometry","text":"
  • Use prefix your_capabilities_object.capabilities.lattice for:
    • maximum number of qubits
  • Use prefix your_capabilities_object.capabilities.lattice.area for:
    • maximum lattice area width
    • maximum lattice area height
  • Use prefix your_capabilities_object.capabilities.lattice.geometry for:
    • maximum number of sites
    • position resolution
    • minimum radial spacing
    • minimum vertical spacing
Capability Attribute Value Maximum Number of Qubits number_qubits_max 256 Maximum Lattice Area Width width 75.0 \u00b5m Maximum Lattice Area Height height 76.0 \u00b5m Minimum Radial Spacing between Qubits spacing_radial_min 4.0 \u00b5m Minimum Vertical Spacing between Qubits spacing_vertical_min 4.0 \u00b5m Position Resolution position_resolution 0.1 \u00b5m Maximum Number of Sites number_sites_max 256"},{"location":"reference/hardware-capabilities/#global-rydberg-values","title":"Global Rydberg Values","text":"
  • Use prefix your_capabilities_object.capabilities.rydberg for:
    • C6 Coefficient
  • Use prefix your_capabilities_object.capabilities.rydberg.global_ for:
    • Everything else related to global (applied to all atom) capabilities
Capability Attribute Value Rydberg Interaction Constant c6_coefficient 5.42\u00d710\u2076 rad/\u03bcs \u00d7 \u00b5m\u2076 Minimum Rabi Frequency rabi_frequency_min 0.00 rad/\u03bcs Maximum Rabi Frequency rabi_frequency_max 15.8 rad/\u03bcs Rabi Frequency Resolution rabi_frequency_resolution 0.0004 rad/\u03bcs Maximum Rabi Frequency Slew Rate rabi_frequency_slew_rate_max 250.0 rad/\u00b5s\u00b2 Minimum Detuning detuning_min -125.0 rad/\u03bcs Maximum Detuning detuning_max 125.0 rad/\u03bcs Detuning Resolution detuning_resolution 2.0\u00d710\u207b\u2077 rad/\u03bcs Maximum Detuning Slew Rate detuning_slew_rate_max 2500.0 rad/\u00b5s\u00b2 Minimum Phase phase_min -99.0 rad Maximum Phase phase_max 99.0 rad Phase Resolution phase_resolution 5.0\u00d710\u207b\u2077 rad Minimum Time time_min 0.0 \u00b5s Maximum Time time_max 4.0 \u00b5s Time Resolution time_resolution 0.001 \u00b5s Minimum \u0394t time_delta_min 0.05 \u00b5s"},{"location":"reference/hardware-capabilities/#local-detuning-values","title":"Local Detuning Values","text":"
  • Use prefix your_capabilities_object.capabilities.rydberg.local for the following values:
Capability Attribute Value Maximum Detuning detuning_max 125.0 rad/\u03bcs Minimum Detuning detuning_min 0 rad/\u03bcs Maximum Detuning Slew Rate detuning_slew_rate_max 1256.0 rad/\u00b5s\u00b2 Maximum Number of Local Detuning Sites number_local_detuning_sites 200 Maximum Site Coefficient site_coefficient_max 1.0 Minimum Site Coefficient site_ceofficient_min 0.0 Minimum Radial Spacing spacing_radial_min 5 \u00b5m Minimum \u0394t time_delta_min 0.05 \u03bcs Time Resolution time_resolution 0.001 \u00b5s"},{"location":"reference/overview/","title":"Builder Overview","text":"

You may have noticed from the Getting Started and Tutorials that Bloqade uses this interesting, dot-intensive syntax.

from bloqade import start\n\nprog = start.add_position((0,0)).rydberg.rabi.amplitude.uniform.constant(1,1)\n
Exhibit A: Lots of Dots

In fact, it might look remniscent of what you see in some gate-based Quantum Computing SDKs:

# this is strictly pseudocode\ncircuit = init_qubits(n_qubits)\n# note the dots!\ncircuit.x(0).z(1).cnot(0, 1)...\n

What's the deal with that?

"},{"location":"reference/overview/#syntax-motivations","title":"Syntax Motivations","text":"

We call this syntax the builder or builder syntax and as its name implies, it is designed to let you build programs for Analog Hamiltonian Simulation hardware as easily and as straightforward as possible.

The linear structure implies a natural hierarchy in how you think about targeting the various degrees of freedom (detuning, atom positions, Rabi amplitude, etc.) your program will have. In the beginning you have unrestricted access to all these degrees of freedom but in order to do something useful you need to:

  1. Narrow down and explicitly identify what you want to control
  2. Provide the instructions on how you want to control what your focused on

Context is a strong component of the builder syntax, as you are both actively restricted from doing certain things that can introduce ambiguity based on where you are in your program and repeating the same action in different parts of the program yields different results.

"},{"location":"reference/overview/#visual-guides","title":"Visual Guides","text":"

While we hope the Smart Documentation (the ability to instantly see all your next possible steps and their capabilities in your favorite IDE/IPython) is sufficient to get you where you need to go, we undestand it's particularly beneficial to get a high-level overview of things before diving in.

The Standard Representation is a nice flow chart that gives a high-level overview of the different steps and components in the builder syntax.

"},{"location":"reference/standard/","title":"Build Workflow","text":"
\nflowchart TD\n  ProgramStart([\"start\"])\n\n  Geometry(\"Geometry or Lattice\")\n\n  Coupling[\"Coupling\n  -----------\n  rydberg\n  hyperfine\"]\n\n  Detuning[\"detuning\"]\n  Rabi[\"rabi\"]\n\n  Amplitude[\"amplitude\"]\n  Phase[\"phase\"]\n\n  SpaceModulation(\"SpatialModulation\n  ----------------------\n  uniform\n  scale\n  location\n  \")\n  Waveform{\"Waveform\n  ------------\n  piecewise_linear\n  piecewise_constant\n  constant\n  linear\n  poly\n  fn\n  \"}\n\n  Options([\"Options\n  ---------\n  assign\n  batch_assign\n  args\n  parallelize\n  \"])\n\n  Services([\"Services\n  ----------\n  bloqade\n  quera\n  braket\"])\n\n  QuEraBackends([\"Backends\n  ------------\n  mock\n  cloud_mock\n  aquila\n  device\"])\n\n  BraketBackends([\"Backends\n  ------------\n  aquila\n  local_emulator\"])\n\n  BloqadeBackends([\"Backends\n  ------------\n  python\n  julia\"])\n\n  Execution(\"\n  Execution hardware only\n  -------------------------------\n  run_async()\n\n  Hardware and simulation\n  -------------------------------\n  run()\n  __call__\")\n\n  ProgramStart -->|add_position| Geometry;\n  Geometry --> Coupling;\n  ProgramStart --> Coupling;\n\n  Coupling --> Detuning;\n  Coupling --> Rabi;\n\n  Rabi --> Amplitude;\n  Rabi --> Phase;\n\n  Detuning --> SpaceModulation;\n  Amplitude --> SpaceModulation;\n  Phase --> SpaceModulation;\n\n  SpaceModulation --> Waveform;\n\n  Waveform --> Coupling;\n  Waveform --> Services;\n  Waveform --> Options;\n  Options --> Services;\n\n  Services -->|quera| QuEraBackends;\n  Services -->|braket| BraketBackends;\n  Services -->|bloqade| BloqadeBackends;\n  QuEraBackends --> Execution;\n  BraketBackends --> Execution;\n  BloqadeBackends --> Execution;\n\n  click ProgramStart \"../bloqade/#bloqade.start\";\n  click Geometry \"../bloqade/atom_arrangement/\";\n  click Coupling \"../bloqade/builder/drive/\";\n  click Detuning \"../bloqade/builder/field/#bloqade.builder.field.Detuning\";\n  click Rabi \"../bloqade/builder/field/#bloqade.builder.field.Rabi\";\n  click Amplitude \"../bloqade/builder/field/#bloqade.builder.field.Amplitude\";\n  click Phase \"../bloqade/builder/field/#bloqade.builder.field.Phase\";\n  click SpaceModulation \"../bloqade/builder/spatial/\";\n  click Waveform \"../bloqade/builder/waveform/\";\n  click Options \"../bloqade/builder/pragmas/\";\n  click Services \"../bloqade/builder/backend/\";\n  click QuEraBackends \"../bloqade/builder/backend/quera/#bloqade.builder.backend.quera.QuEraDeviceRoute\";\n  click BraketBackends \"../bloqade/builder/backend/braket/#bloqade.builder.backend.braket.BraketDeviceRoute\";\n  click BloqadeBackends \"../bloqade/builder/backend/bloqade/#bloqade.builder.backend.bloqade.BloqadeBackend\";\n  click Execution \"../bloqade/ir/routine/braket/#bloqade.ir.routine.braket.BraketRoutine\";\n
"},{"location":"reference/bloqade/analog/","title":"Index","text":""},{"location":"reference/bloqade/analog/#bloqade.analog.RB_C6","title":"RB_C6 module-attribute","text":"
RB_C6 = 2 * pi * 862690\n

The C6 constant for the Rydberg Interaction of two Rubidium atoms in units of: rad \u03bcm^6/\u03bcs

"},{"location":"reference/bloqade/analog/#bloqade.analog.start","title":"start module-attribute","text":"
start = ListOfLocations()\n

A Program starting point, alias of empty ListOfLocations.

  • Next possible steps to build your program are:
  • Specify which level coupling to address with:
    • start.rydberg: for Rydberg Level coupling
    • start.hyperfine: for Hyperfine Level coupling
    • LOCKOUT: You cannot add atoms to your geometry after specifying level coupling.
  • continue/start building your geometry with:
    • start.add_position(): to add atom(s) to current register. It will accept:
      • A single coordinate, represented as a tuple (e.g. (5,6)) with a value that can either be:
        • integers: (5,6)
        • floats: (5.1, 2.5)
        • strings (for later variable assignment): (\"x\", \"y\")
        • Scalar objects: (2*cast(\"x\"), 5+cast(\"y\"))
      • A list of coordinates, represented as a list of types mentioned previously.
      • A numpy array with shape (n, 2) where n is the total number of atoms
"},{"location":"reference/bloqade/analog/#bloqade.analog.Literal","title":"Literal","text":"

Bases: Real

"},{"location":"reference/bloqade/analog/#bloqade.analog.Literal.value","title":"value instance-attribute","text":"
value\n

Scalar Literal, which stores a decimaal value instance.

Parameters:

Name Type Description Default value Decimal

decimal value instance

required"},{"location":"reference/bloqade/analog/#bloqade.analog.Variable","title":"Variable","text":"

Bases: Real

Variable, which stores a variable name.

Parameters:

Name Type Description Default name str

variable instance.

required"},{"location":"reference/bloqade/analog/#bloqade.analog.cast","title":"cast","text":"
cast(py)\n
  1. cast Real number (or list/tuple of Real numbers) to Scalar Literal.

  2. cast str (or list/tuple of Real numbers) to Scalar Variable.

Parameters:

Name Type Description Default py Union[str, Real, Tuple[Real], List[Real]]

python object to cast

required

Returns:

Type Description Scalar

Scalar

Source code in src/bloqade/analog/ir/scalar.py
def cast(py) -> \"Scalar\":\n    \"\"\"\n    1. cast Real number (or list/tuple of Real numbers)\n    to [`Scalar Literal`][bloqade.ir.scalar.Literal].\n\n    2. cast str (or list/tuple of Real numbers)\n    to [`Scalar Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str,Real,Tuple[Real],List[Real]]): python object to cast\n\n    Returns:\n        Scalar\n    \"\"\"\n    ret = trycast(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Scalar Literal\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.constant","title":"constant","text":"
constant(duration, value)\n

Create a Constant waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of the Constant waveform.

required value ScalarType

Value of the Constant waveform.s

required

Returns:

Name Type Description Constant Constant

A Constant waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef constant(duration: ScalarType, value: ScalarType) -> Constant:\n    \"\"\"Create a Constant waveform.\n\n    Args:\n        duration (ScalarType): Duration of the Constant waveform.\n        value (ScalarType): Value of the Constant waveform.s\n\n    Returns:\n        Constant: A Constant waveform.\n    \"\"\"\n    return Constant(value, duration)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.dumps","title":"dumps","text":"
dumps(o, use_decimal=True, **json_kwargs)\n

Serialize object to string

Parameters:

Name Type Description Default o Any

the object to serialize

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dumps

{}

Returns:

Name Type Description str str

the serialized object as a string

Source code in src/bloqade/analog/serialize.py
@beartype\ndef dumps(\n    o: Any,\n    use_decimal: bool = True,\n    **json_kwargs,\n) -> str:\n    \"\"\"Serialize object to string\n\n    Args:\n        o (Any): the object to serialize\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dumps\n\n    Returns:\n        str: the serialized object as a string\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    return json.dumps(o, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.get_capabilities","title":"get_capabilities","text":"
get_capabilities(use_experimental=False)\n

Get the device capabilities for Aquila

Parameters:

Name Type Description Default use_experimental bool

Get experimental capabilities instead of standard ones. By default value is False.

False

Returns:

Name Type Description QuEraCapabilities QuEraCapabilities

capabilities object for Aquila device.

Note

Units of time, distance, and energy are microseconds (us), micrometers (um), and rad / us, respectively.

For a comprehensive list of capabilities, see the Hardware Reference page

Source code in src/bloqade/analog/factory.py
def get_capabilities(use_experimental: bool = False) -> \"QuEraCapabilities\":\n    \"\"\"Get the device capabilities for Aquila\n\n    Args:\n        use_experimental (bool): Get experimental capabilities instead of\n            standard ones. By default value is False.\n\n    Returns:\n        QuEraCapabilities: capabilities object for Aquila device.\n\n\n    Note:\n        Units of time, distance, and energy are microseconds (us),\n        micrometers (um), and rad / us, respectively.\n\n        For a comprehensive list of capabilities,\n        see the [Hardware Reference](../../reference/hardware-capabilities.md)\n        page\n    \"\"\"\n\n    from bloqade.analog.submission.capabilities import get_capabilities\n\n    # manually convert to units\n    return get_capabilities(use_experimental=use_experimental).scale_units(\n        Decimal(\"1e6\"), Decimal(\"1e-6\")\n    )\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.linear","title":"linear","text":"
linear(duration, start, stop)\n

Create a Linear waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of linear waveform

required start ScalarType

Starting value of linear waveform

required stop ScalarType

Ending value of linear waveform

required

Returns:

Name Type Description Linear Linear

Linear waveform

Source code in src/bloqade/analog/factory.py
@beartype\ndef linear(duration: ScalarType, start: ScalarType, stop: ScalarType) -> Linear:\n    \"\"\"Create a Linear waveform.\n\n    Args:\n        duration (ScalarType): Duration of linear waveform\n        start (ScalarType): Starting value of linear waveform\n        stop (ScalarType): Ending value of linear waveform\n\n    Returns:\n        Linear: Linear waveform\n    \"\"\"\n    return Linear(start, stop, duration)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.load","title":"load","text":"
load(fp, use_decimal=True, **json_kwargs)\n

Load object from file

Parameters:

Name Type Description Default fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.load

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef load(fp: Union[TextIO, str], use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from file\n\n    Args:\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.load\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    if isinstance(fp, str):\n        with open(fp, \"r\") as f:\n            return json.load(\n                f,\n                object_hook=Serializer.object_hook,\n                use_decimal=use_decimal,\n                **json_kwargs,\n            )\n    else:\n        return json.load(\n            fp,\n            object_hook=Serializer.object_hook,\n            use_decimal=use_decimal,\n            **json_kwargs,\n        )\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.loads","title":"loads","text":"
loads(s, use_decimal=True, **json_kwargs)\n

Load object from string

Parameters:

Name Type Description Default s str

the string to load

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.loads

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef loads(s: str, use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from string\n\n    Args:\n        s (str): the string to load\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.loads\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    return json.loads(\n        s, object_hook=Serializer.object_hook, use_decimal=use_decimal, **json_kwargs\n    )\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.piecewise_constant","title":"piecewise_constant","text":"
piecewise_constant(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise constant waveform from a list of durations and values. The value duration[i] corresponds to the length of time for the i'th segment with a value of values[i].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not the same as the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_constant(\n    durations: List[ScalarType], values: List[ScalarType]\n) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise constant waveform from a list of durations and values. The\n    value `duration[i]` corresponds to the length of time for the i'th segment\n    with a value of `values[i]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not the same as the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n    if len(durations) != len(values):\n        raise ValueError(\n            \"The length of values must be the same as the length of durations\"\n        )\n\n    pwc_wf = None\n    for duration, value in zip(durations, values):\n        if pwc_wf is None:\n            pwc_wf = Constant(value, duration)\n        else:\n            pwc_wf = pwc_wf.append(Constant(value, duration))\n\n    return pwc_wf\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.piecewise_linear","title":"piecewise_linear","text":"
piecewise_linear(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise linear waveform from a list of durations and values. The value duration[i] is of the linear segment between values[i] and values[i+1].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not one greater than the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_linear(durations: List[ScalarType], values: List[ScalarType]) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise linear waveform from a list of durations and values. The\n    value `duration[i]` is of the linear segment between `values[i]` and `values[i+1]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not one greater than the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n\n    if len(durations) + 1 != len(values):\n        raise ValueError(\n            \"The length of values must be one greater than the length of durations\"\n        )\n\n    pwl_wf = None\n    for duration, start, stop in zip(durations, values[:-1], values[1:]):\n        if pwl_wf is None:\n            pwl_wf = Linear(start, stop, duration)\n        else:\n            pwl_wf = pwl_wf.append(Linear(start, stop, duration))\n\n    return pwl_wf\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.rydberg_h","title":"rydberg_h","text":"
rydberg_h(\n    atoms_positions,\n    detuning=None,\n    amplitude=None,\n    phase=None,\n    static_params={},\n    batch_params=[],\n    args=[],\n)\n

Create a rydberg program with uniform detuning, amplitude, and phase.

Parameters:

Name Type Description Default atoms_positions Any

Description of geometry of atoms in system.

required detuning Optional[Waveform]

Waveform for detuning. Defaults to None.

None amplitude Optional[Waveform]

Waveform describing the amplitude of the rabi term. Defaults to None.

None phase Optional[Waveform]

Waveform describing the phase of rabi term. Defaults to None.

None static_params Dict[str, Any]

Define static parameters of your program. Defaults to {}.

{} batch_params Union[List[Dict[str, Any]], Dict[str, Any]]

Parmaters for a batch of tasks. Defaults to [].

[] args List[str]

List of arguments to leave till runtime. Defaults to [].

[]

Returns:

Name Type Description Routine Routine

An object that can be used to dispatch a rydberg program to multiple backends.

Source code in src/bloqade/analog/factory.py
@beartype\ndef rydberg_h(\n    atoms_positions: Any,\n    detuning: Optional[Waveform] = None,\n    amplitude: Optional[Waveform] = None,\n    phase: Optional[Waveform] = None,\n    static_params: Dict[str, Any] = {},\n    batch_params: Union[List[Dict[str, Any]], Dict[str, Any]] = [],\n    args: List[str] = [],\n) -> Routine:\n    \"\"\"Create a rydberg program with uniform detuning, amplitude, and phase.\n\n    Args:\n        atoms_positions (Any): Description of geometry of atoms in system.\n        detuning (Optional[Waveform], optional): Waveform for detuning.\n            Defaults to None.\n        amplitude (Optional[Waveform], optional): Waveform describing the amplitude of\n            the rabi term. Defaults to None.\n        phase (Optional[Waveform], optional): Waveform describing the phase of rabi\n            term. Defaults to None.\n        static_params (Dict[str, Any], optional): Define static parameters of your\n            program. Defaults to {}.\n        batch_params (Union[List[Dict[str, Any]], Dict[str, Any]], optional):\n            Parmaters for a batch of tasks. Defaults to [].\n        args (List[str], optional): List of arguments to leave till runtime.\n            Defaults to [].\n\n    Returns:\n        Routine: An object that can be used to dispatch a rydberg program to\n            multiple backends.\n    \"\"\"\n    from bloqade.analog import start\n    from bloqade.analog.atom_arrangement import AtomArrangement\n\n    if isinstance(atoms_positions, AtomArrangement):\n        prog = atoms_positions\n    else:\n        prog = start.add_position(atoms_positions)\n\n    if detuning is not None:\n        prog = prog.rydberg.detuning.uniform.apply(detuning)\n\n    if amplitude is not None:\n        prog = prog.amplitude.uniform.apply(amplitude)\n\n    if phase is not None:\n        prog = prog.phase.uniform.apply(phase)\n\n    prog = prog.assign(**static_params)\n\n    if isinstance(batch_params, dict):\n        prog = prog.batch_assign(**batch_params)\n    else:\n        prog = prog.batch_assign(batch_params)\n\n    prog = prog.args(args)\n\n    return prog.parse()\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.save","title":"save","text":"
save(o, fp, use_decimal=True, **json_kwargs)\n

Serialize object to file

Parameters:

Name Type Description Default o Any

the object to serialize

required fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dump

{}

Returns:

Type Description None

None

Source code in src/bloqade/analog/serialize.py
@beartype\ndef save(\n    o: Any,\n    fp: Union[TextIO, str],\n    use_decimal=True,\n    **json_kwargs,\n) -> None:\n    \"\"\"Serialize object to file\n\n    Args:\n        o (Any): the object to serialize\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dump\n\n    Returns:\n        None\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    if isinstance(fp, str):\n        with open(fp, \"w\") as f:\n            json.dump(o, f, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n    else:\n        json.dump(o, fp, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.tree_depth","title":"tree_depth","text":"
tree_depth(depth=None)\n

Setting globally maximum depth for tree printing

If depth=None, return current depth. If depth is provided, setting current depth to depth

Parameters:

Name Type Description Default depth int

the user specified depth. Defaults to None.

None

Returns:

Name Type Description int

current updated depth

Source code in src/bloqade/analog/__init__.py
def tree_depth(depth: int = None):\n    \"\"\"Setting globally maximum depth for tree printing\n\n    If `depth=None`, return current depth.\n    If `depth` is provided, setting current depth to `depth`\n\n    Args:\n        depth (int, optional): the user specified depth. Defaults to None.\n\n    Returns:\n        int: current updated depth\n    \"\"\"\n    if depth is not None:\n        _ir.tree_print.MAX_TREE_DEPTH = depth\n    return _ir.tree_print.MAX_TREE_DEPTH\n
"},{"location":"reference/bloqade/analog/#bloqade.analog.var","title":"var","text":"
var(py)\n

cast string (or list/tuple of strings) to Variable.

Parameters:

Name Type Description Default py Union[str, List[str]]

a string or list/tuple of strings

required

Returns:

Type Description Variable

Union[Variable]

Source code in src/bloqade/analog/ir/scalar.py
def var(py: str) -> \"Variable\":\n    \"\"\"cast string (or list/tuple of strings)\n    to [`Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str, List[str]]): a string or list/tuple of strings\n\n    Returns:\n       Union[Variable]\n    \"\"\"\n    ret = tryvar(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Variable\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/atom_arrangement/","title":"Atom arrangement","text":""},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/atom_arrangement/#bloqade.analog.atom_arrangement.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/constants/","title":"Constants","text":""},{"location":"reference/bloqade/analog/constants/#bloqade.analog.constants.RB_C6","title":"RB_C6 module-attribute","text":"
RB_C6 = 2 * pi * 862690\n

The C6 constant for the Rydberg Interaction of two Rubidium atoms in units of: rad \u03bcm^6/\u03bcs

"},{"location":"reference/bloqade/analog/factory/","title":"Factory","text":""},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.constant","title":"constant","text":"
constant(duration, value)\n

Create a Constant waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of the Constant waveform.

required value ScalarType

Value of the Constant waveform.s

required

Returns:

Name Type Description Constant Constant

A Constant waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef constant(duration: ScalarType, value: ScalarType) -> Constant:\n    \"\"\"Create a Constant waveform.\n\n    Args:\n        duration (ScalarType): Duration of the Constant waveform.\n        value (ScalarType): Value of the Constant waveform.s\n\n    Returns:\n        Constant: A Constant waveform.\n    \"\"\"\n    return Constant(value, duration)\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.get_capabilities","title":"get_capabilities","text":"
get_capabilities(use_experimental=False)\n

Get the device capabilities for Aquila

Parameters:

Name Type Description Default use_experimental bool

Get experimental capabilities instead of standard ones. By default value is False.

False

Returns:

Name Type Description QuEraCapabilities QuEraCapabilities

capabilities object for Aquila device.

Note

Units of time, distance, and energy are microseconds (us), micrometers (um), and rad / us, respectively.

For a comprehensive list of capabilities, see the Hardware Reference page

Source code in src/bloqade/analog/factory.py
def get_capabilities(use_experimental: bool = False) -> \"QuEraCapabilities\":\n    \"\"\"Get the device capabilities for Aquila\n\n    Args:\n        use_experimental (bool): Get experimental capabilities instead of\n            standard ones. By default value is False.\n\n    Returns:\n        QuEraCapabilities: capabilities object for Aquila device.\n\n\n    Note:\n        Units of time, distance, and energy are microseconds (us),\n        micrometers (um), and rad / us, respectively.\n\n        For a comprehensive list of capabilities,\n        see the [Hardware Reference](../../reference/hardware-capabilities.md)\n        page\n    \"\"\"\n\n    from bloqade.analog.submission.capabilities import get_capabilities\n\n    # manually convert to units\n    return get_capabilities(use_experimental=use_experimental).scale_units(\n        Decimal(\"1e6\"), Decimal(\"1e-6\")\n    )\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.linear","title":"linear","text":"
linear(duration, start, stop)\n

Create a Linear waveform.

Parameters:

Name Type Description Default duration ScalarType

Duration of linear waveform

required start ScalarType

Starting value of linear waveform

required stop ScalarType

Ending value of linear waveform

required

Returns:

Name Type Description Linear Linear

Linear waveform

Source code in src/bloqade/analog/factory.py
@beartype\ndef linear(duration: ScalarType, start: ScalarType, stop: ScalarType) -> Linear:\n    \"\"\"Create a Linear waveform.\n\n    Args:\n        duration (ScalarType): Duration of linear waveform\n        start (ScalarType): Starting value of linear waveform\n        stop (ScalarType): Ending value of linear waveform\n\n    Returns:\n        Linear: Linear waveform\n    \"\"\"\n    return Linear(start, stop, duration)\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.piecewise_constant","title":"piecewise_constant","text":"
piecewise_constant(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise constant waveform from a list of durations and values. The value duration[i] corresponds to the length of time for the i'th segment with a value of values[i].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not the same as the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_constant(\n    durations: List[ScalarType], values: List[ScalarType]\n) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise constant waveform from a list of durations and values. The\n    value `duration[i]` corresponds to the length of time for the i'th segment\n    with a value of `values[i]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not the same as the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n    if len(durations) != len(values):\n        raise ValueError(\n            \"The length of values must be the same as the length of durations\"\n        )\n\n    pwc_wf = None\n    for duration, value in zip(durations, values):\n        if pwc_wf is None:\n            pwc_wf = Constant(value, duration)\n        else:\n            pwc_wf = pwc_wf.append(Constant(value, duration))\n\n    return pwc_wf\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.piecewise_linear","title":"piecewise_linear","text":"
piecewise_linear(durations, values)\n

Create a piecewise linear waveform.

Create a piecewise linear waveform from a list of durations and values. The value duration[i] is of the linear segment between values[i] and values[i+1].

Parameters:

Name Type Description Default durations List[ScalarType]

The duration of each segment

required values List[ScalarType]

The values for each segment

required

Raises:

Type Description ValueError

If the length of values is not one greater than the length of

Returns:

Name Type Description Waveform Waveform

The piecewise linear waveform.

Source code in src/bloqade/analog/factory.py
@beartype\ndef piecewise_linear(durations: List[ScalarType], values: List[ScalarType]) -> Waveform:\n    \"\"\"Create a piecewise linear waveform.\n\n    Create a piecewise linear waveform from a list of durations and values. The\n    value `duration[i]` is of the linear segment between `values[i]` and `values[i+1]`.\n\n    Args:\n        durations (List[ScalarType]): The duration of each segment\n        values (List[ScalarType]): The values for each segment\n\n    Raises:\n        ValueError: If the length of `values` is not one greater than the length of\n        `durations`.\n\n    Returns:\n        Waveform: The piecewise linear waveform.\n    \"\"\"\n\n    if len(durations) + 1 != len(values):\n        raise ValueError(\n            \"The length of values must be one greater than the length of durations\"\n        )\n\n    pwl_wf = None\n    for duration, start, stop in zip(durations, values[:-1], values[1:]):\n        if pwl_wf is None:\n            pwl_wf = Linear(start, stop, duration)\n        else:\n            pwl_wf = pwl_wf.append(Linear(start, stop, duration))\n\n    return pwl_wf\n
"},{"location":"reference/bloqade/analog/factory/#bloqade.analog.factory.rydberg_h","title":"rydberg_h","text":"
rydberg_h(\n    atoms_positions,\n    detuning=None,\n    amplitude=None,\n    phase=None,\n    static_params={},\n    batch_params=[],\n    args=[],\n)\n

Create a rydberg program with uniform detuning, amplitude, and phase.

Parameters:

Name Type Description Default atoms_positions Any

Description of geometry of atoms in system.

required detuning Optional[Waveform]

Waveform for detuning. Defaults to None.

None amplitude Optional[Waveform]

Waveform describing the amplitude of the rabi term. Defaults to None.

None phase Optional[Waveform]

Waveform describing the phase of rabi term. Defaults to None.

None static_params Dict[str, Any]

Define static parameters of your program. Defaults to {}.

{} batch_params Union[List[Dict[str, Any]], Dict[str, Any]]

Parmaters for a batch of tasks. Defaults to [].

[] args List[str]

List of arguments to leave till runtime. Defaults to [].

[]

Returns:

Name Type Description Routine Routine

An object that can be used to dispatch a rydberg program to multiple backends.

Source code in src/bloqade/analog/factory.py
@beartype\ndef rydberg_h(\n    atoms_positions: Any,\n    detuning: Optional[Waveform] = None,\n    amplitude: Optional[Waveform] = None,\n    phase: Optional[Waveform] = None,\n    static_params: Dict[str, Any] = {},\n    batch_params: Union[List[Dict[str, Any]], Dict[str, Any]] = [],\n    args: List[str] = [],\n) -> Routine:\n    \"\"\"Create a rydberg program with uniform detuning, amplitude, and phase.\n\n    Args:\n        atoms_positions (Any): Description of geometry of atoms in system.\n        detuning (Optional[Waveform], optional): Waveform for detuning.\n            Defaults to None.\n        amplitude (Optional[Waveform], optional): Waveform describing the amplitude of\n            the rabi term. Defaults to None.\n        phase (Optional[Waveform], optional): Waveform describing the phase of rabi\n            term. Defaults to None.\n        static_params (Dict[str, Any], optional): Define static parameters of your\n            program. Defaults to {}.\n        batch_params (Union[List[Dict[str, Any]], Dict[str, Any]], optional):\n            Parmaters for a batch of tasks. Defaults to [].\n        args (List[str], optional): List of arguments to leave till runtime.\n            Defaults to [].\n\n    Returns:\n        Routine: An object that can be used to dispatch a rydberg program to\n            multiple backends.\n    \"\"\"\n    from bloqade.analog import start\n    from bloqade.analog.atom_arrangement import AtomArrangement\n\n    if isinstance(atoms_positions, AtomArrangement):\n        prog = atoms_positions\n    else:\n        prog = start.add_position(atoms_positions)\n\n    if detuning is not None:\n        prog = prog.rydberg.detuning.uniform.apply(detuning)\n\n    if amplitude is not None:\n        prog = prog.amplitude.uniform.apply(amplitude)\n\n    if phase is not None:\n        prog = prog.phase.uniform.apply(phase)\n\n    prog = prog.assign(**static_params)\n\n    if isinstance(batch_params, dict):\n        prog = prog.batch_assign(**batch_params)\n    else:\n        prog = prog.batch_assign(batch_params)\n\n    prog = prog.args(args)\n\n    return prog.parse()\n
"},{"location":"reference/bloqade/analog/migrate/","title":"Migrate","text":""},{"location":"reference/bloqade/analog/serialize/","title":"Serialize","text":""},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize._import_submodules","title":"_import_submodules","text":"
_import_submodules(package, recursive=True)\n

Import all submodules of a module, recursively, including subpackages

:param package: package (name or actual module) :type package: str | module :rtype: dict[str, types.ModuleType]

Source code in src/bloqade/analog/serialize.py
def _import_submodules(package, recursive=True):\n    \"\"\"Import all submodules of a module, recursively,\n    including subpackages\n\n    :param package: package (name or actual module)\n    :type package: str | module\n    :rtype: dict[str, types.ModuleType]\n    \"\"\"\n\n    if isinstance(package, str):\n        package = importlib.import_module(package)\n\n    for loader, name, is_pkg in pkgutil.walk_packages(package.__path__):\n        full_name = package.__name__ + \".\" + name\n        try:\n            importlib.import_module(full_name)\n        except ModuleNotFoundError:\n            continue\n        if recursive and is_pkg:\n            _import_submodules(full_name)\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.dumps","title":"dumps","text":"
dumps(o, use_decimal=True, **json_kwargs)\n

Serialize object to string

Parameters:

Name Type Description Default o Any

the object to serialize

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dumps

{}

Returns:

Name Type Description str str

the serialized object as a string

Source code in src/bloqade/analog/serialize.py
@beartype\ndef dumps(\n    o: Any,\n    use_decimal: bool = True,\n    **json_kwargs,\n) -> str:\n    \"\"\"Serialize object to string\n\n    Args:\n        o (Any): the object to serialize\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dumps\n\n    Returns:\n        str: the serialized object as a string\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    return json.dumps(o, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.load","title":"load","text":"
load(fp, use_decimal=True, **json_kwargs)\n

Load object from file

Parameters:

Name Type Description Default fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.load

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef load(fp: Union[TextIO, str], use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from file\n\n    Args:\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.load\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    if isinstance(fp, str):\n        with open(fp, \"r\") as f:\n            return json.load(\n                f,\n                object_hook=Serializer.object_hook,\n                use_decimal=use_decimal,\n                **json_kwargs,\n            )\n    else:\n        return json.load(\n            fp,\n            object_hook=Serializer.object_hook,\n            use_decimal=use_decimal,\n            **json_kwargs,\n        )\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.loads","title":"loads","text":"
loads(s, use_decimal=True, **json_kwargs)\n

Load object from string

Parameters:

Name Type Description Default s str

the string to load

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.loads

{}

Returns:

Name Type Description Any

the deserialized object

Source code in src/bloqade/analog/serialize.py
@beartype\ndef loads(s: str, use_decimal: bool = True, **json_kwargs):\n    \"\"\"Load object from string\n\n    Args:\n        s (str): the string to load\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.loads\n\n    Returns:\n        Any: the deserialized object\n    \"\"\"\n    load_bloqade()\n    return json.loads(\n        s, object_hook=Serializer.object_hook, use_decimal=use_decimal, **json_kwargs\n    )\n
"},{"location":"reference/bloqade/analog/serialize/#bloqade.analog.serialize.save","title":"save","text":"
save(o, fp, use_decimal=True, **json_kwargs)\n

Serialize object to file

Parameters:

Name Type Description Default o Any

the object to serialize

required fp Union[TextIO, str]

the file path or file object

required use_decimal bool

use decimal.Decimal for numbers. Defaults to True.

True **json_kwargs

other arguments passed to json.dump

{}

Returns:

Type Description None

None

Source code in src/bloqade/analog/serialize.py
@beartype\ndef save(\n    o: Any,\n    fp: Union[TextIO, str],\n    use_decimal=True,\n    **json_kwargs,\n) -> None:\n    \"\"\"Serialize object to file\n\n    Args:\n        o (Any): the object to serialize\n        fp (Union[TextIO, str]): the file path or file object\n        use_decimal (bool, optional): use decimal.Decimal for numbers. Defaults to True.\n        **json_kwargs: other arguments passed to json.dump\n\n    Returns:\n        None\n    \"\"\"\n    if not isinstance(o, Serializer.types):\n        raise TypeError(\n            f\"Object of type {type(o)} is not JSON serializable. \"\n            f\"Only {Serializer.types} are supported.\"\n        )\n    if isinstance(fp, str):\n        with open(fp, \"w\") as f:\n            json.dump(o, f, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n    else:\n        json.dump(o, fp, cls=Serializer, use_decimal=use_decimal, **json_kwargs)\n
"},{"location":"reference/bloqade/analog/builder/","title":"Index","text":""},{"location":"reference/bloqade/analog/builder/args/","title":"Args","text":""},{"location":"reference/bloqade/analog/builder/assign/","title":"Assign","text":""},{"location":"reference/bloqade/analog/builder/coupling/","title":"Coupling","text":""},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Hyperfine","title":"Hyperfine","text":"
Hyperfine(parent=None)\n

Bases: LevelCoupling

This node represents level coupling between hyperfine states.

Examples:

- To reach the node from the start node:\n\n>>> node = bloqade.start.hyperfine\n>>> type(node)\n<class 'bloqade.builder.coupling.Hyperfine'>\n\n- Hyperfine level coupling has two reachable field nodes:\n\n    - detuning term (See also [`Detuning`][bloqade.builder.field.Detuning])\n    - rabi term (See also [`Rabi`][bloqade.builder.field.Rabi])\n\n>>> hyp_detune = bloqade.start.hyperfine.detuning\n>>> hyp_rabi = bloqade.start.hyperfine.rabi\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Hyperfine.__bloqade_ir__","title":"__bloqade_ir__","text":"
__bloqade_ir__()\n

Generate the intermediate representation (IR) for the Hyperfine level coupling.

Returns:

Name Type Description IR

An intermediate representation of the Hyperfine level coupling sequence.

Note

This method is used internally by the Bloqade framework.

Source code in src/bloqade/analog/builder/coupling.py
def __bloqade_ir__(self):\n    \"\"\"\n    Generate the intermediate representation (IR) for the Hyperfine level coupling.\n\n    Args:\n        None\n\n    Returns:\n        IR: An intermediate representation of the Hyperfine level coupling sequence.\n\n    Raises:\n        None\n\n    Note:\n        This method is used internally by the Bloqade framework.\n    \"\"\"\n    from bloqade.analog.ir.control.sequence import hyperfine\n\n    return hyperfine\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.LevelCoupling","title":"LevelCoupling","text":"
LevelCoupling(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.LevelCoupling.detuning","title":"detuning property","text":"
detuning\n

Specify the Detuning Field of your program. You will be able to specify the spatial modulation afterwards.

Returns:

Type Description Detuning

Detuning: A program node representing the detuning field.

Note

The detuning specifies how off-resonant the laser being applied to the atoms is from the atomic energy transition, driven by the Rabi frequency.

Example:

from bloqade import start\ngeometry = start.add_position((0,0))\ncoupling = geometry.rydberg\ncoupling.detuning\n

  • Next Possible Steps You may continue building your program via:
  • uniform: To address all atoms in the field
  • location(locations, scales): To address atoms at specific locations via indices
  • scale(coeffs): To address all atoms with an individual scale factor
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.LevelCoupling.rabi","title":"rabi property","text":"
rabi\n

Specify the complex-valued Rabi field of your program.

The Rabi field is composed of a real-valued Amplitude and Phase field.

Returns:

Name Type Description Rabi Rabi

A program node representing the Rabi field.

Note

Next possible steps to build your program are creating the RabiAmplitude field and RabiPhase field of the field: - ...rabi.amplitude: To create the Rabi amplitude field - ...rabi.phase: To create the Rabi phase field

"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Rydberg","title":"Rydberg","text":"
Rydberg(parent=None)\n

Bases: LevelCoupling

This node represents level coupling of the Rydberg state.

Examples:

- To reach the node from the start node:\n\n>>> node = bloqade.start.rydberg\n>>> type(node)\n<class 'bloqade.builder.coupling.Rydberg'>\n\n- Rydberg level coupling has two reachable field nodes:\n\n    - detuning term (See also [`Detuning`][bloqade.builder.field.Detuning])\n    - rabi term (See also [`Rabi`][bloqade.builder.field.Rabi])\n\n>>> ryd_detune = bloqade.start.rydberg.detuning\n>>> ryd_rabi = bloqade.start.rydberg.rabi\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/coupling/#bloqade.analog.builder.coupling.Rydberg.__bloqade_ir__","title":"__bloqade_ir__","text":"
__bloqade_ir__()\n

Generate the intermediate representation (IR) for the Rydberg level coupling.

Returns:

Name Type Description IR

An intermediate representation of the Rydberg level coupling sequence.

Note

This method is used internally by the Bloqade framework.

Source code in src/bloqade/analog/builder/coupling.py
def __bloqade_ir__(self):\n    \"\"\"\n    Generate the intermediate representation (IR) for the Rydberg level coupling.\n\n    Args:\n        None\n\n    Returns:\n        IR: An intermediate representation of the Rydberg level coupling sequence.\n\n    Raises:\n        None\n\n    Note:\n        This method is used internally by the Bloqade framework.\n    \"\"\"\n    from bloqade.analog.ir.control.sequence import rydberg\n\n    return rydberg\n
"},{"location":"reference/bloqade/analog/builder/drive/","title":"Drive","text":""},{"location":"reference/bloqade/analog/builder/drive/#bloqade.analog.builder.drive.Drive","title":"Drive","text":""},{"location":"reference/bloqade/analog/builder/drive/#bloqade.analog.builder.drive.Drive.hyperfine","title":"hyperfine property","text":"
hyperfine\n

Address the Hyperfine level coupling in your program.

  • Next possible steps to build your program are specifying the Rabi field or Detuning field.
    • ...hyperfine.rabi: for Rabi field
    • ...hyperfine.detuning: for Detuning field
  • In the absence of a field you the value is set to zero by default.
"},{"location":"reference/bloqade/analog/builder/drive/#bloqade.analog.builder.drive.Drive.rydberg","title":"rydberg property","text":"
rydberg\n

Address the Rydberg level coupling in your program.

  • Next possible steps to build your program are specifying the Rabi field or Detuning field.
    • ...rydberg.rabi: for Rabi field
    • ...rydberg.detuning: for Detuning field
  • In the absence of a field you the value is set to zero by default.
"},{"location":"reference/bloqade/analog/builder/field/","title":"Field","text":""},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Detuning","title":"Detuning","text":"
Detuning(parent=None)\n

Bases: Field

This node represent detuning field of a specified level coupling (rydberg or hyperfine) type.

Examples:

- To specify detuning of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.detuning\n>>> type(node)\n<class 'bloqade.builder.field.Detuning'>\n\n- To specify detuning of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.detuning\n>>> type(node)\n<class 'bloqade.builder.field.Detuning'>\n
Note

This node is a SpatialModulation node. See SpatialModulation for additional options.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field","title":"Field","text":"
Field(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.uniform","title":"uniform property","text":"
uniform\n

Address all atoms as part of defining the spatial modulation component of a drive.

Next steps to build your program include choosing the waveform that will be summed with the spatial modulation to create a drive.

The drive by itself, or the sum of subsequent drives (created by just chaining the construction of drives) will become the field (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.).

  • You can now do:
    • ...uniform.linear(start, stop, duration) : to apply a linear waveform
    • ...uniform.constant(value, duration) : to apply a constant waveform
    • ...uniform.poly([coefficients], duration) : to apply a polynomial waveform
    • ...uniform.apply(wf:bloqade.ir.Waveform): to apply a pre-defined waveform
    • ...uniform.piecewise_linear([durations], [values]): to apply a piecewise linear waveform
    • ...uniform.piecewise_constant([durations], [values]): to apply a piecewise constant waveform
    • ...uniform.fn(f(t,...)): to apply a function as a waveform
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.location","title":"location","text":"
location(labels, scales=None)\n

Address a single atom (or multiple) atoms.

Address a single atom (or multiple) as part of defining the spatial modulation component of a drive. You can specify the atoms to target as a list of labels and a list of scales. The scales are used to multiply the waveform that is applied to the atom. You can also specify a single label and scale to target a single atom.

Next steps to build your program include choosing the waveform that will be summed with the spatial modulation to create a drive.

The drive by itself, or the sum of subsequent drives (created by just chaining the construction of drives) will become the field. (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)

"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.location--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n# to target a single atom with a waveform\n>>> one_location_prog = prog.location(0)\n# to target a single atom with a scale\n>>> one_location_prog = prog.location(0, 0.5)\n# to target multiple atoms with same waveform\n>>> multi_location_prog = prog.location([0, 2])\n# to target multiple atoms with different scales\n>>> multi_location_prog = prog.location([0, 2], [0.5, \"scale\"])\n
  • You can now do:
    • ...location(labels, scales).linear(start, stop, duration) : to apply a linear waveform
    • ...location(labels, scales).constant(value, duration) : to apply a constant waveform
    • ...location(labels, scales).poly([coefficients], duration) : to apply a polynomial waveform
    • ...location(labels, scales).apply(wf:bloqade.ir.Waveform): to apply a pre-defined waveform
    • ...location(labels, scales).piecewise_linear([durations], [values]): to apply a piecewise linear waveform
    • ...location(labels, scales).piecewise_constant([durations], [values]): to apply a piecewise constant waveform
    • ...location(labels, scales).fn(f(t,..)): to apply a function as a waveform
Source code in src/bloqade/analog/builder/field.py
def location(\n    self,\n    labels: Union[List[int], int],\n    scales: Union[List[ScalarType], ScalarType, None] = None,\n) -> \"Location\":\n    \"\"\"Address a single atom (or multiple) atoms.\n\n    Address a single atom (or multiple) as part of defining the spatial\n    modulation component of a drive. You can specify the atoms to target\n    as a list of labels and a list of scales. The scales are used to\n    multiply the waveform that is applied to the atom. You can also specify\n    a single label and scale to target a single atom.\n\n    Next steps to build your program include choosing the waveform that\n    will be summed with the spatial modulation to create a drive.\n\n    The drive by itself, or the sum of subsequent drives (created by just\n    chaining the construction of drives) will become the field.\n    (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n    # to target a single atom with a waveform\n    >>> one_location_prog = prog.location(0)\n    # to target a single atom with a scale\n    >>> one_location_prog = prog.location(0, 0.5)\n    # to target multiple atoms with same waveform\n    >>> multi_location_prog = prog.location([0, 2])\n    # to target multiple atoms with different scales\n    >>> multi_location_prog = prog.location([0, 2], [0.5, \"scale\"])\n    ```\n\n    - You can now do:\n        - `...location(labels, scales).linear(start, stop, duration)` : to apply\n            a linear waveform\n        - `...location(labels, scales).constant(value, duration)` : to apply\n            a constant waveform\n        - `...location(labels, scales).poly([coefficients], duration)` : to apply\n            a polynomial waveform\n        - `...location(labels, scales).apply(wf:bloqade.ir.Waveform)`: to apply\n            a pre-defined waveform\n        - `...location(labels, scales).piecewise_linear([durations], [values])`:\n            to apply\n            a piecewise linear waveform\n        - `...location(labels, scales).piecewise_constant([durations], [values])`:\n            to apply\n            a piecewise constant waveform\n        - `...location(labels, scales).fn(f(t,..))`: to apply a function as a\n            waveform\n\n    \"\"\"\n    return self._location(labels, scales)\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.scale","title":"scale","text":"
scale(coeffs)\n

Address all the atoms scaling each atom with an element of the list or define a variable name for the scale list to be assigned later by defining a name and using assign or batch_assign later.

Next steps to build your program include choosing the waveform that will be summed with the spatial modulation to create a drive.

The drive by itself, or the sum of subsequent drives (created by just chaining the construction of drives) will become the field (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)

"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Field.scale--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n\n# assign a literal list of values to scale each atom\n>>> one_location_prog = prog.scale([0.1, 0.2, 0.3])\n# assign a variable name to be assigned later\n>>> one_location_prog = prog.scale(\"a\")\n# \"a\" can be assigned in the END of the program during variable assignment\n# using a list of values, indicating the scaling for each atom\n>>> single_assignment = ...assign(a = [0.1, 0.2, 0.3])\n# a list of lists, indicating a set of atoms should be targeted\n# for each task in a batch.\n>>> batch_assignment = ...batch_assign(a = [list_1, list_2, list_3,...])\n
  • You can now do:
    • ...scale(coeffs).linear(start, stop, duration) : to apply a linear waveform
    • ...scale(coeffs).constant(value, duration) : to apply a constant waveform
    • ...scale(coeffs).poly([coefficients], duration) : to apply a polynomial waveform
    • ...scale(coeffs).apply(wf:bloqade.ir.Waveform): to apply a pre-defined waveform
    • ...scale(coeffs).piecewise_linear(durations, values): to apply a piecewise linear waveform
    • ...scale(coeffs).piecewise_constant(durations, values): to apply a piecewise constant waveform
    • ...scale(coeffs).fn(f(t,..)): to apply a function as a waveform
Source code in src/bloqade/analog/builder/field.py
def scale(self, coeffs: Union[str, List[ScalarType]]) -> \"Scale\":\n    \"\"\"\n    Address all the atoms scaling each atom with an element of the list\n    or define a variable name for the scale list to be assigned later by\n    defining a `name` and using `assign` or `batch_assign` later.\n\n    Next steps to build your program include choosing the waveform that\n    will be summed with the spatial modulation to create a drive.\n\n    The drive by itself, or the sum of subsequent drives (created by just\n    chaining the construction of drives) will become the field\n    (e.g. Detuning Field, Real-Valued Rabi Amplitude/Rabi Phase Field, etc.)\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position([(0,0),(1,4),(2,8)]).rydberg.rabi\n\n    # assign a literal list of values to scale each atom\n    >>> one_location_prog = prog.scale([0.1, 0.2, 0.3])\n    # assign a variable name to be assigned later\n    >>> one_location_prog = prog.scale(\"a\")\n    # \"a\" can be assigned in the END of the program during variable assignment\n    # using a list of values, indicating the scaling for each atom\n    >>> single_assignment = ...assign(a = [0.1, 0.2, 0.3])\n    # a list of lists, indicating a set of atoms should be targeted\n    # for each task in a batch.\n    >>> batch_assignment = ...batch_assign(a = [list_1, list_2, list_3,...])\n\n    ```\n\n    - You can now do:\n        - `...scale(coeffs).linear(start, stop, duration)` : to apply\n            a linear waveform\n        - `...scale(coeffs).constant(value, duration)` : to apply\n            a constant waveform\n        - `...scale(coeffs).poly([coefficients], duration)` : to apply\n            a polynomial waveform\n        - `...scale(coeffs).apply(wf:bloqade.ir.Waveform)`: to apply\n            a pre-defined waveform\n        - `...scale(coeffs).piecewise_linear(durations, values)`:  to\n            apply a piecewise linear waveform\n        - `...scale(coeffs).piecewise_constant(durations, values)`: to\n            apply a piecewise constant waveform\n        - `...scale(coeffs).fn(f(t,..))`: to apply a function as a waveform\n\n    \"\"\"\n    from bloqade.analog.builder.spatial import Scale\n\n    return Scale(coeffs, self)\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Rabi","title":"Rabi","text":"
Rabi(parent=None)\n

Bases: Builder

This node represent rabi field of a specified level coupling (rydberg or hyperfine) type.

Examples:

- To specify rabi of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.rabi\n<class 'bloqade.builder.field.Rabi'>\n\n- To specify rabi of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.rabi\n>>> type(node)\n<class 'bloqade.builder.field.Rabi'>\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Rabi.amplitude","title":"amplitude property","text":"
amplitude\n

Specify the real-valued Rabi Amplitude field.

Next steps to build your program focus on specifying a spatial modulation.

The spatial modulation, when coupled with a waveform, completes the specification of a \"Drive\". One or more drives can be summed together automatically to create a field such as the Rabi Amplitude here.

  • You can now
    • ...amplitude.uniform: Address all atoms in the field
    • ...amplitude.location(...): Scale atoms by their indices
    • ...amplitude.scale(...): Scale each atom with a value from a list or assign a variable name to be assigned later
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.Rabi.phase","title":"phase property","text":"
phase\n

Specify the real-valued Rabi Phase field.

Next steps to build your program focus on specifying a spatial modulation.

The spatial modulation, when coupled with a waveform, completes the specification of a \"Drive\". One or more drives can be summed together automatically to create a field such as the Rabi Phase here.

  • You can now
    • ...amplitude.uniform: Address all atoms in the field
    • ...amplitude.location(...): Scale atoms by their indices
    • ...amplitude.scale(...): Scale each atom with a value from a list or assign a variable name to be assigned later
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.RabiAmplitude","title":"RabiAmplitude","text":"
RabiAmplitude(parent=None)\n

Bases: Field

This node represent amplitude of a rabi field.

Examples:

- To specify rabi amplitude of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.rabi.amplitude\n>>> type(node)\n<class 'bloqade.builder.field.Amplitude'>\n\n- To specify rabi amplitude of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.rabi.amplitude\n>>> type(node)\n<class 'bloqade.builder.field.Amplitude'>\n
Note

This node is a SpatialModulation node. See SpatialModulation for additional options.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/field/#bloqade.analog.builder.field.RabiPhase","title":"RabiPhase","text":"
RabiPhase(parent=None)\n

Bases: Field

This node represent phase of a rabi field.

Examples:

- To specify rabi phase of rydberg coupling:\n\n>>> node = bloqade.start.rydberg.rabi.phase\n>>> type(node)\n<class 'bloqade.builder.field.Phase'>\n\n- To specify rabi phase of hyperfine coupling:\n\n>>> node = bloqade.start.hyperfine.rabi.phase\n>>> type(node)\n<class 'bloqade.builder.field.Phase'>\n
Note

This node is a SpatialModulation node. See SpatialModulation for additional options.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/parallelize/","title":"Parallelize","text":""},{"location":"reference/bloqade/analog/builder/pragmas/","title":"Pragmas","text":"

This module provides classes for building and managing quantum programs using the Bloqade library.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.AddArgs","title":"AddArgs","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.AddArgs.args","title":"args","text":"
args(args_list)\n

Add arguments to the current program.

Parameters:

Name Type Description Default args_list List[Union[str, Variable]]

List of argument names or Variable objects to be added.

required

Returns:

Name Type Description Args Args

A new instance of the Args class with the specified arguments.

Raises:

Type Description TypeError

If args_list contains invalid types.

Note

This method is useful for deferring the value assignment of certain variables to runtime.

Source code in src/bloqade/analog/builder/pragmas.py
def args(self, args_list: List[Union[str, Variable]]) -> \"Args\":\n    \"\"\"\n    Add arguments to the current program.\n\n    Args:\n        args_list (List[Union[str, Variable]]): List of argument names or Variable\n            objects to be added.\n\n    Returns:\n        Args: A new instance of the Args class with the specified arguments.\n\n    Raises:\n        TypeError: If args_list contains invalid types.\n\n    Note:\n        This method is useful for deferring the value assignment of certain\n        variables to runtime.\n    \"\"\"\n    from bloqade.analog.builder.args import Args\n\n    return Args(args_list, self)\n
"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Assignable","title":"Assignable","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Assignable.assign","title":"assign","text":"
assign(**assignments)\n

Assign values to variables declared previously in the program.

Parameters:

Name Type Description Default **assignments

Key-value pairs where the key is the variable name and the value is the value to assign.

{}

Returns:

Name Type Description Assign Assign

A new instance of the Assign class with the specified assignments.

Raises:

Type Description ValueError

If an invalid assignment is provided.

Note

This is reserved for variables that should take single values or for spatial modulations created with .scale(str). After assigning values, you can choose a backend for emulation or execution.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Assignable.assign--usage-examples","title":"Usage Examples:","text":"
# define geometry\n>>> reg = bloqade.start\n...       .add_position([(0,0),(1,1),(2,2),(3,3)])\n# define variables in program\n>>> seq = reg.rydberg.detuning.uniform\n...       .linear(start=\"ival\", stop=1, duration=\"span_time\")\n# assign values to variables\n>>> seq = seq.assign(span_time=0.5, ival=0.0)\n
  • Next steps:
    • ...assign(assignments).bloqade: select the bloqade local emulator backend
    • ...assign(assignments).braket: select braket local emulator or QuEra hardware
    • ...assign(assignments).device(specifier_string): select backend by specifying a string
    • ...assign(assignments).batch_assign(assignments): assign multiple values for a parameter sweep
    • ...assign(assignments).parallelize(cluster_spacing): parallelize the program register
    • ...assign(assignments).args([previously_defined_vars]): defer value assignment to runtime
Source code in src/bloqade/analog/builder/pragmas.py
def assign(self, **assignments) -> \"Assign\":\n    \"\"\"\n    Assign values to variables declared previously in the program.\n\n    Args:\n        **assignments: Key-value pairs where the key is the variable name and\n            the value is the value to assign.\n\n    Returns:\n        Assign: A new instance of the Assign class with the specified\n            assignments.\n\n    Raises:\n        ValueError: If an invalid assignment is provided.\n\n    Note:\n        This is reserved for variables that should take single values or for\n        spatial modulations created with `.scale(str)`. After assigning values,\n        you can choose a backend for emulation or execution.\n\n    ### Usage Examples:\n    ```\n    # define geometry\n    >>> reg = bloqade.start\n    ...       .add_position([(0,0),(1,1),(2,2),(3,3)])\n    # define variables in program\n    >>> seq = reg.rydberg.detuning.uniform\n    ...       .linear(start=\"ival\", stop=1, duration=\"span_time\")\n    # assign values to variables\n    >>> seq = seq.assign(span_time=0.5, ival=0.0)\n    ```\n\n    - Next steps:\n        - `...assign(assignments).bloqade`: select the bloqade local emulator backend\n        - `...assign(assignments).braket`: select braket local emulator or QuEra hardware\n        - `...assign(assignments).device(specifier_string)`: select backend by specifying a\n        string\n        - `...assign(assignments).batch_assign(assignments)`: assign multiple values for a\n        parameter sweep\n        - `...assign(assignments).parallelize(cluster_spacing)`: parallelize the program\n        register\n        - `...assign(assignments).args([previously_defined_vars])`: defer value assignment to\n        runtime\n    \"\"\"\n    from bloqade.analog.builder.assign import Assign\n\n    return Assign(assignments, parent=self)\n
"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.BatchAssignable","title":"BatchAssignable","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.BatchAssignable.batch_assign","title":"batch_assign","text":"
batch_assign(__batch_params=[], **assignments)\n

Assign multiple values to variables for creating a parameter sweep.

Parameters:

Name Type Description Default __batch_params List[Dict[str, ParamType]]

List of dictionaries where each dictionary contains variable assignments for one set of parameters.

[] **assignments List[ParamType]

Key-value pairs where the key is the variable name and the value is a list of values to assign.

{}

Returns:

Type Description Union[BatchAssign, ListAssign]

Union[BatchAssign, ListAssign]: A new instance of BatchAssign or ListAssign class with the specified assignments.

Raises:

Type Description ValueError

If both __batch_params and assignments are provided.

Note

Bloqade handles the multiple programs generated by this method and treats them as a unified object for easy post-processing. Ensure all lists of values are of the same length as Bloqade will not perform a Cartesian product.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.BatchAssignable.batch_assign--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (0, \"atom_distance\")])\n>>> prog = reg.rydberg.rabi.amplitude.uniform.constant(\"value\", 5.0)\n>>> var_assigned_prog = prog.batch_assign(value=[1.0, 2.0, 3.0],\natom_distance=[1.0, 2.0, 3.0])\n
  • Next steps:
    • ...batch_assign(assignments).bloqade: select the bloqade local emulator backend
    • ...batch_assign(assignments).braket: select braket local emulator or QuEra hardware
    • ...batch_assign(assignments).device(specifier_string): select backend by specifying a string
    • ...batch_assign(assignments).parallelize(cluster_spacing): parallelize the program register
    • ...batch_assign(assignments).args([previously_defined_vars]): defer value assignment to runtime
Source code in src/bloqade/analog/builder/pragmas.py
def batch_assign(\n    self,\n    __batch_params: List[Dict[str, ParamType]] = [],\n    **assignments: List[ParamType],\n) -> Union[\"BatchAssign\", \"ListAssign\"]:\n    \"\"\"\n    Assign multiple values to variables for creating a parameter sweep.\n\n    Args:\n        __batch_params (List[Dict[str, ParamType]], optional): List of dictionaries\n            where each dictionary contains variable assignments for one set of parameters.\n        **assignments (List[ParamType]): Key-value pairs where the key is the variable\n            name and the value is a list of values to assign.\n\n    Returns:\n        Union[BatchAssign, ListAssign]: A new instance of BatchAssign or ListAssign\n            class with the specified assignments.\n\n    Raises:\n        ValueError: If both __batch_params and assignments are provided.\n\n    Note:\n        Bloqade handles the multiple programs generated by this method and treats them\n        as a unified object for easy post-processing. Ensure all lists of values are of\n        the same length as Bloqade will not perform a Cartesian product.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (0, \"atom_distance\")])\n    >>> prog = reg.rydberg.rabi.amplitude.uniform.constant(\"value\", 5.0)\n    >>> var_assigned_prog = prog.batch_assign(value=[1.0, 2.0, 3.0],\n    atom_distance=[1.0, 2.0, 3.0])\n    ```\n\n    - Next steps:\n        - `...batch_assign(assignments).bloqade`: select the bloqade local emulator backend\n        - `...batch_assign(assignments).braket`: select braket local emulator or QuEra hardware\n        - `...batch_assign(assignments).device(specifier_string)`: select backend by specifying\n        a string\n        - `...batch_assign(assignments).parallelize(cluster_spacing)`: parallelize the program\n        register\n        - `...batch_assign(assignments).args([previously_defined_vars])`: defer value assignment\n        to runtime\n    \"\"\"\n    from bloqade.analog.builder.assign import ListAssign, BatchAssign\n\n    if len(__batch_params) > 0 and assignments:\n        raise ValueError(\"batch_params and assignments cannot be used together.\")\n\n    if len(__batch_params) > 0:\n        return ListAssign(__batch_params, parent=self)\n    else:\n        return BatchAssign(assignments, parent=self)\n
"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Parallelizable","title":"Parallelizable","text":""},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Parallelizable.parallelize","title":"parallelize","text":"
parallelize(cluster_spacing)\n

Parallelize the current problem by duplicating the geometry to utilize all available space/qubits on hardware.

Parameters:

Name Type Description Default cluster_spacing LiteralType

Specifies the spacing between clusters in micrometers.

required

Returns:

Name Type Description Parallelize Parallelize

A new instance of the Parallelize class with the specified cluster spacing.

Raises:

Type Description ValueError

If the cluster_spacing is not a valid value.

Note

After calling this method, you can choose a backend for emulation or execution. Options include bloqade for a local emulator, braket for a local emulator or QuEra hardware on the cloud, or specifying a device with a string.

"},{"location":"reference/bloqade/analog/builder/pragmas/#bloqade.analog.builder.pragmas.Parallelizable.parallelize--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position((0,0)).rydberg.rabi.uniform.amplitude.constant(1.0, 1.0)\n# copy-paste the geometry and waveforms\n>>> parallelized_prog = reg.parallelize(24)\n
  • Next steps:
    • ...parallelize(cluster_spacing).bloqade: select the bloqade local emulator backend
    • ...parallelize(cluster_spacing).braket: select braket local emulator or QuEra hardware on the cloud
    • ...parallelize(cluster_spacing).device(specifier_string): select backend by specifying a string
Source code in src/bloqade/analog/builder/pragmas.py
def parallelize(self, cluster_spacing: LiteralType) -> \"Parallelize\":\n    \"\"\"\n    Parallelize the current problem by duplicating the geometry to utilize\n    all available space/qubits on hardware.\n\n    Args:\n        cluster_spacing (LiteralType): Specifies the spacing between clusters\n            in micrometers.\n\n    Returns:\n        Parallelize: A new instance of the Parallelize class with the specified\n            cluster spacing.\n\n    Raises:\n        ValueError: If the cluster_spacing is not a valid value.\n\n    Note:\n        After calling this method, you can choose a backend for emulation or\n        execution. Options include `bloqade` for a local emulator, `braket` for\n        a local emulator or QuEra hardware on the cloud, or specifying a device\n        with a string.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position((0,0)).rydberg.rabi.uniform.amplitude.constant(1.0, 1.0)\n    # copy-paste the geometry and waveforms\n    >>> parallelized_prog = reg.parallelize(24)\n    ```\n\n    - Next steps:\n        - `...parallelize(cluster_spacing).bloqade`: select the bloqade local emulator backend\n        - `...parallelize(cluster_spacing).braket`: select braket local emulator or QuEra\n        hardware on the cloud\n        - `...parallelize(cluster_spacing).device(specifier_string)`: select backend by\n        specifying a string\n    \"\"\"\n    from bloqade.analog.builder.parallelize import Parallelize\n\n    return Parallelize(cluster_spacing, self)\n
"},{"location":"reference/bloqade/analog/builder/route/","title":"Route","text":""},{"location":"reference/bloqade/analog/builder/sequence_builder/","title":"Sequence builder","text":""},{"location":"reference/bloqade/analog/builder/spatial/","title":"Spatial","text":""},{"location":"reference/bloqade/analog/builder/spatial/#bloqade.analog.builder.spatial.Uniform","title":"Uniform","text":"
Uniform(parent=None)\n

Bases: SpatialModulation

The node specify a uniform spacial modulation. Which is ready to apply waveform (See Waveform for available waveform options)

Examples:

- To hit this node from the start node:\n\n>>> reg = bloqade.start.add_position([(0,0),(1,1),(2,2),(3,3)])\n>>> loc = reg.rydberg.detuning.uniform\n\n- Apply Linear waveform:\n\n>>> wv = bloqade.ir.Linear(start=0,stop=1,duration=0.5)\n>>> reg = bloqade.start.add_position([(0,0),(1,1),(2,2),(3,3)])\n>>> loc = reg.rydberg.detuning.uniform.apply(wv)\n
Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/start/","title":"Start","text":""},{"location":"reference/bloqade/analog/builder/start/#bloqade.analog.builder.start.ProgramStart","title":"ProgramStart","text":"
ProgramStart(parent=None)\n

Bases: Drive, Builder

ProgramStart is the base class for a starting/entry node for building a program.

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/start/#bloqade.analog.builder.start.ProgramStart.apply","title":"apply","text":"
apply(sequence)\n

Apply a pre-built sequence to a program.

This allows you to build a program independent of any geometry and then apply the program to said geometry. Or, if you have a program you would like to try on multiple geometries you can trivially do so with this.

Example Usage:

>>> from numpy import pi\n>>> seq = start.rydberg.rabi.amplitude.constant(2.0 * pi, 4.5)\n# choose a geometry of interest to apply the program on\n>>> from bloqade.analog.atom_arrangement import Chain, Kagome\n>>> complete_program = Chain(10).apply(seq)\n# you can .apply to as many geometries as you like\n>>> another_complete_program = Kagome(3).apply(seq)\n

  • From here you can now do:
    • ...assign(assignments).bloqade: select the bloqade local emulator backend
    • ...assign(assignments).braket: select braket local emulator or QuEra hardware
    • ...assign(assignments).device(specifier_string): select backend by specifying a string
  • Assign multiple values to a single variable for a parameter sweep:
    • ...assign(assignments).batch_assign(assignments):
  • Parallelize the program register, duplicating the geometry and waveform sequence to take advantage of all available space/qubits on the QPU:
    • ...assign(assignments).parallelize(cluster_spacing)
  • Defer value assignment of certain variables to runtime:
    • ...assign(assignments).args([previously_defined_vars])
Source code in src/bloqade/analog/builder/start.py
@beartype\ndef apply(self, sequence: SequenceExpr) -> SequenceBuilder:\n    \"\"\"\n    Apply a pre-built sequence to a program.\n\n    This allows you to build a program independent of any geometry\n    and then `apply` the program to said geometry. Or, if you have a\n    program you would like to try on multiple geometries you can\n    trivially do so with this.\n\n    Example Usage:\n    ```\n    >>> from numpy import pi\n    >>> seq = start.rydberg.rabi.amplitude.constant(2.0 * pi, 4.5)\n    # choose a geometry of interest to apply the program on\n    >>> from bloqade.analog.atom_arrangement import Chain, Kagome\n    >>> complete_program = Chain(10).apply(seq)\n    # you can .apply to as many geometries as you like\n    >>> another_complete_program = Kagome(3).apply(seq)\n    ```\n\n    - From here you can now do:\n        - `...assign(assignments).bloqade`: select the bloqade\n            local emulator backend\n        - `...assign(assignments).braket`: select braket\n            local emulator or QuEra hardware\n        - `...assign(assignments).device(specifier_string)`: select\n            backend by specifying a string\n    - Assign multiple values to a single variable for a parameter sweep:\n        - `...assign(assignments).batch_assign(assignments)`:\n    - Parallelize the program register, duplicating the geometry and waveform\n        sequence to take advantage of all available\n      space/qubits on the QPU:\n        - `...assign(assignments).parallelize(cluster_spacing)`\n    - Defer value assignment of certain variables to runtime:\n        - `...assign(assignments).args([previously_defined_vars])`\n\n    \"\"\"\n    return SequenceBuilder(sequence, self)\n
"},{"location":"reference/bloqade/analog/builder/typing/","title":"Typing","text":""},{"location":"reference/bloqade/analog/builder/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Recordable","title":"Recordable","text":""},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Recordable.record","title":"record","text":"
record(name)\n

Copy or \"record\" the value at the end of the waveform into a variable so that it can be used in another place.

A common design pattern is to couple this with .slice() considering you may not know exactly what the end value of a .slice() is, especially in parameter sweeps where it becomes cumbersome to handle.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Recordable.record--usage-example","title":"Usage Example:","text":"
# define program of interest\n>>> from bloqade import start\n>>> prog = start.rydberg.rabi.amplitude.uniform\n>>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n# We now slice the piecewise_linear from above and record the\n# value at the end of that slice. We then use that value\n# to construct a new waveform that can be appended to the previous\n# one without introducing discontinuity (refer to the\n# \"Quantum Scar Dynamics\" tutorial for how this could be handy)\n>>> prog_with_record = prog_with_wf.slice(0.0, 1.0).record(\"end_of_wf\")\n>>> record_applied_prog = prog_with_record.linear(start=\"end_of_wf\"\n, stop=0.0, duration=0.3)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...slice(start, stop).linear(start, stop, duration): to append another linear waveform
    • ...slice(start, stop).constant(value, duration): to append a constant waveform
    • ...slice(start, stop).piecewise_linear(): to append a piecewise linear waveform
    • ...slice(start, stop).piecewise_constant(): to append a piecewise constant waveform
    • ...slice(start, stop).poly([coefficients], duration): to append a polynomial waveform
    • ...slice(start, stop).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...slilce(start, stop).fn(f(t,...)): to append a waveform defined by a python function
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...slice(start, stop).uniform: To address all atoms in the field
    • ...slice(start, stop).location(int): To address an atom at a specific location via index
    • ...slice(start, stop).scale(str)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...slice(start, stop).assign(variable_name = value): to assign a single value to a variable
    • ...slice(start, stop) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...slice(start, stop).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...slice(start, stop).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...slice(start, stop).bloqade: to run on the Bloqade local emulator
    • ...slice(start, stop).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...slice(start, stop).parallelize(spacing)
  • Start targeting another level coupling
    • ...slice(start, stop).rydberg: to target the Rydberg level coupling
    • ...slice(start, stop).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...slice(start, stop).amplitude: to target the real-valued Rabi Amplitude field
    • ...slice(start, stop).phase: to target the real-valued Rabi Phase field
    • ...slice(start, stop).detuning: to target the Detuning field
    • ...slice(start, stop).rabi: to target the complex-valued Rabi field ```
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef record(self, name: str) -> \"Record\":\n    \"\"\"\n    Copy or \"record\" the value at the end of the waveform into a variable\n    so that it can be used in another place.\n\n    A common design pattern is to couple this with `.slice()` considering\n    you may not know exactly what the end value of a `.slice()` is,\n    especially in parameter sweeps where it becomes cumbersome to handle.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    # define program of interest\n    >>> from bloqade import start\n    >>> prog = start.rydberg.rabi.amplitude.uniform\n    >>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    # We now slice the piecewise_linear from above and record the\n    # value at the end of that slice. We then use that value\n    # to construct a new waveform that can be appended to the previous\n    # one without introducing discontinuity (refer to the\n    # \"Quantum Scar Dynamics\" tutorial for how this could be handy)\n    >>> prog_with_record = prog_with_wf.slice(0.0, 1.0).record(\"end_of_wf\")\n    >>> record_applied_prog = prog_with_record.linear(start=\"end_of_wf\"\n    , stop=0.0, duration=0.3)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...slice(start, stop).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...slice(start, stop).constant(value, duration)`:\n            to append a constant waveform\n        - `...slice(start, stop).piecewise_linear()`:\n            to append a piecewise linear waveform\n        - `...slice(start, stop).piecewise_constant()`:\n            to append a piecewise constant waveform\n        - `...slice(start, stop).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...slice(start, stop).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...slilce(start, stop).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...slice(start, stop).uniform`:\n            To address all atoms in the field\n        - `...slice(start, stop).location(int)`:\n            To address an atom at a specific location via index\n        - `...slice(start, stop).scale(str)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...slice(start, stop).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...slice(start, stop)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...slice(start, stop).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...slice(start, stop).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...slice(start, stop).bloqade`:\n            to run on the Bloqade local emulator\n        - `...slice(start, stop).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...slice(start, stop).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...slice(start, stop).rydberg`:\n            to target the Rydberg level coupling\n        - `...slice(start, stop).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...slice(start, stop).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...slice(start, stop).phase`:\n            to target the real-valued Rabi Phase field\n        - `...slice(start, stop).detuning`:\n            to target the Detuning field\n        - `...slice(start, stop).rabi`:\n            to target the complex-valued Rabi field\n    ```\n    \"\"\"\n    return Record(name, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Sliceable","title":"Sliceable","text":""},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Sliceable.slice","title":"slice","text":"
slice(start=None, stop=None)\n

Indicate that you only want a portion of your waveform to be used in the program.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.Sliceable.slice--usage-example","title":"Usage Example:","text":"
# define a program with a waveform of interest\n>>> from bloqade import start\n>>> prog = start.add_position((0,0)).rydberg.rabi.amplitude.uniform\n>>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n# instead of using the full waveform we opt to only take the first 1 us\n>>> prog_with_slice = prog_with_wf.slice(0.0, 1.0)\n# you may use variables as well\n>>> prog_with_slice = prog_with_wf.slice(\"start\", \"end\")\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...slice(start, stop).linear(start, stop, duration): to append another linear waveform
    • ...slice(start, stop).constant(value, duration): to append a constant waveform
    • ...slice(start, stop).piecewise_linear(): to append a piecewise linear waveform
    • ...slice(start, stop).piecewise_constant(): to append a piecewise constant waveform
    • ...slice(start, stop).poly([coefficients], duration): to append a polynomial waveform
    • ...slice(start, stop).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...slilce(start, stop).fn(f(t,...)): to append a waveform defined by a python function
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...slice(start, stop).uniform: To address all atoms in the field
    • ...slice(start, stop).location(int): To address an atom at a specific location via index
    • ...slice(start, stop).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...slice(start, stop).assign(variable_name = value): to assign a single value to a variable
    • ...slice(start, stop) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...slice(start, stop).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...slice(start, stop).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...slice(start, stop).bloqade: to run on the Bloqade local emulator
    • ...slice(start, stop).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...slice(start, stop).parallelize(spacing)
  • Start targeting another level coupling
    • ...slice(start, stop).rydberg: to target the Rydberg level coupling
    • ...slice(start, stop).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...slice(start, stop).amplitude: to target the real-valued Rabi Amplitude field
    • ...slice(start, stop).phase: to target the real-valued Rabi Phase field
    • ...slice(start, stop).detuning: to target the Detuning field
    • ...slice(start, stop).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef slice(\n    self,\n    start: Optional[ScalarType] = None,\n    stop: Optional[ScalarType] = None,\n) -> \"Slice\":\n    \"\"\"\n    Indicate that you only want a portion of your waveform to be used in\n    the program.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n\n    ### Usage Example:\n    ```\n    # define a program with a waveform of interest\n    >>> from bloqade import start\n    >>> prog = start.add_position((0,0)).rydberg.rabi.amplitude.uniform\n    >>> prog_with_wf = prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    # instead of using the full waveform we opt to only take the first 1 us\n    >>> prog_with_slice = prog_with_wf.slice(0.0, 1.0)\n    # you may use variables as well\n    >>> prog_with_slice = prog_with_wf.slice(\"start\", \"end\")\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...slice(start, stop).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...slice(start, stop).constant(value, duration)`:\n            to append a constant waveform\n        - `...slice(start, stop).piecewise_linear()`:\n            to append a piecewise linear waveform\n        - `...slice(start, stop).piecewise_constant()`:\n            to append a piecewise constant waveform\n        - `...slice(start, stop).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...slice(start, stop).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...slilce(start, stop).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...slice(start, stop).uniform`:\n            To address all atoms in the field\n        - `...slice(start, stop).location(int)`:\n            To address an atom at a specific location via index\n        - `...slice(start, stop).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...slice(start, stop).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...slice(start, stop)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...slice(start, stop).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...slice(start, stop).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...slice(start, stop).bloqade`:\n            to run on the Bloqade local emulator\n        - `...slice(start, stop).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...slice(start, stop).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...slice(start, stop).rydberg`:\n            to target the Rydberg level coupling\n        - `...slice(start, stop).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...slice(start, stop).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...slice(start, stop).phase`:\n            to target the real-valued Rabi Phase field\n        - `...slice(start, stop).detuning`:\n            to target the Detuning field\n        - `...slice(start, stop).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return Slice(start, stop, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable","title":"WaveformAttachable","text":"
WaveformAttachable(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.apply","title":"apply","text":"
apply(wf)\n

Apply a Waveform built previously to current location(s).

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.apply--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# build our waveform independently of the main program\n>>> from bloqade import piecewise_linear\n>>> wf = piecewise_linear(durations=[0.3, 2.5, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n>>> prog.apply(wf)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...apply(waveform).linear(start, stop, duration): to append another linear waveform
    • ...apply(waveform).constant(value, duration): to append a constant waveform
    • ...apply(waveform).piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...apply(waveform).piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...apply(waveform).poly([coefficients], duration): to append a polynomial waveform
    • ...apply(waveform).apply(waveform): to append a pre-defined waveform
    • ...apply(waveform).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...apply(waveform).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...apply(waveform).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...apply(waveform).uniform: To address all atoms in the field
    • ...apply(waveform).location(int): To address an atom at a specific location via index
    • ...apply(waveform).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...apply(waveform).assign(variable_name = value): to assign a single value to a variable
    • ...apply(waveform).batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...apply(waveform).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...apply(waveform).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...apply(waveform).bloqade: to run on the Bloqade local emulator
    • ...apply(waveform).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...apply(waveform).parallelize(spacing)
  • Start targeting another level coupling
    • ...apply(waveform).rydberg: to target the Rydberg level coupling
    • ...apply(waveform).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...apply(waveform).amplitude: to target the real-valued Rabi Amplitude field
    • ...apply(waveform).phase: to target the real-valued Rabi Phase field
    • ...apply(waveform).detuning: to target the Detuning field
    • ...apply(waveform).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef apply(self, wf: ir.Waveform) -> \"Apply\":\n    \"\"\"\n    Apply a [`Waveform`][bloqade.ir.control.Waveform] built previously to\n    current location(s).\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # build our waveform independently of the main program\n    >>> from bloqade import piecewise_linear\n    >>> wf = piecewise_linear(durations=[0.3, 2.5, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    >>> prog.apply(wf)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...apply(waveform).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...apply(waveform).constant(value, duration)`:\n            to append a constant waveform\n        - `...apply(waveform).piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...apply(waveform).piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...apply(waveform).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...apply(waveform).apply(waveform)`:\n            to append a pre-defined waveform\n        - `...apply(waveform).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...apply(waveform).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...apply(waveform).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...apply(waveform).uniform`: To address all atoms in the field\n        - `...apply(waveform).location(int)`:\n            To address an atom at a specific location via index\n        - `...apply(waveform).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying a\n                single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...apply(waveform).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...apply(waveform).batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...apply(waveform).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...apply(waveform).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...apply(waveform).bloqade`:\n            to run on the Bloqade local emulator\n        - `...apply(waveform).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...apply(waveform).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...apply(waveform).rydberg`: to target the Rydberg level coupling\n        - `...apply(waveform).hyperfine`: to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...apply(waveform).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...apply(waveform).phase`:\n            to target the real-valued Rabi Phase field\n        - `...apply(waveform).detuning`:\n            to target the Detuning field\n        - `...apply(waveform).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return Apply(wf, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.constant","title":"constant","text":"
constant(value, duration)\n

Append or assign a constant waveform to the current location(s).

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.constant--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# apply a constant waveform of 1.9 radians/us for 0.5 us\n>>> prog.constant(value=1.9,duration=0.5)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...constant(value, duration).linear(start, stop, duration): to append another linear waveform
    • ...constant(value, duration).constant(value, duration): to append a constant waveform
    • ...constant(value, duration) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...constant(value, duration) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...constant(value, duration).poly([coefficients], duration): to append a polynomial waveform
    • ...constant(value, duration).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...constant(value, duration).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...constant(value, duration).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...constant(value, duration).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...constant(value, duration).uniform: To address all atoms in the field
    • ...constant(value, duration).scale(...): To address an atom at a specific location via index
    • ...constant(value, duration).location(int)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...constant(value, duration).assign(variable_name = value): to assign a single value to a variable
    • ...constant(value, duration) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...constant(value, duration).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...constant(value, duration).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...constant(value, duration).bloqade: to run on the Bloqade local emulator
    • ...constant(value, duration).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...constant(start, stop, duration).parallelize(spacing)
  • Start targeting another level coupling
    • ...constant(value, duration).rydberg: to target the Rydberg level coupling
    • ...constant(value, duration).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...constant(value, duration).amplitude: to target the real-valued Rabi Amplitude field
    • ...constant(value, duration).phase: to target the real-valued Rabi Phase field
    • ...constant(value, duration).detuning: to target the Detuning field
    • ...constant(value, duration).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef constant(self, value: ScalarType, duration: ScalarType) -> \"Constant\":\n    \"\"\"\n    Append or assign a constant waveform to the current location(s).\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # apply a constant waveform of 1.9 radians/us for 0.5 us\n    >>> prog.constant(value=1.9,duration=0.5)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...constant(value, duration).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...constant(value, duration).constant(value, duration)`:\n            to append a constant waveform\n        - `...constant(value, duration)\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...constant(value, duration)\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...constant(value, duration).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...constant(value, duration).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...constant(value, duration).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...constant(value, duration).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...constant(value, duration).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...constant(value, duration).uniform`:\n            To address all atoms in the field\n        - `...constant(value, duration).scale(...)`:\n            To address an atom at a specific location via index\n        - `...constant(value, duration).location(int)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...constant(value, duration).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...constant(value, duration)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...constant(value, duration).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...constant(value, duration).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...constant(value, duration).bloqade`:\n            to run on the Bloqade local emulator\n        - `...constant(value, duration).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...constant(start, stop, duration).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...constant(value, duration).rydberg`:\n            to target the Rydberg level coupling\n        - `...constant(value, duration).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current\n      level coupling (previously selected as `rydberg` or `hyperfine`):\n        - `...constant(value, duration).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...constant(value, duration).phase`:\n            to target the real-valued Rabi Phase field\n        - `...constant(value, duration).detuning`:\n            to target the Detuning field\n        - `...constant(value, duration).rabi`:\n            to target the complex-valued Rabi field\n\n    \"\"\"\n    return Constant(value, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.fn","title":"fn","text":"
fn(fn, duration)\n

Append or assign a custom function as a waveform.

The function must have its first argument be that of time but can also have other arguments which are treated as variables. You can assign values to later in the program via .assign or .batch_assign.

The function must also return a singular float value.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.fn--usage-examples","title":"### Usage Examples:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# define our custom waveform. It must have one argument\n# be time followed by any other number of arguments that can\n# be assigned a value later in the program via `.assign` or `.batch_assign`\n>>> def custom_waveform_function(t, arg1, arg2):\n        return arg1*t + arg2\n>>> prog = prog.fn(custom_waveform_function, duration = 0.5)\n# assign values\n>>> assigned_vars_prog = prog.assign(arg1 = 1.0, arg2 = 2.0)\n# or go for batching!\n>>> assigned_vars_batch_prog = prog.assign(arg1 = 1.0, arg2 = [1.0, 2.0, 3.0])\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...fn(f(t,...)) .linear(start, stop, duration): to append another linear waveform
    • ...fn(f(t,...)) .constant(value, duration): to append a constant waveform
    • ...fn(f(t,...)) .piecewise_linear(durations, values): to append a piecewise linear waveform
    • ...fn(f(t,...)) .piecewise_constant(durations, values): to append a piecewise constant waveform
    • ...fn(f(t,...)) .poly([coefficients], duration): to append a polynomial waveform
    • ...fn(f(t,...)) .apply(waveform): to append a pre-defined waveform
    • ...fn(f(t,...)) .fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...fn(f(t,...)).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...fn(f(t,...)).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...fn(f(t,...)).uniform: To address all atoms in the field
    • ...fn(f(t,...)).scale(...): To address an atom at a specific location via index
    • ...fn(f(t,...)).location(int)`
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...fn(f(t,...)) .assign(variable_name = value): to assign a single value to a variable
    • ...fn(f(t,...)) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...fn(f(t,...)) .args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...fn(f(t,...)).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...fn(f(t,...)).bloqade: to run on the Bloqade local emulator
    • ...fn(f(t,...)).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...fn(f(t,...)).parallelize(spacing)
  • Start targeting another level coupling
    • ...fn(f(t,...)).rydberg: to target the Rydberg level coupling
    • ...fn(f(t,...)).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...fn(f(t,...)).amplitude: to target the real-valued Rabi Amplitude field
    • ...fn(f(t,...)).phase: to target the real-valued Rabi Phase field
    • ...fn(f(t,...)).detuning: to target the Detuning field
    • ...fn(f(t,...)).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef fn(self, fn: Callable, duration: ScalarType) -> \"Fn\":\n    \"\"\"\n    Append or assign a custom function as a waveform.\n\n    The function must have its first argument be that of time but\n    can also have other arguments which are treated as variables.\n    You can assign values to later in the program via `.assign` or `.batch_assign`.\n\n    The function must also return a singular float value.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### ### Usage Examples:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # define our custom waveform. It must have one argument\n    # be time followed by any other number of arguments that can\n    # be assigned a value later in the program via `.assign` or `.batch_assign`\n    >>> def custom_waveform_function(t, arg1, arg2):\n            return arg1*t + arg2\n    >>> prog = prog.fn(custom_waveform_function, duration = 0.5)\n    # assign values\n    >>> assigned_vars_prog = prog.assign(arg1 = 1.0, arg2 = 2.0)\n    # or go for batching!\n    >>> assigned_vars_batch_prog = prog.assign(arg1 = 1.0, arg2 = [1.0, 2.0, 3.0])\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...fn(f(t,...))\n            .linear(start, stop, duration)`: to append another linear waveform\n        - `...fn(f(t,...))\n            .constant(value, duration)`: to append a constant waveform\n        - `...fn(f(t,...))\n            .piecewise_linear(durations, values)`:\n            to append a piecewise linear waveform\n        - `...fn(f(t,...))\n            .piecewise_constant(durations, values)`:\n            to append a piecewise constant waveform\n        - `...fn(f(t,...))\n            .poly([coefficients], duration)`: to append a polynomial waveform\n        - `...fn(f(t,...))\n            .apply(waveform)`: to append a pre-defined waveform\n        - `...fn(f(t,...))\n            .fn(f(t,...))`: to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...fn(f(t,...)).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...fn(f(t,...)).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...fn(f(t,...)).uniform`:\n            To address all atoms in the field\n        - `...fn(f(t,...)).scale(...)`:\n            To address an atom at a specific location via index\n        - ...fn(f(t,...)).location(int)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning it a\n                list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...fn(f(t,...))\n            .assign(variable_name = value)`: to assign a single value to a variable\n        - `...fn(f(t,...))\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...fn(f(t,...))\n            .args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...fn(f(t,...)).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...fn(f(t,...)).bloqade`:\n            to run on the Bloqade local emulator\n        - `...fn(f(t,...)).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...fn(f(t,...)).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...fn(f(t,...)).rydberg`:\n            to target the Rydberg level coupling\n        - `...fn(f(t,...)).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...fn(f(t,...)).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...fn(f(t,...)).phase`:\n            to target the real-valued Rabi Phase field\n        - `...fn(f(t,...)).detuning`:\n            to target the Detuning field\n        - `...fn(f(t,...)).rabi`:\n            to target the complex-valued Rabi field\n\n    \"\"\"\n    return Fn(fn, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.linear","title":"linear","text":"
linear(start, stop, duration)\n

Append or assign a linear waveform to the current location(s).

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.linear--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# apply a linear waveform that goes from 0 to 1 radians/us in 0.5 us\n>>> prog.linear(start=0,stop=1,duration=0.5)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...linear(start, stop, duration).linear(start, stop, duration): to append another linear waveform
    • ...linear(start, stop, duration).constant(value, duration): to append a constant waveform
    • ...linear(start, stop, duration) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...linear(start, stop, duration) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...linear(start, stop, duration).poly([coefficients], duration): to append a polynomial waveform
    • ...linear(start, stop, duration).apply(wf:bloqade.ir.Waveform): to append a pre-defined waveform
    • ...linear(start, stop, duration).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...linear(start, stop, duration).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...linear(start, stop, duration).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...linear(start, stop, duration).uniform: To address all atoms in the field
    • ...linear(start, stop, duration).location(int): To address atoms at specific location with scaling
    • ...linear(start, stop, duration).scale(...)
      • To address atoms at specific location with scaling
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...linear(start, stop, duration).assign(variable_name = value): to assign a single value to a variable
    • ...linear(start, stop, duration) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...linear(start, stop, duration).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...linear(start, stop, duration).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...linear(start, stop, duration).bloqade: to run on the Bloqade local emulator
    • ...linear(start, stop, duration).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...linear(start, stop, duration).parallelize(spacing)
  • Start targeting another level coupling
    • ...linear(start, stop, duration).rydberg: to target the Rydberg level coupling
    • ...linear(start, stop, duration).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...linear(start, stop, duration).amplitude: to target the real-valued Rabi Amplitude field
    • ...linear(start, stop, duration).phase: to target the real-valued Rabi Phase field
    • ...linear(start, stop, duration).detuning: to target the Detuning field
    • ...linear(start, stop, duration).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef linear(\n    self, start: ScalarType, stop: ScalarType, duration: ScalarType\n) -> \"Linear\":\n    \"\"\"\n\n    Append or assign a linear waveform to the current location(s).\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # apply a linear waveform that goes from 0 to 1 radians/us in 0.5 us\n    >>> prog.linear(start=0,stop=1,duration=0.5)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...linear(start, stop, duration).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...linear(start, stop, duration).constant(value, duration)`:\n            to append a constant waveform\n        - `...linear(start, stop, duration)\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...linear(start, stop, duration)\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...linear(start, stop, duration).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...linear(start, stop, duration).apply(wf:bloqade.ir.Waveform)`:\n            to append a pre-defined waveform\n        - `...linear(start, stop, duration).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...linear(start, stop, duration).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...linear(start, stop, duration).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n        (this drive will be summed to the one you just created):\n        - `...linear(start, stop, duration).uniform`:\n            To address all atoms in the field\n        - `...linear(start, stop, duration).location(int)`:\n            To address atoms at specific location with scaling\n        - `...linear(start, stop, duration).scale(...)`\n            - To address atoms at specific location with scaling\n            - To address multiple atoms at specific locations by specifying\n                a single variable and then assigning it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...linear(start, stop, duration).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...linear(start, stop, duration)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...linear(start, stop, duration).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...linear(start, stop, duration).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...linear(start, stop, duration).bloqade`:\n            to run on the Bloqade local emulator\n        - `...linear(start, stop, duration).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...linear(start, stop, duration).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...linear(start, stop, duration).rydberg`:\n            to target the Rydberg level coupling\n        - `...linear(start, stop, duration).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...linear(start, stop, duration).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...linear(start, stop, duration).phase`:\n            to target the real-valued Rabi Phase field\n        - `...linear(start, stop, duration).detuning`:\n            to target the Detuning field\n        - `...linear(start, stop, duration).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n\n    return Linear(start, stop, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_constant","title":"piecewise_constant","text":"
piecewise_constant(durations, values)\n

Append or assign a piecewise constant waveform to current location(s).

The durations argument should have number of elements = len(values). durations should be the duration PER section of the waveform, NON-CUMULATIVE.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_constant--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.rabi.phase.uniform\n# create a staircase, we hold 0.0 rad/us for 1.0 us, then\n# to 1.0 rad/us for 0.5 us before stopping at 0.8 rad/us for 0.9 us.\n>>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3], values=[1.0, 0.5, 0.9])\n
  • Your next steps including:
  • Continue building your waveform via:
    • ...piecewise_constant([durations], [values]) .linear(start, stop, duration): to append another linear waveform
    • ...piecewise_constant([durations], [values]) .constant(value, duration): to append a constant waveform
    • ...piecewise_constant([durations], [values]) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...piecewise_constant([durations], [values]) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...piecewise_constant([durations], [values]) .poly([coefficients], duration): to append a polynomial waveform
    • ...piecewise_constant([durations], [values]) .apply(waveform): to append a pre-defined waveform
    • ...piecewise_constant([durations], [values]).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...piecewise_constant([durations], [values]) .slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...piecewise_constant([durations], [values]) .record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...piecewise_constant([durations], [values]).uniform: To address all atoms in the field
    • ...piecewise_constant([durations], [values]).location(int): To address an atom at a specific location via index
    • ...piecewise_constant([durations], [values]).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...piecewise_constant([durations], [values]) .assign(variable_name = value): to assign a single value to a variable
    • ...piecewise_constant([durations], [values]) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...piecewise_constant([durations], [values]) .args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...piecewise_constant([durations], [values]).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...piecewise_constant([durations], [values]).bloqade: to run on the Bloqade local emulator
    • ...piecewise_constant([durations], [values]).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...piecewise_constat([durations], [values]).parallelize(spacing)
  • Start targeting another level coupling
    • ...piecewise_constant([durations], [values]).rydberg: to target the Rydberg level coupling
    • ...piecewise_constant([durations], [values]).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...piecewise_constant(durations, values).amplitude: to target the real-valued Rabi Amplitude field
    • ...piecewise_constant([durations], [values]).phase: to target the real-valued Rabi Phase field
    • ...piecewise_constant([durations], [values]).detuning: to target the Detuning field
    • ...piecewise_constant([durations], [values]).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef piecewise_constant(\n    self, durations: List[ScalarType], values: List[ScalarType]\n) -> \"PiecewiseConstant\":\n    \"\"\"\n    Append or assign a piecewise constant waveform to current location(s).\n\n    The `durations` argument should have number of elements = len(values).\n    `durations` should be the duration PER section of the waveform,\n    NON-CUMULATIVE.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.rabi.phase.uniform\n    # create a staircase, we hold 0.0 rad/us for 1.0 us, then\n    # to 1.0 rad/us for 0.5 us before stopping at 0.8 rad/us for 0.9 us.\n    >>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3], values=[1.0, 0.5, 0.9])\n    ```\n\n    - Your next steps including:\n    - Continue building your waveform via:\n        - `...piecewise_constant([durations], [values])\n            .linear(start, stop, duration)`: to append another linear waveform\n        - `...piecewise_constant([durations], [values])\n            .constant(value, duration)`: to append a constant waveform\n        - `...piecewise_constant([durations], [values])\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...piecewise_constant([durations], [values])\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...piecewise_constant([durations], [values])\n            .poly([coefficients], duration)`: to append a polynomial waveform\n        - `...piecewise_constant([durations], [values])\n            .apply(waveform)`: to append a pre-defined waveform\n        - `...piecewise_constant([durations], [values]).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...piecewise_constant([durations], [values])\n            .slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...piecewise_constant([durations], [values])\n            .record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...piecewise_constant([durations], [values]).uniform`:\n            To address all atoms in the field\n        - `...piecewise_constant([durations], [values]).location(int)`:\n            To address an atom at a specific location via index\n        - `...piecewise_constant([durations], [values]).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning it a\n                list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...piecewise_constant([durations], [values])\n            .assign(variable_name = value)`: to assign a single value to a variable\n        - `...piecewise_constant([durations], [values])\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...piecewise_constant([durations], [values])\n            .args([\"previously_defined_var\"])`: to defer assignment\n            of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...piecewise_constant([durations], [values]).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...piecewise_constant([durations], [values]).bloqade`:\n            to run on the Bloqade local emulator\n        - `...piecewise_constant([durations], [values]).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...piecewise_constat([durations], [values]).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...piecewise_constant([durations], [values]).rydberg`:\n            to target the Rydberg level coupling\n        - `...piecewise_constant([durations], [values]).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...piecewise_constant(durations, values).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...piecewise_constant([durations], [values]).phase`:\n            to target the real-valued Rabi Phase field\n        - `...piecewise_constant([durations], [values]).detuning`:\n            to target the Detuning field\n        - `...piecewise_constant([durations], [values]).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return PiecewiseConstant(durations, values, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_linear","title":"piecewise_linear","text":"
piecewise_linear(durations, values)\n

Append or assign a piecewise linear waveform to current location(s), where the waveform is formed by connecting values[i], values[i+1] with linear segments.

The durations argument should have # of elements = len(values) - 1. durations should be the duration PER section of the waveform, NON-CUMULATIVE.

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.piecewise_linear--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n# ramp our waveform up to a certain value, hold it\n# then ramp down. In this case, we ramp up to 2.0 rad/us in 0.3 us,\n# then hold it for 1.5 us before ramping down in 0.3 us back to 0.0 rad/us.\n>>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\nvalues=[0.0, 2.0, 2.0, 0.0])\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...piecewise_linear([durations], [values]) .linear(start, stop, duration): to append another linear waveform
    • ...piecewise_linear([durations], [values]).constant(value, duration): to append a constant waveform
    • ...piecewise_linear([durations], [values]) .piecewise_linear(durations, values): to append a piecewise linear waveform
    • ...piecewise_linear([durations], [values]) .piecewise_constant([durations], [values]): to append a piecewise constant waveform
    • ...piecewise_linear([durations], [values]) .poly([coefficients], duration): to append a polynomial waveform
    • ...piecewise_linear([durations], [values]).apply(waveform): to append a pre-defined waveform
    • ...piecewise_linear([durations], [values]).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...piecewise_linear([durations], [values]) .slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...piecewise_linear([durations], [values]) .record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...piecewise_linear([durations], [values]).uniform: To address all atoms in the field
    • ...piecewise_linear([durations], [values]).scale(...): To address an atom at a specific location via index
    • ...piecewise_linear([durations], [values]).location(int)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...piecewise_linear([durations], [values]) .assign(variable_name = value): to assign a single value to a variable
    • ...piecewise_linear([durations], [values]) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...piecewise_linear([durations], [values]) .args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...piecewise_linear([durations], [values]).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...piecewise_linear([durations], [values]).bloqade: to run on the Bloqade local emulator
    • ...piecewise_linear([durations], [values]).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...piecewise_linear([durations], [values]).parallelize(spacing)
  • Start targeting another level coupling
    • ...piecewise_linear([durations], [values]).rydberg: to target the Rydberg level coupling
    • ...piecewise_linear([durations], [values]).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...piecewise_linear([durations], [values]).amplitude: to target the real-valued Rabi Amplitude field
    • ...piecewise_linear([durations], [values]).phase: to target the real-valued Rabi Phase field
    • ...piecewise_linear([durations], [values]).detuning: to target the Detuning field
    • ....rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef piecewise_linear(\n    self, durations: List[ScalarType], values: List[ScalarType]\n) -> \"PiecewiseLinear\":\n    \"\"\"\n    Append or assign a piecewise linear waveform to current location(s),\n    where the waveform is formed by connecting `values[i], values[i+1]`\n    with linear segments.\n\n    The `durations` argument should have # of elements = len(values) - 1.\n    `durations` should be the duration PER section of the waveform, NON-CUMULATIVE.\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    # ramp our waveform up to a certain value, hold it\n    # then ramp down. In this case, we ramp up to 2.0 rad/us in 0.3 us,\n    # then hold it for 1.5 us before ramping down in 0.3 us back to 0.0 rad/us.\n    >>> prog.piecewise_linear(durations=[0.3, 2.0, 0.3],\n    values=[0.0, 2.0, 2.0, 0.0])\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...piecewise_linear([durations], [values])\n            .linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...piecewise_linear([durations], [values]).constant(value, duration)`:\n            to append a constant waveform\n        - `...piecewise_linear([durations], [values])\n            .piecewise_linear(durations, values)`:\n            to append a piecewise linear waveform\n        - `...piecewise_linear([durations], [values])\n            .piecewise_constant([durations], [values])`:\n            to append a piecewise constant waveform\n        - `...piecewise_linear([durations], [values])\n            .poly([coefficients], duration)`: to append a polynomial waveform\n        - `...piecewise_linear([durations], [values]).apply(waveform)`:\n            to append a pre-defined waveform\n        - `...piecewise_linear([durations], [values]).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...piecewise_linear([durations], [values])\n            .slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...piecewise_linear([durations], [values])\n            .record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...piecewise_linear([durations], [values]).uniform`:\n            To address all atoms in the field\n        - `...piecewise_linear([durations], [values]).scale(...)`:\n            To address an atom at a specific location via index\n        - `...piecewise_linear([durations], [values]).location(int)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning it a\n                list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...piecewise_linear([durations], [values])\n            .assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...piecewise_linear([durations], [values])\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...piecewise_linear([durations], [values])\n            .args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...piecewise_linear([durations], [values]).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...piecewise_linear([durations], [values]).bloqade`:\n            to run on the Bloqade local emulator\n        - `...piecewise_linear([durations], [values]).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...piecewise_linear([durations], [values]).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...piecewise_linear([durations], [values]).rydberg`:\n            to target the Rydberg level coupling\n        - `...piecewise_linear([durations], [values]).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level coupling\n      (previously selected as `rydberg` or `hyperfine`):\n        - `...piecewise_linear([durations], [values]).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...piecewise_linear([durations], [values]).phase`:\n            to target the real-valued Rabi Phase field\n        - `...piecewise_linear([durations], [values]).detuning`:\n            to target the Detuning field\n        - `....rabi`: to target the complex-valued Rabi field\n    \"\"\"\n    return PiecewiseLinear(durations, values, self)\n
"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.poly","title":"poly","text":"
poly(coeffs, duration)\n

Append or assign a waveform with a polynomial profile to current location(s).

You pass in a list of coefficients and a duration to this method which obeys the following expression:

wv(t) = coeffs[0] + coeffs[1]*t + coeffs[2]*t^2 + ... + coeffs[n]*t^n

If you specified a spatial modulation (e.g. uniform, location,scale) previously without a waveform you will now have completed the construction of a \"drive\", one or a sum of drives creating a \"field\" (e.g. Real-valued Rabi Amplitude/Phase).

If you have already specified a waveform previously you will now be appending this waveform to that previous waveform.

"},{"location":"reference/bloqade/analog/builder/waveform/#bloqade.analog.builder.waveform.WaveformAttachable.poly--usage-example","title":"Usage Example:","text":"
>>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n>>> coeffs = [-1, 0.5, 1.2]\n# resulting polynomial is:\n# f(t) = -1 + 0.5*t + 1.2*t^2 with duration of\n# 0.5 us\n>>> prog.poly(coeffs, duration=0.5)\n
  • Your next steps include:
  • Continue building your waveform via:
    • ...poly([coeffs], duration).linear(start, stop, duration): to append another linear waveform
    • ...poly([coeffs], duration).constant(value, duration): to append a constant waveform
    • ...poly([coeffs], duration) .piecewise_linear([durations], [values]): to append a piecewise linear waveform
    • ...poly([coeffs], duration) .piecewise_constant([durations],[values]): to append a piecewise constant waveform
    • ...poly([coeffs], duration).poly([coefficients], duration): to append a polynomial waveform
    • ...poly([coeffs], duration).apply(waveform): to append a pre-defined waveform
    • ...poly([coeffs], duration).fn(f(t,...)): to append a waveform defined by a python function
  • Slice a portion of the waveform to be used:
    • ...poly([coeffs], duration).slice(start, stop, duration)
  • Save the ending value of your waveform to be reused elsewhere
    • ...poly([coeffs], duration).record(\"you_variable_here\")
  • Begin constructing another drive by starting a new spatial modulation (this drive will be summed to the one you just created):
    • ...poly([coeffs], duration).uniform: To address all atoms in the field
    • ...poly([coeffs], duration).location(int): To address an atom at a specific location via index
    • ...poly([coeffs], duration).scale(...)
      • To address an atom at a specific location via variable
      • To address multiple atoms at specific locations by specifying a single variable and then assigning it a list of coordinates
  • Assign values to pre-existing variables via:
    • ...poly([coeffs], duration).assign(variable_name = value): to assign a single value to a variable
    • ...poly([coeffs], duration) .batch_assign(variable_name = [value1, ...]): to assign multiple values to a variable
    • ...poly([coeffs], duration).args([\"previously_defined_var\"]): to defer assignment of a variable to execution time
  • Select the backend you want your program to run on via:
    • ...poly([coeffs], duration).braket: to run on Braket local emulator or QuEra hardware remotely
    • ...poly([coeffs], duration).bloqade: to run on the Bloqade local emulator
    • ...poly([coeffs], duration).device: to specify the backend via string
  • Choose to parallelize your atom geometry, duplicating it to fill the whole space:
    • ...poly([coeffs], duration).parallelize(spacing)
  • Start targeting another level coupling
    • ...poly([coeffs], duration).rydberg: to target the Rydberg level coupling
    • ...poly([coeffs], duration).hyperfine: to target the Hyperfine level coupling
  • Start targeting other fields within your current level coupling (previously selected as rydberg or hyperfine):
    • ...poly([coeffs], duration).amplitude: to target the real-valued Rabi Amplitude field
    • ...poly([coeffs], duration).phase: to target the real-valued Rabi Phase field
    • ...poly([coeffs], duration).detuning: to target the Detuning field
    • ...poly([coeffs], duration).rabi: to target the complex-valued Rabi field
Source code in src/bloqade/analog/builder/waveform.py
@beartype\ndef poly(self, coeffs: List[ScalarType], duration: ScalarType) -> \"Poly\":\n    \"\"\"\n    Append or assign a waveform with a polynomial profile to current location(s).\n\n    You pass in a list of coefficients and a duration to this method which obeys\n    the following expression:\n\n    `\n    wv(t) = coeffs[0] + coeffs[1]*t + coeffs[2]*t^2 + ... + coeffs[n]*t^n\n    `\n\n    If you specified a spatial modulation (e.g. `uniform`, `location`,`scale`)\n    previously without a waveform you will now have completed the construction\n    of a \"drive\", one or a sum of drives creating a \"field\"\n    (e.g. Real-valued Rabi Amplitude/Phase).\n\n    If you have already specified a waveform previously you will now be appending\n    this waveform to that previous waveform.\n\n    ### Usage Example:\n    ```\n    >>> prog = start.add_position((0,0)).rydberg.detuning.uniform\n    >>> coeffs = [-1, 0.5, 1.2]\n    # resulting polynomial is:\n    # f(t) = -1 + 0.5*t + 1.2*t^2 with duration of\n    # 0.5 us\n    >>> prog.poly(coeffs, duration=0.5)\n    ```\n\n    - Your next steps include:\n    - Continue building your waveform via:\n        - `...poly([coeffs], duration).linear(start, stop, duration)`:\n            to append another linear waveform\n        - `...poly([coeffs], duration).constant(value, duration)`:\n            to append a constant waveform\n        - `...poly([coeffs], duration)\n            .piecewise_linear([durations], [values])`:\n            to append a piecewise linear waveform\n        - `...poly([coeffs], duration)\n            .piecewise_constant([durations],[values])`:\n            to append a piecewise constant waveform\n        - `...poly([coeffs], duration).poly([coefficients], duration)`:\n            to append a polynomial waveform\n        - `...poly([coeffs], duration).apply(waveform)`:\n            to append a pre-defined waveform\n        - `...poly([coeffs], duration).fn(f(t,...))`:\n            to append a waveform defined by a python function\n    - Slice a portion of the waveform to be used:\n        - `...poly([coeffs], duration).slice(start, stop, duration)`\n    - Save the ending value of your waveform to be reused elsewhere\n        - `...poly([coeffs], duration).record(\"you_variable_here\")`\n    - Begin constructing another drive by starting a new spatial modulation\n      (this drive will be summed to the one you just created):\n        - `...poly([coeffs], duration).uniform`:\n            To address all atoms in the field\n        - `...poly([coeffs], duration).location(int)`:\n            To address an atom at a specific location via index\n        - `...poly([coeffs], duration).scale(...)`\n            - To address an atom at a specific location via variable\n            - To address multiple atoms at specific locations by\n                specifying a single variable and then assigning\n                it a list of coordinates\n    - Assign values to pre-existing variables via:\n        - `...poly([coeffs], duration).assign(variable_name = value)`:\n            to assign a single value to a variable\n        - `...poly([coeffs], duration)\n            .batch_assign(variable_name = [value1, ...])`:\n            to assign multiple values to a variable\n        - `...poly([coeffs], duration).args([\"previously_defined_var\"])`:\n            to defer assignment of a variable to execution time\n    - Select the backend you want your program to run on via:\n        - `...poly([coeffs], duration).braket`:\n            to run on Braket local emulator or QuEra hardware remotely\n        - `...poly([coeffs], duration).bloqade`:\n            to run on the Bloqade local emulator\n        - `...poly([coeffs], duration).device`:\n            to specify the backend via string\n    - Choose to parallelize your atom geometry,\n      duplicating it to fill the whole space:\n        - `...poly([coeffs], duration).parallelize(spacing)`\n    - Start targeting another level coupling\n        - `...poly([coeffs], duration).rydberg`:\n            to target the Rydberg level coupling\n        - `...poly([coeffs], duration).hyperfine`:\n            to target the Hyperfine level coupling\n    - Start targeting other fields within your current level\n      coupling (previously selected as `rydberg` or `hyperfine`):\n        - `...poly([coeffs], duration).amplitude`:\n            to target the real-valued Rabi Amplitude field\n        - `...poly([coeffs], duration).phase`:\n            to target the real-valued Rabi Phase field\n        - `...poly([coeffs], duration).detuning`:\n            to target the Detuning field\n        - `...poly([coeffs], duration).rabi`:\n            to target the complex-valued Rabi field\n    \"\"\"\n    return Poly(coeffs, duration, self)\n
"},{"location":"reference/bloqade/analog/builder/backend/","title":"Index","text":""},{"location":"reference/bloqade/analog/builder/backend/#bloqade.analog.builder.backend.BackendRoute","title":"BackendRoute","text":"
BackendRoute(parent=None)\n

Bases: QuEraService, BraketService, BloqadeService

Specify the backend to run your program on via a string (versus more formal builder syntax) of specifying the vendor/product first (Bloqade/Braket) and narrowing it down (e.g: ...device(\"quera.aquila\") versus ...quera.aquila()) - You can pass the following arguments: - \"braket.aquila\" - \"braket.local_emulator\" - \"bloqade.python\" - \"bloqade.julia\"

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/","title":"Bloqade","text":""},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeDeviceRoute","title":"BloqadeDeviceRoute","text":"
BloqadeDeviceRoute(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeDeviceRoute.python","title":"python","text":"
python()\n

Specify the Bloqade Python backend.

  • Possible Next Steps:
    • ...python().run(shots): to submit to the python emulator and await results
Source code in src/bloqade/analog/builder/backend/bloqade.py
def python(self):\n    \"\"\"\n    Specify the Bloqade Python backend.\n\n    - Possible Next Steps:\n        - `...python().run(shots)`:\n            to submit to the python emulator and await results\n    \"\"\"\n    return self.parse().bloqade.python()\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeService","title":"BloqadeService","text":"
BloqadeService(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/bloqade/#bloqade.analog.builder.backend.bloqade.BloqadeService.bloqade","title":"bloqade property","text":"
bloqade\n

Specify the Bloqade backend.

  • Possible Next Steps:
    • ...bloqade.python(): target submission to the Bloqade python backend
    • ...bloqade.julia(): (CURRENTLY NOT IMPLEMENTED!)target submission to the Bloqade.jl backend
"},{"location":"reference/bloqade/analog/builder/backend/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute","title":"BraketDeviceRoute","text":"
BraketDeviceRoute(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute.aquila","title":"aquila","text":"
aquila()\n

Specify QuEra's Aquila QPU on Braket to submit your program to.

The number of shots you specify in the subsequent .run method will either: - dictate the number of times your program is run - dictate the number of times per parameter your program is run if you have a variable with batch assignments/intend to conduct a parameter sweep

  • Possible next steps are:
    • ...aquila().run(shots): To submit to hardware and WAIT for results (blocking)
    • ...aquila().run_async(shots): To submit to hardware and immediately allow for other operations to occur
Source code in src/bloqade/analog/builder/backend/braket.py
def aquila(self) -> \"BraketHardwareRoutine\":\n    \"\"\"\n    Specify QuEra's Aquila QPU on Braket to submit your program to.\n\n    The number of shots you specify in the subsequent `.run` method will either:\n        - dictate the number of times your program is run\n        - dictate the number of times per parameter your program is run if\n          you have a variable with batch assignments/intend to conduct\n          a parameter sweep\n\n\n    - Possible next steps are:\n        - `...aquila().run(shots)`: To submit to hardware and WAIT for\n            results (blocking)\n        - `...aquila().run_async(shots)`: To submit to hardware and immediately\n            allow for other operations to occur\n    \"\"\"\n    return self.parse().braket.aquila()\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute.device","title":"device","text":"
device(device_arn)\n

Specify QPU based on the device ARN on Braket to submit your program to.

The number of shots you specify in the subsequent .run method will either: - dictate the number of times your program is run - dictate the number of times per parameter your program is run if you have a variable with batch assignments/intend to conduct a parameter sweep

  • Possible next steps are:
    • ...device(arn).run(shots): To submit to hardware and WAIT for results (blocking)
    • ...device(arn).run_async(shots): To submit to hardware and immediately allow for other operations to occur
Source code in src/bloqade/analog/builder/backend/braket.py
def device(self, device_arn) -> \"BraketHardwareRoutine\":\n    \"\"\"\n    Specify QPU based on the device ARN on Braket to submit your program to.\n\n    The number of shots you specify in the subsequent `.run` method will either:\n        - dictate the number of times your program is run\n        - dictate the number of times per parameter your program is run if\n            you have a variable with batch assignments/intend to conduct\n            a parameter sweep\n\n\n    - Possible next steps are:\n        - `...device(arn).run(shots)`: To submit to hardware and WAIT for\n            results (blocking)\n        - `...device(arn).run_async(shots)`: To submit to hardware and immediately\n            allow for other operations to occur\n    \"\"\"\n    return self.parse().braket.device(device_arn)\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketDeviceRoute.local_emulator","title":"local_emulator","text":"
local_emulator()\n

Specify the Braket local emulator to submit your program to.

  • The number of shots you specify in the subsequent .run method will either:
    • dictate the number of times your program is run
    • dictate the number of times per parameter your program is run if you have a variable with batch assignments/intend to conduct a parameter sweep
  • Possible next steps are:
    • ...local_emulator().run(shots): to submit to the emulator and await results
Source code in src/bloqade/analog/builder/backend/braket.py
def local_emulator(self) -> \"BraketLocalEmulatorRoutine\":\n    \"\"\"\n    Specify the Braket local emulator to submit your program to.\n\n    - The number of shots you specify in the subsequent `.run` method will either:\n        - dictate the number of times your program is run\n        - dictate the number of times per parameter your program is run if\n          you have a variable with batch assignments/intend to\n          conduct a parameter sweep\n    - Possible next steps are:\n        - `...local_emulator().run(shots)`: to submit to the emulator\n            and await results\n\n    \"\"\"\n    return self.parse().braket.local_emulator()\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketService","title":"BraketService","text":"
BraketService(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/braket/#bloqade.analog.builder.backend.braket.BraketService.braket","title":"braket property","text":"
braket\n

Specify the Braket backend. This allows you to access the AWS Braket local emulator OR go submit things to QuEra hardware on AWS Braket service.

  • Possible Next Steps are:
    • ...braket.aquila(): target submission to the QuEra Aquila QPU
    • ...braket.local_emulator(): target submission to the Braket local emulator
"},{"location":"reference/bloqade/analog/builder/backend/quera/","title":"Quera","text":""},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute","title":"QuEraDeviceRoute","text":"
QuEraDeviceRoute(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.aquila","title":"aquila","text":"
aquila()\n

Specify QuEra's Aquila QPU

Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...aquila().submit :: submit aync remote job

    -> ...aquila().run :: submit job and wait until job finished and results returned

    -> ...aquila().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def aquila(self):\n    \"\"\"\n    Specify QuEra's Aquila QPU\n\n    Return:\n        QuEraHardwareRoutine\n\n\n    - Possible Next:\n\n        -> `...aquila().submit`\n            :: submit aync remote job\n\n        -> `...aquila().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...aquila().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n    \"\"\"\n    return self.parse().quera.aquila()\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.cloud_mock","title":"cloud_mock","text":"
cloud_mock()\n

Specify QuEra's Remote Mock QPU

Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...aquila().submit :: submit aync remote job

    -> ...aquila().run :: submit job and wait until job finished and results returned

    -> ...aquila().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def cloud_mock(self):\n    \"\"\"\n    Specify QuEra's Remote Mock QPU\n\n    Return:\n        QuEraHardwareRoutine\n\n    - Possible Next:\n\n        -> `...aquila().submit`\n            :: submit aync remote job\n\n        -> `...aquila().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...aquila().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n\n    \"\"\"\n    return self.parse().quera.cloud_mock()\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.custom","title":"custom","text":"
custom()\n

Specify custom backend

Return

CustomSubmissionRoutine

Source code in src/bloqade/analog/builder/backend/quera.py
def custom(self):\n    \"\"\"\n    Specify custom backend\n\n    Return:\n        CustomSubmissionRoutine\n\n    \"\"\"\n\n    return self.parse().quera.custom()\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.device","title":"device","text":"
device(config_file=None, **api_config)\n

Specify QuEra's QPU device,

Parameters:

Name Type Description Default config_file str

file that speficy the target hardware

None Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...device().submit :: submit aync remote job

    -> ...device().run :: submit job and wait until job finished and results returned

    -> ...device().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def device(self, config_file: Optional[str] = None, **api_config):\n    \"\"\"\n    Specify QuEra's QPU device,\n\n    Args:\n        config_file (str): file that speficy the target hardware\n\n    Return:\n        QuEraHardwareRoutine\n\n    - Possible Next:\n\n        -> `...device().submit`\n            :: submit aync remote job\n\n        -> `...device().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...device().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n    \"\"\"\n    return self.parse().quera.device(config_file, **api_config)\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraDeviceRoute.mock","title":"mock","text":"
mock(state_file='.mock_state.txt', submission_error=False)\n

Specify mock, testing locally.

Return

QuEraHardwareRoutine

  • Possible Next:

    -> ...aquila().submit :: submit aync remote job

    -> ...aquila().run :: submit job and wait until job finished and results returned

    -> ...aquila().__callable__ :: submit job and wait until job finished and results returned

Source code in src/bloqade/analog/builder/backend/quera.py
def mock(self, state_file: str = \".mock_state.txt\", submission_error: bool = False):\n    \"\"\"\n    Specify mock, testing locally.\n\n    Return:\n        QuEraHardwareRoutine\n\n    - Possible Next:\n\n        -> `...aquila().submit`\n            :: submit aync remote job\n\n        -> `...aquila().run`\n            :: submit job and wait until job finished\n            and results returned\n\n        -> `...aquila().__callable__`\n            :: submit job and wait until job finished\n            and results returned\n\n\n\n    \"\"\"\n    return self.parse().quera.mock(\n        state_file=state_file, submission_error=submission_error\n    )\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraService","title":"QuEraService","text":"
QuEraService(parent=None)\n

Bases: Builder

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/builder/backend/quera/#bloqade.analog.builder.backend.quera.QuEraService.quera","title":"quera property","text":"
quera\n
  • Specify Quera backend
  • Possible Next:

    -> ...quera.aquila :: Aquila QPU

    -> ...quera.mock :: mock backend, meant for testings

    -> ...quera.device :: QuEra QPU, specifiy by config_file

"},{"location":"reference/bloqade/analog/builder/parse/","title":"Index","text":""},{"location":"reference/bloqade/analog/builder/parse/builder/","title":"Builder","text":"

Module for parsing builder definitions into intermediate representation (IR) using the bloqade library.

This module provides a Parser class for parsing various components of a quantum computing program, including atom arrangements, pulse sequences, analog circuits, and routines. It also defines utility functions for reading addresses, waveforms, drives, sequences, registers, and pragmas from a builder stream.

"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser","title":"Parser","text":"

A class for parsing quantum computing program components into intermediate representation (IR).

"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse","title":"parse","text":"
parse(builder)\n

Parse a routine from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Name Type Description Routine Routine

The parsed routine.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse(self, builder: Builder) -> \"Routine\":\n    \"\"\"\n    Parse a routine from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        Routine: The parsed routine.\n    \"\"\"\n    from bloqade.analog.ir.routine.base import Routine\n    from bloqade.analog.ir.analog_circuit import AnalogCircuit\n    from bloqade.analog.ir.routine.params import Params, ScalarArg, VectorArg\n    from bloqade.analog.compiler.analysis.common.scan_variables import ScanVariables\n\n    self.reset(builder)\n    self.read_register()\n    self.read_sequence()\n    self.read_pragmas()\n\n    circuit = AnalogCircuit(self.register, self.sequence)\n\n    var_res = ScanVariables().scan(circuit)\n    # mark vector and scalar arguments\n    args_list = [\n        (VectorArg(name) if name in var_res.vector_vars else ScalarArg(name))\n        for name in self.order\n    ]\n\n    params = Params(\n        n_sites=self.register.n_sites,\n        static_params=self.static_params,\n        batch_params=self.batch_params,\n        args_list=args_list,\n    )\n\n    return Routine(builder, circuit, params)\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse_circuit","title":"parse_circuit","text":"
parse_circuit(builder)\n

Parse an analog circuit from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Name Type Description AnalogCircuit AnalogCircuit

The parsed analog circuit.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse_circuit(self, builder: Builder) -> \"AnalogCircuit\":\n    \"\"\"\n    Parse an analog circuit from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        AnalogCircuit: The parsed analog circuit.\n    \"\"\"\n    from bloqade.analog.ir.analog_circuit import AnalogCircuit\n\n    self.reset(builder)\n    self.read_register()\n    self.read_sequence()\n\n    circuit = AnalogCircuit(self.register, self.sequence)\n\n    return circuit\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse_register","title":"parse_register","text":"
parse_register(builder)\n

Parse an atom arrangement register from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Type Description Union[AtomArrangement, ParallelRegister]

Union[ir.AtomArrangement, ir.ParallelRegister]: The parsed atom arrangement or parallel register.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse_register(\n    self, builder: Builder\n) -> Union[ir.AtomArrangement, ir.ParallelRegister]:\n    \"\"\"\n    Parse an atom arrangement register from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        Union[ir.AtomArrangement, ir.ParallelRegister]: The parsed atom arrangement or parallel register.\n    \"\"\"\n    self.reset(builder)\n    self.read_register()\n    self.read_pragmas()\n    return self.register\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.parse_sequence","title":"parse_sequence","text":"
parse_sequence(builder)\n

Parse a sequence from the builder.

Parameters:

Name Type Description Default builder Builder

The builder instance.

required

Returns:

Type Description Sequence

ir.Sequence: The parsed sequence.

Source code in src/bloqade/analog/builder/parse/builder.py
def parse_sequence(self, builder: Builder) -> ir.Sequence:\n    \"\"\"\n    Parse a sequence from the builder.\n\n    Args:\n        builder (Builder): The builder instance.\n\n    Returns:\n        ir.Sequence: The parsed sequence.\n    \"\"\"\n    self.reset(builder)\n    self.read_sequence()\n    return self.sequence\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_address","title":"read_address","text":"
read_address(stream)\n

Read an address from the builder stream.

Parameters:

Name Type Description Default stream

The builder stream.

required

Returns:

Type Description Tuple[LevelCoupling, Field, BuilderNode]

Tuple[LevelCoupling, Field, BuilderNode]: A tuple containing the level coupling, field, and spatial modulation.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_address(self, stream) -> Tuple[LevelCoupling, Field, BuilderNode]:\n    \"\"\"\n    Read an address from the builder stream.\n\n    Args:\n        stream: The builder stream.\n\n    Returns:\n        Tuple[LevelCoupling, Field, BuilderNode]: A tuple containing the level coupling, field, and spatial modulation.\n    \"\"\"\n    spatial = stream.read_next([Location, Uniform, Scale])\n    curr = spatial\n\n    if curr is None:\n        return (None, None, None)\n\n    while curr.next is not None:\n        if not isinstance(curr.node, SpatialModulation):\n            break\n        curr = curr.next\n\n    if type(spatial.node.__parent__) in [Detuning, RabiAmplitude, RabiPhase]:\n        field = spatial.node.__parent__  # field is updated\n        if type(field) in [RabiAmplitude, RabiPhase]:\n            coupling = field.__parent__.__parent__  # skip Rabi\n        else:\n            coupling = field.__parent__\n\n        # coupling not updated\n        if type(coupling) not in [Rydberg, Hyperfine]:\n            coupling = None\n        return (coupling, field, spatial)\n    else:  # only spatial is updated\n        return (None, None, spatial)\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_drive","title":"read_drive","text":"
read_drive(head)\n

Read a drive from the builder stream.

Parameters:

Name Type Description Default head

The head of the builder stream.

required

Returns:

Type Description Field

ir.Field: The drive field.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_drive(self, head) -> ir.Field:\n    \"\"\"\n    Read a drive from the builder stream.\n\n    Args:\n        head: The head of the builder stream.\n\n    Returns:\n        ir.Field: The drive field.\n    \"\"\"\n    if head is None:\n        return ir.Field({})\n\n    sm = head.node.__bloqade_ir__()\n    wf, _ = self.read_waveform(head.next)\n\n    return ir.Field({sm: wf})\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_pragmas","title":"read_pragmas","text":"
read_pragmas()\n

Read pragmas from the builder stream.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_pragmas(self) -> None:\n    \"\"\"Read pragmas from the builder stream.\"\"\"\n    pragma_types = (\n        Assign,\n        BatchAssign,\n        ListAssign,\n        Args,\n        Parallelize,\n    )\n\n    stream = self.stream.copy()\n    curr = stream.read_next(pragma_types)\n\n    while curr is not None:\n        node = curr.node\n\n        if isinstance(node, Assign):\n            self.static_params = dict(node._static_params)\n        elif isinstance(node, BatchAssign) or isinstance(node, ListAssign):\n            self.batch_params = node._batch_params\n        elif isinstance(node, Args):\n            order = node._order\n\n            seen = set()\n            dup = []\n            for x in order:\n                if x not in seen:\n                    seen.add(x)\n                else:\n                    dup.append(x)\n\n            if dup:\n                raise ValueError(f\"Cannot have duplicate names {dup}.\")\n\n            self.order = order\n\n        elif isinstance(node, Parallelize):\n            self.register = ir.ParallelRegister(\n                self.register, node._cluster_spacing\n            )\n        else:\n            break\n\n        curr = curr.next\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_register","title":"read_register","text":"
read_register()\n

Read an atom arrangement register from the builder stream.

Returns:

Type Description AtomArrangement

ir.AtomArrangement: The parsed atom arrangement.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_register(self) -> ir.AtomArrangement:\n    \"\"\"\n    Read an atom arrangement register from the builder stream.\n\n    Returns:\n        ir.AtomArrangement: The parsed atom arrangement.\n    \"\"\"\n    # register is always head of the stream\n    register_node = self.stream.read()\n    self.register = register_node.node\n\n    return self.register\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_sequence","title":"read_sequence","text":"
read_sequence()\n

Read a sequence from the builder stream.

Returns:

Type Description Sequence

ir.Sequence: The parsed sequence.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_sequence(self) -> ir.Sequence:\n    \"\"\"\n    Read a sequence from the builder stream.\n\n    Returns:\n        ir.Sequence: The parsed sequence.\n    \"\"\"\n    if isinstance(self.stream.curr.node, SequenceBuilder):\n        # case with sequence builder object.\n        self.sequence = self.stream.read().node._sequence\n        return self.sequence\n\n    stream = self.stream.copy()\n    while stream.curr is not None:\n        coupling_builder, field_builder, spatial_head = self.read_address(stream)\n\n        if coupling_builder is not None:\n            # update to new pulse coupling\n            self.coupling_name = coupling_builder.__bloqade_ir__()\n\n        if field_builder is not None:\n            # update to new field coupling\n            self.field_name = field_builder.__bloqade_ir__()\n\n        if spatial_head is None:\n            break\n\n        pulse = self.sequence.pulses.get(self.coupling_name, ir.Pulse({}))\n        field = pulse.fields.get(self.field_name, ir.Field({}))\n\n        drive = self.read_drive(spatial_head)\n        field = field.add(drive)\n\n        pulse = ir.Pulse.create(pulse.fields | {self.field_name: field})\n        self.sequence = ir.Sequence.create(\n            self.sequence.pulses | {self.coupling_name: pulse}\n        )\n\n    return self.sequence\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.read_waveform","title":"read_waveform","text":"
read_waveform(head)\n

Read a waveform from the builder stream.

Parameters:

Name Type Description Default head BuilderNode

The head of the builder stream.

required

Returns:

Type Description Tuple[Waveform, BuilderNode]

Tuple[ir.Waveform, BuilderNode]: A tuple containing the waveform and the next builder node.

Source code in src/bloqade/analog/builder/parse/builder.py
def read_waveform(self, head: BuilderNode) -> Tuple[ir.Waveform, BuilderNode]:\n    \"\"\"\n    Read a waveform from the builder stream.\n\n    Args:\n        head (BuilderNode): The head of the builder stream.\n\n    Returns:\n        Tuple[ir.Waveform, BuilderNode]: A tuple containing the waveform and the next builder node.\n    \"\"\"\n    curr = head\n    waveform = None\n    while curr is not None:\n        node = curr.node\n\n        if isinstance(node, Slice):\n            waveform = waveform[node._start : node._stop]\n        elif isinstance(node, Record):\n            waveform = waveform.record(node._name)\n        elif isinstance(node, Sample):\n            interpolation = node._interpolation\n            if interpolation is None:\n                if self.field_name == ir.rabi.phase:\n                    interpolation = ir.Interpolation.Constant\n                else:\n                    interpolation = ir.Interpolation.Linear\n            fn_waveform = node.__parent__.__bloqade_ir__()\n            sample_waveform = ir.Sample(fn_waveform, interpolation, node._dt)\n            if waveform is None:\n                waveform = sample_waveform\n            else:\n                waveform = waveform.append(sample_waveform)\n        elif (\n            isinstance(node, Fn)\n            and curr.next is not None\n            and isinstance(curr.next.node, Sample)\n        ):\n            pass\n        elif isinstance(node, WaveformPrimitive):\n            if waveform is None:\n                waveform = node.__bloqade_ir__()\n            else:\n                waveform = waveform.append(node.__bloqade_ir__())\n        else:\n            break\n\n        curr = curr.next\n\n    return waveform, curr\n
"},{"location":"reference/bloqade/analog/builder/parse/builder/#bloqade.analog.builder.parse.builder.Parser.reset","title":"reset","text":"
reset(builder)\n

Reset the parser's state.

Source code in src/bloqade/analog/builder/parse/builder.py
def reset(self, builder: Builder):\n    \"\"\"Reset the parser's state.\"\"\"\n    self.stream = BuilderStream.create(builder)\n    self.vector_node_names = set()\n    self.sequence = ir.Sequence.create()\n    self.register = None\n    self.batch_params = [{}]\n    self.static_params = {}\n    self.order = ()\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/","title":"Stream","text":"

Module for managing a stream of builder nodes.

This module provides classes to represent builder nodes and builder streams. A builder node is a single element in the stream, representing a step in a construction process. A builder stream is a sequence of builder nodes, allowing traversal and manipulation of the construction steps.

"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderNode","title":"BuilderNode dataclass","text":"
BuilderNode(node, next=None)\n

A node in the builder stream.

"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderNode.__repr__","title":"__repr__","text":"
__repr__()\n

Representation of the BuilderNode.

Source code in src/bloqade/analog/builder/parse/stream.py
def __repr__(self) -> str:\n    \"\"\"Representation of the BuilderNode.\"\"\"\n    return repr(self.node)\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream","title":"BuilderStream dataclass","text":"
BuilderStream(head, curr=None)\n

Represents a stream of builder nodes.

"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.__iter__","title":"__iter__","text":"
__iter__()\n

Iterator method to iterate over the builder stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def __iter__(self):\n    \"\"\"Iterator method to iterate over the builder stream.\"\"\"\n    return self\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.__next__","title":"__next__","text":"
__next__()\n

Next method to get the next item in the builder stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def __next__(self):\n    \"\"\"Next method to get the next item in the builder stream.\"\"\"\n    node = self.read()\n    if node is None:\n        raise StopIteration\n    return node\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.build_nodes","title":"build_nodes staticmethod","text":"
build_nodes(node)\n

Build BuilderNode instances from the provided Builder.

Parameters:

Name Type Description Default node Builder

The root Builder instance.

required

Returns:

Name Type Description BuilderNode BuilderNode

The head of the linked list of BuilderNodes.

Source code in src/bloqade/analog/builder/parse/stream.py
@staticmethod\ndef build_nodes(node: Builder) -> \"BuilderNode\":\n    \"\"\"\n    Build BuilderNode instances from the provided Builder.\n\n    Args:\n        node (Builder): The root Builder instance.\n\n    Returns:\n        BuilderNode: The head of the linked list of BuilderNodes.\n    \"\"\"\n    curr = node\n    node = None\n    while curr is not None:\n        next = curr\n        curr = curr.__parent__ if hasattr(curr, \"__parent__\") else None\n        node = BuilderNode(next, node)\n\n    return node\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.copy","title":"copy","text":"
copy()\n

Create a copy of the builder stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def copy(self) -> \"BuilderStream\":\n    \"\"\"Create a copy of the builder stream.\"\"\"\n    return BuilderStream(head=self.head, curr=self.curr)\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.create","title":"create staticmethod","text":"
create(builder)\n

Create a BuilderStream instance from a Builder.

Parameters:

Name Type Description Default builder Builder

The root Builder instance.

required

Returns:

Name Type Description BuilderStream BuilderStream

The created BuilderStream instance.

Source code in src/bloqade/analog/builder/parse/stream.py
@staticmethod\ndef create(builder: Builder) -> \"BuilderStream\":\n    \"\"\"\n    Create a BuilderStream instance from a Builder.\n\n    Args:\n        builder (Builder): The root Builder instance.\n\n    Returns:\n        BuilderStream: The created BuilderStream instance.\n    \"\"\"\n    head = BuilderStream.build_nodes(builder)\n    return BuilderStream(head=head, curr=head)\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.eat","title":"eat","text":"
eat(types, skips=None)\n

Move the stream pointer until a node of specified types is found.

Parameters:

Name Type Description Default types List[Type[Builder]]

List of types to move the stream pointer to.

required skips List[Type[Builder]] | None

List of types to end the stream scan.

None

Returns:

Name Type Description BuilderNode BuilderNode

The beginning of the stream which matches a type in types.

Source code in src/bloqade/analog/builder/parse/stream.py
def eat(\n    self, types: List[Type[Builder]], skips: Optional[List[Type[Builder]]] = None\n) -> BuilderNode:\n    \"\"\"\n    Move the stream pointer until a node of specified types is found.\n\n    Args:\n        types (List[Type[Builder]]): List of types to move the stream pointer to.\n        skips (List[Type[Builder]] | None, optional): List of types to end the stream scan.\n\n    Returns:\n        BuilderNode: The beginning of the stream which matches a type in `types`.\n    \"\"\"\n    head = self.read_next(types)\n    curr = head\n    while curr is not None:\n        if type(curr.node) not in types:\n            if skips and type(curr.node) not in skips:\n                break\n        curr = curr.next\n    self.curr = curr\n    return head\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.read","title":"read","text":"
read()\n

Read the next builder node from the stream.

Source code in src/bloqade/analog/builder/parse/stream.py
def read(self) -> Optional[BuilderNode]:\n    \"\"\"Read the next builder node from the stream.\"\"\"\n    if self.curr is None:\n        return None\n\n    node = self.curr\n    self.curr = self.curr.next\n    return node\n
"},{"location":"reference/bloqade/analog/builder/parse/stream/#bloqade.analog.builder.parse.stream.BuilderStream.read_next","title":"read_next","text":"
read_next(builder_types)\n

Read the next builder node of specified types from the stream.

Parameters:

Name Type Description Default builder_types List[type[Builder]]

List of builder types to read from the stream.

required

Returns:

Type Description Optional[BuilderNode]

Optional[BuilderNode]: The next builder node matching one of the specified types, or None if not found.

Source code in src/bloqade/analog/builder/parse/stream.py
def read_next(self, builder_types: List[type[Builder]]) -> Optional[BuilderNode]:\n    \"\"\"\n    Read the next builder node of specified types from the stream.\n\n    Args:\n        builder_types (List[type[Builder]]): List of builder types to read from the stream.\n\n    Returns:\n        Optional[BuilderNode]: The next builder node matching one of the specified types, or None if not found.\n    \"\"\"\n    node = self.read()\n    while node is not None:\n        if type(node.node) in builder_types:\n            return node\n        node = self.read()\n    return None\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/","title":"Trait","text":"

Module for parsing and displaying quantum computing program components using the bloqade library.

"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Parse","title":"Parse","text":"

Bases: ParseRegister, ParseSequence, ParseCircuit, ParseRoutine

A composite class inheriting from ParseRegister, ParseSequence, ParseCircuit, and ParseRoutine. Provides a unified interface for parsing different components of the program.

"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Parse.n_atoms","title":"n_atoms property","text":"
n_atoms\n

Return the number of atoms in the program.

Returns:

Name Type Description int int

The number of atoms in the parsed register.

Raises:

Type Description ValueError

If the register type is unsupported.

Note

If the register is of type ParallelRegister, the number of atoms is extracted from its internal register.

Example:

>>> class MyBuilder(Parse):\n...     pass\n>>> builder = MyBuilder()\n>>> n_atoms = builder.n_atoms\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseCircuit","title":"ParseCircuit","text":"

A class providing functionality to parse the analog circuit from the program.

Example:

>>> class MyBuilder(ParseCircuit):\n...     pass\n>>> builder = MyBuilder()\n>>> analog_circuit = builder.parse_circuit()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseCircuit.parse_circuit","title":"parse_circuit","text":"
parse_circuit()\n

Parse the analog circuit from the program.

Returns:

Name Type Description AnalogCircuit AnalogCircuit

The parsed analog circuit.

Raises:

Type Description ValueError

If the circuit cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse_circuit(self: \"Builder\") -> \"AnalogCircuit\":\n    \"\"\"\n    Parse the analog circuit from the program.\n\n    Returns:\n        AnalogCircuit: The parsed analog circuit.\n\n    Raises:\n        ValueError: If the circuit cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse_circuit(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRegister","title":"ParseRegister","text":"

A class providing functionality to parse the arrangement of atoms in the program.

Example:

>>> class MyBuilder(ParseRegister):\n...     pass\n>>> builder = MyBuilder()\n>>> atom_arrangement = builder.parse_register()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRegister.parse_register","title":"parse_register","text":"
parse_register()\n

Parse the arrangement of atoms in the program.

Returns:

Type Description Union[AtomArrangement, ParallelRegister]

Union[AtomArrangement, ParallelRegister]: The parsed atom arrangement or parallel register.

Raises:

Type Description ValueError

If the register cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse_register(self: \"Builder\") -> Union[\"AtomArrangement\", \"ParallelRegister\"]:\n    \"\"\"\n    Parse the arrangement of atoms in the program.\n\n    Returns:\n        Union[AtomArrangement, ParallelRegister]: The parsed atom arrangement or parallel register.\n\n    Raises:\n        ValueError: If the register cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse_register(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRoutine","title":"ParseRoutine","text":"

A class providing functionality to parse the program and return a Routine object.

Example:

>>> class MyBuilder(ParseRoutine):\n...     pass\n>>> builder = MyBuilder()\n>>> routine = builder.parse()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseRoutine.parse","title":"parse","text":"
parse()\n

Parse the program to return a Routine object.

Returns:

Name Type Description Routine Routine

The parsed routine object.

Raises:

Type Description ValueError

If the routine cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse(self: \"Builder\") -> \"Routine\":\n    \"\"\"\n    Parse the program to return a Routine object.\n\n    Returns:\n        Routine: The parsed routine object.\n\n    Raises:\n        ValueError: If the routine cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseSequence","title":"ParseSequence","text":"

A class providing functionality to parse the pulse sequence part of the program.

Example:

>>> class MyBuilder(ParseSequence):\n...     pass\n>>> builder = MyBuilder()\n>>> sequence = builder.parse_sequence()\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.ParseSequence.parse_sequence","title":"parse_sequence","text":"
parse_sequence()\n

Parse the pulse sequence part of the program.

Returns:

Name Type Description Sequence Sequence

The parsed pulse sequence.

Raises:

Type Description ValueError

If the sequence cannot be parsed.

Source code in src/bloqade/analog/builder/parse/trait.py
def parse_sequence(self: \"Builder\") -> \"Sequence\":\n    \"\"\"\n    Parse the pulse sequence part of the program.\n\n    Returns:\n        Sequence: The parsed pulse sequence.\n\n    Raises:\n        ValueError: If the sequence cannot be parsed.\n    \"\"\"\n    from bloqade.analog.builder.parse.builder import Parser\n\n    return Parser().parse_sequence(self)\n
"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Show","title":"Show","text":"

A mixin class providing functionality to display the builder with given arguments and batch ID.

"},{"location":"reference/bloqade/analog/builder/parse/trait/#bloqade.analog.builder.parse.trait.Show.show","title":"show","text":"
show(*args, batch_id=0)\n

Display the current program being defined with the given arguments and batch ID.

Parameters:

Name Type Description Default *args

Additional arguments for display.

() batch_id int

The batch ID to be displayed. Defaults to 0.

0 Note

This method uses the display_builder function to render the builder's state.

Example:

>>> class MyBuilder(Show):\n...     pass\n>>> builder = MyBuilder()\n>>> builder.show()\n>>> builder.show(batch_id=1)\n>>> builder.show('arg1', 'arg2', batch_id=2)\n
Source code in src/bloqade/analog/builder/parse/trait.py
def show(self, *args, batch_id: int = 0):\n    \"\"\"\n    Display the current program being defined with the given arguments and batch ID.\n\n    Args:\n        *args: Additional arguments for display.\n        batch_id (int, optional): The batch ID to be displayed. Defaults to 0.\n\n    Note:\n        This method uses the `display_builder` function to render the builder's state.\n\n    Example:\n\n    ```python\n    >>> class MyBuilder(Show):\n    ...     pass\n    >>> builder = MyBuilder()\n    >>> builder.show()\n    >>> builder.show(batch_id=1)\n    >>> builder.show('arg1', 'arg2', batch_id=2)\n    ```\n    \"\"\"\n    display_builder(self, batch_id, *args)\n
"},{"location":"reference/bloqade/analog/compiler/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/assignment_scan/","title":"Assignment scan","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/check_slices/","title":"Check slices","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/is_constant/","title":"Is constant","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/is_hyperfine/","title":"Is hyperfine","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/scan_channels/","title":"Scan channels","text":""},{"location":"reference/bloqade/analog/compiler/analysis/common/scan_variables/","title":"Scan variables","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/#bloqade.analog.compiler.analysis.hardware.BasicLatticeValidation","title":"BasicLatticeValidation","text":"
BasicLatticeValidation(capabilities)\n

Bases: BloqadeIRVisitor

This visitor checks that the AtomArrangement is within the bounds of the lattice and that the number of sites is within the maximum number of sites.

Source code in src/bloqade/analog/compiler/analysis/hardware/lattice.py
def __init__(self, capabilities: QuEraCapabilities):\n    self.capabilities = capabilities\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/#bloqade.analog.compiler.analysis.hardware.ValidateChannels","title":"ValidateChannels","text":"
ValidateChannels()\n

Bases: BloqadeIRVisitor

Checks to make sure the given sequence can be compiled to hardware.

This check looks at the spatial modulations and the level coupling to determine if the sequence can be compiled to hardware.

Source code in src/bloqade/analog/compiler/analysis/hardware/channels.py
def __init__(self):\n    self.field_name = None\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/channels/","title":"Channels","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/channels/#bloqade.analog.compiler.analysis.hardware.channels.ValidateChannels","title":"ValidateChannels","text":"
ValidateChannels()\n

Bases: BloqadeIRVisitor

Checks to make sure the given sequence can be compiled to hardware.

This check looks at the spatial modulations and the level coupling to determine if the sequence can be compiled to hardware.

Source code in src/bloqade/analog/compiler/analysis/hardware/channels.py
def __init__(self):\n    self.field_name = None\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/lattice/","title":"Lattice","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/lattice/#bloqade.analog.compiler.analysis.hardware.lattice.BasicLatticeValidation","title":"BasicLatticeValidation","text":"
BasicLatticeValidation(capabilities)\n

Bases: BloqadeIRVisitor

This visitor checks that the AtomArrangement is within the bounds of the lattice and that the number of sites is within the maximum number of sites.

Source code in src/bloqade/analog/compiler/analysis/hardware/lattice.py
def __init__(self, capabilities: QuEraCapabilities):\n    self.capabilities = capabilities\n
"},{"location":"reference/bloqade/analog/compiler/analysis/hardware/piecewise_constant/","title":"Piecewise constant","text":""},{"location":"reference/bloqade/analog/compiler/analysis/hardware/piecewise_linear/","title":"Piecewise linear","text":""},{"location":"reference/bloqade/analog/compiler/analysis/python/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/analysis/python/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/compiler/passes/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/passes/emulator/","title":"Emulator","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.analyze_channels","title":"analyze_channels","text":"
analyze_channels(circuit)\n
  1. Scan channels

This pass checks to make sure that: * There is no hyperfine coupling in the sequence * There are no non-uniform spatial modulation for rabi phase and amplitude * there is no more than one non-uniform spatial modulation for detuning

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to analyze

required

Returns:

Name Type Description level_couplings Dict

Dictionary containing the required channels for the sequence. Note that this will insert a uniform field for any missing channels.

Raises:

Type Description ValueError

If there is hyperfine coupling in the sequence.

ValueError

If there is more than one non-uniform spatial modulation for detuning.

ValueError

If there are non-uniform spatial modulations for rabi phase and amplitude.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def analyze_channels(circuit: analog_circuit.AnalogCircuit) -> Dict:\n    \"\"\"1. Scan channels\n\n    This pass checks to make sure that:\n    * There is no hyperfine coupling in the sequence\n    * There are no non-uniform spatial modulation for rabi phase and amplitude\n    * there is no more than one non-uniform spatial modulation for detuning\n\n    Args:\n        circuit: AnalogCircuit to analyze\n\n    Returns:\n        level_couplings: Dictionary containing the required channels for the\n            sequence. Note that this will insert a uniform field for any missing\n            channels.\n\n    Raises:\n        ValueError: If there is hyperfine coupling in the sequence.\n        ValueError: If there is more than one non-uniform spatial modulation for\n            detuning.\n        ValueError: If there are non-uniform spatial modulations for rabi phase\n            and amplitude.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import ScanChannels\n    from bloqade.analog.compiler.analysis.hardware import ValidateChannels\n\n    ValidateChannels().scan(circuit)\n    level_couplings = ScanChannels().scan(circuit)\n\n    # add missing channels\n    fields = level_couplings[sequence.rydberg]\n    # detuning, phase and amplitude are required\n    # to have at least a uniform field\n    updated_fields = {\n        field_name: fields.get(field_name, {field.Uniform}).union({field.Uniform})\n        for field_name in [pulse.detuning, pulse.rabi.amplitude, pulse.rabi.phase]\n    }\n\n    return {sequence.rydberg: updated_fields}\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.assign_circuit","title":"assign_circuit","text":"
assign_circuit(circuit, assignments)\n
  1. Assign variables and validate assignment

This pass assigns variables to the circuit and validates that all variables have been assigned.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to assign variables to

required assignments Dict[str, ParamType]

Dictionary containing the assignments for the variables in the circuit.

required

Returns:

Name Type Description assigned_circuit Tuple[AnalogCircuit, Dict]

AnalogCircuit with variables assigned.

Raises:

Type Description ValueError

If there are any variables that have not been assigned.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def assign_circuit(\n    circuit: analog_circuit.AnalogCircuit, assignments: Dict[str, ParamType]\n) -> Tuple[analog_circuit.AnalogCircuit, Dict]:\n    \"\"\"3. Assign variables and validate assignment\n\n    This pass assigns variables to the circuit and validates that all variables\n    have been assigned.\n\n    Args:\n        circuit: AnalogCircuit to assign variables to\n        assignments: Dictionary containing the assignments for the variables in\n            the circuit.\n\n    Returns:\n        assigned_circuit: AnalogCircuit with variables assigned.\n\n    Raises:\n        ValueError: If there are any variables that have not been assigned.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import AssignBloqadeIR\n    from bloqade.analog.compiler.analysis.common import ScanVariables, AssignmentScan\n\n    final_assignments = AssignmentScan(assignments).scan(circuit)\n\n    assigned_circuit = AssignBloqadeIR(final_assignments).visit(circuit)\n\n    assignment_analysis = ScanVariables().scan(assigned_circuit)\n\n    if not assignment_analysis.is_assigned:\n        missing_vars = assignment_analysis.scalar_vars.union(\n            assignment_analysis.vector_vars\n        )\n        raise ValueError(\n            \"Missing assignments for variables:\\n\"\n            + (\"\\n\".join(f\"{var}\" for var in missing_vars))\n            + \"\\n\"\n        )\n\n    return assigned_circuit, final_assignments\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.canonicalize_circuit","title":"canonicalize_circuit","text":"
canonicalize_circuit(circuit, level_couplings)\n
  1. Insert zero waveform in the explicit time intervals missing a waveform

This pass inserts a zero waveform in the explicit time intervals missing a waveform. This is required for later analysis passes to check that the waveforms are compatible with the hardware.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to add padding to

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Return circuit: AnalogCircuit with zero waveforms inserted in the explicit time intervals missing a waveform.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def canonicalize_circuit(\n    circuit: analog_circuit.AnalogCircuit, level_couplings: Dict\n) -> analog_circuit.AnalogCircuit:\n    \"\"\"2. Insert zero waveform in the explicit time intervals missing a waveform\n\n    This pass inserts a zero waveform in the explicit time intervals missing a\n    waveform. This is required for later analysis passes to check that the\n    waveforms are compatible with the hardware.\n\n    Args:\n        circuit: AnalogCircuit to add padding to\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Return\n        circuit: AnalogCircuit with zero waveforms inserted in the explicit time\n            intervals missing a waveform.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import (\n        AddPadding,\n        Canonicalizer,\n        AssignToLiteral,\n    )\n\n    circuit = AddPadding(level_couplings).visit(circuit)\n    # these two passes are equivalent to a constant propagation pass\n    circuit = AssignToLiteral().visit(circuit)\n    circuit = Canonicalizer().visit(circuit)\n\n    return circuit\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.generate_ahs_code","title":"generate_ahs_code","text":"
generate_ahs_code(capabilities, level_couplings, circuit)\n
  1. generate ahs code

Generates the AHS code for the given circuit. This includes generating the lattice data, global detuning, global amplitude, global phase, local detuning and lattice site coefficients (if applicable).

Parameters:

Name Type Description Default capabilities QuEraCapabilities | None

Capabilities of the hardware.

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required circuit AnalogCircuit

AnalogCircuit to generate AHS code for.

required

Returns:

Name Type Description ahs_components AHSComponents

A collection of the AHS components generated for the given circuit. Can be used to generate the QuEra and Braket IR.

Raises:

Type Description ValueError

If the capabilities are not provided but the circuit has a ParallelRegister. This is because the ParallelRegister requires the capabilities to generate the lattice data.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_ahs_code(\n    capabilities: Optional[QuEraCapabilities],\n    level_couplings: Dict,\n    circuit: analog_circuit.AnalogCircuit,\n) -> AHSComponents:\n    \"\"\"5. generate ahs code\n\n    Generates the AHS code for the given circuit. This includes generating the\n    lattice data, global detuning, global amplitude, global phase, local\n    detuning and lattice site coefficients (if applicable).\n\n    Args:\n        capabilities (QuEraCapabilities | None): Capabilities of the hardware.\n        level_couplings (Dict): Dictionary containing the given channels for the\n            sequence.\n        circuit (AnalogCircuit): AnalogCircuit to generate AHS code for.\n\n    Returns:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit. Can be used to generate the QuEra\n            and Braket IR.\n\n    Raises:\n        ValueError: If the capabilities are not provided but the circuit has\n            a ParallelRegister. This is because the ParallelRegister requires\n            the capabilities to generate the lattice data.\n\n    \"\"\"\n    from bloqade.analog.compiler.codegen.hardware import (\n        GenerateLattice,\n        GeneratePiecewiseLinearChannel,\n        GenerateLatticeSiteCoefficients,\n        GeneratePiecewiseConstantChannel,\n    )\n    from bloqade.analog.compiler.analysis.hardware import BasicLatticeValidation\n\n    if capabilities is not None:\n        # only validate the lattice if capabilities are provided\n        BasicLatticeValidation(capabilities).visit(circuit)\n\n    ahs_lattice_data = GenerateLattice(capabilities).emit(circuit)\n\n    global_detuning = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.detuning, field.Uniform\n    ).visit(circuit)\n\n    global_amplitude = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.rabi.amplitude, field.Uniform\n    ).visit(circuit)\n\n    global_phase = GeneratePiecewiseConstantChannel(\n        sequence.rydberg, pulse.rabi.phase, field.Uniform\n    ).visit(circuit)\n\n    local_detuning = None\n    lattice_site_coefficients = None\n\n    extra_sm = set(level_couplings[sequence.rydberg][pulse.detuning]) - {field.Uniform}\n\n    if extra_sm:\n        if capabilities is not None and capabilities.capabilities.rydberg.local is None:\n            raise ValueError(\n                \"Device does not support local detuning, but the program has a \"\n                \"non-uniform spatial modulation for detuning.\"\n            )\n\n        sm = extra_sm.pop()\n\n        lattice_site_coefficients = GenerateLatticeSiteCoefficients(\n            parallel_decoder=ahs_lattice_data.parallel_decoder\n        ).emit(circuit)\n\n        local_detuning = GeneratePiecewiseLinearChannel(\n            sequence.rydberg, pulse.detuning, sm\n        ).visit(circuit)\n\n    return AHSComponents(\n        lattice_data=ahs_lattice_data,\n        global_detuning=global_detuning,\n        global_amplitude=global_amplitude,\n        global_phase=global_phase,\n        local_detuning=local_detuning,\n        lattice_site_coefficients=lattice_site_coefficients,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.generate_braket_ir","title":"generate_braket_ir","text":"
generate_braket_ir(ahs_components, shots)\n
  1. generate braket ir

This pass takes the AHS components and generates the Braket IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification BraketTaskSpecification

Braket IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_braket_ir(\n    ahs_components: AHSComponents, shots: int\n) -> BraketTaskSpecification:\n    \"\"\"7. generate braket ir\n\n    This pass takes the AHS components and generates the Braket IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (BraketTaskSpecification): Braket IR for the given\n            circuit.\n\n    \"\"\"\n    import braket.ir.ahs as ahs\n\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    ahs_register = ahs.AtomArrangement(\n        sites=list(map(convert_coordinate_units, ahs_components.lattice_data.sites)),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning_time_series = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning_time_series = ahs.TimeSeries(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n        )\n\n    amplitude_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    phase_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = ahs.PhysicalField(\n        time_series=global_detuning_time_series,\n        pattern=\"uniform\",\n    )\n\n    amplitude = ahs.PhysicalField(\n        time_series=amplitude_time_series,\n        pattern=\"uniform\",\n    )\n\n    phase = ahs.PhysicalField(\n        time_series=phase_time_series,\n        pattern=\"uniform\",\n    )\n\n    local_detuning = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = ahs.PhysicalField(\n            time_series=local_detuning_time_series,\n            pattern=ahs_components.lattice_site_coefficients,\n        )\n\n    driving_field = ahs.DrivingField(\n        detuning=detuning,\n        amplitude=amplitude,\n        phase=phase,\n    )\n\n    shiftingFields = []\n    if ahs_components.lattice_site_coefficients is not None:\n        shiftingFields = [ahs.ShiftingField(magnitude=local_detuning)]\n\n    program = ahs.Program(\n        setup=ahs.Setup(ahs_register=ahs_register),\n        hamiltonian=ahs.Hamiltonian(\n            drivingFields=[driving_field],\n            shiftingFields=shiftingFields,\n        ),\n    )\n\n    return BraketTaskSpecification(nshots=shots, program=program)\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.generate_quera_ir","title":"generate_quera_ir","text":"
generate_quera_ir(ahs_components, shots)\n
  1. generate quera ir

This pass takes the AHS components and generates the QuEra IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification QuEraTaskSpecification

QuEra IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_quera_ir(\n    ahs_components: AHSComponents, shots: int\n) -> QuEraTaskSpecification:\n    \"\"\"7. generate quera ir\n\n    This pass takes the AHS components and generates the QuEra IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (QuEraTaskSpecification): QuEra IR for the given\n            circuit.\n\n    \"\"\"\n    import bloqade.analog.submission.ir.task_specification as task_spec\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    lattice = task_spec.Lattice(\n        sites=list(\n            map(\n                convert_coordinate_units,\n                ahs_components.lattice_data.sites,\n            )\n        ),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning = None\n\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = task_spec.LocalField(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n            lattice_site_coefficients=ahs_components.lattice_site_coefficients,\n        )\n\n    rabi_frequency_amplitude_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    rabi_frequency_phase_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = task_spec.Detuning(\n        global_=global_detuning,\n        local=local_detuning,\n    )\n\n    rabi_frequency_amplitude = task_spec.RabiFrequencyAmplitude(\n        global_=rabi_frequency_amplitude_field,\n    )\n\n    rabi_frequency_phase = task_spec.RabiFrequencyPhase(\n        global_=rabi_frequency_phase_field,\n    )\n\n    rydberg = task_spec.RydbergHamiltonian(\n        rabi_frequency_amplitude=rabi_frequency_amplitude,\n        rabi_frequency_phase=rabi_frequency_phase,\n        detuning=detuning,\n    )\n\n    effective_hamiltonian = task_spec.EffectiveHamiltonian(\n        rydberg=rydberg,\n    )\n\n    return task_spec.QuEraTaskSpecification(\n        nshots=shots,\n        lattice=lattice,\n        effective_hamiltonian=effective_hamiltonian,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/#bloqade.analog.compiler.passes.hardware.validate_waveforms","title":"validate_waveforms","text":"
validate_waveforms(level_couplings, circuit)\n
  1. validate piecewise linear and piecewise constant pieces of pulses

This pass check to make sure that the waveforms are compatible with the hardware. This includes checking that the waveforms are piecewise linear or piecewise constant. It also checks that the waveforms are compatible with the given channels.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to validate waveforms for

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Raises:

Type Description ValueError

If the waveforms are not piecewise linear or piecewise constant, e.g. the waveform is not continuous.

ValueError

If a waveform segment is not compatible with the given channels.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def validate_waveforms(\n    level_couplings: Dict, circuit: analog_circuit.AnalogCircuit\n) -> None:\n    \"\"\"4. validate piecewise linear and piecewise constant pieces of pulses\n\n    This pass check to make sure that the waveforms are compatible with the\n    hardware. This includes checking that the waveforms are piecewise linear or\n    piecewise constant. It also checks that the waveforms are compatible with\n    the given channels.\n\n    Args:\n        circuit: AnalogCircuit to validate waveforms for\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Raises:\n        ValueError: If the waveforms are not piecewise linear or piecewise\n            constant, e.g. the waveform is not continuous.\n        ValueError: If a waveform segment is not compatible with the given\n            channels.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import CheckSlices\n    from bloqade.analog.compiler.analysis.hardware import (\n        ValidatePiecewiseLinearChannel,\n        ValidatePiecewiseConstantChannel,\n    )\n\n    channel_iter = (\n        (level_coupling, field_name, sm)\n        for level_coupling, fields in level_couplings.items()\n        for field_name, spatial_modulations in fields.items()\n        for sm in spatial_modulations\n    )\n    for channel in channel_iter:\n        if channel[1] in [pulse.detuning, pulse.rabi.amplitude]:\n            ValidatePiecewiseLinearChannel(*channel).visit(circuit)\n        else:\n            ValidatePiecewiseConstantChannel(*channel).visit(circuit)\n\n    CheckSlices().visit(circuit)\n\n    if circuit.sequence.duration() == 0:\n        raise ValueError(\"Circuit Duration must be be non-zero\")\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/components/","title":"Components","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/","title":"Define","text":""},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.analyze_channels","title":"analyze_channels","text":"
analyze_channels(circuit)\n
  1. Scan channels

This pass checks to make sure that: * There is no hyperfine coupling in the sequence * There are no non-uniform spatial modulation for rabi phase and amplitude * there is no more than one non-uniform spatial modulation for detuning

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to analyze

required

Returns:

Name Type Description level_couplings Dict

Dictionary containing the required channels for the sequence. Note that this will insert a uniform field for any missing channels.

Raises:

Type Description ValueError

If there is hyperfine coupling in the sequence.

ValueError

If there is more than one non-uniform spatial modulation for detuning.

ValueError

If there are non-uniform spatial modulations for rabi phase and amplitude.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def analyze_channels(circuit: analog_circuit.AnalogCircuit) -> Dict:\n    \"\"\"1. Scan channels\n\n    This pass checks to make sure that:\n    * There is no hyperfine coupling in the sequence\n    * There are no non-uniform spatial modulation for rabi phase and amplitude\n    * there is no more than one non-uniform spatial modulation for detuning\n\n    Args:\n        circuit: AnalogCircuit to analyze\n\n    Returns:\n        level_couplings: Dictionary containing the required channels for the\n            sequence. Note that this will insert a uniform field for any missing\n            channels.\n\n    Raises:\n        ValueError: If there is hyperfine coupling in the sequence.\n        ValueError: If there is more than one non-uniform spatial modulation for\n            detuning.\n        ValueError: If there are non-uniform spatial modulations for rabi phase\n            and amplitude.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import ScanChannels\n    from bloqade.analog.compiler.analysis.hardware import ValidateChannels\n\n    ValidateChannels().scan(circuit)\n    level_couplings = ScanChannels().scan(circuit)\n\n    # add missing channels\n    fields = level_couplings[sequence.rydberg]\n    # detuning, phase and amplitude are required\n    # to have at least a uniform field\n    updated_fields = {\n        field_name: fields.get(field_name, {field.Uniform}).union({field.Uniform})\n        for field_name in [pulse.detuning, pulse.rabi.amplitude, pulse.rabi.phase]\n    }\n\n    return {sequence.rydberg: updated_fields}\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.assign_circuit","title":"assign_circuit","text":"
assign_circuit(circuit, assignments)\n
  1. Assign variables and validate assignment

This pass assigns variables to the circuit and validates that all variables have been assigned.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to assign variables to

required assignments Dict[str, ParamType]

Dictionary containing the assignments for the variables in the circuit.

required

Returns:

Name Type Description assigned_circuit Tuple[AnalogCircuit, Dict]

AnalogCircuit with variables assigned.

Raises:

Type Description ValueError

If there are any variables that have not been assigned.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def assign_circuit(\n    circuit: analog_circuit.AnalogCircuit, assignments: Dict[str, ParamType]\n) -> Tuple[analog_circuit.AnalogCircuit, Dict]:\n    \"\"\"3. Assign variables and validate assignment\n\n    This pass assigns variables to the circuit and validates that all variables\n    have been assigned.\n\n    Args:\n        circuit: AnalogCircuit to assign variables to\n        assignments: Dictionary containing the assignments for the variables in\n            the circuit.\n\n    Returns:\n        assigned_circuit: AnalogCircuit with variables assigned.\n\n    Raises:\n        ValueError: If there are any variables that have not been assigned.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import AssignBloqadeIR\n    from bloqade.analog.compiler.analysis.common import ScanVariables, AssignmentScan\n\n    final_assignments = AssignmentScan(assignments).scan(circuit)\n\n    assigned_circuit = AssignBloqadeIR(final_assignments).visit(circuit)\n\n    assignment_analysis = ScanVariables().scan(assigned_circuit)\n\n    if not assignment_analysis.is_assigned:\n        missing_vars = assignment_analysis.scalar_vars.union(\n            assignment_analysis.vector_vars\n        )\n        raise ValueError(\n            \"Missing assignments for variables:\\n\"\n            + (\"\\n\".join(f\"{var}\" for var in missing_vars))\n            + \"\\n\"\n        )\n\n    return assigned_circuit, final_assignments\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.canonicalize_circuit","title":"canonicalize_circuit","text":"
canonicalize_circuit(circuit, level_couplings)\n
  1. Insert zero waveform in the explicit time intervals missing a waveform

This pass inserts a zero waveform in the explicit time intervals missing a waveform. This is required for later analysis passes to check that the waveforms are compatible with the hardware.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to add padding to

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Return circuit: AnalogCircuit with zero waveforms inserted in the explicit time intervals missing a waveform.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def canonicalize_circuit(\n    circuit: analog_circuit.AnalogCircuit, level_couplings: Dict\n) -> analog_circuit.AnalogCircuit:\n    \"\"\"2. Insert zero waveform in the explicit time intervals missing a waveform\n\n    This pass inserts a zero waveform in the explicit time intervals missing a\n    waveform. This is required for later analysis passes to check that the\n    waveforms are compatible with the hardware.\n\n    Args:\n        circuit: AnalogCircuit to add padding to\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Return\n        circuit: AnalogCircuit with zero waveforms inserted in the explicit time\n            intervals missing a waveform.\n\n    \"\"\"\n    from bloqade.analog.compiler.rewrite.common import (\n        AddPadding,\n        Canonicalizer,\n        AssignToLiteral,\n    )\n\n    circuit = AddPadding(level_couplings).visit(circuit)\n    # these two passes are equivalent to a constant propagation pass\n    circuit = AssignToLiteral().visit(circuit)\n    circuit = Canonicalizer().visit(circuit)\n\n    return circuit\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.generate_ahs_code","title":"generate_ahs_code","text":"
generate_ahs_code(capabilities, level_couplings, circuit)\n
  1. generate ahs code

Generates the AHS code for the given circuit. This includes generating the lattice data, global detuning, global amplitude, global phase, local detuning and lattice site coefficients (if applicable).

Parameters:

Name Type Description Default capabilities QuEraCapabilities | None

Capabilities of the hardware.

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required circuit AnalogCircuit

AnalogCircuit to generate AHS code for.

required

Returns:

Name Type Description ahs_components AHSComponents

A collection of the AHS components generated for the given circuit. Can be used to generate the QuEra and Braket IR.

Raises:

Type Description ValueError

If the capabilities are not provided but the circuit has a ParallelRegister. This is because the ParallelRegister requires the capabilities to generate the lattice data.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_ahs_code(\n    capabilities: Optional[QuEraCapabilities],\n    level_couplings: Dict,\n    circuit: analog_circuit.AnalogCircuit,\n) -> AHSComponents:\n    \"\"\"5. generate ahs code\n\n    Generates the AHS code for the given circuit. This includes generating the\n    lattice data, global detuning, global amplitude, global phase, local\n    detuning and lattice site coefficients (if applicable).\n\n    Args:\n        capabilities (QuEraCapabilities | None): Capabilities of the hardware.\n        level_couplings (Dict): Dictionary containing the given channels for the\n            sequence.\n        circuit (AnalogCircuit): AnalogCircuit to generate AHS code for.\n\n    Returns:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit. Can be used to generate the QuEra\n            and Braket IR.\n\n    Raises:\n        ValueError: If the capabilities are not provided but the circuit has\n            a ParallelRegister. This is because the ParallelRegister requires\n            the capabilities to generate the lattice data.\n\n    \"\"\"\n    from bloqade.analog.compiler.codegen.hardware import (\n        GenerateLattice,\n        GeneratePiecewiseLinearChannel,\n        GenerateLatticeSiteCoefficients,\n        GeneratePiecewiseConstantChannel,\n    )\n    from bloqade.analog.compiler.analysis.hardware import BasicLatticeValidation\n\n    if capabilities is not None:\n        # only validate the lattice if capabilities are provided\n        BasicLatticeValidation(capabilities).visit(circuit)\n\n    ahs_lattice_data = GenerateLattice(capabilities).emit(circuit)\n\n    global_detuning = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.detuning, field.Uniform\n    ).visit(circuit)\n\n    global_amplitude = GeneratePiecewiseLinearChannel(\n        sequence.rydberg, pulse.rabi.amplitude, field.Uniform\n    ).visit(circuit)\n\n    global_phase = GeneratePiecewiseConstantChannel(\n        sequence.rydberg, pulse.rabi.phase, field.Uniform\n    ).visit(circuit)\n\n    local_detuning = None\n    lattice_site_coefficients = None\n\n    extra_sm = set(level_couplings[sequence.rydberg][pulse.detuning]) - {field.Uniform}\n\n    if extra_sm:\n        if capabilities is not None and capabilities.capabilities.rydberg.local is None:\n            raise ValueError(\n                \"Device does not support local detuning, but the program has a \"\n                \"non-uniform spatial modulation for detuning.\"\n            )\n\n        sm = extra_sm.pop()\n\n        lattice_site_coefficients = GenerateLatticeSiteCoefficients(\n            parallel_decoder=ahs_lattice_data.parallel_decoder\n        ).emit(circuit)\n\n        local_detuning = GeneratePiecewiseLinearChannel(\n            sequence.rydberg, pulse.detuning, sm\n        ).visit(circuit)\n\n    return AHSComponents(\n        lattice_data=ahs_lattice_data,\n        global_detuning=global_detuning,\n        global_amplitude=global_amplitude,\n        global_phase=global_phase,\n        local_detuning=local_detuning,\n        lattice_site_coefficients=lattice_site_coefficients,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.generate_braket_ir","title":"generate_braket_ir","text":"
generate_braket_ir(ahs_components, shots)\n
  1. generate braket ir

This pass takes the AHS components and generates the Braket IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification BraketTaskSpecification

Braket IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_braket_ir(\n    ahs_components: AHSComponents, shots: int\n) -> BraketTaskSpecification:\n    \"\"\"7. generate braket ir\n\n    This pass takes the AHS components and generates the Braket IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (BraketTaskSpecification): Braket IR for the given\n            circuit.\n\n    \"\"\"\n    import braket.ir.ahs as ahs\n\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    ahs_register = ahs.AtomArrangement(\n        sites=list(map(convert_coordinate_units, ahs_components.lattice_data.sites)),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning_time_series = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning_time_series = ahs.TimeSeries(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n        )\n\n    amplitude_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    phase_time_series = ahs.TimeSeries(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = ahs.PhysicalField(\n        time_series=global_detuning_time_series,\n        pattern=\"uniform\",\n    )\n\n    amplitude = ahs.PhysicalField(\n        time_series=amplitude_time_series,\n        pattern=\"uniform\",\n    )\n\n    phase = ahs.PhysicalField(\n        time_series=phase_time_series,\n        pattern=\"uniform\",\n    )\n\n    local_detuning = None\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = ahs.PhysicalField(\n            time_series=local_detuning_time_series,\n            pattern=ahs_components.lattice_site_coefficients,\n        )\n\n    driving_field = ahs.DrivingField(\n        detuning=detuning,\n        amplitude=amplitude,\n        phase=phase,\n    )\n\n    shiftingFields = []\n    if ahs_components.lattice_site_coefficients is not None:\n        shiftingFields = [ahs.ShiftingField(magnitude=local_detuning)]\n\n    program = ahs.Program(\n        setup=ahs.Setup(ahs_register=ahs_register),\n        hamiltonian=ahs.Hamiltonian(\n            drivingFields=[driving_field],\n            shiftingFields=shiftingFields,\n        ),\n    )\n\n    return BraketTaskSpecification(nshots=shots, program=program)\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.generate_quera_ir","title":"generate_quera_ir","text":"
generate_quera_ir(ahs_components, shots)\n
  1. generate quera ir

This pass takes the AHS components and generates the QuEra IR.

Parameters:

Name Type Description Default ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description task_specification QuEraTaskSpecification

QuEra IR for the given circuit.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def generate_quera_ir(\n    ahs_components: AHSComponents, shots: int\n) -> QuEraTaskSpecification:\n    \"\"\"7. generate quera ir\n\n    This pass takes the AHS components and generates the QuEra IR.\n\n    Args:\n        ahs_components (AHSComponents): A collection of the AHS components\n            generated for the given circuit.\n        shots (int): Number of shots to run the circuit for.\n\n    Returns:\n        task_specification (QuEraTaskSpecification): QuEra IR for the given\n            circuit.\n\n    \"\"\"\n    import bloqade.analog.submission.ir.task_specification as task_spec\n    from bloqade.analog.compiler.passes.hardware.units import (\n        convert_time_units,\n        convert_energy_units,\n        convert_coordinate_units,\n    )\n\n    lattice = task_spec.Lattice(\n        sites=list(\n            map(\n                convert_coordinate_units,\n                ahs_components.lattice_data.sites,\n            )\n        ),\n        filling=ahs_components.lattice_data.filling,\n    )\n\n    global_detuning = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_detuning.times)),\n        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),\n    )\n\n    local_detuning = None\n\n    if ahs_components.lattice_site_coefficients is not None:\n        local_detuning = task_spec.LocalField(\n            times=list(map(convert_time_units, ahs_components.local_detuning.times)),\n            values=list(\n                map(convert_energy_units, ahs_components.local_detuning.values)\n            ),\n            lattice_site_coefficients=ahs_components.lattice_site_coefficients,\n        )\n\n    rabi_frequency_amplitude_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),\n        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),\n    )\n\n    rabi_frequency_phase_field = task_spec.GlobalField(\n        times=list(map(convert_time_units, ahs_components.global_phase.times)),\n        values=ahs_components.global_phase.values,\n    )\n\n    detuning = task_spec.Detuning(\n        global_=global_detuning,\n        local=local_detuning,\n    )\n\n    rabi_frequency_amplitude = task_spec.RabiFrequencyAmplitude(\n        global_=rabi_frequency_amplitude_field,\n    )\n\n    rabi_frequency_phase = task_spec.RabiFrequencyPhase(\n        global_=rabi_frequency_phase_field,\n    )\n\n    rydberg = task_spec.RydbergHamiltonian(\n        rabi_frequency_amplitude=rabi_frequency_amplitude,\n        rabi_frequency_phase=rabi_frequency_phase,\n        detuning=detuning,\n    )\n\n    effective_hamiltonian = task_spec.EffectiveHamiltonian(\n        rydberg=rydberg,\n    )\n\n    return task_spec.QuEraTaskSpecification(\n        nshots=shots,\n        lattice=lattice,\n        effective_hamiltonian=effective_hamiltonian,\n    )\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/define/#bloqade.analog.compiler.passes.hardware.define.validate_waveforms","title":"validate_waveforms","text":"
validate_waveforms(level_couplings, circuit)\n
  1. validate piecewise linear and piecewise constant pieces of pulses

This pass check to make sure that the waveforms are compatible with the hardware. This includes checking that the waveforms are piecewise linear or piecewise constant. It also checks that the waveforms are compatible with the given channels.

Parameters:

Name Type Description Default circuit AnalogCircuit

AnalogCircuit to validate waveforms for

required level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Raises:

Type Description ValueError

If the waveforms are not piecewise linear or piecewise constant, e.g. the waveform is not continuous.

ValueError

If a waveform segment is not compatible with the given channels.

Source code in src/bloqade/analog/compiler/passes/hardware/define.py
def validate_waveforms(\n    level_couplings: Dict, circuit: analog_circuit.AnalogCircuit\n) -> None:\n    \"\"\"4. validate piecewise linear and piecewise constant pieces of pulses\n\n    This pass check to make sure that the waveforms are compatible with the\n    hardware. This includes checking that the waveforms are piecewise linear or\n    piecewise constant. It also checks that the waveforms are compatible with\n    the given channels.\n\n    Args:\n        circuit: AnalogCircuit to validate waveforms for\n        level_couplings: Dictionary containing the given channels for the\n            sequence.\n\n    Raises:\n        ValueError: If the waveforms are not piecewise linear or piecewise\n            constant, e.g. the waveform is not continuous.\n        ValueError: If a waveform segment is not compatible with the given\n            channels.\n\n    \"\"\"\n    from bloqade.analog.compiler.analysis.common import CheckSlices\n    from bloqade.analog.compiler.analysis.hardware import (\n        ValidatePiecewiseLinearChannel,\n        ValidatePiecewiseConstantChannel,\n    )\n\n    channel_iter = (\n        (level_coupling, field_name, sm)\n        for level_coupling, fields in level_couplings.items()\n        for field_name, spatial_modulations in fields.items()\n        for sm in spatial_modulations\n    )\n    for channel in channel_iter:\n        if channel[1] in [pulse.detuning, pulse.rabi.amplitude]:\n            ValidatePiecewiseLinearChannel(*channel).visit(circuit)\n        else:\n            ValidatePiecewiseConstantChannel(*channel).visit(circuit)\n\n    CheckSlices().visit(circuit)\n\n    if circuit.sequence.duration() == 0:\n        raise ValueError(\"Circuit Duration must be be non-zero\")\n
"},{"location":"reference/bloqade/analog/compiler/passes/hardware/units/","title":"Units","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/#bloqade.analog.compiler.rewrite.common.AssignToLiteral","title":"AssignToLiteral","text":"

Bases: BloqadeIRTransformer

Transform all assigned variables to literals.

"},{"location":"reference/bloqade/analog/compiler/rewrite/common/add_padding/","title":"Add padding","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/assign_to_literal/","title":"Assign to literal","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/assign_to_literal/#bloqade.analog.compiler.rewrite.common.assign_to_literal.AssignToLiteral","title":"AssignToLiteral","text":"

Bases: BloqadeIRTransformer

Transform all assigned variables to literals.

"},{"location":"reference/bloqade/analog/compiler/rewrite/common/assign_variables/","title":"Assign variables","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/canonicalize/","title":"Canonicalize","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/common/flatten/","title":"Flatten","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/python/","title":"Index","text":""},{"location":"reference/bloqade/analog/compiler/rewrite/python/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/emulate/","title":"Index","text":""},{"location":"reference/bloqade/analog/emulate/sparse_operator/","title":"Sparse operator","text":""},{"location":"reference/bloqade/analog/emulate/ir/","title":"Index","text":""},{"location":"reference/bloqade/analog/emulate/ir/atom_type/","title":"Atom type","text":""},{"location":"reference/bloqade/analog/emulate/ir/emulator/","title":"Emulator","text":""},{"location":"reference/bloqade/analog/emulate/ir/emulator/#bloqade.analog.emulate.ir.emulator.Register","title":"Register dataclass","text":"
Register(atom_type, sites, blockade_radius, geometry=None)\n

This class represents the of the atoms in the system.

"},{"location":"reference/bloqade/analog/emulate/ir/space/","title":"Space","text":""},{"location":"reference/bloqade/analog/emulate/ir/state_vector/","title":"State vector","text":""},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.AnalogGate","title":"AnalogGate dataclass","text":"
AnalogGate(hamiltonian)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.AnalogGate.run","title":"run","text":"
run(\n    shots=1,\n    solver_name=\"dop853\",\n    atol=1e-14,\n    rtol=1e-07,\n    nsteps=2147483647,\n    interaction_picture=False,\n    project_hyperfine=True,\n)\n

Run the emulation with all atoms in the ground state, sampling the final state vector.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef run(\n    self,\n    shots: int = 1,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-14,\n    rtol: float = 1e-7,\n    nsteps: int = 2_147_483_647,\n    interaction_picture: bool = False,\n    project_hyperfine: bool = True,\n) -> NDArray[np.uint8]:\n    \"\"\"Run the emulation with all atoms in the ground state,\n    sampling the final state vector.\"\"\"\n\n    options = dict(\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n\n    state = self.hamiltonian.space.zero_state()\n    (result,) = self.apply(state, **options)\n    result.normalize()\n\n    return result.sample(shots, project_hyperfine=project_hyperfine)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian","title":"RydbergHamiltonian dataclass","text":"
RydbergHamiltonian(\n    emulator_ir,\n    space,\n    rydberg,\n    detuning_ops=list(),\n    rabi_ops=list(),\n)\n

Hamiltonian for a given task. With the RydbergHamiltonian you can convert the Hamiltonian to CSR matrix form as well as obtaining the average energy/variance of a register.

Attributes:

Name Type Description emulator_ir EmulatorProgram

A copy of the original program used to generate the RydbergHamiltonian

space Space

The Hilbert space of the Hamiltonian, should align with the register the Hamiltonian is being applied on for average energy/variance

rydberg NDArray

Rydberg interaction operator

detuning_ops List[DetuningOperator]

Detuning Operators of the Hamiltonian

rabi_ops List[RabiOperator]

Rabi Operators of the Hamiltonian

"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.average","title":"average","text":"
average(register, time=None)\n

Get energy average from RydbergHamiltonian object at time time with register register

Parameters:

Name Type Description Default register StateVector

The state vector to take average with

required time Optional[float]

Time value to evaluate average at.

None

Returns:

Name Type Description float float

average energy at time time

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef average(\n    self,\n    register: StateVector,\n    time: Optional[float] = None,\n) -> float:\n    \"\"\"Get energy average from RydbergHamiltonian object at time `time` with\n    register `register`\n\n    Args:\n        register (StateVector): The state vector to take average with\n        time (Optional[float], optional): Time value to evaluate average at.\n        Defaults to duration of RydbergHamiltonian.\n\n    Returns:\n        float: average energy at time `time`\n    \"\"\"\n    return np.vdot(register.data, self._apply(register.data, time)).real\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.average_and_variance","title":"average_and_variance","text":"
average_and_variance(register, time=None)\n

Get energy average and variance from RydbergHamiltonian object at time time with register register

Parameters:

Name Type Description Default register StateVector

The state vector to take average and variance with

required time Optional[float]

Time value to evaluate average at.

None

Returns:

Type Description float

Tuple[float, float]: average and variance of energy at time time

float

respectively.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef average_and_variance(\n    self,\n    register: StateVector,\n    time: Optional[float] = None,\n) -> Tuple[float, float]:\n    \"\"\"Get energy average and variance from RydbergHamiltonian object at time `time`\n    with register `register`\n\n    Args:\n        register (StateVector): The state vector to take average and variance with\n        time (Optional[float], optional): Time value to evaluate average at.\n        Defaults to duration of RydbergHamiltonian.\n\n    Returns:\n        Tuple[float, float]: average and variance of energy at time `time`\n        respectively.\n    \"\"\"\n    H_register_data = self._apply(register.data, time)\n\n    average = np.vdot(register.data, H_register_data).real\n    square_average = np.vdot(H_register_data, H_register_data).real\n\n    return average, square_average - average**2\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.tocsr","title":"tocsr","text":"
tocsr(time)\n

Return the Hamiltonian as a csr matrix at time time.

Parameters:

Name Type Description Default time float

time to evaluate the Hamiltonian at.

required

Returns:

Name Type Description csr_matrix csr_matrix

The Hamiltonian as a csr matrix.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def tocsr(self, time: float) -> csr_matrix:\n    \"\"\"Return the Hamiltonian as a csr matrix at time `time`.\n\n    Args:\n        time (float): time to evaluate the Hamiltonian at.\n\n    Returns:\n        csr_matrix: The Hamiltonian as a csr matrix.\n\n    \"\"\"\n    diagonal = sum(\n        (detuning.get_diagonal(time) for detuning in self.detuning_ops),\n        start=self.rydberg,\n    )\n\n    hamiltonian = diags(diagonal).tocsr()\n    for rabi_op in self.rabi_ops:\n        hamiltonian = hamiltonian + rabi_op.tocsr(time)\n\n    return hamiltonian\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.RydbergHamiltonian.variance","title":"variance","text":"
variance(register, time=None)\n

Get the energy variance from RydbergHamiltonian object at time time with register register

Parameters:

Name Type Description Default register StateVector

The state vector to take variance with

required time Optional[float]

Time value to evaluate average at.

None

Returns:

Name Type Description complex float

variance of energy at time time respectively.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@beartype\ndef variance(\n    self,\n    register: StateVector,\n    time: Optional[float] = None,\n) -> float:\n    \"\"\"Get the energy variance from RydbergHamiltonian object at\n    time `time` with register `register`\n\n    Args:\n        register (StateVector): The state vector to take variance with\n        time (Optional[float], optional): Time value to evaluate average at.\n        Defaults to duration of RydbergHamiltonian.\n\n    Returns:\n        complex: variance of energy at time `time` respectively.\n    \"\"\"\n\n    _, var = self.average_and_variance(register, time)\n    return var\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector","title":"StateVector dataclass","text":"
StateVector(data, space)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.local_trace","title":"local_trace","text":"
local_trace(matrix, site_index)\n

return trace of an operator over the StateVector.

Parameters:

Name Type Description Default matrix ndarray

Square matrix representing operator in the local hilbert space.

required site_index int | Tuple[int, int]

sites to apply one body operator to.

required

Returns:

Name Type Description complex complex

the trace of the operator over the state-vector.

Raises:

Type Description ValueError

Error is raised when the dimension of operator is not

ValueError

Error is raised when the site argument is out of bounds.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
@plum.dispatch\ndef local_trace(  # noqa: F811\n    self, matrix: np.ndarray, site_index: Union[int, Tuple[int, int]]\n) -> complex:  # noqa: F811\n    \"\"\"return trace of an operator over the StateVector.\n\n    Args:\n        matrix (np.ndarray): Square matrix representing operator in the local\n            hilbert space.\n        site_index (int | Tuple[int, int]): sites to apply one body operator to.\n\n    Returns:\n        complex: the trace of the operator over the state-vector.\n\n    Raises:\n        ValueError: Error is raised when the dimension of `operator` is not\n        consistent with `site` argument. The size of the operator must fit\n        the size of the local hilbert space of `site` depending on the number\n        of sites and the number of levels inside each atom, e.g. for two site\n        expectation value with a three level atom the operator must be a 9 by\n        9 array.\n\n        ValueError: Error is raised when the `site` argument is out of bounds.\n\n    \"\"\"\n    ...\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.norm","title":"norm","text":"
norm()\n

Return the norm of the state vector.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def norm(self) -> float:\n    \"\"\"Return the norm of the state vector.\"\"\"\n    return np.linalg.norm(self.data)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.normalize","title":"normalize","text":"
normalize()\n

Normalize the state vector.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def normalize(self) -> None:\n    \"\"\"Normalize the state vector.\"\"\"\n    data = self.data\n    data /= np.linalg.norm(data)\n
"},{"location":"reference/bloqade/analog/emulate/ir/state_vector/#bloqade.analog.emulate.ir.state_vector.StateVector.sample","title":"sample","text":"
sample(shots, project_hyperfine=True)\n

Sample the state vector and return bitstrings.

Source code in src/bloqade/analog/emulate/ir/state_vector.py
def sample(self, shots: int, project_hyperfine: bool = True) -> NDArray:\n    \"\"\"Sample the state vector and return bitstrings.\"\"\"\n    return self.space.sample_state_vector(\n        self.data, shots, project_hyperfine=project_hyperfine\n    )\n
"},{"location":"reference/bloqade/analog/ir/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.start","title":"start module-attribute","text":"
start = ListOfLocations()\n

A Program starting point, alias of empty ListOfLocations.

  • Next possible steps to build your program are:
  • Specify which level coupling to address with:
    • start.rydberg: for Rydberg Level coupling
    • start.hyperfine: for Hyperfine Level coupling
    • LOCKOUT: You cannot add atoms to your geometry after specifying level coupling.
  • continue/start building your geometry with:
    • start.add_position(): to add atom(s) to current register. It will accept:
      • A single coordinate, represented as a tuple (e.g. (5,6)) with a value that can either be:
        • integers: (5,6)
        • floats: (5.1, 2.5)
        • strings (for later variable assignment): (\"x\", \"y\")
        • Scalar objects: (2*cast(\"x\"), 5+cast(\"y\"))
      • A list of coordinates, represented as a list of types mentioned previously.
      • A numpy array with shape (n, 2) where n is the total number of atoms
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AlignedWaveform","title":"AlignedWaveform","text":"

Bases: Waveform

<padded waveform> ::= <waveform> | <waveform> <alignment> <value>\n\n<alignment> ::= 'left aligned' | 'right aligned'\n<value> ::= 'left value' | 'right value' | <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AnalogCircuit","title":"AnalogCircuit","text":"

AnalogCircuit is a dummy type that bundle register and sequence together.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AnalogCircuit.register","title":"register property","text":"
register\n

Get the register of the program.

Returns:

Type Description

register (Union[\"AtomArrangement\", \"ParallelRegister\"])

Note

If the program is built with parallelize(), The the register will be a ParallelRegister. Otherwise it will be a AtomArrangement.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AnalogCircuit.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the program

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the program

{} Source code in src/bloqade/analog/ir/analog_circuit.py
def show(self, **assignments):\n    \"\"\"Interactive visualization of the program\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the program\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais","title":"BoundedBravais","text":"
BoundedBravais(parent=None)\n

Bases: AtomArrangement

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.__match_args__","title":"__match_args__ class-attribute instance-attribute","text":"
__match_args__ = ('shape', 'lattice_spacing')\n

Base classe for Bravais lattices AtomArrangement.

  • Square
  • Chain
  • Honeycomb
  • Triangular
  • Lieb
  • Kagome
  • Rectangular
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.n_dims","title":"n_dims property","text":"
n_dims\n

dimension of the lattice

Returns:

Name Type Description int

dimension of the lattice

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.coordinates","title":"coordinates","text":"
coordinates(index)\n

calculate the coordinates of a cell in the lattice given the cell index.

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef coordinates(self, index: List[int]) -> NDArray:\n    \"\"\"calculate the coordinates of a cell in the lattice\n    given the cell index.\n    \"\"\"\n    # damn! this is like stone age broadcasting\n    vectors = np.array(self.cell_vectors())\n    index = np.array(index)\n    pos = np.sum(vectors.T * index, axis=1)\n    return pos + np.array(self.cell_atoms())\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.BoundedBravais.scale","title":"scale","text":"
scale(factor)\n

Scale the current location with a factor.

(x,y) -> factor*(x,y)

Parameters:

Name Type Description Default factor str | Real | Decimal | Scalar

scale factor

required

Returns:

Name Type Description BoundedBravais BoundedBravais

The lattice with the scaled locations

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef scale(self, factor: ScalarType) -> \"BoundedBravais\":\n    \"\"\"Scale the current location with a factor.\n\n    (x,y) -> factor*(x,y)\n\n    Args:\n        factor (str | Real | Decimal | Scalar): scale factor\n\n    Returns:\n        BoundedBravais: The lattice with the scaled locations\n    \"\"\"\n    factor = cast(factor)\n    obj = self.__new__(type(self))\n    for f in fields(self):\n        if f.name == \"lattice_spacing\":\n            obj.lattice_spacing = factor * self.lattice_spacing\n        else:\n            setattr(obj, f.name, getattr(self, f.name))\n    return obj\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Constant","title":"Constant","text":"
Constant(value, duration)\n

Bases: Instruction

<constant> ::= 'constant' <scalar expr>\n

f(t=0:duration) = value

Parameters:

Name Type Description Default value Scalar

the constant value

required duration Scalar

the time span of the constant waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, value: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"value\", cast(value))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Field","title":"Field","text":"

Bases: FieldExpr

Field node in the IR. Which contains collection(s) of Waveform

<field> ::= ('field' <spatial modulation>  <padded waveform>)*\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Field.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Field

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Field

{} Source code in src/bloqade/analog/ir/control/field.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Field\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Field\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Linear","title":"Linear","text":"
Linear(start, stop, duration)\n

Bases: Instruction

<linear> ::= 'linear' <scalar expr> <scalar expr>\n

f(t=0:duration) = start + (stop-start)/duration * t

Parameters:

Name Type Description Default start Scalar

start value

required stop Scalar

stop value

required duration Scalar

the time span of the linear waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, start: ScalarType, stop: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"start\", cast(start))\n    object.__setattr__(self, \"stop\", cast(stop))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Literal","title":"Literal","text":"

Bases: Real

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Literal.value","title":"value instance-attribute","text":"
value\n

Scalar Literal, which stores a decimaal value instance.

Parameters:

Name Type Description Default value Decimal

decimal value instance

required"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Poly","title":"Poly","text":"
Poly(coeffs, duration)\n

Bases: Instruction

<poly> ::= <scalar>+\n

f(t=0:duration) = c[0] + c[1]t + c[2]t^2 + ... + c[n-1]t^n-1 + c[n]t^n

Parameters:

Name Type Description Default coeffs Tuple[Scalar]

the coefficients c[] of the polynomial.

required duration Scalar

the time span of the waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, coeffs: Container[ScalarType], duration: ScalarType):\n    object.__setattr__(self, \"coeffs\", tuple(map(cast, coeffs)))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Pulse","title":"Pulse","text":"

Bases: PulseExpr

<pulse> ::= (<field name> <field>)+\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Pulse.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Pulse

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Pulse

{} Source code in src/bloqade/analog/ir/control/pulse.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Pulse\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Pulse\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.PythonFn","title":"PythonFn","text":"

Bases: Instruction

<python-fn> ::= 'python-fn' <python function def> <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Record","title":"Record","text":"

Bases: Waveform

<record> ::= 'record' <waveform> <var> <side>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Sample","title":"Sample","text":"

Bases: Waveform

<sample> ::= 'sample' <waveform> <interpolation> <scalar>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Scalar","title":"Scalar","text":"

Base class for all scalar expressions.

<scalar> ::= <literal>\n| <variable>\n| <default>\n| <negative>\n| <add>\n| <mul>\n| <min>\n| <max>\n| <slice>\n| <inverval>\n\n<mul> ::= <scalar> '*' <scalar>\n<add> ::= <scalar> '+' <scalar>\n<min> ::= 'min' <scalar>+\n<max> ::= 'max' <scalar>+\n<slice> ::= <scalar expr> '[' <interval> ']'\n<interval> ::= <scalar expr> '..' <scalar expr>\n<real> ::= <literal> | <var>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Sequence","title":"Sequence","text":"

Bases: SequenceExpr

Sequence of a program, which includes pulses informations.

"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Sequence.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Sequence

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Sequence

{} Source code in src/bloqade/analog/ir/control/sequence.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Sequence\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Sequence\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Variable","title":"Variable","text":"

Bases: Real

Variable, which stores a variable name.

Parameters:

Name Type Description Default name str

variable instance.

required"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Waveform","title":"Waveform","text":"

Bases: HashTrait, CanonicalizeTrait

Waveform node in the IR.

  • <instruction>
  • <smooth>
  • <slice>
  • <apppend>
  • <negative>
  • <scale>
  • <add>
  • <record>
  • <sample>
<waveform> ::= <instruction>\n    | <smooth>\n    | <slice>\n    | <append>\n    | <negative>\n    | <scale>\n    | <add>\n    | <record>\n    | <sample>\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.Waveform.figure","title":"figure","text":"
figure(**assignments)\n

get figure of the plotting the waveform.

Returns:

Name Type Description figure

a bokeh figure

Source code in src/bloqade/analog/ir/control/waveform.py
def figure(self, **assignments):\n    \"\"\"get figure of the plotting the waveform.\n\n    Returns:\n        figure: a bokeh figure\n    \"\"\"\n    return get_ir_figure(self, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.cast","title":"cast","text":"
cast(py)\n
  1. cast Real number (or list/tuple of Real numbers) to Scalar Literal.

  2. cast str (or list/tuple of Real numbers) to Scalar Variable.

Parameters:

Name Type Description Default py Union[str, Real, Tuple[Real], List[Real]]

python object to cast

required

Returns:

Type Description Scalar

Scalar

Source code in src/bloqade/analog/ir/scalar.py
def cast(py) -> \"Scalar\":\n    \"\"\"\n    1. cast Real number (or list/tuple of Real numbers)\n    to [`Scalar Literal`][bloqade.ir.scalar.Literal].\n\n    2. cast str (or list/tuple of Real numbers)\n    to [`Scalar Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str,Real,Tuple[Real],List[Real]]): python object to cast\n\n    Returns:\n        Scalar\n    \"\"\"\n    ret = trycast(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Scalar Literal\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/#bloqade.analog.ir.var","title":"var","text":"
var(py)\n

cast string (or list/tuple of strings) to Variable.

Parameters:

Name Type Description Default py Union[str, List[str]]

a string or list/tuple of strings

required

Returns:

Type Description Variable

Union[Variable]

Source code in src/bloqade/analog/ir/scalar.py
def var(py: str) -> \"Variable\":\n    \"\"\"cast string (or list/tuple of strings)\n    to [`Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str, List[str]]): a string or list/tuple of strings\n\n    Returns:\n       Union[Variable]\n    \"\"\"\n    ret = tryvar(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Variable\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/analog_circuit/","title":"Analog circuit","text":""},{"location":"reference/bloqade/analog/ir/analog_circuit/#bloqade.analog.ir.analog_circuit.AnalogCircuit","title":"AnalogCircuit","text":"

AnalogCircuit is a dummy type that bundle register and sequence together.

"},{"location":"reference/bloqade/analog/ir/analog_circuit/#bloqade.analog.ir.analog_circuit.AnalogCircuit.register","title":"register property","text":"
register\n

Get the register of the program.

Returns:

Type Description

register (Union[\"AtomArrangement\", \"ParallelRegister\"])

Note

If the program is built with parallelize(), The the register will be a ParallelRegister. Otherwise it will be a AtomArrangement.

"},{"location":"reference/bloqade/analog/ir/analog_circuit/#bloqade.analog.ir.analog_circuit.AnalogCircuit.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the program

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the program

{} Source code in src/bloqade/analog/ir/analog_circuit.py
def show(self, **assignments):\n    \"\"\"Interactive visualization of the program\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the program\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/scalar/","title":"Scalar","text":""},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Literal","title":"Literal","text":"

Bases: Real

"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Literal.value","title":"value instance-attribute","text":"
value\n

Scalar Literal, which stores a decimaal value instance.

Parameters:

Name Type Description Default value Decimal

decimal value instance

required"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Scalar","title":"Scalar","text":"

Base class for all scalar expressions.

<scalar> ::= <literal>\n| <variable>\n| <default>\n| <negative>\n| <add>\n| <mul>\n| <min>\n| <max>\n| <slice>\n| <inverval>\n\n<mul> ::= <scalar> '*' <scalar>\n<add> ::= <scalar> '+' <scalar>\n<min> ::= 'min' <scalar>+\n<max> ::= 'max' <scalar>+\n<slice> ::= <scalar expr> '[' <interval> ']'\n<interval> ::= <scalar expr> '..' <scalar expr>\n<real> ::= <literal> | <var>\n
"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.Variable","title":"Variable","text":"

Bases: Real

Variable, which stores a variable name.

Parameters:

Name Type Description Default name str

variable instance.

required"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.cast","title":"cast","text":"
cast(py)\n
  1. cast Real number (or list/tuple of Real numbers) to Scalar Literal.

  2. cast str (or list/tuple of Real numbers) to Scalar Variable.

Parameters:

Name Type Description Default py Union[str, Real, Tuple[Real], List[Real]]

python object to cast

required

Returns:

Type Description Scalar

Scalar

Source code in src/bloqade/analog/ir/scalar.py
def cast(py) -> \"Scalar\":\n    \"\"\"\n    1. cast Real number (or list/tuple of Real numbers)\n    to [`Scalar Literal`][bloqade.ir.scalar.Literal].\n\n    2. cast str (or list/tuple of Real numbers)\n    to [`Scalar Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str,Real,Tuple[Real],List[Real]]): python object to cast\n\n    Returns:\n        Scalar\n    \"\"\"\n    ret = trycast(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Scalar Literal\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/scalar/#bloqade.analog.ir.scalar.var","title":"var","text":"
var(py)\n

cast string (or list/tuple of strings) to Variable.

Parameters:

Name Type Description Default py Union[str, List[str]]

a string or list/tuple of strings

required

Returns:

Type Description Variable

Union[Variable]

Source code in src/bloqade/analog/ir/scalar.py
def var(py: str) -> \"Variable\":\n    \"\"\"cast string (or list/tuple of strings)\n    to [`Variable`][bloqade.ir.scalar.Variable].\n\n    Args:\n        py (Union[str, List[str]]): a string or list/tuple of strings\n\n    Returns:\n       Union[Variable]\n    \"\"\"\n    ret = tryvar(py)\n    if ret is None:\n        raise TypeError(f\"Cannot cast {type(py)} to Variable\")\n\n    return ret\n
"},{"location":"reference/bloqade/analog/ir/control/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/control/field/","title":"Field","text":""},{"location":"reference/bloqade/analog/ir/control/field/#bloqade.analog.ir.control.field.Field","title":"Field","text":"

Bases: FieldExpr

Field node in the IR. Which contains collection(s) of Waveform

<field> ::= ('field' <spatial modulation>  <padded waveform>)*\n
"},{"location":"reference/bloqade/analog/ir/control/field/#bloqade.analog.ir.control.field.Field.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Field

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Field

{} Source code in src/bloqade/analog/ir/control/field.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Field\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Field\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/","title":"Pulse","text":""},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.Append","title":"Append","text":"

Bases: AppendTrait, PulseExpr

<append> ::= <expr>+\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.Pulse","title":"Pulse","text":"

Bases: PulseExpr

<pulse> ::= (<field name> <field>)+\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.Pulse.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Pulse

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Pulse

{} Source code in src/bloqade/analog/ir/control/pulse.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Pulse\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Pulse\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/pulse/#bloqade.analog.ir.control.pulse.PulseExpr","title":"PulseExpr","text":"

Bases: HashTrait, CanonicalizeTrait

<expr> ::= <pulse>\n  | <append>\n  | <slice>\n  | <named>\n
"},{"location":"reference/bloqade/analog/ir/control/sequence/","title":"Sequence","text":""},{"location":"reference/bloqade/analog/ir/control/sequence/#bloqade.analog.ir.control.sequence.Sequence","title":"Sequence","text":"

Bases: SequenceExpr

Sequence of a program, which includes pulses informations.

"},{"location":"reference/bloqade/analog/ir/control/sequence/#bloqade.analog.ir.control.sequence.Sequence.show","title":"show","text":"
show(**assignments)\n

Interactive visualization of the Sequence

Parameters:

Name Type Description Default **assignments

assigning the instance value (literal) to the existing variables in the Sequence

{} Source code in src/bloqade/analog/ir/control/sequence.py
def show(self, **assignments):\n    \"\"\"\n    Interactive visualization of the Sequence\n\n    Args:\n        **assignments: assigning the instance value (literal) to the\n            existing variables in the Sequence\n\n    \"\"\"\n    display_ir(self, assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/","title":"Waveform","text":""},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Add","title":"Add","text":"

Bases: Waveform

<add> ::= <waveform> '+' <waveform>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.AlignedWaveform","title":"AlignedWaveform","text":"

Bases: Waveform

<padded waveform> ::= <waveform> | <waveform> <alignment> <value>\n\n<alignment> ::= 'left aligned' | 'right aligned'\n<value> ::= 'left value' | 'right value' | <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Append","title":"Append","text":"

Bases: AppendTrait, Waveform

<append> ::= <waveform>+\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Constant","title":"Constant","text":"
Constant(value, duration)\n

Bases: Instruction

<constant> ::= 'constant' <scalar expr>\n

f(t=0:duration) = value

Parameters:

Name Type Description Default value Scalar

the constant value

required duration Scalar

the time span of the constant waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, value: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"value\", cast(value))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Instruction","title":"Instruction","text":"

Bases: Waveform

Instruction node in the IR.

  • <linear>
  • <constant>
  • <poly>
  • <python-fn>
<instruction> ::= <linear>\n    | <constant>\n    | <poly>\n    | <python-fn>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Linear","title":"Linear","text":"
Linear(start, stop, duration)\n

Bases: Instruction

<linear> ::= 'linear' <scalar expr> <scalar expr>\n

f(t=0:duration) = start + (stop-start)/duration * t

Parameters:

Name Type Description Default start Scalar

start value

required stop Scalar

stop value

required duration Scalar

the time span of the linear waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, start: ScalarType, stop: ScalarType, duration: ScalarType):\n    object.__setattr__(self, \"start\", cast(start))\n    object.__setattr__(self, \"stop\", cast(stop))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Negative","title":"Negative","text":"

Bases: Waveform

<negative> ::= '-' <waveform>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Poly","title":"Poly","text":"
Poly(coeffs, duration)\n

Bases: Instruction

<poly> ::= <scalar>+\n

f(t=0:duration) = c[0] + c[1]t + c[2]t^2 + ... + c[n-1]t^n-1 + c[n]t^n

Parameters:

Name Type Description Default coeffs Tuple[Scalar]

the coefficients c[] of the polynomial.

required duration Scalar

the time span of the waveform.

required Source code in src/bloqade/analog/ir/control/waveform.py
@beartype\ndef __init__(self, coeffs: Container[ScalarType], duration: ScalarType):\n    object.__setattr__(self, \"coeffs\", tuple(map(cast, coeffs)))\n    object.__setattr__(self, \"duration\", cast(duration))\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.PythonFn","title":"PythonFn","text":"

Bases: Instruction

<python-fn> ::= 'python-fn' <python function def> <scalar expr>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Record","title":"Record","text":"

Bases: Waveform

<record> ::= 'record' <waveform> <var> <side>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Sample","title":"Sample","text":"

Bases: Waveform

<sample> ::= 'sample' <waveform> <interpolation> <scalar>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Scale","title":"Scale","text":"
Scale(scalar, waveform)\n

Bases: Waveform

<scale> ::= <scalar expr> '*' <waveform>\n
Source code in src/bloqade/analog/ir/control/waveform.py
def __init__(self, scalar, waveform: Waveform):\n    object.__setattr__(self, \"scalar\", cast(scalar))\n    object.__setattr__(self, \"waveform\", waveform)\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Slice","title":"Slice","text":"

Bases: SliceTrait, Waveform

<slice> ::= <waveform> <scalar.interval>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Smooth","title":"Smooth","text":"
Smooth(radius, kernel, waveform)\n

Bases: Waveform

<smooth> ::= 'smooth' <kernel> <waveform>\n
Source code in src/bloqade/analog/ir/control/waveform.py
def __init__(self, radius, kernel, waveform):\n    if isinstance(kernel, str):\n        if kernel == \"Gaussian\":\n            kernel = GaussianKernel\n        elif kernel == \"Logistic\":\n            kernel = LogisticKernel\n        elif kernel == \"Sigmoid\":\n            kernel = SigmoidKernel\n        elif kernel == \"Triangle\":\n            kernel = TriangleKernel\n        elif kernel == \"Uniform\":\n            kernel = UniformKernel\n        elif kernel == \"Parabolic\":\n            kernel = ParabolicKernel\n        elif kernel == \"Biweight\":\n            kernel = BiweightKernel\n        elif kernel == \"Triweight\":\n            kernel = TriweightKernel\n        elif kernel == \"Tricube\":\n            kernel = TricubeKernel\n        elif kernel == \"Cosine\":\n            kernel = CosineKernel\n        else:\n            raise ValueError(f\"Invalid kernel: {kernel}\")\n\n    object.__setattr__(self, \"radius\", cast(radius))\n    object.__setattr__(self, \"kernel\", kernel)\n    object.__setattr__(self, \"waveform\", waveform)\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Waveform","title":"Waveform","text":"

Bases: HashTrait, CanonicalizeTrait

Waveform node in the IR.

  • <instruction>
  • <smooth>
  • <slice>
  • <apppend>
  • <negative>
  • <scale>
  • <add>
  • <record>
  • <sample>
<waveform> ::= <instruction>\n    | <smooth>\n    | <slice>\n    | <append>\n    | <negative>\n    | <scale>\n    | <add>\n    | <record>\n    | <sample>\n
"},{"location":"reference/bloqade/analog/ir/control/waveform/#bloqade.analog.ir.control.waveform.Waveform.figure","title":"figure","text":"
figure(**assignments)\n

get figure of the plotting the waveform.

Returns:

Name Type Description figure

a bokeh figure

Source code in src/bloqade/analog/ir/control/waveform.py
def figure(self, **assignments):\n    \"\"\"get figure of the plotting the waveform.\n\n    Returns:\n        figure: a bokeh figure\n    \"\"\"\n    return get_ir_figure(self, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/control/traits/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/control/traits/#bloqade.analog.ir.control.traits.SliceTrait","title":"SliceTrait","text":""},{"location":"reference/bloqade/analog/ir/control/traits/#bloqade.analog.ir.control.traits.SliceTrait.start","title":"start cached property","text":"
start\n

Start time of the sliced object

Returns:

Name Type Description Scalar Scalar

The starting time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/control/traits/#bloqade.analog.ir.control.traits.SliceTrait.stop","title":"stop cached property","text":"
stop\n

Stop time of the sliced object

Returns:

Name Type Description Scalar Scalar

The stopping time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/control/traits/append/","title":"Append","text":""},{"location":"reference/bloqade/analog/ir/control/traits/canonicalize/","title":"Canonicalize","text":""},{"location":"reference/bloqade/analog/ir/control/traits/hash/","title":"Hash","text":""},{"location":"reference/bloqade/analog/ir/control/traits/slice/","title":"Slice","text":""},{"location":"reference/bloqade/analog/ir/control/traits/slice/#bloqade.analog.ir.control.traits.slice.SliceTrait","title":"SliceTrait","text":""},{"location":"reference/bloqade/analog/ir/control/traits/slice/#bloqade.analog.ir.control.traits.slice.SliceTrait.start","title":"start cached property","text":"
start\n

Start time of the sliced object

Returns:

Name Type Description Scalar Scalar

The starting time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/control/traits/slice/#bloqade.analog.ir.control.traits.slice.SliceTrait.stop","title":"stop cached property","text":"
stop\n

Stop time of the sliced object

Returns:

Name Type Description Scalar Scalar

The stopping time of the sliced object as a

Scalar

Scalar Expression

"},{"location":"reference/bloqade/analog/ir/location/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.start","title":"start module-attribute","text":"
start = ListOfLocations()\n

A Program starting point, alias of empty ListOfLocations.

  • Next possible steps to build your program are:
  • Specify which level coupling to address with:
    • start.rydberg: for Rydberg Level coupling
    • start.hyperfine: for Hyperfine Level coupling
    • LOCKOUT: You cannot add atoms to your geometry after specifying level coupling.
  • continue/start building your geometry with:
    • start.add_position(): to add atom(s) to current register. It will accept:
      • A single coordinate, represented as a tuple (e.g. (5,6)) with a value that can either be:
        • integers: (5,6)
        • floats: (5.1, 2.5)
        • strings (for later variable assignment): (\"x\", \"y\")
        • Scalar objects: (2*cast(\"x\"), 5+cast(\"y\"))
      • A list of coordinates, represented as a list of types mentioned previously.
      • A numpy array with shape (n, 2) where n is the total number of atoms
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais","title":"BoundedBravais","text":"
BoundedBravais(parent=None)\n

Bases: AtomArrangement

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.__match_args__","title":"__match_args__ class-attribute instance-attribute","text":"
__match_args__ = ('shape', 'lattice_spacing')\n

Base classe for Bravais lattices AtomArrangement.

  • Square
  • Chain
  • Honeycomb
  • Triangular
  • Lieb
  • Kagome
  • Rectangular
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.n_dims","title":"n_dims property","text":"
n_dims\n

dimension of the lattice

Returns:

Name Type Description int

dimension of the lattice

"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.coordinates","title":"coordinates","text":"
coordinates(index)\n

calculate the coordinates of a cell in the lattice given the cell index.

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef coordinates(self, index: List[int]) -> NDArray:\n    \"\"\"calculate the coordinates of a cell in the lattice\n    given the cell index.\n    \"\"\"\n    # damn! this is like stone age broadcasting\n    vectors = np.array(self.cell_vectors())\n    index = np.array(index)\n    pos = np.sum(vectors.T * index, axis=1)\n    return pos + np.array(self.cell_atoms())\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.BoundedBravais.scale","title":"scale","text":"
scale(factor)\n

Scale the current location with a factor.

(x,y) -> factor*(x,y)

Parameters:

Name Type Description Default factor str | Real | Decimal | Scalar

scale factor

required

Returns:

Name Type Description BoundedBravais BoundedBravais

The lattice with the scaled locations

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef scale(self, factor: ScalarType) -> \"BoundedBravais\":\n    \"\"\"Scale the current location with a factor.\n\n    (x,y) -> factor*(x,y)\n\n    Args:\n        factor (str | Real | Decimal | Scalar): scale factor\n\n    Returns:\n        BoundedBravais: The lattice with the scaled locations\n    \"\"\"\n    factor = cast(factor)\n    obj = self.__new__(type(self))\n    for f in fields(self):\n        if f.name == \"lattice_spacing\":\n            obj.lattice_spacing = factor * self.lattice_spacing\n        else:\n            setattr(obj, f.name, getattr(self, f.name))\n    return obj\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/#bloqade.analog.ir.location.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/","title":"Bravais","text":""},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais","title":"BoundedBravais","text":"
BoundedBravais(parent=None)\n

Bases: AtomArrangement

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.__match_args__","title":"__match_args__ class-attribute instance-attribute","text":"
__match_args__ = ('shape', 'lattice_spacing')\n

Base classe for Bravais lattices AtomArrangement.

  • Square
  • Chain
  • Honeycomb
  • Triangular
  • Lieb
  • Kagome
  • Rectangular
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.n_dims","title":"n_dims property","text":"
n_dims\n

dimension of the lattice

Returns:

Name Type Description int

dimension of the lattice

"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.coordinates","title":"coordinates","text":"
coordinates(index)\n

calculate the coordinates of a cell in the lattice given the cell index.

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef coordinates(self, index: List[int]) -> NDArray:\n    \"\"\"calculate the coordinates of a cell in the lattice\n    given the cell index.\n    \"\"\"\n    # damn! this is like stone age broadcasting\n    vectors = np.array(self.cell_vectors())\n    index = np.array(index)\n    pos = np.sum(vectors.T * index, axis=1)\n    return pos + np.array(self.cell_atoms())\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.BoundedBravais.scale","title":"scale","text":"
scale(factor)\n

Scale the current location with a factor.

(x,y) -> factor*(x,y)

Parameters:

Name Type Description Default factor str | Real | Decimal | Scalar

scale factor

required

Returns:

Name Type Description BoundedBravais BoundedBravais

The lattice with the scaled locations

Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef scale(self, factor: ScalarType) -> \"BoundedBravais\":\n    \"\"\"Scale the current location with a factor.\n\n    (x,y) -> factor*(x,y)\n\n    Args:\n        factor (str | Real | Decimal | Scalar): scale factor\n\n    Returns:\n        BoundedBravais: The lattice with the scaled locations\n    \"\"\"\n    factor = cast(factor)\n    obj = self.__new__(type(self))\n    for f in fields(self):\n        if f.name == \"lattice_spacing\":\n            obj.lattice_spacing = factor * self.lattice_spacing\n        else:\n            setattr(obj, f.name, getattr(self, f.name))\n    return obj\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Chain","title":"Chain","text":"
Chain(L, *, lattice_spacing=1.0, vertical_chain=False)\n

Bases: BoundedBravais

Chain lattice.

  • 1D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0).
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L int

number of sites in the chain

required lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L: int, *, lattice_spacing: ScalarType = 1.0, vertical_chain: bool = False\n):\n    self.L = L\n    self.lattice_spacing = cast(lattice_spacing)\n    self.vertical_chain = vertical_chain\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Honeycomb","title":"Honeycomb","text":"
Honeycomb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Honeycomb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (2 atom(s))
    • loc1 (0, 0)
    • loc2 (\u00bd, 1/(2*sqrt(3))

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = L1 * L1 * 2.

required L2 Optional[int]

number of unit cells in direction a2. n_atoms = L1 * L2 * 2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Kagome","title":"Kagome","text":"
Kagome(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Kagome lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0.25 ,0.25sqrt(3))

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = 3 * L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Lieb","title":"Lieb","text":"
Lieb(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Lieb lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (0, 1)
  • unit cell (3 atom(s))
    • loc1 (0, 0)
    • loc2 (0.5, 0)
    • loc3 (0 ,0.5)

Parameters:

Name Type Description Default L1 int

number of unit cells in linear direction. n_atoms = 3* L1 * L1.

required L2 Optional[int]

number of unit cells along a2 direction, n_atoms = 3 * L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Rectangular","title":"Rectangular","text":"
Rectangular(\n    width,\n    height,\n    *,\n    lattice_spacing_x=1.0,\n    lattice_spacing_y=1.0\n)\n

Bases: BoundedBravais

Rectangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default width int

number of sites in x direction.

required height int

number of sites in y direction.

required lattice_spacing_x (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0 lattice_spacing_y (Scalar, Real)

lattice spacing in y direction. optional.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self,\n    width: int,\n    height: int,\n    *,\n    lattice_spacing_x: ScalarType = 1.0,\n    lattice_spacing_y: ScalarType = 1.0,\n):\n    self.width = width\n    self.height = height\n    self.lattice_spacing_x = cast(lattice_spacing_x)\n    self.lattice_spacing_y = (\n        cast(lattice_spacing_y)\n        if lattice_spacing_y is not None\n        else self.lattice_spacing_x\n    )\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Square","title":"Square","text":"
Square(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Square lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1,0)
    • a2 = (0,1)
  • unit cell (1 atom(s))
    • loc (0,0)

Parameters:

Name Type Description Default L1 int

number of sites in linear direction. n_atoms = L1 * L1.

required L2 Optional[int]

number of sites in direction a2. n_atoms = L1 * L2, default is L1

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/bravais/#bloqade.analog.ir.location.bravais.Triangular","title":"Triangular","text":"
Triangular(L1, L2=None, *, lattice_spacing=1.0)\n

Bases: BoundedBravais

Triangular lattice.

  • 2D lattice
  • primitive (cell) vector(s)
    • a1 = (1, 0)
    • a2 = (\u00bd, sqrt(3)/2)
  • unit cell (1 atom(s))
    • loc (0, 0)

Parameters:

Name Type Description Default L int

number of sites in linear direction. n_atoms = L * L.

required L2 Optional[int]

number of sites along a2 direction, n_atoms = L1 * L2, default is L1.

None lattice_spacing (Scalar, Real)

lattice spacing. Defaults to 1.0.

1.0
  • Possible Next: continue with . to see possible next step in auto-prompt supported setting (IPython, IDE ...)
Source code in src/bloqade/analog/ir/location/bravais.py
@beartype\ndef __init__(\n    self, L1: int, L2: Optional[int] = None, *, lattice_spacing: ScalarType = 1.0\n):\n    if L2 is None:\n        L2 = L1\n    self.L1 = L1\n    self.L2 = L2\n    self.lattice_spacing = cast(lattice_spacing)\n\n    super().__init__()\n
"},{"location":"reference/bloqade/analog/ir/location/location/","title":"Location","text":""},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement","title":"AtomArrangement","text":"
AtomArrangement(parent=None)\n

Bases: ProgramStart

Source code in src/bloqade/analog/builder/base.py
def __init__(\n    self,\n    parent: Optional[\"Builder\"] = None,\n) -> None:\n    self.__parent__ = parent\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_atoms","title":"n_atoms property","text":"
n_atoms\n

number of atoms (filled sites) in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_dims","title":"n_dims property","text":"
n_dims\n

number of dimensions in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_sites","title":"n_sites property","text":"
n_sites\n

number of sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.n_vacant","title":"n_vacant property","text":"
n_vacant\n

number of vacant sites in the register.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.add_position","title":"add_position","text":"
add_position(position, filling=None)\n

Add a position or multiple positions to a pre-existing geometry.

add_position is capable of accepting: - A single tuple for one atom coordinate: (1.0, 2.5) - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.] - A numpy array of shape (N, 2) where N is the number of atoms

You may also intersperse variables anywhere a value may be present.

You can also pass in an optional argument which determines the atom \"filling\" (whether or not at a specified coordinate an atom should be present).

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.add_position--usage-example","title":"Usage Example:","text":"
# single coordinate\n>>> reg = start.add_position((0,0))\n# you may chain add_position calls\n>>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n# you can add variables anywhere a value may be present\n>>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n# and specify your atom fillings\n>>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n[True, False])\n# alternatively you could use one boolean to specify\n# all coordinates should be empty/filled\n>>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n(5.2, 2.2)], False)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
def add_position(\n    self,\n    position: Union[\n        PositionArray,\n        List[Tuple[ScalarType, ScalarType]],\n        Tuple[ScalarType, ScalarType],\n    ],\n    filling: Optional[Union[BoolArray, List[bool], bool]] = None,\n) -> \"ListOfLocations\":\n    \"\"\"\n    Add a position or multiple positions to a pre-existing geometry.\n\n    `add_position` is capable of accepting:\n    - A single tuple for one atom coordinate: `(1.0, 2.5)`\n    - A list of tuples: `[(0.0, 1.0), (2.0,1.5), etc.]\n    - A numpy array of shape (N, 2) where N is the number of atoms\n\n    You may also intersperse variables anywhere a value may be present.\n\n    You can also pass in an optional argument which determines the atom \"filling\"\n    (whether or not at a specified coordinate an atom should be present).\n\n    ### Usage Example:\n    ```\n    # single coordinate\n    >>> reg = start.add_position((0,0))\n    # you may chain add_position calls\n    >>> reg_plus_two = reg.add_position([(2,2),(5.0, 2.1)])\n    # you can add variables anywhere a value may be present\n    >>> reg_with_var = reg_plus_two.add_position((\"x\", \"y\"))\n    # and specify your atom fillings\n    >>> reg_with_filling = reg_with_var.add_position([(3.1, 0.0), (4.1, 2.2)],\n    [True, False])\n    # alternatively you could use one boolean to specify\n    # all coordinates should be empty/filled\n    >>> reg_with_more_filling = reg_with_filling.add_positions([(3.1, 2.9),\n    (5.2, 2.2)], False)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`: to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`: to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    if is_bearable(position, PositionArray) and is_bearable(\n        filling, Optional[BoolArray]\n    ):\n        return self.add_position_ndarray(position, filling)\n    elif is_bearable(position, List[Tuple[ScalarType, ScalarType]]) and is_bearable(\n        filling, Optional[List[bool]]\n    ):\n        return self.add_position_list_tuples(position, filling)\n    elif is_bearable(position, Tuple[ScalarType, ScalarType]) and is_bearable(\n        filling, Optional[bool]\n    ):\n        return self.add_position_single_tupe(position, filling)\n    else:\n        raise TypeError(\"Invalid input types for add_position provided!\")\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_count","title":"apply_defect_count","text":"
apply_defect_count(n_defects, rng=np.random.default_rng())\n

Drop n_defects atoms from the geometry randomly. Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_count--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_count(2, custom_rng)\n# you may also chain apply_defect_count calls\n>>> reg.apply_defect_count(2, custom_rng)\n# you can also use apply_defect_count on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts) .apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_count(\n    self, n_defects: int, rng: np.random.Generator = np.random.default_rng()\n):\n    \"\"\"\n    Drop `n_defects` atoms from the geometry randomly. Internally this occurs\n    by setting certain sites to have a SiteFilling set to false indicating\n    no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_count(2, custom_rng)\n    # you may also chain apply_defect_count calls\n    >>> reg.apply_defect_count(2, custom_rng)\n    # you can also use apply_defect_count on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)]).apply_defect_count(1, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n            to add more positions\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_count(n_defects)`: to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n            .apply_defect_density(defect_probability)`:\n            to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n            to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`: to specify\n            Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n            to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n            shows your geometry in your web browser\n    \"\"\"\n\n    location_list = []\n    for location_info in self.enumerate():\n        location_list.append(location_info)\n\n    filled_sites = []\n\n    for index, location_info in enumerate(location_list):\n        if location_info.filling is SiteFilling.filled:\n            filled_sites.append(index)\n\n    if n_defects >= len(filled_sites):\n        raise ValueError(\n            f\"n_defects {n_defects} must be less than the number of filled sites \"\n            f\"({len(filled_sites)})\"\n        )\n\n    for _ in range(n_defects):\n        index = rng.choice(filled_sites)\n        location_list[index] = LocationInfo.create(\n            location_list[index].position,\n            (False if location_list[index].filling is SiteFilling.filled else True),\n        )\n        filled_sites.remove(index)\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_density","title":"apply_defect_density","text":"
apply_defect_density(\n    defect_probability, rng=np.random.default_rng()\n)\n

Drop atoms randomly with defect_probability probability (range of 0 to 1). Internally this occurs by setting certain sites to have a SiteFilling set to false indicating no atom is present at the coordinate.

A default numpy-based Random Number Generator is used but you can explicitly override this by passing in your own.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.apply_defect_density--usage-example","title":"Usage Example:","text":"
>>> from bloqade.analog.atom_arrangement import Chain\n>>> import numpy as np\n# set a custom seed for a numpy-based RNG\n>>> custom_rng = np.random.default_rng(888)\n# randomly remove two atoms from the geometry\n>>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n# you may also chain apply_defect_density calls\n>>> reg.apply_defect_count(0.1, custom_rng)\n# you can also use apply_defect_density on custom geometries\n>>> from bloqade import start\n>>> start.add_position([(0,0), (1,1)])\n.apply_defect_density(0.5, custom_rng)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...apply_defect_count(defect_counts).add_position(positions): to add more positions
    • ...apply_defect_count(defect_counts).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...apply_defect_count(defect_counts) .apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...apply_defect_count(defect_counts).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...apply_defect_count(defect_counts).rydberg: to specify Rydberg coupling
    • ...apply_defect_count(defect_counts).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...apply_defect_count(defect_counts).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef apply_defect_density(\n    self,\n    defect_probability: float,\n    rng: np.random.Generator = np.random.default_rng(),\n):\n    \"\"\"\n    Drop atoms randomly with `defect_probability` probability (range of 0 to 1).\n    Internally this occurs by setting certain sites to have a SiteFilling\n    set to false indicating no atom is present at the coordinate.\n\n    A default numpy-based Random Number Generator is used but you can\n    explicitly override this by passing in your own.\n\n    ### Usage Example:\n\n    ```\n    >>> from bloqade.analog.atom_arrangement import Chain\n    >>> import numpy as np\n    # set a custom seed for a numpy-based RNG\n    >>> custom_rng = np.random.default_rng(888)\n    # randomly remove two atoms from the geometry\n    >>> reg = Chain(11).apply_defect_density(0.2, custom_rng)\n    # you may also chain apply_defect_density calls\n    >>> reg.apply_defect_count(0.1, custom_rng)\n    # you can also use apply_defect_density on custom geometries\n    >>> from bloqade import start\n    >>> start.add_position([(0,0), (1,1)])\n    .apply_defect_density(0.5, custom_rng)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...apply_defect_count(defect_counts).add_position(positions)`:\n        to add more positions\n        - `...apply_defect_count(defect_counts).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...apply_defect_count(defect_counts)\n        .apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...apply_defect_count(defect_counts).scale(scale)`:\n        to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...apply_defect_count(defect_counts).rydberg`:\n        to specify Rydberg coupling\n        - `...apply_defect_count(defect_counts).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...apply_defect_count(defect_counts).show()`:\n        shows your geometry in your web browser\n    \"\"\"\n\n    p = min(1, max(0, defect_probability))\n    location_list = []\n\n    for location_info in self.enumerate():\n        if rng.random() < p:\n            location_list.append(\n                LocationInfo.create(\n                    location_info.position,\n                    (\n                        False\n                        if location_info.filling is SiteFilling.filled\n                        else True\n                    ),\n                )\n            )\n        else:\n            location_list.append(location_info)\n\n    return ListOfLocations(location_list=location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.enumerate","title":"enumerate","text":"
enumerate()\n

enumerate all locations in the register.

Source code in src/bloqade/analog/ir/location/location.py
def enumerate(self) -> Generator[LocationInfo, None, None]:\n    \"\"\"enumerate all locations in the register.\"\"\"\n    raise NotImplementedError\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.figure","title":"figure","text":"
figure(fig_kwargs=None, **assignments)\n

obtain a figure object from the atom arrangement.

Source code in src/bloqade/analog/ir/location/location.py
def figure(self, fig_kwargs=None, **assignments):\n    \"\"\"obtain a figure object from the atom arrangement.\"\"\"\n    return get_atom_arrangement_figure(self, fig_kwargs=fig_kwargs, **assignments)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.rydberg_interaction","title":"rydberg_interaction","text":"
rydberg_interaction(**assignments)\n

calculate the Rydberg interaction matrix.

Parameters:

Name Type Description Default **assignments

the values to assign to the variables in the register.

{}

Returns:

Name Type Description NDArray NDArray

the Rydberg interaction matrix in the lower triangular form.

Source code in src/bloqade/analog/ir/location/location.py
def rydberg_interaction(self, **assignments) -> NDArray:\n    \"\"\"calculate the Rydberg interaction matrix.\n\n    Args:\n        **assignments: the values to assign to the variables in the register.\n\n    Returns:\n        NDArray: the Rydberg interaction matrix in the lower triangular form.\n\n    \"\"\"\n\n    from bloqade.analog.constants import RB_C6\n\n    # calculate the Interaction matrix\n    V_ij = np.zeros((self.n_sites, self.n_sites))\n    for i, site_i in enumerate(self.enumerate()):\n        pos_i = np.array([float(ele(**assignments)) for ele in site_i.position])\n\n        for j, site_j in enumerate(self.enumerate()):\n            if j >= i:\n                break  # enforce lower triangular form\n\n            pos_j = np.array([float(ele(**assignments)) for ele in site_j.position])\n            r_ij = np.linalg.norm(pos_i - pos_j)\n\n            V_ij[i, j] = RB_C6 / r_ij**6\n\n    return V_ij\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.scale","title":"scale","text":"
scale(scale)\n

Scale the geometry of your atoms.

"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.AtomArrangement.scale--usage-example","title":"Usage Example:","text":"
>>> reg = start.add_position([(0,0), (1,1)])\n# atom positions are now (0,0), (2,2)\n>>> new_reg = reg.scale(2)\n# you may also use scale on pre-defined geometries\n>>> from bloqade.analog.atom_arrangement import Chain\n# atoms in the chain will now be 2 um apart versus\n# the default 1 um\n>>> Chain(11).scale(2)\n
  • Next possible steps are:
  • Continuing to build your geometry via:
    • ...add_position(positions).add_position(positions): to add more positions
    • ...add_position(positions).apply_defect_count(n_defects): to randomly drop out n_atoms
    • ...add_position(positions).apply_defect_density(defect_probability): to drop out atoms with a certain probability
    • ...add_position(positions).scale(scale): to scale the geometry
  • Targeting a level coupling once you're done with the atom geometry:
    • ...add_position(positions).rydberg: to specify Rydberg coupling
    • ...add_position(positions).hyperfine: to specify Hyperfine coupling
  • Visualizing your atom geometry:
    • ...add_position(positions).show(): shows your geometry in your web browser
Source code in src/bloqade/analog/ir/location/location.py
@beartype\ndef scale(self, scale: ScalarType):\n    \"\"\"\n    Scale the geometry of your atoms.\n\n    ### Usage Example:\n    ```\n    >>> reg = start.add_position([(0,0), (1,1)])\n    # atom positions are now (0,0), (2,2)\n    >>> new_reg = reg.scale(2)\n    # you may also use scale on pre-defined geometries\n    >>> from bloqade.analog.atom_arrangement import Chain\n    # atoms in the chain will now be 2 um apart versus\n    # the default 1 um\n    >>> Chain(11).scale(2)\n    ```\n\n    - Next possible steps are:\n    - Continuing to build your geometry via:\n        - `...add_position(positions).add_position(positions)`:\n            to add more positions\n        - `...add_position(positions).apply_defect_count(n_defects)`:\n        to randomly drop out n_atoms\n        - `...add_position(positions).apply_defect_density(defect_probability)`:\n        to drop out atoms with a certain probability\n        - `...add_position(positions).scale(scale)`: to scale the geometry\n    - Targeting a level coupling once you're done with the atom geometry:\n        - `...add_position(positions).rydberg`:\n        to specify Rydberg coupling\n        - `...add_position(positions).hyperfine`:\n        to specify Hyperfine coupling\n    - Visualizing your atom geometry:\n        - `...add_position(positions).show()`:\n        shows your geometry in your web browser\n\n    \"\"\"\n\n    scale = cast(scale)\n    location_list = []\n    for location_info in self.enumerate():\n        x, y = location_info.position\n        new_position = (scale * x, scale * y)\n        location_list.append(\n            LocationInfo.create(new_position, bool(location_info.filling.value))\n        )\n\n    return ListOfLocations(location_list)\n
"},{"location":"reference/bloqade/analog/ir/location/location/#bloqade.analog.ir.location.location.ParallelRegisterInfo","title":"ParallelRegisterInfo","text":"
ParallelRegisterInfo(parallel_register)\n

ParallelRegisterInfo

Source code in src/bloqade/analog/ir/location/location.py
def __init__(self, parallel_register: ParallelRegister):\n    atom_arrangement = parallel_register.atom_arrangement\n    cluster_spacing = parallel_register.cluster_spacing\n\n    if atom_arrangement.n_atoms > 0:\n        # calculate bounding box\n        # of this register\n        location_iter = atom_arrangement.enumerate()\n        (x, y) = next(location_iter).position\n        x_min = x\n        x_max = x\n        y_min = y\n        y_max = y\n\n        for location_info in location_iter:\n            (x, y) = location_info.position\n            x_min = x.min(x_min)\n            x_max = x.max(x_max)\n            y_min = y.min(y_min)\n            y_max = y.max(y_max)\n\n        shift_x = (x_max - x_min) + cluster_spacing\n        shift_y = (y_max - y_min) + cluster_spacing\n\n        register_locations = [\n            list(location_info.position)\n            for location_info in atom_arrangement.enumerate()\n        ]\n        register_filling = [\n            location_info.filling.value\n            for location_info in atom_arrangement.enumerate()\n        ]\n        shift_vectors = [[shift_x, cast(0)], [cast(0), shift_y]]\n    else:\n        raise ValueError(\"No locations to parallelize.\")\n\n    self.register_locations = register_locations\n    self.register_filling = register_filling\n    self.shift_vectors = shift_vectors\n
"},{"location":"reference/bloqade/analog/ir/routine/","title":"Index","text":""},{"location":"reference/bloqade/analog/ir/routine/base/","title":"Base","text":""},{"location":"reference/bloqade/analog/ir/routine/base/#bloqade.analog.ir.routine.base.Routine","title":"Routine","text":"

Bases: RoutineBase

Result of parsing a completed Builder string.

"},{"location":"reference/bloqade/analog/ir/routine/base/#bloqade.analog.ir.routine.base.RoutineShow","title":"RoutineShow","text":"

Bases: Show

"},{"location":"reference/bloqade/analog/ir/routine/base/#bloqade.analog.ir.routine.base.RoutineShow.show","title":"show","text":"
show(*args, batch_index=0)\n

Show an interactive plot of the routine.

int

which parameter set out of the batch to use. Default is 0. If there are no batch parameters, use 0.

*args: Any Specify the parameters that are defined in the .args([...]) build step.

Source code in src/bloqade/analog/ir/routine/base.py
def show(self: \"RoutineBase\", *args, batch_index: int = 0):\n    \"\"\"Show an interactive plot of the routine.\n\n    batch_index: int\n        which parameter set out of the batch to use. Default is 0.\n        If there are no batch parameters, use 0.\n\n    *args: Any\n        Specify the parameters that are defined in the `.args([...])` build step.\n\n    \"\"\"\n    if self.source is None:\n        raise ValueError(\"Cannot show a routine without a source Builder.\")\n\n    return self.source.show(*args, batch_id=batch_index)\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/","title":"Bloqade","text":""},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation","title":"BloqadeEmulation dataclass","text":"
BloqadeEmulation(task_data, compile_cache=None)\n

Data class to hold the Hamiltonian and metadata for a given set of parameters

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.hamiltonian","title":"hamiltonian property","text":"
hamiltonian\n

Return the Hamiltonian object for the given task data.

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.metadata","title":"metadata property","text":"
metadata\n

The metadata for the given task data.

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.evolve","title":"evolve","text":"
evolve(\n    state=None,\n    solver_name=\"dop853\",\n    atol=1e-07,\n    rtol=1e-14,\n    nsteps=2147483647,\n    times=(),\n    interaction_picture=False,\n)\n

Evolve an initial state vector using the Hamiltonian

Parameters:

Name Type Description Default state Optional[StateVector]

The initial state vector to

None solver_name str

Which SciPy Solver to use. Defaults to

'dop853' atol float

Absolute tolerance for ODE solver. Defaults

1e-07 rtol float

Relative tolerance for adaptive step in

1e-14 nsteps int

Maximum number of steps allowed per integration

2147483647 times Sequence[float]

The times to evaluate the state vector

() interaction_picture bool

Use the interaction picture when

False

Returns:

Type Description Iterator[StateVector]

Iterator[StateVector]: An iterator of the state vectors at each time step.

Source code in src/bloqade/analog/ir/routine/bloqade.py
def evolve(\n    self,\n    state: Optional[StateVector] = None,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-7,\n    rtol: float = 1e-14,\n    nsteps: int = 2147483647,\n    times: Sequence[float] = (),\n    interaction_picture: bool = False,\n) -> Iterator[StateVector]:\n    \"\"\"Evolve an initial state vector using the Hamiltonian\n\n    Args:\n        state (Optional[StateVector], optional): The initial state vector to\n        evolve. if not provided, the zero state will be used. Defaults to None.\n        solver_name (str, optional): Which SciPy Solver to use. Defaults to\n        \"dop853\".\n        atol (float, optional): Absolute tolerance for ODE solver. Defaults\n        to 1e-14.\n        rtol (float, optional): Relative tolerance for adaptive step in\n        ODE solver. Defaults to 1e-7.\n        nsteps (int, optional): Maximum number of steps allowed per integration\n        step. Defaults to 2147483647.\n        times (Sequence[float], optional): The times to evaluate the state vector\n        at. Defaults to (). If not provided the state will be evaluated at\n        the end of the bloqade program.\n        interaction_picture (bool, optional): Use the interaction picture when\n        solving schrodinger equation. Defaults to False.\n\n    Returns:\n        Iterator[StateVector]: An iterator of the state vectors at each time step.\n\n    \"\"\"\n    state = self.zero_state(np.complex128) if state is None else state\n\n    U = AnalogGate(self.hamiltonian)\n\n    return U.apply(\n        state,\n        times=times,\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.fock_state","title":"fock_state","text":"
fock_state(fock_state_str, dtype=np.float64)\n

Return the fock state for the given Hamiltonian.

Source code in src/bloqade/analog/ir/routine/bloqade.py
def fock_state(\n    self, fock_state_str: str, dtype: np.dtype = np.float64\n) -> StateVector:\n    \"\"\"Return the fock state for the given Hamiltonian.\"\"\"\n    index = self.hamiltonian.space.fock_state_to_index(fock_state_str)\n    data = np.zeros(self.hamiltonian.space.size, dtype=dtype)\n    data[index] = 1\n    return StateVector(data, self.hamiltonian.space)\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadeEmulation.zero_state","title":"zero_state","text":"
zero_state(dtype=np.float64)\n

Return the zero state for the given Hamiltonian.

Source code in src/bloqade/analog/ir/routine/bloqade.py
def zero_state(self, dtype: np.dtype = np.float64) -> StateVector:\n    \"\"\"Return the zero state for the given Hamiltonian.\"\"\"\n    return self.hamiltonian.space.zero_state(dtype)\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine","title":"BloqadePythonRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine.hamiltonian","title":"hamiltonian","text":"
hamiltonian(\n    *args,\n    blockade_radius=0.0,\n    use_hyperfine=False,\n    waveform_runtime=\"interpret\",\n    cache_matrices=False\n)\n

Generates a list of BloqadeEmulation objects which contain the Hamiltonian of your program.

If you have a variable(s) in your program you have assigned multiple values via batch_assign() there will be multiple BloqadeEmulation objects, one for each value. On the other hand if the program only assumes a singular value per each variable, there will only be one BloqadeEmulation object but it will still be encapsulated in a list.

Parameters:

Name Type Description Default *args LiteralType

If your program has a variable that was declared as run-time assignable via .args you may pass a value to it here. If there are multiple variables declared via .args the order in which you assign values to those variables through this argument should follow the order in which the declaration occurred.

() blockade_radius float

The radius in which atoms blockade eachother. Default value is 0.0 micrometers.

0.0 use_hyperfine bool

Should the Hamiltonian account for hyperfine levels. Default value is False.

False waveform_runtime str

Specify which runtime to use for waveforms. If \"numba\" is specify the waveform is compiled, otherwise it is interpreted via the \"interpret\" argument. Defaults to \"interpret\".

'interpret' cache_matrices bool

Speed up Hamiltonian generation by reusing data (when possible) from previously generated Hamiltonians. Default value is False.

False

Returns:

Type Description List[BloqadeEmulation]

List[BloqadeEmulation]

Source code in src/bloqade/analog/ir/routine/bloqade.py
def hamiltonian(\n    self,\n    *args: LiteralType,\n    blockade_radius: float = 0.0,\n    use_hyperfine: bool = False,\n    waveform_runtime: str = \"interpret\",\n    cache_matrices: bool = False,\n) -> List[BloqadeEmulation]:\n    \"\"\"\n    Generates a list of BloqadeEmulation objects which contain the Hamiltonian of your program.\n\n    If you have a variable(s) in your program you have assigned multiple values via `batch_assign()`\n    there will be multiple `BloqadeEmulation` objects, one for each value. On the other hand\n    if the program only assumes a singular value per each variable, there will only be\n    one `BloqadeEmulation` object but it will still be encapsulated in a list.\n\n\n    Args:\n        *args (LiteralType): If your program has a variable that was declared as run-time assignable\n            via `.args` you may pass a value to it here. If there are multiple\n            variables declared via `.args` the order in which you assign values to those variables\n            through this argument should follow the order in which the declaration occurred.\n        blockade_radius (float): The radius in which atoms blockade eachother. Default value is 0.0 micrometers.\n        use_hyperfine (bool): Should the Hamiltonian account for hyperfine levels. Default value is False.\n        waveform_runtime (str): Specify which runtime to use for waveforms. If \"numba\" is specify the waveform\n            is compiled, otherwise it is interpreted via the \"interpret\" argument. Defaults to \"interpret\".\n        cache_matrices (bool): Speed up Hamiltonian generation by reusing data (when possible) from previously generated Hamiltonians.\n            Default value is False.\n\n    Returns:\n        List[BloqadeEmulation]\n\n    \"\"\"\n    ir_iter = self._generate_ir(\n        args, blockade_radius, waveform_runtime, use_hyperfine\n    )\n\n    if cache_matrices:\n        compile_cache = CompileCache()\n    else:\n        compile_cache = None\n\n    return [\n        BloqadeEmulation(task_data, compile_cache=compile_cache)\n        for task_data in ir_iter\n    ]\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine.run","title":"run","text":"
run(\n    shots,\n    args=(),\n    name=None,\n    blockade_radius=0.0,\n    waveform_runtime=\"interpret\",\n    interaction_picture=False,\n    cache_matrices=False,\n    multiprocessing=False,\n    num_workers=None,\n    solver_name=\"dop853\",\n    atol=1e-07,\n    rtol=1e-14,\n    nsteps=2147483647,\n)\n

Run the current program using bloqade python backend

Parameters:

Name Type Description Default shots int

number of shots after running state vector simulation

required args Tuple[LiteralType, ...]

The values for parameters defined

() name Optional[str]

Name to give this run. Defaults to None.

None blockade_radius float

Use the Blockade subspace given a

0.0 waveform_runtime str

(bool, optional): Use Numba to compile the waveforms,

'interpret' interaction_picture bool

Use the interaction picture when

False cache_matrices bool

Reuse previously evaluated matrcies when

False multiprocessing bool

Use multiple processes to process the

False num_workers Optional[int]

Number of processes to run with

None solver_name str

Which SciPy Solver to use. Defaults to

'dop853' atol float

Absolute tolerance for ODE solver. Defaults to

1e-07 rtol float

Relative tolerance for adaptive step in ODE solver.

1e-14 nsteps int

Maximum number of steps allowed per integration

2147483647

Raises:

Type Description ValueError

Cannot use multiprocessing and cache_matrices at the same time.

Returns:

Name Type Description LocalBatch LocalBatch

Batch of local tasks that have been executed.

Source code in src/bloqade/analog/ir/routine/bloqade.py
@beartype\ndef run(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    blockade_radius: float = 0.0,\n    waveform_runtime: str = \"interpret\",\n    interaction_picture: bool = False,\n    cache_matrices: bool = False,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-7,\n    rtol: float = 1e-14,\n    nsteps: int = 2_147_483_647,\n) -> LocalBatch:\n    \"\"\"Run the current program using bloqade python backend\n\n    Args:\n        shots (int): number of shots after running state vector simulation\n        args (Tuple[LiteralType, ...], optional): The values for parameters defined\n        in `args`. Defaults to ().\n        name (Optional[str], optional): Name to give this run. Defaults to None.\n        blockade_radius (float, optional): Use the Blockade subspace given a\n        particular radius. Defaults to 0.0.\n        waveform_runtime: (bool, optional): Use Numba to compile the waveforms,\n        Defaults to False.\n        interaction_picture (bool, optional): Use the interaction picture when\n        solving schrodinger equation. Defaults to False.\n        cache_matrices (bool, optional): Reuse previously evaluated matrcies when\n        possible. Defaults to False.\n        multiprocessing (bool, optional): Use multiple processes to process the\n        batches. Defaults to False.\n        num_workers (Optional[int], optional): Number of processes to run with\n        multiprocessing. Defaults to None.\n        solver_name (str, optional): Which SciPy Solver to use. Defaults to\n        \"dop853\".\n        atol (float, optional): Absolute tolerance for ODE solver. Defaults to\n        1e-14.\n        rtol (float, optional): Relative tolerance for adaptive step in ODE solver.\n        Defaults to 1e-7.\n        nsteps (int, optional): Maximum number of steps allowed per integration\n        step. Defaults to 2_147_483_647, the maximum value.\n\n    Raises:\n        ValueError: Cannot use multiprocessing and cache_matrices at the same time.\n\n    Returns:\n        LocalBatch: Batch of local tasks that have been executed.\n    \"\"\"\n    if multiprocessing and cache_matrices:\n        raise ValueError(\n            \"Cannot use multiprocessing and cache_matrices at the same time.\"\n        )\n\n    compile_options = dict(\n        shots=shots,\n        args=args,\n        name=name,\n        blockade_radius=blockade_radius,\n        cache_matrices=cache_matrices,\n        waveform_runtime=waveform_runtime,\n    )\n\n    solver_options = dict(\n        multiprocessing=multiprocessing,\n        num_workers=num_workers,\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n\n    batch = self._compile(**compile_options)\n    batch._run(**solver_options)\n\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.BloqadePythonRoutine.run_callback","title":"run_callback","text":"
run_callback(\n    callback,\n    program_args=(),\n    callback_args=(),\n    ignore_exceptions=False,\n    blockade_radius=0.0,\n    waveform_runtime=\"interpret\",\n    interaction_picture=False,\n    cache_matrices=False,\n    multiprocessing=False,\n    num_workers=None,\n    solver_name=\"dop853\",\n    atol=1e-07,\n    rtol=1e-14,\n    nsteps=2147483647,\n    use_hyperfine=False,\n)\n

Run state-vector simulation with a callback to access full state-vector from emulator

Parameters:

Name Type Description Default callback Callable[[StateVector, Metadata, RydbergHamiltonian, Any], Any] required program_args Tuple[LiteralType, ...]

The values for parameters

() callback_args Tuple[Any, ...]

Extra arguments to pass into

() ignore_exceptions bool

(bool, optional) If True any exception raised during

False blockade_radius float

Use the Blockade subspace given a

0.0 waveform_runtime str

(str, optional): Specify which runtime to use for

'interpret' interaction_picture bool

Use the interaction picture when

False cache_matrices bool

Reuse previously evaluated matrcies when

False multiprocessing bool

Use multiple processes to process the

False num_workers Optional[int]

Number of processes to run with

None solver_name str

Which SciPy Solver to use. Defaults to

'dop853' atol float

Absolute tolerance for ODE solver. Defaults to

1e-07 rtol float

Relative tolerance for adaptive step in ODE solver.

1e-14 nsteps int

Maximum number of steps allowed per integration

2147483647

Returns:

Name Type Description List List

List of resulting outputs from the callbacks

Raises:

Type Description RuntimeError

Raises the first error that occurs, only if

Note

For the callback function, first argument is the many-body wavefunction as a 1D complex numpy array, the second argument is of type Metadata which is a Named Tuple where the fields correspond to the parameters of that given task, RydbergHamiltonian is the object that contains the Hamiltonian used to generate the evolution for that task, Finally any optional positional arguments are allowed after that. The return value can be anything, the results will be collected in a list for each task in the batch.

Source code in src/bloqade/analog/ir/routine/bloqade.py
@beartype\ndef run_callback(\n    self,\n    callback: Callable[[StateVector, NamedTuple, RydbergHamiltonian, Any], Any],\n    program_args: Tuple[LiteralType, ...] = (),\n    callback_args: Tuple = (),\n    ignore_exceptions: bool = False,\n    blockade_radius: float = 0.0,\n    waveform_runtime: str = \"interpret\",\n    interaction_picture: bool = False,\n    cache_matrices: bool = False,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    solver_name: str = \"dop853\",\n    atol: float = 1e-7,\n    rtol: float = 1e-14,\n    nsteps: int = 2_147_483_647,\n    use_hyperfine: bool = False,\n) -> List:\n    \"\"\"Run state-vector simulation with a callback to access full state-vector from\n    emulator\n\n    Args:\n        callback (Callable[[StateVector, Metadata, RydbergHamiltonian, Any], Any]):\n        The callback function to run for each task in batch. See note below for more\n        details about the signature of the function.\n        program_args (Tuple[LiteralType, ...], optional): The values for parameters\n        defined in `args`. Defaults to ().\n        callback_args (Tuple[Any,...], optional): Extra arguments to pass into\n        ignore_exceptions: (bool, optional) If `True` any exception raised during\n        a task will be saved instead of the resulting output of the callback,\n        otherwise the first exception by task number will be raised after *all*\n        tasks have executed. Defaults to False.\n        blockade_radius (float, optional): Use the Blockade subspace given a\n        particular radius. Defaults to 0.0.\n        waveform_runtime: (str, optional): Specify which runtime to use for\n        waveforms. Defaults to \"interpret\".\n        interaction_picture (bool, optional): Use the interaction picture when\n        solving schrodinger equation. Defaults to False.\n        cache_matrices (bool, optional): Reuse previously evaluated matrcies when\n        possible. Defaults to False.\n        multiprocessing (bool, optional): Use multiple processes to process the\n        batches. Defaults to False.\n        num_workers (Optional[int], optional): Number of processes to run with\n        multiprocessing. Defaults to None.\n        solver_name (str, optional): Which SciPy Solver to use. Defaults to\n        \"dop853\".\n        atol (float, optional): Absolute tolerance for ODE solver. Defaults to\n        1e-14.\n        rtol (float, optional): Relative tolerance for adaptive step in ODE solver.\n        Defaults to 1e-7.\n        nsteps (int, optional): Maximum number of steps allowed per integration\n        step. Defaults to 2_147_483_647, the maximum value.\n\n    Returns:\n        List: List of resulting outputs from the callbacks\n\n    Raises:\n        RuntimeError: Raises the first error that occurs, only if\n        `ignore_exceptions=False`.\n\n    Note:\n        For the `callback` function, first argument is the many-body wavefunction\n        as a 1D complex numpy array, the second argument is of type `Metadata` which\n        is a Named Tuple where the fields correspond to the parameters of that given\n        task, RydbergHamiltonian is the object that contains the Hamiltonian used to\n        generate the evolution for that task, Finally any optional positional\n        arguments are allowed after that. The return value can be anything, the\n        results will be collected in a list for each task in the batch.\n\n\n    \"\"\"\n    if multiprocessing:\n        from multiprocessing import Queue, Process, cpu_count\n    else:\n        from queue import Queue\n\n    if cache_matrices:\n        compile_cache = CompileCache()\n    else:\n        compile_cache = None\n\n    solver_args = dict(\n        solver_name=solver_name,\n        atol=atol,\n        rtol=rtol,\n        nsteps=nsteps,\n        interaction_picture=interaction_picture,\n    )\n\n    runner = self.EmuRunner(\n        compile_cache=compile_cache,\n        solver_args=solver_args,\n        callback=callback,\n        callback_args=callback_args,\n    )\n\n    tasks = Queue()\n    results = Queue()\n\n    total_tasks = 0\n    ir_iter = self._generate_ir(\n        program_args, blockade_radius, waveform_runtime, use_hyperfine\n    )\n    for task_data in ir_iter:\n        task_number = task_data.task_id\n        emulator_ir = task_data.emulator_ir\n        metadata = task_data.metadata_dict\n        total_tasks += 1\n        tasks.put((task_number, (emulator_ir, metadata)))\n\n    workers = []\n    if multiprocessing:\n        num_workers = max(int(num_workers or cpu_count()), 1)\n        num_workers = min(total_tasks, num_workers)\n\n        for _ in range(num_workers):\n            worker = Process(\n                target=BloqadePythonRoutine.process_tasks,\n                args=(runner, tasks, results),\n            )\n            worker.start()\n\n            workers.append(worker)\n    else:\n        self.process_tasks(runner, tasks, results)\n\n    # blocks until all\n    # results have been fetched\n    # from the id_results Queue\n    id_results = []\n    for i in range(total_tasks):\n        id_results.append(results.get())\n\n    if workers:\n        for worker in workers:\n            worker.join()\n\n        tasks.close()\n        results.close()\n\n    id_results.sort(key=lambda x: x[0])\n    results = []\n\n    for task_id, result in id_results:\n        if not ignore_exceptions and isinstance(result, BaseException):\n            try:\n                raise result\n            except BaseException:\n                raise RuntimeError(\n                    f\"{result.__class__.__name__} occured during child process \"\n                    f\"running for task number {task_id}:\\n{traceback.format_exc()}\"\n                )\n\n        results.append(result)\n\n    return results\n
"},{"location":"reference/bloqade/analog/ir/routine/bloqade/#bloqade.analog.ir.routine.bloqade.TaskData","title":"TaskData dataclass","text":"
TaskData(task_id, emulator_ir, metadata_dict)\n

Data class to hold the program ir and metadata for a given set of parameters

"},{"location":"reference/bloqade/analog/ir/routine/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine","title":"BraketHardwareRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine.__call__","title":"__call__","text":"
__call__(\n    *args,\n    shots=1,\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain Braket backend specific tasks, run_async to Braket, and wait until the results are coming back.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

1 args LiteralType

additional arguments for args variables.

() name str

custom name of the batch

None shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef __call__(\n    self,\n    *args: LiteralType,\n    shots: int = 1,\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n):\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n    Braket backend specific tasks, run_async to Braket,\n    and wait until the results are coming back.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args: additional arguments for args variables.\n        name (str): custom name of the batch\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    return self.run(shots, args, name, use_experimental, shuffle, **kwargs)\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine.run","title":"run","text":"
run(\n    shots,\n    args=(),\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain Braket backend specific tasks, run_async to Braket, and wait until the results are coming back.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple

additional arguments

() name str

custom name of the batch

None shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef run(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n) -> RemoteBatch:\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n    Braket backend specific tasks, run_async to Braket,\n    and wait until the results are coming back.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args (Tuple): additional arguments\n        name (str): custom name of the batch\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n\n    batch = self.run_async(shots, args, name, use_experimental, shuffle, **kwargs)\n    batch.pull()\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketHardwareRoutine.run_async","title":"run_async","text":"
run_async(\n    shots,\n    args=(),\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain Braket backend specific tasks, and run_async to Braket.

Note

This is async.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple

Values of the parameter defined in args, defaults to ()

() name str | None

custom name of the batch, defaults to None

None use_experimental bool

Use experimental hardware capabilities

False shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef run_async(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n) -> RemoteBatch:\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n    Braket backend specific tasks, and run_async to Braket.\n\n    Note:\n        This is async.\n\n    Args:\n        shots (int): number of shots\n        args (Tuple): Values of the parameter defined in `args`, defaults to ()\n        name (str | None): custom name of the batch, defaults to None\n        use_experimental (bool): Use experimental hardware capabilities\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n\n    batch = self._compile(shots, use_experimental, args, name)\n    batch._submit(shuffle, **kwargs)\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketLocalEmulatorRoutine","title":"BraketLocalEmulatorRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketLocalEmulatorRoutine.__call__","title":"__call__","text":"
__call__(\n    *args,\n    shots=1,\n    name=None,\n    multiprocessing=False,\n    num_workers=None,\n    **kwargs\n)\n

Compile to a LocalBatch, and run. The LocalBatch contain tasks to run on local emulator.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

1 args LiteralType

additional arguments for args variables.

() multiprocessing bool

enable multi-process

False num_workers int

number of workers to run the emulator

None Return

LocalBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef __call__(\n    self,\n    *args: LiteralType,\n    shots: int = 1,\n    name: Optional[str] = None,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    **kwargs,\n):\n    \"\"\"\n    Compile to a LocalBatch, and run.\n    The LocalBatch contain tasks to run on local emulator.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args: additional arguments for args variables.\n        multiprocessing (bool): enable multi-process\n        num_workers (int): number of workers to run the emulator\n\n    Return:\n        LocalBatch\n\n    \"\"\"\n    return self.run(\n        shots,\n        args,\n        name,\n        multiprocessing=multiprocessing,\n        num_workers=num_workers,\n        **kwargs,\n    )\n
"},{"location":"reference/bloqade/analog/ir/routine/braket/#bloqade.analog.ir.routine.braket.BraketLocalEmulatorRoutine.run","title":"run","text":"
run(\n    shots,\n    args=(),\n    name=None,\n    multiprocessing=False,\n    num_workers=None,\n    **kwargs\n)\n

Compile to a LocalBatch, and run. The LocalBatch contain tasks to run on local emulator.

Note

This is sync, and will wait until remote results finished.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple[LiteralType, ...]

additional arguments for args variables.

() multiprocessing bool

enable multi-process

False num_workers int

number of workers to run the emulator

None Return

LocalBatch

Source code in src/bloqade/analog/ir/routine/braket.py
@beartype\ndef run(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    multiprocessing: bool = False,\n    num_workers: Optional[int] = None,\n    **kwargs,\n) -> LocalBatch:\n    \"\"\"\n    Compile to a LocalBatch, and run.\n    The LocalBatch contain tasks to run on local emulator.\n\n    Note:\n        This is sync, and will wait until remote results\n        finished.\n\n    Args:\n        shots (int): number of shots\n        args: additional arguments for args variables.\n        multiprocessing (bool): enable multi-process\n        num_workers (int): number of workers to run the emulator\n\n    Return:\n        LocalBatch\n\n    \"\"\"\n\n    batch = self._compile(shots, args, name)\n    batch._run(multiprocessing=multiprocessing, num_workers=num_workers, **kwargs)\n    return batch\n
"},{"location":"reference/bloqade/analog/ir/routine/params/","title":"Params","text":""},{"location":"reference/bloqade/analog/ir/routine/quera/","title":"Quera","text":""},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.CustomSubmissionRoutine","title":"CustomSubmissionRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.CustomSubmissionRoutine.submit","title":"submit","text":"
submit(\n    shots,\n    url,\n    json_body_template,\n    method=\"POST\",\n    args=(),\n    request_options={},\n    use_experimental=False,\n    sleep_time=0.1,\n)\n

Compile to QuEraTaskSpecification and submit to a custom service.

Parameters:

Name Type Description Default shots int

number of shots

required url str

url of the custom service

required json_body_template str

json body template, must contain '{task_ir}'

required method str

http method to be used. Defaults to \"POST\".

'POST' args Tuple[LiteralType]

additional arguments to be passed into the

() request_options Dict[str, Any]

additional options to be passed into the request method,

{} use_experimental bool

Enable experimental hardware capabilities

False sleep_time float

time to sleep between each request. Defaults to 0.1.

0.1

Returns:

Type Description List[Tuple[NamedTuple, Response]]

List[Tuple[NamedTuple, Response]]: List of parameters for each batch in

List[Tuple[NamedTuple, Response]]

the task and the response from the post request.

Examples:

Here is a simple example of how to use this method. Note the body_template has double curly braces on the outside to escape the string formatting.

>>> body_template = \"{{\"token\": \"my_token\", \"task\": {task_ir}}}\"\n>>> responses = (\n    program.quera.custom.submit(\n        100,\n        \"http://my_custom_service.com\",\n        body_template\n    )\n)\n
Source code in src/bloqade/analog/ir/routine/quera.py
def submit(\n    self,\n    shots: int,\n    url: str,\n    json_body_template: str,\n    method: str = \"POST\",\n    args: Tuple[LiteralType] = (),\n    request_options: Dict[str, Any] = {},\n    use_experimental: bool = False,\n    sleep_time: float = 0.1,\n) -> List[Tuple[NamedTuple, Response]]:\n    \"\"\"Compile to QuEraTaskSpecification and submit to a custom service.\n\n    Args:\n        shots (int): number of shots\n        url (str): url of the custom service\n        json_body_template (str): json body template, must contain '{task_ir}'\n        which is a placeholder for a string representation of the task ir.\n        The task ir string will be inserted into the template with\n        `json_body_template.format(task_ir=task_ir_string)`.\n        to be replaced by QuEraTaskSpecification\n        method (str): http method to be used. Defaults to \"POST\".\n        args (Tuple[LiteralType]): additional arguments to be passed into the\n        compiler coming from `args` option of the build. Defaults to ().\n        request_options: additional options to be passed into the request method,\n        Note the `data` option will be overwritten by the\n        `json_body_template.format(task_ir=task_ir_string)`.\n        use_experimental (bool): Enable experimental hardware capabilities\n        sleep_time (float): time to sleep between each request. Defaults to 0.1.\n\n    Returns:\n        List[Tuple[NamedTuple, Response]]: List of parameters for each batch in\n        the task and the response from the post request.\n\n    Examples:\n        Here is a simple example of how to use this method. Note the body_template\n        has double curly braces on the outside to escape the string formatting.\n\n    ```python\n    >>> body_template = \"{{\"token\": \"my_token\", \"task\": {task_ir}}}\"\n    >>> responses = (\n        program.quera.custom.submit(\n            100,\n            \"http://my_custom_service.com\",\n            body_template\n        )\n    )\n    ```\n    \"\"\"\n\n    if r\"{task_ir}\" not in json_body_template:\n        raise ValueError(r\"body_template must contain '{task_ir}'\")\n\n    partial_eval = json_body_template.format(task_ir='\"task_ir\"')\n    try:\n        _ = json.loads(partial_eval)\n    except json.JSONDecodeError as e:\n        raise ValueError(\n            \"body_template must be a valid json template. \"\n            'When evaluating template with task_ir=\"task_ir\", '\n            f\"the template evaluated to: {partial_eval!r}.\\n\"\n            f\"JSONDecodeError: {e}\"\n        )\n\n    out = []\n    for metadata, task_ir in self._compile(shots, use_experimental, args):\n        json_request_body = json_body_template.format(\n            task_ir=task_ir.json(exclude_none=True, exclude_unset=True)\n        )\n        request_options.update(data=json_request_body)\n        response = request(method, url, **request_options)\n        out.append((metadata, response))\n        time.sleep(sleep_time)\n\n    return out\n
"},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.QuEraHardwareRoutine","title":"QuEraHardwareRoutine","text":"

Bases: RoutineBase

"},{"location":"reference/bloqade/analog/ir/routine/quera/#bloqade.analog.ir.routine.quera.QuEraHardwareRoutine.run_async","title":"run_async","text":"
run_async(\n    shots,\n    args=(),\n    name=None,\n    use_experimental=False,\n    shuffle=False,\n    **kwargs\n)\n

Compile to a RemoteBatch, which contain QuEra backend specific tasks, and run_async through QuEra service.

Parameters:

Name Type Description Default shots int

number of shots

required args Tuple

additional arguments

() name str

custom name of the batch

None shuffle bool

shuffle the order of jobs

False Return

RemoteBatch

Source code in src/bloqade/analog/ir/routine/quera.py
@beartype\ndef run_async(\n    self,\n    shots: int,\n    args: Tuple[LiteralType, ...] = (),\n    name: Optional[str] = None,\n    use_experimental: bool = False,\n    shuffle: bool = False,\n    **kwargs,\n) -> RemoteBatch:\n    \"\"\"\n    Compile to a RemoteBatch, which contain\n        QuEra backend specific tasks,\n        and run_async through QuEra service.\n\n    Args:\n        shots (int): number of shots\n        args (Tuple): additional arguments\n        name (str): custom name of the batch\n        shuffle (bool): shuffle the order of jobs\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    batch = self._compile(shots, use_experimental, args, name)\n    batch._submit(shuffle, **kwargs)\n    return batch\n
"},{"location":"reference/bloqade/analog/submission/","title":"Index","text":""},{"location":"reference/bloqade/analog/submission/base/","title":"Base","text":""},{"location":"reference/bloqade/analog/submission/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/submission/load_config/","title":"Load config","text":""},{"location":"reference/bloqade/analog/submission/mock/","title":"Mock","text":""},{"location":"reference/bloqade/analog/submission/quera/","title":"Quera","text":""},{"location":"reference/bloqade/analog/submission/ir/","title":"Index","text":""},{"location":"reference/bloqade/analog/submission/ir/braket/","title":"Braket","text":"

Helper functions related to IR submission co-ordinations between Bloqade and Braket

"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.BraketTaskSpecification","title":"BraketTaskSpecification","text":"

Bases: BaseModel

Class representing geometry of an atom arrangement.

Attributes:

Name Type Description nshots int

Number of shots

program Program

IR(Intermediate Representation) program suitable for braket

"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.extract_braket_program","title":"extract_braket_program","text":"
extract_braket_program(quera_task_ir)\n

Extracts the Braket program.

Parameters:

Name Type Description Default quera_task_ir QuEraTaskSpecification

Quera IR(Intermediate representation) of the task.

required Source code in src/bloqade/analog/submission/ir/braket.py
def extract_braket_program(quera_task_ir: QuEraTaskSpecification):\n    \"\"\"Extracts the Braket program.\n\n    Args:\n        quera_task_ir (QuEraTaskSpecification):\n            Quera IR(Intermediate representation) of the task.\n    \"\"\"\n    lattice = quera_task_ir.lattice\n\n    rabi_amplitude = (\n        quera_task_ir.effective_hamiltonian.rydberg.rabi_frequency_amplitude.global_\n    )\n    rabi_phase = (\n        quera_task_ir.effective_hamiltonian.rydberg.rabi_frequency_phase.global_\n    )\n    global_detuning = quera_task_ir.effective_hamiltonian.rydberg.detuning.global_\n    local_detuning = quera_task_ir.effective_hamiltonian.rydberg.detuning.local\n\n    register = AtomArrangement()\n    for site, filled in zip(lattice.sites, lattice.filling):\n        site_type = SiteType.FILLED if filled == 1 else SiteType.VACANT\n        register.add(site, site_type)\n\n    hamiltonian = DrivingField(\n        amplitude=to_braket_field(rabi_amplitude),\n        phase=to_braket_field(rabi_phase),\n        detuning=to_braket_field(global_detuning),\n    )\n\n    if local_detuning:\n        hamiltonian = hamiltonian + ShiftingField(to_braket_field(local_detuning))\n\n    return AnalogHamiltonianSimulation(\n        register=register,\n        hamiltonian=hamiltonian,\n    )\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.from_braket_status_codes","title":"from_braket_status_codes","text":"
from_braket_status_codes(braket_status)\n

Gets the QuEraTaskStatusCode object for working with Bloqade SDK.

Parameters:

Name Type Description Default braket_status str

str The value of status in metadata() in the Amazon Braket. GetQuantumTask operation. If use_cached_value is True, the value most recently returned from GetQuantumTask operation is used

required

Returns:

Type Description QuEraTaskStatusCode

An object of the type Field in Braket SDK

Source code in src/bloqade/analog/submission/ir/braket.py
def from_braket_status_codes(braket_status: str) -> QuEraTaskStatusCode:\n    \"\"\"Gets the `QuEraTaskStatusCode` object for working with Bloqade SDK.\n\n    Args:\n        braket_status: str\n            The value of status in metadata() in the Amazon Braket.\n            `GetQuantumTask` operation. If `use_cached_value` is `True`,\n            the value most recently returned from\n            `GetQuantumTask` operation is used\n\n    Returns:\n        An object of the type `Field` in Braket SDK\n    \"\"\"\n    if braket_status == str(\"QUEUED\"):\n        return QuEraTaskStatusCode.Enqueued\n    else:\n        return QuEraTaskStatusCode(braket_status.lower().capitalize())\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.from_braket_task_results","title":"from_braket_task_results","text":"
from_braket_task_results(braket_task_results)\n

Get the QuEraTaskResults object for working with Bloqade SDK.

Parameters:

Name Type Description Default braket_task_results AnalogHamiltonianSimulationTaskResult

AnalogHamiltonianSimulationTaskResult Quantum task result of braket system

required

Returns:

Type Description QuEraTaskResults

An object of the type Field in Braket SDK.

Source code in src/bloqade/analog/submission/ir/braket.py
def from_braket_task_results(\n    braket_task_results: AnalogHamiltonianSimulationTaskResult,\n) -> QuEraTaskResults:\n    \"\"\"Get the `QuEraTaskResults` object for working with Bloqade SDK.\n\n    Args:\n        braket_task_results: AnalogHamiltonianSimulationTaskResult\n            Quantum task result of braket system\n\n    Returns:\n        An object of the type `Field` in Braket SDK.\n    \"\"\"\n    shot_outputs = []\n    for measurement in braket_task_results.measurements:\n        shot_outputs.append(\n            QuEraShotResult(\n                shot_status=QuEraShotStatusCode.Completed,\n                pre_sequence=list(measurement.pre_sequence),\n                post_sequence=list(measurement.post_sequence),\n            )\n        )\n\n    return QuEraTaskResults(\n        task_status=QuEraTaskStatusCode.Completed, shot_outputs=shot_outputs\n    )\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_field","title":"to_braket_field","text":"
to_braket_field(quera_field)\n

Converts to TimeSeries object supported by Braket.

Parameters:

Name Type Description Default quera_field Union[GlobalField, LocalField)]

Field supported by Quera

required

Returns:

Type Description Field

An object of the type braket.ahs.field.Field

Raises:

Type Description TypeError

If field is not of the type GlobalField or LocalField.

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_field(quera_field: Union[GlobalField, LocalField]) -> Field:\n    \"\"\"Converts to `TimeSeries` object supported by Braket.\n\n    Args:\n        quera_field (Union[GlobalField, LocalField)]:\n            Field supported by Quera\n\n    Returns:\n        An object of the type `braket.ahs.field.Field`\n\n    Raises:\n        TypeError: If field is not of the type `GlobalField` or `LocalField`.\n    \"\"\"\n    if isinstance(quera_field, GlobalField):\n        times = quera_field.times\n        values = quera_field.values\n        time_series = to_braket_time_series(times, values)\n        return Field(pattern=\"uniform\", time_series=time_series)\n    elif isinstance(quera_field, LocalField):\n        times = quera_field.times\n        values = quera_field.values\n        pattern = quera_field.lattice_site_coefficients\n        time_series = to_braket_time_series(times, values)\n        pattern = Pattern(pattern)\n        return Field(pattern=pattern, time_series=time_series)\n    else:\n        raise TypeError\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_task","title":"to_braket_task","text":"
to_braket_task(quera_task_ir)\n

Converts to Tuple[int, AnalogHamiltonianSimulation] object supported by Braket.

Parameters:

Name Type Description Default quera_task_ir QuEraTaskSpecification

Quera IR(Intermediate representation) of the task.

required

Returns:

Type Description Tuple[int, AnalogHamiltonianSimulation]

An tuple of the type Tuple[int, AnalogHamiltonianSimulation].

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_task(\n    quera_task_ir: QuEraTaskSpecification,\n) -> Tuple[int, AnalogHamiltonianSimulation]:\n    \"\"\"Converts to `Tuple[int, AnalogHamiltonianSimulation]` object supported by Braket.\n\n    Args:\n        quera_task_ir (QuEraTaskSpecification):\n            Quera IR(Intermediate representation) of the task.\n\n    Returns:\n        An tuple  of the type `Tuple[int, AnalogHamiltonianSimulation]`.\n    \"\"\"\n    braket_ahs_program = extract_braket_program(quera_task_ir)\n    return quera_task_ir.nshots, braket_ahs_program\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_task_ir","title":"to_braket_task_ir","text":"
to_braket_task_ir(quera_task_ir)\n

Converts quera IR(Intermendiate Representation) to to BraketTaskSpecification object.

Parameters:

Name Type Description Default quera_task_ir QuEraTaskSpecification

Quera IR(Intermediate representation) of the task.

required

Returns:

Type Description BraketTaskSpecification

An object of the type BraketTaskSpecification in Braket SDK

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_task_ir(quera_task_ir: QuEraTaskSpecification) -> BraketTaskSpecification:\n    \"\"\"Converts quera IR(Intermendiate Representation) to\n    to `BraketTaskSpecification` object.\n\n    Args:\n        quera_task_ir (QuEraTaskSpecification):\n            Quera IR(Intermediate representation) of the task.\n\n    Returns:\n        An object of the type `BraketTaskSpecification` in Braket SDK\n\n    \"\"\"\n    nshots, braket_ahs_program = to_braket_task(quera_task_ir)\n    return BraketTaskSpecification(nshots=nshots, program=braket_ahs_program.to_ir())\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_braket_time_series","title":"to_braket_time_series","text":"
to_braket_time_series(times, values)\n

Converts to TimeSeries object supported by Braket.

Parameters:

Name Type Description Default times List[Decimal]

Times of the value.

required values List[Decimal]

Corresponding values to add to the time series

required

Returns:

Type Description TimeSeries

An object of the type braket.timings.TimeSeries

Source code in src/bloqade/analog/submission/ir/braket.py
def to_braket_time_series(times: List[Decimal], values: List[Decimal]) -> TimeSeries:\n    \"\"\"Converts to `TimeSeries` object supported by Braket.\n\n    Args:\n        times (List[Decimal]): Times of the value.\n        values (List[Decimal]): Corresponding values to add to the time series\n\n    Returns:\n        An object of the type `braket.timings.TimeSeries`\n    \"\"\"\n    time_series = TimeSeries()\n    for time, value in zip(times, values):\n        time_series.put(time, value)\n\n    return time_series\n
"},{"location":"reference/bloqade/analog/submission/ir/braket/#bloqade.analog.submission.ir.braket.to_quera_capabilities","title":"to_quera_capabilities","text":"
to_quera_capabilities(paradigm)\n

Converts to QuEraCapabilities object supported by Braket.

Parameters:

Name Type Description Default paradigm

The paradigm property of the AwsDevice object for Aquila

required

Returns:

Type Description QuEraCapabilities

An object of the type QuEraCapabilities in Bloqade SDK.

Source code in src/bloqade/analog/submission/ir/braket.py
def to_quera_capabilities(paradigm) -> cp.QuEraCapabilities:\n    \"\"\"Converts to `QuEraCapabilities` object supported by Braket.\n\n    Args:\n        paradigm: The `paradigm` property of the `AwsDevice` object for Aquila\n\n    Returns:\n        An object of the type `QuEraCapabilities` in Bloqade SDK.\n    \"\"\"\n    rydberg_global = paradigm.rydberg.rydbergGlobal\n\n    return cp.QuEraCapabilities(\n        version=paradigm.braketSchemaHeader.version,\n        capabilities=cp.DeviceCapabilities(\n            task=cp.TaskCapabilities(\n                number_shots_min=1,\n                number_shots_max=1000,\n            ),\n            lattice=cp.LatticeCapabilities(\n                number_qubits_max=paradigm.qubitCount,\n                geometry=cp.LatticeGeometryCapabilities(\n                    spacing_radial_min=paradigm.lattice.geometry.spacingRadialMin,\n                    spacing_vertical_min=paradigm.lattice.geometry.spacingVerticalMin,\n                    position_resolution=paradigm.lattice.geometry.positionResolution,\n                    number_sites_max=paradigm.lattice.geometry.numberSitesMax,\n                ),\n                area=cp.LatticeAreaCapabilities(\n                    width=paradigm.lattice.area.width,\n                    height=paradigm.lattice.area.height,\n                ),\n            ),\n            rydberg=cp.RydbergCapabilities(\n                c6_coefficient=paradigm.rydberg.c6Coefficient,\n                global_=cp.RydbergGlobalCapabilities(\n                    rabi_frequency_max=rydberg_global.rabiFrequencyRange[0],\n                    rabi_frequency_min=rydberg_global.rabiFrequencyRange[1],\n                    rabi_frequency_resolution=rydberg_global.rabiFrequencyResolution,\n                    rabi_frequency_slew_rate_max=rydberg_global.rabiFrequencySlewRateMax,\n                    detuning_max=rydberg_global.detuningRange[0],\n                    detuning_min=rydberg_global.detuningRange[1],\n                    detuning_resolution=rydberg_global.detuningResolution,\n                    detuning_slew_rate_max=rydberg_global.detuningSlewRateMax,\n                    phase_min=rydberg_global.phaseRange[0],\n                    phase_max=rydberg_global.phaseRange[1],\n                    phase_resolution=rydberg_global.phaseResolution,\n                    time_min=rydberg_global.timeMin,\n                    time_max=rydberg_global.timeMax,\n                    time_resolution=rydberg_global.timeResolution,\n                    time_delta_min=rydberg_global.timeDeltaMin,\n                ),\n                local=None,\n            ),\n        ),\n    )\n
"},{"location":"reference/bloqade/analog/submission/ir/capabilities/","title":"Capabilities","text":""},{"location":"reference/bloqade/analog/submission/ir/parallel/","title":"Parallel","text":""},{"location":"reference/bloqade/analog/submission/ir/parallel/#bloqade.analog.submission.ir.parallel.ClusterLocationInfo","title":"ClusterLocationInfo","text":"

Bases: BaseModel

Class that stores the mapping of batched jobs.

Parameters:

Name Type Description Default cluster_index int

the index of the cluster a site belongs to

required global_location_index int

the index of the site in the multplexed system

required cluster_location_index int

the index of the site in the original system

required"},{"location":"reference/bloqade/analog/submission/ir/task_results/","title":"Task results","text":""},{"location":"reference/bloqade/analog/submission/ir/task_results/#bloqade.analog.submission.ir.task_results.QuEraTaskResults","title":"QuEraTaskResults","text":"

Bases: BaseModel

"},{"location":"reference/bloqade/analog/submission/ir/task_results/#bloqade.analog.submission.ir.task_results.QuEraTaskResults.export_as_probabilities","title":"export_as_probabilities","text":"
export_as_probabilities()\n

converts from shot results to probabilities

Returns:

Name Type Description TaskProbabilities TaskProbabilities

The task results as probabilties

Source code in src/bloqade/analog/submission/ir/task_results.py
def export_as_probabilities(self) -> TaskProbabilities:\n    \"\"\"converts from shot results to probabilities\n\n    Returns:\n        TaskProbabilities: The task results as probabilties\n    \"\"\"\n    counts = dict()\n    nshots = len(self.shot_outputs)\n    for shot_result in self.shot_outputs:\n        pre_sequence_str = \"\".join(str(bit) for bit in shot_result.pre_sequence)\n\n        post_sequence_str = \"\".join(str(bit) for bit in shot_result.post_sequence)\n\n        configuration = (pre_sequence_str, post_sequence_str)\n        # iterative average\n        current_count = counts.get(configuration, 0)\n        counts[configuration] = current_count + 1\n\n    probabilities = [(config, count / nshots) for config, count in counts.items()]\n    return TaskProbabilities(probabilities=probabilities)\n
"},{"location":"reference/bloqade/analog/submission/ir/task_results/#bloqade.analog.submission.ir.task_results.QuEraTaskStatusCode","title":"QuEraTaskStatusCode","text":"

Bases: str, Enum

An Enum representing the various states a task can be in within the QuEra system.

Attributes:

Name Type Description Created

The task has been created but not yet started.

Running

The task is currently running.

Completed

The task has completed successfully.

Failed

The task has failed.

Cancelled

The task has been cancelled.

Executing

The task is currently being executed.

Enqueued

The task is in the queue waiting to be executed.

Accepted

The task has been accepted for execution.

Unaccepted

The task has not been accepted for execution.

Partial

The task has partially completed.

Unsubmitted

The task has not been submitted for execution.

"},{"location":"reference/bloqade/analog/submission/ir/task_specification/","title":"Task specification","text":""},{"location":"reference/bloqade/analog/task/","title":"Index","text":""},{"location":"reference/bloqade/analog/task/base/","title":"Base","text":""},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Geometry","title":"Geometry","text":"

Class representing geometry of an atom arrangement.

Attributes:

Name Type Description sites List[Tuple[float, float]]

Atom site arrangement

filling List[int]

Which sites are filled

parallel_decoder Optional[ParallelDecoder]

Decoder object for decoding Geometry object

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.LocalTask","title":"LocalTask","text":"

Bases: Task

Task to use for local executions for simulation purposes..

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.RemoteTask","title":"RemoteTask","text":"

Bases: Task

Task to use for remote executions to run the program on Quera Quantum Computers.

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report","title":"Report","text":"
Report(data, metas, geos, name='')\n

Report is a helper class for organizing and analysing data

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report--analyzing-results","title":"Analyzing Results","text":"

When you've retrieved your results from either emulation or hardware you can generate a .report():

report = results.report()\n

For the examples below we analyze the results of a two atom program.

The report contains useful information such as:

The raw bitstrings measured per each execution of the program

>>> report.bitstrings()\n[array([[1, 1],\n        [1, 1],\n        [1, 1],\n        ...,\n        [1, 1],\n        [1, 1],\n

The number of times each unique bitstring occurred:

>>> report.counts()\n\n[OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n

The Rydberg Density for each atom

>>> report.rydberg_densities()\n\n                0      1\ntask_number\n0            0.053  0.054\n

Source code in src/bloqade/analog/task/base.py
def __init__(self, data, metas, geos, name=\"\") -> None:\n    self.dataframe = data  # df\n    self._bitstrings = None  # bitstring cache\n    self._counts = None  # counts cache\n    self.metas = metas\n    self.geos = geos\n    self.name = name + \" \" + str(datetime.datetime.now())\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.markdown","title":"markdown property","text":"
markdown\n

Get the markdown representation of the dataframe

"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.bitstrings","title":"bitstrings","text":"
bitstrings(filter_perfect_filling=True, clusters=[])\n

Get the bitstrings from the data.

Parameters:

Name Type Description Default filter_perfect_filling bool

whether return will only contain perfect filling shots. Defaults to True.

True clusters Union[tuple[int, int], List[tuple[int, int]]]

(tuple[int, int], Sequence[Tuple[int, int]]): cluster index to filter shots from. If none are provided all clusters are used, defaults to [].

[]

Returns:

Name Type Description bitstrings list of ndarray

list corresponding to each task in the report. Each element is an ndarray of shape (nshots, nsites) where nshots is the number of shots for the task and nsites is the number of sites in the task. For example:

[array([[1, 1],\n        [1, 1],\n        [1, 1],\n        ...,\n        [1, 1],\n        [1, 1],\n        [1, 0]], dtype=int8)]\n

Note

Note that nshots may vary between tasks if filter_perfect_filling is set to True.

Source code in src/bloqade/analog/task/base.py
@beartype\ndef bitstrings(\n    self,\n    filter_perfect_filling: bool = True,\n    clusters: Union[tuple[int, int], List[tuple[int, int]]] = [],\n) -> List[NDArray]:\n    \"\"\"Get the bitstrings from the data.\n\n    Args:\n        filter_perfect_filling (bool): whether return will\n            only contain perfect filling shots. Defaults to True.\n        clusters: (tuple[int, int], Sequence[Tuple[int, int]]):\n            cluster index to filter shots from. If none are provided\n            all clusters are used, defaults to [].\n\n    Returns:\n        bitstrings (list of ndarray): list corresponding to each\n            task in the report. Each element is an ndarray of shape\n            (nshots, nsites) where nshots is the number of shots for\n            the task and nsites is the number of sites in the task.\n            For example:\n            ```python3\n            [array([[1, 1],\n                    [1, 1],\n                    [1, 1],\n                    ...,\n                    [1, 1],\n                    [1, 1],\n                    [1, 0]], dtype=int8)]\n            ```\n\n    Note:\n        Note that nshots may vary between tasks if filter_perfect_filling\n        is set to True.\n\n    \"\"\"\n\n    task_numbers = self.dataframe.index.get_level_values(\"task_number\").unique()\n\n    bitstrings = []\n    for task_number in task_numbers:\n        mask = self._filter(\n            task_number=task_number,\n            filter_perfect_filling=filter_perfect_filling,\n            clusters=clusters,\n        )\n        if np.any(mask):\n            bitstrings.append(self.dataframe.loc[mask].to_numpy())\n        else:\n            bitstrings.append(\n                np.zeros((0, self.dataframe.shape[1]), dtype=np.uint8)\n            )\n\n    return bitstrings\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.counts","title":"counts","text":"
counts(filter_perfect_filling=True, clusters=[])\n

Get the counts of unique bit strings.

Parameters:

Name Type Description Default filter_perfect_filling bool

whether return will only contain perfect filling shots. Defaults to True.

True clusters Union[tuple[int, int], List[tuple[int, int]]]

(tuple[int, int], Sequence[Tuple[int, int]]): cluster index to filter shots from. If none are provided all clusters are used, defaults to [].

[]

Returns:

Name Type Description counts list of OrderedDict[str, int]

list corresponding to each task in the report. Each element is an ndarray of shape (nshots, nsites) where nshots is the number of shots for the task and nsites is the number of sites in the task. For example:

    [OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n

Note

Note that nshots may vary between tasks if filter_perfect_filling is set to True.

Source code in src/bloqade/analog/task/base.py
def counts(\n    self,\n    filter_perfect_filling: bool = True,\n    clusters: Union[tuple[int, int], List[tuple[int, int]]] = [],\n) -> List[OrderedDict[str, int]]:\n    \"\"\"Get the counts of unique bit strings.\n\n    Args:\n        filter_perfect_filling (bool): whether return will\n            only contain perfect filling shots. Defaults to True.\n        clusters: (tuple[int, int], Sequence[Tuple[int, int]]):\n            cluster index to filter shots from. If none are provided\n            all clusters are used, defaults to [].\n\n    Returns:\n        counts (list of OrderedDict[str, int]): list corresponding to each\n            task in the report. Each element is an ndarray of shape\n            (nshots, nsites) where nshots is the number of shots for\n            the task and nsites is the number of sites in the task.\n            For example:\n            ```python\n                [OrderedDict([('11', 892), ('10', 59), ('01', 49)])]\n            ```\n\n    Note:\n        Note that nshots may vary between tasks if filter_perfect_filling\n        is set to True.\n\n    \"\"\"\n\n    def _generate_counts(bitstring):\n        output = np.unique(bitstring, axis=0, return_counts=True)\n\n        count_list = [\n            (\"\".join(map(str, bitstring)), int(count))\n            for bitstring, count in zip(*output)\n        ]\n        count_list.sort(key=lambda x: x[1], reverse=True)\n        count = OrderedDict(count_list)\n\n        return count\n\n    return list(\n        map(_generate_counts, self.bitstrings(filter_perfect_filling, clusters))\n    )\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.list_param","title":"list_param","text":"
list_param(field_name)\n

List the parameters associate with the given variable field_name for each tasks.

Parameters:

Name Type Description Default field_name str

variable name

required Source code in src/bloqade/analog/task/base.py
def list_param(self, field_name: str) -> List[Union[Number, None]]:\n    \"\"\"\n    List the parameters associate with the given variable field_name\n    for each tasks.\n\n    Args:\n        field_name (str): variable name\n\n    \"\"\"\n\n    def cast(x):\n        if x is None:\n            return None\n        elif isinstance(x, (list, tuple, np.ndarray)):\n            return list(map(cast, x))\n        else:\n            return float(x)\n\n    return list(map(cast, (meta.get(field_name) for meta in self.metas)))\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.rydberg_densities","title":"rydberg_densities","text":"
rydberg_densities(filter_perfect_filling=True, clusters=[])\n

Get rydberg density for each task.

Parameters:

Name Type Description Default filter_perfect_filling bool

whether return will only contain perfect filling shots. Defaults to True.

True clusters Union[tuple[int, int], List[tuple[int, int]]]

(tuple[int, int], Sequence[Tuple[int, int]]): cluster index to filter shots from. If none are provided all clusters are used, defaults to [].

[]

Returns:

Name Type Description rydberg_densities Union[Series, DataFrame]

per-site rydberg density for each task as a pandas DataFrame or Series. For example:

0      1\ntask_number\n0            0.053  0.054\n

Source code in src/bloqade/analog/task/base.py
@beartype\ndef rydberg_densities(\n    self,\n    filter_perfect_filling: bool = True,\n    clusters: Union[tuple[int, int], List[tuple[int, int]]] = [],\n) -> Union[pd.Series, pd.DataFrame]:\n    \"\"\"Get rydberg density for each task.\n\n    Args:\n        filter_perfect_filling (bool, optional): whether return will\n            only contain perfect filling shots. Defaults to True.\n        clusters: (tuple[int, int], Sequence[Tuple[int, int]]):\n            cluster index to filter shots from. If none are provided\n            all clusters are used, defaults to [].\n\n    Returns:\n        rydberg_densities (Union[pd.Series, pd.DataFrame]):\n            per-site rydberg density for each task as a pandas DataFrame or Series.\n            For example:\n            ```python\n            0      1\n            task_number\n            0            0.053  0.054\n            ```\n    \"\"\"\n    mask = self._filter(\n        filter_perfect_filling=filter_perfect_filling, clusters=clusters\n    )\n    df = self.dataframe[mask]\n    return 1 - (df.groupby(\"task_number\").mean())\n
"},{"location":"reference/bloqade/analog/task/base/#bloqade.analog.task.base.Report.show","title":"show","text":"
show()\n

Interactive Visualization of the Report

Source code in src/bloqade/analog/task/base.py
def show(self):\n    \"\"\"\n    Interactive Visualization of the Report\n\n    \"\"\"\n    display_report(self)\n
"},{"location":"reference/bloqade/analog/task/batch/","title":"Batch","text":""},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Filter","title":"Filter","text":""},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Filter.filter_metadata","title":"filter_metadata","text":"
filter_metadata(__match_any__=False, **metadata)\n

Create a Batch object that has tasks filtered based on the values of metadata.

Parameters:

Name Type Description Default __match_any__ bool

if True, then a task will be included if it matches any of the metadata filters. If False, then a task will be included only if it matches all of the metadata filters. Defaults to False.

False **metadata MetadataFilterType

the metadata to filter on. The keys are the metadata names and the values (as a set) are the values to filter on. The elements in the set can be Real, Decimal, Tuple[Real], or Tuple[Decimal].

{} Return

type(self): a Batch object with the filtered tasks, either LocalBatch or RemoteBatch depending on the type of self

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef filter_metadata(\n    self, __match_any__: bool = False, **metadata: MetadataFilterType\n) -> Union[\"LocalBatch\", \"RemoteBatch\"]:\n    \"\"\"Create a Batch object that has tasks filtered based on the\n    values of metadata.\n\n    Args:\n        __match_any__: if True, then a task will be included if it\n            matches any of the metadata filters. If False, then a\n            task will be included only if it matches all of the\n            metadata filters. Defaults to False.\n\n        **metadata: the metadata to filter on. The keys are the metadata\n            names and the values (as a set) are the values to filter on.\n            The elements in the set can be Real, Decimal, Tuple[Real], or\n            Tuple[Decimal].\n\n    Return:\n        type(self): a Batch object with the filtered tasks, either\n            LocalBatch or RemoteBatch depending on the type of self\n\n    \"\"\"\n\n    def convert_to_decimal(element):\n        if isinstance(element, list):\n            return list(map(convert_to_decimal, element))\n        elif isinstance(element, (Real, Decimal)):\n            return Decimal(str(element))\n        else:\n            raise ValueError(\n                f\"Invalid value {element} for metadata filter. \"\n                \"Only Real, Decimal, List[Real], and List[Decimal] \"\n                \"are supported.\"\n            )\n\n    def metadata_match_all(task):\n        return all(\n            task.metadata.get(key) in value for key, value in metadata.items()\n        )\n\n    def metadata_match_any(task):\n        return any(\n            task.metadata.get(key) in value for key, value in metadata.items()\n        )\n\n    metadata = {k: list(map(convert_to_decimal, v)) for k, v in metadata.items()}\n\n    metadata_filter = metadata_match_any if __match_any__ else metadata_match_all\n\n    new_tasks = OrderedDict(\n        [(k, v) for k, v in self.tasks.items() if metadata_filter(v)]\n    )\n\n    kw = dict(self.__dict__)\n    kw[\"tasks\"] = new_tasks\n\n    return self.__class__(**kw)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch","title":"LocalBatch dataclass","text":"
LocalBatch(source, tasks, name=None)\n

Bases: Serializable, Filter

"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch._run","title":"_run","text":"
_run(multiprocessing=False, num_workers=None, **kwargs)\n

Private method to run tasks in the batch.

Parameters:

Name Type Description Default multiprocessing bool

If True, tasks are run in parallel using multiple processes. If False, tasks are run sequentially in a single process. Defaults to False.

False num_workers Optional[int]

The maximum number of processes that can be used to execute the given calls if multiprocessing is True. If None, the number of workers will be the number of processors on the machine.

None **kwargs

Arbitrary keyword arguments passed to the task's run method.

{}

Raises:

Type Description ValueError

If num_workers is not None and multiprocessing is False.

Returns:

Name Type Description self

The instance of the batch with tasks run.

Source code in src/bloqade/analog/task/batch.py
def _run(\n    self, multiprocessing: bool = False, num_workers: Optional[int] = None, **kwargs\n):\n    \"\"\"\n    Private method to run tasks in the batch.\n\n    Args:\n        multiprocessing (bool, optional): If True, tasks are run in parallel using multiple processes.\n            If False, tasks are run sequentially in a single process. Defaults to False.\n        num_workers (Optional[int], optional): The maximum number of processes that can be used to\n            execute the given calls if multiprocessing is True. If None, the number of workers will be the number of processors on the machine.\n        **kwargs: Arbitrary keyword arguments passed to the task's run method.\n\n    Raises:\n        ValueError: If num_workers is not None and multiprocessing is False.\n\n    Returns:\n        self: The instance of the batch with tasks run.\n    \"\"\"\n    if multiprocessing:\n        from concurrent.futures import ProcessPoolExecutor as Pool\n\n        with Pool(max_workers=num_workers) as pool:\n            futures = OrderedDict()\n            for task_number, task in enumerate(self.tasks.values()):\n                futures[task_number] = pool.submit(task.run, **kwargs)\n\n            for task_number, future in futures.items():\n                self.tasks[task_number] = future.result()\n\n    else:\n        if num_workers is not None:\n            raise ValueError(\n                \"num_workers is only used when multiprocessing is enabled.\"\n            )\n        for task in self.tasks.values():\n            task.run(**kwargs)\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch.report","title":"report","text":"
report()\n

Generate analysis report base on currently completed tasks in the LocalBatch.

Return

Report

Source code in src/bloqade/analog/task/batch.py
def report(self) -> Report:\n    \"\"\"\n    Generate analysis report base on currently\n    completed tasks in the LocalBatch.\n\n    Return:\n        Report\n\n    \"\"\"\n\n    ## this potentially can be specialize/disatch\n    ## offline\n    index = []\n    data = []\n    metas = []\n    geos = []\n\n    for task_number, task in self.tasks.items():\n        geometry = task.geometry\n        perfect_sorting = \"\".join(map(str, geometry.filling))\n        parallel_decoder = geometry.parallel_decoder\n\n        if parallel_decoder:\n            cluster_indices = parallel_decoder.get_cluster_indices()\n        else:\n            cluster_indices = {(0, 0): list(range(len(perfect_sorting)))}\n\n        shot_iter = filter(\n            lambda shot: shot.shot_status == QuEraShotStatusCode.Completed,\n            task.result().shot_outputs,\n        )\n\n        for shot, (cluster_coordinate, cluster_index) in product(\n            shot_iter, cluster_indices.items()\n        ):\n            pre_sequence = \"\".join(\n                map(\n                    str,\n                    (shot.pre_sequence[index] for index in cluster_index),\n                )\n            )\n\n            post_sequence = np.asarray(\n                [shot.post_sequence[index] for index in cluster_index],\n                dtype=np.int8,\n            )\n\n            pfc_sorting = \"\".join(\n                [perfect_sorting[index] for index in cluster_index]\n            )\n\n            key = (\n                task_number,\n                cluster_coordinate,\n                pfc_sorting,\n                pre_sequence,\n            )\n\n            index.append(key)\n            data.append(post_sequence)\n\n        metas.append(task.metadata)\n        geos.append(task.geometry)\n\n    index = pd.MultiIndex.from_tuples(\n        index, names=[\"task_number\", \"cluster\", \"perfect_sorting\", \"pre_sequence\"]\n    )\n\n    df = pd.DataFrame(data, index=index)\n    df.sort_index(axis=\"index\")\n\n    rept = None\n    if self.name is None:\n        rept = Report(df, metas, geos, \"Local\")\n    else:\n        rept = Report(df, metas, geos, self.name)\n\n    return rept\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.LocalBatch.rerun","title":"rerun","text":"
rerun(multiprocessing=False, num_workers=None, **kwargs)\n

Rerun all the tasks in the LocalBatch.

Return

Report

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef rerun(\n    self, multiprocessing: bool = False, num_workers: Optional[int] = None, **kwargs\n):\n    \"\"\"\n    Rerun all the tasks in the LocalBatch.\n\n    Return:\n        Report\n\n    \"\"\"\n\n    return self._run(\n        multiprocessing=multiprocessing, num_workers=num_workers, **kwargs\n    )\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch","title":"RemoteBatch dataclass","text":"
RemoteBatch(source, tasks, name=None)\n

Bases: Serializable, Filter

"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.total_nshots","title":"total_nshots property","text":"
total_nshots\n

Total number of shots of all tasks in the RemoteBatch

Return

number of shots

"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch._submit","title":"_submit","text":"
_submit(\n    shuffle_submit_order=True,\n    ignore_submission_error=False,\n    **kwargs\n)\n

Private method to submit tasks in the RemoteBatch.

Parameters:

Name Type Description Default shuffle_submit_order bool

If True, tasks are submitted in a random order. If False, tasks are submitted in the order they were added to the batch. Defaults to True.

True ignore_submission_error bool

If True, submission errors are ignored and the method continues to submit the remaining tasks. If False, the method stops at the first submission error. Defaults to False.

False **kwargs

Arbitrary keyword arguments.

{}

Returns:

Name Type Description RemoteBatch RemoteBatch

The RemoteBatch instance with tasks submitted.

Source code in src/bloqade/analog/task/batch.py
def _submit(\n    self, shuffle_submit_order: bool = True, ignore_submission_error=False, **kwargs\n) -> \"RemoteBatch\":\n    \"\"\"\n    Private method to submit tasks in the RemoteBatch.\n\n    Args:\n        shuffle_submit_order (bool, optional): If True, tasks are submitted in a random order.\n            If False, tasks are submitted in the order they were added to the batch. Defaults to True.\n        ignore_submission_error (bool, optional): If True, submission errors are ignored and the method continues to submit the remaining tasks.\n            If False, the method stops at the first submission error. Defaults to False.\n        **kwargs: Arbitrary keyword arguments.\n\n    Returns:\n        RemoteBatch: The RemoteBatch instance with tasks submitted.\n    \"\"\"\n    from bloqade.analog import save\n\n    # online, non-blocking\n    if shuffle_submit_order:\n        submission_order = np.random.permutation(list(self.tasks.keys()))\n    else:\n        submission_order = list(self.tasks.keys())\n\n    # submit tasks in random order but store them\n    # in the original order of tasks.\n    # futures = OrderedDict()\n\n    ## upon submit() should validate for Both backends\n    ## and throw errors when fail.\n    errors = BatchErrors()\n    shuffled_tasks = OrderedDict()\n    for task_index in submission_order:\n        task = self.tasks[task_index]\n        shuffled_tasks[task_index] = task\n        try:\n            task.submit(**kwargs)\n        except BaseException as error:\n            # record the error in the error dict\n            errors.task_errors[int(task_index)] = TaskError(\n                exception_type=error.__class__.__name__,\n                stack_trace=traceback.format_exc(),\n            )\n\n            task.task_result_ir = QuEraTaskResults(\n                task_status=QuEraTaskStatusCode.Unaccepted\n            )\n\n    self.tasks = shuffled_tasks  # permute order using dump way\n\n    if len(errors.task_errors) > 0:\n        time_stamp = datetime.datetime.now()\n\n        if \"win\" in sys.platform:\n            time_stamp = str(time_stamp).replace(\":\", \"~\")\n\n        if self.name:\n            future_file = f\"{self.name}-partial-batch-future-{time_stamp}.json\"\n            error_file = f\"{self.name}-partial-batch-errors-{time_stamp}.json\"\n        else:\n            future_file = f\"partial-batch-future-{time_stamp}.json\"\n            error_file = f\"partial-batch-errors-{time_stamp}.json\"\n\n        cwd = os.getcwd()\n        # cloud_batch_result.save_json(future_file, indent=2)\n        # saving ?\n\n        save(errors, error_file)\n        save(self, future_file)\n\n        if ignore_submission_error:\n            warnings.warn(\n                \"One or more error(s) occured during submission, please see \"\n                \"the following files for more information:\\n\"\n                f\"  - {os.path.join(cwd, future_file)}\\n\"\n                f\"  - {os.path.join(cwd, error_file)}\\n\",\n                RuntimeWarning,\n            )\n        else:\n            raise RemoteBatch.SubmissionException(\n                str(errors)\n                + \"\\n\"\n                + \"One or more error(s) occured during submission, please see \"\n                \"the following files for more information:\\n\"\n                f\"  - {os.path.join(cwd, future_file)}\\n\"\n                f\"  - {os.path.join(cwd, error_file)}\\n\"\n            )\n\n    else:\n        # TODO: think about if we should automatically save successful submissions\n        #       as well.\n        pass\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.cancel","title":"cancel","text":"
cancel()\n

Cancel all the tasks in the Batch.

Return

self

Source code in src/bloqade/analog/task/batch.py
def cancel(self) -> \"RemoteBatch\":\n    \"\"\"\n    Cancel all the tasks in the Batch.\n\n    Return:\n        self\n\n    \"\"\"\n    # cancel all jobs\n    for task in self.tasks.values():\n        task.cancel()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.fetch","title":"fetch","text":"
fetch()\n

Fetch the tasks in the Batch.

Note

Fetching will update the status of tasks, and only pull the results for those tasks that have completed.

Return

self

Source code in src/bloqade/analog/task/batch.py
def fetch(self) -> \"RemoteBatch\":\n    \"\"\"\n    Fetch the tasks in the Batch.\n\n    Note:\n        Fetching will update the status of tasks,\n        and only pull the results for those tasks\n        that have completed.\n\n    Return:\n        self\n\n    \"\"\"\n    # online, non-blocking\n    # pull the results only when its ready\n    for task in self.tasks.values():\n        task.fetch()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_completed_tasks","title":"get_completed_tasks","text":"
get_completed_tasks()\n

Create a RemoteBatch object that contain completed tasks from current Batch.

Tasks consider completed with following status codes:

  1. Completed
  2. Partial
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def get_completed_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain completed tasks from current Batch.\n\n    Tasks consider completed with following status codes:\n\n    1. Completed\n    2. Partial\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    statuses = [\n        \"Completed\",\n        \"Partial\",\n    ]\n    return self.get_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_failed_tasks","title":"get_failed_tasks","text":"
get_failed_tasks()\n

Create a RemoteBatch object that contain failed tasks from current Batch.

failed tasks with following status codes:

  1. Failed
  2. Unaccepted
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def get_failed_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain failed tasks from current Batch.\n\n    failed tasks with following status codes:\n\n    1. Failed\n    2. Unaccepted\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # statuses that are in a state that are\n    # completed because of an error\n    statuses = [\"Failed\", \"Unaccepted\"]\n    return self.get_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_finished_tasks","title":"get_finished_tasks","text":"
get_finished_tasks()\n

Create a RemoteBatch object that contain finished tasks from current Batch.

Tasks consider finished with following status codes:

  1. Failed
  2. Unaccepted
  3. Completed
  4. Partial
  5. Cancelled
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def get_finished_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain finished tasks from current Batch.\n\n    Tasks consider finished with following status codes:\n\n    1. Failed\n    2. Unaccepted\n    3. Completed\n    4. Partial\n    5. Cancelled\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # statuses that are in a state that will\n    # not run going forward for any reason\n    statuses = [\"Completed\", \"Failed\", \"Unaccepted\", \"Partial\", \"Cancelled\"]\n    return self.get_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.get_tasks","title":"get_tasks","text":"
get_tasks(*status_codes)\n

Get Tasks with specify status_codes.

Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef get_tasks(self, *status_codes: str) -> \"RemoteBatch\":\n    \"\"\"\n    Get Tasks with specify status_codes.\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # offline:\n    st_codes = [QuEraTaskStatusCode(x) for x in status_codes]\n\n    new_task_results = OrderedDict()\n    for task_number, task in self.tasks.items():\n        if task.task_result_ir.task_status in st_codes:\n            new_task_results[task_number] = task\n\n    return RemoteBatch(self.source, new_task_results, name=self.name)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.pull","title":"pull","text":"
pull()\n

Pull results of the tasks in the Batch.

Note

Pulling will pull the results for the tasks. If a given task(s) has not been completed, wait until it finished.

Return

self

Source code in src/bloqade/analog/task/batch.py
def pull(self) -> \"RemoteBatch\":\n    \"\"\"\n    Pull results of the tasks in the Batch.\n\n    Note:\n        Pulling will pull the results for the tasks.\n        If a given task(s) has not been completed, wait\n        until it finished.\n\n    Return:\n        self\n    \"\"\"\n    # online, blocking\n    # pull the results. if its not ready, hanging\n    for task in self.tasks.values():\n        task.pull()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.remove_failed_tasks","title":"remove_failed_tasks","text":"
remove_failed_tasks()\n

Create a RemoteBatch object that contain tasks from current Batch, with failed tasks removed.

failed tasks with following status codes:

  1. Failed
  2. Unaccepted
Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def remove_failed_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain tasks from current Batch,\n    with failed tasks removed.\n\n    failed tasks with following status codes:\n\n    1. Failed\n    2. Unaccepted\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # statuses that are in a state that will\n    # not run going forward because of an error\n    statuses = [\"Failed\", \"Unaccepted\"]\n    return self.remove_tasks(*statuses)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.remove_invalid_tasks","title":"remove_invalid_tasks","text":"
remove_invalid_tasks()\n

Create a RemoteBatch object that contain tasks from current Batch, with all Unaccepted tasks removed.

Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
def remove_invalid_tasks(self) -> \"RemoteBatch\":\n    \"\"\"\n    Create a RemoteBatch object that\n    contain tasks from current Batch,\n    with all Unaccepted tasks removed.\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    return self.remove_tasks(\"Unaccepted\")\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.remove_tasks","title":"remove_tasks","text":"
remove_tasks(*status_codes)\n

Remove Tasks with specify status_codes.

Return

RemoteBatch

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef remove_tasks(\n    self,\n    *status_codes: Literal[\n        \"Created\",\n        \"Running\",\n        \"Completed\",\n        \"Failed\",\n        \"Cancelled\",\n        \"Executing\",\n        \"Enqueued\",\n        \"Accepted\",\n        \"Unaccepted\",\n        \"Partial\",\n        \"Unsubmitted\",\n    ],\n) -> \"RemoteBatch\":\n    \"\"\"\n    Remove Tasks with specify status_codes.\n\n    Return:\n        RemoteBatch\n\n    \"\"\"\n    # offline:\n\n    st_codes = [QuEraTaskStatusCode(x) for x in status_codes]\n\n    new_results = OrderedDict()\n    for task_number, task in self.tasks.items():\n        if task.task_result_ir.task_status in st_codes:\n            continue\n\n        new_results[task_number] = task\n\n    return RemoteBatch(self.source, new_results, self.name)\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.report","title":"report","text":"
report()\n

Generate analysis report base on currently completed tasks in the RemoteBatch.

Return

Report

Source code in src/bloqade/analog/task/batch.py
def report(self) -> \"Report\":\n    \"\"\"\n    Generate analysis report base on currently\n    completed tasks in the RemoteBatch.\n\n    Return:\n        Report\n\n    \"\"\"\n    ## this potentially can be specialize/disatch\n    ## offline\n    index = []\n    data = []\n    metas = []\n    geos = []\n\n    for task_number, task in self.tasks.items():\n        ## fliter not existing results tasks:\n        if (task.task_id is None) or (not task._result_exists()):\n            continue\n\n        ## filter has result but is not correctly completed.\n        if task.task_result_ir.task_status not in [\n            QuEraTaskStatusCode.Completed,\n            QuEraTaskStatusCode.Partial,\n        ]:\n            continue\n\n        geometry = task.geometry\n        perfect_sorting = \"\".join(map(str, geometry.filling))\n        parallel_decoder = geometry.parallel_decoder\n\n        if parallel_decoder:\n            cluster_indices = parallel_decoder.get_cluster_indices()\n        else:\n            cluster_indices = {(0, 0): list(range(len(perfect_sorting)))}\n\n        shot_iter = filter(\n            lambda shot: shot.shot_status == QuEraShotStatusCode.Completed,\n            task.result().shot_outputs,\n        )\n\n        for shot, (cluster_coordinate, cluster_index) in product(\n            shot_iter, cluster_indices.items()\n        ):\n            pre_sequence = \"\".join(\n                map(\n                    str,\n                    (shot.pre_sequence[index] for index in cluster_index),\n                )\n            )\n\n            post_sequence = np.asarray(\n                [shot.post_sequence[index] for index in cluster_index],\n                dtype=np.int8,\n            )\n\n            pfc_sorting = \"\".join(\n                [perfect_sorting[index] for index in cluster_index]\n            )\n\n            key = (\n                task_number,\n                cluster_coordinate,\n                pfc_sorting,\n                pre_sequence,\n            )\n\n            index.append(key)\n            data.append(post_sequence)\n\n        metas.append(task.metadata)\n        geos.append(task.geometry)\n\n    index = pd.MultiIndex.from_tuples(\n        index, names=[\"task_number\", \"cluster\", \"perfect_sorting\", \"pre_sequence\"]\n    )\n\n    df = pd.DataFrame(data, index=index)\n    df.sort_index(axis=\"index\")\n\n    rept = None\n    if self.name is None:\n        rept = Report(df, metas, geos, \"Remote\")\n    else:\n        rept = Report(df, metas, geos, self.name)\n\n    return rept\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.resubmit","title":"resubmit","text":"
resubmit(shuffle_submit_order=True)\n

Resubmit all the tasks in the RemoteBatch

Return

self

Source code in src/bloqade/analog/task/batch.py
@beartype\ndef resubmit(self, shuffle_submit_order: bool = True) -> \"RemoteBatch\":\n    \"\"\"\n    Resubmit all the tasks in the RemoteBatch\n\n    Return:\n        self\n\n    \"\"\"\n    # online, non-blocking\n    self._submit(shuffle_submit_order, force=True)\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.retrieve","title":"retrieve","text":"
retrieve()\n

Retrieve missing task results.

Note

Retrieve will update the status of tasks, and only pull the results for those tasks that have completed.

Return

self

Source code in src/bloqade/analog/task/batch.py
def retrieve(self) -> \"RemoteBatch\":\n    \"\"\"Retrieve missing task results.\n\n    Note:\n        Retrieve will update the status of tasks,\n        and only pull the results for those tasks\n        that have completed.\n\n    Return:\n        self\n\n    \"\"\"\n    # partially online, sometimes blocking\n    # pull the results for tasks that have\n    # not been pulled already.\n    for task in self.tasks.values():\n        if not task._result_exists():\n            task.pull()\n\n    return self\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.RemoteBatch.tasks_metric","title":"tasks_metric","text":"
tasks_metric()\n

Get current tasks status metric

Return

dataframe with [\"task id\", \"status\", \"shots\"]

Source code in src/bloqade/analog/task/batch.py
def tasks_metric(self) -> pd.DataFrame:\n    \"\"\"\n    Get current tasks status metric\n\n    Return:\n        dataframe with [\"task id\", \"status\", \"shots\"]\n\n    \"\"\"\n    # [TODO] more info on current status\n    # offline, non-blocking\n    tid = []\n    data = []\n    for int, task in self.tasks.items():\n        tid.append(int)\n\n        dat = [None, None, None]\n        dat[0] = task.task_id\n        if task.task_result_ir is not None:\n            dat[1] = task.task_result_ir.task_status.name\n        dat[2] = task.task_ir.nshots\n        data.append(dat)\n\n    return pd.DataFrame(data, index=tid, columns=[\"task ID\", \"status\", \"shots\"])\n
"},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Serializable","title":"Serializable","text":""},{"location":"reference/bloqade/analog/task/batch/#bloqade.analog.task.batch.Serializable.json","title":"json","text":"
json(**options)\n

Serialize the object to JSON string.

Return

JSON string

Source code in src/bloqade/analog/task/batch.py
def json(self, **options) -> str:\n    \"\"\"\n    Serialize the object to JSON string.\n\n    Return:\n        JSON string\n\n    \"\"\"\n    from bloqade.analog import dumps\n\n    return dumps(self, **options)\n
"},{"location":"reference/bloqade/analog/task/bloqade/","title":"Bloqade","text":""},{"location":"reference/bloqade/analog/task/braket/","title":"Braket","text":""},{"location":"reference/bloqade/analog/task/braket_simulator/","title":"Braket simulator","text":""},{"location":"reference/bloqade/analog/task/quera/","title":"Quera","text":""}]} \ No newline at end of file