-
Notifications
You must be signed in to change notification settings - Fork 31
Add Neighborhood Tensor Update (NTU) #144
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
base: main
Are you sure you want to change the base?
Changes from all commits
c101c79
2fdd026
1a13c39
bfb826a
0c74c01
f6554f3
2540e48
24145b1
f9d029a
71e6e31
c51b54b
e8f07eb
a4de5ff
c14fa16
3a915c4
6bfb34f
26344d2
8ed7d13
3498fea
ea0a968
3cc7769
5a90194
3d1c3f9
99e3e48
b6aeff3
bbc3bc4
de5a5d5
2d90e04
931a575
14c2fde
f8aaff0
9079316
511a654
eb06fc0
c60ab31
dbb4a6b
d0bcf0e
5234126
6034a67
8e4d44a
fa109bc
e16c935
fba41a2
1fdc81c
1655e48
03d2c8f
e1e0a0a
676f8d7
e89a35b
6b54e1c
a0f819a
9976630
03a160f
897ed8d
8d21293
01ae874
18d2041
81f5f18
44ac6d8
e80948b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,239 @@ | ||
| #= | ||
| The construction of bond environment for Neighborhood Tensor Update (NTU) | ||
| is adapted from YASTN (https://github.com/yastn/yastn). | ||
| Copyright 2024 The YASTN Authors. All Rights Reserved. | ||
| Licensed under the Apache License, Version 2.0 | ||
| =# | ||
|
|
||
| """ | ||
| Algorithms to construct bond environment for Neighborhood Tensor Update (NTU). | ||
| """ | ||
| abstract type NeighbourEnv end | ||
|
|
||
| """ | ||
| SVD which truncion only keeping the leading singular value in the trivial sector. | ||
| """ | ||
| function _svd_cut!(t::AbstractTensorMap) | ||
| A, B = left_orth!(t; trunc = truncspace(oneunit(spacetype(t)))) | ||
| return removeunit(A, numind(A)), removeunit(B, 1) | ||
| end | ||
|
|
||
| """ | ||
| Algorithm struct for "NTU-NN" bond environment. | ||
| """ | ||
| struct NNEnv <: NeighbourEnv end | ||
| """ | ||
| Calculate the bond environment within "NTU-NN" approximation. | ||
| ``` | ||
| -1 ●=======● | ||
| ║ ║ | ||
| 0 ●===X== ==Y===● | ||
| ║ ║ | ||
| 1 ●=======● | ||
| -1 0 1 2 | ||
| ``` | ||
| """ | ||
| function bondenv_ntu( | ||
| row::Int, col::Int, X, Y, state::InfiniteState, alg::NNEnv | ||
| ) | ||
| neighbors = [(-1, 0), (0, -1), (1, 0), (1, 1), (0, 2), (-1, 1)] | ||
| m = collect_neighbors(state, row, col, neighbors) | ||
| X, Y = _prepare_site_tensor(X), _prepare_site_tensor(Y) | ||
| # southwest half | ||
|
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. Do you need these to be normalized separately? In principle, by putting the entire |
||
| @autoopt @tensor benv_sw[Dse1 Dse0 Dw1 Dw0 Dnw1 Dnw0] := | ||
| cor_se(m[1, 1])[Dse1 Dse0 Ds1 Ds0] * | ||
| cor_sw(m[1, 0])[Dsw1 Dsw0 Ds1 Ds0] * | ||
| edge_w(X, hair_w(m[0, -1]))[Dnw1 Dnw0 Dw1 Dw0 Dsw1 Dsw0] | ||
| normalize!(benv_sw, Inf) | ||
| # northeast half | ||
| @autoopt @tensor benv_ne[Dnw1 Dnw0 De1 De0 Dse1 Dse0] := | ||
| cor_nw(m[-1, 0])[Dn1 Dn0 Dnw1 Dnw0] * | ||
| cor_ne(m[-1, 1])[Dne1 Dne0 Dn1 Dn0] * | ||
| edge_e(Y, hair_e(m[0, 2]))[Dne1 Dne0 Dse1 Dse0 De1 De0] | ||
| normalize!(benv_ne, Inf) | ||
| @tensor benv[Dw1 De1; Dw0 De0] := | ||
| benv_sw[Dse1 Dse0 Dw1 Dw0 Dnw1 Dnw0] * benv_ne[Dnw1 Dnw0 De1 De0 Dse1 Dse0] | ||
| normalize!(benv, Inf) | ||
| return benv | ||
| end | ||
|
|
||
| """ | ||
| Algorithm struct for "NTU-NN+" bond environment. | ||
| """ | ||
| struct NNpEnv <: NeighbourEnv end | ||
| """ | ||
| Calculate the bond environment within "NTU-NN+" approximation. | ||
| ``` | ||
| -2 ●.......● | ||
| ║ ║ | ||
| -1 ○===●=======●===○ | ||
| ║ ║ ║ ║ | ||
| 0 ●===●===X== ==Y===●===● | ||
| ║ ║ ║ ║ | ||
| 1 ○===●=======●===○ | ||
| ║ ║ | ||
| 2 ●.......● | ||
| -2 -1 0 1 2 3 | ||
| ``` | ||
| Dotted lines and ○ are splitted using SVD with `truncrank(1)`. | ||
| """ | ||
| function bondenv_ntu( | ||
| row::Int, col::Int, X, Y, state::InfiniteState, alg::NNpEnv | ||
| ) | ||
| neighbors = [ | ||
| (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1), (1, 2), (0, 2), (-1, 2), | ||
| (-1, 1), (-1, 0), (0, -2), (2, 0), (2, 1), (0, 3), (-2, 1), (-2, 0), | ||
| ] | ||
| ms = collect_neighbors(state, row, col, neighbors) | ||
| X, Y = _prepare_site_tensor(X), _prepare_site_tensor(Y) | ||
|
|
||
| # ---- hairs (size D^2) with a 1D auxiliary leg ---- | ||
|
|
||
| @tensor top[-1 -2; -3 -4] := cor_nw(ms[-2, 0])[1 2 -1 -2] * cor_ne(ms[-2, 1])[-3 -4 1 2] | ||
| tl, tr = _svd_cut!(top) | ||
|
|
||
| @tensor bot[-1 -2; -3 -4] := cor_sw(ms[2, 0])[-1 -2 1 2] * cor_se(ms[2, 1])[-3 -4 1 2] | ||
| bl, br = _svd_cut!(bot) | ||
|
|
||
| nw = permute(cor_nw(ms[-1, -1]), ((3, 4), (1, 2))) | ||
| nw1, nw2 = _svd_cut!(nw) | ||
|
|
||
| ne = permute(cor_ne(ms[-1, 2]), ((3, 4), (1, 2))) | ||
| ne1, ne2 = _svd_cut!(ne) | ||
|
|
||
| sw = permute(cor_sw(ms[1, -1]), ((1, 2), (3, 4))) | ||
| sw1, sw2 = _svd_cut!(sw) | ||
|
|
||
| se = permute(cor_se(ms[1, 2]), ((3, 4), (1, 2))) | ||
| se1, se2 = _svd_cut!(se) | ||
|
|
||
| m = ms[0, -1] | ||
| @tensoropt hW[DXw1 DXw0] := | ||
| hair_w(ms[0, -2])[Dw21 Dw20] * | ||
| nw1[Dnw11 Dnw10] * sw1[Dsw11 Dsw10] * | ||
| twistdual(m, 1)[p Dnw10 DXw0 Dsw10 Dw20] * | ||
| conj(m[p Dnw11 DXw1 Dsw11 Dw21]) | ||
|
|
||
| m = ms[0, 2] | ||
| @tensoropt hE[DYe1 DYe0] := | ||
| hair_e(ms[0, 3])[De21 De20] * | ||
| ne2[Dne21 Dne20] * se2[Dse21 Dse20] * | ||
| twistdual(m, 1)[p Dne20 De20 Dse20 DYe0] * | ||
| conj(m[p Dne21 De21 Dse21 DYe1]) | ||
|
|
||
| # ---- corners (size D^4) with a 1D auxiliary leg ---- | ||
|
|
||
| m = ms[-1, 0] | ||
| @tensoropt NW[Dn1 Dn0 DXn1 DXn0] := | ||
| tl[Dtl1 Dtl0] * nw2[Dnw21 Dnw20] * | ||
| twistdual(m, 1)[p Dtl0 Dn0 DXn0 Dnw20] * | ||
| conj(m[p Dtl1 Dn1 DXn1 Dnw21]) | ||
|
|
||
| m = ms[-1, 1] | ||
| @tensoropt NE[Dn1 Dn0 DYn1 DYn0] := | ||
| tr[Dtr1 Dtr0] * ne1[Dne11 Dne10] * | ||
| twistdual(m, 1)[p Dtr0 Dne10 DYn0 Dn0] * | ||
| conj(m[p Dtr1 Dne11 DYn1 Dn1]) | ||
|
|
||
| m = ms[1, 0] | ||
| @tensoropt SW[DXs1 DXs0 Ds1 Ds0] := | ||
| bl[Dbl1 Dbl0] * sw2[Dsw21 Dsw20] * | ||
| twistdual(m, 1)[p DXs0 Ds0 Dbl0 Dsw20] * | ||
| conj(m[p DXs1 Ds1 Dbl1 Dsw21]) | ||
|
|
||
| m = ms[1, 1] | ||
| @tensoropt SE[DYs1 DYs0 Ds1 Ds0] := | ||
| br[Dbr1 Dbr0] * se1[Dse11 Dse10] * | ||
| twistdual(m, 1)[p DYs0 Dse10 Dbr0 Ds0] * | ||
| conj(m[p DYs1 Dse11 Dbr1 Ds1]) | ||
|
|
||
| # ---- left half ---- | ||
| @tensoropt benvL[Dn1 Dn0 Dw1 Dw0 Ds1 Ds0] := | ||
| hW[DXw1 DXw0] * | ||
| NW[Dn1 Dn0 DXn1 DXn0] * | ||
| SW[DXs1 DXs0 Ds1 Ds0] * | ||
| twistdual(X, 1)[p DXn0 Dw0 DXs0 DXw0] * | ||
| conj(X[p DXn1 Dw1 DXs1 DXw1]) | ||
| normalize!(benvL, Inf) | ||
|
|
||
| # ---- right half ---- | ||
|
|
||
| @tensoropt benvR[Dn1 Dn0 De1 De0 Ds1 Ds0] := | ||
| hE[DYe1 DYe0] * | ||
| NE[Dn1 Dn0 DYn1 DYn0] * | ||
| SE[DYs1 DYs0 Ds1 Ds0] * | ||
| twistdual(Y, 1)[p DYn0 DYe0 DYs0 De0] * | ||
| conj(Y[p DYn1 DYe1 DYs1 De1]) | ||
| normalize!(benvR, Inf) | ||
|
|
||
| # ---- the full NN+ environment ---- | ||
|
|
||
| @tensor benv[Dw1, De1; Dw0, De0] := | ||
| benvL[Dn1 Dn0 Dw1 Dw0 Ds1 Ds0] * | ||
| benvR[Dn1 Dn0 De1 De0 Ds1 Ds0] | ||
| normalize!(benv, Inf) | ||
| return benv | ||
| end | ||
|
|
||
| """ | ||
| Algorithm struct for "NTU-NNN" bond environment. | ||
| """ | ||
| struct NNNEnv <: NeighbourEnv end | ||
| """ | ||
| Calculates the bond environment within "NTU-NNN" approximation. | ||
| ``` | ||
| -1 ●===●=======●===● | ||
| ║ ║ ║ ║ | ||
| 0 ●===X== ==Y===● | ||
| ║ ║ ║ ║ | ||
| 1 ●===●=======●===● | ||
| -1 0 1 2 | ||
| ``` | ||
| """ | ||
| function bondenv_ntu( | ||
| row::Int, col::Int, X, Y, state::InfiniteState, alg::NNNEnv | ||
| ) | ||
| neighbors = [ | ||
| (-1, -1), (0, -1), (1, -1), | ||
| (1, 0), (1, 1), (1, 2), (0, 2), | ||
| (-1, 2), (-1, 1), (-1, 0), | ||
| ] | ||
| m = collect_neighbors(state, row, col, neighbors) | ||
| X, Y = _prepare_site_tensor(X), _prepare_site_tensor(Y) | ||
| #= left half | ||
| -1 ●======●=== -1/-2 | ||
| ║ ║ | ||
| 0 ●======X=== -3/-4 | ||
| ║ ║ | ||
| ....D1.....D2... | ||
| ║ ║ | ||
| 1 ●==D3==●=== -5/-6 | ||
| -1 0 | ||
| =# | ||
| vecl = enlarge_corner_nw(cor_nw(m[-1, -1]), edge_n(m[-1, 0]), edge_w(m[0, -1]), X) | ||
| @tensor vecl[:] := | ||
| cor_sw(m[1, -1])[D11 D10 D31 D30] * | ||
| edge_s(m[1, 0])[D21 D20 -5 -6 D31 D30] * | ||
| vecl[D11 D10 D21 D20 -1 -2 -3 -4] | ||
| normalize!(vecl, Inf) | ||
| #= right half | ||
| -1 -1/-2===●==D1==● | ||
| ║ ║ | ||
| ........D2.....D3... | ||
| ║ ║ | ||
| 0 -3/-4===Y======● | ||
| ║ ║ | ||
| 1 -5/-6===●======● | ||
| 1 2 | ||
| =# | ||
| vecr = enlarge_corner_se(cor_se(m[1, 2]), edge_s(m[1, 1]), edge_e(m[0, 2]), Y) | ||
| @tensor vecr[:] := | ||
| edge_n(m[-1, 1])[D11 D10 D21 D20 -1 -2] * | ||
| cor_ne(m[-1, 2])[D31 D30 D11 D10] * | ||
| vecr[D21 D20 D31 D30 -3 -4 -5 -6] | ||
| normalize!(vecr, Inf) | ||
| # combine left and right part | ||
| @tensor benv[-1 -2; -3 -4] := vecl[1 2 -1 -3 3 4] * vecr[1 2 -2 -4 3 4] | ||
|
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. Same comment here about a single |
||
| normalize!(benv, Inf) | ||
| return benv | ||
| end | ||
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.
Out of curiosity: do you need the weight to be distributed equally? Otherwise this might be replaced with
left_orth!(t; trunc = truncrank(1))orright_orth!(t; trunc = truncrank(1)), which I think removes some intermediate allocations.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.
On a separate note, do we need this to be trivially charged for everything to work? It might reduce quite a bit of the number of legs if we can do something like:
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.
Nice observation! Actually no, since this D = 1 leg is in the end contracted, so how we distribute
sis irrelevant.It seems that
_svd_cutis always applied to a positive map, which then (if my feeling is right) ensures that the leading singular value has trivial charge. I'll double-check this.In YASTN they don't need to worry about it, since they only support Abelian symmetries and allow a tensor to have nonzero total charge.