-
Notifications
You must be signed in to change notification settings - Fork 16
Thermal TNR #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Adwait-Naravane
wants to merge
14
commits into
QuantumKitHub:master
Choose a base branch
from
Adwait-Naravane:ThermalTNR
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Thermal TNR #172
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
3db1cad
Create another file for Ground state degeneracy
9cc0bd8
Create another file for Ground state degeneracy
8969ab8
Runic format
d7bd5b3
Add Thermal TNR algorithm
58aa579
Format
0d5ff6b
Add Finalize for Thermal TNR
65bee20
Add custom run function and step function for ThermalTNR
Adwait-Naravane f4215ad
Add references
Adwait-Naravane 798aea9
Modify the finalize of ttnr to return floats
Adwait-Naravane 1f29261
Add Tests
Adwait-Naravane db49028
Change test code to make it simpler
Adwait-Naravane cb5029c
Merge branch 'master' into ThermalTNR
Adwait-Naravane 0d6620b
Merge branch 'master' into ThermalTNR
Adwait-Naravane 05b7277
Merge branch 'master' into ThermalTNR
VictorVanthilt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,309 @@ | ||
| """ | ||
| TNOTensor{E,S} | ||
|
|
||
| Type alias for a local tensor-network-operator tensor with two physical legs and four | ||
| virtual legs, i.e. an `AbstractTensorMap{E,S,2,4}`. | ||
|
|
||
| Following the PEPO convention used in PEPSKit, the local tensor is interpreted as | ||
| `P_out ⊗ P_in <- N ⊗ E ⊗ S ⊗ W`. | ||
| """ | ||
| const TNOTensor{E, S} = AbstractTensorMap{E, S, 2, 4} | ||
|
|
||
| """ | ||
| $(TYPEDEF) | ||
|
|
||
| Matrix-like container for a tensor network operator (TNO) unit cell. | ||
|
|
||
| The entries are local operator tensors with two physical indices and four virtual | ||
| indices. The container behaves like an `AbstractMatrix`, so it supports `size`, | ||
| `axes`, indexing and iteration. | ||
|
|
||
| ### Constructors | ||
| $(FUNCTIONNAME)(A::AbstractMatrix{<:TNOTensor}) | ||
| $(FUNCTIONNAME)(A::TNOTensor; unitcell=(1, 1)) | ||
|
|
||
| ### Fields | ||
|
|
||
| $(TYPEDFIELDS) | ||
| """ | ||
| struct TNO{E, S, TT <: TNOTensor{E, S}} <: AbstractMatrix{TT} | ||
| "Matrix of local TNO tensors over the unit cell." | ||
| A::Matrix{TT} | ||
|
|
||
| function TNO(A::AbstractMatrix{TT}) where {E, S, TT <: TNOTensor{E, S}} | ||
| size(A, 1) > 0 || throw(ArgumentError("The unit cell must have a positive number of rows.")) | ||
| size(A, 2) > 0 || throw(ArgumentError("The unit cell must have a positive number of columns.")) | ||
| return new{E, S, TT}(Matrix(A)) | ||
| end | ||
| end | ||
|
|
||
| function TNO(A::TT; unitcell::Tuple{Int, Int} = (1, 1)) where {E, S, TT <: TNOTensor{E, S}} | ||
| rows, cols = unitcell | ||
| rows > 0 || throw(ArgumentError("The unit cell must have a positive number of rows.")) | ||
| cols > 0 || throw(ArgumentError("The unit cell must have a positive number of columns.")) | ||
| return TNO([copy(A) for _ in 1:rows, _ in 1:cols]) | ||
| end | ||
|
|
||
| Base.IndexStyle(::Type{<:TNO}) = IndexCartesian() | ||
| Base.eltype(::Type{TNO{E, S, TT}}) where {E, S, TT} = TT | ||
| Base.size(tno::TNO) = size(tno.A) | ||
| Base.axes(tno::TNO) = axes(tno.A) | ||
| Base.getindex(tno::TNO, i::Int, j::Int) = tno.A[i, j] | ||
| Base.setindex!(tno::TNO, value, i::Int, j::Int) = setindex!(tno.A, value, i, j) | ||
| Base.copy(tno::TNO) = TNO(copy(tno.A)) | ||
|
|
||
| """ | ||
| $(TYPEDEF) | ||
|
|
||
| Minimal storage object for thermal tensor network renormalization on a square-lattice | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line is a stylistic break from all the other scheme's docstrings. Please fix |
||
| TNO. | ||
|
|
||
| ### Constructors | ||
| $(FUNCTIONNAME)(T::TNO) | ||
|
|
||
| ### Running the algorithm | ||
| run!(::ThermalTNR, T::TNO, trunc::TruncationStrategy, criterion::stopcrit[ | ||
| , finalizer=default_Finalizer, finalize_beginning=true, verbosity=1]) | ||
|
|
||
| ### Fields | ||
|
|
||
| $(TYPEDFIELDS) | ||
|
|
||
| ### References | ||
| * [Ueda et al. (2025)](@cite ueda_2025) | ||
| """ | ||
| mutable struct ThermalTNR{E, S} <: TNRScheme{E, S} | ||
| "Tensor network operator stored in the current TTNR layer." | ||
| T::TNO{E, S} | ||
|
|
||
| function ThermalTNR(T::TT) where {E, S, TT <: TNO{E, S}} | ||
| return new{E, S}(T) | ||
| end | ||
| end | ||
|
|
||
| const _TNO_NORTH_AXIS = 3 | ||
| const _TNO_EAST_AXIS = 4 | ||
| const _TNO_SOUTH_AXIS = 5 | ||
| const _TNO_WEST_AXIS = 6 | ||
|
|
||
| @inline _right_index(j, ncols) = mod1(j + 1, ncols) | ||
| @inline _down_index(i, nrows) = mod1(i + 1, nrows) | ||
| @inline _up_index(i, nrows) = mod1(i - 1, nrows) | ||
|
|
||
| function _check_tno_bond_structure(tno::TNO) | ||
| nrows, ncols = size(tno) | ||
|
|
||
| for i in 1:nrows, j in 1:ncols | ||
| T = tno[i, j] | ||
| T_right = tno[i, _right_index(j, ncols)] | ||
| T_down = tno[_down_index(i, nrows), j] | ||
|
|
||
| space(T, _TNO_EAST_AXIS) == space(T_right, _TNO_WEST_AXIS)' || | ||
| throw(ArgumentError("East-west bond mismatch between sites ($i, $j) and ($i, $(_right_index(j, ncols))).")) | ||
|
|
||
| space(T, _TNO_SOUTH_AXIS) == space(T_down, _TNO_NORTH_AXIS)' || | ||
| throw(ArgumentError("North-south bond mismatch between sites ($i, $j) and ($(_down_index(i, nrows)), $j).")) | ||
| end | ||
|
|
||
| return nothing | ||
| end | ||
|
|
||
| function _check_tno_compatibility(top::TNO, bottom::TNO) | ||
| size(top) == size(bottom) || | ||
| throw(ArgumentError("The two TNOs must have the same unit-cell dimensions.")) | ||
|
|
||
| _check_tno_bond_structure(top) | ||
| _check_tno_bond_structure(bottom) | ||
|
|
||
| for i in axes(top, 1), j in axes(top, 2) | ||
| T_top = top[i, j] | ||
| T_bottom = bottom[i, j] | ||
|
|
||
| space(T_top, 2) == space(T_bottom, 1)' || | ||
| throw(ArgumentError("Physical output/input mismatch at site ($i, $j).")) | ||
| end | ||
|
|
||
| return nothing | ||
| end | ||
|
|
||
| function QR_two_pepo_left(O1::TNOTensor, O2::TNOTensor, ind::Int) | ||
| pb = (1, ind) | ||
| p, q1 = ind_pair(O1, pb) | ||
| _, Rb = left_orth(permute(O1, (q1, p))) | ||
|
|
||
| pt = (2, ind) | ||
| p, q2 = ind_pair(O2, pt) | ||
| _, Rt = left_orth(permute(O2, (q2, p))) | ||
|
|
||
| @tensor M[-1 -2; -3 -4] := Rt[-3; 1 -1] * Rb[-4; 1 -2] | ||
| _, R = left_orth(permute(M, ((3, 4), (1, 2)))) | ||
| return R | ||
| end | ||
|
|
||
| function QR_two_pepo_right(O1::TNOTensor, O2::TNOTensor, ind::Int) | ||
| pb = (1, ind) | ||
| p, q1 = ind_pair(O1, pb) | ||
| Rb, _ = right_orth(permute(O1, (p, q1))) | ||
|
|
||
| pt = (2, ind) | ||
| p, q2 = ind_pair(O2, pt) | ||
| Rt, _ = right_orth(permute(O2, (p, q2))) | ||
|
|
||
| @tensor M[-1 -2; -3 -4] := Rt[1 -1; -3] * Rb[1 -2; -4] | ||
| R, _ = right_orth(permute(M, ((1, 2), (3, 4)))) | ||
| return R | ||
| end | ||
|
|
||
| function QR_two_pepo(O1::TNOTensor, O2::TNOTensor, ind::Int; side = :left) | ||
| if side == :left | ||
| return QR_two_pepo_left(O1, O2, ind) | ||
| elseif side == :right | ||
| return QR_two_pepo_right(O1, O2, ind) | ||
| else | ||
| throw(ArgumentError("side should be :left or :right")) | ||
| end | ||
| end | ||
|
|
||
| function R1R2( | ||
| A1::TNOTensor, A2::TNOTensor, A3::TNOTensor, A4::TNOTensor, | ||
| ind1::Int, ind2::Int; check_space = true | ||
| ) | ||
| RA1 = QR_two_pepo_left(A1, A2, ind1) | ||
| RA2 = QR_two_pepo_right(A3, A4, ind2) | ||
| if check_space && domain(RA1) != codomain(RA2) | ||
| throw(ArgumentError("space mismatch")) | ||
| end | ||
| return RA1, RA2 | ||
| end | ||
|
|
||
| function find_P1P2( | ||
| A1::TNOTensor, A2::TNOTensor, A3::TNOTensor, A4::TNOTensor, | ||
| p1::Int, p2::Int, trunc::TruncationStrategy; check_space = true | ||
| ) | ||
| R1, R2 = R1R2(A1, A2, A3, A4, p1, p2; check_space = check_space) | ||
| return oblique_projector(R1, R2, trunc) | ||
| end | ||
|
|
||
| function _bond_projectors(top::TNO, bottom::TNO, trunc::TruncationStrategy) | ||
| nrows, ncols = size(top) | ||
| north_proj = Matrix{Any}(undef, nrows, ncols) | ||
| east_proj = Matrix{Any}(undef, nrows, ncols) | ||
| south_proj = Matrix{Any}(undef, nrows, ncols) | ||
| west_proj = Matrix{Any}(undef, nrows, ncols) | ||
|
|
||
| for i in 1:nrows, j in 1:ncols | ||
| inorth = _up_index(i, nrows) | ||
| jeast = _right_index(j, ncols) | ||
|
|
||
| Pnorth, Psouth = find_P1P2( | ||
| top[i, j], bottom[i, j], top[inorth, j], bottom[inorth, j], 3, 5, trunc | ||
| ) | ||
| Peast, Pwest = find_P1P2( | ||
| top[i, j], bottom[i, j], top[i, jeast], bottom[i, jeast], 4, 6, trunc | ||
| ) | ||
|
|
||
| north_proj[i, j] = Pnorth | ||
| south_proj[inorth, j] = Psouth | ||
| east_proj[i, j] = Peast | ||
| west_proj[i, jeast] = Pwest | ||
| end | ||
|
|
||
| return north_proj, east_proj, south_proj, west_proj | ||
| end | ||
|
|
||
| function _compose_local_tno(top::TNOTensor, bottom::TNOTensor, Pnorth, Peast, Psouth, Pwest) | ||
|
|
||
| @tensor merged[-1 -2; -3 -4 -5 -6] := | ||
| top[1 -2; 7 8 9 10] * | ||
| bottom[-1 1; 3 4 5 6] * | ||
| Pwest[-6; 6 10] * | ||
| Pnorth[3 7; -3] * | ||
| Peast[4 8; -4] * | ||
| Psouth[-5; 5 9] | ||
|
|
||
| return merged | ||
| end | ||
|
|
||
| """ | ||
| apply!(top::TNO, bottom::TNO, trunc::TruncationStrategy) | ||
|
|
||
| Compose two TNO layers sitewise. The physical input leg of `top` is contracted with the | ||
| physical output leg of `bottom`, after which each pair of corresponding virtual bonds is | ||
| merged into a single fused bond. | ||
|
|
||
| The result is returned as a new `TNO` with the same unit-cell shape. | ||
| """ | ||
| function apply!(top::TNO, bottom::TNO, trunc::TruncationStrategy) | ||
| _check_tno_compatibility(top, bottom) | ||
| north_proj, east_proj, south_proj, west_proj = _bond_projectors(top, bottom, trunc) | ||
| merged = [ | ||
| _compose_local_tno( | ||
| top[i, j], bottom[i, j], | ||
| north_proj[i, j], east_proj[i, j], south_proj[i, j], west_proj[i, j] | ||
| ) for | ||
| i in axes(top, 1), j in axes(top, 2) | ||
| ] | ||
| return TNO(merged) | ||
| end | ||
|
|
||
| function apply!(top::ThermalTNR, bottom::ThermalTNR, trunc::TruncationStrategy) | ||
| top.T = apply!(top.T, bottom.T, trunc) | ||
| return top | ||
| end | ||
|
|
||
| function step!(scheme::ThermalTNR, layer::TNO, trunc::TruncationStrategy) | ||
| scheme.T = apply!(scheme.T, layer, trunc) | ||
| return scheme | ||
| end | ||
|
|
||
| function step!(scheme::ThermalTNR, layer::ThermalTNR, trunc::TruncationStrategy) | ||
| return step!(scheme, layer.T, trunc) | ||
| end | ||
|
|
||
| function run!( | ||
| scheme::ThermalTNR, layer::TNO, trscheme::TruncationStrategy, | ||
| criterion::stopcrit, finalizer::Finalizer{E}; | ||
| finalize_beginning = true, verbosity = 1 | ||
| ) where {E} | ||
| data = Vector{E}() | ||
|
|
||
| LoggingExtras.withlevel(; verbosity) do | ||
| @infov 1 "Starting simulation\n $(scheme)\n" | ||
| if finalize_beginning | ||
| push!(data, finalizer.f!(scheme)) | ||
| end | ||
|
|
||
| steps = 0 | ||
| crit = true | ||
|
|
||
| t = @elapsed while crit | ||
| @infov 2 "Step $(steps + 1), data[end]: $(!isempty(data) ? data[end] : "empty")" | ||
| step!(scheme, layer, trscheme) | ||
| push!(data, finalizer.f!(scheme)) | ||
|
|
||
| steps += 1 | ||
| crit = criterion(steps, data) | ||
| end | ||
|
|
||
| @infov 1 "Simulation finished\n $(stopping_info(criterion, steps, data))\n Elapsed time: $(t)s\n Iterations: $steps" | ||
| end | ||
| return data | ||
| end | ||
|
|
||
| function run!( | ||
| scheme::ThermalTNR, layer::ThermalTNR, trscheme::TruncationStrategy, | ||
| criterion::stopcrit, finalizer::Finalizer{E}; kwargs... | ||
| ) where {E} | ||
| return run!(scheme, layer.T, trscheme, criterion, finalizer; kwargs...) | ||
| end | ||
|
|
||
| function run!(scheme::ThermalTNR, layer, trscheme, criterion; kwargs...) | ||
| return run!(scheme, layer, trscheme, criterion, default_Finalizer; kwargs...) | ||
| end | ||
|
|
||
| function Base.show(io::IO, scheme::ThermalTNR) | ||
| println(io, "ThermalTNR - Thermal Tensor Network Renormalization") | ||
| println(io, " * T: $(summary(scheme.T))") | ||
| println(io, " * unit cell: $(size(scheme.T))") | ||
| return nothing | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rethink exports. Does the user need
apply!,TNO,TNOTensor?