Skip to content

Commit abff68e

Browse files
committed
Changes for non-CPU array support
1 parent 0b6c65b commit abff68e

21 files changed

Lines changed: 2176 additions & 27 deletions

File tree

Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ cuTENSOR = "011b41b2-24ef-40a8-b3eb-fa098493e9e1"
7676

7777
[targets]
7878
test = ["Aqua", "Adapt", "CUDA", "cuTENSOR", "Pkg", "Test", "TestExtras", "Plots", "Combinatorics", "ParallelTestRunner", "TensorKitTensors"]
79+
80+
[sources]
81+
TensorKit = {url="https://github.com/QuantumKitHub/TensorKit.jl", rev="ksh/cuda_tweaks"}
82+
BlockTensorKit = {url="https://github.com/kshyatt/BlockTensorKit.jl", rev="ksh/conversions"}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using Markdown
2+
3+
md"""
4+
# [The Hard Hexagon model](@id demo_hardhexagon)
5+
6+
![logo](hexagon.svg)
7+
8+
Tensor networks are a natural way to do statistical mechanics on a lattice.
9+
As an example of this we will extract the central charge of the hard hexagon model.
10+
This model is known to have central charge 0.8, and has very peculiar non-local (anyonic) symmetries.
11+
Because TensorKit supports anyonic symmetries, so does MPSKit.
12+
To follow the tutorial you need the following packages.
13+
"""
14+
15+
using MatrixAlgebraKit, MPSKit, MPSKitModels, TensorKit, Plots, Polynomials, Adapt, CUDA, cuTENSOR
16+
17+
#src # for reproducibility:
18+
#src using Random
19+
#src Random.seed!(123)
20+
21+
md"""
22+
The [hard hexagon model](https://en.wikipedia.org/wiki/Hard_hexagon_model) is a 2-dimensional lattice model of a gas, where particles are allowed to be on the vertices of a triangular lattice, but no two particles may be adjacent.
23+
This can be encoded in a transfer matrix with a local MPO tensor using anyonic symmetries, and the resulting MPO has been implemented in MPSKitModels.
24+
25+
In order to use these anyonic symmetries, we need to generalise the notion of the bond dimension and define how it interacts with the symmetry. Thus, we implement away of converting integers to symmetric spaces of the given dimension, which provides a crude guess for how the final MPS would distribute its Schmidt spectrum.
26+
"""
27+
mpo = adapt(CuArray, hard_hexagon())
28+
P = physicalspace(mpo, 1)
29+
function virtual_space(D::Integer)
30+
_D = round(Int, D / sum(dim, values(FibonacciAnyon)))
31+
return Vect[FibonacciAnyon](sector => _D for sector in (:I, ))
32+
end
33+
34+
@assert isapprox(dim(virtual_space(100)), 100; atol = 3)
35+
36+
md"""
37+
## The leading boundary
38+
39+
One way to study statistical mechanics in infinite systems with tensor networks is by approximating the dominant eigenvector of the transfer matrix by an MPS.
40+
This dominant eigenvector contains a lot of hidden information.
41+
For example, the free energy can be extracted by computing the expectation value of the mpo.
42+
Additionally, we can compute the entanglement entropy as well as the correlation length of the state:
43+
"""
44+
45+
D = 10
46+
V = virtual_space(D)
47+
ψ₀ = adapt(CuArray, InfiniteMPS(ComplexF64, [P], [V]))
48+
49+
# put this here to avoid interfering with initial InfiniteMPS construction
50+
MPSKit.Defaults.alg_qr() = CUSOLVER_HouseholderQR(; positive = true)
51+
MPSKit.Defaults.alg_svd() = CUSOLVER_QRIteration()
52+
MPSKit.Defaults.alg_lq() = LQViaTransposedQR(CUSOLVER_HouseholderQR(; positive = true))
53+
54+
ψ, envs, = leading_boundary(
55+
ψ₀, mpo,
56+
VUMPS(; verbosity = 0, alg_eigsolve = MPSKit.Defaults.alg_eigsolve(; ishermitian = false))
57+
) # use non-hermitian eigensolver
58+
F = real(expectation_value(ψ, mpo))
59+
S = real(first(entropy(ψ)))
60+
ξ = correlation_length(ψ)
61+
println("F = $F\tS = $S\tξ = ")
62+
63+
md"""
64+
## The scaling hypothesis
65+
66+
The dominant eigenvector is of course only an approximation. The finite bond dimension enforces a finite correlation length, which effectively introduces a length scale in the system. This can be exploited to formulate a scaling hypothesis [pollmann2009](@cite), which in turn allows to extract the central charge.
67+
68+
First we need to know the entropy and correlation length at a bunch of different bond dimensions. Our approach will be to re-use the previous approximated dominant eigenvector, and then expanding its bond dimension and re-running VUMPS.
69+
According to the scaling hypothesis we should have ``S \propto \frac{c}{6} log(ξ)``. Therefore we should find ``c`` using
70+
"""
71+
72+
function scaling_simulations(
73+
ψ₀, mpo, Ds; verbosity = 0, tol = 1.0e-6,
74+
alg_eigsolve = MPSKit.Defaults.alg_eigsolve(; ishermitian = false)
75+
)
76+
entropies = similar(Ds, Float64)
77+
correlations = similar(Ds, Float64)
78+
alg = VUMPS(; verbosity, tol, alg_eigsolve)
79+
80+
ψ, envs, = leading_boundary(ψ₀, mpo, alg)
81+
entropies[1] = real(entropy(ψ)[1])
82+
correlations[1] = correlation_length(ψ)
83+
84+
for (i, d) in enumerate(diff(Ds))
85+
ψ, envs = changebonds(ψ, mpo, OptimalExpand(; trscheme = truncrank(d)), envs)
86+
ψ, envs, = leading_boundary(ψ, mpo, alg, envs)
87+
entropies[i + 1] = real(entropy(ψ)[1])
88+
correlations[i + 1] = correlation_length(ψ)
89+
end
90+
return entropies, correlations
91+
end
92+
93+
bond_dimensions = 10:5:25
94+
ψ₀ = InfiniteMPS(CuVector{ComplexF64}, [P], [virtual_space(bond_dimensions[1])])
95+
Ss, ξs = scaling_simulations(ψ₀, mpo, bond_dimensions)
96+
97+
f = fit(log.(ξs), 6 * Ss, 1)
98+
c = f.coeffs[2]
99+
100+
#+
101+
102+
p = plot(; xlabel = "logarithmic correlation length", ylabel = "entanglement entropy")
103+
p = plot(log.(ξs), Ss; seriestype = :scatter, label = nothing)
104+
plot!(p, ξ -> f(ξ) / 6; label = "fit")
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using Markdown
2+
md"""
3+
# The Ising CFT spectrum
4+
5+
This tutorial is meant to show the finite size CFT spectrum for the quantum Ising model. We
6+
do this by first employing an exact diagonalization technique, and then extending the
7+
analysis to larger system sizes through the use of MPS techniques.
8+
"""
9+
10+
using MPSKit, MPSKitModels, TensorKit, Plots, KrylovKit
11+
using LinearAlgebra: eigvals, diagm, Hermitian
12+
using CUDA, cuTENSOR, Adapt
13+
14+
md"""
15+
The Hamiltonian is defined on a finite lattice with periodic boundary conditions,
16+
which can be implemented as follows:
17+
"""
18+
19+
L = 12
20+
H = periodic_boundary_conditions(transverse_field_ising(), L)
21+
22+
md"""
23+
## Exact diagonalisation
24+
25+
In MPSKit, there is support for exact diagonalisation by leveraging the fact that applying
26+
the Hamiltonian to an untruncated MPS will result in an effective Hamiltonian on the center
27+
site which implements the action of the entire Hamiltonian. Thus, optimizing the middle
28+
tensor is equivalent to optimixing a state in the entire Hilbert space, as all other tensors
29+
are just unitary matrices that mix the basis.
30+
"""
31+
32+
energies, states = exact_diagonalization(H; num = 18, alg = Lanczos(; krylovdim = 200));
33+
plot(
34+
real.(energies);
35+
seriestype = :scatter, legend = false, ylabel = "energy", xlabel = "#eigenvalue"
36+
)
37+
cu_states = map(state -> adapt(CuArray, state), states)
38+
39+
md"""
40+
!!! note "Krylov dimension"
41+
Note that we have specified a large Krylov dimension as degenerate eigenvalues are
42+
notoriously difficult for iterative methods.
43+
"""
44+
45+
md"""
46+
## Extracting momentum
47+
48+
Given a state, it is possible to assign a momentum label
49+
through the use of the translation operator. This operator can be defined in MPO language
50+
either diagramatically as
51+
52+
```@raw html
53+
<img src="translation_mpo.svg" alt="translation operator" class="color-invertible" width="50%"/>
54+
```
55+
56+
or in the code as:
57+
"""
58+
59+
function O_shift(L)
60+
I = id(ComplexF64, ℂ^2)
61+
@tensor O[W S; N E] := I[W; N] * I[S; E]
62+
return adapt(CuArray, periodic_boundary_conditions(InfiniteMPO([O]), L))
63+
end
64+
65+
md"""
66+
We can then calculate the momentum of the ground state as the expectation value of this
67+
operator. However, there is a subtlety because of the degeneracies in the energy
68+
eigenvalues. The eigensolver will find an orthonormal basis within each energy subspace, but
69+
this basis is not necessarily a basis of eigenstates of the translation operator. In order
70+
to fix this, we diagonalize the translation operator within each energy subspace.
71+
The resulting energy levels have one-to-one correspondence to the operators in CFT, where
72+
the momentum is related to their conformal spin as $P_n = \frac{2\pi}{L}S_n$.
73+
"""
74+
75+
function fix_degeneracies(basis)
76+
L = length(basis[1])
77+
M = zeros(ComplexF64, length(basis), length(basis))
78+
T = O_shift(L)
79+
for j in eachindex(basis), i in eachindex(basis)
80+
M[i, j] = dot(basis[i], T, basis[j])
81+
end
82+
83+
vals = eigvals(M)
84+
return angle.(vals)
85+
end
86+
87+
momenta = Float64[]
88+
append!(momenta, fix_degeneracies(cu_states[1:1]))
89+
append!(momenta, fix_degeneracies(cu_states[2:2]))
90+
append!(momenta, fix_degeneracies(cu_states[3:3]))
91+
append!(momenta, fix_degeneracies(cu_states[4:5]))
92+
append!(momenta, fix_degeneracies(cu_states[6:9]))
93+
append!(momenta, fix_degeneracies(cu_states[10:11]))
94+
append!(momenta, fix_degeneracies(cu_states[12:12]))
95+
append!(momenta, fix_degeneracies(cu_states[13:16]))
96+
append!(momenta, fix_degeneracies(cu_states[17:18]))
97+
98+
md"""
99+
We can compute the scaling dimensions $\Delta_n$ of the operators in the CFT from the
100+
energy gap of the corresponding excitations as $E_n - E_0 = \frac{2\pi v}{L} \Delta_n$,
101+
where $v = 2$. If we plot these scaling dimensions against the conformal spin $S_n$ from
102+
above, we retrieve the familiar spectrum of the Ising CFT.
103+
"""
104+
105+
v = 2.0
106+
Δ = real.(energies[1:18] .- energies[1]) ./ (2π * v / L)
107+
S = momenta ./ (2π / L)
108+
109+
p = plot(
110+
S, real.(Δ);
111+
seriestype = :scatter, xlabel = "conformal spin (S)", ylabel = "scaling dimension (Δ)",
112+
legend = false
113+
)
114+
vline!(p, -3:3; color = "gray", linestyle = :dash)
115+
hline!(p, [0, 1 / 8, 1, 9 / 8, 2, 17 / 8]; color = "gray", linestyle = :dash)
116+
p
117+
118+
md"""
119+
## Finite bond dimension
120+
121+
If we limit the maximum bond dimension of the MPS, we get an approximate solution, but we
122+
can reach higher system sizes.
123+
"""
124+
125+
L_mps = 20
126+
H_mps = adapt(CuArray, periodic_boundary_conditions(transverse_field_ising(), L_mps))
127+
D = 64
128+
129+
ψ, envs, δ = find_groundstate(adapt(CuArray, FiniteMPS(L_mps, ℂ^2, ℂ^D)), H_mps, DMRG());
130+
131+
md"""
132+
Excitations on top of the ground state can be found through the use of the quasiparticle
133+
ansatz. This returns quasiparticle states, which can be converted to regular `FiniteMPS`
134+
objects.
135+
"""
136+
137+
E_ex, qps = excitations(H_mps, QuasiparticleAnsatz(), ψ, envs; num = 18)
138+
states_mps = vcat(ψ, map(qp -> convert(FiniteMPS, qp), qps))
139+
energies_mps = map(x -> expectation_value(x, H_mps), states_mps)
140+
141+
momenta_mps = Float64[]
142+
append!(momenta_mps, fix_degeneracies(states_mps[1:1]))
143+
append!(momenta_mps, fix_degeneracies(states_mps[2:2]))
144+
append!(momenta_mps, fix_degeneracies(states_mps[3:3]))
145+
append!(momenta_mps, fix_degeneracies(states_mps[4:5]))
146+
append!(momenta_mps, fix_degeneracies(states_mps[6:9]))
147+
append!(momenta_mps, fix_degeneracies(states_mps[10:11]))
148+
append!(momenta_mps, fix_degeneracies(states_mps[12:12]))
149+
append!(momenta_mps, fix_degeneracies(states_mps[13:16]))
150+
append!(momenta_mps, fix_degeneracies(states_mps[17:18]))
151+
152+
v = 2.0
153+
Δ_mps = real.(energies_mps[1:18] .- energies_mps[1]) ./ (2π * v / L_mps)
154+
S_mps = momenta_mps ./ (2π / L_mps)
155+
156+
p_mps = plot(
157+
S_mps, real.(Δ_mps);
158+
seriestype = :scatter, xlabel = "conformal spin (S)",
159+
ylabel = "scaling dimension (Δ)", legend = false
160+
)
161+
vline!(p_mps, -3:3; color = "gray", linestyle = :dash)
162+
hline!(p_mps, [0, 1 / 8, 1, 9 / 8, 2, 17 / 8]; color = "gray", linestyle = :dash)
163+
p_mps

0 commit comments

Comments
 (0)