Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

negative Grassmann inner product #53

Open
lkdvos opened this issue May 6, 2023 · 2 comments
Open

negative Grassmann inner product #53

lkdvos opened this issue May 6, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@lkdvos
Copy link
Member

lkdvos commented May 6, 2023

Due to numerical errors, it seems like the inner product of a grassman gradient with itself can sometimes take on negative values that are of the order -eps, which then fails when OptimKit wants to take the square root.

MBA:

using MPSKit, MPSKitModels
psi = InfiniteMPS(2, 12)
H = transverse_field_ising(; hx=0.0) # exact product state solution
julia> psi, envs, delta = find_groundstate(psi, H)
[ Info: vumps @iteration 1 galerkin = 0.5339115698990319
[ Info: vumps @iteration 2 galerkin = 0.0012648372627602012
[ Info: vumps @iteration 3 galerkin = 1.1562975109758041e-11
ERROR: DomainError with -1.413494684364987e-21:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
Stacktrace:
 [1] throw_complex_domainerror(f::Symbol, x::Float64)
   @ Base.Math ./math.jl:33
 [2] sqrt
   @ ./math.jl:591 [inlined]
 [3] optimize(fg::typeof(MPSKit.GrassmannMPS.fg), x::MPSKit.GrassmannMPS.ManifoldPoint{InfiniteMPS{TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}}, MPSKit.MPOHamInfEnv{MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 2, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, ComplexF64}, TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, InfiniteMPS{TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}}, KrylovKit.GMRES{KrylovKit.ModifiedGramSchmidt2, Float64}}, PeriodicArray{TensorKitManifolds.Grassmann.GrassmannTangent{TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{Float64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}}, 1}, Vector{TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}}}, alg::OptimKit.ConjugateGradient{OptimKit.HagerZhang{Rational{Int64}}, Float64, OptimKit.HagerZhangLineSearch{Rational{Int64}}}; precondition::typeof(OptimKit._precondition), finalize!::typeof(OptimKit._finalize!), retract::Function, inner::typeof(MPSKit.GrassmannMPS.inner), transport!::typeof(MPSKit.GrassmannMPS.transport!), scale!::typeof(MPSKit.GrassmannMPS.scale!), add!::typeof(MPSKit.GrassmannMPS.add!), isometrictransport::Bool)
   @ OptimKit ~/.julia/packages/OptimKit/xpmbV/src/cg.jl:27
 [4] find_groundstate(Ψ::InfiniteMPS{TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}}, H::MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 2, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, ComplexF64}, alg::GradientGrassmann, envs::MPSKit.MPOHamInfEnv{MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 2, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, ComplexF64}, TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, InfiniteMPS{TensorKit.TensorMap{TensorKit.ComplexSpace, 2, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}, TensorKit.TensorMap{TensorKit.ComplexSpace, 1, 1, TensorKit.Trivial, Matrix{ComplexF64}, Nothing, Nothing}}, KrylovKit.GMRES{KrylovKit.ModifiedGramSchmidt2, Float64}})
   @ MPSKit ~/Projects/JuliaProjects/MPSKit.jl/src/algorithms/groundstate/gradient_grassmann.jl:53
 [5] find_groundstate
   @ ~/Projects/JuliaProjects/MPSKit.jl/src/algorithms/unionalg.jl:25 [inlined]
 [6] #find_groundstate#381
   @ ~/Projects/JuliaProjects/MPSKit.jl/src/algorithms/groundstate/find_groundstate.jl:41 [inlined]
 [7] find_groundstate (repeats 2 times)
   @ ~/Projects/JuliaProjects/MPSKit.jl/src/algorithms/groundstate/find_groundstate.jl:19 [inlined]
 [8] top-level scope
   @ REPL[12]:1
@DaanMaertens
Copy link
Collaborator

So I've been trying to fix this bug by implementing what we discussed together, namely:

function inner(g1::PrecGrad, g2::PrecGrad, rho=one(g1.rho))
   
    if g1 === g2
        max(real(unsafe_inner(g1,g2,rho)),eps())
    else   
        unsafe_inner(g1,g2,rho)
    end
end
function unsafe_inner(g1::PrecGrad, g2::PrecGrad, rho=one(g1.rho))
    Grassmann.base(g1) == Grassmann.base(g2) || throw(ArgumentError("incompatible base"))
    if g1.rho == rho
        Grassmann.dot(g1.g.Z, g2.Pg.Z)
    elseif g2.rho == rho
        Grassmann.dot(g1.Pg.Z, g2.g.Z)
    else
        Grassmann.dot(g1.Pg.Z, g2.Pg.Z * rho)
    end

end

This fixes the bug for the sqrt but introduces another later down the line

