Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 34 additions & 30 deletions src/algorithms/ED.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,47 +31,51 @@

"""
function exact_diagonalization(H::FiniteMPOHamiltonian;
sector=first(sectors(oneunit(physicalspace(H, 1)))),
len::Int=length(H), num::Int=1, which::Symbol=:SR,
sector=one(sectortype(H)),
num::Int=1, which::Symbol=:SR,
alg=Defaults.alg_eigsolve(; dynamic_tols=false))
left = ℂ[typeof(sector)](sector => 1)
right = oneunit(left)
L = length(H)
@assert L > 1 "FiniteMPOHamiltonian must have length > 1"
middle_site = (L >> 1) + 1

Check warning on line 39 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L37-L39

Added lines #L37 - L39 were not covered by tests

middle_site = Int(round(len / 2))

Ot = eltype(H[1])

mpst_type = tensormaptype(spacetype(Ot), 2, 1, storagetype(Ot))
mpsb_type = tensormaptype(spacetype(Ot), 1, 1, storagetype(Ot))
Cs = Vector{Union{Missing,mpsb_type}}(missing, len + 1)
ALs = Vector{Union{Missing,mpst_type}}(missing, len)
ARs = Vector{Union{Missing,mpst_type}}(missing, len)
ACs = Vector{Union{Missing,mpst_type}}(missing, len)
T = storagetype(eltype(H))
TA = tensormaptype(spacetype(H), 2, 1, T)

Check warning on line 42 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L41-L42

Added lines #L41 - L42 were not covered by tests

# fuse from left to right
ALs = Vector{Union{Missing,TA}}(missing, L)
left = oneunit(spacetype(H))

Check warning on line 46 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L45-L46

Added lines #L45 - L46 were not covered by tests
for i in 1:(middle_site - 1)
ALs[i] = isomorphism(storagetype(Ot), left * physicalspace(H, i),
fuse(left * physicalspace(H, i)))
left = _lastspace(ALs[i])'
P = physicalspace(H, i)
ALs[i] = isomorphism(T, left ⊗ P ← fuse(left ⊗ P))
left = right_virtualspace(ALs[i])

Check warning on line 50 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L48-L50

Added lines #L48 - L50 were not covered by tests
end
for i in len:-1:(middle_site + 1)
ARs[i] = _transpose_front(isomorphism(storagetype(Ot),
fuse(right * physicalspace(H, i)'),
right * physicalspace(H, i)'))
right = _firstspace(ARs[i])

# fuse from right to left
ARs = Vector{Union{Missing,TA}}(missing, L)
right = spacetype(H)(sector => 1)
for i in reverse((middle_site + 1):L)
P = physicalspace(H, i)
ARs[i] = _transpose_front(isomorphism(T, fuse(right ⊗ P') ← right ⊗ P'))
right = left_virtualspace(ARs[i])

Check warning on line 59 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L54-L59

Added lines #L54 - L59 were not covered by tests
end
ACs[middle_site] = randomize!(similar(H[1][1, 1, 1, 1],
left * physicalspace(H, middle_site) ← right))
norm(ACs[middle_site]) == 0 && throw(ArgumentError("invalid sector"))
normalize!(ACs[middle_site])

#construct the largest possible finite mps of that length
# center
ACs = Vector{Union{Missing,TA}}(missing, L)
P = physicalspace(H, middle_site)
ACs[middle_site] = rand!(similar(ALs[1], left ⊗ P ← right))

Check warning on line 65 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L63-L65

Added lines #L63 - L65 were not covered by tests

TB = tensormaptype(spacetype(H), 1, 1, T)
Cs = Vector{Union{Missing,TB}}(missing, L + 1)

Check warning on line 68 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L67-L68

Added lines #L67 - L68 were not covered by tests
state = FiniteMPS(ALs, ARs, ACs, Cs)
envs = environments(state, H)

#optimize the middle site. Because there is no truncation, this single site captures the entire possible hilbert space
H_ac = ∂∂AC(middle_site, state, H, envs) # this linear operator is now the actual full hamiltonian!
(vals, vecs, convhist) = eigsolve(H_ac, state.AC[middle_site], num, which, alg)
# optimize the middle site
# Because the MPS is full rank - this is equivalent to the full Hamiltonian
AC₀ = state.AC[middle_site]
H_ac = ∂∂AC(middle_site, state, H, envs)
vals, vecs, convhist = eigsolve(H_ac, AC₀, num, which, alg)

Check warning on line 76 in src/algorithms/ED.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/ED.jl#L74-L76

Added lines #L74 - L76 were not covered by tests

# repack eigenstates
state_vecs = map(vecs) do v
cs = copy(state)
cs.AC[middle_site] = v
Expand Down
8 changes: 3 additions & 5 deletions src/operators/abstractmpo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@

function add_physical_charge(O::MPOTensor, charge::Sector)
sectortype(O) === typeof(charge) || throw(SectorMismatch())
auxspace = Vect[typeof(charge)](charge => 1)
auxspace = Vect[typeof(charge)](charge => 1)'

Check warning on line 264 in src/operators/abstractmpo.jl

View check run for this annotation

Codecov / codecov/patch

src/operators/abstractmpo.jl#L264

Added line #L264 was not covered by tests
F = fuser(scalartype(O), physicalspace(O), auxspace)
@plansor O_charged[-1 -2; -3 -4] := F[-2; 1 2] *
O[-1 1; 4 3] *
Expand All @@ -270,16 +270,14 @@
end
function add_physical_charge(O::BraidingTensor, charge::Sector)
sectortype(O) === typeof(charge) || throw(SectorMismatch())
auxspace = Vect[typeof(charge)](charge => 1)
auxspace = Vect[typeof(charge)](charge => 1)'

Check warning on line 273 in src/operators/abstractmpo.jl

View check run for this annotation

Codecov / codecov/patch

src/operators/abstractmpo.jl#L273

Added line #L273 was not covered by tests
V = left_virtualspace(O) ⊗ fuse(physicalspace(O), auxspace) ←
fuse(physicalspace(O), auxspace) ⊗ right_virtualspace(O)
return BraidingTensor{scalartype(O)}(V)
end
function add_physical_charge(O::AbstractBlockTensorMap{<:Any,<:Any,2,2}, charge::Sector)
sectortype(O) == typeof(charge) || throw(SectorMismatch())

auxspace = Vect[typeof(charge)](charge => 1)

auxspace = Vect[typeof(charge)](charge => 1)'

Check warning on line 280 in src/operators/abstractmpo.jl

View check run for this annotation

Codecov / codecov/patch

src/operators/abstractmpo.jl#L280

Added line #L280 was not covered by tests
Odst = similar(O,
left_virtualspace(O) ⊗ fuse(physicalspace(O), auxspace) ←
fuse(physicalspace(O), auxspace) ⊗ right_virtualspace(O))
Expand Down
38 changes: 28 additions & 10 deletions src/states/finitemps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,13 @@

Vspaces[1] = left
for k in 2:N
Vspaces[k] = infimum(fuse(Vspaces[k - 1], fusedPspaces[k]), maxVspaces[k - 1])
Vspaces[k] = infimum(fuse(Vspaces[k - 1], fusedPspaces[k - 1]), maxVspaces[k - 1])
dim(Vspaces[k]) > 0 || @warn "no fusion channels available at site $k"
end

Vspaces[end] = right
for k in N:-1:2
Vspaces[k] = infimum(maxVspaces[k - 1], fuse(Vspaces[k + 1], dual(fusedPspaces[k])))
for k in reverse(2:N)
Vspaces[k] = infimum(Vspaces[k], fuse(Vspaces[k + 1], dual(fusedPspaces[k])))
dim(Vspaces[k]) > 0 || @warn "no fusion channels available at site $k"
end

Expand Down Expand Up @@ -383,18 +383,36 @@
return ProductSpace{S}(space.(Ref(t), Base.front(Base.tail(TensorKit.allind(t)))))
end

"""
max_virtualspaces(ψ::FiniteMPS)
max_virtualspaces(Ps::Vector{<:Union{S,CompositeSpace{S}}}; left=oneunit(S), right=oneunit(S))

