diff --git a/Project.toml b/Project.toml index 2dec89104..b345da7af 100644 --- a/Project.toml +++ b/Project.toml @@ -38,7 +38,7 @@ LinearAlgebra = "1" LoggingExtras = "1" MPSKit = "0.13.9" MPSKitModels = "0.4" -MatrixAlgebraKit = "0.6" +MatrixAlgebraKit = "0.6.5" OhMyThreads = "0.7, 0.8" OptimKit = "0.4" Printf = "1" diff --git a/docs/make.jl b/docs/make.jl index 965b10442..636330ec3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -26,6 +26,7 @@ links = InterLinks( "MPSKitModels" => "https://quantumkithub.github.io/MPSKitModels.jl/dev/", # "Zygote" => "https://fluxml.ai/Zygote.jl/stable/", "ChainRulesCore" => "https://juliadiff.org/ChainRulesCore.jl/stable/", + "MatrixAlgebraKit" => "https://quantumkithub.github.io/MatrixAlgebraKit.jl/stable/", ) # explicitly set math engine diff --git a/docs/src/examples/3d_ising_partition_function/index.md b/docs/src/examples/3d_ising_partition_function/index.md index 21f6f5a20..cec367329 100644 --- a/docs/src/examples/3d_ising_partition_function/index.md +++ b/docs/src/examples/3d_ising_partition_function/index.md @@ -163,7 +163,8 @@ of this cost function. ````julia boundary_alg = SimultaneousCTMRG(; maxiter = 150, tol = 1.0e-8, verbosity = 1) rrule_alg = EigSolver(; - solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true), iterscheme = :diffgauge + solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true), + iterscheme = :fixed, ) T = InfinitePEPO(O) @@ -293,83 +294,83 @@ optimizer_alg = LBFGS(32; maxiter = 100, gradtol = 1.0e-5, verbosity = 3) ```` [ Info: LBFGS: initializing with f = -5.540733951820e-01, ‖∇f‖ = 7.7844e-01 -┌ Warning: CTMRG cancel 150: obj = +1.702942228759e+01 +1.443123137050e-07im err = 2.4386740933e-05 time = 1.04 sec -└ @ PEPSKit ~/repos/PEPSKit.jl/src/algorithms/ctmrg/ctmrg.jl:153 -[ Info: LBFGS: iter 1, Δt 4.96 s: f = -7.770809303692e-01, ‖∇f‖ = 3.1305e-02, α = 7.10e+02, m = 0, nfg = 7 -[ Info: LBFGS: iter 2, Δt 568.8 ms: f = -7.841115159615e-01, ‖∇f‖ = 2.0103e-02, α = 1.00e+00, m = 1, nfg = 1 -[ Info: LBFGS: iter 3, Δt 175.6 ms: f = -7.927057334845e-01, ‖∇f‖ = 2.3327e-02, α = 1.00e+00, m = 2, nfg = 1 -[ Info: LBFGS: iter 4, Δt 135.5 ms: f = -7.962897324757e-01, ‖∇f‖ = 2.2475e-02, α = 1.00e+00, m = 3, nfg = 1 -[ Info: LBFGS: iter 5, Δt 131.8 ms: f = -7.996749023744e-01, ‖∇f‖ = 7.0288e-03, α = 1.00e+00, m = 4, nfg = 1 -[ Info: LBFGS: iter 6, Δt 159.1 ms: f = -8.000821001207e-01, ‖∇f‖ = 1.2717e-03, α = 1.00e+00, m = 5, nfg = 1 -[ Info: LBFGS: iter 7, Δt 196.0 ms: f = -8.001106031252e-01, ‖∇f‖ = 1.3384e-03, α = 1.00e+00, m = 6, nfg = 1 -[ Info: LBFGS: iter 8, Δt 215.9 ms: f = -8.002622019964e-01, ‖∇f‖ = 2.4945e-03, α = 1.00e+00, m = 7, nfg = 1 -[ Info: LBFGS: iter 9, Δt 243.9 ms: f = -8.004505054484e-01, ‖∇f‖ = 2.9259e-03, α = 1.00e+00, m = 8, nfg = 1 -[ Info: LBFGS: iter 10, Δt 127.7 ms: f = -8.007649170868e-01, ‖∇f‖ = 1.7221e-03, α = 1.00e+00, m = 9, nfg = 1 -[ Info: LBFGS: iter 11, Δt 136.6 ms: f = -8.008760488382e-01, ‖∇f‖ = 2.2475e-03, α = 1.00e+00, m = 10, nfg = 1 -[ Info: LBFGS: iter 12, Δt 126.0 ms: f = -8.011008674672e-01, ‖∇f‖ = 1.5561e-03, α = 1.00e+00, m = 11, nfg = 1 -[ Info: LBFGS: iter 13, Δt 161.5 ms: f = -8.013170488565e-01, ‖∇f‖ = 1.1561e-03, α = 1.00e+00, m = 12, nfg = 1 -[ Info: LBFGS: iter 14, Δt 173.9 ms: f = -8.013730505450e-01, ‖∇f‖ = 7.1300e-04, α = 1.00e+00, m = 13, nfg = 1 -[ Info: LBFGS: iter 15, Δt 169.2 ms: f = -8.013886152636e-01, ‖∇f‖ = 2.8462e-04, α = 1.00e+00, m = 14, nfg = 1 -[ Info: LBFGS: iter 16, Δt 179.4 ms: f = -8.013946333330e-01, ‖∇f‖ = 2.7607e-04, α = 1.00e+00, m = 15, nfg = 1 -[ Info: LBFGS: iter 17, Δt 356.0 ms: f = -8.014080615636e-01, ‖∇f‖ = 3.6096e-04, α = 1.00e+00, m = 16, nfg = 1 -[ Info: LBFGS: iter 18, Δt 134.3 ms: f = -8.015095421688e-01, ‖∇f‖ = 1.9822e-03, α = 1.00e+00, m = 17, nfg = 1 -[ Info: LBFGS: iter 19, Δt 145.7 ms: f = -8.015784052508e-01, ‖∇f‖ = 1.8040e-03, α = 1.00e+00, m = 18, nfg = 1 -[ Info: LBFGS: iter 20, Δt 501.1 ms: f = -8.016945244238e-01, ‖∇f‖ = 2.9356e-03, α = 5.48e-01, m = 19, nfg = 3 -[ Info: LBFGS: iter 21, Δt 361.1 ms: f = -8.017619206832e-01, ‖∇f‖ = 1.1993e-03, α = 3.82e-01, m = 20, nfg = 2 -[ Info: LBFGS: iter 22, Δt 348.7 ms: f = -8.017977854941e-01, ‖∇f‖ = 6.0337e-04, α = 1.00e+00, m = 21, nfg = 1 -[ Info: LBFGS: iter 23, Δt 291.0 ms: f = -8.018087478343e-01, ‖∇f‖ = 3.7053e-04, α = 5.24e-01, m = 22, nfg = 2 -[ Info: LBFGS: iter 24, Δt 161.3 ms: f = -8.018127291733e-01, ‖∇f‖ = 3.0781e-04, α = 1.00e+00, m = 23, nfg = 1 -[ Info: LBFGS: iter 25, Δt 171.3 ms: f = -8.018164452111e-01, ‖∇f‖ = 2.9994e-04, α = 1.00e+00, m = 24, nfg = 1 -[ Info: LBFGS: iter 26, Δt 186.0 ms: f = -8.018247131297e-01, ‖∇f‖ = 3.6496e-04, α = 1.00e+00, m = 25, nfg = 1 -[ Info: LBFGS: iter 27, Δt 197.4 ms: f = -8.018396738228e-01, ‖∇f‖ = 5.4222e-04, α = 1.00e+00, m = 26, nfg = 1 -[ Info: LBFGS: iter 28, Δt 369.0 ms: f = -8.018574789038e-01, ‖∇f‖ = 2.7917e-04, α = 1.00e+00, m = 27, nfg = 1 -[ Info: LBFGS: iter 29, Δt 183.7 ms: f = -8.018645552239e-01, ‖∇f‖ = 1.2319e-04, α = 1.00e+00, m = 28, nfg = 1 -[ Info: LBFGS: iter 30, Δt 165.3 ms: f = -8.018655987357e-01, ‖∇f‖ = 8.6048e-05, α = 1.00e+00, m = 29, nfg = 1 -[ Info: LBFGS: iter 31, Δt 173.6 ms: f = -8.018675717547e-01, ‖∇f‖ = 8.8636e-05, α = 1.00e+00, m = 30, nfg = 1 -[ Info: LBFGS: iter 32, Δt 173.9 ms: f = -8.018703935281e-01, ‖∇f‖ = 2.6554e-04, α = 1.00e+00, m = 31, nfg = 1 -[ Info: LBFGS: iter 33, Δt 177.8 ms: f = -8.018747970386e-01, ‖∇f‖ = 2.7841e-04, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 34, Δt 193.3 ms: f = -8.018775666443e-01, ‖∇f‖ = 1.8523e-04, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 35, Δt 184.9 ms: f = -8.018785062445e-01, ‖∇f‖ = 2.0638e-04, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 36, Δt 389.4 ms: f = -8.018789950966e-01, ‖∇f‖ = 5.6081e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 37, Δt 176.7 ms: f = -8.018791535731e-01, ‖∇f‖ = 6.2356e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 38, Δt 143.4 ms: f = -8.018793550753e-01, ‖∇f‖ = 6.0528e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 39, Δt 160.6 ms: f = -8.018801150998e-01, ‖∇f‖ = 6.2768e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 40, Δt 191.0 ms: f = -8.018814750648e-01, ‖∇f‖ = 6.2301e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 41, Δt 218.0 ms: f = -8.018822724254e-01, ‖∇f‖ = 9.5267e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 42, Δt 210.1 ms: f = -8.018826000327e-01, ‖∇f‖ = 5.1283e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 43, Δt 398.2 ms: f = -8.018827118752e-01, ‖∇f‖ = 2.6091e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 44, Δt 190.0 ms: f = -8.018828058280e-01, ‖∇f‖ = 2.9316e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 45, Δt 164.0 ms: f = -8.018830270596e-01, ‖∇f‖ = 2.7982e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 46, Δt 176.0 ms: f = -8.018834021781e-01, ‖∇f‖ = 3.8102e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 47, Δt 200.2 ms: f = -8.018837183208e-01, ‖∇f‖ = 5.3658e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 48, Δt 196.9 ms: f = -8.018839628864e-01, ‖∇f‖ = 2.8728e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 49, Δt 384.9 ms: f = -8.018841580849e-01, ‖∇f‖ = 3.0680e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 50, Δt 188.4 ms: f = -8.018843859401e-01, ‖∇f‖ = 4.1973e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 51, Δt 198.0 ms: f = -8.018848104588e-01, ‖∇f‖ = 6.8881e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 52, Δt 176.0 ms: f = -8.018850110140e-01, ‖∇f‖ = 3.8651e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 53, Δt 192.5 ms: f = -8.018851266254e-01, ‖∇f‖ = 1.9013e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 54, Δt 207.5 ms: f = -8.018851864896e-01, ‖∇f‖ = 3.2919e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 55, Δt 217.6 ms: f = -8.018853097129e-01, ‖∇f‖ = 4.8521e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 56, Δt 439.8 ms: f = -8.018854916307e-01, ‖∇f‖ = 1.1478e-04, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 57, Δt 237.1 ms: f = -8.018859128567e-01, ‖∇f‖ = 7.7221e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 58, Δt 192.7 ms: f = -8.018864519794e-01, ‖∇f‖ = 6.5316e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 59, Δt 212.9 ms: f = -8.018866398048e-01, ‖∇f‖ = 5.1566e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 60, Δt 435.6 ms: f = -8.018866993724e-01, ‖∇f‖ = 4.5541e-05, α = 3.68e-01, m = 32, nfg = 2 -[ Info: LBFGS: iter 61, Δt 415.0 ms: f = -8.018867239928e-01, ‖∇f‖ = 2.1992e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 62, Δt 188.7 ms: f = -8.018867352019e-01, ‖∇f‖ = 1.8064e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 63, Δt 173.1 ms: f = -8.018867713955e-01, ‖∇f‖ = 3.8651e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 64, Δt 181.4 ms: f = -8.018868019525e-01, ‖∇f‖ = 4.2630e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 65, Δt 192.6 ms: f = -8.018868378564e-01, ‖∇f‖ = 3.9318e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 66, Δt 209.6 ms: f = -8.018869167860e-01, ‖∇f‖ = 3.8747e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 67, Δt 201.4 ms: f = -8.018870300585e-01, ‖∇f‖ = 3.7138e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 68, Δt 416.7 ms: f = -8.018871411994e-01, ‖∇f‖ = 5.7019e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 69, Δt 417.3 ms: f = -8.018871992080e-01, ‖∇f‖ = 3.0699e-05, α = 5.24e-01, m = 32, nfg = 2 -[ Info: LBFGS: iter 70, Δt 196.3 ms: f = -8.018872466141e-01, ‖∇f‖ = 1.3886e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 71, Δt 216.8 ms: f = -8.018872637171e-01, ‖∇f‖ = 1.5769e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 72, Δt 223.4 ms: f = -8.018873194654e-01, ‖∇f‖ = 2.1425e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 73, Δt 427.1 ms: f = -8.018874061425e-01, ‖∇f‖ = 1.9898e-05, α = 1.00e+00, m = 32, nfg = 1 -[ Info: LBFGS: iter 74, Δt 428.8 ms: f = -8.018874674598e-01, ‖∇f‖ = 1.9802e-05, α = 3.61e-01, m = 32, nfg = 2 -[ Info: LBFGS: converged after 75 iterations and time 11.46 m: f = -8.018875356693e-01, ‖∇f‖ = 9.9333e-06 +┌ Warning: CTMRG cancel 150: obj = +1.702942228759e+01 +1.443123029406e-07im err = 2.4386740984e-05 time = 5.88 sec +└ @ PEPSKit ~/git/PEPSKit.jl/src/algorithms/ctmrg/ctmrg.jl:162 +[ Info: LBFGS: iter 1, Δt 18.49 s: f = -7.770809303692e-01, ‖∇f‖ = 3.1305e-02, α = 7.10e+02, m = 0, nfg = 7 +[ Info: LBFGS: iter 2, Δt 1.48 s: f = -7.841115159615e-01, ‖∇f‖ = 2.0103e-02, α = 1.00e+00, m = 1, nfg = 1 +[ Info: LBFGS: iter 3, Δt 857.1 ms: f = -7.927057334845e-01, ‖∇f‖ = 2.3327e-02, α = 1.00e+00, m = 2, nfg = 1 +[ Info: LBFGS: iter 4, Δt 743.3 ms: f = -7.962897324757e-01, ‖∇f‖ = 2.2475e-02, α = 1.00e+00, m = 3, nfg = 1 +[ Info: LBFGS: iter 5, Δt 1.42 s: f = -7.996749023744e-01, ‖∇f‖ = 7.0288e-03, α = 1.00e+00, m = 4, nfg = 1 +[ Info: LBFGS: iter 6, Δt 695.0 ms: f = -8.000821001207e-01, ‖∇f‖ = 1.2717e-03, α = 1.00e+00, m = 5, nfg = 1 +[ Info: LBFGS: iter 7, Δt 655.4 ms: f = -8.001106031252e-01, ‖∇f‖ = 1.3384e-03, α = 1.00e+00, m = 6, nfg = 1 +[ Info: LBFGS: iter 8, Δt 551.8 ms: f = -8.002622019964e-01, ‖∇f‖ = 2.4945e-03, α = 1.00e+00, m = 7, nfg = 1 +[ Info: LBFGS: iter 9, Δt 560.7 ms: f = -8.004505054484e-01, ‖∇f‖ = 2.9259e-03, α = 1.00e+00, m = 8, nfg = 1 +[ Info: LBFGS: iter 10, Δt 628.4 ms: f = -8.007649170868e-01, ‖∇f‖ = 1.7221e-03, α = 1.00e+00, m = 9, nfg = 1 +[ Info: LBFGS: iter 11, Δt 664.4 ms: f = -8.008760488382e-01, ‖∇f‖ = 2.2475e-03, α = 1.00e+00, m = 10, nfg = 1 +[ Info: LBFGS: iter 12, Δt 595.1 ms: f = -8.011008674672e-01, ‖∇f‖ = 1.5561e-03, α = 1.00e+00, m = 11, nfg = 1 +[ Info: LBFGS: iter 13, Δt 659.7 ms: f = -8.013170488565e-01, ‖∇f‖ = 1.1561e-03, α = 1.00e+00, m = 12, nfg = 1 +[ Info: LBFGS: iter 14, Δt 629.0 ms: f = -8.013730505450e-01, ‖∇f‖ = 7.1300e-04, α = 1.00e+00, m = 13, nfg = 1 +[ Info: LBFGS: iter 15, Δt 624.0 ms: f = -8.013886152636e-01, ‖∇f‖ = 2.8462e-04, α = 1.00e+00, m = 14, nfg = 1 +[ Info: LBFGS: iter 16, Δt 616.8 ms: f = -8.013946333330e-01, ‖∇f‖ = 2.7607e-04, α = 1.00e+00, m = 15, nfg = 1 +[ Info: LBFGS: iter 17, Δt 585.2 ms: f = -8.014080615636e-01, ‖∇f‖ = 3.6096e-04, α = 1.00e+00, m = 16, nfg = 1 +[ Info: LBFGS: iter 18, Δt 710.2 ms: f = -8.015095421688e-01, ‖∇f‖ = 1.9822e-03, α = 1.00e+00, m = 17, nfg = 1 +[ Info: LBFGS: iter 19, Δt 1.53 s: f = -8.015784052508e-01, ‖∇f‖ = 1.8040e-03, α = 1.00e+00, m = 18, nfg = 1 +[ Info: LBFGS: iter 20, Δt 2.53 s: f = -8.016945244238e-01, ‖∇f‖ = 2.9356e-03, α = 5.48e-01, m = 19, nfg = 3 +[ Info: LBFGS: iter 21, Δt 1.71 s: f = -8.017619206832e-01, ‖∇f‖ = 1.1993e-03, α = 3.82e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 22, Δt 800.7 ms: f = -8.017977854941e-01, ‖∇f‖ = 6.0337e-04, α = 1.00e+00, m = 21, nfg = 1 +[ Info: LBFGS: iter 23, Δt 1.64 s: f = -8.018087478343e-01, ‖∇f‖ = 3.7053e-04, α = 5.24e-01, m = 22, nfg = 2 +[ Info: LBFGS: iter 24, Δt 801.1 ms: f = -8.018127291733e-01, ‖∇f‖ = 3.0781e-04, α = 1.00e+00, m = 23, nfg = 1 +[ Info: LBFGS: iter 25, Δt 947.9 ms: f = -8.018164452111e-01, ‖∇f‖ = 2.9994e-04, α = 1.00e+00, m = 24, nfg = 1 +[ Info: LBFGS: iter 26, Δt 1.50 s: f = -8.018247131297e-01, ‖∇f‖ = 3.6496e-04, α = 1.00e+00, m = 25, nfg = 1 +[ Info: LBFGS: iter 27, Δt 912.3 ms: f = -8.018396738228e-01, ‖∇f‖ = 5.4222e-04, α = 1.00e+00, m = 26, nfg = 1 +[ Info: LBFGS: iter 28, Δt 788.8 ms: f = -8.018574789038e-01, ‖∇f‖ = 2.7917e-04, α = 1.00e+00, m = 27, nfg = 1 +[ Info: LBFGS: iter 29, Δt 888.8 ms: f = -8.018645552239e-01, ‖∇f‖ = 1.2319e-04, α = 1.00e+00, m = 28, nfg = 1 +[ Info: LBFGS: iter 30, Δt 858.3 ms: f = -8.018655987357e-01, ‖∇f‖ = 8.6048e-05, α = 1.00e+00, m = 29, nfg = 1 +[ Info: LBFGS: iter 31, Δt 863.2 ms: f = -8.018675717547e-01, ‖∇f‖ = 8.8636e-05, α = 1.00e+00, m = 30, nfg = 1 +[ Info: LBFGS: iter 32, Δt 889.2 ms: f = -8.018703935281e-01, ‖∇f‖ = 2.6554e-04, α = 1.00e+00, m = 31, nfg = 1 +[ Info: LBFGS: iter 33, Δt 929.2 ms: f = -8.018747970386e-01, ‖∇f‖ = 2.7841e-04, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 34, Δt 934.8 ms: f = -8.018775666443e-01, ‖∇f‖ = 1.8523e-04, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 35, Δt 883.7 ms: f = -8.018785062445e-01, ‖∇f‖ = 2.0638e-04, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 36, Δt 853.0 ms: f = -8.018789950966e-01, ‖∇f‖ = 5.6081e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 37, Δt 850.4 ms: f = -8.018791535731e-01, ‖∇f‖ = 6.2356e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 38, Δt 1.71 s: f = -8.018793550753e-01, ‖∇f‖ = 6.0528e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 39, Δt 944.9 ms: f = -8.018801150998e-01, ‖∇f‖ = 6.2768e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 40, Δt 875.9 ms: f = -8.018814750648e-01, ‖∇f‖ = 6.2301e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 41, Δt 948.2 ms: f = -8.018822724254e-01, ‖∇f‖ = 9.5267e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 42, Δt 886.1 ms: f = -8.018826000327e-01, ‖∇f‖ = 5.1283e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 43, Δt 878.1 ms: f = -8.018827118752e-01, ‖∇f‖ = 2.6091e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 44, Δt 897.8 ms: f = -8.018828058280e-01, ‖∇f‖ = 2.9316e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 45, Δt 856.3 ms: f = -8.018830270596e-01, ‖∇f‖ = 2.7982e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 46, Δt 847.5 ms: f = -8.018834021781e-01, ‖∇f‖ = 3.8102e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 47, Δt 912.3 ms: f = -8.018837183208e-01, ‖∇f‖ = 5.3658e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 48, Δt 1.88 s: f = -8.018839628864e-01, ‖∇f‖ = 2.8728e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 49, Δt 1.05 s: f = -8.018841580849e-01, ‖∇f‖ = 3.0680e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 50, Δt 933.0 ms: f = -8.018843859400e-01, ‖∇f‖ = 4.1973e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 51, Δt 950.3 ms: f = -8.018848104588e-01, ‖∇f‖ = 6.8881e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 52, Δt 907.2 ms: f = -8.018850110140e-01, ‖∇f‖ = 3.8651e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 53, Δt 909.8 ms: f = -8.018851266254e-01, ‖∇f‖ = 1.9013e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 54, Δt 911.4 ms: f = -8.018851864896e-01, ‖∇f‖ = 3.2919e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 55, Δt 951.9 ms: f = -8.018853097129e-01, ‖∇f‖ = 4.8521e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 56, Δt 991.0 ms: f = -8.018854916306e-01, ‖∇f‖ = 1.1478e-04, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 57, Δt 999.6 ms: f = -8.018859128567e-01, ‖∇f‖ = 7.7221e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 58, Δt 1.83 s: f = -8.018864519794e-01, ‖∇f‖ = 6.5316e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 59, Δt 1.11 s: f = -8.018866398050e-01, ‖∇f‖ = 5.1566e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 60, Δt 1.79 s: f = -8.018866993724e-01, ‖∇f‖ = 4.5541e-05, α = 3.68e-01, m = 32, nfg = 2 +[ Info: LBFGS: iter 61, Δt 938.5 ms: f = -8.018867239929e-01, ‖∇f‖ = 2.1992e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 62, Δt 833.4 ms: f = -8.018867352019e-01, ‖∇f‖ = 1.8064e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 63, Δt 903.7 ms: f = -8.018867713956e-01, ‖∇f‖ = 3.8651e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 64, Δt 859.6 ms: f = -8.018868019526e-01, ‖∇f‖ = 4.2630e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 65, Δt 860.1 ms: f = -8.018868378565e-01, ‖∇f‖ = 3.9318e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 66, Δt 861.3 ms: f = -8.018869167865e-01, ‖∇f‖ = 3.8747e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 67, Δt 912.3 ms: f = -8.018870300592e-01, ‖∇f‖ = 3.7138e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 68, Δt 944.6 ms: f = -8.018871411997e-01, ‖∇f‖ = 5.7019e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 69, Δt 3.06 s: f = -8.018871992087e-01, ‖∇f‖ = 3.0698e-05, α = 5.24e-01, m = 32, nfg = 2 +[ Info: LBFGS: iter 70, Δt 861.7 ms: f = -8.018872466144e-01, ‖∇f‖ = 1.3886e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 71, Δt 881.0 ms: f = -8.018872637174e-01, ‖∇f‖ = 1.5769e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 72, Δt 918.2 ms: f = -8.018873194656e-01, ‖∇f‖ = 2.1426e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 73, Δt 953.3 ms: f = -8.018874061424e-01, ‖∇f‖ = 1.9898e-05, α = 1.00e+00, m = 32, nfg = 1 +[ Info: LBFGS: iter 74, Δt 1.89 s: f = -8.018874674599e-01, ‖∇f‖ = 1.9802e-05, α = 3.61e-01, m = 32, nfg = 2 +[ Info: LBFGS: converged after 75 iterations and time 18.21 m: f = -8.018875356692e-01, ‖∇f‖ = 9.9332e-06 ```` @@ -384,7 +385,7 @@ the final value of the cost function we have just optimized. ```` ```` --0.8018875356693276 +-0.8018875356692025 ```` As another check, we can compute the magnetization per site and compare it to a [reference @@ -402,7 +403,7 @@ m_ref = 0.667162 ```` ```` -0.00011314613831048259 +0.00011314483261026798 ```` --- diff --git a/docs/src/examples/3d_ising_partition_function/main.ipynb b/docs/src/examples/3d_ising_partition_function/main.ipynb index b35edd5c0..edcc2b4f6 100644 --- a/docs/src/examples/3d_ising_partition_function/main.ipynb +++ b/docs/src/examples/3d_ising_partition_function/main.ipynb @@ -1,16 +1,17 @@ { "cells": [ { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Markdown #hide" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# The 3D classical Ising model\n", "\n", @@ -36,12 +37,13 @@ "spirit as the boundary MPS methods demonstrated in another example.\n", "\n", "Let's start by making the example deterministic and importing the required packages:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Random\n", "using LinearAlgebra\n", @@ -49,12 +51,11 @@ "using KrylovKit, OptimKit, Zygote\n", "\n", "Random.seed!(81812781144);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Defining the partition function\n", "\n", @@ -65,12 +66,13 @@ "constituent rank-6 `PEPSKit.PEPOTensor` `O` located at each site of the cubic\n", "lattice. To verify our example we will check the magnetization and energy, so we also define\n", "the corresponding rank-6 tensors `M` and `E` while we're at it." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "function three_dimensional_classical_ising(; beta, J = 1.0)\n", " K = beta * J\n", @@ -108,31 +110,30 @@ "\n", " return TensorMap(o, TMS), TensorMap(m, TMS), TensorMap(e, TMS)\n", "end;" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Let's initialize these tensors at inverse temperature $\\beta=0.2391$, which corresponds to\n", "a slightly lower temperature than the critical value $\\beta_c=0.2216544…$" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "beta = 0.2391\n", "O, M, E = three_dimensional_classical_ising(; beta)\n", "O isa PEPSKit.PEPOTensor" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Contracting the partition function\n", "\n", @@ -190,16 +191,18 @@ "contraction algorithm we can use to compute the values of these two networks. In addition,\n", "we'll specify the specific reverse rule algorithm that will be used to compute the gradient\n", "of this cost function." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "boundary_alg = SimultaneousCTMRG(; maxiter = 150, tol = 1.0e-8, verbosity = 1)\n", "rrule_alg = EigSolver(;\n", - " solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true), iterscheme = :diffgauge\n", + " solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true),\n", + " iterscheme = :fixed,\n", ")\n", "T = InfinitePEPO(O)\n", "\n", @@ -240,12 +243,11 @@ " g = only(gs)\n", " return E, g\n", "end;" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "There are a few things to note about this cost function definition. Since we will pass it to\n", "the `OptimKit.optimize`, we require it to return both our cost function and the\n", @@ -286,12 +288,13 @@ "them where the only difference is that we have to pass along an extra environment since our\n", "cost function requires two distinct contractions as opposed to the setting of Hamiltonian\n", "PEPS optimization which only requires a double-layer contraction." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "function pepo_retract((peps, env_double_layer, env_triple_layer), η, α)\n", " (peps´, env_double_layer´), ξ = PEPSKit.peps_retract((peps, env_double_layer), η, α)\n", @@ -309,24 +312,24 @@ " ξ, (peps, env_double_layer), η, α, (peps´, env_double_layer´)\n", " )\n", "end;" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Finding the fixed point\n", "\n", "All that is left then is to specify the virtual spaces of the PEPS and the two environments,\n", "initialize them in the appropriate way, choose an optimization algortithm and call the\n", "`optimize` function from OptimKit.jl to get our desired PEPS fixed point." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "Vpeps = ℂ^2\n", "Venv = ℂ^12\n", @@ -345,41 +348,41 @@ " retract = pepo_retract,\n", " (transport!) = (pepo_transport!),\n", ");" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Verifying the result\n", "\n", "Having found the fixed point, we have essentially contracted the entire partition function\n", "and we can start computing observables. The free energy per site for example is just given by\n", "the final value of the cost function we have just optimized." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "@show f" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "As another check, we can compute the magnetization per site and compare it to a [reference\n", "value obtaind through Monte-Carlo simulations](@cite hasenbusch_monte_2001)." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "n3_final = InfiniteSquareNetwork(psi_final, T)\n", "num = PEPSKit.contract_local_tensor((1, 1, 1), M, n3_final, env3_final)\n", @@ -389,33 +392,31 @@ "m_ref = 0.667162\n", "\n", "@show abs(m - m_ref)" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "---\n", "\n", "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" - ], - "metadata": {} + ] } ], - "nbformat_minor": 3, "metadata": { + "kernelspec": { + "display_name": "Julia 1.12.5", + "language": "julia", + "name": "julia-1.12" + }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.12.5" - }, - "kernelspec": { - "name": "julia-1.12", - "display_name": "Julia 1.12.5", - "language": "julia" } }, - "nbformat": 4 + "nbformat": 4, + "nbformat_minor": 3 } \ No newline at end of file diff --git a/docs/src/examples/fermi_hubbard/index.md b/docs/src/examples/fermi_hubbard/index.md index 8480950ed..71c284fe5 100644 --- a/docs/src/examples/fermi_hubbard/index.md +++ b/docs/src/examples/fermi_hubbard/index.md @@ -82,7 +82,7 @@ define all algorithmic parameters: ````julia boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, trunc = (; alg = :fixedspace)) -gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :diffgauge) +gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :fixed) optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, maxiter = 80, ls_maxiter = 3, ls_maxfg = 3) ```` @@ -101,8 +101,8 @@ env₀, = leading_boundary(CTMRGEnv(peps₀, V_env), peps₀; boundary_alg...); ```` ```` -[ Info: CTMRG init: obj = +5.484842275411e+04 +4.469243203539e+04im err = 1.0000e+00 -[ Info: CTMRG conv 26: obj = +8.371681846538e+04 -3.790073606069e-07im err = 7.4963854907e-09 time = 7.98 sec +[ Info: CTMRG init: obj = +5.484842275412e+04 +4.469243203539e+04im err = 1.0000e+00 +[ Info: CTMRG conv 26: obj = +8.371681846538e+04 -3.790119080804e-07im err = 7.4963849914e-09 time = 36.38 sec ```` @@ -120,91 +120,91 @@ peps, env, E, info = fixedpoint( ┌ Warning: Linesearch not converged after 1 iterations and 4 function evaluations: │ α = 2.50e+01, dϕ = -1.49e-01, ϕ - ϕ₀ = -2.88e+00 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/linesearches.jl:151 -[ Info: LBFGS: iter 1, Δt 44.79 s: f = 3.801336895996e+00, ‖∇f‖ = 2.3457e+01, α = 2.50e+01, m = 0, nfg = 4 +[ Info: LBFGS: iter 1, Δt 38.64 s: f = 3.801336895927e+00, ‖∇f‖ = 2.3457e+01, α = 2.50e+01, m = 0, nfg = 4 ┌ Warning: Linesearch not converged after 1 iterations and 4 function evaluations: │ α = 2.50e+01, dϕ = -5.73e-03, ϕ - ϕ₀ = -3.81e+00 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/linesearches.jl:151 -[ Info: LBFGS: iter 2, Δt 38.26 s: f = -9.717026892628e-03, ‖∇f‖ = 3.2049e+00, α = 2.50e+01, m = 0, nfg = 4 -[ Info: LBFGS: iter 3, Δt 9.11 s: f = -1.151937221231e-01, ‖∇f‖ = 2.7846e+00, α = 1.00e+00, m = 1, nfg = 1 -[ Info: LBFGS: iter 4, Δt 7.93 s: f = -6.164097148624e-01, ‖∇f‖ = 2.3680e+00, α = 1.00e+00, m = 2, nfg = 1 -[ Info: LBFGS: iter 5, Δt 7.97 s: f = -8.177983956552e-01, ‖∇f‖ = 1.9112e+00, α = 1.00e+00, m = 3, nfg = 1 -[ Info: LBFGS: iter 6, Δt 7.27 s: f = -9.902797531380e-01, ‖∇f‖ = 2.3790e+00, α = 1.00e+00, m = 4, nfg = 1 -[ Info: LBFGS: iter 7, Δt 6.91 s: f = -1.142781180434e+00, ‖∇f‖ = 1.5680e+00, α = 1.00e+00, m = 5, nfg = 1 -[ Info: LBFGS: iter 8, Δt 6.04 s: f = -1.238252367608e+00, ‖∇f‖ = 3.5020e+00, α = 1.00e+00, m = 6, nfg = 1 -[ Info: LBFGS: iter 9, Δt 6.35 s: f = -1.438152718476e+00, ‖∇f‖ = 1.3366e+00, α = 1.00e+00, m = 7, nfg = 1 -[ Info: LBFGS: iter 10, Δt 5.96 s: f = -1.523106534555e+00, ‖∇f‖ = 1.3495e+00, α = 1.00e+00, m = 8, nfg = 1 -[ Info: LBFGS: iter 11, Δt 13.16 s: f = -1.619309099210e+00, ‖∇f‖ = 1.1948e+00, α = 1.72e-01, m = 9, nfg = 2 -[ Info: LBFGS: iter 12, Δt 12.73 s: f = -1.681436569538e+00, ‖∇f‖ = 9.4842e-01, α = 2.37e-01, m = 10, nfg = 2 -[ Info: LBFGS: iter 13, Δt 6.23 s: f = -1.720664405828e+00, ‖∇f‖ = 1.4227e+00, α = 1.00e+00, m = 11, nfg = 1 -[ Info: LBFGS: iter 14, Δt 6.20 s: f = -1.770786332451e+00, ‖∇f‖ = 6.2727e-01, α = 1.00e+00, m = 12, nfg = 1 -[ Info: LBFGS: iter 15, Δt 6.49 s: f = -1.807472184382e+00, ‖∇f‖ = 5.1285e-01, α = 1.00e+00, m = 13, nfg = 1 -[ Info: LBFGS: iter 16, Δt 6.20 s: f = -1.859749157697e+00, ‖∇f‖ = 7.1361e-01, α = 1.00e+00, m = 14, nfg = 1 -[ Info: LBFGS: iter 17, Δt 6.22 s: f = -1.893132038649e+00, ‖∇f‖ = 6.7317e-01, α = 1.00e+00, m = 15, nfg = 1 -[ Info: LBFGS: iter 18, Δt 6.53 s: f = -1.923092864927e+00, ‖∇f‖ = 5.5354e-01, α = 1.00e+00, m = 16, nfg = 1 -[ Info: LBFGS: iter 19, Δt 6.17 s: f = -1.948135786436e+00, ‖∇f‖ = 4.7674e-01, α = 1.00e+00, m = 17, nfg = 1 -[ Info: LBFGS: iter 20, Δt 6.51 s: f = -1.969521622377e+00, ‖∇f‖ = 4.1602e-01, α = 1.00e+00, m = 18, nfg = 1 -[ Info: LBFGS: iter 21, Δt 6.24 s: f = -1.982569431031e+00, ‖∇f‖ = 4.5188e-01, α = 1.00e+00, m = 19, nfg = 1 -[ Info: LBFGS: iter 22, Δt 6.17 s: f = -1.994023093772e+00, ‖∇f‖ = 3.1544e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 23, Δt 6.62 s: f = -2.002841836933e+00, ‖∇f‖ = 3.0502e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 24, Δt 6.18 s: f = -2.014066310812e+00, ‖∇f‖ = 3.3498e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 25, Δt 6.29 s: f = -2.022003031089e+00, ‖∇f‖ = 4.3896e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 26, Δt 6.60 s: f = -2.030108712400e+00, ‖∇f‖ = 2.0527e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 27, Δt 6.22 s: f = -2.035064140788e+00, ‖∇f‖ = 1.6295e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 28, Δt 7.21 s: f = -2.038644453084e+00, ‖∇f‖ = 1.6908e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 29, Δt 6.63 s: f = -2.041287656776e+00, ‖∇f‖ = 2.4233e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 30, Δt 6.27 s: f = -2.044963003064e+00, ‖∇f‖ = 1.2134e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 31, Δt 6.26 s: f = -2.046709201566e+00, ‖∇f‖ = 9.5293e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 32, Δt 6.58 s: f = -2.048704698396e+00, ‖∇f‖ = 1.0554e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 33, Δt 6.27 s: f = -2.049753774431e+00, ‖∇f‖ = 1.7672e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 34, Δt 6.62 s: f = -2.051012655381e+00, ‖∇f‖ = 6.4429e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 35, Δt 6.24 s: f = -2.051487362644e+00, ‖∇f‖ = 4.8991e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 36, Δt 6.25 s: f = -2.051906992546e+00, ‖∇f‖ = 6.2050e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 37, Δt 6.57 s: f = -2.052351423104e+00, ‖∇f‖ = 9.2729e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 38, Δt 6.17 s: f = -2.052848307081e+00, ‖∇f‖ = 4.8571e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 39, Δt 6.58 s: f = -2.053135861431e+00, ‖∇f‖ = 3.5616e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 40, Δt 6.13 s: f = -2.053405790904e+00, ‖∇f‖ = 4.2303e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 41, Δt 6.30 s: f = -2.053600750553e+00, ‖∇f‖ = 5.7966e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 42, Δt 6.60 s: f = -2.053812274065e+00, ‖∇f‖ = 3.2230e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 43, Δt 6.26 s: f = -2.054009903020e+00, ‖∇f‖ = 3.1640e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 44, Δt 6.29 s: f = -2.054189826272e+00, ‖∇f‖ = 4.1575e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 45, Δt 6.60 s: f = -2.054332724188e+00, ‖∇f‖ = 6.9194e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 46, Δt 6.29 s: f = -2.054519394728e+00, ‖∇f‖ = 2.9113e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 47, Δt 6.30 s: f = -2.054613025514e+00, ‖∇f‖ = 2.5330e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 48, Δt 6.64 s: f = -2.054720907548e+00, ‖∇f‖ = 3.1755e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 49, Δt 6.31 s: f = -2.054879186805e+00, ‖∇f‖ = 3.4648e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 50, Δt 6.28 s: f = -2.054968291030e+00, ‖∇f‖ = 8.4868e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 51, Δt 6.59 s: f = -2.055240598515e+00, ‖∇f‖ = 3.1534e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 52, Δt 6.30 s: f = -2.055381144002e+00, ‖∇f‖ = 2.5669e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 53, Δt 6.68 s: f = -2.055572825440e+00, ‖∇f‖ = 3.8027e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 54, Δt 6.30 s: f = -2.055872604944e+00, ‖∇f‖ = 4.6489e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 55, Δt 6.28 s: f = -2.056396522667e+00, ‖∇f‖ = 8.8080e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 56, Δt 6.66 s: f = -2.056856239722e+00, ‖∇f‖ = 8.3565e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 57, Δt 6.31 s: f = -2.057479315508e+00, ‖∇f‖ = 4.4471e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 58, Δt 6.68 s: f = -2.057912243806e+00, ‖∇f‖ = 5.9337e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 59, Δt 6.32 s: f = -2.058287160865e+00, ‖∇f‖ = 6.0136e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 60, Δt 6.23 s: f = -2.058998799983e+00, ‖∇f‖ = 6.2226e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 61, Δt 12.83 s: f = -2.059475804662e+00, ‖∇f‖ = 1.0086e-01, α = 4.83e-01, m = 20, nfg = 2 -[ Info: LBFGS: iter 62, Δt 6.34 s: f = -2.060083017277e+00, ‖∇f‖ = 6.8345e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 63, Δt 6.76 s: f = -2.060482561109e+00, ‖∇f‖ = 7.3320e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 64, Δt 6.31 s: f = -2.060741769883e+00, ‖∇f‖ = 9.5623e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 65, Δt 6.41 s: f = -2.061312309048e+00, ‖∇f‖ = 7.1633e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 66, Δt 6.65 s: f = -2.061708108692e+00, ‖∇f‖ = 5.4922e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 67, Δt 6.30 s: f = -2.062077117667e+00, ‖∇f‖ = 5.4604e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 68, Δt 6.58 s: f = -2.062376818127e+00, ‖∇f‖ = 7.1800e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 69, Δt 12.31 s: f = -2.062695947352e+00, ‖∇f‖ = 9.6476e-02, α = 5.00e-01, m = 20, nfg = 2 -[ Info: LBFGS: iter 70, Δt 6.39 s: f = -2.063157063540e+00, ‖∇f‖ = 7.1450e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 71, Δt 6.15 s: f = -2.063918977538e+00, ‖∇f‖ = 9.1357e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 72, Δt 6.09 s: f = -2.064221211695e+00, ‖∇f‖ = 7.8535e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 73, Δt 6.42 s: f = -2.064680585193e+00, ‖∇f‖ = 7.3845e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 74, Δt 6.05 s: f = -2.065193848145e+00, ‖∇f‖ = 1.1291e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 75, Δt 6.38 s: f = -2.066080890415e+00, ‖∇f‖ = 9.7562e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 76, Δt 6.06 s: f = -2.067019814101e+00, ‖∇f‖ = 1.6919e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 77, Δt 7.04 s: f = -2.067204715883e+00, ‖∇f‖ = 1.6814e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 78, Δt 6.41 s: f = -2.068147829832e+00, ‖∇f‖ = 1.8170e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 79, Δt 13.08 s: f = -2.068989082597e+00, ‖∇f‖ = 2.0607e-01, α = 3.00e-01, m = 20, nfg = 2 -┌ Warning: LBFGS: not converged to requested tol after 80 iterations and time 19.47 m: f = -2.070356853340e+00, ‖∇f‖ = 2.9208e-01 +[ Info: LBFGS: iter 2, Δt 33.51 s: f = -9.717027903025e-03, ‖∇f‖ = 3.2049e+00, α = 2.50e+01, m = 0, nfg = 4 +[ Info: LBFGS: iter 3, Δt 6.56 s: f = -1.151937230814e-01, ‖∇f‖ = 2.7846e+00, α = 1.00e+00, m = 1, nfg = 1 +[ Info: LBFGS: iter 4, Δt 7.11 s: f = -6.164097151643e-01, ‖∇f‖ = 2.3680e+00, α = 1.00e+00, m = 2, nfg = 1 +[ Info: LBFGS: iter 5, Δt 5.99 s: f = -8.177983968326e-01, ‖∇f‖ = 1.9112e+00, α = 1.00e+00, m = 3, nfg = 1 +[ Info: LBFGS: iter 6, Δt 5.39 s: f = -9.902797555067e-01, ‖∇f‖ = 2.3790e+00, α = 1.00e+00, m = 4, nfg = 1 +[ Info: LBFGS: iter 7, Δt 6.47 s: f = -1.142781183014e+00, ‖∇f‖ = 1.5680e+00, α = 1.00e+00, m = 5, nfg = 1 +[ Info: LBFGS: iter 8, Δt 4.97 s: f = -1.238252399424e+00, ‖∇f‖ = 3.5020e+00, α = 1.00e+00, m = 6, nfg = 1 +[ Info: LBFGS: iter 9, Δt 5.92 s: f = -1.438152723955e+00, ‖∇f‖ = 1.3366e+00, α = 1.00e+00, m = 7, nfg = 1 +[ Info: LBFGS: iter 10, Δt 4.83 s: f = -1.523106553003e+00, ‖∇f‖ = 1.3495e+00, α = 1.00e+00, m = 8, nfg = 1 +[ Info: LBFGS: iter 11, Δt 11.09 s: f = -1.619309113033e+00, ‖∇f‖ = 1.1948e+00, α = 1.72e-01, m = 9, nfg = 2 +[ Info: LBFGS: iter 12, Δt 10.75 s: f = -1.681436580003e+00, ‖∇f‖ = 9.4842e-01, α = 2.37e-01, m = 10, nfg = 2 +[ Info: LBFGS: iter 13, Δt 4.81 s: f = -1.720664442091e+00, ‖∇f‖ = 1.4227e+00, α = 1.00e+00, m = 11, nfg = 1 +[ Info: LBFGS: iter 14, Δt 5.91 s: f = -1.770786352947e+00, ‖∇f‖ = 6.2727e-01, α = 1.00e+00, m = 12, nfg = 1 +[ Info: LBFGS: iter 15, Δt 4.69 s: f = -1.807472232437e+00, ‖∇f‖ = 5.1285e-01, α = 1.00e+00, m = 13, nfg = 1 +[ Info: LBFGS: iter 16, Δt 6.02 s: f = -1.859749167278e+00, ‖∇f‖ = 7.1361e-01, α = 1.00e+00, m = 14, nfg = 1 +[ Info: LBFGS: iter 17, Δt 4.65 s: f = -1.893132058603e+00, ‖∇f‖ = 6.7317e-01, α = 1.00e+00, m = 15, nfg = 1 +[ Info: LBFGS: iter 18, Δt 4.84 s: f = -1.923092871787e+00, ‖∇f‖ = 5.5354e-01, α = 1.00e+00, m = 16, nfg = 1 +[ Info: LBFGS: iter 19, Δt 5.89 s: f = -1.948135797818e+00, ‖∇f‖ = 4.7674e-01, α = 1.00e+00, m = 17, nfg = 1 +[ Info: LBFGS: iter 20, Δt 4.83 s: f = -1.969521620203e+00, ‖∇f‖ = 4.1602e-01, α = 1.00e+00, m = 18, nfg = 1 +[ Info: LBFGS: iter 21, Δt 6.12 s: f = -1.982569429583e+00, ‖∇f‖ = 4.5188e-01, α = 1.00e+00, m = 19, nfg = 1 +[ Info: LBFGS: iter 22, Δt 4.79 s: f = -1.994023088009e+00, ‖∇f‖ = 3.1544e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 23, Δt 6.09 s: f = -2.002841835268e+00, ‖∇f‖ = 3.0502e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 24, Δt 4.93 s: f = -2.014066311538e+00, ‖∇f‖ = 3.3498e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 25, Δt 5.04 s: f = -2.022003034919e+00, ‖∇f‖ = 4.3896e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 26, Δt 5.98 s: f = -2.030108714405e+00, ‖∇f‖ = 2.0527e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 27, Δt 4.94 s: f = -2.035064142878e+00, ‖∇f‖ = 1.6295e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 28, Δt 6.60 s: f = -2.038644459020e+00, ‖∇f‖ = 1.6908e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 29, Δt 4.92 s: f = -2.041287669506e+00, ‖∇f‖ = 2.4233e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 30, Δt 5.95 s: f = -2.044963015191e+00, ‖∇f‖ = 1.2134e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 31, Δt 4.83 s: f = -2.046709214218e+00, ‖∇f‖ = 9.5293e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 32, Δt 6.05 s: f = -2.048704711627e+00, ‖∇f‖ = 1.0554e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 33, Δt 4.78 s: f = -2.049753785745e+00, ‖∇f‖ = 1.7672e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 34, Δt 5.96 s: f = -2.051012657058e+00, ‖∇f‖ = 6.4429e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 35, Δt 4.80 s: f = -2.051487365494e+00, ‖∇f‖ = 4.8991e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 36, Δt 4.82 s: f = -2.051906995005e+00, ‖∇f‖ = 6.2050e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 37, Δt 6.04 s: f = -2.052351424092e+00, ‖∇f‖ = 9.2730e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 38, Δt 4.80 s: f = -2.052848308926e+00, ‖∇f‖ = 4.8571e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 39, Δt 5.93 s: f = -2.053135861688e+00, ‖∇f‖ = 3.5616e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 40, Δt 4.80 s: f = -2.053405790277e+00, ‖∇f‖ = 4.2303e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 41, Δt 4.88 s: f = -2.053600751472e+00, ‖∇f‖ = 5.7965e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 42, Δt 5.95 s: f = -2.053812276343e+00, ‖∇f‖ = 3.2230e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 43, Δt 4.68 s: f = -2.054009904322e+00, ‖∇f‖ = 3.1640e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 44, Δt 4.74 s: f = -2.054189829937e+00, ‖∇f‖ = 4.1575e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 45, Δt 5.93 s: f = -2.054332727237e+00, ‖∇f‖ = 6.9194e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 46, Δt 4.71 s: f = -2.054519396790e+00, ‖∇f‖ = 2.9113e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 47, Δt 5.92 s: f = -2.054613028290e+00, ‖∇f‖ = 2.5330e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 48, Δt 4.69 s: f = -2.054720909675e+00, ‖∇f‖ = 3.1755e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 49, Δt 5.72 s: f = -2.054879189481e+00, ‖∇f‖ = 3.4648e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 50, Δt 4.90 s: f = -2.054968277255e+00, ‖∇f‖ = 8.4871e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 51, Δt 4.71 s: f = -2.055240591253e+00, ‖∇f‖ = 3.1534e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 52, Δt 5.92 s: f = -2.055381130477e+00, ‖∇f‖ = 2.5669e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 53, Δt 4.75 s: f = -2.055572809496e+00, ‖∇f‖ = 3.8027e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 54, Δt 4.88 s: f = -2.055872578414e+00, ‖∇f‖ = 4.6489e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 55, Δt 6.02 s: f = -2.056396546910e+00, ‖∇f‖ = 8.8069e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 56, Δt 4.94 s: f = -2.056856099700e+00, ‖∇f‖ = 8.3587e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 57, Δt 6.07 s: f = -2.057479296853e+00, ‖∇f‖ = 4.4471e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 58, Δt 4.81 s: f = -2.057912211557e+00, ‖∇f‖ = 5.9322e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 59, Δt 6.08 s: f = -2.058287106374e+00, ‖∇f‖ = 6.0138e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 60, Δt 4.78 s: f = -2.058998688168e+00, ‖∇f‖ = 6.2214e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 61, Δt 10.81 s: f = -2.059475430386e+00, ‖∇f‖ = 1.0083e-01, α = 4.82e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 62, Δt 4.85 s: f = -2.060082712314e+00, ‖∇f‖ = 6.8338e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 63, Δt 6.18 s: f = -2.060482611701e+00, ‖∇f‖ = 7.3298e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 64, Δt 4.92 s: f = -2.060741140972e+00, ‖∇f‖ = 9.5443e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 65, Δt 4.88 s: f = -2.061312696274e+00, ‖∇f‖ = 7.1658e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 66, Δt 5.97 s: f = -2.061709741165e+00, ‖∇f‖ = 5.4940e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 67, Δt 4.87 s: f = -2.062078223556e+00, ‖∇f‖ = 5.4620e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 68, Δt 6.00 s: f = -2.062377140676e+00, ‖∇f‖ = 7.1416e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 69, Δt 10.93 s: f = -2.062698062544e+00, ‖∇f‖ = 9.6845e-02, α = 5.00e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 70, Δt 5.04 s: f = -2.063163727897e+00, ‖∇f‖ = 7.1580e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 71, Δt 6.13 s: f = -2.063925627174e+00, ‖∇f‖ = 9.0915e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 72, Δt 5.02 s: f = -2.064219513055e+00, ‖∇f‖ = 8.0698e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 73, Δt 4.91 s: f = -2.064673250535e+00, ‖∇f‖ = 7.5326e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 74, Δt 6.12 s: f = -2.065226882556e+00, ‖∇f‖ = 1.0638e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 75, Δt 4.85 s: f = -2.066059171824e+00, ‖∇f‖ = 9.5076e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 76, Δt 4.99 s: f = -2.067195111916e+00, ‖∇f‖ = 1.5006e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 77, Δt 5.94 s: f = -2.068289278812e+00, ‖∇f‖ = 2.3385e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 78, Δt 16.76 s: f = -2.068482519585e+00, ‖∇f‖ = 6.6865e-01, α = 1.56e-01, m = 20, nfg = 3 +[ Info: LBFGS: iter 79, Δt 12.04 s: f = -2.068666326649e+00, ‖∇f‖ = 3.3508e-01, α = 2.43e-01, m = 20, nfg = 2 +┌ Warning: LBFGS: not converged to requested tol after 80 iterations and time 21.90 m: f = -2.069886404460e+00, ‖∇f‖ = 2.6573e-01 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/lbfgs.jl:199 -E = -2.07035685333967 +E = -2.069886404460094 ```` @@ -219,7 +219,7 @@ E_ref = -2.09765625 ```` ```` -(E - E_ref) / E_ref = -0.013014237514049358 +(E - E_ref) / E_ref = -0.013238511095374089 ```` diff --git a/docs/src/examples/fermi_hubbard/main.ipynb b/docs/src/examples/fermi_hubbard/main.ipynb index c6d055d4f..260320382 100644 --- a/docs/src/examples/fermi_hubbard/main.ipynb +++ b/docs/src/examples/fermi_hubbard/main.ipynb @@ -1,16 +1,17 @@ { "cells": [ { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Markdown #hide" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# Fermi-Hubbard model with $f\\mathbb{Z}_2 \\boxtimes U(1)$ symmetry, at large $U$ and half-filling\n", "\n", @@ -28,44 +29,44 @@ "workflow remains the same.\n", "\n", "First though, we make the example deterministic by seeding the RNG, and we make our imports:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Random\n", "using TensorKit, PEPSKit\n", "using MPSKit: add_physical_charge\n", "Random.seed!(2928528937);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Defining the fermionic Hamiltonian\n", "\n", "Let us start by fixing the parameters of the Hubbard model. We're going to use a hopping of\n", "$t=1$ and a large $U=8$ on a $2 \\times 2$ unit cell:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "t = 1.0\n", "U = 8.0\n", "lattice = InfiniteSquare(2, 2);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "In order to create fermionic tensors, one needs to define symmetry sectors using TensorKit's\n", "`FermionParity`. Not only do we want use fermion parity but we also want our\n", @@ -73,33 +74,34 @@ "using the [Deligne product](https://jutho.github.io/TensorKit.jl/stable/lib/sectors/#TensorKitSectors.deligneproduct-Tuple{Sector,%20Sector}),\n", "called through `⊠` which is obtained by typing `\\boxtimes+TAB`. We will not impose any extra\n", "spin symmetry, so we have:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "fermion = fℤ₂\n", "particle_symmetry = U1Irrep\n", "spin_symmetry = Trivial\n", "S = fermion ⊠ particle_symmetry" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "The next step is defining graded virtual PEPS and environment spaces using `S`. Here we also\n", "use the symmetry sector to impose half-filling. That is all we need to define the Hubbard\n", "Hamiltonian:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "D, χ = 1, 1\n", "V_peps = Vect[S]((0, 0) => 2 * D, (1, 1) => D, (1, -1) => D)\n", @@ -109,113 +111,111 @@ "S_aux = S((1, 1))\n", "H₀ = hubbard_model(ComplexF64, particle_symmetry, spin_symmetry, lattice; t, U)\n", "H = add_physical_charge(H₀, fill(S_aux, size(H₀.lattice)...));" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Finding the ground state\n", "\n", "Again, the procedure of ground state optimization is very similar to before. First, we\n", "define all algorithmic parameters:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, trunc = (; alg = :fixedspace))\n", - "gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :diffgauge)\n", + "gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :fixed)\n", "optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, maxiter = 80, ls_maxiter = 3, ls_maxfg = 3)" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Second, we initialize a PEPS state and environment (which we converge) constructed from\n", "symmetric physical and virtual spaces:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "physical_spaces = physicalspace(H)\n", "virtual_spaces = fill(V_peps, size(lattice)...)\n", "peps₀ = InfinitePEPS(randn, ComplexF64, physical_spaces, virtual_spaces)\n", "env₀, = leading_boundary(CTMRGEnv(peps₀, V_env), peps₀; boundary_alg...);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "And third, we start the ground state search (this does take quite long):" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "peps, env, E, info = fixedpoint(\n", " H, peps₀, env₀; boundary_alg, gradient_alg, optimizer_alg, verbosity = 3\n", ")\n", "@show E;" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Finally, let's compare the obtained energy against a reference energy from a QMC study by\n", "[Qin et al.](@cite qin_benchmark_2016). With the parameters specified above, they obtain an\n", "energy of $E_\\text{ref} \\approx 4 \\times -0.5244140625 = -2.09765625$ (the factor 4 comes\n", "from the $2 \\times 2$ unit cell that we use here). Thus, we find:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "E_ref = -2.09765625\n", "@show (E - E_ref) / E_ref;" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "---\n", "\n", "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" - ], - "metadata": {} + ] } ], - "nbformat_minor": 3, "metadata": { + "kernelspec": { + "display_name": "Julia 1.12.5", + "language": "julia", + "name": "julia-1.12" + }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.12.5" - }, - "kernelspec": { - "name": "julia-1.12", - "display_name": "Julia 1.12.5", - "language": "julia" } }, - "nbformat": 4 + "nbformat": 4, + "nbformat_minor": 3 } \ No newline at end of file diff --git a/docs/src/examples/j1j2_su/index.md b/docs/src/examples/j1j2_su/index.md index baf3d1fbb..5edd3051e 100644 --- a/docs/src/examples/j1j2_su/index.md +++ b/docs/src/examples/j1j2_su/index.md @@ -27,7 +27,7 @@ We first import all required modules and seed the RNG: ````julia using Random using TensorKit, PEPSKit -Random.seed!(29385293); +Random.seed!(29385294); ```` ## Simple updating a challenging phase @@ -69,36 +69,41 @@ end ```` ```` +[ Info: --- Time evolution (simple update), dt = 0.01 --- [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1/2 => 1, -1/2 => 1) -[ Info: SU iter 1 : dt = 0.01, |Δλ| = 1.189e+00. Time = 0.034 s/it +[ Info: SU iter 1 : |Δλ| = 1.190e+00. Time = 118.568 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1833 : dt = 0.01, |Δλ| = 9.859e-09. Time = 0.037 s/it +[ Info: SU iter 1373 : |Δλ| = 9.898e-09. Time = 0.069 s/it [ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 70.90 s +[ Info: Time evolution finished in 225.44 s +[ Info: --- Time evolution (simple update), dt = 0.01 --- [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1 : dt = 0.01, |Δλ| = 3.401e-04. Time = 0.037 s/it +[ Info: SU iter 1 : |Δλ| = 2.985e-04. Time = 0.089 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 523 : dt = 0.01, |Δλ| = 9.965e-09. Time = 0.037 s/it +[ Info: SU iter 523 : |Δλ| = 9.955e-09. Time = 0.070 s/it [ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 21.18 s +[ Info: Time evolution finished in 38.09 s +[ Info: --- Time evolution (simple update), dt = 0.01 --- [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1 : dt = 0.01, |Δλ| = 3.526e-04. Time = 0.038 s/it +[ Info: SU iter 1 : |Δλ| = 3.001e-04. Time = 0.085 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 611 : dt = 0.01, |Δλ| = 9.848e-09. Time = 0.037 s/it +[ Info: SU iter 610 : |Δλ| = 9.971e-09. Time = 0.070 s/it [ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 24.83 s +[ Info: Time evolution finished in 44.48 s +[ Info: --- Time evolution (simple update), dt = 0.01 --- [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1 : dt = 0.01, |Δλ| = 3.664e-04. Time = 0.037 s/it +[ Info: SU iter 1 : |Δλ| = 3.021e-04. Time = 0.084 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 735 : dt = 0.01, |Δλ| = 9.963e-09. Time = 0.092 s/it +[ Info: SU iter 740 : |Δλ| = 9.953e-09. Time = 0.070 s/it [ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 29.87 s +[ Info: Time evolution finished in 53.86 s +[ Info: --- Time evolution (simple update), dt = 0.01 --- [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1 : dt = 0.01, |Δλ| = 3.828e-04. Time = 0.037 s/it +[ Info: SU iter 1 : |Δλ| = 3.089e-04. Time = 0.069 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 901 : dt = 0.01, |Δλ| = 9.995e-09. Time = 0.037 s/it +[ Info: SU iter 1140 : |Δλ| = 1.000e-08. Time = 0.070 s/it [ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 36.57 s +[ Info: Time evolution finished in 83.30 s ```` @@ -116,32 +121,185 @@ end ```` ```` +[ Info: --- Time evolution (simple update), dt = 0.001 --- [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1 : dt = 0.001, |Δλ| = 4.477e-04. Time = 0.037 s/it +[ Info: SU iter 1 : |Δλ| = 7.604e-04. Time = 0.138 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 500 : dt = 0.001, |Δλ| = 2.767e-08. Time = 0.037 s/it +[ Info: SU iter 500 : |Δλ| = 1.692e-06. Time = 0.085 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1000 : dt = 0.001, |Δλ| = 9.954e-09. Time = 0.037 s/it +[ Info: SU iter 1000 : |Δλ| = 1.002e-06. Time = 0.069 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1500 : dt = 0.001, |Δλ| = 5.019e-09. Time = 0.038 s/it +[ Info: SU iter 1500 : |Δλ| = 6.304e-07. Time = 0.070 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 2000 : dt = 0.001, |Δλ| = 3.015e-09. Time = 0.039 s/it +[ Info: SU iter 2000 : |Δλ| = 4.078e-07. Time = 0.069 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 2500 : dt = 0.001, |Δλ| = 1.935e-09. Time = 0.090 s/it +[ Info: SU iter 2500 : |Δλ| = 2.688e-07. Time = 0.070 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 3000 : dt = 0.001, |Δλ| = 1.273e-09. Time = 0.037 s/it +[ Info: SU iter 3000 : |Δλ| = 1.797e-07. Time = 0.070 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 3295 : dt = 0.001, |Δλ| = 9.994e-10. Time = 0.036 s/it -[ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 132.66 s +[ Info: SU iter 3500 : |Δλ| = 1.217e-07. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 4000 : |Δλ| = 8.352e-08. Time = 0.084 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 4500 : |Δλ| = 5.817e-08. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 5000 : |Δλ| = 4.132e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 5500 : |Δλ| = 3.002e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 6000 : |Δλ| = 2.216e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 6500 : |Δλ| = 1.651e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 7000 : |Δλ| = 1.235e-08. Time = 0.084 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 7500 : |Δλ| = 9.271e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 8000 : |Δλ| = 6.980e-09. Time = 0.086 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 1 : dt = 0.0001, |Δλ| = 4.467e-05. Time = 0.036 s/it +[ Info: SU iter 8500 : |Δλ| = 5.278e-09. Time = 0.069 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 500 : dt = 0.0001, |Δλ| = 1.150e-09. Time = 0.035 s/it +[ Info: SU iter 9000 : |Δλ| = 4.021e-09. Time = 0.069 s/it [ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) -[ Info: SU iter 873 : dt = 0.0001, |Δλ| = 9.998e-10. Time = 0.037 s/it +[ Info: SU iter 9500 : |Δλ| = 3.090e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 10000 : |Δλ| = 2.394e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 10500 : |Δλ| = 1.878e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 11000 : |Δλ| = 1.498e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 11500 : |Δλ| = 1.209e-09. Time = 0.071 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 11962 : |Δλ| = 9.999e-10. Time = 0.070 s/it [ Info: SU: bond weights have converged. -[ Info: Simple update finished. Total time elapsed: 34.62 s +[ Info: Time evolution finished in 870.98 s +[ Info: --- Time evolution (simple update), dt = 0.0001 --- +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 1 : |Δλ| = 7.683e-05. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 500 : |Δλ| = 3.277e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 1000 : |Δλ| = 2.995e-08. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 1500 : |Δλ| = 2.752e-08. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 2000 : |Δλ| = 2.540e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 2500 : |Δλ| = 2.355e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 3000 : |Δλ| = 2.193e-08. Time = 0.071 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 3500 : |Δλ| = 2.049e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 4000 : |Δλ| = 1.920e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 4500 : |Δλ| = 1.805e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 5000 : |Δλ| = 1.700e-08. Time = 0.071 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 5500 : |Δλ| = 1.605e-08. Time = 0.087 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 6000 : |Δλ| = 1.518e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 6500 : |Δλ| = 1.438e-08. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 7000 : |Δλ| = 1.363e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 7500 : |Δλ| = 1.294e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 8000 : |Δλ| = 1.230e-08. Time = 0.073 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 8500 : |Δλ| = 1.170e-08. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 9000 : |Δλ| = 1.114e-08. Time = 0.084 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 9500 : |Δλ| = 1.060e-08. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 10000 : |Δλ| = 1.011e-08. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 10500 : |Δλ| = 9.635e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 11000 : |Δλ| = 9.190e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 11500 : |Δλ| = 8.770e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 12000 : |Δλ| = 8.372e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 12500 : |Δλ| = 7.995e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 13000 : |Δλ| = 7.637e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 13500 : |Δλ| = 7.298e-09. Time = 0.093 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 14000 : |Δλ| = 6.976e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 14500 : |Δλ| = 6.670e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 15000 : |Δλ| = 6.379e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 15500 : |Δλ| = 6.102e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 16000 : |Δλ| = 5.839e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 16500 : |Δλ| = 5.588e-09. Time = 0.071 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 17000 : |Δλ| = 5.349e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 17500 : |Δλ| = 5.122e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 18000 : |Δλ| = 4.905e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 18500 : |Δλ| = 4.699e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 19000 : |Δλ| = 4.502e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 19500 : |Δλ| = 4.314e-09. Time = 0.086 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 20000 : |Δλ| = 4.134e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 20500 : |Δλ| = 3.963e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 21000 : |Δλ| = 3.800e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 21500 : |Δλ| = 3.644e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 22000 : |Δλ| = 3.494e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 22500 : |Δλ| = 3.352e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 23000 : |Δλ| = 3.216e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 23500 : |Δλ| = 3.085e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 24000 : |Δλ| = 2.961e-09. Time = 0.086 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 24500 : |Δλ| = 2.842e-09. Time = 0.070 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 25000 : |Δλ| = 2.728e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 25500 : |Δλ| = 2.619e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 26000 : |Δλ| = 2.515e-09. Time = 0.085 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 26500 : |Δλ| = 2.415e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 27000 : |Δλ| = 2.319e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 27500 : |Δλ| = 2.228e-09. Time = 0.084 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 28000 : |Δλ| = 2.140e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 28500 : |Δλ| = 2.056e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 29000 : |Δλ| = 1.976e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 29500 : |Δλ| = 1.899e-09. Time = 0.069 s/it +[ Info: Space of x-weight at [1, 1] = Rep[U₁](0 => 2, 1 => 1, -1 => 1) +[ Info: SU iter 30000 : |Δλ| = 1.825e-09. Time = 0.069 s/it +┌ Warning: SU: bond weights have not converged. +└ @ PEPSKit ~/git/PEPSKit.jl/src/algorithms/time_evolution/simpleupdate.jl:241 +[ Info: Time evolution finished in 2182.89 s ```` @@ -161,7 +319,7 @@ E = expectation_value(peps, H, env) / (Nr * Nc) ```` ```` --0.4908483447932438 +-0.4908450911219574 ```` Let us compare that estimate with benchmark data obtained from the @@ -174,7 +332,7 @@ E_ref = -0.49425 ```` ```` -(E - E_ref) / abs(E_ref) = 0.006882458688429391 +(E - E_ref) / abs(E_ref) = 0.006889041736049819 ```` @@ -189,99 +347,105 @@ In order to break some of the $C_{4v}$ symmetry of the PEPS, we will add a bit o This is conviently done using MPSKit's `randomize!` function. (Breaking some of the spatial symmetry can be advantageous for obtaining lower energies.) +In our optimization, we will use a fixed-point differentiation scheme which requires a +gauge fixing of the contraction environment +(specified by the `gradient_alg = (; iterscheme = :fixed)` setting). +Since this gauge fixing involves potentially complex phases, we have to convert our +real-valued contraction environment to complex numbers before the optimization. + ````julia using MPSKit: randomize! noise_peps = InfinitePEPS(randomize!.(deepcopy(peps.A))) peps₀ = peps + 1.0e-1noise_peps peps_opt, env_opt, E_opt, = fixedpoint( - H, peps₀, env; - optimizer_alg = (; tol = 1.0e-4, maxiter = 80), gradient_alg = (; iterscheme = :diffgauge) + H, peps₀, complex(env); + optimizer_alg = (; tol = 1.0e-4, maxiter = 80), gradient_alg = (; iterscheme = :fixed) ); ```` ```` -[ Info: LBFGS: initializing with f = -1.917915769323e+00, ‖∇f‖ = 4.2598e-01 -[ Info: LBFGS: iter 1, Δt 16.45 s: f = -1.921875846208e+00, ‖∇f‖ = 3.6931e-01, α = 1.00e+00, m = 0, nfg = 1 -[ Info: LBFGS: iter 2, Δt 12.76 s: f = -1.942022618990e+00, ‖∇f‖ = 2.0804e-01, α = 1.00e+00, m = 1, nfg = 1 -[ Info: LBFGS: iter 3, Δt 12.69 s: f = -1.948412125614e+00, ‖∇f‖ = 1.4224e-01, α = 1.00e+00, m = 2, nfg = 1 -[ Info: LBFGS: iter 4, Δt 11.25 s: f = -1.954734282994e+00, ‖∇f‖ = 1.6428e-01, α = 1.00e+00, m = 3, nfg = 1 -[ Info: LBFGS: iter 5, Δt 12.79 s: f = -1.957501635760e+00, ‖∇f‖ = 1.8493e-01, α = 1.00e+00, m = 4, nfg = 1 -[ Info: LBFGS: iter 6, Δt 12.20 s: f = -1.959162742352e+00, ‖∇f‖ = 1.0888e-01, α = 1.00e+00, m = 5, nfg = 1 -[ Info: LBFGS: iter 7, Δt 12.06 s: f = -1.961758227820e+00, ‖∇f‖ = 9.0418e-02, α = 1.00e+00, m = 6, nfg = 1 -[ Info: LBFGS: iter 8, Δt 12.57 s: f = -1.963102797068e+00, ‖∇f‖ = 7.7890e-02, α = 1.00e+00, m = 7, nfg = 1 -[ Info: LBFGS: iter 9, Δt 12.02 s: f = -1.965635307562e+00, ‖∇f‖ = 5.7454e-02, α = 1.00e+00, m = 8, nfg = 1 -[ Info: LBFGS: iter 10, Δt 12.22 s: f = -1.967012786653e+00, ‖∇f‖ = 1.0695e-01, α = 1.00e+00, m = 9, nfg = 1 -[ Info: LBFGS: iter 11, Δt 12.75 s: f = -1.968331989207e+00, ‖∇f‖ = 4.7357e-02, α = 1.00e+00, m = 10, nfg = 1 -[ Info: LBFGS: iter 12, Δt 12.52 s: f = -1.968984356192e+00, ‖∇f‖ = 3.6819e-02, α = 1.00e+00, m = 11, nfg = 1 -[ Info: LBFGS: iter 13, Δt 13.08 s: f = -1.969738509271e+00, ‖∇f‖ = 3.8320e-02, α = 1.00e+00, m = 12, nfg = 1 -[ Info: LBFGS: iter 14, Δt 13.97 s: f = -1.970765612340e+00, ‖∇f‖ = 4.1807e-02, α = 1.00e+00, m = 13, nfg = 1 -[ Info: LBFGS: iter 15, Δt 13.32 s: f = -1.971316317211e+00, ‖∇f‖ = 4.5580e-02, α = 1.00e+00, m = 14, nfg = 1 -[ Info: LBFGS: iter 16, Δt 13.46 s: f = -1.971822370984e+00, ‖∇f‖ = 2.4262e-02, α = 1.00e+00, m = 15, nfg = 1 -[ Info: LBFGS: iter 17, Δt 12.99 s: f = -1.972203923570e+00, ‖∇f‖ = 2.4564e-02, α = 1.00e+00, m = 16, nfg = 1 -[ Info: LBFGS: iter 18, Δt 12.95 s: f = -1.972802900923e+00, ‖∇f‖ = 2.8491e-02, α = 1.00e+00, m = 17, nfg = 1 -[ Info: LBFGS: iter 19, Δt 13.74 s: f = -1.973589666789e+00, ‖∇f‖ = 3.2039e-02, α = 1.00e+00, m = 18, nfg = 1 -[ Info: LBFGS: iter 20, Δt 13.18 s: f = -1.973913379566e+00, ‖∇f‖ = 5.1316e-02, α = 1.00e+00, m = 19, nfg = 1 -[ Info: LBFGS: iter 21, Δt 13.55 s: f = -1.974416985201e+00, ‖∇f‖ = 1.8951e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 22, Δt 13.47 s: f = -1.974639779350e+00, ‖∇f‖ = 1.8591e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 23, Δt 13.23 s: f = -1.974980106926e+00, ‖∇f‖ = 1.9583e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 24, Δt 14.00 s: f = -1.975202056049e+00, ‖∇f‖ = 3.9045e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 25, Δt 13.33 s: f = -1.975442229571e+00, ‖∇f‖ = 1.8554e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 26, Δt 13.95 s: f = -1.975560352122e+00, ‖∇f‖ = 1.5857e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 27, Δt 13.25 s: f = -1.975643058810e+00, ‖∇f‖ = 1.2993e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 28, Δt 13.13 s: f = -1.975704724372e+00, ‖∇f‖ = 1.9944e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 29, Δt 14.12 s: f = -1.975779000149e+00, ‖∇f‖ = 1.1828e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 30, Δt 13.48 s: f = -1.975862495962e+00, ‖∇f‖ = 1.0766e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 31, Δt 13.36 s: f = -1.975947783240e+00, ‖∇f‖ = 9.5066e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 32, Δt 13.70 s: f = -1.976052804517e+00, ‖∇f‖ = 1.5333e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 33, Δt 13.19 s: f = -1.976106986012e+00, ‖∇f‖ = 2.1883e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 34, Δt 13.41 s: f = -1.976164433529e+00, ‖∇f‖ = 7.9599e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 35, Δt 14.17 s: f = -1.976190058936e+00, ‖∇f‖ = 6.7778e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 36, Δt 13.45 s: f = -1.976224201954e+00, ‖∇f‖ = 7.6168e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 37, Δt 13.73 s: f = -1.976267854501e+00, ‖∇f‖ = 1.7393e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 38, Δt 13.84 s: f = -1.976315102216e+00, ‖∇f‖ = 8.0912e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 39, Δt 13.22 s: f = -1.976342354040e+00, ‖∇f‖ = 6.1351e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 40, Δt 13.44 s: f = -1.976371404915e+00, ‖∇f‖ = 6.6216e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 41, Δt 13.71 s: f = -1.976421353914e+00, ‖∇f‖ = 8.2468e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 42, Δt 13.47 s: f = -1.976466860391e+00, ‖∇f‖ = 9.9248e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 43, Δt 13.64 s: f = -1.976507540729e+00, ‖∇f‖ = 6.9877e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 44, Δt 14.04 s: f = -1.976535673591e+00, ‖∇f‖ = 5.6235e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 45, Δt 13.18 s: f = -1.976573549708e+00, ‖∇f‖ = 7.4445e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 46, Δt 13.51 s: f = -1.976590425955e+00, ‖∇f‖ = 1.5662e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 47, Δt 13.88 s: f = -1.976621753066e+00, ‖∇f‖ = 6.2307e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 48, Δt 13.08 s: f = -1.976639047822e+00, ‖∇f‖ = 5.1405e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 49, Δt 13.33 s: f = -1.976657938685e+00, ‖∇f‖ = 1.1028e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 50, Δt 13.74 s: f = -1.976676808863e+00, ‖∇f‖ = 9.7274e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 51, Δt 13.29 s: f = -1.976691906282e+00, ‖∇f‖ = 5.8050e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 52, Δt 13.20 s: f = -1.976710655182e+00, ‖∇f‖ = 5.7333e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 53, Δt 13.66 s: f = -1.976732623549e+00, ‖∇f‖ = 5.2887e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 54, Δt 13.26 s: f = -1.976766233304e+00, ‖∇f‖ = 8.5088e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 55, Δt 13.39 s: f = -1.976781456137e+00, ‖∇f‖ = 1.1582e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 56, Δt 24.51 s: f = -1.976799996356e+00, ‖∇f‖ = 5.1443e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 57, Δt 13.08 s: f = -1.976812132182e+00, ‖∇f‖ = 3.9200e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 58, Δt 13.75 s: f = -1.976828056507e+00, ‖∇f‖ = 6.6193e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 59, Δt 13.05 s: f = -1.976851081866e+00, ‖∇f‖ = 6.9020e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 60, Δt 13.15 s: f = -1.976872354754e+00, ‖∇f‖ = 5.8100e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 61, Δt 13.76 s: f = -1.976887353263e+00, ‖∇f‖ = 1.5507e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 62, Δt 13.33 s: f = -1.976913441456e+00, ‖∇f‖ = 5.4576e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 63, Δt 13.19 s: f = -1.976925022985e+00, ‖∇f‖ = 4.5942e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 64, Δt 13.90 s: f = -1.976945457629e+00, ‖∇f‖ = 6.1499e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 65, Δt 13.54 s: f = -1.976948121976e+00, ‖∇f‖ = 1.2404e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 66, Δt 13.37 s: f = -1.976990622832e+00, ‖∇f‖ = 1.0997e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 67, Δt 13.89 s: f = -1.977019727681e+00, ‖∇f‖ = 5.3064e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 68, Δt 13.40 s: f = -1.977038041468e+00, ‖∇f‖ = 3.9154e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 69, Δt 13.22 s: f = -1.977061135927e+00, ‖∇f‖ = 5.5351e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 70, Δt 25.93 s: f = -1.977069437407e+00, ‖∇f‖ = 9.1542e-03, α = 2.16e-01, m = 20, nfg = 2 -[ Info: LBFGS: iter 71, Δt 11.98 s: f = -1.977082632066e+00, ‖∇f‖ = 7.0584e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 72, Δt 12.86 s: f = -1.977109455547e+00, ‖∇f‖ = 6.5585e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 73, Δt 12.26 s: f = -1.977124023586e+00, ‖∇f‖ = 1.0470e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 74, Δt 12.29 s: f = -1.977136222448e+00, ‖∇f‖ = 9.2794e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 75, Δt 12.79 s: f = -1.977174289195e+00, ‖∇f‖ = 6.4735e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 76, Δt 12.52 s: f = -1.977220054869e+00, ‖∇f‖ = 6.4042e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 77, Δt 12.26 s: f = -1.977245223602e+00, ‖∇f‖ = 6.9440e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 78, Δt 12.87 s: f = -1.977264616541e+00, ‖∇f‖ = 1.5115e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 79, Δt 12.17 s: f = -1.977292459833e+00, ‖∇f‖ = 6.6226e-03, α = 1.00e+00, m = 20, nfg = 1 -┌ Warning: LBFGS: not converged to requested tol after 80 iterations and time 25.05 m: f = -1.977304651029e+00, ‖∇f‖ = 4.5558e-03 +[ Info: LBFGS: initializing with f = -1.887578587634e+00, ‖∇f‖ = 7.8780e-01 +[ Info: LBFGS: iter 1, Δt 2.11 m: f = -1.926388092775e+00, ‖∇f‖ = 4.7092e-01, α = 1.19e+01, m = 0, nfg = 4 +[ Info: LBFGS: iter 2, Δt 30.68 s: f = -1.936546032899e+00, ‖∇f‖ = 2.1792e-01, α = 1.00e+00, m = 1, nfg = 1 +[ Info: LBFGS: iter 3, Δt 29.68 s: f = -1.942713411326e+00, ‖∇f‖ = 2.0267e-01, α = 1.00e+00, m = 2, nfg = 1 +[ Info: LBFGS: iter 4, Δt 29.00 s: f = -1.952873152491e+00, ‖∇f‖ = 1.6713e-01, α = 1.00e+00, m = 3, nfg = 1 +[ Info: LBFGS: iter 5, Δt 26.25 s: f = -1.958619448466e+00, ‖∇f‖ = 1.5871e-01, α = 1.00e+00, m = 4, nfg = 1 +[ Info: LBFGS: iter 6, Δt 27.27 s: f = -1.961555293087e+00, ‖∇f‖ = 9.2861e-02, α = 1.00e+00, m = 5, nfg = 1 +[ Info: LBFGS: iter 7, Δt 25.52 s: f = -1.962811912498e+00, ‖∇f‖ = 6.7900e-02, α = 1.00e+00, m = 6, nfg = 1 +[ Info: LBFGS: iter 8, Δt 27.71 s: f = -1.965000830793e+00, ‖∇f‖ = 5.5994e-02, α = 1.00e+00, m = 7, nfg = 1 +[ Info: LBFGS: iter 9, Δt 26.97 s: f = -1.966386885688e+00, ‖∇f‖ = 5.8303e-02, α = 1.00e+00, m = 8, nfg = 1 +[ Info: LBFGS: iter 10, Δt 27.50 s: f = -1.967582741430e+00, ‖∇f‖ = 1.1340e-01, α = 1.00e+00, m = 9, nfg = 1 +[ Info: LBFGS: iter 11, Δt 24.91 s: f = -1.968967360870e+00, ‖∇f‖ = 4.1612e-02, α = 1.00e+00, m = 10, nfg = 1 +[ Info: LBFGS: iter 12, Δt 24.17 s: f = -1.969387768033e+00, ‖∇f‖ = 3.6625e-02, α = 1.00e+00, m = 11, nfg = 1 +[ Info: LBFGS: iter 13, Δt 22.91 s: f = -1.970335449656e+00, ‖∇f‖ = 3.8759e-02, α = 1.00e+00, m = 12, nfg = 1 +[ Info: LBFGS: iter 14, Δt 27.81 s: f = -1.971409090676e+00, ‖∇f‖ = 4.5864e-02, α = 1.00e+00, m = 13, nfg = 1 +[ Info: LBFGS: iter 15, Δt 28.11 s: f = -1.972264675328e+00, ‖∇f‖ = 3.3125e-02, α = 1.00e+00, m = 14, nfg = 1 +[ Info: LBFGS: iter 16, Δt 30.00 s: f = -1.972963700423e+00, ‖∇f‖ = 3.8311e-02, α = 1.00e+00, m = 15, nfg = 1 +[ Info: LBFGS: iter 17, Δt 27.60 s: f = -1.973393808483e+00, ‖∇f‖ = 3.4025e-02, α = 1.00e+00, m = 16, nfg = 1 +[ Info: LBFGS: iter 18, Δt 26.40 s: f = -1.973719445599e+00, ‖∇f‖ = 2.4697e-02, α = 1.00e+00, m = 17, nfg = 1 +[ Info: LBFGS: iter 19, Δt 28.38 s: f = -1.974117003995e+00, ‖∇f‖ = 2.3402e-02, α = 1.00e+00, m = 18, nfg = 1 +[ Info: LBFGS: iter 20, Δt 27.75 s: f = -1.974537198653e+00, ‖∇f‖ = 2.3338e-02, α = 1.00e+00, m = 19, nfg = 1 +[ Info: LBFGS: iter 21, Δt 27.06 s: f = -1.975099516920e+00, ‖∇f‖ = 2.6565e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 22, Δt 26.82 s: f = -1.975286936081e+00, ‖∇f‖ = 4.4455e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 23, Δt 25.91 s: f = -1.975701217338e+00, ‖∇f‖ = 1.5220e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 24, Δt 28.52 s: f = -1.975821697001e+00, ‖∇f‖ = 1.8130e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 25, Δt 26.42 s: f = -1.975915354964e+00, ‖∇f‖ = 2.1138e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 26, Δt 24.35 s: f = -1.975998069768e+00, ‖∇f‖ = 1.3443e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 27, Δt 24.80 s: f = -1.976153039607e+00, ‖∇f‖ = 1.4680e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 28, Δt 23.66 s: f = -1.976260274804e+00, ‖∇f‖ = 1.7700e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 29, Δt 24.93 s: f = -1.976336675890e+00, ‖∇f‖ = 3.6212e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 30, Δt 22.98 s: f = -1.976481030702e+00, ‖∇f‖ = 1.2667e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 31, Δt 23.03 s: f = -1.976539819784e+00, ‖∇f‖ = 1.2939e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 32, Δt 23.95 s: f = -1.976636245246e+00, ‖∇f‖ = 1.3135e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 33, Δt 48.36 s: f = -1.976684971058e+00, ‖∇f‖ = 1.9116e-02, α = 4.62e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 34, Δt 23.65 s: f = -1.976743262496e+00, ‖∇f‖ = 1.1658e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 35, Δt 23.80 s: f = -1.976804909822e+00, ‖∇f‖ = 9.8461e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 36, Δt 23.74 s: f = -1.976867380046e+00, ‖∇f‖ = 1.1271e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 37, Δt 24.66 s: f = -1.976958913613e+00, ‖∇f‖ = 1.1353e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 38, Δt 24.14 s: f = -1.977004149888e+00, ‖∇f‖ = 3.0196e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 39, Δt 24.29 s: f = -1.977132482812e+00, ‖∇f‖ = 8.3199e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 40, Δt 23.70 s: f = -1.977168854066e+00, ‖∇f‖ = 6.5281e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 41, Δt 24.26 s: f = -1.977230989059e+00, ‖∇f‖ = 9.2541e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 42, Δt 24.18 s: f = -1.977285220461e+00, ‖∇f‖ = 1.3935e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 43, Δt 23.53 s: f = -1.977362590244e+00, ‖∇f‖ = 1.0743e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 44, Δt 23.86 s: f = -1.977429195025e+00, ‖∇f‖ = 8.6810e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 45, Δt 25.41 s: f = -1.977458751818e+00, ‖∇f‖ = 2.5717e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 46, Δt 22.06 s: f = -1.977509209358e+00, ‖∇f‖ = 1.3339e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 47, Δt 22.96 s: f = -1.977531778536e+00, ‖∇f‖ = 1.0403e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 48, Δt 22.65 s: f = -1.977584620950e+00, ‖∇f‖ = 1.0581e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 49, Δt 23.16 s: f = -1.977638977445e+00, ‖∇f‖ = 1.1478e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 50, Δt 24.26 s: f = -1.977695226616e+00, ‖∇f‖ = 1.1637e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 51, Δt 22.61 s: f = -1.977738682348e+00, ‖∇f‖ = 1.8362e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 52, Δt 21.76 s: f = -1.977786348227e+00, ‖∇f‖ = 8.4144e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 53, Δt 23.05 s: f = -1.977834226107e+00, ‖∇f‖ = 9.5424e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 54, Δt 24.76 s: f = -1.977872709228e+00, ‖∇f‖ = 1.0069e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 55, Δt 23.20 s: f = -1.977896046364e+00, ‖∇f‖ = 1.1177e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 56, Δt 22.34 s: f = -1.977948855869e+00, ‖∇f‖ = 1.5958e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 57, Δt 22.56 s: f = -1.977994579851e+00, ‖∇f‖ = 8.9051e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 58, Δt 22.35 s: f = -1.978026072493e+00, ‖∇f‖ = 6.8546e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 59, Δt 24.53 s: f = -1.978061626606e+00, ‖∇f‖ = 9.8392e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 60, Δt 24.11 s: f = -1.978102554569e+00, ‖∇f‖ = 9.4732e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 61, Δt 22.77 s: f = -1.978139870452e+00, ‖∇f‖ = 9.1003e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 62, Δt 23.50 s: f = -1.978176133536e+00, ‖∇f‖ = 6.4191e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 63, Δt 23.05 s: f = -1.978213215021e+00, ‖∇f‖ = 6.9446e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 64, Δt 24.10 s: f = -1.978234971062e+00, ‖∇f‖ = 1.5980e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 65, Δt 25.47 s: f = -1.978268225326e+00, ‖∇f‖ = 8.5546e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 66, Δt 22.02 s: f = -1.978286888113e+00, ‖∇f‖ = 6.4777e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 67, Δt 23.79 s: f = -1.978300997146e+00, ‖∇f‖ = 8.0692e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 68, Δt 22.57 s: f = -1.978300528984e+00, ‖∇f‖ = 5.5147e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 69, Δt 23.63 s: f = -1.978328958743e+00, ‖∇f‖ = 6.3994e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 70, Δt 24.58 s: f = -1.978331153308e+00, ‖∇f‖ = 6.5489e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 71, Δt 24.48 s: f = -1.978363716954e+00, ‖∇f‖ = 5.9050e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 72, Δt 24.34 s: f = -1.978377069104e+00, ‖∇f‖ = 1.1874e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 73, Δt 23.47 s: f = -1.978401095295e+00, ‖∇f‖ = 5.3880e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 74, Δt 23.53 s: f = -1.978411402203e+00, ‖∇f‖ = 3.9472e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 75, Δt 23.03 s: f = -1.978423812150e+00, ‖∇f‖ = 5.1734e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 76, Δt 23.97 s: f = -1.978437405148e+00, ‖∇f‖ = 7.4640e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 77, Δt 23.49 s: f = -1.978449959375e+00, ‖∇f‖ = 4.6023e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 78, Δt 23.47 s: f = -1.978465209487e+00, ‖∇f‖ = 4.0286e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 79, Δt 23.17 s: f = -1.978478118790e+00, ‖∇f‖ = 6.5526e-03, α = 1.00e+00, m = 20, nfg = 1 +┌ Warning: LBFGS: not converged to requested tol after 80 iterations and time 52.05 m: f = -1.978491610275e+00, ‖∇f‖ = 7.4246e-03 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/lbfgs.jl:199 ```` @@ -297,8 +461,8 @@ E_opt /= (Nr * Nc) ```` ```` -E_opt = -0.49432616275726 -(E_opt - E_ref) / abs(E_ref) = -0.0001540976373494541 +E_opt = -0.4946229025687655 +(E_opt - E_ref) / abs(E_ref) = -0.0007544816768143398 ```` diff --git a/docs/src/examples/j1j2_su/main.ipynb b/docs/src/examples/j1j2_su/main.ipynb index 737098291..67086a16f 100644 --- a/docs/src/examples/j1j2_su/main.ipynb +++ b/docs/src/examples/j1j2_su/main.ipynb @@ -1,16 +1,17 @@ { "cells": [ { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Markdown #hide" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# Three-site simple update for the $J_1$-$J_2$ model\n", "\n", @@ -28,22 +29,22 @@ "optimization.\n", "\n", "We first import all required modules and seed the RNG:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Random\n", "using TensorKit, PEPSKit\n", - "Random.seed!(29385293);" - ], - "metadata": {}, - "execution_count": null + "Random.seed!(29385294);" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Simple updating a challenging phase\n", "\n", @@ -52,12 +53,13 @@ "The `SUWeight` used by simple update will be initialized to identity matrices.\n", "We use the minimal unit cell size ($2 \\times 2$) required by the simple update algorithm\n", "for Hamiltonians with next-nearest-neighbour interactions:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "Dbond, symm = 4, U1Irrep\n", "Nr, Nc, J1 = 2, 2, 1.0\n", @@ -67,23 +69,23 @@ "Vspace = Vect[U1Irrep](0 => 2, 1 // 2 => 1, -1 // 2 => 1)\n", "peps = InfinitePEPS(rand, Float64, Pspace, Vspace; unitcell = (Nr, Nc));\n", "wts = SUWeight(peps);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "The value $J_2 / J_1 = 0.5$ corresponds to a [possible spin liquid phase](@cite liu_gapless_2022),\n", "which is challenging for SU to produce a relatively good state from random initialization.\n", "Therefore, we shall gradually increase $J_2 / J_1$ from 0.1 to 0.5, each time initializing\n", "on the previously evolved PEPS:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dt, tol, nstep = 1.0e-2, 1.0e-8, 30000\n", "check_interval = 4000\n", @@ -96,21 +98,21 @@ " )\n", " global peps, wts, = time_evolve(peps, H, dt, nstep, alg, wts; tol, check_interval)\n", "end" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "After we reach $J_2 / J_1 = 0.5$, we gradually decrease the evolution time step to obtain\n", "a more accurately evolved PEPS:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dts = [1.0e-3, 1.0e-4]\n", "tols = [1.0e-9, 1.0e-9]\n", @@ -119,23 +121,23 @@ "for (dt, tol) in zip(dts, tols)\n", " global peps, wts, = time_evolve(peps, H, dt, nstep, alg, wts; tol)\n", "end" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Computing the simple update energy estimate\n", "\n", "Finally, we measure the ground-state energy by converging a CTMRG environment and computing\n", "the expectation value, where we first normalize tensors in the PEPS:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "normalize!.(peps.A, Inf) ## normalize each PEPS tensor by largest element\n", "χenv = 32\n", @@ -144,31 +146,30 @@ "env₀ = CTMRGEnv(rand, Float64, peps, Espace)\n", "env, = leading_boundary(env₀, peps; tol = 1.0e-10, alg = :sequential, trunc = trunc_env);\n", "E = expectation_value(peps, H, env) / (Nr * Nc)" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Let us compare that estimate with benchmark data obtained from the\n", "[YASTN/peps-torch package](https://github.com/jurajHasik/j1j2_ipeps_states/blob/ea4140fbd7da0fc1b75fac2871f75bda125189a8/single-site_pg-C4v-A1_internal-U1/j20.5/state_1s_A1_U1B_j20.5_D4_chi_opt96.dat).\n", "which utilizes AD-based PEPS optimization to find $E_\\text{ref}=-0.49425$:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "E_ref = -0.49425\n", "@show (E - E_ref) / abs(E_ref);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Variational PEPS optimization using AD\n", "\n", @@ -179,69 +180,74 @@ "the already evolved `peps`, thus giving us a physical initial guess for the optimization.\n", "In order to break some of the $C_{4v}$ symmetry of the PEPS, we will add a bit of noise to it.\n", "This is conviently done using MPSKit's `randomize!` function.\n", - "(Breaking some of the spatial symmetry can be advantageous for obtaining lower energies.)" - ], - "metadata": {} + "(Breaking some of the spatial symmetry can be advantageous for obtaining lower energies.)\n", + "\n", + "In our optimization, we will use a fixed-point differentiation scheme which requires a\n", + "gauge fixing of the contraction environment\n", + "(specified by the `gradient_alg = (; iterscheme = :fixed)` setting).\n", + "Since this gauge fixing involves potentially complex phases, we have to convert our\n", + "real-valued contraction environment to complex numbers before the optimization." + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using MPSKit: randomize!\n", "\n", "noise_peps = InfinitePEPS(randomize!.(deepcopy(peps.A)))\n", "peps₀ = peps + 1.0e-1noise_peps\n", "peps_opt, env_opt, E_opt, = fixedpoint(\n", - " H, peps₀, env;\n", - " optimizer_alg = (; tol = 1.0e-4, maxiter = 80), gradient_alg = (; iterscheme = :diffgauge)\n", + " H, peps₀, complex(env);\n", + " optimizer_alg = (; tol = 1.0e-4, maxiter = 80), gradient_alg = (; iterscheme = :fixed)\n", ");" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Finally, we compare the variationally optimized energy against the reference energy. Indeed,\n", "we find that the additional AD-based optimization improves the SU-evolved PEPS and leads to\n", "a more accurate energy estimate." - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "E_opt /= (Nr * Nc)\n", "@show E_opt\n", "@show (E_opt - E_ref) / abs(E_ref);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "---\n", "\n", "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" - ], - "metadata": {} + ] } ], - "nbformat_minor": 3, "metadata": { + "kernelspec": { + "display_name": "Julia 1.12.5", + "language": "julia", + "name": "julia-1.12" + }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.12.5" - }, - "kernelspec": { - "name": "julia-1.12", - "display_name": "Julia 1.12.5", - "language": "julia" } }, - "nbformat": 4 + "nbformat": 4, + "nbformat_minor": 3 } \ No newline at end of file diff --git a/docs/src/examples/xxz/index.md b/docs/src/examples/xxz/index.md index 2a4762152..bc2f10dc0 100644 --- a/docs/src/examples/xxz/index.md +++ b/docs/src/examples/xxz/index.md @@ -85,7 +85,7 @@ From this point onwards it's business as usual: Create an initial PEPS and envir ````julia boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, trunc = (; alg = :fixedspace)) -gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :diffgauge) +gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :fixed) optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, maxiter = 85, ls_maxiter = 3, ls_maxfg = 3) peps₀ = InfinitePEPS(randn, ComplexF64, physical_spaces, virtual_spaces) @@ -94,7 +94,7 @@ env₀, = leading_boundary(CTMRGEnv(peps₀, V_env), peps₀; boundary_alg...); ```` [ Info: CTMRG init: obj = -2.356413456811e+03 +3.307968169629e+02im err = 1.0000e+00 -[ Info: CTMRG conv 30: obj = +6.245129734283e+03 -4.009962140117e-08im err = 5.3638613065e-09 time = 1.07 sec +[ Info: CTMRG conv 30: obj = +6.245129734283e+03 -4.008506948594e-08im err = 5.3638614844e-09 time = 14.24 sec ```` @@ -116,96 +116,96 @@ peps, env, E, info = fixedpoint( ┌ Warning: Linesearch not converged after 1 iterations and 4 function evaluations: │ α = 2.50e+01, dϕ = -2.44e-02, ϕ - ϕ₀ = -4.56e-01 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/linesearches.jl:151 -[ Info: LBFGS: iter 1, Δt 49.56 s: f = -5.947088553802e-01, ‖∇f‖ = 3.7329e+00, α = 2.50e+01, m = 0, nfg = 4 +[ Info: LBFGS: iter 1, Δt 45.37 s: f = -5.947088553357e-01, ‖∇f‖ = 3.7329e+00, α = 2.50e+01, m = 0, nfg = 4 ┌ Warning: Linesearch not converged after 1 iterations and 4 function evaluations: │ α = 2.50e+01, dϕ = -7.72e-03, ϕ - ϕ₀ = -1.52e+00 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/linesearches.jl:151 -[ Info: LBFGS: iter 2, Δt 45.67 s: f = -2.114273976232e+00, ‖∇f‖ = 2.9121e+00, α = 2.50e+01, m = 0, nfg = 4 -[ Info: LBFGS: iter 3, Δt 8.71 s: f = -2.218657556737e+00, ‖∇f‖ = 1.4788e+00, α = 1.00e+00, m = 1, nfg = 1 -[ Info: LBFGS: iter 4, Δt 27.86 s: f = -2.473597362493e+00, ‖∇f‖ = 1.2506e+00, α = 3.17e+00, m = 2, nfg = 3 -[ Info: LBFGS: iter 5, Δt 9.06 s: f = -2.546159337642e+00, ‖∇f‖ = 1.4463e+00, α = 1.00e+00, m = 3, nfg = 1 -[ Info: LBFGS: iter 6, Δt 8.67 s: f = -2.614645566780e+00, ‖∇f‖ = 4.0554e-01, α = 1.00e+00, m = 4, nfg = 1 -[ Info: LBFGS: iter 7, Δt 9.03 s: f = -2.622673933972e+00, ‖∇f‖ = 1.8054e-01, α = 1.00e+00, m = 5, nfg = 1 -[ Info: LBFGS: iter 8, Δt 8.40 s: f = -2.626310260618e+00, ‖∇f‖ = 1.7749e-01, α = 1.00e+00, m = 6, nfg = 1 -[ Info: LBFGS: iter 9, Δt 7.93 s: f = -2.632769136711e+00, ‖∇f‖ = 1.8586e-01, α = 1.00e+00, m = 7, nfg = 1 -[ Info: LBFGS: iter 10, Δt 7.61 s: f = -2.639694621229e+00, ‖∇f‖ = 2.2500e-01, α = 1.00e+00, m = 8, nfg = 1 -[ Info: LBFGS: iter 11, Δt 7.16 s: f = -2.644827933828e+00, ‖∇f‖ = 1.2801e-01, α = 1.00e+00, m = 9, nfg = 1 -[ Info: LBFGS: iter 12, Δt 7.50 s: f = -2.646459705942e+00, ‖∇f‖ = 6.7575e-02, α = 1.00e+00, m = 10, nfg = 1 -[ Info: LBFGS: iter 13, Δt 6.99 s: f = -2.647499600848e+00, ‖∇f‖ = 6.0731e-02, α = 1.00e+00, m = 11, nfg = 1 -[ Info: LBFGS: iter 14, Δt 7.50 s: f = -2.648703045941e+00, ‖∇f‖ = 7.1313e-02, α = 1.00e+00, m = 12, nfg = 1 -[ Info: LBFGS: iter 15, Δt 7.11 s: f = -2.650602127531e+00, ‖∇f‖ = 9.3675e-02, α = 1.00e+00, m = 13, nfg = 1 -[ Info: LBFGS: iter 16, Δt 6.94 s: f = -2.652309117887e+00, ‖∇f‖ = 8.3679e-02, α = 1.00e+00, m = 14, nfg = 1 -[ Info: LBFGS: iter 17, Δt 7.16 s: f = -2.654182949559e+00, ‖∇f‖ = 9.5661e-02, α = 1.00e+00, m = 15, nfg = 1 -[ Info: LBFGS: iter 18, Δt 7.49 s: f = -2.655830713827e+00, ‖∇f‖ = 1.4282e-01, α = 1.00e+00, m = 16, nfg = 1 -[ Info: LBFGS: iter 19, Δt 7.23 s: f = -2.658506509688e+00, ‖∇f‖ = 8.6259e-02, α = 1.00e+00, m = 17, nfg = 1 -[ Info: LBFGS: iter 20, Δt 7.64 s: f = -2.660101929784e+00, ‖∇f‖ = 5.5569e-02, α = 1.00e+00, m = 18, nfg = 1 -[ Info: LBFGS: iter 21, Δt 6.90 s: f = -2.660655804151e+00, ‖∇f‖ = 5.0089e-02, α = 1.00e+00, m = 19, nfg = 1 -[ Info: LBFGS: iter 22, Δt 6.77 s: f = -2.661713763966e+00, ‖∇f‖ = 6.6021e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 23, Δt 7.52 s: f = -2.663782980193e+00, ‖∇f‖ = 1.4168e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 24, Δt 7.16 s: f = -2.664843902331e+00, ‖∇f‖ = 1.3559e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 25, Δt 7.53 s: f = -2.666211884109e+00, ‖∇f‖ = 6.7533e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 26, Δt 7.02 s: f = -2.666722962130e+00, ‖∇f‖ = 5.1877e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 27, Δt 7.53 s: f = -2.667030602502e+00, ‖∇f‖ = 4.7362e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 28, Δt 7.18 s: f = -2.668170280191e+00, ‖∇f‖ = 5.6312e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 29, Δt 7.54 s: f = -2.668423712729e+00, ‖∇f‖ = 1.1943e-01, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 30, Δt 7.17 s: f = -2.669339626497e+00, ‖∇f‖ = 4.0858e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 31, Δt 7.49 s: f = -2.669607082478e+00, ‖∇f‖ = 3.0582e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 32, Δt 6.99 s: f = -2.669888660598e+00, ‖∇f‖ = 3.6474e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 33, Δt 7.62 s: f = -2.670409252201e+00, ‖∇f‖ = 5.7241e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 34, Δt 7.24 s: f = -2.670955657881e+00, ‖∇f‖ = 6.0849e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 35, Δt 7.57 s: f = -2.671400731193e+00, ‖∇f‖ = 4.4891e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 36, Δt 7.01 s: f = -2.671654809276e+00, ‖∇f‖ = 2.3662e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 37, Δt 7.38 s: f = -2.671805678430e+00, ‖∇f‖ = 2.3809e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 38, Δt 6.97 s: f = -2.672069404251e+00, ‖∇f‖ = 3.7660e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 39, Δt 7.29 s: f = -2.672392002437e+00, ‖∇f‖ = 4.6077e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 40, Δt 6.99 s: f = -2.672631813806e+00, ‖∇f‖ = 2.8973e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 41, Δt 7.42 s: f = -2.672757659661e+00, ‖∇f‖ = 2.0266e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 42, Δt 6.29 s: f = -2.672874991777e+00, ‖∇f‖ = 2.3891e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 43, Δt 6.72 s: f = -2.673085962228e+00, ‖∇f‖ = 3.1468e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 44, Δt 6.38 s: f = -2.673264939913e+00, ‖∇f‖ = 5.1073e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 45, Δt 6.77 s: f = -2.673441648495e+00, ‖∇f‖ = 2.2047e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 46, Δt 6.31 s: f = -2.673518600682e+00, ‖∇f‖ = 1.6760e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 47, Δt 6.72 s: f = -2.673610627656e+00, ‖∇f‖ = 2.1357e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 48, Δt 6.49 s: f = -2.673749851382e+00, ‖∇f‖ = 3.0805e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 49, Δt 6.83 s: f = -2.673964407099e+00, ‖∇f‖ = 2.8044e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 50, Δt 6.54 s: f = -2.674085306498e+00, ‖∇f‖ = 3.7187e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 51, Δt 6.70 s: f = -2.674190416395e+00, ‖∇f‖ = 1.7204e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 52, Δt 6.90 s: f = -2.674244147958e+00, ‖∇f‖ = 1.4388e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 53, Δt 6.69 s: f = -2.674308492367e+00, ‖∇f‖ = 1.8135e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 54, Δt 6.99 s: f = -2.674434142909e+00, ‖∇f‖ = 2.0460e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 55, Δt 13.65 s: f = -2.674482027661e+00, ‖∇f‖ = 2.0923e-02, α = 3.35e-01, m = 20, nfg = 2 -[ Info: LBFGS: iter 56, Δt 6.68 s: f = -2.674544061262e+00, ‖∇f‖ = 1.1687e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 57, Δt 7.07 s: f = -2.674594606079e+00, ‖∇f‖ = 1.2128e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 58, Δt 6.64 s: f = -2.674646184030e+00, ‖∇f‖ = 1.7080e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 59, Δt 7.11 s: f = -2.674708616316e+00, ‖∇f‖ = 1.4174e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 60, Δt 6.76 s: f = -2.674768771588e+00, ‖∇f‖ = 1.4598e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 61, Δt 7.12 s: f = -2.674820230487e+00, ‖∇f‖ = 1.9700e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 62, Δt 6.68 s: f = -2.674864015912e+00, ‖∇f‖ = 1.5491e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 63, Δt 6.87 s: f = -2.674936674188e+00, ‖∇f‖ = 1.4360e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 64, Δt 6.57 s: f = -2.674957688553e+00, ‖∇f‖ = 2.0196e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 65, Δt 6.80 s: f = -2.674990714506e+00, ‖∇f‖ = 1.0037e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 66, Δt 6.30 s: f = -2.675007817715e+00, ‖∇f‖ = 9.4268e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 67, Δt 6.97 s: f = -2.675032496794e+00, ‖∇f‖ = 1.1461e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 68, Δt 6.68 s: f = -2.675089463603e+00, ‖∇f‖ = 1.4806e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 69, Δt 7.01 s: f = -2.675108881011e+00, ‖∇f‖ = 2.8465e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 70, Δt 6.60 s: f = -2.675166443058e+00, ‖∇f‖ = 1.1529e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 71, Δt 7.03 s: f = -2.675186479546e+00, ‖∇f‖ = 6.7512e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 72, Δt 6.69 s: f = -2.675204431516e+00, ‖∇f‖ = 8.4356e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 73, Δt 6.98 s: f = -2.675227128219e+00, ‖∇f‖ = 1.1948e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 74, Δt 6.74 s: f = -2.675257941898e+00, ‖∇f‖ = 1.3696e-02, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 75, Δt 7.10 s: f = -2.675283294818e+00, ‖∇f‖ = 9.3807e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 76, Δt 6.73 s: f = -2.675300545094e+00, ‖∇f‖ = 6.3181e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 77, Δt 7.08 s: f = -2.675312515675e+00, ‖∇f‖ = 8.9126e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 78, Δt 6.76 s: f = -2.675328270454e+00, ‖∇f‖ = 7.2766e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 79, Δt 7.09 s: f = -2.675354289574e+00, ‖∇f‖ = 7.6916e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 80, Δt 13.87 s: f = -2.675364316717e+00, ‖∇f‖ = 9.2305e-03, α = 4.61e-01, m = 20, nfg = 2 -[ Info: LBFGS: iter 81, Δt 6.72 s: f = -2.675376292963e+00, ‖∇f‖ = 6.5369e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 82, Δt 7.11 s: f = -2.675389682288e+00, ‖∇f‖ = 7.1072e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 83, Δt 6.63 s: f = -2.675405538777e+00, ‖∇f‖ = 9.7469e-03, α = 1.00e+00, m = 20, nfg = 1 -[ Info: LBFGS: iter 84, Δt 7.06 s: f = -2.675421118041e+00, ‖∇f‖ = 7.2757e-03, α = 1.00e+00, m = 20, nfg = 1 -┌ Warning: LBFGS: not converged to requested tol after 85 iterations and time 12.42 m: f = -2.675438005792e+00, ‖∇f‖ = 6.4678e-03 +[ Info: LBFGS: iter 2, Δt 45.67 s: f = -2.114273976569e+00, ‖∇f‖ = 2.9121e+00, α = 2.50e+01, m = 0, nfg = 4 +[ Info: LBFGS: iter 3, Δt 9.49 s: f = -2.218657558447e+00, ‖∇f‖ = 1.4788e+00, α = 1.00e+00, m = 1, nfg = 1 +[ Info: LBFGS: iter 4, Δt 28.19 s: f = -2.473597365661e+00, ‖∇f‖ = 1.2506e+00, α = 3.17e+00, m = 2, nfg = 3 +[ Info: LBFGS: iter 5, Δt 9.28 s: f = -2.546159342811e+00, ‖∇f‖ = 1.4463e+00, α = 1.00e+00, m = 3, nfg = 1 +[ Info: LBFGS: iter 6, Δt 7.74 s: f = -2.614645567632e+00, ‖∇f‖ = 4.0554e-01, α = 1.00e+00, m = 4, nfg = 1 +[ Info: LBFGS: iter 7, Δt 8.85 s: f = -2.622673934023e+00, ‖∇f‖ = 1.8054e-01, α = 1.00e+00, m = 5, nfg = 1 +[ Info: LBFGS: iter 8, Δt 7.07 s: f = -2.626310260611e+00, ‖∇f‖ = 1.7749e-01, α = 1.00e+00, m = 6, nfg = 1 +[ Info: LBFGS: iter 9, Δt 8.59 s: f = -2.632769137184e+00, ‖∇f‖ = 1.8586e-01, α = 1.00e+00, m = 7, nfg = 1 +[ Info: LBFGS: iter 10, Δt 6.53 s: f = -2.639694621494e+00, ‖∇f‖ = 2.2500e-01, α = 1.00e+00, m = 8, nfg = 1 +[ Info: LBFGS: iter 11, Δt 8.00 s: f = -2.644827934020e+00, ‖∇f‖ = 1.2801e-01, α = 1.00e+00, m = 9, nfg = 1 +[ Info: LBFGS: iter 12, Δt 5.91 s: f = -2.646459705819e+00, ‖∇f‖ = 6.7575e-02, α = 1.00e+00, m = 10, nfg = 1 +[ Info: LBFGS: iter 13, Δt 6.22 s: f = -2.647499600831e+00, ‖∇f‖ = 6.0731e-02, α = 1.00e+00, m = 11, nfg = 1 +[ Info: LBFGS: iter 14, Δt 7.75 s: f = -2.648703045894e+00, ‖∇f‖ = 7.1313e-02, α = 1.00e+00, m = 12, nfg = 1 +[ Info: LBFGS: iter 15, Δt 6.29 s: f = -2.650602127388e+00, ‖∇f‖ = 9.3675e-02, α = 1.00e+00, m = 13, nfg = 1 +[ Info: LBFGS: iter 16, Δt 7.53 s: f = -2.652309117542e+00, ‖∇f‖ = 8.3679e-02, α = 1.00e+00, m = 14, nfg = 1 +[ Info: LBFGS: iter 17, Δt 5.86 s: f = -2.654182949224e+00, ‖∇f‖ = 9.5661e-02, α = 1.00e+00, m = 15, nfg = 1 +[ Info: LBFGS: iter 18, Δt 7.49 s: f = -2.655830713358e+00, ‖∇f‖ = 1.4282e-01, α = 1.00e+00, m = 16, nfg = 1 +[ Info: LBFGS: iter 19, Δt 5.62 s: f = -2.658506508894e+00, ‖∇f‖ = 8.6260e-02, α = 1.00e+00, m = 17, nfg = 1 +[ Info: LBFGS: iter 20, Δt 5.98 s: f = -2.660101929403e+00, ‖∇f‖ = 5.5569e-02, α = 1.00e+00, m = 18, nfg = 1 +[ Info: LBFGS: iter 21, Δt 7.27 s: f = -2.660655802769e+00, ‖∇f‖ = 5.0089e-02, α = 1.00e+00, m = 19, nfg = 1 +[ Info: LBFGS: iter 22, Δt 5.69 s: f = -2.661713752636e+00, ‖∇f‖ = 6.6020e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 23, Δt 6.23 s: f = -2.663782967628e+00, ‖∇f‖ = 1.4168e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 24, Δt 7.11 s: f = -2.664843906404e+00, ‖∇f‖ = 1.3559e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 25, Δt 6.05 s: f = -2.666211885495e+00, ‖∇f‖ = 6.7533e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 26, Δt 7.18 s: f = -2.666722965867e+00, ‖∇f‖ = 5.1877e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 27, Δt 6.02 s: f = -2.667030607084e+00, ‖∇f‖ = 4.7362e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 28, Δt 7.70 s: f = -2.668170313888e+00, ‖∇f‖ = 5.6311e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 29, Δt 6.04 s: f = -2.668423708832e+00, ‖∇f‖ = 1.1943e-01, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 30, Δt 7.68 s: f = -2.669339639442e+00, ‖∇f‖ = 4.0859e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 31, Δt 5.65 s: f = -2.669607092068e+00, ‖∇f‖ = 3.0582e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 32, Δt 6.03 s: f = -2.669888674448e+00, ‖∇f‖ = 3.6474e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 33, Δt 7.56 s: f = -2.670409260559e+00, ‖∇f‖ = 5.7241e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 34, Δt 6.35 s: f = -2.670955670621e+00, ‖∇f‖ = 6.0848e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 35, Δt 7.45 s: f = -2.671400740936e+00, ‖∇f‖ = 4.4890e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 36, Δt 6.16 s: f = -2.671654819742e+00, ‖∇f‖ = 2.3662e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 37, Δt 7.47 s: f = -2.671805688410e+00, ‖∇f‖ = 2.3809e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 38, Δt 6.15 s: f = -2.672069418094e+00, ‖∇f‖ = 3.7660e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 39, Δt 7.50 s: f = -2.672391998692e+00, ‖∇f‖ = 4.6082e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 40, Δt 6.15 s: f = -2.672631813229e+00, ‖∇f‖ = 2.8972e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 41, Δt 7.60 s: f = -2.672757646725e+00, ‖∇f‖ = 2.0266e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 42, Δt 5.76 s: f = -2.672874968531e+00, ‖∇f‖ = 2.3891e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 43, Δt 6.09 s: f = -2.673085935987e+00, ‖∇f‖ = 3.1467e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 44, Δt 7.17 s: f = -2.673264955042e+00, ‖∇f‖ = 5.1067e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 45, Δt 6.11 s: f = -2.673441653001e+00, ‖∇f‖ = 2.2050e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 46, Δt 7.64 s: f = -2.673518614777e+00, ‖∇f‖ = 1.6760e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 47, Δt 6.03 s: f = -2.673610642660e+00, ‖∇f‖ = 2.1356e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 48, Δt 7.60 s: f = -2.673749855167e+00, ‖∇f‖ = 3.0804e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 49, Δt 6.08 s: f = -2.673964481832e+00, ‖∇f‖ = 2.8038e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 50, Δt 6.24 s: f = -2.674085336827e+00, ‖∇f‖ = 3.7211e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 51, Δt 7.20 s: f = -2.674190542900e+00, ‖∇f‖ = 1.7211e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 52, Δt 6.09 s: f = -2.674244307002e+00, ‖∇f‖ = 1.4385e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 53, Δt 7.45 s: f = -2.674308652203e+00, ‖∇f‖ = 1.8132e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 54, Δt 6.28 s: f = -2.674434242130e+00, ‖∇f‖ = 2.0442e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 55, Δt 13.84 s: f = -2.674482156825e+00, ‖∇f‖ = 2.0921e-02, α = 3.35e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 56, Δt 7.94 s: f = -2.674544199355e+00, ‖∇f‖ = 1.1684e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 57, Δt 5.86 s: f = -2.674594731099e+00, ‖∇f‖ = 1.2135e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 58, Δt 6.35 s: f = -2.674646300923e+00, ‖∇f‖ = 1.7065e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 59, Δt 7.54 s: f = -2.674708781785e+00, ‖∇f‖ = 1.4159e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 60, Δt 6.33 s: f = -2.674769125064e+00, ‖∇f‖ = 1.4517e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 61, Δt 7.79 s: f = -2.674820428656e+00, ‖∇f‖ = 1.9999e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 62, Δt 6.10 s: f = -2.674864524466e+00, ‖∇f‖ = 1.5512e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 63, Δt 8.24 s: f = -2.674936594389e+00, ‖∇f‖ = 1.4904e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 64, Δt 6.26 s: f = -2.674955282643e+00, ‖∇f‖ = 1.9377e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 65, Δt 7.47 s: f = -2.674989475402e+00, ‖∇f‖ = 1.0749e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 66, Δt 5.94 s: f = -2.675008560457e+00, ‖∇f‖ = 9.3873e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 67, Δt 7.63 s: f = -2.675035121673e+00, ‖∇f‖ = 1.0893e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 68, Δt 5.88 s: f = -2.675093424988e+00, ‖∇f‖ = 1.5948e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 69, Δt 13.66 s: f = -2.675123092585e+00, ‖∇f‖ = 1.8297e-02, α = 5.07e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 70, Δt 6.11 s: f = -2.675158145862e+00, ‖∇f‖ = 1.0411e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 71, Δt 8.91 s: f = -2.675184397098e+00, ‖∇f‖ = 7.5551e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 72, Δt 6.70 s: f = -2.675202127278e+00, ‖∇f‖ = 1.0326e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 73, Δt 9.29 s: f = -2.675232074331e+00, ‖∇f‖ = 1.0276e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 74, Δt 15.73 s: f = -2.675249906405e+00, ‖∇f‖ = 1.7745e-02, α = 3.56e-01, m = 20, nfg = 2 +[ Info: LBFGS: iter 75, Δt 6.61 s: f = -2.675277747740e+00, ‖∇f‖ = 8.6877e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 76, Δt 6.90 s: f = -2.675295012134e+00, ‖∇f‖ = 5.9675e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 77, Δt 9.00 s: f = -2.675309457155e+00, ‖∇f‖ = 8.1916e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 78, Δt 6.50 s: f = -2.675327390804e+00, ‖∇f‖ = 1.1679e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 79, Δt 8.11 s: f = -2.675346033915e+00, ‖∇f‖ = 7.3995e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 80, Δt 6.22 s: f = -2.675361840744e+00, ‖∇f‖ = 6.2470e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 81, Δt 7.71 s: f = -2.675372633878e+00, ‖∇f‖ = 1.0378e-02, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 82, Δt 6.16 s: f = -2.675385864468e+00, ‖∇f‖ = 7.9203e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 83, Δt 8.23 s: f = -2.675408682962e+00, ‖∇f‖ = 5.6544e-03, α = 1.00e+00, m = 20, nfg = 1 +[ Info: LBFGS: iter 84, Δt 6.10 s: f = -2.675422272234e+00, ‖∇f‖ = 7.8184e-03, α = 1.00e+00, m = 20, nfg = 1 +┌ Warning: LBFGS: not converged to requested tol after 85 iterations and time 18.43 m: f = -2.675439882383e+00, ‖∇f‖ = 7.8348e-03 └ @ OptimKit ~/.julia/packages/OptimKit/OEwMx/src/lbfgs.jl:199 -E / prod(size(lattice)) = -0.6688595014480129 +E / prod(size(lattice)) = -0.6688599705957462 ```` diff --git a/docs/src/examples/xxz/main.ipynb b/docs/src/examples/xxz/main.ipynb index f015a4dbe..319cc86e2 100644 --- a/docs/src/examples/xxz/main.ipynb +++ b/docs/src/examples/xxz/main.ipynb @@ -1,16 +1,17 @@ { "cells": [ { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Markdown #hide" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# Néel order in the $U(1)$-symmetric XXZ model\n", "\n", @@ -27,34 +28,35 @@ "PEPS and CTMRG environments. For simplicity, we will consider spin-$1/2$ operators.\n", "\n", "But first, let's make this example deterministic and import the required packages:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "using Random\n", "using TensorKit, PEPSKit\n", "using MPSKit: add_physical_charge\n", "Random.seed!(2928528935);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Constructing the model\n", "\n", "Let us define the $U(1)$-symmetric XXZ Hamiltonian on a $2 \\times 2$ unit cell with the\n", "parameters:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "J = 1.0\n", "Delta = 1.0\n", @@ -62,34 +64,33 @@ "symmetry = U1Irrep\n", "lattice = InfiniteSquare(2, 2)\n", "H₀ = heisenberg_XXZ(ComplexF64, symmetry, lattice; J, Delta, spin);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "This ensures that our PEPS ansatz can support the bipartite Néel order. As discussed above,\n", "we encode the Néel order directly in the ansatz by adding staggered auxiliary physical\n", "charges:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "S_aux = [\n", " U1Irrep(-1 // 2) U1Irrep(1 // 2)\n", " U1Irrep(1 // 2) U1Irrep(-1 // 2)\n", "]\n", "H = add_physical_charge(H₀, S_aux);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Specifying the symmetric virtual spaces\n", "\n", @@ -99,70 +100,70 @@ "symmetry sector. From the virtual spaces, we will need to construct a unit cell (a matrix)\n", "of spaces which will be supplied to the PEPS constructor. The same is true for the physical\n", "spaces, which can be extracted directly from the Hamiltonian `LocalOperator`:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "V_peps = U1Space(0 => 2, 1 => 1, -1 => 1)\n", "V_env = U1Space(0 => 6, 1 => 4, -1 => 4, 2 => 2, -2 => 2)\n", "virtual_spaces = fill(V_peps, size(lattice)...)\n", "physical_spaces = physicalspace(H)" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Ground state search\n", "\n", "From this point onwards it's business as usual: Create an initial PEPS and environment\n", "(using the symmetric spaces), specify the algorithmic parameters and optimize:" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, trunc = (; alg = :fixedspace))\n", - "gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :diffgauge)\n", + "gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :fixed)\n", "optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, maxiter = 85, ls_maxiter = 3, ls_maxfg = 3)\n", "\n", "peps₀ = InfinitePEPS(randn, ComplexF64, physical_spaces, virtual_spaces)\n", "env₀, = leading_boundary(CTMRGEnv(peps₀, V_env), peps₀; boundary_alg...);" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Finally, we can optimize the PEPS with respect to the XXZ Hamiltonian and check the\n", "resulting ground state energy per site using our $(2 \\times 2)$ unit cell. Note that the\n", "optimization might take a while since precompilation of symmetric AD code takes longer and\n", "because symmetric tensors do create a bit of overhead (which does pay off at larger bond and\n", "environment dimensions):" - ], - "metadata": {} + ] }, { - "outputs": [], "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "peps, env, E, info = fixedpoint(\n", " H, peps₀, env₀; boundary_alg, gradient_alg, optimizer_alg, verbosity = 3\n", ")\n", "@show E / prod(size(lattice));" - ], - "metadata": {}, - "execution_count": null + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Note that for the specified parameters $J = \\Delta = 1$, we simulated the same Hamiltonian\n", "as in the Heisenberg example. In that example, with a\n", @@ -170,32 +171,31 @@ "$E_\\text{D=2} = -0.6625\\dots$. Again comparing against [Sandvik's](@cite\n", "sandvik_computational_2011) accurate QMC estimate $E_{\\text{ref}}=−0.6694421$, we see that\n", "we already got closer to the reference energy." - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "---\n", "\n", "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" - ], - "metadata": {} + ] } ], - "nbformat_minor": 3, "metadata": { + "kernelspec": { + "display_name": "Julia 1.12.5", + "language": "julia", + "name": "julia-1.12" + }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.12.5" - }, - "kernelspec": { - "name": "julia-1.12", - "display_name": "Julia 1.12.5", - "language": "julia" } }, - "nbformat": 4 + "nbformat": 4, + "nbformat_minor": 3 } \ No newline at end of file diff --git a/examples/3d_ising_partition_function/main.jl b/examples/3d_ising_partition_function/main.jl index 222989330..51747f7ec 100644 --- a/examples/3d_ising_partition_function/main.jl +++ b/examples/3d_ising_partition_function/main.jl @@ -152,7 +152,8 @@ of this cost function. boundary_alg = SimultaneousCTMRG(; maxiter = 150, tol = 1.0e-8, verbosity = 1) rrule_alg = EigSolver(; - solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true), iterscheme = :diffgauge + solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true), + iterscheme = :fixed, ) T = InfinitePEPO(O) diff --git a/examples/Cache.toml b/examples/Cache.toml index 0efc83e68..ee31b89a4 100644 --- a/examples/Cache.toml +++ b/examples/Cache.toml @@ -2,10 +2,10 @@ boundary_mps = "e935558f16247ba5532ce1e2fa5577574d75d9818ab9863775ff6b97a920affb heisenberg_su = "20949c9f88410a30de2e79b15c1af47dfa87be4b0203b99f703b757220d9497b" bose_hubbard = "a006cc5ed863ce0a31b47ccfe861d4830157ddf0de6bacab03fcb5ba5ea348aa" c4v_ctmrg = "75669dae8280d608fa83612bb44b2b28a28ef3297ff16d69fba2a216a1ca9697" -j1j2_su = "9fb021d1cc62fc2ca7447d53e277f784f9fb17d285063f52bcfd8d74e0101b9c" +j1j2_su = "185d7e0475c2020fe86814537d648115c53770991a18d8ba941fb154308e8a70" hubbard_su = "8060c867a1b50753f8482c5fc217c9ec12f6af4b9710fc6aefbd9d812edb218f" heisenberg = "80bb9cc57ed85297b1b789a6c5f09494dac81b23631f48c6600ede9424c5d248" 2d_ising_partition_function = "043e1b0b97197ed611559f4a4683cb8f166c01af82a97f71364f2f5421abe3d2" -3d_ising_partition_function = "baf05623f2b0c496393892be1dfe5c7f72af94ac8c1158db9af5c1aae816c264" -xxz = "0231f0c1af2013e8edd9e5c192b108e1ab19a7dca22251c3bde525e3eee2a6aa" -fermi_hubbard = "4997680c826e555557c661e605e1d7d363e0cee15522d0895fa0cfd53b1de001" +3d_ising_partition_function = "933663904d0652218951111d9c6c128ee03c1e8e3dd7c8c97177c15de9d74aef" +xxz = "b48824c6f56be5c6d113e25097ebc515c982907982d32a123f294e62c38b9e19" +fermi_hubbard = "9651a02a27d1a88dd96c3f1892a56ec7d5b5ec83edfb8feab65ab94c623de2bb" diff --git a/examples/fermi_hubbard/main.jl b/examples/fermi_hubbard/main.jl index 247e288d6..0517bc7c3 100644 --- a/examples/fermi_hubbard/main.jl +++ b/examples/fermi_hubbard/main.jl @@ -71,7 +71,7 @@ define all algorithmic parameters: """ boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, trunc = (; alg = :fixedspace)) -gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :diffgauge) +gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :fixed) optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, maxiter = 80, ls_maxiter = 3, ls_maxfg = 3) md""" diff --git a/examples/j1j2_su/main.jl b/examples/j1j2_su/main.jl index 4e4be49c0..acb201084 100644 --- a/examples/j1j2_su/main.jl +++ b/examples/j1j2_su/main.jl @@ -20,7 +20,7 @@ We first import all required modules and seed the RNG: using Random using TensorKit, PEPSKit -Random.seed!(29385293); +Random.seed!(29385294); md""" ## Simple updating a challenging phase @@ -108,6 +108,12 @@ the already evolved `peps`, thus giving us a physical initial guess for the opti In order to break some of the $C_{4v}$ symmetry of the PEPS, we will add a bit of noise to it. This is conviently done using MPSKit's `randomize!` function. (Breaking some of the spatial symmetry can be advantageous for obtaining lower energies.) + +In our optimization, we will use a fixed-point differentiation scheme which requires a +gauge fixing of the contraction environment +(specified by the `gradient_alg = (; iterscheme = :fixed)` setting). +Since this gauge fixing involves potentially complex phases, we have to convert our +real-valued contraction environment to complex numbers before the optimization. """ using MPSKit: randomize! @@ -115,8 +121,8 @@ using MPSKit: randomize! noise_peps = InfinitePEPS(randomize!.(deepcopy(peps.A))) peps₀ = peps + 1.0e-1noise_peps peps_opt, env_opt, E_opt, = fixedpoint( - H, peps₀, env; - optimizer_alg = (; tol = 1.0e-4, maxiter = 80), gradient_alg = (; iterscheme = :diffgauge) + H, peps₀, complex(env); + optimizer_alg = (; tol = 1.0e-4, maxiter = 80), gradient_alg = (; iterscheme = :fixed) ); md""" diff --git a/examples/xxz/main.jl b/examples/xxz/main.jl index 4980cefa5..234b0479f 100644 --- a/examples/xxz/main.jl +++ b/examples/xxz/main.jl @@ -72,7 +72,7 @@ From this point onwards it's business as usual: Create an initial PEPS and envir """ boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, trunc = (; alg = :fixedspace)) -gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :diffgauge) +gradient_alg = (; tol = 1.0e-6, alg = :eigsolver, maxiter = 10, iterscheme = :fixed) optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, maxiter = 85, ls_maxiter = 3, ls_maxfg = 3) peps₀ = InfinitePEPS(randn, ComplexF64, physical_spaces, virtual_spaces) diff --git a/src/Defaults.jl b/src/Defaults.jl index a0b2e9731..392a37743 100644 --- a/src/Defaults.jl +++ b/src/Defaults.jl @@ -22,30 +22,40 @@ Module containing default algorithm parameter values and arguments. - `:truncrank` : Additionally supply truncation dimension `η`; truncate such that the 2-norm of the truncated values is smaller than `η` - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space - `:trunctol` : Additionally supply singular value cutoff `η`; truncate such that every retained singular value is larger than `η` -* `rrule_degeneracy_atol=$(Defaults.rrule_degeneracy_atol)` : Broadening amplitude which smoothens the divergent term in the retained contributions of an SVD or eigh pullback, in case of (pseudo) degenerate singular values +* `rrule_degeneracy_atol=$(Defaults.rrule_degeneracy_atol)` : Broadening amplitude which + smoothens the divergent term in the retained contributions of an SVD or eigh pullback, in + case of (pseudo) degenerate singular values * `svd_fwd_alg=:$(Defaults.svd_fwd_alg)` : SVD algorithm that is used in the forward pass. - - `:sdd` : MatrixAlgebraKit's `LAPACK_DivideAndConquer` - - `:svd` : MatrixAlgebraKit's `LAPACK_QRIteration` - - `:iterative` : Iterative SVD only computing the specifed number of singular values and vectors, see [`IterSVD`](@ref PEPSKit.IterSVD) + - `:DefaultAlgorithm` : MatrixAlgebraKit's default SVD algorithm for a given matrix type. + - `:DivideAndConquer` : MatrixAlgebraKit's [`DivideAndConquer`](@extref MatrixAlgebraKit.DivideAndConquer) + - `:QRIteration` : MatrixAlgebraKit's [`QRIteration`](@extref MatrixAlgebraKit.QRIteration) + - `:Bisection` : MatrixAlgebraKit's [`Bisection`](@extref MatrixAlgebraKit.Bisection) + - `:Jacobi` : MatrixAlgebraKit's [`Jacobi`](@extref MatrixAlgebraKit.Jacobi) + - `:SVDViaPolar` : MatrixAlgebraKit's [`SVDViaPolar`](@extref MatrixAlgebraKit.SVDViaPolar) + - `:SafeDivideAndConquer` : MatrixAlgebraKit's [`SafeDivideAndConquer`](@extref MatrixAlgebraKit.SafeDivideAndConquer) + - `:iterative` : Iterative Krylov-based SVD only computing the specifed number of + singular values and vectors, see [`IterSVD`](@ref PEPSKit.IterSVD) for details. * `svd_rrule_tol=$(Defaults.svd_rrule_tol)` : Accuracy of SVD reverse-rule. * `svd_rrule_min_krylovdim=$(Defaults.svd_rrule_min_krylovdim)` : Minimal Krylov dimension of the reverse-rule algorithm (if it is a Krylov algorithm). * `svd_rrule_verbosity=$(Defaults.svd_rrule_verbosity)` : SVD gradient output verbosity. * `svd_rrule_alg=:$(Defaults.svd_rrule_alg)` : Reverse-rule algorithm for the SVD gradient. - - `:full` : Uses a modified version of MatrixAlgebraKit's reverse-rule for `svd_compact` which doesn't solve any linear problem and instead requires access to the full SVD, see [`PEPSKit.FullSVDPullback`](@ref). - - `:trunc` : MatrixAlgebraKit's `svd_trunc_pullback!` solving a Sylvester equation on the truncated subspace and therefore only requires access to the truncated SVD. - - `:gmres` : GMRES iterative linear solver, see the [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.GMRES) for details - - `:bicgstab` : BiCGStab iterative linear solver, see the [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.BiCGStab) for details - - `:arnoldi` : Arnoldi Krylov algorithm, see the [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.Arnoldi) for details + - `:full` : MatrixAlgebraKit's [`svd_pullback!`](@extref MatrixAlgebraKit.svd_pullback!) that requires access to the full spectrum + - `:trunc` : MatrixAlgebraKit's [`svd_trunc_pullback!`](@extref MatrixAlgebraKit.svd_trunc_pullback!) solving a Sylvester equation on the truncated subspace + - `:gmres` : GMRES iterative linear solver, see [`KrylovKit.GMRES`](@extref) + - `:bicgstab` : BiCGStab iterative linear solver, see [`KrylovKit.BiCGStab`](@extref) + - `:arnoldi` : Arnoldi Krylov algorithm, see the [`KrylovKit.Arnoldi`](@extref) ## `eigh` forward & reverse * `eigh_fwd_alg=:$(Defaults.eigh_fwd_alg)` : `eigh` algorithm that is used in the forward pass. - - `:qriteration` : MatrixAlgebraKit's `LAPACK_QRIteration`. - - `:bisection` : MatrixAlgebraKit's `LAPACK_Bisection`. - - `:divideandconquer` : MatrixAlgebraKit's `LAPACK_DivideAndConquer`. - - `:multiple` : MatrixAlgebraKit's `LAPACK_MultipleRelativelyRobustRepresentations`. - - `:lanczos` : Lanczos algorithm, see [`KrylovKit.Lanczos`](@extref) for details. - - `:blocklanczos` : Block Lanczos algorithm, see [`KrylovKit.BlockLanczos`](@extref) for details. + - `:DefaultAlgorithm` : MatrixAlgebraKit's default Eigh algorithm for a given matrix type. + - `:DivideAndConquer` : MatrixAlgebraKit's [`DivideAndConquer`](@extref MatrixAlgebraKit.DivideAndConquer) + - `:QRIteration` : MatrixAlgebraKit's [`QRIteration`](@extref MatrixAlgebraKit.QRIteration) + - `:Bisection` : MatrixAlgebraKit's [`Bisection`](@extref MatrixAlgebraKit.Bisection) + - `:Jacobi` : MatrixAlgebraKit's [`Jacobi`](@extref MatrixAlgebraKit.Jacobi) + - `:RobustRepresentations` : MatrixAlgebraKit's [`RobustRepresentations`](@extref MatrixAlgebraKit.RobustRepresentations) + - `:Lanczos` : Lanczos algorithm for symmetric/Hermitian matrices, see [`KrylovKit.Lanczos`](@extref) + - `:BlockLanczos` : Block version of `:Lanczos` for repeated extremal eigenvalues, see [`KrylovKit.BlockLanczos`](@extref) * `eigh_rrule_alg=:$(Defaults.eigh_rrule_alg)` : Reverse-rule algorithm for the `eigh` gradient. - `:full` : Full pullback algorithm for eigendecompositions, see [`PEPSKit.FullEighPullback`](@ref). - `:trunc` : Truncated reverse-mode algorithm for eigendecompositions, see [`PEPSKit.TruncEighPullback`](@ref). @@ -57,6 +67,9 @@ Module containing default algorithm parameter values and arguments. - `:halfinfinite` : Projection via SVDs of half-infinite (two enlarged corners) CTMRG environments. - `:fullinfinite` : Projection via SVDs of full-infinite (all four enlarged corners) CTMRG environments. * `projector_verbosity=$(Defaults.projector_verbosity)` : Projector output information verbosity. +* `projector_alg_c4v=:$(Defaults.projector_alg_c4v)` : Default variant of the C4v CTMRG projector algorithm. + - `:c4v_eigh` : Projection via truncated Eigh of an enlarged corner. + - `:c4v_qr` : Projection via QR decomposition of a column-enlarged corner. ## Fixed-point gradient @@ -109,7 +122,7 @@ const sparse = false # TODO: implement sparse CTMRG # SVD forward & reverse const trunc = :fixedspace # ∈ {:fixedspace, :notrunc, :truncerror, :truncspace, :trunctol} const rrule_degeneracy_atol = 1.0e-13 -const svd_fwd_alg = :sdd # ∈ {:sdd, :svd, :bisection, :jacobi, :iterative} +const svd_fwd_alg = :DefaultAlgorithm # ∈ {:, :iterative} const svd_rrule_tol = ctmrg_tol const svd_rrule_min_krylovdim = 48 const svd_rrule_verbosity = -1 @@ -117,12 +130,12 @@ const svd_rrule_alg = :full # ∈ {:full, :trunc, :gmres, :bicgstab, :arnoldi} const krylovdim_factor = 1.4 # eigh forward & reverse -const eigh_fwd_alg = :qriteration # ∈ {:qriteration, :bisection, :divideandconquer, :multiple, :lanczos, :blocklanczos} +const eigh_fwd_alg = :DefaultAlgorithm # ∈ {:, :Lanczos, :BlockLanczos} const eigh_rrule_alg = :full # ∈ {:full, :trunc} const eigh_rrule_verbosity = 0 # QR forward & reverse -const qr_fwd_alg = :qr +const qr_fwd_alg = :Householder const qr_fwd_positive = true const qr_rrule_alg = :qr const qr_rrule_verbosity = 0 @@ -130,7 +143,7 @@ const qr_rrule_verbosity = 0 # Projectors const projector_alg = :halfinfinite # ∈ {:halfinfinite, :fullinfinite} const projector_verbosity = 0 -const projector_alg_c4v = :c4v_eigh # ∈ {:c4v_eigh, :c4v_qr (TODO)} +const projector_alg_c4v = :c4v_eigh # ∈ {:c4v_eigh, :c4v_qr} # Fixed-point gradient const gradient_tol = 1.0e-6 diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index f1c537ee6..3c950af33 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -8,10 +8,10 @@ using VectorInterface import VectorInterface as VI using MatrixAlgebraKit -using MatrixAlgebraKit: LAPACK_DivideAndConquer, LAPACK_QRIteration using MatrixAlgebraKit: TruncationStrategy, NoTruncation, truncate, findtruncated, truncation_error, diagview -using MatrixAlgebraKit: LAPACK_EighAlgorithm, eigh_pullback!, eigh_trunc_pullback! +using MatrixAlgebraKit: TruncatedAlgorithm +using MatrixAlgebraKit: eigh_pullback!, eigh_trunc_pullback! using MatrixAlgebraKit: svd_pullback!, svd_trunc_pullback! using TensorKit diff --git a/src/algorithms/ctmrg/c4v.jl b/src/algorithms/ctmrg/c4v.jl index fa0b7650f..777bd4b27 100644 --- a/src/algorithms/ctmrg/c4v.jl +++ b/src/algorithms/ctmrg/c4v.jl @@ -21,7 +21,7 @@ For a full description, see [`leading_boundary`](@ref). The supported keywords a * `miniter::Int=$(Defaults.ctmrg_miniter)` * `verbosity::Int=$(Defaults.ctmrg_verbosity)` * `trunc::Union{TruncationStrategy,NamedTuple}=(; alg::Symbol=:$(Defaults.trunc))` -* `decomposition_alg::Union{<:EighAdjoint,NamedTuple}` +* `decomposition_alg::Union{NamedTuple,<:EighAdjoint,<:QRAdjoint}=(;)` * `projector_alg::Symbol=:$(Defaults.projector_alg_c4v)` """ struct C4vCTMRG{P <: ProjectorAlgorithm} <: CTMRGAlgorithm @@ -99,8 +99,11 @@ function C4vQRProjector(; kwargs...) end PROJECTOR_SYMBOLS[:c4v_qr] = C4vQRProjector +decomposition_algorithm(alg::C4vQRProjector) = alg.decomposition_alg + # no truncation _set_truncation(alg::C4vQRProjector, ::TruncationStrategy) = alg +_set_decomposition_truncation(alg::C4vQRProjector, ::TruncationStrategy) = alg function check_input( ::typeof(leading_boundary), network::InfiniteSquareNetwork, env::CTMRGEnv, alg::C4vCTMRG; atol = 1.0e-10 @@ -144,8 +147,8 @@ function ctmrg_iteration( corner′, projector, info = c4v_projector!(enlarged_corner, alg.projector_alg) edge′ = c4v_renormalize_edge(network, env, projector) info = (; - contraction_metrics = (; info.truncation_error, info.condition_number), - info.D, info.V, info.D_full, info.V_full, info.truncation_indices, + contraction_metrics = (; info.truncation_error), + info.D, info.V, ) return CTMRGEnv(corner′, edge′), info end @@ -189,8 +192,10 @@ Compute the C₄ᵥ projector from `eigh` decomposing the Hermitian `enlarged_co Also return the normalized eigenvalues as the new corner tensor. """ function c4v_projector!(enlarged_corner, alg::C4vEighProjector) - trunc = truncation_strategy(alg, enlarged_corner) - D, V, info = eigh_trunc!(enlarged_corner, decomposition_algorithm(alg); trunc) + alg = _set_decomposition_truncation(alg, truncation_strategy(alg, enlarged_corner)) + eigh_alg = decomposition_algorithm(alg) + + D, V, truncation_error = eigh_trunc!(enlarged_corner, eigh_alg) # Check for degenerate eigenvalues Zygote.isderiving() && ignore_derivatives() do @@ -200,7 +205,7 @@ function c4v_projector!(enlarged_corner, alg::C4vEighProjector) end end - return D / norm(D), V, (; D, V, info...) + return D / norm(D), V, (; D, V, truncation_error) end """ c4v_projector!(enlarged_corner, alg::C4vQRProjector) @@ -216,7 +221,7 @@ Compute the C₄ᵥ projector by decomposing the column-enlarged corner with `le function c4v_projector!(enlarged_corner, alg::C4vQRProjector) Q, R = left_orth!(enlarged_corner, decomposition_algorithm(alg)) # TODO: what's a meaningful way to compute a truncation error/condition number in this scheme? - return Q, (; Q, R, truncation_error = zero(scalartype(Q)), condition_number = 0) + return Q, (; Q, R, truncation_error = zero(scalartype(Q))) end """ diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index 839e32a43..b8f20c905 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -8,6 +8,7 @@ abstract type CTMRGAlgorithm end const CTMRG_SYMBOLS = IdDict{Symbol, Type{<:CTMRGAlgorithm}}() + """ CTMRGAlgorithm(; kwargs...) @@ -30,6 +31,10 @@ function CTMRGAlgorithm(; if alg == :c4v && projector_alg == Defaults.projector_alg projector_alg = Defaults.projector_alg_c4v end + # check for full decomposition algorithm specification, otherwise interpret as forward alg + if decomposition_alg isa NamedTuple + decomposition_alg = (; fwd_alg = decomposition_alg) + end projector_algorithm = ProjectorAlgorithm(; alg = projector_alg, decomposition_alg, trunc, verbosity ) @@ -79,12 +84,16 @@ supplied via the keyword arguments or directly as an [`CTMRGAlgorithm`](@ref) st - `:truncrank` : Additionally supply truncation dimension `η`; truncate such that the 2-norm of the truncated values is smaller than `η` - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space - `:trunctol` : Additionally supply singular value cutoff `η`; truncate such that every retained singular value is larger than `η` -* `decomposition_alg` : Tensor decomposition algorithm for computing projectors. See e.g. [`SVDAdjoint`](@ref). * `projector_alg::Symbol=:$(Defaults.projector_alg)` : Variant of the projector algorithm. See also [`ProjectorAlgorithm`](@ref). - `:halfinfinite` : Projection via SVDs of half-infinite (two enlarged corners) CTMRG environments. - `:fullinfinite` : Projection via SVDs of full-infinite (all four enlarged corners) CTMRG environments. - `:c4v_eigh` : Projection via `eigh` of the Hermitian enlarged corner, works only for [`C4vCTMRG`](@ref). - `:c4v_qr` : Projection via QR decomposition of the lower-rank column-enlarged corner, works only for [`C4vCTMRG`](@ref). +* `decomposition_alg::Union{NamedTuple,<:SVDAdjoint,<:EighAdjoint,<:QRAdjoint}` : Tensor + decomposition algorithm used for computing projectors. When specified as a `NamedTuple`, + the settings are passed a the forward algorithm to the appropriate decomposition + for the given projector algorithm. For information on which forward algorithms are + available, and how to specify them, see [`SVDAdjoint`](@ref), [`EighAdjoint`](@ref) and [`QRAdjoint`](@ref). ## Return values diff --git a/src/algorithms/ctmrg/gaugefix.jl b/src/algorithms/ctmrg/gaugefix.jl index afab216c8..9d238cafc 100644 --- a/src/algorithms/ctmrg/gaugefix.jl +++ b/src/algorithms/ctmrg/gaugefix.jl @@ -1,20 +1,3 @@ -""" - gauge_fix(alg::CTMRGAlgorithm, signs, info) - gauge_fix(alg::ProjectorAlgorithm, signs, info) - -Fix the free gauges of the tensor decompositions associated with `alg`. -""" -function gauge_fix(alg::CTMRGAlgorithm, signs, info) - alg_fixed = @set alg.projector_alg = gauge_fix(alg.projector_alg, signs, info) - return alg_fixed -end -function gauge_fix(alg::ProjectorAlgorithm, signs, info) - decomposition_alg_fixed = gauge_fix(decomposition_algorithm(alg), signs, info) - alg_fixed = @set alg.decomposition_alg = decomposition_alg_fixed # every ProjectorAlgorithm needs an `decomposition_alg` field? - alg_fixed = _set_truncation(alg_fixed, notrunc()) # potentially set no truncation - return alg_fixed -end - # TODO: add eigensolver algorithm, verbosity to gauge algorithm structs """ $(TYPEDEF) @@ -43,13 +26,43 @@ This assumes that the `envfinal` is the result of one CTMRG iteration on `envpre Given that the CTMRG run is converged, the returned environment will be element-wise converged to `envprev`. """ -function gauge_fix(envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, ::ScramblingEnvGauge) where {C, T} +function gauge_fix( + envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, alg::G + ) where {C, T, G <: Union{ScramblingEnvGauge, ScramblingEnvGaugeC4v}} + signs, corner_phases, edge_phases = compute_gauge_fix_gauge(envfinal, envprev, alg) + return fix_phases(envfinal, signs, corner_phases, edge_phases) +end + +function compute_gauge_fix_gauge( + envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, alg::G + ) where {C, T, G <: Union{ScramblingEnvGauge, ScramblingEnvGaugeC4v}} # Check if spaces in envprev and envfinal are the same same_spaces = map(eachcoordinate(envfinal, 1:4)) do (dir, r, c) space(envfinal.edges[dir, r, c]) == space(envprev.edges[dir, r, c]) && space(envfinal.corners[dir, r, c]) == space(envprev.corners[dir, r, c]) end - @assert all(same_spaces) "Spaces of envprev and envfinal are not the same" + all(same_spaces) || throw(ArgumentError("Spaces of envfinal and envprev are not the same")) + + # find relative phases + signs = compute_relative_phases(envfinal, envprev, alg) + + # find additional global phases + corner_phases, edge_phases = compute_global_phases( + fix_relative_phases(envfinal, signs), envprev + ) + + return signs, corner_phases, edge_phases +end + +function fix_phases(env::CTMRGEnv, signs, corner_phases, edge_phases) + env_fixed_relative = fix_relative_phases(env, signs) + env_fixed_global = fix_global_phases(env_fixed_relative, corner_phases, edge_phases) + return env_fixed_global +end + +function compute_relative_phases( + envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, ::ScramblingEnvGauge + ) where {C, T} signs = map(eachcoordinate(envfinal, 1:4)) do (dir, r, c) # Gather edge tensors and pretend they're InfiniteMPSs @@ -84,21 +97,10 @@ function gauge_fix(envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, ::Scrambli return Qprev * Qfinal' end - env_fixed_relative = fix_relative_phases(envfinal, signs) - env_fixed_full = fix_global_phases(env_fixed_relative, envprev) - - return env_fixed_full, signs + return signs end -# C4v specialized gauge fixing routine with Hermitian transfer matrix -function gauge_fix(envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, ::ScramblingEnvGaugeC4v) where {C, T} - # Check if spaces in envprev and envfinal are the same - same_spaces = map(eachcoordinate(envfinal, 1:4)) do (dir, r, c) - space(envfinal.edges[dir, r, c]) == space(envprev.edges[dir, r, c]) && - space(envfinal.corners[dir, r, c]) == space(envprev.corners[dir, r, c]) - end - @assert all(same_spaces) "Spaces of envprev and envfinal are not the same" - +function compute_relative_phases(envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, ::ScramblingEnvGaugeC4v) where {C, T} # "general" algorithm from https://arxiv.org/abs/2311.11894 Tprev = envprev.edges[1, 1, 1] Tfinal = envfinal.edges[1, 1, 1] @@ -118,11 +120,9 @@ function gauge_fix(envfinal::CTMRGEnv{C, T}, envprev::CTMRGEnv{C, T}, ::Scrambli σ = Qprev * Qfinal' - cornerfix = σ * envfinal.corners[1] * σ' - @tensor edgefix[χ_in D_in_above D_in_below; χ_out] := - σ[χ_in; χ1] * envfinal.edges[1][χ1 D_in_above D_in_below; χ2] * conj(σ[χ_out; χ2]) + signs = fill(σ, (4, 1, 1)) - return CTMRGEnv(cornerfix, edgefix), fill(σ, (4, 1, 1)) + return signs end # this is a bit of a hack to get the fixed point of the mixed transfer matrix @@ -167,27 +167,29 @@ end # Explicit fixing of relative phases (doing this compactly in a loop is annoying) function fix_relative_phases(envfinal::CTMRGEnv, signs) corners_fixed = map(eachcoordinate(envfinal, 1:4)) do (dir, r, c) - if dir == NORTHWEST + Cf = if dir == NORTHWEST fix_gauge_northwest_corner((r, c), envfinal, signs) elseif dir == NORTHEAST fix_gauge_northeast_corner((r, c), envfinal, signs) elseif dir == SOUTHEAST fix_gauge_southeast_corner((r, c), envfinal, signs) - elseif dir == SOUTHWEST + else # dir == SOUTHWEST fix_gauge_southwest_corner((r, c), envfinal, signs) end + return Cf end edges_fixed = map(eachcoordinate(envfinal, 1:4)) do (dir, r, c) - if dir == NORTHWEST + Ef = if dir == NORTHWEST fix_gauge_north_edge((r, c), envfinal, signs) elseif dir == NORTHEAST fix_gauge_east_edge((r, c), envfinal, signs) elseif dir == SOUTHEAST fix_gauge_south_edge((r, c), envfinal, signs) - elseif dir == SOUTHWEST + else # dir == SOUTHWEST fix_gauge_west_edge((r, c), envfinal, signs) end + return Ef end return CTMRGEnv(corners_fixed, edges_fixed) @@ -197,28 +199,30 @@ function fix_relative_phases( ) where {Ut <: AbstractTensorMap, Vt <: AbstractTensorMap} U_fixed = map(eachindex(IndexCartesian(), U)) do I dir, r, c = Tuple(I) - if dir == NORTHWEST + Uf = if dir == NORTHWEST fix_gauge_north_left_vecs((r, c), U, signs) elseif dir == NORTHEAST fix_gauge_east_left_vecs((r, c), U, signs) elseif dir == SOUTHEAST fix_gauge_south_left_vecs((r, c), U, signs) - elseif dir == SOUTHWEST + else # dir == SOUTHWEST fix_gauge_west_left_vecs((r, c), U, signs) end + return Uf end V_fixed = map(eachindex(IndexCartesian(), V)) do I dir, r, c = Tuple(I) - if dir == NORTHWEST + Vf = if dir == NORTHWEST fix_gauge_north_right_vecs((r, c), V, signs) elseif dir == NORTHEAST fix_gauge_east_right_vecs((r, c), V, signs) elseif dir == SOUTHEAST fix_gauge_south_right_vecs((r, c), V, signs) - elseif dir == SOUTHWEST + else # dir == SOUTHWEST fix_gauge_west_right_vecs((r, c), V, signs) end + return Vf end return U_fixed, V_fixed @@ -232,15 +236,21 @@ between all corners and all edges are computed to obtain the global phase which divided out. """ function fix_global_phases(envfix::CTMRGEnv, envprev::CTMRGEnv) - cornersgfix = map(zip(envprev.corners, envfix.corners)) do (Cprev, Cfix) - return Cfix * inv(dot(Cprev, Cfix)) - end - edgesgfix = map(zip(envprev.edges, envfix.edges)) do (Tprev, Tfix) - return Tfix * inv(dot(Tprev, Tfix)) - end + corner_phases, edge_phases = compute_global_phases(envfix, envprev) + return fix_global_phases(envfix, corner_phases, edge_phases) +end +function fix_global_phases(env::CTMRGEnv, corner_phases, edge_phases) + cornersgfix = env.corners .* inv.(corner_phases) + edgesgfix = env.edges .* inv.(edge_phases) return CTMRGEnv(cornersgfix, edgesgfix) end +function compute_global_phases(envfix::CTMRGEnv, envprev::CTMRGEnv) + corner_phases = dot.(envprev.corners, envfix.corners) + edge_phases = dot.(envprev.edges, envfix.edges) + return corner_phases, edge_phases +end + """ calc_elementwise_convergence(envfinal, envfix; atol=1e-6) diff --git a/src/algorithms/ctmrg/projectors.jl b/src/algorithms/ctmrg/projectors.jl index f90f9d0c4..b49b542d4 100644 --- a/src/algorithms/ctmrg/projectors.jl +++ b/src/algorithms/ctmrg/projectors.jl @@ -52,34 +52,10 @@ end """ decomposition_algorithm(alg::ProjectorAlgorithm) - decomposition_algorithm(alg::ProjectorAlgorithm, (dir, r, c)) Return the tensor decomposition algorithm of the `alg` projector algorithm. -Additionally, the multi-index `(dir, r, c)` can be supplied which will return the -decomposition performed at that index, e.g. when using [`FixedEig`](@ref) or [`FixedSVD`](@ref). """ decomposition_algorithm(alg::ProjectorAlgorithm) = alg.decomposition_alg -function decomposition_algorithm(alg::ProjectorAlgorithm, (dir, r, c)) - decomposition_alg = decomposition_algorithm(alg) - if decomposition_alg isa SVDAdjoint{<:FixedSVD} - fwd_alg = decomposition_alg.fwd_alg - fix_svd = if isfullsvd(decomposition_alg.fwd_alg) - FixedSVD( - fwd_alg.U[dir, r, c], fwd_alg.S[dir, r, c], fwd_alg.V[dir, r, c], - fwd_alg.U_full[dir, r, c], fwd_alg.S_full[dir, r, c], fwd_alg.V_full[dir, r, c], - fwd_alg.truncation_indices[dir, r, c], - ) - else - FixedSVD( - fwd_alg.U[dir, r, c], fwd_alg.S[dir, r, c], fwd_alg.V[dir, r, c], - nothing, nothing, nothing, nothing, - ) - end - return SVDAdjoint(; fwd_alg = fix_svd, rrule_alg = decomposition_alg.rrule_alg) - else - return decomposition_alg - end -end function truncation_strategy(alg::ProjectorAlgorithm, edge) if alg.trunc isa FixedSpaceTruncation @@ -97,8 +73,22 @@ Update the truncation strategy of a given projector algorithm, keeping all other the same. """ function _set_truncation(alg::ProjectorAlgorithm, trunc::TruncationStrategy) - alg´ = @set alg.trunc = trunc - return alg´ + alg = @set alg.trunc = trunc + return alg +end + +""" + _set_decomposition_truncation(alg::ProjectorAlgorithm, trunc::TruncationStrategy) + +Set the truncation strategy of the decomposition algorithm within a given projector +algorithm, keeping all other settings the same. +""" +function _set_decomposition_truncation(alg::ProjectorAlgorithm, trunc::TruncationStrategy) + decomp_alg = decomposition_algorithm(alg) + truncated_fwd_alg = TruncatedAlgorithm(decomp_alg.fwd_alg, trunc) + decomp_alg = @set decomp_alg.fwd_alg = truncated_fwd_alg + alg = @set alg.decomposition_alg = decomp_alg + return alg end """ @@ -178,16 +168,19 @@ end PROJECTOR_SYMBOLS[:fullinfinite] = FullInfiniteProjector """ - compute_projector(enlarged_corners, coordinate, alg::ProjectorAlgorithm) + compute_projector(enlarged_corners, alg::ProjectorAlgorithm) Determine left and right projectors at the bond given determined by the enlarged corners -and the given coordinate using the specified `alg`. +using the specified `alg`. """ -function compute_projector(enlarged_corners, coordinate, alg::HalfInfiniteProjector) +function compute_projector(enlarged_corners, alg::HalfInfiniteProjector) # SVD half-infinite environment halfinf = half_infinite_environment(enlarged_corners...) - svd_alg = decomposition_algorithm(alg, coordinate) - U, S, V, info = svd_trunc!(halfinf / norm(halfinf), svd_alg; trunc = alg.trunc) + svd_alg = decomposition_algorithm(alg) + U, S, V, truncation_error = svd_trunc!(halfinf / norm(halfinf), svd_alg) + + # get some decomposition info + truncation_error = truncation_error / norm(S) # normalize truncation error # Check for degenerate singular values Zygote.isderiving() && ignore_derivatives() do @@ -197,18 +190,20 @@ function compute_projector(enlarged_corners, coordinate, alg::HalfInfiniteProjec end end - @reset info.truncation_error = info.truncation_error / norm(S) # normalize truncation error P_left, P_right = contract_projectors(U, S, V, enlarged_corners...) - return (P_left, P_right), (; U, S, V, info...) + return (P_left, P_right), (; U, S, V, truncation_error) end -function compute_projector(enlarged_corners, coordinate, alg::FullInfiniteProjector) +function compute_projector(enlarged_corners, alg::FullInfiniteProjector) halfinf_left = half_infinite_environment(enlarged_corners[1], enlarged_corners[2]) halfinf_right = half_infinite_environment(enlarged_corners[3], enlarged_corners[4]) # SVD full-infinite environment fullinf = full_infinite_environment(halfinf_left, halfinf_right) - svd_alg = decomposition_algorithm(alg, coordinate) - U, S, V, info = svd_trunc!(fullinf / norm(fullinf), svd_alg; trunc = alg.trunc) + svd_alg = decomposition_algorithm(alg) + U, S, V, truncation_error = svd_trunc!(fullinf / norm(fullinf), svd_alg) + + # get some decomposition info + truncation_error = truncation_error / norm(S) # normalize truncation error # Check for degenerate singular values Zygote.isderiving() && ignore_derivatives() do @@ -218,7 +213,6 @@ function compute_projector(enlarged_corners, coordinate, alg::FullInfiniteProjec end end - @reset info.truncation_error = info.truncation_error / norm(S) # normalize truncation error P_left, P_right = contract_projectors(U, S, V, halfinf_left, halfinf_right) - return (P_left, P_right), (; U, S, V, info...) + return (P_left, P_right), (; U, S, V, truncation_error) end diff --git a/src/algorithms/ctmrg/sequential.jl b/src/algorithms/ctmrg/sequential.jl index 9c858d36d..69d45a34a 100644 --- a/src/algorithms/ctmrg/sequential.jl +++ b/src/algorithms/ctmrg/sequential.jl @@ -59,17 +59,15 @@ end function ctmrg_iteration(network, env::CTMRGEnv, alg::SequentialCTMRG) truncation_error = zero(real(scalartype(network))) - condition_number = zero(real(scalartype(network))) for _ in 1:4 # rotate for col in 1:size(network, 2) # left move column-wise env, info = ctmrg_leftmove(col, network, env, alg) truncation_error = max(truncation_error, info.truncation_error) - condition_number = max(condition_number, info.condition_number) end network = rotate_north(network, EAST) env = rotate_north(env, EAST) end - return env, (; contraction_metrics = (; truncation_error, condition_number)) + return env, (; contraction_metrics = (; truncation_error)) end """ @@ -97,10 +95,10 @@ function sequential_projectors( _, r, c = coordinate r′ = _prev(r, size(env, 2)) trunc = truncation_strategy(alg, env.edges[WEST, r′, c]) - alg′ = @set alg.trunc = trunc + alg´ = _set_decomposition_truncation(alg, trunc) Q1 = TensorMap(EnlargedCorner(network, env, (SOUTHWEST, r, c))) Q2 = TensorMap(EnlargedCorner(network, env, (NORTHWEST, r′, c))) - return compute_projector((Q1, Q2), coordinate, alg′) + return compute_projector((Q1, Q2), alg´) end function sequential_projectors( coordinate::NTuple{3, Int}, network, env::CTMRGEnv, alg::FullInfiniteProjector @@ -110,14 +108,14 @@ function sequential_projectors( coordinate_ne = _next_coordinate(coordinate_nw, rowsize, colsize) coordinate_se = _next_coordinate(coordinate_ne, rowsize, colsize) trunc = truncation_strategy(alg, env.edges[WEST, coordinate_nw[2:3]...]) - alg′ = @set alg.trunc = trunc + alg´ = _set_decomposition_truncation(alg, trunc) ec = ( TensorMap(EnlargedCorner(network, env, coordinate_se)), TensorMap(EnlargedCorner(network, env, coordinate)), TensorMap(EnlargedCorner(network, env, coordinate_nw)), TensorMap(EnlargedCorner(network, env, coordinate_ne)), ) - return compute_projector(ec, coordinate, alg′) + return compute_projector(ec, alg´) end """ diff --git a/src/algorithms/ctmrg/simultaneous.jl b/src/algorithms/ctmrg/simultaneous.jl index 7e1fafb00..cab9e6dc3 100644 --- a/src/algorithms/ctmrg/simultaneous.jl +++ b/src/algorithms/ctmrg/simultaneous.jl @@ -49,8 +49,8 @@ function ctmrg_iteration(network, env::CTMRGEnv, alg::SimultaneousCTMRG) projectors, info = simultaneous_projectors(enlarged_corners, env, alg.projector_alg) # compute projectors on all coordinates env′ = renormalize_simultaneously(enlarged_corners, projectors, network, env) # renormalize enlarged corners info = (; - contraction_metrics = (; info.truncation_error, info.condition_number), - info.U, info.S, info.V, info.U_full, info.S_full, info.V_full, info.truncation_indices, + contraction_metrics = (; info.truncation_error), + info.U, info.S, info.V, ) return env′, info end @@ -61,15 +61,10 @@ function _split_proj_and_info(proj_and_info) P_left = map(x -> x[1][1], proj_and_info) P_right = map(x -> x[1][2], proj_and_info) truncation_error = maximum(x -> x[2].truncation_error, proj_and_info) - condition_number = maximum(x -> x[2].condition_number, proj_and_info) U = map(x -> x[2].U, proj_and_info) S = map(x -> x[2].S, proj_and_info) V = map(x -> x[2].V, proj_and_info) - U_full = map(x -> x[2].U_full, proj_and_info) - S_full = map(x -> x[2].S_full, proj_and_info) - V_full = map(x -> x[2].V_full, proj_and_info) - truncation_indices = map(x -> x[2].truncation_indices, proj_and_info) - info = (; truncation_error, condition_number, U, S, V, U_full, S_full, V_full, truncation_indices) + info = (; truncation_error, U, S, V) return (P_left, P_right), info end @@ -100,9 +95,9 @@ function simultaneous_projectors( ) where {E} coordinate′ = _next_coordinate(coordinate, size(env)[2:3]...) trunc = truncation_strategy(alg, env.edges[coordinate[1], coordinate′[2:3]...]) - alg′ = @set alg.trunc = trunc + alg′ = _set_decomposition_truncation(alg, trunc) ec = (enlarged_corners[coordinate...], enlarged_corners[coordinate′...]) - return compute_projector(ec, coordinate, alg′) + return compute_projector(ec, alg′) end function simultaneous_projectors( coordinate, enlarged_corners::Array{E, 3}, env, alg::FullInfiniteProjector @@ -112,14 +107,14 @@ function simultaneous_projectors( coordinate3 = _next_coordinate(coordinate2, rowsize, colsize) coordinate4 = _next_coordinate(coordinate3, rowsize, colsize) trunc = truncation_strategy(alg, env.edges[coordinate[1], coordinate2[2:3]...]) - alg′ = @set alg.trunc = trunc + alg′ = _set_decomposition_truncation(alg, trunc) ec = ( enlarged_corners[coordinate4...], enlarged_corners[coordinate...], enlarged_corners[coordinate2...], enlarged_corners[coordinate3...], ) - return compute_projector(ec, coordinate, alg′) + return compute_projector(ec, alg′) end """ diff --git a/src/algorithms/optimization/fixed_point_differentiation.jl b/src/algorithms/optimization/fixed_point_differentiation.jl index b5c47f979..9a8135c65 100644 --- a/src/algorithms/optimization/fixed_point_differentiation.jl +++ b/src/algorithms/optimization/fixed_point_differentiation.jl @@ -265,11 +265,11 @@ function _rrule( alg_gauge = _scrambling_env_gauge(alg) # TODO: make this a field in GradMode? # prepare iterating function corresponding to a single gauge-fixed CTMRG iteration - function f(A, x) - return gauge_fix(ctmrg_iteration(InfiniteSquareNetwork(A), x, alg_fixed)[1], x, alg_gauge)[1] + function gauge_fixed_iteration(A, x) + return gauge_fix(ctmrg_iteration(InfiniteSquareNetwork(A), x, alg_fixed)[1], x, alg_gauge) end # compute its pullback - _, env_vjp = rrule_via_ad(config, f, state, env) + _, env_vjp = rrule_via_ad(config, gauge_fixed_iteration, state, env) # split off state and environment parts ∂f∂A(x)::typeof(state) = env_vjp(x)[2] ∂f∂x(x)::typeof(env) = env_vjp(x)[3] @@ -301,20 +301,18 @@ function _rrule( alg_fixed = _set_fixed_truncation(alg) # fix spaces during differentiation alg_gauge = _scrambling_env_gauge(alg) # TODO: make this a field in GradMode? env_conv, info = ctmrg_iteration(InfiniteSquareNetwork(state), env, alg_fixed) - _, signs = gauge_fix(env_conv, env, alg_gauge) - - # fix decomposition - alg_fixed = gauge_fix(alg, signs, info) + signs, corner_phases, edge_phases = compute_gauge_fix_gauge(env_conv, env, alg_gauge) # prepare iterating function corresponding to a single CTMRG iteration with a # gauge-fixed projector - function f(A, x) - return fix_global_phases( - ctmrg_iteration(InfiniteSquareNetwork(A), x, alg_fixed)[1], x, + function gauge_fixed_iteration(A, x) + return fix_phases( + ctmrg_iteration(InfiniteSquareNetwork(A), x, alg_fixed)[1], + signs, corner_phases, edge_phases, ) end # prepare its pullback - _, env_vjp = rrule_via_ad(config, f, state, env) + _, env_vjp = rrule_via_ad(config, gauge_fixed_iteration, state, env) # split off state and environment parts ∂f∂A(x)::typeof(state) = env_vjp(x)[2] ∂f∂x(x)::typeof(env) = env_vjp(x)[3] @@ -331,85 +329,6 @@ function _rrule( return (env, info), leading_boundary_fixed_pullback end -function gauge_fix(alg::SVDAdjoint, signs, info) - # embed gauge signs in larger space to fix gauge of full U and V on truncated subspace - rowsize, colsize = size(signs, 2), size(signs, 3) - inds = info.truncation_indices - signs_full = map(Iterators.product(1:4, 1:rowsize, 1:colsize)) do (dir, row, col) - σ = signs[dir, row, col] - row_sign, col_sign = if dir == NORTH # take unit cell interdependency of signs into account - row, _prev(col, colsize) - elseif dir == EAST - _prev(row, rowsize), col - elseif dir == SOUTH - row, _next(col, colsize) - elseif dir == WEST - _next(row, rowsize), col - end - - ind = inds[dir, row_sign, col_sign] - extended_σ = id(scalartype(σ), domain(info.S_full[dir, row_sign, col_sign])) - for (c, b) in blocks(σ) - I = get(ind, c, nothing) - @assert !isnothing(I) - block(extended_σ, c)[I, I] = b - end - return extended_σ - end - - # fix kept and full U and V - U_fixed, V_fixed = fix_relative_phases(info.U, info.V, signs) - U_full_fixed, V_full_fixed = fix_relative_phases(info.U_full, info.V_full, signs_full) - return SVDAdjoint(; - fwd_alg = FixedSVD(U_fixed, info.S, V_fixed, U_full_fixed, info.S_full, V_full_fixed, inds), - rrule_alg = alg.rrule_alg, - ) -end -function gauge_fix(alg::SVDAdjoint{F}, signs, info) where {F <: IterSVD} - # fix kept U and V only since iterative SVD doesn't have access to full spectrum - U_fixed, V_fixed = fix_relative_phases(info.U, info.V, signs) - return SVDAdjoint(; - fwd_alg = FixedSVD(U_fixed, info.S, V_fixed, nothing, nothing, nothing, nothing), - rrule_alg = alg.rrule_alg, - ) -end -function gauge_fix(alg::EighAdjoint, signs, info) - σ = signs[1] - inds = info.truncation_indices - - # embed gauge signs in larger space to fix gauge of full V on truncated subspace - extended_σ = id(scalartype(σ), domain(info.D_full)) - for (c, b) in blocks(σ) - I = get(inds, c, nothing) - @assert !isnothing(I) - block(extended_σ, c)[I, I] = b - end - - # fix kept and full V - V_fixed = info.V * σ' - V_full_fixed = info.V_full * extended_σ' - return EighAdjoint(; - fwd_alg = FixedEig(info.D, V_fixed, info.D_full, V_full_fixed, inds), - rrule_alg = alg.rrule_alg, - ) -end -function gauge_fix(alg::EighAdjoint{F}, signs, info) where {F <: IterEigh} - # fix kept V only since iterative decomposition doesn't have access to full spectrum - V_fixed = info.V * signs[1]' - return EighAdjoint(; - fwd_alg = FixedEig(info.D, V_fixed, nothing, nothing, nothing), - rrule_alg = alg.rrule_alg, - ) -end -function gauge_fix(alg::QRAdjoint, signs, info) - Q_fixed = info.Q * signs[1]' - R_fixed = signs[1] * info.R - return QRAdjoint(; - fwd_alg = FixedQR(Q_fixed, R_fixed), - rrule_alg = alg.rrule_alg, - ) -end - @doc """ fpgrad(∂F∂x, ∂f∂x, ∂f∂A, y0, alg) diff --git a/src/algorithms/time_evolution/apply_gate.jl b/src/algorithms/time_evolution/apply_gate.jl index 363b23f8d..27f9da61f 100644 --- a/src/algorithms/time_evolution/apply_gate.jl +++ b/src/algorithms/time_evolution/apply_gate.jl @@ -139,7 +139,7 @@ function _apply_gate( else trunc end - a, s, b, ϵ = svd_trunc!(a2b2; trunc, alg = LAPACK_QRIteration()) + a, s, b, ϵ = svd_trunc!(a2b2; trunc) a, b = absorb_s(a, s, b) if need_flip a, s, b = flip(a, numind(a)), _fliptwist_s(s), flip(b, 1) diff --git a/src/utility/eigh.jl b/src/utility/eigh.jl index 20f0773ad..eec53ad42 100644 --- a/src/utility/eigh.jl +++ b/src/utility/eigh.jl @@ -46,7 +46,6 @@ end $(TYPEDEF) Wrapper for a eigenvalue decomposition algorithm `fwd_alg` with a defined reverse rule `rrule_alg`. -If `isnothing(rrule_alg)`, Zygote differentiates the forward call automatically. ## Fields @@ -58,34 +57,55 @@ $(TYPEDFIELDS) Construct a `EighAdjoint` algorithm struct based on the following keyword arguments: -* `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.eigh_fwd_alg))`: Eig algorithm of the forward pass which can either be passed as an `Algorithm` instance or a `NamedTuple` where `alg` is one of the following: - - `:qriteration` : MatrixAlgebraKit's `LAPACK_QRIteration` - - `:bisection` : MatrixAlgebraKit's `LAPACK_Bisection` - - `:divideandconquer` : MatrixAlgebraKit's `LAPACK_DivideAndConquer` - - `:multiple` : MatrixAlgebraKit's `LAPACK_MultipleRelativelyRobustRepresentations` - - `:lanczos` : Lanczos algorithm for symmetric/Hermitian matrices, see [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.Lanczos) - - `:blocklanczos` : Block version of `:lanczos` for repeated extremal eigenvalues, see [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.BlockLanczos) -* `rrule_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.eigh_rrule_alg))`: Reverse-rule algorithm for differentiating the eigenvalue decomposition. Can be supplied by an `Algorithm` instance directly or as a `NamedTuple` where `alg` is one of the following: - - `:full` : MatrixAlgebraKit's `eigh_pullback!` that requires access to the full spectrum - - `:trunc` : MatrixAlgebraKit's `eigh_trunc_pullback!` solving a Sylvester equation on the truncated subspace +* `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.eigh_fwd_alg))`: Eigh + algorithm of the forward pass which can either be passed as an `Algorithm` instance or a + `NamedTuple` where the algorithm is specified by the `alg` keyword. + The available Eigh algorithms can be divided into two categories: + - "Dense" Eigh algorithms which compute a truncated Eigh through the truncation of a full + [`MatrixAlgebraKit.eigh_full!`](@extref) decomposition. + Available algorithms are: + - `:DefaultAlgorithm` : MatrixAlgebraKit's [default Eigh algorithm](@extref MatrixAlgebraKit.DefaultAlgorithm) for a given matrix type. + - `:DivideAndConquer` : MatrixAlgebraKit's [`DivideAndConquer`](@extref MatrixAlgebraKit.DivideAndConquer) + - `:QRIteration` : MatrixAlgebraKit's [`QRIteration`](@extref MatrixAlgebraKit.QRIteration) + - `:Bisection` : MatrixAlgebraKit's [`Bisection`](@extref MatrixAlgebraKit.Bisection) + - `:Jacobi` : MatrixAlgebraKit's [`Jacobi`](@extref MatrixAlgebraKit.Jacobi) + - `:RobustRepresentations` : MatrixAlgebraKit's [`RobustRepresentations`](@extref MatrixAlgebraKit.RobustRepresentations) + - "Sparse" Eigh algorithms which directly compute a truncated Eigh without access to the + full decomposition. Available algorithms are: + - `:Lanczos` : Lanczos algorithm for symmetric/Hermitian matrices, see [`KrylovKit.Lanczos`](@extref) + - `:BlockLanczos` : Block version of `:Lanczos` for repeated extremal eigenvalues, see [`KrylovKit.BlockLanczos`](@extref) +* `rrule_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.eigh_rrule_alg))`: + Reverse-rule algorithm for differentiating the eigenvalue decomposition. Can be supplied + by an `Algorithm` instance directly or as a `NamedTuple` where `alg` is one of the + following: + - `:full` : MatrixAlgebraKit's [`eigh_pullback!`](@extref MatrixAlgebraKit.eigh_pullback!) that requires access to the full spectrum + - `:trunc` : MatrixAlgebraKit's [`eigh_trunc_pullback!`](@extref MatrixAlgebraKit.eigh_trunc_pullback!) solving a Sylvester equation on the truncated subspace + +!!! note + Manually specifying a `rrule_alg` is considered expert-mode usage, and should only be done when full control over the implementation is desired. + For all regular use cases, the default reverse rule algorithms, automatically chosen based on the forward algorithm, should be sufficient. """ struct EighAdjoint{F, R} fwd_alg::F rrule_alg::R -end # Keep truncation algorithm separate to be able to specify CTMRG dependent information +end const EIGH_FWD_SYMBOLS = IdDict{Symbol, Any}( - :qriteration => LAPACK_QRIteration, - :bisection => LAPACK_Bisection, - :divideandconquer => LAPACK_DivideAndConquer, - :multiple => LAPACK_MultipleRelativelyRobustRepresentations, - :lanczos => (; tol = 1.0e-14, krylovdim = 30, kwargs...) -> IterEigh(; alg = Lanczos(; tol, krylovdim), kwargs...), - :blocklanczos => (; tol = 1.0e-14, krylovdim = 30, kwargs...) -> IterEigh(; alg = BlockLanczos(; tol, krylovdim), kwargs...), + :DefaultAlgorithm => DefaultAlgorithm, + :QRIteration => QRIteration, + :Bisection => Bisection, + :DivideAndConquer => DivideAndConquer, + :Jacobi => Jacobi, + :RobustRepresentations => RobustRepresentations, + :Lanczos => (; tol = 1.0e-14, krylovdim = 30, kwargs...) -> IterEigh(; alg = Lanczos(; tol, krylovdim), kwargs...), + :BlockLanczos => (; tol = 1.0e-14, krylovdim = 30, kwargs...) -> IterEigh(; alg = BlockLanczos(; tol, krylovdim), kwargs...), ) const EIGH_RRULE_SYMBOLS = IdDict{Symbol, Type{<:Any}}( :full => FullEighPullback, :trunc => TruncEighPullback, ) +_default_eigh_rrule_alg(::MatrixAlgebraKit.Algorithm) = :full + function EighAdjoint(; fwd_alg = (;), rrule_alg = (;)) # parse forward algorithm fwd_algorithm = if fwd_alg isa NamedTuple @@ -102,7 +122,7 @@ function EighAdjoint(; fwd_alg = (;), rrule_alg = (;)) # parse reverse-rule algorithm rrule_algorithm = if rrule_alg isa NamedTuple rrule_kwargs = (; - alg = Defaults.eigh_rrule_alg, + alg = _default_eigh_rrule_alg(fwd_algorithm), degeneracy_atol = Defaults.rrule_degeneracy_atol, verbosity = Defaults.eigh_rrule_verbosity, rrule_alg..., @@ -124,86 +144,25 @@ function EighAdjoint(; fwd_alg = (;), rrule_alg = (;)) end """ - eigh_trunc(t, alg::EighAdjoint; trunc=notrunc()) - eigh_trunc!(t, alg::EighAdjoint; trunc=notrunc()) + eigh_trunc(t, alg::EighAdjoint) + eigh_trunc!(t, alg::EighAdjoint) Wrapper around `eigh_trunc(!)` which dispatches on the `EighAdjoint` algorithm. This is needed since a custom adjoint may be defined, depending on the `alg`. """ -MatrixAlgebraKit.eigh_trunc(t, alg::EighAdjoint; kwargs...) = eigh_trunc!(copy(t), alg; kwargs...) -function MatrixAlgebraKit.eigh_trunc!(t, alg::EighAdjoint; trunc = notrunc()) - return _eigh_trunc!(t, alg.fwd_alg, trunc) +MatrixAlgebraKit.eigh_trunc(t, alg::EighAdjoint) = eigh_trunc!(copy(t), alg) +function MatrixAlgebraKit.eigh_trunc!(t, alg::EighAdjoint) + return eigh_trunc!(t, alg.fwd_alg) end -function MatrixAlgebraKit.eigh_trunc!( - t::AdjointTensorMap, alg::EighAdjoint; trunc = notrunc() - ) - D, V, info = eigh_trunc!(adjoint(t), alg; trunc) - return adjoint(D), adjoint(V), info +function MatrixAlgebraKit.eigh_trunc!(t::AdjointTensorMap, alg::EighAdjoint) + D, V, ϵ = eigh_trunc!(adjoint(t), alg) + return adjoint(D), adjoint(V), ϵ end # ## Forward algorithms # -# Truncated eigh but also return full D and V to make it compatible with :fixed mode -function _eigh_trunc!( - t::TensorMap, - alg::LAPACK_EighAlgorithm, - trunc::TruncationStrategy, - ) - D, V = eigh_full!(t; alg) - (D̃, Ṽ), ind = truncate(eigh_trunc!, (D, V), trunc) - truncerror = truncation_error(diagview(D), ind) - - # construct info NamedTuple - condnum = cond(D) - info = (; - truncation_error = truncerror, - condition_number = condnum, - D_full = D, - V_full = V, - truncation_indices = ind, - ) - return D̃, Ṽ, info -end - -""" -$(TYPEDEF) - -Eigenvalue decomposition struct containing a pre-computed decomposition or even multiple -ones. Additionally, it can contain the full untruncated decomposition and the corresponding -truncation indices as well. The call to `eigh_trunc`/`eig_trunc` just returns the -pre-computed D and V. In the reverse pass, the adjoint is computed with these exact D and V -and, potentially, the full decompositions if the adjoints require access to them. - -## Fields - -$(TYPEDFIELDS) -""" -struct FixedEig{Dt, Vt, Dtf, Vtf, It} - D::Dt - V::Vt - D_full::Dtf - V_full::Vtf - truncation_indices::It -end - -# check whether the full D and V are supplied -isfulleig(alg::FixedEig) = !isnothing(alg.D_full) && !isnothing(alg.V_full) && !isnothing(alg.truncation_indices) - -# Return pre-computed decomposition -function _eigh_trunc!(_, alg::FixedEig, ::TruncationStrategy) - info = (; - truncation_error = zero(real(scalartype(alg.D))), - condition_number = cond(alg.D), - D_full = alg.D_full, - V_full = alg.V_full, - truncation_indices = alg.truncation_indices, - ) - return alg.D, alg.V, info -end - - """ $(TYPEDEF) @@ -225,35 +184,31 @@ Construct an `IterEigh` algorithm struct based on the following keyword argument * `alg=KrylovKit.Lanczos(; tol=1e-14, krylovdim=25)` : KrylovKit algorithm struct for iterative eigenvalue decomposition. * `fallback_threshold::Float64=Inf` : Threshold for `howmany / minimum(size(block))` above which (if the block is too small) the algorithm falls back to a dense decomposition. -* `start_vector=random_start_vector` : Function providing the initial vector for the iterative algorithm. +* `start_vector=deterministic_start_vector` : Function providing the initial vector for the iterative algorithm. """ @kwdef struct IterEigh alg = KrylovKit.Lanczos(; tol = 1.0e-14, krylovdim = 25) fallback_threshold::Float64 = Inf - start_vector = random_start_vector + start_vector = deterministic_start_vector end +_default_eigh_rrule_alg(::IterEigh) = :trunc # Compute eigh data block-wise using KrylovKit algorithm -function _eigh_trunc!(f, alg::IterEigh, trunc::TruncationStrategy) +function MatrixAlgebraKit.eigh_trunc!(f, alg::TruncatedAlgorithm{<:IterEigh}) D, V = if isempty(blocksectors(f)) # early return truncation_error = zero(real(scalartype(f))) - MatrixAlgebraKit.initialize_output(eigh_full!, f, LAPACK_QRIteration()) # specified algorithm doesn't matter here + MatrixAlgebraKit.initialize_output(eigh_full!, f, QRIteration()) # specified algorithm doesn't matter here else - eighdata, dims = _compute_eighdata!(f, alg, trunc) + eighdata, dims = _compute_eighdata!(f, alg.alg, alg.trunc) _create_eightensors(f, eighdata, dims) end # construct info NamedTuple truncation_error = - trunc isa NoTruncation ? abs(zero(scalartype(f))) : norm(V * D * V' - f) - condition_number = cond(D) - info = (; - truncation_error, condition_number, D_full = nothing, V_full = nothing, - truncation_indices = nothing, - ) + alg.trunc isa NoTruncation ? abs(zero(scalartype(f))) : norm(V * D * V' - f) - return D, V, info + return D, V, truncation_error end # Obtain sparse decomposition from block-wise eigsolve calls @@ -272,7 +227,7 @@ function _compute_eighdata!( howmany = trunc isa NoTruncation ? minimum(size(b)) : blockdim(trunc.space, c) if howmany / minimum(size(b)) > alg.fallback_threshold # Use dense decomposition for small blocks - D, V = eigh_full!(b, LAPACK_QRIteration()) + D, V = eigh_full!(b) lm_ordering = sortperm(abs.(D.diag); rev = true) # order values and vectors consistently with eigsolve D = D.diag[lm_ordering] # extracts diagonal as Vector instead of Diagonal to make compatible with D of svdsolve V = stack(eachcol(V)[lm_ordering])[:, 1:howmany] @@ -285,7 +240,7 @@ function _compute_eighdata!( D, lvecs, info = eigsolve(b, x₀, howmany, :LM, eig_alg) if info.converged < howmany # Fall back to dense SVD if not properly converged @warn "Iterative eigendecomposition did not converge for block $c, falling back to eigh_full" - D, V = eigh_full!(b, LAPACK_QRIteration()) + D, V = eigh_full!(b) lm_ordering = sortperm(abs.(D.diag); rev = true) D = D.diag[lm_ordering] V = stack(eachcol(V)[lm_ordering])[:, 1:howmany] @@ -294,6 +249,9 @@ function _compute_eighdata!( end end + # make it deterministic-ish + MatrixAlgebraKit.gaugefix!(eigh_full!, V) + resize!(D, howmany) dims[c] = length(D) return c => (D, V) @@ -338,14 +296,17 @@ function _get_pullback_gauge_tol(verbosity::Int) end # eigh_trunc! rrule wrapping MatrixAlgebraKit's eigh_pullback! +# https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/blob/b76c7bb60014ecfead6925d0df6cb4b8d7c2668a/src/pullbacks/eigh.jl#L34 function ChainRulesCore.rrule( ::typeof(eigh_trunc!), t::AbstractTensorMap, - alg::EighAdjoint{F, R}; - trunc::TruncationStrategy = notrunc(), - ) where {F <: Union{<:LAPACK_EighAlgorithm, <:FixedEig}, R <: FullEighPullback} - D̃, Ṽ, info = eigh_trunc(t, alg; trunc) - D, V, inds = info.D_full, info.V_full, info.truncation_indices # untruncated decomposition + alg::EighAdjoint{<:TruncatedAlgorithm{<:MatrixAlgebraKit.Algorithm}, <:FullEighPullback} + ) + + D, V = eigh_full!(t; alg.fwd_alg.alg) + (D̃, Ṽ), inds = truncate(eigh_trunc!, (D, V), alg.fwd_alg.trunc) + truncerror = truncation_error(diagview(D), inds) + gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) function eigh_trunc!_full_pullback(ΔDV) @@ -359,17 +320,17 @@ function ChainRulesCore.rrule( return NoTangent(), ZeroTangent(), NoTangent() end - return (D̃, Ṽ, info), eigh_trunc!_full_pullback + return (D̃, Ṽ, truncerror), eigh_trunc!_full_pullback end # eigh_trunc! rrule wrapping MatrixAlgebraKit's eigh_trunc_pullback! (also works for IterEigh) +# https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/blob/b76c7bb60014ecfead6925d0df6cb4b8d7c2668a/src/pullbacks/eigh.jl#L113 function ChainRulesCore.rrule( ::typeof(eigh_trunc!), t, - alg::EighAdjoint{F, R}; - trunc::TruncationStrategy = notrunc(), - ) where {F <: Union{<:LAPACK_EighAlgorithm, <:FixedEig, IterEigh}, R <: TruncEighPullback} - D, V, info = eigh_trunc(t, alg; trunc) + alg::EighAdjoint{F, R} + ) where {F, R <: TruncEighPullback} + D, V, truncerror = eigh_trunc(t, alg) gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) function eigh_trunc!_trunc_pullback(ΔDV) @@ -383,5 +344,5 @@ function ChainRulesCore.rrule( return NoTangent(), ZeroTangent(), NoTangent() end - return (D, V, info), eigh_trunc!_trunc_pullback + return (D, V, truncerror), eigh_trunc!_trunc_pullback end diff --git a/src/utility/qr.jl b/src/utility/qr.jl index 426a2a643..9c26dd074 100644 --- a/src/utility/qr.jl +++ b/src/utility/qr.jl @@ -11,7 +11,6 @@ end $(TYPEDEF) Wrapper for a QR decomposition algorithm `fwd_alg` with a defined reverse rule `rrule_alg`. -If `isnothing(rrule_alg)`, Zygote differentiates the forward call automatically. ## Fields @@ -23,19 +22,27 @@ $(TYPEDFIELDS) Construct a `QRAdjoint` algorithm struct based on the following keyword arguments: -* `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.qr_fwd_alg))`: Eig algorithm of the forward pass which can either be passed as an `Algorithm` instance or a `NamedTuple` where `alg` is one of the following: - - `:qr` : MatrixAlgebraKit's `LAPACK_HouseholderQR` - +* `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.qr_fwd_alg))`: QR + algorithm of the forward pass which can either be passed as an `Algorithm` instance or a + `NamedTuple` where the algorithm is specified by the `alg` keyword. + The available algorithms are provided through MatrixAlgebraKit and include: + - `:DefaultAlgorithm` : MatrixAlgebraKit's [default QR algorithm](@extref MatrixAlgebraKit.DefaultAlgorithm) for a given matrix type. + - `:Householder` : MatrixAlgebraKit's [`Householder`](@extref MatrixAlgebraKit.Householder) * `rrule_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.qr_rrule_alg))`: Reverse-rule algorithm for differentiating the eigenvalue decomposition. Can be supplied by an `Algorithm` instance directly or as a `NamedTuple` where `alg` is one of the following: - - `:qr` : MatrixAlgebraKit's `qr_pullback` + - `:qr` : MatrixAlgebraKit's [`qr_pullback!`](@extref MatrixAlgebraKit.qr_pullback!) + +!!! note + Manually specifying a `rrule_alg` is considered expert-mode usage, and should only be done when full control over the implementation is desired. + For all regular use cases, the default reverse rule algorithms, automatically chosen based on the forward algorithm, should be sufficient. """ struct QRAdjoint{F, R} fwd_alg::F rrule_alg::R -end # Keep truncation algorithm separate to be able to specify CTMRG dependent information +end const QR_FWD_SYMBOLS = IdDict{Symbol, Any}( - :qr => LAPACK_HouseholderQR + # :DefaultAlgorithm => DefaultAlgorithm, # TODO: broken, needs to be fixed + :Householder => Householder, ) const QR_RRULE_SYMBOLS = IdDict{Symbol, Type{<:Any}}( :qr => QRPullback @@ -85,33 +92,15 @@ Wrapper around `left_orth(!)` which dispatches on the `QRAdjoint` algorithm. This is needed since a custom adjoint may be defined, depending on the `alg`. """ MatrixAlgebraKit.left_orth(t, alg::QRAdjoint) = left_orth!(copy(t), alg) -MatrixAlgebraKit.left_orth!(t, alg::QRAdjoint) = _left_orth!(t, alg.fwd_alg) -_left_orth!(t, alg::LAPACK_HouseholderQR) = left_orth!(t; alg) - -""" -$(TYPEDEF) - -QR decomposition struct containing a pre-computed decomposition. Th call to `left_orth(!)` -just returns the precomputed `Q` and `R`. In the reverse pass, the adjoint is computed with -these exact `D` and `R`. - -## Fields - -$(TYPEDFIELDS) -""" -struct FixedQR{Qt, Rt} - Q::Qt - R::Rt -end - -_left_orth!(_, alg::FixedQR) = alg.Q, alg.R +MatrixAlgebraKit.left_orth!(t, alg::QRAdjoint) = left_orth!(t, alg.fwd_alg) # left_orth! rrule wrapping MatrixAlgebraKit's qr_pullback! +# https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/blob/b76c7bb60014ecfead6925d0df6cb4b8d7c2668a/src/pullbacks/qr.jl#L49 function ChainRulesCore.rrule( ::typeof(left_orth!), t::AbstractTensorMap, alg::QRAdjoint{F, R}, - ) where {F <: Union{LAPACK_HouseholderQR, FixedQR}, R <: QRPullback} + ) where {F <: MatrixAlgebraKit.Algorithm, R <: QRPullback} QR = left_orth(t, alg) gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) diff --git a/src/utility/svd.jl b/src/utility/svd.jl index 8d834296b..a7887091e 100644 --- a/src/utility/svd.jl +++ b/src/utility/svd.jl @@ -50,7 +50,6 @@ end $(TYPEDEF) Wrapper for a SVD algorithm `fwd_alg` with a defined reverse rule `rrule_alg`. -If `isnothing(rrule_alg)`, Zygote differentiates the forward call automatically. ## Fields @@ -62,29 +61,50 @@ $(TYPEDFIELDS) Construct a `SVDAdjoint` algorithm struct based on the following keyword arguments: -* `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.svd_fwd_alg))`: SVD algorithm of the forward pass which can either be passed as an `Algorithm` instance or a `NamedTuple` where `alg` is one of the following: - - `:sdd` : MatrixAlgebraKit's `LAPACK_DivideAndConquer` - - `:svd` : MatrixAlgebraKit's `LAPACK_QRIteration` - - `:bisection` : MatrixAlgebraKit's `LAPACK_Bisection` - - `:jacobi` : MatrixAlgebraKit's `LAPACK_Jacobi` - - `:iterative` : Iterative SVD only computing the specifed number of singular values and vectors, see [`IterSVD`](@ref) -* `rrule_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.svd_rrule_alg))`: Reverse-rule algorithm for differentiating the SVD. Can be supplied by an `Algorithm` instance directly or as a `NamedTuple` where `alg` is one of the following: - - `:full` : MatrixAlgebraKit's `svd_pullback!` that requires access to the full spectrum - - `:trunc` : MatrixAlgebraKit's `svd_trunc_pullback!` solving a Sylvester equation on the truncated subspace - - `:gmres` : GMRES iterative linear solver, see the [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.GMRES) for details - - `:bicgstab` : BiCGStab iterative linear solver, see the [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.BiCGStab) for details - - `:arnoldi` : Arnoldi Krylov algorithm, see the [KrylovKit docs](https://jutho.github.io/KrylovKit.jl/stable/man/algorithms/#KrylovKit.Arnoldi) for details +* `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.svd_fwd_alg))`: SVD + algorithm of the forward pass which can either be passed as an `Algorithm` instance or a + `NamedTuple` where the algorithm is specified by the `alg` keyword. + The available SVD algorithms can be divided into two categories: + - "Dense" SVD algorithms which compute a truncated SVD through the truncation of a full + [`MatrixAlgebraKit.svd_compact!`](@extref) decomposition. + Available algorithms are: + - `:DefaultAlgorithm` : MatrixAlgebraKit's [default SVD algorithm](@extref MatrixAlgebraKit.DefaultAlgorithm) for a given matrix type. + - `:DivideAndConquer` : MatrixAlgebraKit's [`DivideAndConquer`](@extref MatrixAlgebraKit.DivideAndConquer) + - `:QRIteration` : MatrixAlgebraKit's [`QRIteration`](@extref MatrixAlgebraKit.QRIteration) + - `:Bisection` : MatrixAlgebraKit's [`Bisection`](@extref MatrixAlgebraKit.Bisection) + - `:Jacobi` : MatrixAlgebraKit's [`Jacobi`](@extref MatrixAlgebraKit.Jacobi) + - `:SVDViaPolar` : MatrixAlgebraKit's [`SVDViaPolar`](@extref MatrixAlgebraKit.SVDViaPolar) + - `:SafeDivideAndConquer` : MatrixAlgebraKit's [`SafeDivideAndConquer`](@extref MatrixAlgebraKit.SafeDivideAndConquer) + - "Sparse" SVD algorithms which directly compute a truncated SVD without access to the + full decomposition. Available algorithms are: + - `:iterative` : Iterative Krylov-based SVD only computing the specifed number of + singular values and vectors, see [`IterSVD`](@ref) +* `rrule_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=:$(Defaults.svd_rrule_alg))`: + Reverse-rule algorithm for differentiating the SVD. Can be supplied by an `Algorithm` + instance directly or as a `NamedTuple` where `alg` is one of the following: + - `:full` : MatrixAlgebraKit's [`svd_pullback!`](@extref MatrixAlgebraKit.svd_pullback!) that requires access to the full spectrum + - `:trunc` : MatrixAlgebraKit's [`svd_trunc_pullback!`](@extref MatrixAlgebraKit.svd_trunc_pullback!) solving a Sylvester equation on the truncated subspace + - `:gmres` : GMRES iterative linear solver, see [`KrylovKit.GMRES`](@extref) + - `:bicgstab` : BiCGStab iterative linear solver, see [`KrylovKit.BiCGStab`](@extref) + - `:arnoldi` : Arnoldi Krylov algorithm, see the [`KrylovKit.Arnoldi`](@extref KrylovKit.Arnoldi) + +!!! note + Manually specifying a `rrule_alg` is considered expert-mode usage, and should only be done when full control over the implementation is desired. + For all regular use cases, the default reverse rule algorithms, automatically chosen based on the forward algorithm, should be sufficient. """ struct SVDAdjoint{F, R} fwd_alg::F rrule_alg::R -end # Keep truncation algorithm separate to be able to specify CTMRG dependent information +end const SVD_FWD_SYMBOLS = IdDict{Symbol, Any}( - :sdd => LAPACK_DivideAndConquer, - :svd => LAPACK_QRIteration, - :bisection => LAPACK_Bisection, - :jacobi => LAPACK_Jacobi, + :DefaultAlgorithm => DefaultAlgorithm, + :DivideAndConquer => DivideAndConquer, + :QRIteration => QRIteration, + :Bisection => Bisection, + :Jacobi => Jacobi, + :SVDViaPolar => SVDViaPolar, + :SafeDivideAndConquer => SafeDivideAndConquer, :iterative => (; tol = 1.0e-14, krylovdim = 25, kwargs...) -> IterSVD(; alg = GKL(; tol, krylovdim), kwargs...), ) const SVD_RRULE_SYMBOLS = IdDict{Symbol, Type{<:Any}}( @@ -92,6 +112,8 @@ const SVD_RRULE_SYMBOLS = IdDict{Symbol, Type{<:Any}}( :gmres => GMRES, :bicgstab => BiCGStab, :arnoldi => Arnoldi ) +_default_svd_rrule_alg(::MatrixAlgebraKit.Algorithm) = :full + function SVDAdjoint(; fwd_alg = (;), rrule_alg = (;)) # parse forward SVD algorithm fwd_algorithm = if fwd_alg isa NamedTuple @@ -108,7 +130,7 @@ function SVDAdjoint(; fwd_alg = (;), rrule_alg = (;)) # parse reverse-rule SVD algorithm rrule_algorithm = if rrule_alg isa NamedTuple rrule_kwargs = (; - alg = Defaults.svd_rrule_alg, + alg = _default_svd_rrule_alg(fwd_algorithm), # default rrule depends on forward algorithm tol = Defaults.svd_rrule_tol, krylovdim = Defaults.svd_rrule_min_krylovdim, degeneracy_atol = Defaults.rrule_degeneracy_atol, @@ -141,92 +163,26 @@ function SVDAdjoint(; fwd_alg = (;), rrule_alg = (;)) end """ - svd_trunc(t, alg::SVDAdjoint; trunc=notrunc()) - svd_trunc!(t, alg::SVDAdjoint; trunc=notrunc()) + svd_trunc(t, alg::SVDAdjoint) + svd_trunc!(t, alg::SVDAdjoint) Wrapper around `svd_trunc(!)` which dispatches on the `SVDAdjoint` algorithm. This is needed since a custom adjoint may be defined, depending on the `alg`. E.g., for `IterSVD` the adjoint for a truncated SVD from `KrylovKit.svdsolve` is used. """ -MatrixAlgebraKit.svd_trunc(t, alg::SVDAdjoint; kwargs...) = svd_trunc!(copy(t), alg; kwargs...) -function MatrixAlgebraKit.svd_trunc!(t, alg::SVDAdjoint; trunc = notrunc()) - return _svd_trunc!(t, alg.fwd_alg, trunc) +MatrixAlgebraKit.svd_trunc(t, alg::SVDAdjoint) = svd_trunc!(copy(t), alg) +function MatrixAlgebraKit.svd_trunc!(t, alg::SVDAdjoint) + return svd_trunc!(t, alg.fwd_alg) end -function MatrixAlgebraKit.svd_trunc!( - t::AdjointTensorMap, alg::SVDAdjoint; trunc = notrunc() - ) - u, s, vt, info = svd_trunc!(adjoint(t), alg; trunc) - return adjoint(vt), adjoint(s), adjoint(u), info +function MatrixAlgebraKit.svd_trunc!(t::AdjointTensorMap, alg::SVDAdjoint) + u, s, vt, ϵ = svd_trunc!(adjoint(t), alg) + return adjoint(vt), adjoint(s), adjoint(u), ϵ end # ## Forward algorithms # -# Truncated SVD but also return full U, S and V to make it compatible with :fixed mode -function _svd_trunc!( - t::TensorMap, - alg::Union{LAPACK_DivideAndConquer, LAPACK_QRIteration}, - trunc::TruncationStrategy, - ) - U, S, V⁺ = svd_compact!(t; alg) - (Ũ, S̃, Ṽ⁺), ind = truncate(svd_trunc!, (U, S, V⁺), trunc) - truncerror = truncation_error(diagview(S), ind) - - # construct info NamedTuple - condnum = cond(S) - info = (; - truncation_error = truncerror, condition_number = condnum, - U_full = U, S_full = S, V_full = V⁺, - truncation_indices = ind, - ) - return Ũ, S̃, Ṽ⁺, info -end - -""" -$(TYPEDEF) - -SVD struct containing a pre-computed decomposition or even multiple ones. Additionally, it -can contain the untruncated full decomposition as well. The call to `svd_trunc` just returns the -pre-computed U, S and V. In the reverse pass, the SVD adjoint is computed with these exact -U, S, and V and, potentially, the full decompositions if the adjoints needs access to them. - -## Fields - -$(TYPEDFIELDS) -""" -struct FixedSVD{Ut, St, Vt, Utf, Stf, Vtf, It} - U::Ut - S::St - V::Vt - U_full::Utf - S_full::Stf - V_full::Vtf - truncation_indices::It -end - -# check whether the full U, S and V are supplied -function isfullsvd(alg::FixedSVD) - if isnothing(alg.U_full) || isnothing(alg.S_full) || isnothing(alg.V_full) || isnothing(alg.truncation_indices) - return false - else - return true - end -end - -# Return pre-computed SVD -function _svd_trunc!(_, alg::FixedSVD, ::TruncationStrategy) - info = (; - truncation_error = zero(real(scalartype(alg.S))), - condition_number = cond(alg.S), - U_full = alg.U_full, - S_full = alg.S_full, - V_full = alg.V_full, - truncation_indices = alg.truncation_indices, - ) - return alg.U, alg.S, alg.V, info -end - """ $(TYPEDEF) @@ -248,40 +204,36 @@ Construct an `IterSVD` algorithm struct based on the following keyword arguments * `alg::KrylovKit.GKL=KrylovKit.GKL(; tol=1e-14, krylovdim=25)` : GKL algorithm struct for block-wise iterative SVD. * `fallback_threshold::Float64=Inf` : Threshold for `howmany / minimum(size(block))` above which (if the block is too small) the algorithm falls back to TensorKit's dense SVD. -* `start_vector=random_start_vector` : Function providing the initial vector for the iterative SVD algorithm. +* `start_vector=deterministic_start_vector` : Function providing the initial vector for the iterative SVD algorithm. """ @kwdef struct IterSVD alg::KrylovKit.GKL = KrylovKit.GKL(; tol = 1.0e-14, krylovdim = 25) fallback_threshold::Float64 = Inf - start_vector = random_start_vector + start_vector = deterministic_start_vector end +_default_svd_rrule_alg(::IterSVD) = :trunc -function random_start_vector(t::AbstractMatrix) - return randn(scalartype(t), size(t, 1)) -end +random_start_vector(t::AbstractMatrix) = randn(scalartype(t), size(t, 1)) +deterministic_start_vector(t::AbstractMatrix) = ones(scalartype(t), size(t, 1)) # Compute SVD data block-wise using KrylovKit algorithm # TODO: redefine _empty_svdtensors, _create_svdtensors -function _svd_trunc!(f, alg::IterSVD, trunc::TruncationStrategy) +function MatrixAlgebraKit.svd_trunc!(f, alg::TruncatedAlgorithm{<:IterSVD}) + fwd_alg = alg.alg + trunc = alg.trunc U, S, V = if isempty(blocksectors(f)) # early return truncation_error = zero(real(scalartype(f))) - MatrixAlgebraKit.initialize_output(svd_compact!, f, LAPACK_QRIteration()) # specified algorithm doesn't matter here + MatrixAlgebraKit.initialize_output(svd_compact!, f, DefaultAlgorithm()) # specified algorithm doesn't matter here else - SVDdata, dims = _compute_svddata!(f, alg, trunc) + SVDdata, dims = _compute_svddata!(f, fwd_alg, trunc) _create_svdtensors(f, SVDdata, dims) end - # construct info NamedTuple truncation_error = trunc isa NoTruncation ? abs(zero(scalartype(f))) : norm(U * S * V - f) - condition_number = cond(S) - info = (; - truncation_error, condition_number, U_full = nothing, S_full = nothing, V_full = nothing, - truncation_indices = nothing, - ) - return U, S, V, info + return U, S, V, truncation_error end # Copy from TensorKit v0.14 internal functions @@ -319,7 +271,7 @@ function _compute_svddata!( howmany = trunc isa NoTruncation ? minimum(size(b)) : blockdim(trunc.space, c) if howmany / minimum(size(b)) > alg.fallback_threshold # Use dense SVD for small blocks - U, S, V = svd_compact!(b, LAPACK_DivideAndConquer()) + U, S, V = svd_compact!(b; alg = Defaults.svd_fwd_alg) S = S.diag # extracts diagonal as Vector instead of Diagonal to make compatible with S of svdsolve U = U[:, 1:howmany] V = V[1:howmany, :] @@ -332,7 +284,7 @@ function _compute_svddata!( S, lvecs, rvecs, info = svdsolve(b, x₀, howmany, :LR, svd_alg) if info.converged < howmany # Fall back to dense SVD if not properly converged @warn "Iterative SVD did not converge for block $c, falling back to dense SVD" - U, S, V = svd_compact!(b, LAPACK_DivideAndConquer()) + U, S, V = svd_compact!(b; alg = Defaults.svd_fwd_alg) S = S.diag U = U[:, 1:howmany] V = V[1:howmany, :] @@ -342,6 +294,9 @@ function _compute_svddata!( end end + # make it deterministic-ish + MatrixAlgebraKit.gaugefix!(svd_trunc!, U, V) + resize!(S, howmany) dims[c] = length(S) return c => (U, S, V) @@ -356,16 +311,19 @@ end # # svd_trunc! rrule wrapping MatrixAlgebraKit's svd_pullback! +# https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/blob/b76c7bb60014ecfead6925d0df6cb4b8d7c2668a/src/pullbacks/svd.jl#L33 function ChainRulesCore.rrule( ::typeof(svd_trunc!), t::AbstractTensorMap, - alg::SVDAdjoint{F, R}; - trunc::TruncationStrategy = notrunc(), - ) where {F, R <: FullSVDPullback} - @assert !(alg.fwd_alg isa IterSVD) "IterSVD is not compatible with FullSVDPullback" + alg::SVDAdjoint{F, R} + ) where {F <: TruncatedAlgorithm{<:MatrixAlgebraKit.Algorithm}, R <: FullSVDPullback} + # TODO: filter out any decomposition algorithm that doesn't give access to the full spectrum + + # requires access to the full decomposition + U, S, V⁺ = svd_compact!(t, alg.fwd_alg.alg) + (Ũ, S̃, Ṽ⁺), inds = truncate(svd_trunc!, (U, S, V⁺), alg.fwd_alg.trunc) + truncerror = truncation_error(diagview(S), inds) - Ũ, S̃, Ṽ⁺, info = svd_trunc(t, alg; trunc) - U, S, V⁺, inds = info.U_full, info.S_full, info.V_full, info.truncation_indices # untruncated decomposition gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) function svd_trunc!_full_pullback(ΔUSV′) @@ -380,17 +338,17 @@ function ChainRulesCore.rrule( return NoTangent(), ZeroTangent(), NoTangent() end - return (Ũ, S̃, Ṽ⁺, info), svd_trunc!_full_pullback + return (Ũ, S̃, Ṽ⁺, truncerror), svd_trunc!_full_pullback end # svd_trunc! rrule wrapping MatrixAlgebraKit's svd_trunc_pullback! (also works for IterSVD) +# https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/blob/b76c7bb60014ecfead6925d0df6cb4b8d7c2668a/src/pullbacks/svd.jl#L143 function ChainRulesCore.rrule( ::typeof(svd_trunc!), t, - alg::SVDAdjoint{F, R}; - trunc::TruncationStrategy = notrunc(), + alg::SVDAdjoint{F, R}, ) where {F, R <: TruncSVDPullback} - U, S, V⁺, info = svd_trunc(t, alg; trunc) + U, S, V⁺, ϵ = svd_trunc(t, alg) gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) function svd_trunc!_trunc_pullback(ΔUSV′) @@ -405,17 +363,16 @@ function ChainRulesCore.rrule( return NoTangent(), ZeroTangent(), NoTangent() end - return (U, S, V⁺, info), svd_trunc!_trunc_pullback + return (U, S, V⁺, ϵ), svd_trunc!_trunc_pullback end # KrylovKit rrule compatible with TensorMaps & function handles function ChainRulesCore.rrule( ::typeof(svd_trunc!), f, - alg::SVDAdjoint{F, R}; - trunc::TruncationStrategy = notrunc(), + alg::SVDAdjoint{F, R} ) where {F, R <: Union{GMRES, BiCGStab, Arnoldi}} - U, S, V, info = svd_trunc(f, alg; trunc) + U, S, V, ϵ = svd_trunc(f, alg) # update rrule_alg tolerance to be compatible with smallest singular value rrule_alg = alg.rrule_alg @@ -475,5 +432,5 @@ function ChainRulesCore.rrule( return NoTangent(), ZeroTangent(), NoTangent() end - return (U, S, V, info), svd_trunc!_itersvd_pullback + return (U, S, V, ϵ), svd_trunc!_itersvd_pullback end diff --git a/test/ctmrg/fixed_iterscheme.jl b/test/ctmrg/fixed_iterscheme.jl index 2952a485c..62c4251e4 100644 --- a/test/ctmrg/fixed_iterscheme.jl +++ b/test/ctmrg/fixed_iterscheme.jl @@ -6,10 +6,10 @@ using LinearAlgebra using TensorKit, KrylovKit using PEPSKit using PEPSKit: - FixedSVD, ctmrg_iteration, + compute_gauge_fix_gauge, + fix_phases, fix_relative_phases, - fix_global_phases, calc_elementwise_convergence, peps_normalize, ScramblingEnvGauge, @@ -19,13 +19,13 @@ using PEPSKit.Defaults: ctmrg_tol # initialize parameters D = 2 χ = 16 -svd_algs = [SVDAdjoint(; fwd_alg = (; alg = :sdd)), SVDAdjoint(; fwd_alg = (; alg = :iterative))] +svd_algs = [(; alg = :DivideAndConquer), (; alg = :iterative)] projector_algs_asymm = [:halfinfinite] #, :fullinfinite] unitcells = [(1, 1), (3, 4)] atol = 1.0e-5 # test for element-wise convergence after application of fixed step -@testset "$unitcell unit cell with $(typeof(decomposition_alg.fwd_alg)) and $projector_alg" for ( +@testset "$unitcell unit cell with $(decomposition_alg.alg) and $projector_alg" for ( unitcell, decomposition_alg, projector_alg, ) in Iterators.product( unitcells, svd_algs, projector_algs_asymm @@ -39,27 +39,31 @@ atol = 1.0e-5 env_conv1, = leading_boundary(CTMRGEnv(psi, ComplexSpace(χ)), psi, ctm_alg) - # do extra iteration to get SVD - env_conv2, info = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg) - env_fix, signs = gauge_fix(env_conv2, env_conv1, ScramblingEnvGauge()) - @test calc_elementwise_convergence(env_conv1, env_fix) ≈ 0 atol = atol - - # fix gauge of SVD - ctm_alg_fix = gauge_fix(ctm_alg, signs, info) + # do extra iteration and gauge fix + env_conv2, = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg) + env_fixed = gauge_fix(env_conv2, env_conv1, ScramblingEnvGauge()) + @test calc_elementwise_convergence(env_conv1, env_fixed) ≈ 0 atol = atol + + # fix gauge of single iteration + signs, corner_phases, edge_phases = + compute_gauge_fix_gauge(env_conv2, env_conv1, ScramblingEnvGauge()) + gauge_fixed_iteration(env::CTMRGEnv) = fix_phases( + ctmrg_iteration(n, env, ctm_alg)[1], + signs, corner_phases, edge_phases, + ) - # do iteration with FixedSVD - env_fixedsvd, = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg_fix) - env_fixedsvd = fix_global_phases(env_fixedsvd, env_conv1) - @test calc_elementwise_convergence(env_conv1, env_fixedsvd) ≈ 0 atol = atol + # do gauge-fixed iteration + env_fixed2 = @constinferred gauge_fixed_iteration(env_conv1) + @test calc_elementwise_convergence(env_conv1, env_fixed2) ≈ 0 atol = atol end # test same thing for C4v CTMRG c4v_algs = [ - (:c4v_qr, QRAdjoint(; fwd_alg = (; alg = :qr))), - (:c4v_eigh, EighAdjoint(; fwd_alg = (; alg = :qriteration))), - (:c4v_eigh, EighAdjoint(; fwd_alg = (; alg = :lanczos))), + (:c4v_qr, (; alg = :Householder)), + (:c4v_eigh, (; alg = :QRIteration)), + (:c4v_eigh, (; alg = :Lanczos)), ] -@testset "$(typeof(decomposition_alg.fwd_alg)) and $projector_alg" for +@testset "$(decomposition_alg.alg) and $projector_alg" for (projector_alg, decomposition_alg) in c4v_algs # initialize states Random.seed!(2394823842) @@ -74,31 +78,35 @@ c4v_algs = [ n = InfiniteSquareNetwork(psi) env₀ = initialize_random_c4v_env(psi, ComplexSpace(χ)) - env_conv1, = leading_boundary(env₀, psi, ctm_alg) + env_conv1, info = leading_boundary(env₀, psi, ctm_alg) # do extra iteration to check gauge fixing env_conv2, info = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg) # CHECK - env_fix, signs = gauge_fix(env_conv2, env_conv1, ScramblingEnvGaugeC4v()) - env_diff = calc_elementwise_convergence(env_conv1, env_fix) + + env_fixed = gauge_fix(env_conv2, env_conv1, ScramblingEnvGaugeC4v()) + env_diff = calc_elementwise_convergence(env_conv1, env_fixed) @info "Diff between iters = $(env_diff)" @test env_diff ≈ 0 atol = atol - if projector_alg == :c4v_eigh # TODO: enable this for :c4v_qr projector - # fix gauge of decomposition - ctm_alg_fix = gauge_fix(ctm_alg, signs, info) - # do iteration with decomposition - env_fixedsvd, = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg_fix) - env_fixedsvd = fix_global_phases(env_fixedsvd, env_conv1) - @test calc_elementwise_convergence(env_conv1, env_fixedsvd) ≈ 0 atol = atol - end + # fix gauge of single iteration + signs, corner_phases, edge_phases = + compute_gauge_fix_gauge(env_conv2, env_conv1, ScramblingEnvGaugeC4v()) + gauge_fixed_iteration(env::CTMRGEnv) = fix_phases( + ctmrg_iteration(n, env, ctm_alg)[1], + signs, corner_phases, edge_phases, + ) + + # do gauge-fixed iteration + env_fixed2 = @constinferred gauge_fixed_iteration(env_conv1) + @test calc_elementwise_convergence(env_conv1, env_fixed2) ≈ 0 atol = atol end -@testset "Element-wise consistency of :sdd and :iterative" begin +@testset "Element-wise consistency of :DivideAndConquer and :iterative" begin ctm_alg_iter = SimultaneousCTMRG(; maxiter = 200, - decomposition_alg = SVDAdjoint(; fwd_alg = (; alg = :iterative, krylovdim = χ + 10)), + decomposition_alg = (; alg = :iterative, krylovdim = χ + 10), ) - ctm_alg_full = SimultaneousCTMRG(; decomposition_alg = SVDAdjoint(; fwd_alg = (; alg = :sdd))) + ctm_alg_full = SimultaneousCTMRG(; decomposition_alg = (; alg = :DivideAndConquer)) # initialize states Random.seed!(91283219347) @@ -107,26 +115,34 @@ end env₀ = CTMRGEnv(psi, ComplexSpace(χ)) env_conv1, = leading_boundary(env₀, psi, ctm_alg_iter) - # do extra iteration to get SVD - env_conv2_iter, info_iter = ctmrg_iteration(n, env_conv1, ctm_alg_iter) - env_fix_iter, signs_iter = gauge_fix(env_conv2_iter, env_conv1, ScramblingEnvGauge()) + # do extra iteration to get gauge fixing + env_conv2_iter, info_iter = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg_iter) + env_fix_iter = gauge_fix(env_conv2_iter, env_conv1, ScramblingEnvGauge()) @test calc_elementwise_convergence(env_conv1, env_fix_iter) ≈ 0 atol = atol - env_conv2_full, info_full = ctmrg_iteration(n, env_conv1, ctm_alg_full) - env_fix_full, signs_full = gauge_fix(env_conv2_full, env_conv1, ScramblingEnvGauge()) + env_conv2_full, info_full = @constinferred ctmrg_iteration(n, env_conv1, ctm_alg_full) + env_fix_full = gauge_fix(env_conv2_full, env_conv1, ScramblingEnvGauge()) @test calc_elementwise_convergence(env_conv1, env_fix_full) ≈ 0 atol = atol - # fix gauge of SVD - ctm_alg_fix_iter = gauge_fix(ctm_alg_iter, signs_iter, info_iter) - ctm_alg_fix_full = gauge_fix(ctm_alg_full, signs_full, info_full) + # fix gauge of single iteration + signs_iter, corner_phases_iter, edge_phases_iter = + compute_gauge_fix_gauge(env_conv2_iter, env_conv1, ScramblingEnvGauge()) + gauge_fixed_iteration_iter(env::CTMRGEnv) = fix_phases( + ctmrg_iteration(n, env, ctm_alg_iter)[1], + signs_iter, corner_phases_iter, edge_phases_iter, + ) + signs_full, corner_phases_full, edge_phases_full = + compute_gauge_fix_gauge(env_conv2_full, env_conv1, ScramblingEnvGauge()) + gauge_fixed_iteration_full(env::CTMRGEnv) = fix_phases( + ctmrg_iteration(n, env, ctm_alg_full)[1], + signs_full, corner_phases_full, edge_phases_full, + ) - # do iteration with FixedSVD - env_fixedsvd_iter, = ctmrg_iteration(n, env_conv1, ctm_alg_fix_iter) - env_fixedsvd_iter = fix_global_phases(env_fixedsvd_iter, env_conv1) + # do gauge-fixed iteration + env_fixedsvd_iter = @constinferred gauge_fixed_iteration_iter(env_conv1) @test calc_elementwise_convergence(env_conv1, env_fixedsvd_iter) ≈ 0 atol = atol # This doesn't work for x₀ = rand(size(b, 1))? - env_fixedsvd_full, = ctmrg_iteration(n, env_conv1, ctm_alg_fix_full) - env_fixedsvd_full = fix_global_phases(env_fixedsvd_full, env_conv1) + env_fixedsvd_full = @constinferred gauge_fixed_iteration_full(env_conv1) @test calc_elementwise_convergence(env_conv1, env_fixedsvd_full) ≈ 0 atol = atol # check matching decompositions @@ -145,11 +161,13 @@ end end @test svalues_check + # gauge-fix the isometries using computed relative signs + U_iter_fix, V_iter_fix = fix_relative_phases(info_iter.U, info_iter.V, signs_iter) + U_full_fix, V_full_fix = fix_relative_phases(info_full.U, info_full.V, signs_full) + # check normalization of U's and V's - salg_fix_iter = ctm_alg_fix_iter.projector_alg.decomposition_alg.fwd_alg - salg_fix_full = ctm_alg_fix_full.projector_alg.decomposition_alg.fwd_alg - Us = [info_iter.U, salg_fix_iter.U, info_full.U, salg_fix_full.U] - Vs = [info_iter.V, salg_fix_iter.V, info_full.V, salg_fix_full.V] + Us = [info_iter.U, U_iter_fix, info_full.U, U_full_fix] + Vs = [info_iter.V, V_iter_fix, info_full.V, V_full_fix] for (U, V) in zip(Us, Vs) U_check = all(U) do u uu = u' * u diff --git a/test/ctmrg/flavors.jl b/test/ctmrg/flavors.jl index fe4588dca..37614ab02 100644 --- a/test/ctmrg/flavors.jl +++ b/test/ctmrg/flavors.jl @@ -12,8 +12,8 @@ D = 2 unitcells = [(1, 1), (3, 4)] projector_algs_asymm = [:halfinfinite, :fullinfinite] projector_algs_c4v = [ - (:c4v_qr, :qr), - (:c4v_eigh, :qriteration), (:c4v_eigh, :lanczos), + (:c4v_qr, :Householder), + (:c4v_eigh, :QRIteration), (:c4v_eigh, :Lanczos), ] Ts = [Float64, ComplexF64] @@ -81,7 +81,7 @@ end env₀ = initialize_random_c4v_env(peps, Venv) env, = leading_boundary( env₀, peps; alg = :c4v, projector_alg, - decomposition_alg = (; fwd_alg = (; alg = decomp_alg)) + decomposition_alg = (; alg = decomp_alg) ) @test env isa CTMRGEnv end diff --git a/test/ctmrg/gaugefix.jl b/test/ctmrg/gaugefix.jl index 6199d7ac2..fe668a4df 100644 --- a/test/ctmrg/gaugefix.jl +++ b/test/ctmrg/gaugefix.jl @@ -71,7 +71,7 @@ end n = InfiniteSquareNetwork(psi) env, = leading_boundary(env_pre, psi, alg) env′, = ctmrg_iteration(n, env, alg) - env_fixed, = gauge_fix(env′, env, gauge_alg) + env_fixed = gauge_fix(env′, env, gauge_alg) env_diff = calc_elementwise_convergence(env, env_fixed) @info "Diff between iters = $(env_diff)" @test env_diff ≈ 0 atol = atol @@ -88,7 +88,7 @@ end n = InfiniteSquareNetwork(psi) env, = leading_boundary(env_pre, psi, alg) env′, = ctmrg_iteration(n, env, alg) - env_fixed, = gauge_fix(env′, env, gauge_alg) + env_fixed = gauge_fix(env′, env, gauge_alg) env_diff = calc_elementwise_convergence(env, env_fixed) @info "Diff between iters = $(env_diff)" @test env_diff ≈ 0 atol = atol diff --git a/test/ctmrg/jacobian_real_linear.jl b/test/ctmrg/jacobian_real_linear.jl index 62d1f6062..07da478d5 100644 --- a/test/ctmrg/jacobian_real_linear.jl +++ b/test/ctmrg/jacobian_real_linear.jl @@ -4,7 +4,7 @@ using Accessors using Zygote using TensorKit, KrylovKit, PEPSKit using PEPSKit: - ctmrg_iteration, fix_relative_phases, fix_global_phases, ScramblingEnvGauge + ctmrg_iteration, compute_gauge_fix_gauge, fix_phases, ScramblingEnvGauge algs = [ (:fixed, SimultaneousCTMRG(; projector_alg = :halfinfinite)), @@ -26,16 +26,15 @@ alg_gauge = ScramblingEnvGauge() # follow code of _rrule if iterscheme == :fixed env_conv, info = ctmrg_iteration(InfiniteSquareNetwork(state), env, ctm_alg) - env_fixed, signs = gauge_fix(env_conv, env, alg_gauge) - alg_fixed = gauge_fix(ctm_alg, signs, info) + signs, corner_phases, edge_phases = compute_gauge_fix_gauge(env_conv, env, alg_gauge) - _, env_vjp = pullback(state, env_fixed) do A, x - e, = PEPSKit.ctmrg_iteration(InfiniteSquareNetwork(A), x, alg_fixed) - return PEPSKit.fix_global_phases(e, x) + _, env_vjp = pullback(state, env_conv) do A, x + e, = ctmrg_iteration(InfiniteSquareNetwork(A), x, ctm_alg) + return fix_phases(e, signs, corner_phases, edge_phases) end elseif iterscheme == :diffgauge _, env_vjp = pullback(state, env) do A, x - return gauge_fix(ctmrg_iteration(InfiniteSquareNetwork(A), x, ctm_alg)[1], x, alg_gauge)[1] + return gauge_fix(ctmrg_iteration(InfiniteSquareNetwork(A), x, ctm_alg)[1], x, alg_gauge) end end diff --git a/test/ctmrg/pepo.jl b/test/ctmrg/pepo.jl index 5b52bd367..4bd22a60a 100644 --- a/test/ctmrg/pepo.jl +++ b/test/ctmrg/pepo.jl @@ -87,7 +87,7 @@ end ctm_alg = SimultaneousCTMRG(; maxiter = 150, tol = 1.0e-8, verbosity = 2) alg_rrule = EigSolver(; solver_alg = KrylovKit.Arnoldi(; maxiter = 30, tol = 1.0e-6, eager = true), - iterscheme = :diffgauge, + iterscheme = :fixed, ) opt_alg = LBFGS(32; maxiter = 50, gradtol = 1.0e-5, verbosity = 3) function pepo_retract(x, η, α) diff --git a/test/ctmrg/unitcell.jl b/test/ctmrg/unitcell.jl index 89aa76280..1b83de2ef 100644 --- a/test/ctmrg/unitcell.jl +++ b/test/ctmrg/unitcell.jl @@ -1,7 +1,7 @@ using Test using Random using PEPSKit -using PEPSKit: _prev, _next, ctmrg_iteration, ScramblingEnvGauge +using PEPSKit: _prev, _next, ctmrg_iteration, compute_gauge_fix_gauge, ScramblingEnvGauge using TensorKit # settings @@ -39,14 +39,11 @@ function test_unitcell( @test expectation_value(peps, random_op, env′) isa Number # test if gauge fixing routines run through - _, signs = gauge_fix(env″, env′, ScramblingEnvGauge()) + signs, corner_phases, edge_phases = compute_gauge_fix_gauge(env″, env′, ScramblingEnvGauge()) @test signs isa Array - return if ctm_alg isa SimultaneousCTMRG # also test :fixed mode gauge fixing for simultaneous CTMRG - svd_alg_fixed_full = gauge_fix(SVDAdjoint(; fwd_alg = (; alg = :sdd)), signs, info) - svd_alg_fixed_iter = gauge_fix(SVDAdjoint(; fwd_alg = (; alg = :iterative)), signs, info) - @test svd_alg_fixed_full isa SVDAdjoint - @test svd_alg_fixed_iter isa SVDAdjoint - end + @test corner_phases isa Array + @test edge_phases isa Array + return nothing end @testset "Random Cartesian spaces with $ctm_alg" for ctm_alg in ctm_algs diff --git a/test/examples/bose_hubbard.jl b/test/examples/bose_hubbard.jl index 3b3a16ec6..3d7161bf6 100644 --- a/test/examples/bose_hubbard.jl +++ b/test/examples/bose_hubbard.jl @@ -27,7 +27,7 @@ Venv = U1Space(0 => 6, 1 => 4, -1 => 4, 2 => 2, -2 => 2) # algorithms boundary_alg = (; tol = 1.0e-8, alg = :simultaneous, verbosity = 2, trunc = (; alg = :fixedspace)) -gradient_alg = (; tol = 1.0e-6, maxiter = 10, alg = :eigsolver, iterscheme = :diffgauge) +gradient_alg = (; tol = 1.0e-6, maxiter = 10, alg = :eigsolver, iterscheme = :fixed) optimizer_alg = (; tol = 1.0e-4, alg = :lbfgs, verbosity = 3, maxiter = 25, ls_maxiter = 2, ls_maxfg = 2) reuse_env = true diff --git a/test/examples/j1j2_model.jl b/test/examples/j1j2_model.jl index b155d5264..3ab11d6cf 100644 --- a/test/examples/j1j2_model.jl +++ b/test/examples/j1j2_model.jl @@ -19,7 +19,7 @@ env₀, = leading_boundary(CTMRGEnv(peps₀, ComplexSpace(χenv)), peps₀) # find fixedpoint peps, env, E, = fixedpoint( H, peps₀, env₀; - tol = 1.0e-3, gradient_alg = (; iterscheme = :diffgauge), symmetrization = RotateReflect(), + tol = 1.0e-3, gradient_alg = (; iterscheme = :fixed), symmetrization = RotateReflect(), ) ξ_h, ξ_v, = correlation_length(peps, env) diff --git a/test/gradients/c4v_ctmrg_gradients.jl b/test/gradients/c4v_ctmrg_gradients.jl index 6b0b2f9ad..f7993a9b8 100644 --- a/test/gradients/c4v_ctmrg_gradients.jl +++ b/test/gradients/c4v_ctmrg_gradients.jl @@ -94,6 +94,15 @@ end # check for allowed combinations of projector alg and decomposition rrule alg decomposition_rrule_alg in allowed_rrule_algs[projector_alg] || continue + # construct appropriate decomposition struct to pass custom rrule alg + decomposition_alg = if projector_alg == :c4v_eigh + EighAdjoint(; rrule_alg = (; alg = decomposition_rrule_alg)) + elseif projector_alg == :c4v_qr + QRAdjoint(; rrule_alg = (; alg = decomposition_rrule_alg)) + else + error("unknown projector alg: $projector_alg") + end + @info "optimtest of ctmrg_alg=:$ctmrg_alg, projector_alg=:$projector_alg, decomposition_rrule_alg=:$decomposition_rrule_alg, gradient_alg=:$gradient_alg and gradient_iterscheme=:$gradient_iterscheme on $(names[i])" Random.seed!(sd) dir = InfinitePEPS(Pspace, Vspace) @@ -105,7 +114,7 @@ end alg = ctmrg_alg, verbosity = ctmrg_verbosity, projector_alg = projector_alg, - decomposition_alg = (; rrule_alg = (; alg = decomposition_rrule_alg)), + decomposition_alg, ) # instantiate because hook_pullback doesn't go through the keyword selector... concrete_gradient_alg = if isnothing(gradient_alg) diff --git a/test/gradients/ctmrg_gradients.jl b/test/gradients/ctmrg_gradients.jl index ab4b0915e..128f67caf 100644 --- a/test/gradients/ctmrg_gradients.jl +++ b/test/gradients/ctmrg_gradients.jl @@ -20,7 +20,7 @@ gradtol = 1.0e-4 ctmrg_verbosity = 0 ctmrg_algs = [[:sequential, :simultaneous], [:sequential, :simultaneous]] projector_algs = [[:halfinfinite, :fullinfinite], [:halfinfinite, :fullinfinite]] -svd_rrule_algs = [[:full, :arnoldi], [:full, :arnoldi]] +svd_rrule_algs = [[:full, :trunc, :arnoldi], [:full, :arnoldi]] gradient_algs = [ [nothing, :geomsum, :manualiter, :linsolver, :eigsolver], [:geomsum, :manualiter, :linsolver, :eigsolver], @@ -28,6 +28,7 @@ gradient_algs = [ gradient_iterschemes = [[:fixed, :diffgauge], [:fixed, :diffgauge]] steps = -0.01:0.005:0.01 +# don't check naive AD gradients for all algorithm combinations, since it's slow naive_gradient_combinations = [ (:simultaneous, :halfinfinite, :full), (:simultaneous, :fullinfinite, :full), @@ -35,6 +36,15 @@ naive_gradient_combinations = [ ] naive_gradient_done = Set() +# don't check :diffgauge gradients for all algorithm combinations, since it's slow +diffgauge_gradient_combinations = [ + (:simultaneous, :halfinfinite, :full), + (:sequential, :halfinfinite, :full), + (:simultaneous, :fullinfinite, :full), + (:sequential, :fullinfinite, :full), +] +diffgauge_gradient_done = Set() + # :fixed iterscheme is incompatible with sequential CTMRG function _check_disallowed_combination( ctmrg_alg, projector_alg, decomposition_rrule_alg, gradient_alg, gradient_iterscheme @@ -84,6 +94,14 @@ end push!(naive_gradient_done, combo) end + # check for allowed algorithm combinations when testing :diffgauge gradient + if gradient_iterscheme == :diffgauge + combo = (ctmrg_alg, projector_alg, svd_rrule_alg) + combo in diffgauge_gradient_combinations || continue + combo in diffgauge_gradient_done && continue + push!(diffgauge_gradient_done, combo) + end + @info "optimtest of ctmrg_alg=:$ctmrg_alg, projector_alg=:$projector_alg, svd_rrule_alg=:$svd_rrule_alg, gradient_alg=:$gradient_alg and gradient_iterscheme=:$gradient_iterscheme on $(names[i])" Random.seed!(42039482030) dir = InfinitePEPS(Pspace, Vspace) @@ -93,7 +111,7 @@ end alg = ctmrg_alg, verbosity = ctmrg_verbosity, projector_alg = projector_alg, - decomposition_alg = (; rrule_alg = (; alg = svd_rrule_alg)), + decomposition_alg = SVDAdjoint(; rrule_alg = (; alg = svd_rrule_alg)), ) # instantiate because hook_pullback doesn't go through the keyword selector... concrete_gradient_alg = if isnothing(gradient_alg) diff --git a/test/utility/eigh_wrapper.jl b/test/utility/eigh_wrapper.jl index 4533897b2..d7ff4ed5f 100644 --- a/test/utility/eigh_wrapper.jl +++ b/test/utility/eigh_wrapper.jl @@ -6,9 +6,12 @@ using ChainRulesCore, Zygote using Accessors using PEPSKit +using MatrixAlgebraKit: TruncatedAlgorithm, diagview + # Gauge-invariant loss function function lossfun(A, alg, R = randn(space(A)), trunc = notrunc()) - D, V, = eigh_trunc(A, alg; trunc) + alg = @set alg.fwd_alg = TruncatedAlgorithm(alg.fwd_alg, trunc) + D, V, = eigh_trunc(A, alg) return real(dot(R, V * V')) + dot(D, D) # Overlap with random tensor R is gauge-invariant and differentiable end @@ -23,9 +26,9 @@ r = 0.5 * (r + r') # make r Hermitian R = randn(space(r)) R = 0.5 * (R + R') -full_alg = EighAdjoint(; fwd_alg = (; alg = :qriteration), rrule_alg = (; alg = :full)) -trunc_alg = EighAdjoint(; fwd_alg = (; alg = :qriteration), rrule_alg = (; alg = :trunc)) -iter_alg = EighAdjoint(; fwd_alg = (; alg = :lanczos), rrule_alg = (; alg = :trunc)) +full_alg = EighAdjoint(; fwd_alg = (; alg = :QRIteration), rrule_alg = (; alg = :full)) +trunc_alg = EighAdjoint(; fwd_alg = (; alg = :QRIteration), rrule_alg = (; alg = :trunc)) +iter_alg = EighAdjoint(; fwd_alg = (; alg = :Lanczos), rrule_alg = (; alg = :trunc)) @testset "Non-truncated eigh" begin l_full, g_full = withgradient(A -> lossfun(A, full_alg, R), r) @@ -114,7 +117,13 @@ end @testset "Truncated symmetric eigh broadening for $(alg.rrule_alg)" for alg in [full_alg, trunc_alg] d, v = eigh_full(symm_r) - d.data[1:2:symm_m] .= d.data[2:2:symm_m] # make every eigenvalue two-fold degenerate + # make every singular value in the 0-sector three-fold degenerate + b0 = diagview(block(d, Z2Irrep(0))) + b0[1:3:symm_m] .= b0[3:3:symm_m] + b0[2:3:symm_m] .= b0[3:3:symm_m] + # make every singular value in the 1-sector two-fold degenerate + b1 = diagview(block(d, Z2Irrep(1))) + b1[1:2:symm_n] .= b1[2:2:symm_n] symm_r_degen = v * d * v' no_broadening_no_cutoff_alg = @set alg.rrule_alg.degeneracy_atol = 1.0e-30 diff --git a/test/utility/svd_wrapper.jl b/test/utility/svd_wrapper.jl index 411b05d9a..95c0208df 100644 --- a/test/utility/svd_wrapper.jl +++ b/test/utility/svd_wrapper.jl @@ -5,11 +5,13 @@ using TensorKit using ChainRulesCore, Zygote using Accessors using PEPSKit -# using PEPSKit: HalfInfiniteEnv + +using MatrixAlgebraKit: TruncatedAlgorithm, diagview # Gauge-invariant loss function function lossfun(A, alg, R = randn(space(A)), trunc = notrunc()) - U, S, V, = svd_trunc(A, alg; trunc) + alg = @set alg.fwd_alg = TruncatedAlgorithm(alg.fwd_alg, trunc) + U, S, V, = svd_trunc(A, alg) return real(dot(R, U * V)) + dot(S, S) # Overlap with random tensor R is gauge-invariant and differentiable, also for m≠n end @@ -18,7 +20,7 @@ m, n = 20, 30 χ = 12 trunc = truncspace(ℂ^χ) rtol = 1.0e-9 -Random.seed!(123456789) +Random.seed!(12345678) r = randn(dtype, ℂ^m, ℂ^n) R = randn(space(r)) @@ -111,7 +113,13 @@ end @testset "Truncated symmetric SVD broadening for $(alg.rrule_alg)" for alg in [full_alg, trunc_alg] u, s, v, = svd_compact(symm_r) - s.data[1:2:m] .= s.data[2:2:m] # make every singular value two-fold degenerate + # make every singular value in the 0-sector three-fold degenerate + b0 = diagview(block(s, Z2Irrep(0))) + b0[1:3:symm_m] .= b0[3:3:symm_m] + b0[2:3:symm_m] .= b0[3:3:symm_m] + # make every singular value in the 1-sector two-fold degenerate + b1 = diagview(block(s, Z2Irrep(1))) + b1[1:2:symm_n] .= b1[2:2:symm_n] symm_r_degen = u * s * v no_broadening_no_cutoff_alg = @set alg.rrule_alg.degeneracy_atol = 1.0e-30