ERROR: LoadError: linesearch was not given a descent direction!
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] (::OptimKit.HagerZhangLineSearch{Rational{Int64}})(fg::Function, x₀::MPSKit.GrassmannMPS.ManifoldPoint{InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, MPSKit.MPOHamInfEnv{MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 2, Matrix{ComplexF64}}, ComplexF64}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, KrylovKit.GMRES{KrylovKit.ModifiedGramSchmidt2, Float64}}, PeriodicArray{TensorKitManifolds.Grassmann.GrassmannTangent{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{Float64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, 1}, Vector{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}}, η₀::Vector{MPSKit.GrassmannMPS.PrecGrad{TensorKitManifolds.Grassmann.GrassmannTangent{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{Float64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}}, fg₀::Tuple{Float64, Vector{MPSKit.GrassmannMPS.PrecGrad{TensorKitManifolds.Grassmann.GrassmannTangent{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{Float64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}}}; retract::Function, inner::typeof(MPSKit.GrassmannMPS.inner), initialguess::Float64, acceptfirst::Bool)
   @ OptimKit ~/.julia/packages/OptimKit/xpmbV/src/linesearches.jl:255
 [3] optimize(fg::typeof(MPSKit.GrassmannMPS.fg), x::MPSKit.GrassmannMPS.ManifoldPoint{InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, MPSKit.MPOHamInfEnv{MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 2, Matrix{ComplexF64}}, ComplexF64}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, KrylovKit.GMRES{KrylovKit.ModifiedGramSchmidt2, Float64}}, PeriodicArray{TensorKitManifolds.Grassmann.GrassmannTangent{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{Float64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, 1}, Vector{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}}, alg::OptimKit.ConjugateGradient{OptimKit.HagerZhang{Rational{Int64}}, Float64, OptimKit.HagerZhangLineSearch{Rational{Int64}}}; precondition::typeof(OptimKit._precondition), finalize!::typeof(OptimKit._finalize!), retract::Function, inner::typeof(MPSKit.GrassmannMPS.inner), transport!::typeof(MPSKit.GrassmannMPS.transport!), scale!::typeof(MPSKit.GrassmannMPS.scale!), add!::typeof(MPSKit.GrassmannMPS.add!), isometrictransport::Bool)
   @ OptimKit ~/.julia/packages/OptimKit/xpmbV/src/cg.jl:68
 [4] find_groundstate::InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, H::MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 2, Matrix{ComplexF64}}, ComplexF64}, alg::GradientGrassmann, envs::MPSKit.MPOHamInfEnv{MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 2, Matrix{ComplexF64}}, ComplexF64}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, KrylovKit.GMRES{KrylovKit.ModifiedGramSchmidt2, Float64}})
   @ MPSKit ~/.julia/packages/MPSKit/atykv/src/algorithms/groundstate/gradient_grassmann.jl:54
 [5] find_groundstate
   @ ~/.julia/packages/MPSKit/atykv/src/algorithms/unionalg.jl:25 [inlined]
 [6] #find_groundstate#380
   @ ~/.julia/packages/MPSKit/atykv/src/algorithms/groundstate/find_groundstate.jl:40 [inlined]
 [7] find_groundstate
   @ ~/.julia/packages/MPSKit/atykv/src/algorithms/groundstate/find_groundstate.jl:19 [inlined]
 [8] find_groundstate::InfiniteMPS{TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 1, Matrix{ComplexF64}}, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 1, 1, Matrix{ComplexF64}}}, H::MPOHamiltonian{TensorKit.ComplexSpace, TensorKit.TrivialTensorMap{TensorKit.ComplexSpace, 2, 2, Matrix{ComplexF64}}, ComplexF64})
   @ MPSKit ~/.julia/packages/MPSKit/atykv/src/algorithms/groundstate/find_groundstate.jl:19
 [9] top-level scope
   @ ~/Desktop/GitHub/MyGradientFix.jl/test/runtests.jl:12
in expression starting at /Users/daan/Desktop/GitHub/MyGradientFix.jl/test/runtests.jl:12

I made a small package called MyGradientFix.jl that overloads the inner function in GrasmannMPS, hence this stacktrace. The line in question inside OptimKit that throws the error message is

df₀ = inner(x₀, g₀, η₀)
    if df₀ >= zero(df₀)
        error("linesearch was not given a descent direction!")
    end

I do not understand OptimKit well enough to know why this check is required and why it fails.

@maartenvd
Copy link
Collaborator

optimkit needs to be given a gradient and a descent direction (in gradient descent you would make the descent direction be - gradient). A descent direction has to satsify that inner(x,gradient,direction) is smaller than zero, which is what optimkit tests. Honestly I wouldn't mind if optimkit turns it into a warning ,and just flips the sign.

Gradientgrassman does something wrong in the case that C is numerically degenerate. A real fix would probably entail going through the derivation again, and making sure that everything is defined when C is no longer invertible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants