|
| 1 | +""" |
| 2 | +$(TYPEDEF) |
| 3 | +
|
| 4 | +CTMRG algorithm assuming a C₄ᵥ-symmetric PEPS, i.e. invariance under 90° spatial rotation and |
| 5 | +Hermitian reflection. This requires a single-site unit cell. The projector is obtained from |
| 6 | +`eigh` decomposing the Hermitian enlarged corner. |
| 7 | +
|
| 8 | +## Fields |
| 9 | +
|
| 10 | +$(TYPEDFIELDS) |
| 11 | +
|
| 12 | +## Constructors |
| 13 | +
|
| 14 | + C4vCTMRG(; kwargs...) |
| 15 | +
|
| 16 | +Construct a C₄ᵥ CTMRG algorithm struct based on keyword arguments. |
| 17 | +For a full description, see [`leading_boundary`](@ref). The supported keywords are: |
| 18 | +
|
| 19 | +* `tol::Real=$(Defaults.ctmrg_tol)` |
| 20 | +* `maxiter::Int=$(Defaults.ctmrg_maxiter)` |
| 21 | +* `miniter::Int=$(Defaults.ctmrg_miniter)` |
| 22 | +* `verbosity::Int=$(Defaults.ctmrg_verbosity)` |
| 23 | +* `trunc::Union{TruncationStrategy,NamedTuple}=(; alg::Symbol=:$(Defaults.trunc))` |
| 24 | +* `decomposition_alg::Union{<:EighAdjoint,NamedTuple}` |
| 25 | +* `projector_alg::Symbol=:$(Defaults.projector_alg_c4v)` |
| 26 | +""" |
| 27 | +struct C4vCTMRG{P <: ProjectorAlgorithm} <: CTMRGAlgorithm |
| 28 | + tol::Float64 |
| 29 | + maxiter::Int |
| 30 | + miniter::Int |
| 31 | + verbosity::Int |
| 32 | + projector_alg::P |
| 33 | +end |
| 34 | +function C4vCTMRG(; kwargs...) |
| 35 | + return CTMRGAlgorithm(; alg = :c4v, kwargs...) |
| 36 | +end |
| 37 | +CTMRG_SYMBOLS[:c4v] = C4vCTMRG |
| 38 | + |
| 39 | +""" |
| 40 | +$(TYPEDEF) |
| 41 | +
|
| 42 | +Projector algorithm implementing the `eigh` decomposition of a Hermitian enlarged corner. |
| 43 | +
|
| 44 | +## Fields |
| 45 | +
|
| 46 | +$(TYPEDFIELDS) |
| 47 | +
|
| 48 | +## Constructors |
| 49 | +
|
| 50 | + C4vEighProjector(; kwargs...) |
| 51 | +
|
| 52 | +Construct the C₄ᵥ `eigh`-based projector algorithm based on the following keyword arguments: |
| 53 | +
|
| 54 | +* `decomposition_alg::Union{<:EighAdjoint,NamedTuple}=EighAdjoint()` : `eigh` algorithm including the reverse rule. See [`EighAdjoint`](@ref). |
| 55 | +* `trunc::Union{TruncationStrategy,NamedTuple}=(; alg::Symbol=:$(Defaults.trunc))` : Truncation strategy for the projector computation, which controls the resulting virtual spaces. Here, `alg` can be one of the following: |
| 56 | + - `:fixedspace` : Keep virtual spaces fixed during projection |
| 57 | + - `:notrunc` : No singular values are truncated and the performed SVDs are exact |
| 58 | + - `:truncerror` : Additionally supply error threshold `η`; truncate to the maximal virtual dimension of `η` |
| 59 | + - `:truncrank` : Additionally supply truncation dimension `η`; truncate such that the 2-norm of the truncated values is smaller than `η` |
| 60 | + - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space |
| 61 | + - `:trunctol` : Additionally supply singular value cutoff `η`; truncate such that every retained singular value is larger than `η` |
| 62 | +* `verbosity::Int=$(Defaults.projector_verbosity)` : Projector output verbosity which can be: |
| 63 | + 0. Suppress output information |
| 64 | + 1. Print singular value degeneracy warnings |
| 65 | +""" |
| 66 | +struct C4vEighProjector{S <: EighAdjoint, T} <: ProjectorAlgorithm |
| 67 | + decomposition_alg::S |
| 68 | + trunc::T |
| 69 | + verbosity::Int |
| 70 | +end |
| 71 | +function C4vEighProjector(; kwargs...) |
| 72 | + return ProjectorAlgorithm(; alg = :c4v_eigh, kwargs...) |
| 73 | +end |
| 74 | +PROJECTOR_SYMBOLS[:c4v_eigh] = C4vEighProjector |
| 75 | + |
| 76 | +# struct C4vQRProjector{S, T} <: ProjectorAlgorithm |
| 77 | +# decomposition_alg::S |
| 78 | +# verbosity::Int |
| 79 | +# end |
| 80 | +# function C4vQRProjector(; kwargs...) |
| 81 | +# return ProjectorAlgorithm(; alg = :c4v_qr, kwargs...) |
| 82 | +# end |
| 83 | +# PROJECTOR_SYMBOLS[:c4v_qr] = C4vQRProjector |
| 84 | + |
| 85 | +# |
| 86 | +## C4v-symmetric CTMRG iteration (called through `leading_boundary`) |
| 87 | +# |
| 88 | + |
| 89 | +function ctmrg_iteration( |
| 90 | + network, |
| 91 | + env::CTMRGEnv, |
| 92 | + alg::C4vCTMRG, |
| 93 | + ) |
| 94 | + enlarged_corner = c4v_enlarge(network, env, alg.projector_alg) |
| 95 | + corner′, projector, info = c4v_projector(enlarged_corner, alg.projector_alg) |
| 96 | + edge′ = c4v_renormalize(network, env, projector) |
| 97 | + return CTMRGEnv(corner′, edge′), info |
| 98 | +end |
| 99 | + |
| 100 | +""" |
| 101 | + c4v_enlarge(network, env, ::C4vEighProjector) |
| 102 | +
|
| 103 | +Compute the normalized and Hermitian-symmetrized C₄ᵥ enlarged corner. |
| 104 | +""" |
| 105 | +function c4v_enlarge(network, env, ::C4vEighProjector) |
| 106 | + enlarged_corner = TensorMap(EnlargedCorner(network, env, (NORTHWEST, 1, 1))) |
| 107 | + return 0.5 * (enlarged_corner + enlarged_corner') / norm(enlarged_corner) |
| 108 | +end |
| 109 | +# function c4v_enlarge(enlarged_corner, alg::C4vQRProjector) |
| 110 | +# # TODO |
| 111 | +# end |
| 112 | + |
| 113 | +""" |
| 114 | + c4v_projector(enlarged_corner, alg::C4vEighProjector) |
| 115 | +
|
| 116 | +Compute the C₄ᵥ projector from `eigh` decomposing the Hermitian `enlarged_corner`. |
| 117 | +Also return the normalized eigenvalues as the new corner tensor. |
| 118 | +""" |
| 119 | +function c4v_projector(enlarged_corner, alg::C4vEighProjector) |
| 120 | + trunc = truncation_strategy(alg, enlarged_corner) |
| 121 | + D, V, info = eigh_trunc!(enlarged_corner, decomposition_algorithm(alg); trunc) |
| 122 | + |
| 123 | + # Check for degenerate eigenvalues |
| 124 | + Zygote.isderiving() && ignore_derivatives() do |
| 125 | + if alg.verbosity > 0 && is_degenerate_spectrum(D) |
| 126 | + vals = TensorKit.SectorDict(c => diag(b) for (c, b) in blocks(D)) |
| 127 | + @warn("degenerate eigenvalues detected: ", vals) |
| 128 | + end |
| 129 | + end |
| 130 | + |
| 131 | + return D / norm(D), V, (; D, V, info...) |
| 132 | +end |
| 133 | +# function c4v_projector(enlarged_corner, alg::C4vQRProjector) |
| 134 | +# # TODO |
| 135 | +# end |
| 136 | + |
| 137 | +""" |
| 138 | + c4v_renormalize(network, env, projector) |
| 139 | +
|
| 140 | +Renormalize the single edge tensor. |
| 141 | +""" |
| 142 | +function c4v_renormalize(network, env, projector) |
| 143 | + new_edge = renormalize_north_edge(env.edges[1], projector, projector', network[1, 1]) |
| 144 | + new_edge = _project_hermitian(new_edge) # additional Hermitian projection step for numerical stability |
| 145 | + return new_edge / norm(new_edge) |
| 146 | +end |
| 147 | + |
| 148 | +# TODO: this should eventually be the constructor for a new C4vCTMRGEnv type |
| 149 | +function CTMRGEnv( |
| 150 | + corner::AbstractTensorMap{T, S, 1, 1}, edge::AbstractTensorMap{T′, S, N, 1} |
| 151 | + ) where {T, T′, S, N} |
| 152 | + corners = fill(corner, 4, 1, 1) |
| 153 | + edge_SW = physical_flip(edge) |
| 154 | + edges = reshape([edge, edge, edge_SW, edge_SW], (4, 1, 1)) |
| 155 | + return CTMRGEnv(corners, edges) |
| 156 | +end |
| 157 | + |
| 158 | +# |
| 159 | +## utility |
| 160 | +# |
| 161 | + |
| 162 | +# Adjoint of an edge tensor, but permutes the physical spaces back into the codomain. |
| 163 | +# Intuitively, this conjugates a tensor and then reinterprets its 'direction' as an edge tensor. |
| 164 | +function _dag(A::AbstractTensorMap{T, S, N, 1}) where {T, S, N} |
| 165 | + return permute(A', ((1, (3:(N + 1))...), (2,))) |
| 166 | +end |
| 167 | + |
| 168 | +function physical_flip(A::AbstractTensorMap{T, S, N, 1}) where {T, S, N} |
| 169 | + return flip(A, 2:N) |
| 170 | +end |
| 171 | + |
| 172 | +# call it `_project_hermitian` to avoid type piracy with MAK's exported project_hermitian |
| 173 | +function _project_hermitian(E::AbstractTensorMap{T, S, N, 1}) where {T, S, N} |
| 174 | + E´ = (E + physical_flip(_dag(E))) / 2 |
| 175 | + return E´ |
| 176 | +end |
| 177 | +function _project_hermitian(C::AbstractTensorMap{T, S, 1, 1}) where {T, S} |
| 178 | + C´ = (C + C') / 2 |
| 179 | + return C´ |
| 180 | +end |
| 181 | + |
| 182 | +# should perform this check at the beginning of `leading_boundary` really... |
| 183 | +function check_symmetry(state, ::RotateReflect; atol = 1.0e-10) |
| 184 | + @assert length(state) == 1 "check_symmetry only works for single site unit cells" |
| 185 | + @assert norm(state[1] - _fit_spaces(rotl90(state[1]), state[1])) / |
| 186 | + norm(state[1]) < atol "not rotation invariant" |
| 187 | + @assert norm(state[1] - _fit_spaces(herm_depth(state[1]), state[1])) / |
| 188 | + norm(state[1]) < atol "not hermitian-reflection invariant" |
| 189 | + return nothing |
| 190 | +end |
| 191 | + |
| 192 | +# |
| 193 | +## environment initialization |
| 194 | +# |
| 195 | + |
| 196 | +""" |
| 197 | + initialize_random_c4v_env([f=randn, T=scalartype(state)], state, Venv::ElementarySpace) |
| 198 | +
|
| 199 | +Initialize a C₄ᵥ-symmetric `CTMRGEnv` on virtual spaces `Venv` with random entries created |
| 200 | +by `f` and scalartype `T`. |
| 201 | +""" |
| 202 | +function initialize_random_c4v_env(state, Venv::ElementarySpace) |
| 203 | + return initialize_random_c4v_env(randn, scalartype(state), state, Venv) |
| 204 | +end |
| 205 | +function initialize_random_c4v_env(f, T, state::InfinitePEPS, Venv::ElementarySpace) |
| 206 | + Vpeps = north_virtualspace(state, 1, 1)' |
| 207 | + return initialize_random_c4v_env(f, T, Vpeps ⊗ Vpeps', Venv) |
| 208 | +end |
| 209 | +function initialize_random_c4v_env(f, T, state::InfinitePartitionFunction, Venv::ElementarySpace) |
| 210 | + Vpf = north_virtualspace(state, 1, 1)' |
| 211 | + return initialize_random_c4v_env(f, T, Vpf, Venv) |
| 212 | +end |
| 213 | +function initialize_random_c4v_env(f, T, Vstate::VectorSpace, Venv::ElementarySpace) |
| 214 | + corner₀ = DiagonalTensorMap(randn(real(T), Venv ← Venv)) |
| 215 | + edge₀ = f(T, Venv ⊗ Vstate ← Venv) |
| 216 | + edge₀ = _project_hermitian(edge₀) |
| 217 | + return CTMRGEnv(corner₀, edge₀) |
| 218 | +end |
| 219 | + |
| 220 | +""" |
| 221 | + initialize_singlet_c4v_env([T=scalartype(state)], state::InfinitePEPS, Venv::ElementarySpace) |
| 222 | +
|
| 223 | +Initialize a C₄ᵥ-symmetric `CTMRGEnv` with a singlet corner of dimension `dim(Venv)` and an |
| 224 | +identity edge from `id(T, Venv ⊗ Vpeps)`. |
| 225 | +""" |
| 226 | +function initialize_singlet_c4v_env(state::InfinitePEPS, Venv::ElementarySpace) |
| 227 | + return initialize_singlet_c4v_env(scalartype(state), state, Venv) |
| 228 | +end |
| 229 | +function initialize_singlet_c4v_env(T, state::InfinitePEPS, Venv::ElementarySpace) |
| 230 | + Vpeps = north_virtualspace(state, 1, 1)' |
| 231 | + return initialize_singlet_c4v_env(T, Vpeps, Venv) |
| 232 | +end |
| 233 | +function initialize_singlet_c4v_env(T, Vpeps::ElementarySpace, Venv::ElementarySpace) |
| 234 | + corner₀ = DiagonalTensorMap(zeros(real(T), Venv ← Venv)) |
| 235 | + corner₀.data[1] = one(real(T)) |
| 236 | + edge₀ = permute(id(T, Venv ⊗ Vpeps), ((1, 2, 4), (3,))) |
| 237 | + return CTMRGEnv(corner₀, edge₀) |
| 238 | +end |
0 commit comments