|
| 1 | +""" |
| 2 | +Replace bond environment `benv` by its positive approximant `Z† Z` |
| 3 | +(returns the "half environment" `Z`) |
| 4 | +``` |
| 5 | + ┌-----------------┐ ┌---------------┐ |
| 6 | + | ┌----┐ | | | |
| 7 | + └-| |-- 3 4 --┘ └-- Z -- 3 4 --┘ |
| 8 | + |benv| = ↓ |
| 9 | + ┌-| |-- 1 2 --┐ ┌-- Z†-- 1 2 --┐ |
| 10 | + | └----┘ | | | |
| 11 | + └-----------------┘ └---------------┘ |
| 12 | +``` |
| 13 | +""" |
| 14 | +function positive_approx(benv::BondEnv) |
| 15 | + # eigen-decomposition: benv = U D U' |
| 16 | + D, U = eigh((benv + benv') / 2) |
| 17 | + # determine if `env` is (mostly) positive or negative |
| 18 | + sgn = sign(sum(D.data)) |
| 19 | + # When optimizing the truncation of a bond, |
| 20 | + # its environment can always be multiplied by a number. |
| 21 | + # If `benv` is negative (e.g. obtained approximately from CTMRG), |
| 22 | + # we can multiply it by (-1). |
| 23 | + data = D.data |
| 24 | + @inbounds for i in eachindex(data) |
| 25 | + d = (sgn == -1) ? -data[i] : data[i] |
| 26 | + data[i] = (d > 0) ? sqrt(d) : zero(d) |
| 27 | + end |
| 28 | + Z = D * U' |
| 29 | + return Z |
| 30 | +end |
| 31 | + |
| 32 | +""" |
| 33 | +Use QR decomposition to fix gauge of the half bond environment `Z`. |
| 34 | +The reduced bond tensors `a`, `b` and `Z` are arranged as |
| 35 | +``` |
| 36 | + ┌---------------┐ |
| 37 | + | | |
| 38 | + └---Z---a---b---┘ |
| 39 | + | ↓ ↓ |
| 40 | + ↓ |
| 41 | +``` |
| 42 | +Reference: |
| 43 | +- Physical Review B 90, 064425 (2014) |
| 44 | +- Physical Review B 92, 035142 (2015) |
| 45 | +""" |
| 46 | +function fixgauge_benv( |
| 47 | + Z::AbstractTensorMap{T,S,1,2}, |
| 48 | + a::AbstractTensorMap{T,S,1,2}, |
| 49 | + b::AbstractTensorMap{T,S,2,1}, |
| 50 | +) where {T<:Number,S<:ElementarySpace} |
| 51 | + @assert !isdual(space(Z, 1)) |
| 52 | + @assert !isdual(space(a, 2)) |
| 53 | + @assert !isdual(space(b, 2)) |
| 54 | + #= QR/LQ decomposition of Z |
| 55 | +
|
| 56 | + 3 - Z - 2 = 2 - L - 1 3 - QL - 1 |
| 57 | + ↓ ↓ |
| 58 | + 1 2 |
| 59 | +
|
| 60 | + = 1 - QR - 3 1 - R - 2 |
| 61 | + ↓ |
| 62 | + 2 |
| 63 | + =# |
| 64 | + QL, L = leftorth(Z, ((2, 1), (3,))) |
| 65 | + QR, R = leftorth(Z, ((3, 1), (2,))) |
| 66 | + @debug "cond(L) = $(LinearAlgebra.cond(L)); cond(R) = $(LinearAlgebra.cond(R))" |
| 67 | + # TODO: find a better way to fix gauge that avoids `inv` |
| 68 | + Linv, Rinv = inv(L), inv(R) |
| 69 | + #= fix gauge of Z, a, b |
| 70 | + ┌---------------------------------------┐ |
| 71 | + | | |
| 72 | + └---Z---Rinv)---(R--a)--(b--L)---(Linv--┘ |
| 73 | + | ↓ ↓ |
| 74 | + ↓ |
| 75 | +
|
| 76 | + -1 - R - 1 - a - -3 -1 - b - 1 - L - -3 |
| 77 | + ↓ ↓ |
| 78 | + -2 -2 |
| 79 | +
|
| 80 | + ┌-----------------------------------------┐ |
| 81 | + | | |
| 82 | + └---Z-- 1 --Rinv-- -2 -3 --Linv-- 2 -┘ |
| 83 | + ↓ |
| 84 | + -1 |
| 85 | + =# |
| 86 | + @plansor a[-1; -2 -3] := R[-1; 1] * a[1; -2 -3] |
| 87 | + @plansor b[-1 -2; -3] := b[-1 -2; 1] * L[-3; 1] |
| 88 | + @plansor Z[-1; -2 -3] := Z[-1; 1 2] * Rinv[1; -2] * Linv[2; -3] |
| 89 | + (isdual(space(R, 1)) == isdual(space(R, 2))) && twist!(a, 1) |
| 90 | + (isdual(space(L, 1)) == isdual(space(L, 2))) && twist!(b, 3) |
| 91 | + return Z, a, b, (Linv, Rinv) |
| 92 | +end |
| 93 | + |
| 94 | +""" |
| 95 | +When the (half) bond environment `Z` consists of two `PEPSOrth` tensors `X`, `Y` as |
| 96 | +``` |
| 97 | + ┌---------------┐ ┌-------------------┐ |
| 98 | + | | = | | , |
| 99 | + └---Z-- --┘ └--Z0---X-- --Y--┘ |
| 100 | + ↓ ↓ |
| 101 | +``` |
| 102 | +apply the gauge transformation `Linv`, `Rinv` for `Z` to `X`, `Y`: |
| 103 | +``` |
| 104 | + -1 -1 |
| 105 | + | | |
| 106 | + -4 - X - 1 - Rinv - -2 -4 - Linv - 1 - Y - -2 |
| 107 | + | | |
| 108 | + -3 -3 |
| 109 | +``` |
| 110 | +""" |
| 111 | +function _fixgauge_benvXY( |
| 112 | + X::PEPSOrth{T,S}, |
| 113 | + Y::PEPSOrth{T,S}, |
| 114 | + Linv::AbstractTensorMap{T,S,1,1}, |
| 115 | + Rinv::AbstractTensorMap{T,S,1,1}, |
| 116 | +) where {T<:Number,S<:ElementarySpace} |
| 117 | + @plansor X[-1 -2 -3 -4] := X[-1 1 -3 -4] * Rinv[1; -2] |
| 118 | + @plansor Y[-1 -2 -3 -4] := Y[-1 -2 -3 1] * Linv[1; -4] |
| 119 | + return X, Y |
| 120 | +end |
0 commit comments