|
| 1 | +""" |
| 2 | +$(TYPEDEF) |
| 3 | +
|
| 4 | +C4v symmetric Corner Transfer Matrix Renormalization Group |
| 5 | +
|
| 6 | +### Constructors |
| 7 | + $(FUNCTIONNAME)(T) |
| 8 | + $(FUNCTIONNAME)(T, [, symmetrize=false]) |
| 9 | +
|
| 10 | +c4vCTM can be called with a (2,2) tensor (West, South, North, East) with the usual arrow conventions (flipped arrow convention), |
| 11 | +or with a (0,4) tensor (North, East, South, West) (unflipped arrow convention). |
| 12 | +The keyword argument symmetrize makes the tensor C4v symmetric when set to true. If symmetrize = false, it checks the symmetry explicitly. |
| 13 | +
|
| 14 | +### Running the algorithm |
| 15 | + run!(::c4vCTM, trunc::TensorKit.TruncationSheme, stop::Stopcrit[, finalize_beginning=true, verbosity=1]) |
| 16 | +
|
| 17 | +!!! info "verbosity levels" |
| 18 | + - 0: No output |
| 19 | + - 1: Print information at start and end of the algorithm |
| 20 | + - 2: Print information at each step |
| 21 | +
|
| 22 | +### Fields |
| 23 | +
|
| 24 | +$(TYPEDFIELDS) |
| 25 | +""" |
| 26 | +mutable struct c4vCTM{A, S} |
| 27 | + T::TensorMap{A, S, 0, 4} |
| 28 | + C::TensorMap{A, S, 1, 1} |
| 29 | + E::TensorMap{A, S, 2, 1} |
| 30 | + |
| 31 | + function c4vCTM(T::TensorMap{A, S, 0, 4}) where {A, S} |
| 32 | + C, E = c4vCTM_init(T) |
| 33 | + |
| 34 | + return new{A, S}(T, C, E) |
| 35 | + end |
| 36 | +end |
| 37 | + |
| 38 | +function c4vCTM(T_flipped::TensorMap{A, S, 2, 2}; symmetrize = false) where {A, S} |
| 39 | + T_unflipped = permute(flip(T_flipped, (1, 2); inv = true), ((), (3, 4, 2, 1))) |
| 40 | + if symmetrize |
| 41 | + T_unflipped = symmetrize_C4v(T_unflipped) |
| 42 | + else |
| 43 | + @assert norm(T_flipped - T_flipped') < 1.0e-14 |
| 44 | + @assert norm(T_unflipped - rotl90_pf(T_unflipped)) < 1.0e-14 |
| 45 | + end |
| 46 | + return c4vCTM(T_unflipped) |
| 47 | +end |
| 48 | + |
| 49 | +# Functions to permute (flipped and unflipped) tensors under 90 degree rotation |
| 50 | +function rotl90_pf(T::TensorMap{A, S, 2, 2}) where {A, S} |
| 51 | + return permute(T, ((3, 1), (4, 2))) |
| 52 | +end |
| 53 | + |
| 54 | +function rotl90_pf(T::TensorMap{A, S, 0, 4}) where {A, S} |
| 55 | + return permute(T, ((), (2, 3, 4, 1))) |
| 56 | +end |
| 57 | + |
| 58 | +# Function to construct a C4v symmetric tensor from a given tensor in the unflipped arrow convention |
| 59 | +function symmetrize_C4v(T_unflipped) |
| 60 | + T_c4_unflipped = (T_unflipped + rotl90_pf(T_unflipped) + rotl90_pf(rotl90_pf(T_unflipped)) + rotl90_pf(rotl90_pf(rotl90_pf(T_unflipped)))) / 4 |
| 61 | + T_c4_flipped = permute(flip(T_c4_unflipped, (3, 4); inv = false), ((4, 3), (1, 2))) |
| 62 | + T_c4v_flipped = (T_c4_flipped + T_c4_flipped') / 2 |
| 63 | + T_c4v_unflipped = permute(flip(T_c4v_flipped, (1, 2); inv = true), ((), (3, 4, 2, 1))) |
| 64 | + return T_c4v_unflipped |
| 65 | +end |
| 66 | + |
| 67 | +# Below, I wrote a code with the following correspondence. (O,C,T) <=> (scheme.T, scheme.C, scheme.E) |
| 68 | +# https://www.issp.u-tokyo.ac.jp/public/caqmp2019/slides/808L_Okubo.pdf |
| 69 | +#= |
| 70 | +┌───────┐ ┌───────┐ |
| 71 | +│ │ │ │ |
| 72 | +│ │ │ │ |
| 73 | +│ C ├──────►│ E ├──────► |
| 74 | +│ │ │ │ |
| 75 | +└───────┘ └───────┘ |
| 76 | + ▲ ▲ |
| 77 | + │ │ |
| 78 | + │ │ |
| 79 | +=# |
| 80 | + |
| 81 | +function run!( |
| 82 | + scheme::c4vCTM, trunc::TensorKit.TruncationScheme, criterion::stopcrit; |
| 83 | + verbosity = 1 |
| 84 | + ) |
| 85 | + LoggingExtras.withlevel(; verbosity) do |
| 86 | + @infov 1 "Starting simulation\n $(scheme)\n" |
| 87 | + steps = 0 |
| 88 | + crit = true |
| 89 | + ε = Inf |
| 90 | + S_prev = id(domain(scheme.C)) |
| 91 | + |
| 92 | + t = @elapsed while crit |
| 93 | + @infov 2 "Step $(steps + 1), ε = $(ε)" |
| 94 | + |
| 95 | + S = step!(scheme, trunc) |
| 96 | + |
| 97 | + if space(S) == space(S_prev) |
| 98 | + ε = norm(S^4 - S_prev^4) |
| 99 | + end |
| 100 | + |
| 101 | + S_prev = S |
| 102 | + |
| 103 | + steps += 1 |
| 104 | + crit = criterion(steps, ε) |
| 105 | + end |
| 106 | + |
| 107 | + @infov 1 "Simulation finished\n $(stopping_info(criterion, steps, ε))\n Elapsed time: $(t)s\n Iterations: $steps" |
| 108 | + end |
| 109 | + return lnz(scheme) |
| 110 | +end |
| 111 | + |
| 112 | +function step!(scheme::c4vCTM, trunc) |
| 113 | + mat, U, S = find_U_sym(scheme, trunc) |
| 114 | + |
| 115 | + @tensor scheme.C[-1; -2] := mat[1 2; 3 4] * U[3 4; -2] * conj(U[1 2; -1]) |
| 116 | + @tensor scheme.E[-1 -2; -3] := scheme.E[1 5; 3] * flip(scheme.T, (3, 4); inv = true)[5 4 -2 2] * |
| 117 | + U[3 4; -3] * |
| 118 | + conj(U[1 2; -1]) |
| 119 | + |
| 120 | + scheme.C /= norm(scheme.C) |
| 121 | + scheme.E /= norm(scheme.E) |
| 122 | + return S |
| 123 | +end |
| 124 | + |
| 125 | +function lnz(scheme::c4vCTM) |
| 126 | + Z, env = tensor2env(permute(flip(scheme.T, (3, 4); inv = true), ((4, 3), (1, 2))), scheme.C, scheme.E) |
| 127 | + # should be inv = false ?? |
| 128 | + return real(log(network_value(Z, env))) |
| 129 | +end |
| 130 | + |
| 131 | +function build_corner_matrix(scheme) |
| 132 | + @tensor opt = true mat[-1 -2; -3 -4] := scheme.C[1; 2] * scheme.E[-1 3; 1] * |
| 133 | + scheme.E[2 4; -3] * |
| 134 | + flip(scheme.T, 3; inv = true)[4 -4 -2 3] |
| 135 | + return mat |
| 136 | +end |
| 137 | + |
| 138 | +function find_U_sym(scheme, trunc) |
| 139 | + mat = build_corner_matrix(scheme) |
| 140 | + # avoid symmetry breaking due to numerical accuracy |
| 141 | + mat = 0.5 * (mat + adjoint(mat)) |
| 142 | + |
| 143 | + U, S, _ = tsvd(mat; trunc = trunc & truncbelow(1.0e-20)) |
| 144 | + return mat, U, S |
| 145 | +end |
| 146 | + |
| 147 | +function c4vCTM_init(T::TensorMap{A, S, 0, 4}) where {A, S} |
| 148 | + S_type = scalartype(T) |
| 149 | + Vp = space(T)[1]' |
| 150 | + C = TensorMap(ones, S_type, oneunit(Vp) ← oneunit(Vp)) |
| 151 | + E = TensorMap(ones, S_type, oneunit(Vp) ⊗ Vp ← oneunit(Vp)) |
| 152 | + return C, E |
| 153 | +end |
| 154 | + |
| 155 | +function tensor2env(O, C, T) |
| 156 | + Z = InfinitePartitionFunction(O) |
| 157 | + env = CTMRGEnv(Z, space(C)[1]) |
| 158 | + |
| 159 | + for i in 1:4 |
| 160 | + env.corners[i] = C |
| 161 | + env.edges[i] = T |
| 162 | + end |
| 163 | + |
| 164 | + env.edges[3] = flip(T, 2) |
| 165 | + env.edges[4] = flip(T, 2) |
| 166 | + return Z, env |
| 167 | +end |
| 168 | + |
| 169 | +function Base.show(io::IO, scheme::c4vCTM) |
| 170 | + println(io, "c4vCTM - C4v symmetric Corner Transfer Matrix") |
| 171 | + println(io, " * T: $(summary(scheme.T))") |
| 172 | + println(io, " * C: $(summary(scheme.C))") |
| 173 | + println(io, " * E: $(summary(scheme.E))") |
| 174 | + return nothing |
| 175 | +end |
0 commit comments