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

Correct adjoint for truncated SVD #15

Merged
merged 29 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c390bec
Add truncated SVD adjoint with wrapper for KrylovKit iterative SVD, a…
pbrehmer Mar 4, 2024
51507ce
Use KrylovKit.linsolve for truncation linear problem, make loss funct…
pbrehmer Mar 5, 2024
d3a31fb
Improve loss function, compare SVD gradient with TensorKit.tsvd gradient
pbrehmer Mar 5, 2024
8ac307e
Update SVD adjoint linear problem to use Tuple and remove reshapes
pbrehmer Mar 26, 2024
80db1c0
Fix ZeroTangent case for linear problem
pbrehmer Apr 11, 2024
ae96298
Add SVD wrapper structs and function, utilize tsvd machinery, convert…
pbrehmer Jun 20, 2024
78ab152
Copy ctmrg.jl from master, add svdalg field to CTMRG, use svdwrap in …
pbrehmer Jun 20, 2024
dc6ad2b
Merge branch 'master' into svd_adjoint
lkdvos Jun 28, 2024
fc6600e
Use KrylovKit implementation of eigsolve instead of eigsolve.jl, dele…
pbrehmer Jul 4, 2024
823f52e
Add IterSVD _tsvd! method and adjoint using KrylovKit.svdsolve adjoint
pbrehmer Jul 5, 2024
a615b4a
Add PEPSKit.tsvd wrapper, fix IterSVD adjoint
pbrehmer Jul 5, 2024
a815e41
Add TensorKit compat entry for softened tsvd type restrictions
pbrehmer Jul 5, 2024
447bfd8
Add ProjectorAlg and refactor all tests and examples
pbrehmer Jul 5, 2024
bbd132d
Update MPSKit compat
lkdvos Jul 5, 2024
0c03cd4
Replace tsvd with tsvd!, add views to IterSVD adjoint
pbrehmer Jul 8, 2024
14f0065
Improve IterSVD allocation, implement CTMRG convenience constructor, …
pbrehmer Jul 8, 2024
9b2c4b7
Fix tests
pbrehmer Jul 8, 2024
0c13d47
Add block-wise dense fallback option
pbrehmer Jul 8, 2024
538652d
Add SVDrrule wrapper, add separate adjoint structs and rrules, update…
pbrehmer Jul 8, 2024
7032ed0
Add IterSVD test for symmetric tensor with fallback
pbrehmer Jul 9, 2024
66a827e
Merge branch 'master' into svd_adjoint
pbrehmer Jul 9, 2024
d09561f
Formatting
pbrehmer Jul 9, 2024
b3a0726
Fix missing cnext in ctmrg, update README example
pbrehmer Jul 9, 2024
89ae0a4
Rename DenseSVDAdjoint, update svd_wrapper test
pbrehmer Jul 9, 2024
25d198c
Make CRCExt extension backwards compatible with v1.8
pbrehmer Jul 9, 2024
6b818e7
Replace SVDrrule with SVDAdjoint, clean up adjoint algorithms
pbrehmer Jul 9, 2024
bb96664
Small cleanup
lkdvos Jul 9, 2024
fa7a56a
Update minimal julia version 1.9
lkdvos Jul 10, 2024
6df8efc
Remove duplicate line in left_move
pbrehmer Jul 10, 2024
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
8 changes: 4 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
Accessors = "0.1"
ChainRulesCore = "1.0"
Compat = "3.46, 4.2"
KrylovKit = "0.6, 0.7, 0.8"
KrylovKit = "0.8"
LinearAlgebra = "1"
MPSKit = "0.10"
MPSKit = "0.11"
OptimKit = "0.3"
Printf = "1"
Statistics = "1"
TensorKit = "0.12"
TensorKit = "0.12.5"
VectorInterface = "0.4"
Zygote = "0.6"
julia = "1.6"
julia = "1.8"

[extras]
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
Expand Down
8 changes: 2 additions & 6 deletions examples/boundary_mps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ mps, envs, ϵ = leading_boundary(mps, T, VUMPS())
N = abs(prod(expectation_value(mps, T)))

# This can be compared to the result obtained using the CTMRG algorithm
ctm = leading_boundary(
peps, CTMRG(; verbosity=1, fixedspace=true), CTMRGEnv(peps; Venv=ComplexSpace(20))
)
ctm = leading_boundary(peps, CTMRG(; verbosity=1), CTMRGEnv(peps; Venv=ComplexSpace(20)))
N´ = abs(norm(peps, ctm))

@show abs(N - N´) / N
Expand All @@ -55,9 +53,7 @@ mps2 = PEPSKit.initializeMPS(T2, fill(ComplexSpace(20), 2, 2))
mps2, envs2, ϵ = leading_boundary(mps2, T2, VUMPS())
N2 = abs(prod(expectation_value(mps2, T2)))

