Skip to content

Commit 3b9bfed

Browse files
authored
Improve quasiparticle type stability (#272)
* Quasiparticle type stability improvements Test type stability excitations * Add Multiline VectorInterface support * Add multiline QP constructor * utility `eltype` in type domain * More utility functions * Replace `@constinferred` with `@inferred` * Refactor QP to improve type stability (again) * various fixes * restore `effective_excitation_hamiltonian` * attempt to fix type stability for lts
1 parent d30ef9e commit 3b9bfed

File tree

7 files changed

+221
-173
lines changed

7 files changed

+221
-173
lines changed

src/algorithms/excitation/quasiparticleexcitation.jl

Lines changed: 129 additions & 151 deletions
Large diffs are not rendered by default.

src/environments/qp_envs.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ end
150150
function environments(exci::FiniteQP,
151151
H::FiniteMPOHamiltonian,
152152
lenvs=environments(exci.left_gs, H),
153-
renvs=exci.trivial ? lenvs : environments(exci.right_gs, H))
153+
renvs=exci.trivial ? lenvs : environments(exci.right_gs, H);
154+
kwargs...)
154155
AL = exci.left_gs.AL
155156
AR = exci.right_gs.AR
156157

src/states/infinitemps.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ Utility
214214

215215
Base.size::InfiniteMPS, args...) = size.AL, args...)
216216
Base.length::InfiniteMPS) = length.AL)
217-
Base.eltype::InfiniteMPS) = eltype.AL)
217+
Base.eltype::InfiniteMPS) = eltype(typeof(ψ))
218+
Base.eltype(::Type{<:InfiniteMPS{A}}) where {A} = A
218219
Base.copy::InfiniteMPS) = InfiniteMPS(copy.AL), copy.AR), copy.C), copy.AC))
219220
function Base.copy!::InfiniteMPS, ϕ::InfiniteMPS)
220221
copy!.(ψ.AL, ϕ.AL)

src/states/multilinemps.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ bond_type(::Type{Multiline{S}}) where {S} = bond_type(S)
7474
site_type(st::Multiline) = site_type(typeof(st))
7575
bond_type(st::Multiline) = bond_type(typeof(st))
7676
VectorInterface.scalartype(::Multiline{T}) where {T} = scalartype(T)
77+
TensorKit.sectortype(t::Multiline) = sectortype(typeof(t))
78+
TensorKit.sectortype(::Type{Multiline{T}}) where {T} = sectortype(T)
79+
TensorKit.spacetype(t::Multiline) = spacetype(typeof(t))
80+
TensorKit.spacetype(::Type{Multiline{T}}) where {T} = spacetype(T)
7781

7882
function TensorKit.dot(a::MultilineMPS, b::MultilineMPS; kwargs...)
7983
return sum(dot.(parent(a), parent(b); kwargs...))

src/states/quasiparticle_state.jl

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,40 @@ struct RightGaugedQP{S,T1,T2,E<:Number}
2626
momentum::E
2727
end
2828

