Skip to content

Commit eeea17f

Browse files
authored
Adding the split-operator chapter and code (algorithm-archivists#108)
* adding smallscale changes. * adding partial draft for the split-op method * adding draft of split-op chapter. * adding back split-op.jl file. * fixing typo in split-op method. * turning the splitop param module into a struct * adding smallscale changes to spacing in split_op.jl
1 parent a47bdee commit eeea17f

File tree

5 files changed

+162
-4
lines changed

5 files changed

+162
-4
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ This goal is obviously too ambitious for a book of any size, but it is a great p
44
The book can be found here: https://www.algorithm-archive.org/.
55
The github repository can be found here: https://github.com/algorithm-archivists/algorithm-archive.
66
Most algorithms have been covered on the youtube channel LeiosOS: https://www.youtube.com/user/LeiosOS
7-
and livecoded on Twitch: https://www.twitch.tv/simuleios
7+
and livecoded on Twitch: https://www.twitch.tv/simuleios.
8+
If you would like to communicate more directly, please feel free to go to our discord: https://discord.gg/Pr2E9S6.
9+
810

911
Note that the this project is is essentially a book about algorithms collaboratively written by an online community.
1012
Fortunately, there are a lot of algorithms out there, which means that there is a lot of content material available.

chapters/physics_solvers/quantum/quantum.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ $$
5757
\int_{-\infty}^{+\infty}|\Psi(\mathbf{r},t)|^2 d\mathbf{r} = 1
5858
$$
5959

60+
As another note: Just like position space can be parameterized by a position vector $$\textbf{x}$$, wavefunctions can be parameterized by a _wave_vector $$\textbf{k}$$ in frequency space.
61+
Often times, the wavevector space is called _momentum_ space, which makes sense when considering the de Broglie formula:
62+
63+
$$
64+
p = \frac{h}{\lambda}
65+
$$
66+
67+
where $$h$$ is Planck's constant and $$\lambda$$ is the wavelength.
68+
This means that we can ultimately move between real and momentum space by using [Fourier Transforms](../../FFT/cooley_tukey.md), which is incredibly useful in a number of cases!
69+
6070
Unfortunately, the interpretation of quantum simulation is rather tricky and is ultimately easier to understand with slightly different notation.
6171
This notation is called _braket_ notation, where a _ket_ looks like this:
6272

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using Plots
2+
pyplot()
3+
4+
# struct to hold all parameters for simulation
5+
struct Param
6+
xmax::Float64
7+
res::Int64
8+
dt::Float64
9+
timesteps::Int64
10+
dx::Float64
11+
x::Vector{Float64}
12+
dk::Float64
13+
k::Vector{Float64}
14+
15+
Param() = new(10.0, 512, 0.05, 1000, 2 * 10.0/512,
16+
Vector{Float64}(-10.0 + 10.0/512 : 20.0/512 : 10.0),
17+
pi / 10.0,
18+
Vector{Float64}(vcat(0:512/2 - 1, -512/2 : -1) * pi/10.0))
19+
Param(xmax::Float64, res::Int64, dt::Float64, timesteps::Int64) = new(
20+
xmax, res, dt, timesteps,
21+
2*xmax/res, Vector{Float64}(-xmax+xmax/res:2*xmax/res:xmax),
22+
pi/xmax, Vector{Float64}(vcat(0:res/2-1, -res/2:-1)*pi/xmax)
23+
)
24+
end
25+
26+
# struct to hold all operators
27+
mutable struct Operators
28+
V::Vector{Complex{Float64}}
29+
PE::Vector{Complex{Float64}}
30+
KE::Vector{Complex{Float64}}
31+
wfc::Vector{Complex{Float64}}
32+
end
33+
34+
# Function to initialize the wfc and potential
35+
function init(par::Param, voffset::Float64, wfcoffset::Float64)
36+
V = 0.5 * (par.x - voffset).^2
37+
wfc = 3 * exp.(-(par.x - wfcoffset).^2/2)
38+
PE = exp.(-0.5*im*V*par.dt)
39+
KE = exp.(-0.5*im*par.k.^2*par.dt)
40+
41+
opr = Operators(V, PE, KE, wfc)
42+
end
43+
44+
# Function for the split-operator loop
45+
function split_op(par::Param, opr::Operators)
46+
47+
for i = 1:par.timesteps
48+
# Half-step in real space
49+
opr.wfc = opr.wfc .* opr.PE
50+
51+
# fft to phase space
52+
opr.wfc = fft(opr.wfc)
53+
54+
# Full step in phase space
55+
opr.wfc = opr.wfc .* opr.KE
56+
57+
# ifft back
58+
opr.wfc = ifft(opr.wfc)
59+
60+
# final half-step in real space
61+
opr.wfc = opr.wfc .* opr.PE
62+
63+
# plotting density and potential
64+
density = abs2.(opr.wfc)
65+
66+
plot([density, real(opr.V)])
67+
savefig("density" * string(lpad(i, 5, 0)) * ".png")
68+
println(i)
69+
end
70+
end
71+
72+
# main function
73+
function main()
74+
par = Param(10.0, 512, 0.05, 1000)
75+
opr = init(par, 0.0, 1.0)
76+
split_op(par, opr)
77+
end
78+
79+
main()

chapters/physics_solvers/quantum/split-op/split-op.md

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,76 @@ This is the system I studied for most of my PhD (granted, we played a few tricks
1717

1818
At it's heart, the split-op method is nothing more than a pseudo-spectral differential equation solver... That is to say, it solves the Schrodinger equation with [FFT's](../../../FFT/cooley_tukey.md).
1919
In fact, there is a large class of spectral and pseudo-spectral methods used to solve a number of different physical systems, and we'll definitely be covering those in the future.
20+
As mentioned in the [quantum systems](../quantum.md) section, we can represent a a quantum wavefunction in momentum space, which is parameterized with the wavevector $$k$$.
21+
In the hamiltonian shown above, we can split our system into real-space components, $$\hat{H}_R = \left[V(\mathbf{r}) + g|\Psi(\mathbf{r},t)|^2 \right] \Psi(\mathbf{r},t)$$, and momentum space components, $$\hat{H}_M = \left[-\frac{\hbar^2}{2m}\nabla^2 \right]\Psi(\mathbf{r},t)$$.
22+
If we assume a somewhat general solution to our quantum system:
2023

21-
For now, let's answer the obvious question, "How on Earth can FFT's be used to solve quantum systems?"
22-
That is precisely the question we will answer here!
24+
$$
25+
\Psi(\mathbf{r},t + dt) = \left[e^{-\frac{i\hat{H}dt}{\hbar}}\right]\Psi(\mathbf{r},t) = \left[e^{-\frac{i(\hat{H}_R + \hat{H}_M)dt}{\hbar}}\right]\Psi(\mathbf{r},t)
26+
$$
27+
28+
and assume we are simulating our system by a series of small tiemsteps ($$dt$$), we can perform similar splitting by using the Baker-Campbell-Housdorff formula:
29+
30+
$$
31+
\Psi(\mathbf{r},t+dt) = \left[e^{-\frac{i\hat{H}_Rdt}{\hbar}}e^{-\frac{i\hat{H}_Mdt}{\hbar}}e^{-\frac{[i\hat{H}_R, i\hat{H}_M]dt^2}{2}}\right]\Psi(\mathbf{r},t)
32+
$$
33+
34+
This accrues a small amount of error ($$dt^2$$) related to the commutation of the real and momentum-space components of the Hamiltonian. That's not okay.
35+
In order to change the $$dt^2$$ error to $$dt^3$$, we can split the system by performing a half-step in real space before doing a full-step in momentum space, through a process called _Strang Splitting_ like so:
36+
37+
$$
38+
\Psi(\mathbf{r},t+dt) = \left[e^{-\frac{i\hat{H}_Rdt}{2\hbar}}e^{-\frac{i\hat{H}_Mdt}{\hbar}}e^{-\frac{i\hat{H}_Rdt}{2\hbar}} \right]\Psi(\mathbf{r},t) + \mathcal{O}(dt^3)
39+
$$
40+
41+
We can then address each part of this solution in chunks, first in real space, then in momentum space, then in real space again by using [Fourier Transforms](../../../FFT/cooley_tukey.md).
42+
Which looks something like this:
43+
44+
$$
45+
\Psi(\mathcal{r}, t+dt) = \left[\hat{U}_R(\frac{dt}{2})\mathcal{F}\left[\hat{U}_M(dt) \mathcal{F} \left[\hat{U}_R(\frac{dt}{2}) \Psi(\mathbf{r},t) \right] \right] \right] + \mathcal{O}(dt^3)
46+
$$
47+
48+
where $$\hat{U}_R = e^{-\frac{i\hat{H}_Rdt}{\hbar}}$$, $$\hat{U}_M = e^{-\frac{i\hat{H}_Mdt}{\hbar}}$$, and $$\mathcal{F}$$ and $$\mathcal{F}^{-1}$$ indicate forward and inverse Fourier Transforms.
49+
50+
As a small concession here, using this method enforces periodic boundary conditions, where the wavefunction will simply slide from one side of your simulation box to the other, but that's fine for most cases.
51+
In fact, for many cases (such as large-scale turbulence models) it's ideal.
52+
53+
Luckily, the code in this case is pretty straightforward.
54+
Frist, we need to set all the initial parameters, including the initial grids in real and momentum space:
55+
56+
{% method %}
57+
{% sample lang="jl" %}
58+
[import:4-31, lang:"julia"](code/julia/split_op.jl)
59+
{% endmethod %}
60+
61+
As a note, when we generate our grid in momentum space `k`, we need to split the grid into two lines, one that is going from `0` to `-kmax` and is then discontinuous and goes from `kmax` to `0`.
62+
This is simply because the FFT will naturally assume that the `0` in our grid is at the left side of the simulation, so we shift k-space to match this expectation.
63+
Afterwards, we turn them into operators:
64+
65+
{% method %}
66+
{% sample lang="jl" %}
67+
[import:32-41, lang:"julia"](code/julia/split_op.jl)
68+
{% endmethod %}
69+
70+
Here, we use a standard harmonic potential for the atoms to sit in and a gaussian distribution for an initial guess for the probability distribution.
71+
As a note, if we run this simulation in _imaginary time_, by simply setting $$\tau = it$$ and stepping through $$\tau$$, we will no longer see an "real-world" example of how the atoms should behave, but will instead see an exponential decay of higher-energy states.
72+
This means that we can find the ground state of our system by running the simulation in imaginary time, which is an incredibly useful feature!
73+
74+
And finally go step-by-step through the simulation:
75+
76+
{% method %}
77+
{% sample lang="jl" %}
78+
[import:42-69, lang:"julia"](code/julia/split_op.jl)
79+
{% endmethod %}
80+
81+
And that's it.
82+
The Split-Operator method is one of the most commonly used quantum simulation algorithms because of how straightforward it is to code and how quickly you can start really digging into the physics of the simulation results!
83+
84+
# Example Code
85+
{% method %}
86+
{% sample lang="jl" %}
87+
### Julia
88+
[import, lang:"julia"](code/julia/split_op.jl)
89+
{% endmethod %}
2390

2491
<script>
2592
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);

update_site.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ if [ $# -ge 1 ]; then
2626
cd "$out_dir"
2727
git reset --hard && \
2828
git clean -dfx && \
29-
git pull
29+
git pull origin master
3030

3131
if [ $? -ne 0 ]; then
3232
echo "Failed to prepare repository"

0 commit comments

Comments
 (0)