diff --git a/src/algorithms/contractions/ctmrg/characteristic_equations.jl b/src/algorithms/contractions/ctmrg/characteristic_equations.jl index 621f37316..724e639d0 100644 --- a/src/algorithms/contractions/ctmrg/characteristic_equations.jl +++ b/src/algorithms/contractions/ctmrg/characteristic_equations.jl @@ -53,6 +53,7 @@ end Efp::EdgeTensor, # unused Ufp::LeftProjector, ULfp::LeftProjector; + projector_alg, getsite = getindex, ) @@ -66,7 +67,9 @@ corner and edge tensors, while ``u`` parametrizes a differentiable projector ``U U_{fp} + U_{L,fp} * u``. The local sandwich is read through `getsite`, so a caller can choose whether it is -differentiated at all; see [`PEPSKit.constant_site`](@ref). +differentiated at all; see [`PEPSKit.constant_site`](@ref). The projector algorithm +`projector_alg` of the contraction selects how ``C_{fp}^{-1}`` is computed: the corner is +diagonal for [`C4vEighProjector`](@ref), but only Hermitian for [`C4vQRProjector`](@ref). ``F`` returns a tuple of three tensors, corresponding to an equation for ``C``, ``E`` and ``u`` respectively: @@ -100,10 +103,11 @@ function generate_symmetric_characteristic_equation( Efp::EdgeTensor, # unused Ufp::LeftProjector, ULfp::LeftProjector; + projector_alg, getsite = getindex, ) - iC = sdiag_pow(real(DiagonalTensorMap(Cfp)), -1) + iC = _c4v_corner_inverse(projector_alg, Cfp) ULd = ULfp' function symmetric_characteristic_equation(n, C, E, u) diff --git a/src/algorithms/ctmrg/projectors/c4v_eigh.jl b/src/algorithms/ctmrg/projectors/c4v_eigh.jl index 9e4903900..c990bfed7 100644 --- a/src/algorithms/ctmrg/projectors/c4v_eigh.jl +++ b/src/algorithms/ctmrg/projectors/c4v_eigh.jl @@ -35,6 +35,9 @@ function C4vEighProjector(; kwargs...) end PROJECTOR_SYMBOLS[:C4vEighProjector] = C4vEighProjector +# diagonal inverse for diagonal corner +_c4v_corner_inverse(::C4vEighProjector, C) = sdiag_pow(real(DiagonalTensorMap(C)), -1) + """ Compute the normalized and Hermitian-symmetrized C₄ᵥ enlarged corner. ``` diff --git a/src/algorithms/ctmrg/projectors/c4v_qr.jl b/src/algorithms/ctmrg/projectors/c4v_qr.jl index 51dfbd4f8..987adb4aa 100644 --- a/src/algorithms/ctmrg/projectors/c4v_qr.jl +++ b/src/algorithms/ctmrg/projectors/c4v_qr.jl @@ -26,6 +26,12 @@ PROJECTOR_SYMBOLS[:C4vQRProjector] = C4vQRProjector decomposition_algorithm(alg::C4vQRProjector) = alg.decomposition_alg +# full inverse for non-diagonal Hermitian corner +function _c4v_corner_inverse(::C4vQRProjector, C) + D, V = eigh_full(C) + return V * sdiag_pow(D, -1) * V' +end + # no truncation _set_truncation(alg::C4vQRProjector, ::TruncationStrategy) = alg _set_decomposition_truncation(alg::C4vQRProjector, ::TruncationStrategy) = alg diff --git a/src/algorithms/optimization/implicit_differentiation.jl b/src/algorithms/optimization/implicit_differentiation.jl index d3a0fbfe3..f64b1b17e 100644 --- a/src/algorithms/optimization/implicit_differentiation.jl +++ b/src/algorithms/optimization/implicit_differentiation.jl @@ -504,9 +504,11 @@ function _rrule( # Two tapes: the linear solve only uses the environment cotangents, so reading the # sandwich through `constant_site` leaves the ket and bra cotangents unforced. The state # pullback runs once, after the solve, and gets its own tape. - F_tracked = generate_symmetric_characteristic_equation(C, E, U, UL) + F_tracked = generate_symmetric_characteristic_equation( + C, E, U, UL; projector_alg = alg.projector_alg + ) F_untracked = generate_symmetric_characteristic_equation( - C, E, U, UL; getsite = constant_site + C, E, U, UL; projector_alg = alg.projector_alg, getsite = constant_site ) network = InfiniteSquareNetwork(state)