Compute the maximal virtual spaces of a given MPS or its spaces.
"""
function max_virtualspaces(Ps::Vector{<:Union{S,CompositeSpace{S}}}; left=oneunit(S),

Check warning on line 392 in src/states/finitemps.jl

View check run for this annotation

Codecov / codecov/patch

src/states/finitemps.jl#L392

Added line #L392 was not covered by tests
right=oneunit(S)) where {S<:ElementarySpace}
Vs = similar(Ps, length(Ps) + 1)
Vs[1] = left
Vs[end] = right
for k in 2:length(Ps)
Vs[k] = fuse(Vs[k - 1], fuse(Ps[k - 1]))
end
for k in reverse(2:length(Ps))
Vs[k] = infimum(Vs[k], fuse(Vs[k + 1], dual(fuse(Ps[k]))))
end
return Vs

Check warning on line 403 in src/states/finitemps.jl

View check run for this annotation

Codecov / codecov/patch

src/states/finitemps.jl#L394-L403

Added lines #L394 - L403 were not covered by tests
end
function max_virtualspaces(ψ::FiniteMPS)
return max_virtualspaces(physicalspace(ψ); left=left_virtualspace(ψ, 1),

Check warning on line 406 in src/states/finitemps.jl

View check run for this annotation

Codecov / codecov/patch

src/states/finitemps.jl#L405-L406

Added lines #L405 - L406 were not covered by tests
right=right_virtualspace(ψ, length(ψ)))
end

"""
max_Ds(ψ::FiniteMPS) -> Vector{Float64}

Compute the dimension of the maximal virtual space at a given site.
"""
function max_Ds(ψ::FiniteMPS)
N = length(ψ)
physicaldims = dim.(space.(Ref(ψ)), 1:N)
D_left = cumprod(vcat(dim(left_virtualspace(ψ, 1)), physicaldims))
D_right = cumprod(vcat(dim(right_virtualspace(ψ, N)), reverse(physicaldims)))
return min.(D_left, D_right)
end
max_Ds(ψ::FiniteMPS) = dim.(max_virtualspaces(ψ))

Check warning on line 415 in src/states/finitemps.jl

View check run for this annotation

Codecov / codecov/patch

src/states/finitemps.jl#L415

Added line #L415 was not covered by tests

function Base.summary(io::IO, ψ::FiniteMPS)
return print(io, "$(length(ψ))-site FiniteMPS ($(scalartype(ψ)), $(spacetype(ψ)))")
Expand Down
20 changes: 11 additions & 9 deletions src/states/quasiparticle_state.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function LeftGaugedQP(datfun, left_gs, right_gs=left_gs;
Xs = map(enumerate(VLs)) do (loc, vl)
x = similar(vl,
right_virtualspace(vl) ←
excitation_space' ⊗ right_virtualspace(right_gs, loc))
excitation_space ⊗ right_virtualspace(right_gs, loc))
fill_data!(x, datfun)
return x
end
Expand All @@ -63,13 +63,15 @@ end

function RightGaugedQP(datfun, left_gs, right_gs=left_gs;
sector=one(sectortype(left_gs)), momentum=0.0)
#find the left null spaces for the TNS
# find the left null spaces for the TNS
excitation_space = Vect[typeof(sector)](sector => 1)
VRs = [adjoint(leftnull(adjoint(v))) for v in _transpose_tail.(right_gs.AR)]
Xs = [TensorMap{scalartype(left_gs)}(undef, left_virtualspace(right_gs, loc)',
excitation_space' * _firstspace(VRs[loc]))
for loc in 1:length(left_gs)]
fill_data!.(Xs, datfun)
VRs = convert(Vector, map(rightnull! ∘ _transpose_tail, right_gs.AR))
Xs = map(enumerate(VRs)) do (i, vr)
x = similar(vr,
left_virtualspace(left_gs, i)' ←
excitation_space ⊗ _firstspace(vr))
return fill_data!(x, datfun)
end
left_gs isa InfiniteMPS ||
momentum == zero(momentum) ||
@warn "momentum is ignored for finite quasiparticles"
Expand All @@ -84,10 +86,10 @@ function Base.similar(v::RightGaugedQP, ::Type{T}=scalartype(v)) where {T<:Numbe
return RightGaugedQP(v.left_gs, v.right_gs, similar.(v.Xs, T), v.VRs, v.momentum)
end

Base.getindex(v::LeftGaugedQP, i::Int) = v.VLs[mod1(i, end)] * v.Xs[mod1(i, end)];
Base.getindex(v::LeftGaugedQP, i::Int) = v.VLs[mod1(i, end)] * v.Xs[mod1(i, end)]
function Base.getindex(v::RightGaugedQP, i::Int)
@plansor t[-1 -2; -3 -4] := v.Xs[mod1(i, end)][-1; -3 1] * v.VRs[mod1(i, end)][1; -4 -2]
end;
end

function Base.setindex!(v::LeftGaugedQP, B, i::Int)
v.Xs[mod1(i, end)] = v.VLs[mod1(i, end)]' * B
Expand Down
100 changes: 100 additions & 0 deletions test/excis.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using MPSKit, TensorKit
import LinearAlgebra.eigvals
using MPSKit: max_virtualspaces

V = U1Space(i => 1 for i in 0:1)
O = randn(V^2 ← V^2)
O += O' # Hermitian

N = 3
H = FiniteMPOHamiltonian(fill(V, N), (i, i + 1) => O for i in 1:(N - 1));

h = convert(TensorMap, H);

sectors = collect(blocksectors(h))
sec = U1Irrep(1)
@assert sec in sectors
num = 10
vals1 = eigvals(block(h, sec))
vals2 = eigvals(h)[sec]
@assert vals1 ≈ vals2
vals3, vecs = exact_diagonalization(H; sector=(sec), num);
vals1
vals3

right = U1Space(sec => 1)
max_virtualspaces(physicalspace(H); right)

psi_full = rand(oneunit(V) * V^N ← right);
dim(space(psi_full))
psi = MPSKit.decompose_localmps(psi_full);
left_virtualspace.(psi)

left_virtualspace.(vecs[1].AL)
right_virtualspace.(vecs[1].AL)
max_virtualspaces(physicalspace(H); right)
psi1 = FiniteMPS(physicalspace(H), max_virtualspaces(physicalspace(H))[2:(end - 1)])
psi1, = find_groundstate(psi1, H);
psi2 = FiniteMPS(physicalspace(H), max_virtualspaces(physicalspace(H); right)[2:(end - 1)];
right)
left_virtualspace.(psi2.AL)
right_virtualspace.(psi2.AL)

psi2, = find_groundstate(psi2, H);
expectation_value(psi2, H)

Es, Bs = excitations(H, QuasiparticleAnsatz(), FiniteMPS(psi); sector=sec);
@inferred excitations(H, QuasiparticleAnsatz(), FiniteMPS(psi); sector=sec);

Es .+ expectation_value(psi1, H)

vals1
vals3

psi2
using TestEnv
using Test
TestEnv.activate()
include("setup.jl")
using .TestSetup
using TensorKit, MPSKit
using MPSKit: Multiline
using KrylovKit

H = repeat(TestSetup.sixvertex(), 2)
ψ = InfiniteMPS([ℂ^2, ℂ^2], [ℂ^10, ℂ^10])
ψ, envs, _ = leading_boundary(ψ, H,
VUMPS(; maxiter=400, tol=1e-10))
energies, ϕs = @inferred excitations(H, QuasiparticleAnsatz(),
[0.0, Float64(pi / 2)], ψ,
envs; verbosity=0)
@test abs(energies[1]) > abs(energies[2]) # has a minimum at pi/2
alg = QuasiparticleAnsatz()
ps = [0.0, Float64(pi / 2)]
excitations(H, alg, ps, ψ, envs; verbosity=0);
using Cthulhu
Hm = convert(MultilineMPO, H);
psim = convert(MultilineMPS, ψ);
envs = environments(psim, Hm);
excitations(Hm, alg, ps[1], psim, envs, psim, envs; verbosity=0);

@descend excitations(Hm, alg, ps[1], psim, envs, psim, envs);

qp = Multiline([LeftGaugedQP(rand, psim[1], psim[1]; sector=one(sectortype(psim[1])),
momentum=ps[1])]);
excitations(Hm, alg, qp, envs, envs; num=1);

@descend excitations(Hm, alg, qp, envs, envs; num=1);
@code_warntype excitations(Hm, alg, qp, envs, envs; num=1);

Heff = MPSKit.EffectiveExcitationHamiltonian(H, envs[1], envs[1], fill(1.0, length(H)));
Heffs = Multiline([Heff]);
@code_warntype KrylovKit.apply(Heff, qp[1])
@descend KrylovKit.apply(Heff, qp[1])

KrylovKit.apply(Multiline([Heff]), qp);
@code_warntype KrylovKit.apply(Heffs, qp);

@descend eigsolve(Heffs, qp, 1, :LM, Lanczos());
@code_warntype eigsolve(Heffs, qp, 1, :LM);
@descend eigsolve(Heffs, qp, 1, :LM);