Bug: excitations(H, FiniteExcited(), ψ; num>1) returns energies/states in reverse order
excitations with FiniteExcited() and num > 1 returns ens/excis with the highest requested excitation at index 1, not the lowest.
Cause (dmrgexcitation.jl)
envs = environments(init, super_op)
ne, _ = find_groundstate(init, super_op, alg.gsalg, envs)
nstates = (states..., ne)
ens, excis = excitations(H, alg, nstates; init = init, num = num - 1)
push!(ens, expectation_value(ne, H))
push!(excis, ne)
ne is the ground state of the penalized operator H + λΣᵢ|ψᵢ⟩⟨ψᵢ|, i.e. the lowest excitation of H orthogonal to everything in states so far — not the ground state of H itself. On the outermost call (states=(ψ_gs,)), this is the true first excited state; the recursion then finds progressively higher excitations. Since each call recurses before pushing its own result, the last-found (highest-energy) state ends up first in the returned array.
Reproducer (TFIM)
using TensorKit, MPSKit
L = 16; J = 1.0; g = 0.7
V = ComplexSpace(2)
X = TensorMap(ComplexF64[0 1; 1 0], V, V)
Z = TensorMap(ComplexF64[1 0; 0 -1], V, V)
lattice = fill(V, L)
H = FiniteMPOHamiltonian(lattice, (i,i+1) => -J*(Z⊗Z) for i in 1:L-1) +
FiniteMPOHamiltonian(lattice, (i,) => -g*X for i in 1:L)
psi_gs, envs_gs, _ = find_groundstate(FiniteMPS(L, V, ComplexSpace(32)), H, DMRG())
E0 = real(expectation_value(psi_gs, H, envs_gs))
E_ex, _ = excitations(H, FiniteExcited(; weight=20.0), psi_gs; num=2)
println(real.(E_ex) .- E0) # [0.7078, 0.00339] -- gap order reversed
Cross-checked against QuasiparticleAnsatz, which returns the same two gaps in ascending order: [0.00339, 0.7078].
Suggested fix
Replace push! with pushfirst! on the two lines above:
pushfirst!(ens, expectation_value(ne, H))
pushfirst!(excis, ne)
Since the recursive call already returns its sublist in ascending-energy order (by induction), and ne is always lower in energy than anything found by the recursion, prepending it preserves ascending order at every level.
Unrelated docstring inconsistency
The FiniteExcited type docstring states the algorithm minimizes the energy of H - λᵢ|ψᵢ⟩⟨ψᵢ|, but the actual code builds H + λᵢ|ψᵢ⟩⟨ψᵢ| (all-positive coefficients in the LinearCombination call above), consistent with the field docstring "energy penalty for enforcing orthogonality." The type docstring's minus sign looks like a typo.
Originally posted by @kangzb in https://github.com/QuantumKitHub/MPSKit.jl/discussions/440
Bug:
excitations(H, FiniteExcited(), ψ; num>1)returns energies/states in reverse orderexcitationswithFiniteExcited()andnum > 1returnsens/exciswith the highest requested excitation at index 1, not the lowest.Cause (
dmrgexcitation.jl)neis the ground state of the penalized operatorH + λΣᵢ|ψᵢ⟩⟨ψᵢ|, i.e. the lowest excitation ofHorthogonal to everything instatesso far — not the ground state ofHitself. On the outermost call (states=(ψ_gs,)), this is the true first excited state; the recursion then finds progressively higher excitations. Since each call recurses before pushing its own result, the last-found (highest-energy) state ends up first in the returned array.Reproducer (TFIM)
Cross-checked against
QuasiparticleAnsatz, which returns the same two gaps in ascending order:[0.00339, 0.7078].Suggested fix
Replace
push!withpushfirst!on the two lines above:Since the recursive call already returns its sublist in ascending-energy order (by induction), and
neis always lower in energy than anything found by the recursion, prepending it preserves ascending order at every level.Unrelated docstring inconsistency
The
FiniteExcitedtype docstring states the algorithm minimizes the energy ofH - λᵢ|ψᵢ⟩⟨ψᵢ|, but the actual code buildsH + λᵢ|ψᵢ⟩⟨ψᵢ|(all-positive coefficients in theLinearCombinationcall above), consistent with the field docstring "energy penalty for enforcing orthogonality." The type docstring's minus sign looks like a typo.Originally posted by @kangzb in https://github.com/QuantumKitHub/MPSKit.jl/discussions/440