ctm2 = leading_boundary(
peps2, CTMRG(; verbosity=1, fixedspace=true), CTMRGEnv(peps2; Venv=ComplexSpace(20))
)
ctm2 = leading_boundary(peps2, CTMRG(; verbosity=1), CTMRGEnv(peps2; Venv=ComplexSpace(20)))
N2´ = abs(norm(peps2, ctm2))

@show abs(N2 - N2´) / N2
Expand Down
10 changes: 5 additions & 5 deletions examples/heisenberg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ H = square_lattice_heisenberg(; Jx=-1, Jy=1, Jz=-1)
# Parameters
χbond = 2
χenv = 20
ctmalg = CTMRG(; trscheme=truncdim(χenv), tol=1e-10, miniter=4, maxiter=100, verbosity=1)
alg = PEPSOptimize(;
boundary_alg=ctmalg,
ctm_alg = CTMRG(; tol=1e-10, miniter=4, maxiter=100, verbosity=1, trscheme=truncdim(χenv))
opt_alg = PEPSOptimize(;
boundary_alg=ctm_alg,
optimizer=LBFGS(4; maxiter=100, gradtol=1e-4, verbosity=2),
gradient_alg=GMRES(; tol=1e-6, maxiter=100),
reuse_env=true,
Expand All @@ -27,6 +27,6 @@ alg = PEPSOptimize(;
# E/N = −0.6694421, which is a QMC estimate from https://arxiv.org/abs/1101.3281.
# Of course there is a noticable bias for small χbond and χenv.
ψ₀ = InfinitePEPS(2, χbond)
env₀ = leading_boundary(CTMRGEnv(ψ₀; Venv=ℂ^χenv), ψ₀, ctmalg)
result = fixedpoint(ψ₀, H, alg, env₀)
env₀ = leading_boundary(CTMRGEnv(ψ₀; Venv=ℂ^χenv), ψ₀, ctm_alg)
result = fixedpoint(ψ₀, H, opt_alg, env₀)
@show result.E
6 changes: 4 additions & 2 deletions src/PEPSKit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ using TensorKit, KrylovKit, MPSKit, OptimKit
using ChainRulesCore, Zygote

include("utility/util.jl")
include("utility/eigsolve.jl")
include("utility/svd.jl")
include("utility/rotations.jl")
include("utility/hook_pullback.jl")

Expand Down Expand Up @@ -58,12 +58,14 @@ module Defaults
const fpgrad_tol = 1e-6
end

export CTMRG, CTMRGEnv
export FullSVD, IterSVD, OldSVD
export FixedSpaceTruncation, ProjectorAlg, CTMRG, CTMRGEnv
export NLocalOperator, AnisotropicNNOperator, OnSite, NearestNeighbor
export expectation_value, costfun
export leading_boundary
export PEPSOptimize, GeomSum, ManualIter, LinSolve
export fixedpoint

export InfinitePEPS, InfiniteTransferPEPS
export InfinitePEPO, InfiniteTransferPEPO
export initializeMPS, initializePEPS
Expand Down
83 changes: 59 additions & 24 deletions src/algorithms/ctmrg.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,60 @@
"""
FixedSpaceTruncation <: TensorKit.TruncationScheme

CTMRG specific truncation scheme for `tsvd` which keeps the bond space on which the SVD
is performed fixed. Since different environment directions and unit cell entries might
have different spaces, this truncation style is different from `TruncationSpace`.
"""
struct FixedSpaceTruncation <: TensorKit.TruncationScheme end

# TODO: add option for different projector styles (half-infinite, full-infinite, etc.)
"""
struct ProjectorAlg{S}(; svd_alg = TensorKit.SVD(), trscheme = TensorKit.notrunc(),
fixedspace = false, verbosity = 0)

Algorithm struct collecting all projector related parameters. The truncation scheme has to be
a `TensorKit.TruncationScheme`, and some SVD algorithms might have further restrictions on what
kind of truncation scheme can be used. If `fixedspace` is true, the truncation scheme is set to
`truncspace(V)` where `V` is the environment bond space, adjusted to the corresponding
environment direction/unit cell entry.
"""
@kwdef struct ProjectorAlg{S,T}
svd_alg::S = TensorKit.SVD()
trscheme::T = FixedSpaceTruncation()
verbosity::Int = 0
end

# TODO: add abstract Algorithm type?
"""
struct CTMRG(; trscheme = TensorKit.notrunc(), tol = Defaults.ctmrg_tol,
maxiter = Defaults.ctmrg_maxiter, miniter = Defaults.ctmrg_miniter,
verbosity = 0, fixedspace = false)
CTMRG(; tol=Defaults.ctmrg_tol, maxiter=Defaults.ctmrg_maxiter,
miniter=Defaults.ctmrg_miniter, verbosity=0,
svd_alg=TensorKit.SVD(), trscheme=FixedSpaceTruncation())

Algorithm struct that represents the CTMRG algorithm for contracting infinite PEPS.
The projector bond dimensions are set via `trscheme` which controls the truncation
properties inside of `TensorKit.tsvd`. Each CTMRG run is converged up to `tol`
where the singular value convergence of the corners as well as the norm is checked.
The maximal and minimal number of CTMRG iterations is set with `maxiter` and `miniter`.
Different levels of output information are printed depending on `verbosity` (0, 1 or 2).
Regardless of the truncation scheme, the space can be kept fixed with `fixedspace`.
Each CTMRG run is converged up to `tol` where the singular value convergence of the
corners as well as the norm is checked. The maximal and minimal number of CTMRG iterations
is set with `maxiter` and `miniter`. Different levels of output information are printed
depending on `verbosity` (0, 1 or 2). The projectors are computed from `svd_alg` SVDs
where the truncation scheme is set via `trscheme`.
"""
@kwdef struct CTMRG
trscheme::TruncationScheme = TensorKit.notrunc()
tol::Float64 = Defaults.ctmrg_tol
maxiter::Int = Defaults.ctmrg_maxiter
miniter::Int = Defaults.ctmrg_miniter
verbosity::Int = 0
fixedspace::Bool = false
struct CTMRG
tol::Float64
maxiter::Int
miniter::Int
verbosity::Int
projector_alg::ProjectorAlg
end
function CTMRG(;
tol=Defaults.ctmrg_tol,
maxiter=Defaults.ctmrg_maxiter,
miniter=Defaults.ctmrg_miniter,
verbosity=0,
svd_alg=TensorKit.SVD(),
trscheme=FixedSpaceTruncation(),
)
return CTMRG(
tol, maxiter, miniter, verbosity, ProjectorAlg(; svd_alg, trscheme, verbosity)
)
end

"""
Expand All @@ -39,6 +75,7 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRG)

for i in 1:(alg.maxiter)
env, ϵ = ctmrg_iter(state, env, alg) # Grow and renormalize in all 4 directions

conv_condition, normold, CSold, TSold, ϵ = ignore_derivatives() do
# Compute convergence criteria and take max (TODO: How should we handle logging all of this?)
Δϵ = abs((ϵold - ϵ) / ϵold)
Expand Down Expand Up @@ -86,9 +123,7 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRG)
end

# Do one final iteration that does not change the spaces
alg_fixed = CTMRG(;
alg.trscheme, alg.tol, alg.maxiter, alg.miniter, alg.verbosity, fixedspace=true
)
alg_fixed = @set alg.projector_alg.trscheme = FixedSpaceTruncation()
env′, = ctmrg_iter(state, env, alg_fixed)
envfix = gauge_fix(env, env′)
check_elementwise_convergence(env, envfix; atol=alg.tol^(1 / 2)) ||
Expand Down Expand Up @@ -146,8 +181,8 @@ function gauge_fix(envprev::CTMRGEnv{C,T}, envfinal::CTMRGEnv{C,T}) where {C,T}

# Decompose and multiply
Up, _, Vp = tsvd!(ρ_prev)
Uf, _, Vf = tsvd!(ρ_final)
Qprev = Up * Vp
Uf, _, Vf = tsvd!(ρ_final)
Qfinal = Uf * Vf
σ = Qprev * Qfinal'

Expand Down Expand Up @@ -283,7 +318,7 @@ function ctmrg_iter(state, env::CTMRGEnv{C,T}, alg::CTMRG) where {C,T}
ϵ = 0.0

for _ in 1:4
env, _, _, ϵ₀ = left_move(state, env, alg)
env, _, _, ϵ₀ = left_move(state, env, alg.projector_alg)
state = rotate_north(state, EAST)
env = rotate_north(env, EAST)
ϵ = max(ϵ, ϵ₀)
Expand All @@ -298,7 +333,7 @@ end
Grow, project and renormalize the environment `env` in west direction.
Return the updated environment as well as the projectors and truncation error.
"""
function left_move(state, env::CTMRGEnv{C,T}, alg::CTMRG) where {C,T}
function left_move(state, env::CTMRGEnv{C,T}, alg::ProjectorAlg) where {C,T}
corners::typeof(env.corners) = copy(env.corners)
edges::typeof(env.edges) = copy(env.edges)
ϵ = 0.0
Expand Down Expand Up @@ -328,13 +363,13 @@ function left_move(state, env::CTMRGEnv{C,T}, alg::CTMRG) where {C,T}
)

# SVD half-infinite environment
trscheme = if alg.fixedspace == true
trscheme = if alg.trscheme isa FixedSpaceTruncation
truncspace(space(env.edges[WEST, row, cnext], 1))
else
alg.trscheme
end
@tensor QQ[-1 -2 -3; -4 -5 -6] := Q_sw[-1 -2 -3; 1 2 3] * Q_nw[1 2 3; -4 -5 -6]
U, S, V, ϵ_local = tsvd!(QQ; trunc=trscheme, alg=TensorKit.SVD())
U, S, V, ϵ_local = PEPSKit.tsvd!(QQ, alg.svd_alg; trunc=trscheme)
ϵ = max(ϵ, ϵ_local / norm(S))
# TODO: check if we can just normalize enlarged corners s.t. trunc behaves a bit better

Expand Down
Loading
Loading