29+
function leftgaugedqptype(::Type{S}, ::Type{E}) where {S,E<:Number}
30+
T1 = eltype(S)
31+
T2 = tensormaptype(spacetype(T1), 1, 2, storagetype(T1))
32+
return LeftGaugedQP{S,T1,T2,E}
33+
end
34+
2935
#constructors
3036
function LeftGaugedQP(datfun, left_gs, right_gs=left_gs;
3137
sector=one(sectortype(left_gs)), momentum=0.0)
3238
# find the left null spaces for the TNS
3339
excitation_space = Vect[typeof(sector)](sector => 1)
34-
VLs = [adjoint(rightnull(adjoint(v))) for v in left_gs.AL]
35-
Xs = [TensorMap{scalartype(left_gs)}(undef, _lastspace(VLs[loc])',
36-
excitation_space' *
37-
right_virtualspace(right_gs, loc))
38-
for loc in 1:length(left_gs)]
39-
fill_data!.(Xs, datfun)
40+
VLs = convert(Vector, map(leftnull, left_gs.AL))
41+
Xs = map(enumerate(VLs)) do (loc, vl)
42+
x = similar(vl,
43+
right_virtualspace(vl)
44+
excitation_space' right_virtualspace(right_gs, loc))
45+
fill_data!(x, datfun)
46+
return x
47+
end
4048
left_gs isa InfiniteMPS ||
4149
momentum == zero(momentum) ||
4250
@warn "momentum is ignored for finite quasiparticles"
4351
return LeftGaugedQP(left_gs, right_gs, VLs, Xs, momentum)
4452
end
53+
function LeftGaugedQP(datfun, left_gs::MultilineMPS, right_gs::MultilineMPS=left_gs;
54+
sector=one(sectortype(left_gs)), momentum=0.0)
55+
# not sure why this is needed for type stability
56+
Tresult = leftgaugedqptype(eltype(parent(left_gs)), typeof(momentum))
57+
qp_rows = Vector{Tresult}(undef, size(left_gs, 1))
58+
for row in eachindex(qp_rows)
59+
qp_rows[row] = LeftGaugedQP(datfun, left_gs[row], right_gs[row]; sector, momentum)
60+
end
61+
return Multiline(qp_rows)
62+
end
4563

4664
function RightGaugedQP(datfun, left_gs, right_gs=left_gs;
4765
sector=one(sectortype(left_gs)), momentum=0.0)
@@ -59,13 +77,11 @@ function RightGaugedQP(datfun, left_gs, right_gs=left_gs;
5977
end
6078

6179
#gauge dependent code
62-
function Base.similar(v::LeftGaugedQP, T=scalartype(v))
63-
return LeftGaugedQP(v.left_gs, v.right_gs, v.VLs, map(e -> similar(e, T), v.Xs),
64-
v.momentum)
80+
function Base.similar(v::LeftGaugedQP, ::Type{T}=scalartype(v)) where {T<:Number}
81+
return LeftGaugedQP(v.left_gs, v.right_gs, v.VLs, similar.(v.Xs, T), v.momentum)
6582
end
66-
function Base.similar(v::RightGaugedQP, T=scalartype(v))
67-
return RightGaugedQP(v.left_gs, v.right_gs, map(e -> similar(e, T), v.Xs), v.VRs,
68-
v.momentum)
83+
function Base.similar(v::RightGaugedQP, ::Type{T}=scalartype(v)) where {T<:Number}
84+
return RightGaugedQP(v.left_gs, v.right_gs, similar.(v.Xs, T), v.VRs, v.momentum)
6985
end
7086

7187
Base.getindex(v::LeftGaugedQP, i::Int) = v.VLs[mod1(i, end)] * v.Xs[mod1(i, end)];

src/utility/multiline.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,49 @@ function Base.repeat(A::Multiline, rows::Int, cols::Int)
5151
outer = repeat(inner, rows)
5252
return Multiline(outer)
5353
end
54+
55+
# VectorInterface
56+
# ---------------
57+
VectorInterface.scalartype(::Type{Multiline{T}}) where {T} = scalartype(T)
58+
59+
function VectorInterface.zerovector(x::Multiline, ::Type{S}) where {S<:Number}
60+
return Multiline(zerovector.(parent(x), S))
61+
end
62+
VectorInterface.zerovector!(x::Multiline) = (zerovector!.(parent(x)); x)
63+
64+
function VectorInterface.scale(x::Multiline, α::Number)
65+
return scale!(zerovector(x, VectorInterface.promote_scale(x, α)), x, α)
66+
end
67+
68+
function VectorInterface.scale!(x::Multiline, α::Number)
69+
scale!.(parent(x), α)
70+
return x
71+
end
72+
VectorInterface.scale!!(x::Multiline, α::Number) = scale!(x, α)
73+
74+
function VectorInterface.scale!(x::Multiline, x′::Multiline, α::Number)
75+
scale!.(parent(x), parent(x′), α)
76+
return x
77+
end
78+
79+
VectorInterface.scale!!(x::Multiline, x′::Multiline, α::Number) = scale!(x, x′, α)
80+
81+
function VectorInterface.add(x::Multiline, y::Multiline, α::Number, β::Number)
82+
z = zerovector(x, VectorInterface.promote_add(x, y, α, β))
83+
return add!(scale!(z, x, β), y, α)
84+
end
85+
86+
function VectorInterface.add!(x::Multiline, y::Multiline, α::Number, β::Number)
87+
add!.(parent(x), parent(y), α, β)
88+
return x
89+
end
90+
91+
VectorInterface.add!!(x::Multiline, y::Multiline, α::Number, β::Number) = add!(x, y, α, β)
92+
93+
function VectorInterface.inner(x::Multiline, y::Multiline)
94+
T = VectorInterface.promote_inner(x, y)
95+
init = zero(T)
96+
return sum(splat(inner), zip(parent(parent(x)), parent(parent(y))); init)
97+
end
98+
99+
LinearAlgebra.norm(x::Multiline) = sqrt(real(inner(x, x)))

test/algorithms.jl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,8 @@ end
435435
ψ = InfiniteMPS([ℙ^3, ℙ^3], [ℙ^48, ℙ^48])
436436
ψ, envs, _ = find_groundstate(ψ, H; maxiter=400, verbosity=verbosity_conv,
437437
tol=1e-10)
438-
energies, ϕs = excitations(H, QuasiparticleAnsatz(), Float64(pi), ψ, envs)
438+
energies, ϕs = @inferred excitations(H, QuasiparticleAnsatz(), Float64(pi), ψ,
439+
envs)
439440
@test energies[1] 0.41047925 atol = 1e-4
440441
@test variance(ϕs[1], H) < 1e-8
441442
end
@@ -445,8 +446,9 @@ end
445446
ψ, envs, _ = leading_boundary(ψ, H,
446447
VUMPS(; maxiter=400, verbosity=verbosity_conv,
447448
tol=1e-10))
448-
energies, ϕs = excitations(H, QuasiparticleAnsatz(), [0.0, Float64(pi / 2)], ψ,
449-
envs; verbosity=0)
449+
energies, ϕs = @inferred excitations(H, QuasiparticleAnsatz(),
450+
[0.0, Float64(pi / 2)], ψ,
451+
envs; verbosity=0)
450452
@test abs(energies[1]) > abs(energies[2]) # has a minimum at pi/2
451453
end
452454

@@ -455,7 +457,7 @@ end
455457
H_inf = force_planar(transverse_field_ising())
456458
ψ_inf = InfiniteMPS([ℙ^2], [ℙ^10])
457459
ψ_inf, envs, _ = find_groundstate(ψ_inf, H_inf; maxiter=400, verbosity, tol=1e-9)
458-
energies, ϕs = excitations(H_inf, QuasiparticleAnsatz(), 0.0, ψ_inf, envs)
460+
energies, ϕs = @inferred excitations(H_inf, QuasiparticleAnsatz(), 0.0, ψ_inf, envs)
459461
inf_en = energies[1]
460462

461463
fin_en = map([20, 10]) do len
@@ -464,20 +466,20 @@ end
464466
ψ, envs, = find_groundstate(ψ, H; verbosity)
465467

466468
# find energy with quasiparticle ansatz
467-
energies_QP, ϕs = excitations(H, QuasiparticleAnsatz(), ψ, envs)
469+
energies_QP, ϕs = @inferred excitations(H, QuasiparticleAnsatz(), ψ, envs)
468470
@test variance(ϕs[1], H) < 1e-6
469471

470472
# find energy with normal dmrg
471473
for gsalg in (DMRG(; verbosity, tol=1e-6),
472474
DMRG2(; verbosity, tol=1e-6, trscheme=truncbelow(1e-4)))
473-
energies_dm, _ = excitations(H, FiniteExcited(; gsalg), ψ)
475+
energies_dm, _ = @inferred excitations(H, FiniteExcited(; gsalg), ψ)
474476
@test energies_dm[1] energies_QP[1] + expectation_value(ψ, H, envs) atol = 1e-4
475477
end
476478

477479
# find energy with Chepiga ansatz
478-
energies_ch, _ = excitations(H, ChepigaAnsatz(), ψ, envs)
480+
energies_ch, _ = @inferred excitations(H, ChepigaAnsatz(), ψ, envs)
479481
@test energies_ch[1] energies_QP[1] + expectation_value(ψ, H, envs) atol = 1e-4
480-
energies_ch2, _ = excitations(H, ChepigaAnsatz2(), ψ, envs)
482+
energies_ch2, _ = @inferred excitations(H, ChepigaAnsatz2(), ψ, envs)
481483
@test energies_ch2[1] energies_QP[1] + expectation_value(ψ, H, envs) atol = 1e-4
482484
return energies_QP[1]
483485
end

0 commit comments

Comments
 (0)