Skip to content

Commit 6053b28

Browse files
authored
Restructure digital tutorials (#266)
In light of more tutorials coming in (see #260 ) I figured re-structuring that section of the docs makes sense. This also adds a very short example showing how you can manually include noise in a squin kernel. That example requires QuEraComputing/bloqade-circuit#441 to be merged and released though.
1 parent b87ac0b commit 6053b28

17 files changed

+443
-56
lines changed

docs/digital/dialects_and_kernels.md

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
11
# Dialects and kernels
22

3+
Bloqade provides a set of pre-defined dialects, with which you can write your programs and circuits.
4+
5+
Once you have your kernel, you can inspect their intermediate representation (IR), apply different optimizations using [compiler passes](../quick_start/circuits/compiler_passes/index.md), or run them on a [(simulator) device](./simulator_device/simulator_device.md).
6+
37
!!! info
48
A **kernel** function is a piece of code that runs on specialized hardware such as a quantum computer.
59

610
A **dialect** is a domain-specific language (DSL) with which you can write such a kernel.
711
Each dialect comes with a specific set of statements and instructions you can use in order to write your program.
812

9-
Bloqade provides a set of pre-defined dialects, with which you can write your programs and circuits.
1013

11-
Once you have your kernel, you can inspect their intermediate representation (IR), apply different optimizations using [compiler passes](../quick_start/circuits/compiler_passes/index.md), or run them on a [(simulator) device](./simulator_device/simulator_device.md).
14+
When running code that targets a specialized execution environment, there are typically several layers involved.
15+
At the surface, the programmer writes functions in a syntax that may resemble a host language (e.g., Python), but is actually expressed in a dialect— a domain-specific variant with its own semantics.
16+
A decorator marks these functions so they can be intercepted before normal host-language execution.
17+
All dialects can be used by decorating a function.
18+
19+
!!! info
20+
Here's a short primer on decorators: a decorator in Python is simply a function (or any callable really) that takes in another function as argument and returns yet another function (callable).
21+
Usually, the returned function will be a modified version of the input.
22+
Decorators are used with the `@` syntax.
23+
24+
25+
Instead of running directly, the kernel function body is parsed and translated (lowered) into an intermediate representation (IR).
26+
This IR can be manipulated (e.g. to perform optimizations) and can later be executed by an interpreter that understands the dialect's semantics.
27+
The interpreter uses an internal instruction set to execute the code on the intended backend, which may be a simulator, virtual machine, or physical device.
28+
This separation lets developers write high-level, expressive code while the interpreter ensures it runs correctly in the target environment.
29+
[QuEra's Kirin](https://queracomputing.github.io/kirin/latest/) infrastructure uses this concept by defining custom dialects that are tailored towards the needs to program neutral atom quantum computers.
30+
While the dialects are not python syntax, Kirin still uses the python interpreter to execute the code.
31+
32+
33+
!!! note
34+
It is important to understand that when you are writing a kernel function in a dialect you are generally **not writing Python** code, even though it looks a lot like it.
35+
Therefore, kernel functions can usually not be called directly.
36+
Think of this as trying to execute another programming language with the Python interpreter: of course, that will error.
1237

1338

1439
# Available dialects
@@ -128,18 +153,39 @@ main.print()
128153

129154
## squin
130155

131-
This dialect is, in a sense, more expressive than the qasm2 dialects: it allows you to specify operators rather than just gate applications.
132-
That can be useful if you're trying to e.g. simulate a Hamiltonian time evolution.
133-
134156
!!! warning
135157
The squin dialect is in an early stage of development.
136158
Expect substantial changes to it in the near future.
137159

160+
161+
This dialect is, in a sense, more expressive than the qasm2 dialects: it allows you to specify operators rather than just gate applications.
162+
That can be useful if you're trying to e.g. simulate a Hamiltonian time evolution.
163+
164+
For simple circuits, however, gate applications also have short-hand standard library definitions defined in the `squin.gate` submodule.
138165
Here's a short example:
139166

140167
```python
141168
from bloqade import squin
142169

170+
@squin.kernel
171+
def main():
172+
q = squin.qubit.new(2)
173+
squin.gate.h(q[0])
174+
squin.gate.cx(q[0], q[1])
175+
return squin.qubit.measure(q)
176+
177+
# have a look at the IR
178+
main.print()
179+
```
180+
181+
182+
As mentioned above, you can also build up more complex "operators" that are then applied to any number of qubits.
183+
To show how you can do that, here's an example on how to write the above kernel defining the gates as separate operators.
184+
This isn't exactly a practical use-case, but serves as an example.
185+
186+
```python
187+
from bloqade import squin
188+
143189
@squin.kernel
144190
def main():
145191
q = squin.qubit.new(2)
@@ -148,10 +194,10 @@ def main():
148194
# apply a hadamard to only the first qubit
149195
h1 = squin.op.kron(h, squin.op.identity(sites=1))
150196

151-
squin.qubit.apply(h1, q)
197+
squin.qubit.apply(h1, q[0], q[1])
152198

153199
cx = squin.op.cx()
154-
squin.qubit.apply(cx, q)
200+
squin.qubit.apply(cx, q[0], q[1])
155201

156202
return squin.qubit.measure(q)
157203

File renamed without changes.
File renamed without changes.
File renamed without changes.

docs/digital/examples/ghz.py renamed to docs/digital/examples/qasm2/ghz.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
# <div align="center">
2525
# <picture>
26-
# <img src="../ghz_linear_circuit.svg" >
26+
# <img src="../../ghz_linear_circuit.svg" >
2727
# </picture>
2828
# </div>
2929

@@ -60,13 +60,13 @@ def ghz_linear_program():
6060
# <p>
6161
# Before going any further, it's worth distinguishing between the concept of circuit depth and circuit execution depth.
6262
# For example, in the following implementation, each CX gate instruction inside the for-loop is executed in sequence.
63-
# So even thought the circuit depth is $log(N) = n$, the circuit execution depth is still $N$.
63+
# So even though the circuit depth is $log(N) = n$, the circuit execution depth is still $N$.
6464
# </p>
6565
# </div>
6666

6767
# <div align="center">
6868
# <picture>
69-
# <img src="../ghz_log_circuit.svg" >
69+
# <img src="../../ghz_log_circuit.svg" >
7070
# </picture>
7171
# </div>
7272

File renamed without changes.

docs/digital/examples/pauli_exponentiation.svg renamed to docs/digital/examples/qasm2/pauli_exponentiation.svg

Lines changed: 1 addition & 1 deletion
Loading
File renamed without changes.

docs/digital/examples/qft.py renamed to docs/digital/examples/qasm2/qft.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,11 @@
55
# our high-level programming features.
66
#
77
# To begin, we will import the `qasm2` module from the `bloqade` package and the `PyQrack`
8-
# backend from the `bloqade.pyqrack` module, which can be installed via
9-
#
10-
# ```bash
11-
# pip install bloqade-pyqrack[backend]
12-
# ```
13-
# with the `backend` being one of ` pyqrack`, `pyqrack-cpu`, `pyqrack-cuda` depending on
14-
# the hardware and OS you have. see [README](https://github.com/QuEraComputing/bloqade-pyqrack?tab=readme-ov-file#which-extra-do-i-install)
15-
# for mote details.
8+
# backend from the `bloqade.pyqrack` module.
169
# %%
1710
import math
1811

19-
from bloqade.pyqrack import PyQrack
12+
from bloqade.pyqrack import StackMemorySimulator
2013

2114
from bloqade import qasm2
2215

@@ -56,13 +49,13 @@ def main():
5649
# to see the final state of the qubits after applying the QFT circuit.
5750
# <div align="center">
5851
# <picture>
59-
# <img src="../qft.svg" >
52+
# <img src="../../qft.svg" >
6053
# </picture>
6154
# </div>
6255

6356

6457
# %%
65-
device = PyQrack()
58+
device = StackMemorySimulator(min_qubits=3)
6659
qreg = device.run(main)
6760
print(qreg)
6861

File renamed without changes.

0 commit comments

Comments
 (0)