Hamiltonians

Quantum Hamiltonians encode the essential physical properties of a quantum system. For the analog mode of neutral-atom quantum computers, the quantum dynamics is governed by the Rydberg Hamiltonian $\hat{\mathcal{H}}$:

\[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, 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/|\overrightarrow{\mathbf{r}_j} - \overrightarrow{\mathbf{r}_k}|^6$ describes the Rydberg interaction (van der Waals interaction) between atoms $j$ and $k$ where $\overrightarrow{\mathbf{r}_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 μm}^6$ for $|r \rangle = \lvert 70S_{1/2} \rangle$ of the $^{87}$Rb atoms; $\hbar$ is the reduced Planck's constant.

One can use the Rydberg Hamiltonian to understand the ground state properties of the corresponding system and to generate interesting quantum dynamics. The Rydberg Hamiltonian is generally specified by atom positions $\overrightarrow{\mathbf{r}_j}$, Rabi frequencies $\Omega_j$, laser phase $\phi_j$, and detunings $\Delta_j$. In Bloqade, we can easily create a Hamiltonian by inputting these variable parameters into the function rydberg_h. Furthermore, by inputting waveforms for the Rabi frequency and detuning, we can easily generate time-dependent Hamiltonians.

Building Time-Independent Hamiltonians

To specify the Hamiltonian, we first need to specify the atom positions, which determine the Rydberg interactions strengths $V_{jk}$ between pairs of atoms. Here, we generate a square lattice by using the code below:

julia> using Bloqade
julia> atoms = generate_sites(SquareLattice(), 3, 3, scale=6.3)9-element AtomList{2, Float64}: (0.0, 0.0) (6.3, 0.0) (12.6, 0.0) (0.0, 6.3) (6.3, 6.3) (12.6, 6.3) (0.0, 12.6) (6.3, 12.6) (12.6, 12.6)

Please refer to the Lattices page for more details on how to generate lattices and the relevant operations.

Then, the Hamiltonian can be simply built by inputting the generated atom positions atoms and by specifying the strength of the detuning Δ, Rabi frequency Ω, and laser phase ϕ:

julia> h0 = rydberg_h(atoms; Δ=1.2*2π, Ω=1.1*2π, ϕ=2.1)nqubits: 9
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|r_i-r_j|^6 n_i n_j
├─ [+] 2π ⋅ 0.55 ⋅ ∑ e^{2.1 ⋅ im} |0⟩⟨1| + e^{-2.1 ⋅ im} |1⟩⟨0|
└─ [-] 2π ⋅ 1.2 ⋅ ∑ n_i

Note that the default value for the Rydberg interaction constant is $C_6 = 2\pi \times 862690 \text{ MHz μm}^6$ to match the default unit used on the hardware. For more information about units, please refer to Bloqade. Instead of using the default value for $C_6$, the users are free to set their own values. For instance, if the users would like to have a chain lattice with nearest-neighbor atoms separated by 1 μm, and interaction strength to be a particular value, say, $2\pi * 10.0^6 \text{ MHz μm}^6$, it can be done with the following code:

julia> atoms = generate_sites(ChainLattice(), 9, scale=1.0)9-element AtomList{1, Float64}:
 (0.0,)
 (1.0,)
 (2.0,)
 (3.0,)
 (4.0,)
 (5.0,)
 (6.0,)
 (7.0,)
 (8.0,)
julia> h0 = rydberg_h(atoms; C=2π*10.0^6, Δ=1.2*2π, Ω=1.1*2π, ϕ=2.1)nqubits: 9 + ├─ [+] ∑ 2π ⋅ 10.0e5.0/|r_i-r_j|^6 n_i n_j ├─ [+] 2π ⋅ 0.55 ⋅ ∑ e^{2.1 ⋅ im} |0⟩⟨1| + e^{-2.1 ⋅ im} |1⟩⟨0| └─ [-] 2π ⋅ 1.2 ⋅ ∑ n_i

Building Time-Dependent Hamiltonians

One can also directly use waveforms (instead of constant values of detuning, Rabi frequency, and laser phase) to build a time-dependent Hamiltonian. First, let us again use the generate_sites to create a list of atom coordinates:

julia> atoms = generate_sites(ChainLattice(), 5, scale=5.72)5-element AtomList{1, Float64}:
 (0.0,)
 (5.72,)
 (11.44,)
 (17.16,)
 (22.88,)

Then, we generate the time-dependent pulses for $\Omega$ and $\Delta$ by using piecewise_linear. For details on how to create waveforms and the built-in functions, please refer to the page Waveforms.

julia> Ω1 = piecewise_linear(clocks=[0.0, 0.1, 2.1, 2.2], values=2π*[0.0, 6.0, 6.0, 0]);
julia> Δ1 = piecewise_linear(clocks=[0.0, 0.6, 2.1, 2.2], values=2π*[-10.1, -10.1, 10.1, 10.1]);

The time-dependent Hamiltonian can then be easily generated by inputting the waveforms into the function rydberg_h:

julia> h1 = rydberg_h(atoms; Δ=Δ1, Ω=Ω1)nqubits: 5
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|r_i-r_j|^6 n_i n_j
├─ [+] Ω(t) ⋅ ∑ σ^x_i
└─ [-] Δ(t) ⋅ ∑ n_i

By specifying the time of h1, we can access the Hamiltonian at a particular time, e.g.:

julia> ht= h1 |> attime(0.5)nqubits: 5
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|r_i-r_j|^6 n_i n_j
├─ [+] 2π ⋅ 3.0 ⋅ ∑ σ^x_i
└─ [-] 2π ⋅ -10.1 ⋅ ∑ n_i

Building Hamiltonians with Site-Dependent Waveforms

In certain cases, the user may want to build a Hamiltonian that has site-dependent $\Omega_j$, $\phi_j$, and $\Delta_j$, which may or may not have time dependence.

For the time-independent Hamiltonian, one can for example build a Hamiltonian like:

julia> h0 = rydberg_h(atoms; Δ=1.2*2π*rand(length(atoms)), Ω=1.1*2π*rand(length(atoms)), ϕ=2.1)nqubits: 5
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|r_i-r_j|^6 n_i n_j
├─ [+] ∑ Ω_i ⋅ (e^{2.1 ⋅ im} |0⟩⟨1| + e^{-2.1 ⋅ im} |1⟩⟨0|)
└─ [-] ∑ Δ_i ⋅ n_i

For time-dependent Hamiltonians, here is an example:

julia> atoms = generate_sites(ChainLattice(), 5, scale=5.72)5-element AtomList{1, Float64}:
 (0.0,)
 (5.72,)
 (11.44,)
 (17.16,)
 (22.88,)
julia> Δ1 = map(1:length(atoms)) do idx Waveform(t-> idx*sin(2π*t), duration = 2) end5-element Vector{Waveform{Main.var"#2#4"{Int64}, Int64}}: Waveform(_, 2) Waveform(_, 2) Waveform(_, 2) Waveform(_, 2) Waveform(_, 2)
julia> h =rydberg_h(atoms; Δ=Δ1)nqubits: 5 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|r_i-r_j|^6 n_i n_j └─ [-] ∑ Δ_i ⋅ n_i

Hamiltonian Expressions

Bloqade uses "block"s from Yao to build symbolic hamiltonian expressions. This gives users the flexibility to define various kinds of Hamiltonians by simply writing down the expression.

Please refer to the References section below for the types of operators supported by Bloqade.

As an example, we can explicitly add up some Hamiltonian terms to compose a new Hamiltonian, e.g.:

julia> using Bloqade
julia> h = 2π*1.1*SumOfX(5, 1.0) + 2π*1.2*SumOfZ(5, 1.0)nqubits: 5 + ├─ [scale: 6.911503837897546] ∑ σ^x_i └─ [scale: 7.5398223686155035] ∑ σ^z_i

Convert Hamiltonians to Matrices

An Hamiltonian expression can be converted to a matrix via the mat interface from Yao:

YaoAPI.matFunction
mat([T=ComplexF64], blk)

Returns the most compact matrix form of given block, e.g

Examples

julia> mat(X)
2×2 LuxurySparse.SDPermMatrix{ComplexF64, Int64, Vector{ComplexF64}, Vector{Int64}}:
 0.0+0.0im  1.0+0.0im
 1.0+0.0im  0.0+0.0im

julia> mat(Float64, X)
2×2 LuxurySparse.SDPermMatrix{Float64, Int64, Vector{Float64}, Vector{Int64}}:
 0.0  1.0
 1.0  0.0

julia> mat(kron(X, X))
4×4 LuxurySparse.SDPermMatrix{ComplexF64, Int64, Vector{ComplexF64}, Vector{Int64}}:
 0.0+0.0im  0.0+0.0im  0.0+0.0im  1.0+0.0im
 0.0+0.0im  0.0+0.0im  1.0+0.0im  0.0+0.0im
 0.0+0.0im  1.0+0.0im  0.0+0.0im  0.0+0.0im
 1.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im

julia> mat(kron(X, X) + put(2, 1=>X))
4×4 SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:
     ⋅      1.0+0.0im      ⋅      1.0+0.0im
 1.0+0.0im      ⋅      1.0+0.0im      ⋅
     ⋅      1.0+0.0im      ⋅      1.0+0.0im
 1.0+0.0im      ⋅      1.0+0.0im      ⋅    

This method will return the most compact matrix representation of the operator, e.g.:

julia> mat(X) # will return a PermMatrix2×2 LuxurySparse.SDPermMatrix{ComplexF64, Int64, Vector{ComplexF64}, Vector{Int64}}:
 0.0+0.0im  1.0+0.0im
 1.0+0.0im  0.0+0.0im
julia> mat(ht) # will return a SparseMatrixCSC32×32 SparseMatrixCSC{ComplexF64, Int64} with 191 stored entries: ⢞⣵⠑⢄⠑⢄⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀ ⠑⢄⢟⣵⠀⠀⠑⢄⠀⠀⠑⢄⠀⠀⠀⠀ ⠑⢄⠀⠀⢟⣵⠑⢄⠀⠀⠀⠀⠑⢄⠀⠀ ⠀⠀⠑⢄⠑⢄⢟⣵⠀⠀⠀⠀⠀⠀⠑⢄ ⠑⢄⠀⠀⠀⠀⠀⠀⢟⣵⠑⢄⠑⢄⠀⠀ ⠀⠀⠑⢄⠀⠀⠀⠀⠑⢄⢟⣵⠀⠀⠑⢄ ⠀⠀⠀⠀⠑⢄⠀⠀⠑⢄⠀⠀⢟⣵⠑⢄ ⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠑⢄⠑⢄⢟⣵

The Hamiltonian matrix can also be created in a subspace, such as the blockade subspace (see also Working with Subspace). This will allow one to simulate larger system sizes because of the smaller truncated Hilbert space.

For the Rydberg Hamiltonian, we can create a subspace via the blockade_subspace method, e.g.:

julia> space = blockade_subspace(atoms, 7.5)5-qubits 13-elements Subspace{Int64, Vector{Int64}}:
───┬───
  1│ 0
  2│ 1
  3│ 2
   ⋮│ ⋮
 11│ 18
 12│ 20
 13│ 21

The above code means that the blockade subspace only includes states where there is only one Rydberg excitation within the distance of 7.5 μm, which we call the subspace radius $R_s$. If we have a chain of atoms separated by 5.72 μm, the blockade subspace does not contain states with nearest-neighbor atoms being simultaneously excited to the Rydberg state $| r \rangle$.

Once we have defined the space, we can convert the Hamiltonian to a matrix in a subspace basis via the codes below:

julia> h_m = mat(ht, space)13×13 SparseMatrixCSC{ComplexF64, Int64} with 52 stored entries:
         ⋅      18.8496+0.0im  18.8496+0.0im  …          ⋅              ⋅
 18.8496+0.0im  63.4602+0.0im          ⋅                 ⋅              ⋅
 18.8496+0.0im          ⋅      63.4602+0.0im             ⋅              ⋅
 18.8496+0.0im          ⋅              ⋅         18.8496+0.0im          ⋅
         ⋅      18.8496+0.0im          ⋅                 ⋅      18.8496+0.0im
 18.8496+0.0im          ⋅              ⋅      …          ⋅              ⋅
         ⋅      18.8496+0.0im          ⋅                 ⋅              ⋅
         ⋅              ⋅      18.8496+0.0im             ⋅              ⋅
 18.8496+0.0im          ⋅              ⋅         18.8496+0.0im          ⋅
         ⋅      18.8496+0.0im          ⋅                 ⋅      18.8496+0.0im
         ⋅              ⋅      18.8496+0.0im  …          ⋅              ⋅
         ⋅              ⋅              ⋅         129.338+0.0im  18.8496+0.0im
         ⋅              ⋅              ⋅         18.8496+0.0im  195.255+0.0im

We can see that the size of the Hamiltonian matrix in the blockade subspace is much smaller than that in the full Hilbert space.

Diagonalization of the Hamiltonian

Bloqade doesn't provide any built-in diagonalization tool, as there are many existing tools in the Julia ecosystem. Here, we demonstrate how to use the KrylovKit package for this purpose as follows:

julia> using KrylovKit
julia> vals, vecs, info = KrylovKit.eigsolve(h_m, 1, :SR)([-23.53183367285078, 49.369907160338045, 51.29063792209698, 55.891040715044426, 61.44324863140736, 65.27248354593033, 124.97072996229838, 130.659309130817, 133.5372339586213, 135.95163912164844, 139.99824815581474, 146.74962587152322, 210.19192698918917], Vector{ComplexF64}[[0.7747520881370227 + 0.3847279334922316im, -0.2004120116409832 - 0.09952099551104297im, -0.18848911831997933 - 0.09360030142208883im, -0.18940022228096942 - 0.09405273923991055im, 0.04967152364088162 + 0.024665984043643088im, -0.18848911831997975 - 0.09360030142208951im, 0.04865522518945199 + 0.024161308536449513im, 0.04648301424905335 + 0.023082627705503428im, -0.20041201164098302 - 0.09952099551104332im, 0.05183646854376143 + 0.0257410566912198im, 0.048655225189451895 + 0.02416130853644949im, 0.049671523640881454 + 0.02466598404364303im, -0.013024881869028889 - 0.006467921754817736im], [0.09635031851761121 - 0.04476667182944617im, 0.34262227392401795 - 0.15919053651503748im, -0.39476254389685894 + 0.1834161580893772im, 0.35663695088098807 - 0.1657020919907717im, -0.1814703140274799 + 0.08431546589407389im, -0.39476254389682414 + 0.1834161580893912im, 0.012638714921578888 - 0.005872250470433073im, 0.18610060466822098 - 0.08646681012187556im, 0.34262227392396216 - 0.15919053651505918im, -0.18363289331925275 + 0.08532025216722337im, 0.012638714921601625 - 0.00587225047042389im, -0.1814703140274667 + 0.08431546589407875im, 0.07062202232970048 - 0.03281268755731011im], [-3.81844485501312e-15 + 5.18579997737037e-15im, 0.5247193438944638 + 0.18594197496857665im, -0.3284309787432783 - 0.11638432152153823im, -1.0919216919536012e-14 - 7.038640503775895e-15im, -0.1267264799618768 - 0.04490738189683842im, 0.3284309787433065 + 0.11638432152152807im, -0.21203957664284723 - 0.07513932564376374im, -6.868637603130168e-15 + 1.97758476261356e-15im, -0.5247193438944919 - 0.1859419749685453im, 7.093284293269164e-15 - 9.103828801926284e-15im, 0.2120395766428479 + 0.07513932564375914im, 0.12672647996188965 + 0.044907381896833486im, -2.3503334695140765e-15 + 2.1391308863139002e-15im], [-0.028567839132882345 + 0.16338308384595626im, -0.0768239399019442 + 0.4393658251850956im, -0.02190011371128421 + 0.1252495191563207im, 0.11274127027161687 - 0.6447815786139257im, -0.008351983227698478 + 0.04776604802431006im, -0.02190011371129438 + 0.12524951915632568im, 0.02612104090520921 - 0.1493895354320562im, 0.011240895437243034 - 0.06428810219718006im, -0.0768239399019203 + 0.43936582518511025im, 0.041647808288121625 - 0.23818908115126772im, 0.026121040905199688 - 0.14938953543205888im, -0.008351983227704517 + 0.04776604802430677im, -0.0033737695078994096 + 0.01929501436289619im], [-2.6711353398253812e-15 - 1.3722048942000492e-14im, 0.13019487224006215 + 0.3465155617311852im, 0.2076113352100096 + 0.5525606132122083im, -1.164866814118426e-15 - 2.360178025240245e-14im, -0.036145631357279016 - 0.09620212792098776im, -0.2076113352100139 - 0.5525606132122342im, 0.02221463851934586 + 0.059124586189480174im, 6.349087922075114e-16 + 7.446300520630444e-15im, -0.13019487224006382 - 0.3465155617311829im, 8.049116928532385e-16 + 3.3306690738754696e-16im, -0.022214638519343813 - 0.059124586189472514im, 0.03614563135728126 + 0.0962021279210026im, -6.713379852030243e-16 - 2.377438523826214e-15im], [0.05646926921598544 + 0.435341033154686im, 0.012263025137698884 + 0.0945398817297681im, 0.05330288754493742 + 0.41093030698136057im, 0.06441068296193816 + 0.49656412516337034im, -0.025138215506624522 - 0.19379915593490815im, 0.05330288754491742 + 0.4109303069813063im, -0.019978747721330625 - 0.15402304288504717im, -0.031365654886742686 - 0.24180862960596275im, 0.0122630251376863 + 0.09453988172973463im, -0.010173263520824424 - 0.07842919012766142im, -0.01997874772133211 - 0.15402304288505222im, -0.025138215506621913 - 0.19379915593489994im, 0.008766208845705548 + 0.06758172132780178im], [0.01812119641743421 + 0.027564148410783716im, 0.04955887159125742 + 0.07538399011547232im, -0.020083020406588985 - 0.030548278506126455im, 0.06119007463078565 + 0.09307621083822294im, 0.09077824341395656 + 0.1380827687252061im, -0.020083020406586674 - 0.03054827850612472im, -0.2569987958400747 - 0.3909208192850586im, 0.1733419547686174 + 0.2636704143033797im, 0.0495588715912556 + 0.07538399011547223im, 0.3098216732849107 + 0.4712696880812338im, -0.2569987958400794 - 0.390920819285063im, 0.09077824341395983 + 0.1380827687252116im, -0.1317836843774986 - 0.20045613714592153im], [-1.8019440106709084e-16 - 3.441257695468991e-16im, 0.024018386290795092 + 0.03075969353646228im, 0.07212764819757282 + 0.09237191571497624im, -1.2559397966072083e-15 - 2.213507155346406e-15im, 0.3427630136899963 + 0.43896726154242416im, -0.07212764819757328 - 0.0923719157149775im, -0.25713686683108566 - 0.3293081860241984im, -6.661338147750939e-16 + 1.3739009929736312e-15im, -0.02401838629079328 - 0.030759693536459597im, 6.744604874597826e-15 + 7.91033905045424e-15im, 0.2571368668310846 + 0.32930818602419565im, -0.3427630136900003 - 0.43896726154242904im, -6.990935608186533e-16 - 7.251144129583054e-16im], [0.022166027969177274 + 0.02102522648784307im, -0.03149659830747019 - 0.029875587720636414im, 0.008597288164364073 + 0.008154818314241334im, 0.20283097028821465 + 0.19239202869313354im, 0.3659497026428499 + 0.3471156578852971im, 0.008597288164362255 + 0.00815481831424002im, -0.06739559414267221 - 0.06392699824717724im, 0.07719173553680625 + 0.07321896935743327im, -0.031496598307470175 - 0.02987558772063692im, -0.43781515413371036 - 0.4152824668574639im, -0.06739559414266558 - 0.06392699824717146im, 0.36594970264284243 + 0.3471156578852884im, -0.08981851991692871 - 0.08519590098335221im], [0.04089413406370905 + 0.015068866283323957im, 0.19631639281367078 + 0.07233960420643969im, -0.11534919795603965 - 0.042504424648787786im, 0.13301285358126813 + 0.04901321303091798im, 0.23532280349321014 + 0.08671287314047729im, -0.11534919795603982 - 0.04250442464878599im, 0.17305757583581655 + 0.0637690839846049im, -0.6575607090608134 - 0.24230111787105546im, 0.19631639281367289 + 0.07233960420644063im, 0.305717459487874 + 0.11265223296631055im, 0.17305757583581885 + 0.06376908398460304im, 0.23532280349321458 + 0.08671287314047962im, -0.24676866675666237 - 0.09093049962806996im], [-2.0141765859349459e-16 - 8.891813067096743e-17im, 0.2270134358127512 + 0.0036484438154596958im, -0.12815176069055162 - 0.00205958954392994im, -4.2500725161431774e-16 + 4.0245584642661925e-16im, 0.4014249720357758 + 0.006451496808335989im, 0.12815176069055098 + 0.0020595895439297018im, 0.5203565172039897 + 0.008362903764836303im, -1.9290125052862095e-15 - 7.008282842946301e-16im, -0.22701343581275124 - 0.0036484438154601607im, 2.8449465006019636e-16 + 5.551115123125783e-17im, -0.5203565172039893 - 0.008362903764835197im, -0.4014249720357768 - 0.006451496808336716im, 2.7994100093575724e-16 + 1.6046192152785466e-16im], [0.09029000813788805 + 0.0884660587745575im, 0.1447933800909007 + 0.14186840756206878im, 0.17749508857116594 + 0.1739095085001204im, 0.05835871640294619 + 0.057179811385400174im, 0.08378815651249717 + 0.08209555111930385im, 0.17749508857116625 + 0.1739095085001206im, 0.309680226078957 + 0.3034243727144259im, 0.3843171582319779 + 0.3765535634496644im, 0.14479338009090031 + 0.1418684075620684im, 0.15603183349318447 + 0.1528798328540371im, 0.30968022607895546 + 0.3034243727144245im, 0.08378815651249732 + 0.08209555111930383im, -0.12575775724645125 - 0.12321732352632896im], [0.013855239637447893 + 0.011999274783480786im, 0.04944328164742898 + 0.042820155999396294im, 0.0035362282830236087 + 0.003062536338269566im, 0.04854114610663114 + 0.04203886512827151im, 0.18200329203815502 + 0.15762322195866352im, 0.0035362282830234213 + 0.0030625363382694765im, 0.012023220976550869 + 0.010412662361335862im, 0.0016488183084273048 + 0.0014279524907948884im, 0.04944328164742916 + 0.04282015599939627im, 0.17700262013644605 + 0.1532924100910392im, 0.012023220976550715 + 0.01041266236133583im, 0.18200329203815493 + 0.15762322195866355im, 0.6827021835228535 + 0.5912514911132918im]], ConvergenceInfo: 13 converged values after 1 iterations and 13 applications of the linear map; norms of residuals are given by (1.1418079822761064e-37, 1.3296215781277314e-31, 1.379825054782084e-31, 7.098798834133463e-32, 2.617692903049193e-31, 2.1047302046305064e-31, 1.1696108953549987e-31, 2.6577790839711294e-30, 4.8374941426155455e-30, 2.297441944205312e-30, 6.650527616026521e-31, 6.875168993416231e-33, 7.081486998418712e-38). )

where the vals and vecs store the calculated eigenvalues and eigenvectors respectively.

Low-Level Representation of the Hamiltonian

Besides the symbolic representation, in order to achieve the best possible performance, we use a lower-level representation of the Hamiltonian in Bloqade, which is the Hamiltonian and StepHamiltonian type:

BloqadeExpr.HamiltonianType
struct Hamiltonian

Hamiltonian stores the dynamic prefactors of each term. The actual hamiltonian is the sum of f_i(t) * t_i where f_i and t_i are entries of fs and ts.

source
BloqadeExpr.StepHamiltonianType
struct StepHamiltonian

A low-level linear-map object that encodes time-dependent hamiltonian at time step t. This object supports the linear map interface mul!(Y, H, X).

source

The Hamiltonian type represents the following Hamiltonian expression

\[f_1(t) H_1 + f_2(t) H_2 + \cdots + f_n(t) H_n + H_c,\]

where $f_i(t)$ are time-dependent parameters of the Hamiltonian, $H_i$ are time-independent local terms of the Hamiltonian as linear operators (in Julia, this means objects that support LinearAlgebra.mul! interface), and $H_c$ is the constant component of the Hamiltonian.

A Hamiltonian object supports callable methods, which will produce a StepHamiltonian that is time-independent, e.g.:

julia> using BloqadeExpr
julia> h = BloqadeExpr.Hamiltonian(Float64, SumOfX(5, sin) + SumOfZ(5, cos))Hamiltonian number of dynamic terms: 2 storage size: 48 bytes
julia> h(0.1)BloqadeExpr.StepHamiltonian{Float64, Tuple{typeof(sin), typeof(cos), typeof(one)}, Tuple{SparseMatrixCSC{Float64, Int64}, Diagonal{Float64, Vector{Float64}}}}(0.1, BloqadeExpr.Hamiltonian{Tuple{typeof(sin), typeof(cos), typeof(one)}, Tuple{SparseMatrixCSC{Float64, Int64}, Diagonal{Float64, Vector{Float64}}}}((sin, cos, one), (sparse([2, 3, 5, 9, 17, 1, 4, 6, 10, 18 … 15, 23, 27, 29, 32, 16, 24, 28, 30, 31], [1, 1, 1, 1, 1, 2, 2, 2, 2, 2 … 31, 31, 31, 31, 31, 32, 32, 32, 32, 32], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 … 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 32, 32), [5.0 0.0 … 0.0 0.0; 0.0 3.0 … 0.0 0.0; … ; 0.0 0.0 … -3.0 0.0; 0.0 0.0 … 0.0 -5.0])))

Here, we see that the Hamiltonian expression written as Yao blocks are automatically analyzed into time-dependent terms and constant terms. A more complicated example can be SumOfXPhase:

julia> using BloqadeExpr
julia> h = BloqadeExpr.Hamiltonian(Float64, SumOfXPhase(5, sin, cos) + SumOfZ(5, cos))Hamiltonian number of dynamic terms: 3 storage size: 88 bytes
julia> h(0.1)BloqadeExpr.StepHamiltonian{Float64, Tuple{BloqadeExpr.var"#74#108", BloqadeExpr.var"#76#110", typeof(cos), typeof(one)}, Tuple{SparseMatrixCSC{Float64, Int64}, SparseMatrixCSC{Float64, Int64}, Diagonal{Float64, Vector{Float64}}}}(0.1, BloqadeExpr.Hamiltonian{Tuple{BloqadeExpr.var"#74#108", BloqadeExpr.var"#76#110", typeof(cos), typeof(one)}, Tuple{SparseMatrixCSC{Float64, Int64}, SparseMatrixCSC{Float64, Int64}, Diagonal{Float64, Vector{Float64}}}}((BloqadeExpr.var"#74#108"(Core.Box(cos), Core.Box(sin)), BloqadeExpr.var"#76#110"(Core.Box(cos), Core.Box(sin)), cos, one), (sparse([1, 1, 2, 3, 1, 2, 5, 3, 5, 4 … 29, 15, 23, 27, 29, 16, 24, 28, 30, 31], [2, 3, 4, 4, 5, 6, 6, 7, 7, 8 … 30, 31, 31, 31, 31, 32, 32, 32, 32, 32], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 … 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 32, 32), sparse([2, 3, 5, 9, 17, 4, 6, 10, 18, 4 … 29, 28, 30, 28, 31, 32, 30, 31, 32, 32], [1, 1, 1, 1, 1, 2, 2, 2, 2, 3 … 25, 26, 26, 27, 27, 28, 29, 29, 30, 31], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 … 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 32, 32), [5.0 0.0 … 0.0 0.0; 0.0 3.0 … 0.0 0.0; … ; 0.0 0.0 … -3.0 0.0; 0.0 0.0 … 0.0 -5.0])))

References

BloqadeExpr.rydberg_hFunction
rydberg_h(atoms; [C=2π * 862690 * MHz*µm^6], Ω[, ϕ, Δ])

Create a rydberg hamiltonian

\[∑ \frac{C}{|r_i - r_j|^6} n_i n_j + \frac{Ω}{2} σ_x - Δ σ_n\]

shorthand for

RydInteract(C, atoms) + SumOfXPhase(length(atoms), Ω, ϕ) - SumOfN(length(atoms), Δ)

Arguments

  • atoms: a collection of atom positions.

Keyword Arguments

  • C: optional, default unit is MHz*µm^6, interation parameter, see also RydInteract.
  • Ω: optional, default unit is MHz, Rabi frequencies, divided by 2, see also SumOfX.
  • Δ: optional, default unit is MHz, detuning parameter, see SumOfN.
  • ϕ: optional, does not have unit, the phase, see SumOfXPhase.
Tips

The rabi frequencies are divided by two in the Rydberg hamiltonian unlike directly constructing via SumOfX or SumOfXPhase.

Tips

The parameters of Hamiltonian have their own default units to match hardware, one can use Unitful.jl to specify their units explicitly. If the units are specified explicitly, they will be converted to default units automatically.

Example

julia> using Bloqade

julia> atoms = [(1, ), (2, ), (3, ), (4, )]
4-element Vector{Tuple{Int64}}:
 (1,)
 (2,)
 (3,)
 (4,)

julia> rydberg_h(atoms)
∑ 5.42e6/|r_i-r_j|^6 n_i n_j
julia> rydberg_h(atoms; Ω=0.1)
nqubits: 4
+
├─ ∑ 5.42e6/|r_i-r_j|^6 n_i n_j
└─ 0.05 ⋅ ∑ σ^x_i
source

Except the standard operators from Yao, the following operators are also supported by Bloqade:

BloqadeExpr.RydInteractType
struct RydInteract{D} <: AbstractTerm{D}
RydInteract(;atoms, C=2π * 862690MHz⋅μm^6)

Type for Rydberg interactive term.

Expression

\[\sum_{i, j} \frac{C}{|r_i - r_j|^6} n_i n_j\]

Keyword Arguments

  • atoms: a list of atom positions, must be type RydAtom, default unit is μm.
  • C: the interaction strength, default unit is MHz⋅μm^6. default value is 2π * 862690 * MHz*µm^6.
source
BloqadeExpr.SumOfXType
struct SumOfX <: AbstractTerm{2}
SumOfX(nsites, Ω)

Term for sum of X operators.

The following two expressions are equivalent

julia> SumOfX(nsites=5)
∑ σ^x_i

julia> sum([X for _ in 1:5])
nqudits: 1
+
├─ X
├─ X
├─ X
├─ X
└─ X

Expression

\[\sum_i Ω σ^x_i\]

source
BloqadeExpr.SumOfXPhaseType
struct SumOfXPhase <: AbstractTerm{2}
SumOfXPhase(;nsites, Ω=1, ϕ)

Sum of XPhase operators.

The following two expressions are equivalent

julia> SumOfXPhase(nsites=5, ϕ=0.1)
1.0 ⋅ ∑ e^{0.1 ⋅ im} |0⟩⟨1| + e^{-0.1 ⋅ im} |1⟩⟨0|

julia> sum([XPhase(0.1) for _ in 1:5])
nqudits: 1
+
├─ XPhase(0.1)
├─ XPhase(0.1)
├─ XPhase(0.1)
├─ XPhase(0.1)
└─ XPhase(0.1)

But may provide extra speed up.

Expression

\[\sum_i Ω ⋅ (e^{ϕ ⋅ im} |0⟩⟨1| + e^{-ϕ ⋅ im} |1⟩⟨0|)\]

source
BloqadeExpr.SumOfZType
struct SumOfZ <: AbstractTerm{2}
SumOfZ(;nsites, Δ=1)

Sum of Pauli Z operators.

The following two expression are equivalent

julia> SumOfZ(nsites=5)
∑ σ^z_i

julia> sum([Z for _ in 1:5])
nqudits: 1
+
├─ Z
├─ Z
├─ Z
├─ Z
└─ Z

Expression

\[\sum_i Δ ⋅ σ^z_i\]

source
BloqadeExpr.SumOfNType
struct SumOfN <: AbstractTerm{2}
SumOfN(;nsites[, Δ=1])

Sum of N operators.

The following two expression are equivalent

julia> SumOfN(nsites=5)
∑ n_i

julia> sum([Op.n for _ in 1:5])
nqudits: 1
+
├─ P1
├─ P1
├─ P1
├─ P1
└─ P1

But may provide extra speed up.

Expression

\[\sum_i Δ ⋅ n_i\]

source
BloqadeExpr.XPhaseType
XPhase{T} <: PrimitiveBlock{2}

XPhase operator for 2-level Rydberg system.

\[e^{ϕ ⋅ im} |0⟩⟨1| + e^{-ϕ ⋅ im} |1⟩⟨0|\]

source