6. 2D Algorithms¶
As with 1D tensor networks (TNs), 2D TNs in quimb
are a combination of
‘mixin’ subclasses of TensorNetwork
each
with some extra details about how the tensors are labelled and indices named.
Having this extra information about the 2D structure then allows special
methods for e.g. boundary contraction.
Here’s a quick reference of some key objects:
And key algorithms:
6.1. Structure of a 2D Tensor Network¶
%config InlineBackend.figure_formats = ['svg']
import quimb as qu
import quimb.tensor as qtn
As an example we can take a look at a randomly generated PEPS, which also inherits
methods from these mixin subclasses: TensorNetwork2DVector
and TensorNetwork2DFlat
,
since it has a) a single physical index per site and
b) a single tensor per site, respectively.
peps = qtn.PEPS.rand(Lx=5, Ly=5, bond_dim=3, seed=666)
peps
PEPS(tensors=25, indices=65, Lx=5, Ly=5, max_bond=3)
Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAA, _aea46cAAAAB, k0,0], tags={I0,0, X0, Y0}),
backend=numpy, dtype=float64, data=array([[[ 0.19758123, -0.20600803], [-0.02115149, -0.30155026], [ 0.08369179, 0.42321298]], [[-0.78599677, 0.27198615], [-0.01315806, -0.26534693], [-0.00531344, 0.33645332]], [[-0.57577375, 0.10554638], [-0.07281841, 0.45726951], [ 0.26362141, -0.08463805]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAC, _aea46cAAAAD, _aea46cAAAAB, k0,1], tags={I0,1, X0, Y1}),
backend=numpy, dtype=float64, data=array([[[[-0.0886793 , 0.38960521], [-0.07864096, -0.1405622 ], [-0.27039043, 0.40912656]], [[-0.25722849, -0.3621938 ], [-0.01145245, 0.07481682], [-0.04101569, -0.31399061]], [[-0.0585233 , 0.08844857], [-0.34306234, 0.14325768], [ 0.44382168, -0.17613362]]], [[[-0.11086622, -0.07888345], [-0.08731526, -0.1098593 ], [-0.08997919, -0.25855771]], [[-0.00974778, -0.06474578], [-0.53768285, 0.26626594], [ 0.1852418 , -0.17064799]], [[-0.23546533, 0.10044162], [-0.04641026, -0.33127844], [ 0.31312999, 0.24287011]]], [[[-0.41959896, -0.14805525], [ 0.02569746, -0.49149678], [-0.08605362, 0.07599989]], [[-0.19989431, -0.1171608 ], [-0.27427135, -0.18171656], [-0.35111996, -0.0948195 ]], [[ 0.33734665, -0.66881823], [ 0.2574683 , -0.32198307], [-0.44438948, 0.2297073 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAE, _aea46cAAAAF, _aea46cAAAAD, k0,2], tags={I0,2, X0, Y2}),
backend=numpy, dtype=float64, data=array([[[[ 0.00787712, 0.07483492], [ 0.23423454, -0.41977078], [-0.07098577, -0.08227457]], [[ 0.58049387, -0.28265144], [-0.50102255, -0.1383515 ], [ 0.46154386, 0.15899825]], [[-0.48357646, -0.32435753], [-0.24554998, -0.0063898 ], [-0.4288379 , 0.28063253]]], [[[ 0.4529943 , 0.12319876], [-0.12452825, -0.25212084], [ 0.07434282, 0.07358095]], [[-0.07124641, -0.06452709], [-0.10609616, 0.06050403], [-0.27691535, 0.18652204]], [[ 0.18944672, 0.28066808], [-0.26338667, 0.05858565], [ 0.17191266, 0.09251535]]], [[[-0.40473276, -0.77385977], [ 0.15369863, 0.34102213], [-0.3052184 , 0.00141725]], [[ 0.07717418, 0.39021751], [ 0.37797629, -0.3581846 ], [-0.00915705, -0.21592738]], [[ 0.21857823, 0.02861824], [-0.12619608, 0.21470106], [ 0.26837599, 0.3497904 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAG, _aea46cAAAAH, _aea46cAAAAF, k0,3], tags={I0,3, X0, Y3}),
backend=numpy, dtype=float64, data=array([[[[-0.35302799, -0.18588165], [ 0.06628363, 0.18146305], [-0.64362369, -0.2252469 ]], [[ 0.08364773, 0.01679925], [ 0.18941434, -0.14216882], [-0.07795615, 0.24121163]], [[ 0.36766087, 0.18291524], [ 0.48242292, 0.17032754], [-0.18111091, 0.32120585]]], [[[-0.73965826, 0.12207832], [-0.21999 , -0.35361801], [-0.36855658, -0.31388888]], [[ 0.41657027, 0.14911351], [-0.03321268, -0.036751 ], [ 0.27384496, -0.24498083]], [[ 0.35392829, 0.46963827], [-0.28648917, -0.16491934], [ 0.08454636, 0.3485048 ]]], [[[-0.2487877 , -0.81637444], [-0.11929533, 0.21710726], [-0.05459544, -0.16750029]], [[-0.12530134, -0.44630833], [ 0.22974167, -0.14514381], [ 0.32546501, -0.07342843]], [[-0.26259823, 0.26310325], [-0.1439656 , 0.08012546], [ 0.14057252, -0.31473198]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAI, _aea46cAAAAH, k0,4], tags={I0,4, X0, Y4}),
backend=numpy, dtype=float64, data=array([[[ 0.43152581, -0.23969586], [-0.16808012, 0.08247557], [ 0.33020835, -0.28069495]], [[-0.15814594, -0.3455025 ], [-0.4347297 , -0.65814361], [ 0.24335002, 0.01839728]], [[-0.18092796, 0.07677303], [-0.27159058, -0.12283561], [-0.37800116, -0.40040474]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAJ, _aea46cAAAAK, _aea46cAAAAA, k1,0], tags={I1,0, X1, Y0}),
backend=numpy, dtype=float64, data=array([[[[ 0.78977302, 0.20610627], [-0.17232708, -0.32686794], [ 0.12781562, -0.11373377]], [[ 0.09609733, 0.32360355], [-0.14147276, 0.08949845], [-0.14720314, -0.19955648]], [[-0.2027934 , -0.11879961], [-0.14779857, 0.06389199], [-0.06141446, -0.08943344]]], [[[ 0.01172702, 0.65384372], [-0.4016258 , 0.62405045], [ 0.0183161 , -0.42458339]], [[ 0.00276003, 0.25519974], [-0.29860681, -0.19277402], [ 0.36346475, 0.07670103]], [[-0.2414894 , 0.04928607], [-0.53921085, 0.55625126], [ 0.33501048, 0.14937114]]], [[[ 0.47162932, 0.17082597], [ 0.06865947, -0.28654631], [-0.46735522, -0.20633878]], [[ 0.24972016, -0.17040072], [ 0.15429501, 0.4294151 ], [-0.19904102, -0.00177625]], [[ 0.05496409, 0.03333935], [-0.25443675, 0.27334373], [ 0.05015645, 0.10742787]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAL, _aea46cAAAAM, _aea46cAAAAC, _aea46cAAAAK, k1,1], tags={I1,1, X1, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAN, _aea46cAAAAO, _aea46cAAAAE, _aea46cAAAAM, k1,2], tags={I1,2, X1, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAP, _aea46cAAAAQ, _aea46cAAAAG, _aea46cAAAAO, k1,3], tags={I1,3, X1, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAR, _aea46cAAAAI, _aea46cAAAAQ, k1,4], tags={I1,4, X1, Y4}),
backend=numpy, dtype=float64, data=array([[[[ 0.36548229, -0.26015584], [ 0.14163331, -0.06427805], [ 0.3257745 , -0.53845238]], [[ 0.49660934, 0.35980179], [ 0.35161007, -0.26212529], [ 0.17691887, -0.41049041]], [[ 0.35321357, 0.14903971], [ 0.58041384, -0.14440401], [ 0.10477843, 0.04271563]]], [[[-0.18523296, 0.08600995], [-0.00249853, 0.00309299], [-0.38302772, -0.11931442]], [[-0.01032181, 0.35569799], [-0.1177868 , 0.09307973], [-0.32977233, 0.31827419]], [[-0.01066864, 0.5333739 ], [-0.51256 , 0.03966059], [ 0.25838267, -0.18445352]]], [[[ 0.45910942, 0.03237033], [ 0.1103594 , -0.06656127], [-0.28261971, 0.47622606]], [[ 0.2713872 , 0.22772949], [-0.70921321, -0.6142656 ], [-0.22789126, -0.07517024]], [[-0.18087422, 0.29178375], [-0.17016618, -0.13840751], [-0.15878981, -0.07968 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAS, _aea46cAAAAT, _aea46cAAAAJ, k2,0], tags={I2,0, X2, Y0}),
backend=numpy, dtype=float64, data=array([[[[-0.38056033, 0.24804757], [-0.07572871, -0.13027434], [-0.30343203, 0.09497906]], [[ 0.08621316, -0.30894061], [-0.07400557, 0.2997675 ], [ 0.13113942, -0.02904785]], [[-0.47955682, 0.73818644], [-0.08958236, -0.44780715], [-0.27007575, -0.09415205]]], [[[-0.1108852 , 0.0971295 ], [-0.19637978, -0.23722133], [-0.3326612 , -0.14791084]], [[-0.1607138 , -0.3585758 ], [ 0.17374931, 0.07621275], [-0.13889808, 0.31498138]], [[-0.00429754, 0.35580526], [ 0.23141829, -0.10033515], [ 0.08118212, -0.37380152]]], [[[ 0.28702139, -0.00675585], [ 0.26061321, 0.16028784], [ 0.58456152, 0.66808804]], [[ 0.12426176, -0.21271792], [-0.57620289, 0.1145728 ], [-0.12986616, -0.36577064]], [[ 0.18087245, 0.12187611], [ 0.2093346 , -0.4805098 ], [ 0.38713581, -0.1013577 ]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAU, _aea46cAAAAV, _aea46cAAAAL, _aea46cAAAAT, k2,1], tags={I2,1, X2, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAW, _aea46cAAAAX, _aea46cAAAAN, _aea46cAAAAV, k2,2], tags={I2,2, X2, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAY, _aea46cAAAAZ, _aea46cAAAAP, _aea46cAAAAX, k2,3], tags={I2,3, X2, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAa, _aea46cAAAAR, _aea46cAAAAZ, k2,4], tags={I2,4, X2, Y4}),
backend=numpy, dtype=float64, data=array([[[[ 0.01567375, -0.09310011], [ 0.24768273, -0.11738978], [-0.251629 , -0.1782275 ]], [[-0.26829665, 0.31267077], [-0.22495458, -0.12581883], [ 0.26748041, -0.66605332]], [[-0.023022 , 0.11326969], [ 0.18469781, -0.55483234], [ 0.32973489, 0.27550022]]], [[[ 0.10759164, -0.63445143], [ 0.03337969, 0.25331677], [ 0.45157972, -0.17408386]], [[ 0.20383984, 0.45867942], [ 0.01499983, -0.2965261 ], [-0.19994835, 0.14174105]], [[ 0.19374226, -0.60597725], [ 0.49222259, 0.19789102], [ 0.20171385, 0.0422929 ]]], [[[-0.26715396, -0.16995193], [ 0.34863328, 0.45914815], [ 0.08663278, 0.61174177]], [[ 0.22506451, -0.12569846], [-0.27588113, -0.29585981], [ 0.17803576, 0.11039606]], [[-0.03518468, -0.36600593], [ 0.64683561, 0.09689121], [-0.27371473, -0.15114634]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAb, _aea46cAAAAc, _aea46cAAAAS, k3,0], tags={I3,0, X3, Y0}),
backend=numpy, dtype=float64, data=array([[[[-0.03287723, 0.22373023], [ 0.21720609, -0.12940337], [ 0.26421373, 0.12598597]], [[-0.05993477, 0.23901176], [-0.5080131 , 0.1581344 ], [-0.2468453 , -0.24597057]], [[ 0.05509204, 0.20433684], [ 0.25810118, 0.6133055 ], [ 0.12314849, 0.09794608]]], [[[ 0.26466672, 0.46330901], [-0.37261901, -0.14613522], [-0.04725875, -0.05370155]], [[-0.21671809, -0.6030256 ], [ 0.18518784, 0.51043185], [ 0.17336402, 0.17334707]], [[ 0.23415478, 0.31106511], [-0.08608762, 0.33643773], [-0.02513669, 0.29852203]]], [[[ 0.11660528, -0.63708811], [ 0.29317834, 0.55391842], [ 0.22281977, 0.02624954]], [[-0.61615086, 0.31477655], [-0.21857305, -0.23485264], [-0.07015365, 0.18019487]], [[ 0.47228582, -0.02025982], [ 0.03324436, -0.05201856], [ 0.08216902, -0.15068886]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAd, _aea46cAAAAe, _aea46cAAAAU, _aea46cAAAAc, k3,1], tags={I3,1, X3, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAf, _aea46cAAAAg, _aea46cAAAAW, _aea46cAAAAe, k3,2], tags={I3,2, X3, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAh, _aea46cAAAAi, _aea46cAAAAY, _aea46cAAAAg, k3,3], tags={I3,3, X3, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAj, _aea46cAAAAa, _aea46cAAAAi, k3,4], tags={I3,4, X3, Y4}),
backend=numpy, dtype=float64, data=array([[[[-0.02785434, -0.19377183], [ 0.13567531, -0.10062713], [-0.07749432, 0.35753385]], [[-0.25709318, -0.08090333], [ 0.10074147, 0.21459987], [-0.05594702, 0.48585484]], [[-0.02995602, -0.12112102], [ 0.14817227, 0.37143844], [ 0.09314821, 0.2501424 ]]], [[[-0.22927907, -0.16533426], [-0.19022857, -0.49516235], [ 0.03630534, -0.491662 ]], [[ 0.66526663, -0.06528429], [ 0.19440541, -0.33161728], [-0.22234613, -0.22712846]], [[-0.21079084, -0.07107046], [-0.19357984, -0.570392 ], [ 0.49999969, 0.07619666]]], [[[-0.36850847, 0.26388082], [-0.02058343, -0.5785781 ], [-0.13305771, -0.17363738]], [[-0.01600171, -0.25669566], [-0.07669599, 0.34866238], [ 0.53794805, -0.77247211]], [[ 0.46701018, -0.03136358], [-0.36865922, 0.55544779], [-0.05441975, 0.31138795]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAk, _aea46cAAAAb, k4,0], tags={I4,0, X4, Y0}),
backend=numpy, dtype=float64, data=array([[[-0.03622255, -0.64783791], [-0.35413836, -0.06839641], [-0.26610905, -0.4381159 ]], [[ 0.30796793, -0.02458458], [ 0.29830521, -0.13475392], [ 0.05871056, -0.29670865]], [[ 0.08531347, -0.27240719], [ 0.03741549, 0.46378323], [-0.29799446, -0.68974713]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAl, _aea46cAAAAd, _aea46cAAAAk, k4,1], tags={I4,1, X4, Y1}),
backend=numpy, dtype=float64, data=array([[[[ 7.32071132e-02, 1.63793612e-01], [ 1.95103932e-02, 6.34924932e-02], [-1.86589186e-01, 5.02850574e-01]], [[ 2.21822008e-02, 1.45419471e-01], [ 1.70098419e-02, -3.45904379e-01], [ 1.17070971e-01, 7.49301787e-01]], [[ 1.82502382e-01, 1.30361449e-01], [-6.40960880e-02, -6.50550425e-01], [-1.58615286e-01, -2.17396291e-01]]], [[[ 3.36823530e-01, 4.77320168e-01], [ 3.33942936e-02, -3.22675181e-01], [ 3.00501540e-01, -1.30890164e-01]], [[-4.93261133e-02, 1.80571112e-01], [-8.34259724e-02, -1.36661366e-01], [ 6.47967822e-01, 2.89957316e-01]], [[ 3.51996531e-01, -2.58543810e-01], [ 3.93574280e-01, 2.09913863e-01], [-1.49833263e-04, -3.14774589e-01]]], [[[ 1.95185567e-01, -3.00442172e-01], [ 5.46766593e-01, 2.17461520e-01], [ 5.47755703e-01, 1.47049000e-01]], [[-2.89939243e-02, -2.29325724e-01], [-2.19042143e-01, -5.19124212e-01], [-2.76151915e-01, -3.36271916e-01]], [[ 5.01194142e-01, 1.12354943e-01], [-2.74712104e-01, 1.17000234e-01], [ 1.01969558e-02, -1.37528548e-01]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAm, _aea46cAAAAf, _aea46cAAAAl, k4,2], tags={I4,2, X4, Y2}),
backend=numpy, dtype=float64, data=array([[[[-0.04691427, 0.04518512], [-0.48821014, 0.14472043], [ 0.2289111 , -0.49996531]], [[-0.22946103, -0.56242939], [-0.1519321 , -0.08036349], [-0.07974806, -0.12597931]], [[ 0.16025181, 0.3009493 ], [-0.21928384, -0.14216206], [-0.56038647, 0.15624933]]], [[[ 0.24839524, -0.28966023], [-0.20838007, -0.18817065], [ 0.17665091, -0.02378777]], [[ 0.35291229, -0.26963928], [ 0.16652744, 0.39175549], [ 0.00254081, -0.59435346]], [[ 0.36046884, -0.19522254], [-0.00934237, 0.10191553], [-0.62675368, 0.20896072]]], [[[ 0.22663422, -0.21799479], [-0.10634787, -0.2027503 ], [ 0.68532395, -0.02940163]], [[ 0.1583736 , 0.1362018 ], [-0.14871838, 0.16141379], [ 0.33185367, 0.43178459]], [[-0.06391033, 0.27971557], [-0.20968179, -0.51190256], [ 0.29081901, 0.09433118]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAn, _aea46cAAAAh, _aea46cAAAAm, k4,3], tags={I4,3, X4, Y3}),
backend=numpy, dtype=float64, data=array([[[[-0.04268813, 0.65947468], [-0.00643255, -0.57697121], [ 0.57728807, 0.70715589]], [[-0.02511551, 0.29979619], [ 0.25984809, 0.37272275], [-0.23439044, -0.13467509]], [[ 0.06414487, 0.11633378], [-0.17244477, -0.11933729], [-0.06883606, 0.03145422]]], [[[-0.40488939, 0.19470758], [ 0.12764037, -0.56489277], [-0.18223419, -0.34254078]], [[ 0.41968604, 0.19940955], [ 0.21937432, 0.17137236], [-0.09779707, -0.3709037 ]], [[ 0.09661398, -0.59484165], [ 0.16929148, 0.24812902], [ 0.23701328, 0.24395429]]], [[[-0.01667156, -0.10023877], [-0.00398862, -0.02343363], [ 0.47390102, 0.32692523]], [[ 0.70393136, 0.02803209], [-0.21699308, -0.21125616], [ 0.30153273, 0.38770508]], [[-0.16267959, -0.18765657], [ 0.00855063, -0.16643927], [-0.19250898, 0.23623521]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAj, _aea46cAAAAn, k4,4], tags={I4,4, X4, Y4}),
backend=numpy, dtype=float64, data=array([[[ 0.04200821, 0.31899505], [-0.21784933, -0.42481105], [-0.45498257, 0.35867999]], [[ 0.24995048, -0.17124387], [ 0.52845545, 0.69610531], [ 0.18589178, -0.07414434]], [[-0.25978338, -0.16469329], [ 0.01989423, -0.17488996], [-0.23159834, -0.48782655]]])peps.show()
3 3 3 3
●━━━━●━━━━●━━━━●━━━━●
╱┃3 ╱┃3 ╱┃3 ╱┃3 ╱┃3
┃ 3 ┃ 3 ┃ 3 ┃ 3 ┃
●━━━━●━━━━●━━━━●━━━━●
╱┃3 ╱┃3 ╱┃3 ╱┃3 ╱┃3
┃ 3 ┃ 3 ┃ 3 ┃ 3 ┃
●━━━━●━━━━●━━━━●━━━━●
╱┃3 ╱┃3 ╱┃3 ╱┃3 ╱┃3
┃ 3 ┃ 3 ┃ 3 ┃ 3 ┃
●━━━━●━━━━●━━━━●━━━━●
╱┃3 ╱┃3 ╱┃3 ╱┃3 ╱┃3
┃ 3 ┃ 3 ┃ 3 ┃ 3 ┃
●━━━━●━━━━●━━━━●━━━━●
╱ ╱ ╱ ╱ ╱
You can see all the special properties the PEPS
class carries with:
peps._EXTRA_PROPS
('_site_tag_id', '_x_tag_id', '_y_tag_id', '_Lx', '_Ly', '_site_ind_id')
This enable various convenient functions:
# index specifying an physical site
peps.site_ind(3, 4)
'k3,4'
# tag specifying a coordinate
peps.site_tag(3, 4)
'I3,4'
# access by coordinate rather than full tag
peps[3, 4]
Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAj, _aea46cAAAAa, _aea46cAAAAi, k3,4], tags={I3,4, X3, Y4}),
backend=numpy, dtype=float64, data=array([[[[-0.02785434, -0.19377183], [ 0.13567531, -0.10062713], [-0.07749432, 0.35753385]], [[-0.25709318, -0.08090333], [ 0.10074147, 0.21459987], [-0.05594702, 0.48585484]], [[-0.02995602, -0.12112102], [ 0.14817227, 0.37143844], [ 0.09314821, 0.2501424 ]]], [[[-0.22927907, -0.16533426], [-0.19022857, -0.49516235], [ 0.03630534, -0.491662 ]], [[ 0.66526663, -0.06528429], [ 0.19440541, -0.33161728], [-0.22234613, -0.22712846]], [[-0.21079084, -0.07107046], [-0.19357984, -0.570392 ], [ 0.49999969, 0.07619666]]], [[[-0.36850847, 0.26388082], [-0.02058343, -0.5785781 ], [-0.13305771, -0.17363738]], [[-0.01600171, -0.25669566], [-0.07669599, 0.34866238], [ 0.53794805, -0.77247211]], [[ 0.46701018, -0.03136358], [-0.36865922, 0.55544779], [-0.05441975, 0.31138795]]]])peps.draw(color=peps.site_tags)
6.2. Combining 2D Tensor Networks¶
When you combine two 2D tensor networks with the &
or |
operators the
new combined TN will be ~quimb.tensor.tensor_2d.TensorNetwork2D
if they are
compatible (i.e. all extra properties match). That means that if you combine two
PEPS for example, the new object still has a boundary contraction method.
norm = peps.H & peps
norm
TensorNetwork2D(tensors=50, indices=105, Lx=5, Ly=5, max_bond=3)
Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAA, _aea46cAAAAB, k0,0], tags={I0,0, X0, Y0}),
backend=numpy, dtype=float64, data=array([[[ 0.19758123, -0.20600803], [-0.02115149, -0.30155026], [ 0.08369179, 0.42321298]], [[-0.78599677, 0.27198615], [-0.01315806, -0.26534693], [-0.00531344, 0.33645332]], [[-0.57577375, 0.10554638], [-0.07281841, 0.45726951], [ 0.26362141, -0.08463805]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAC, _aea46cAAAAD, _aea46cAAAAB, k0,1], tags={I0,1, X0, Y1}),
backend=numpy, dtype=float64, data=array([[[[-0.0886793 , 0.38960521], [-0.07864096, -0.1405622 ], [-0.27039043, 0.40912656]], [[-0.25722849, -0.3621938 ], [-0.01145245, 0.07481682], [-0.04101569, -0.31399061]], [[-0.0585233 , 0.08844857], [-0.34306234, 0.14325768], [ 0.44382168, -0.17613362]]], [[[-0.11086622, -0.07888345], [-0.08731526, -0.1098593 ], [-0.08997919, -0.25855771]], [[-0.00974778, -0.06474578], [-0.53768285, 0.26626594], [ 0.1852418 , -0.17064799]], [[-0.23546533, 0.10044162], [-0.04641026, -0.33127844], [ 0.31312999, 0.24287011]]], [[[-0.41959896, -0.14805525], [ 0.02569746, -0.49149678], [-0.08605362, 0.07599989]], [[-0.19989431, -0.1171608 ], [-0.27427135, -0.18171656], [-0.35111996, -0.0948195 ]], [[ 0.33734665, -0.66881823], [ 0.2574683 , -0.32198307], [-0.44438948, 0.2297073 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAE, _aea46cAAAAF, _aea46cAAAAD, k0,2], tags={I0,2, X0, Y2}),
backend=numpy, dtype=float64, data=array([[[[ 0.00787712, 0.07483492], [ 0.23423454, -0.41977078], [-0.07098577, -0.08227457]], [[ 0.58049387, -0.28265144], [-0.50102255, -0.1383515 ], [ 0.46154386, 0.15899825]], [[-0.48357646, -0.32435753], [-0.24554998, -0.0063898 ], [-0.4288379 , 0.28063253]]], [[[ 0.4529943 , 0.12319876], [-0.12452825, -0.25212084], [ 0.07434282, 0.07358095]], [[-0.07124641, -0.06452709], [-0.10609616, 0.06050403], [-0.27691535, 0.18652204]], [[ 0.18944672, 0.28066808], [-0.26338667, 0.05858565], [ 0.17191266, 0.09251535]]], [[[-0.40473276, -0.77385977], [ 0.15369863, 0.34102213], [-0.3052184 , 0.00141725]], [[ 0.07717418, 0.39021751], [ 0.37797629, -0.3581846 ], [-0.00915705, -0.21592738]], [[ 0.21857823, 0.02861824], [-0.12619608, 0.21470106], [ 0.26837599, 0.3497904 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAG, _aea46cAAAAH, _aea46cAAAAF, k0,3], tags={I0,3, X0, Y3}),
backend=numpy, dtype=float64, data=array([[[[-0.35302799, -0.18588165], [ 0.06628363, 0.18146305], [-0.64362369, -0.2252469 ]], [[ 0.08364773, 0.01679925], [ 0.18941434, -0.14216882], [-0.07795615, 0.24121163]], [[ 0.36766087, 0.18291524], [ 0.48242292, 0.17032754], [-0.18111091, 0.32120585]]], [[[-0.73965826, 0.12207832], [-0.21999 , -0.35361801], [-0.36855658, -0.31388888]], [[ 0.41657027, 0.14911351], [-0.03321268, -0.036751 ], [ 0.27384496, -0.24498083]], [[ 0.35392829, 0.46963827], [-0.28648917, -0.16491934], [ 0.08454636, 0.3485048 ]]], [[[-0.2487877 , -0.81637444], [-0.11929533, 0.21710726], [-0.05459544, -0.16750029]], [[-0.12530134, -0.44630833], [ 0.22974167, -0.14514381], [ 0.32546501, -0.07342843]], [[-0.26259823, 0.26310325], [-0.1439656 , 0.08012546], [ 0.14057252, -0.31473198]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAI, _aea46cAAAAH, k0,4], tags={I0,4, X0, Y4}),
backend=numpy, dtype=float64, data=array([[[ 0.43152581, -0.23969586], [-0.16808012, 0.08247557], [ 0.33020835, -0.28069495]], [[-0.15814594, -0.3455025 ], [-0.4347297 , -0.65814361], [ 0.24335002, 0.01839728]], [[-0.18092796, 0.07677303], [-0.27159058, -0.12283561], [-0.37800116, -0.40040474]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAJ, _aea46cAAAAK, _aea46cAAAAA, k1,0], tags={I1,0, X1, Y0}),
backend=numpy, dtype=float64, data=array([[[[ 0.78977302, 0.20610627], [-0.17232708, -0.32686794], [ 0.12781562, -0.11373377]], [[ 0.09609733, 0.32360355], [-0.14147276, 0.08949845], [-0.14720314, -0.19955648]], [[-0.2027934 , -0.11879961], [-0.14779857, 0.06389199], [-0.06141446, -0.08943344]]], [[[ 0.01172702, 0.65384372], [-0.4016258 , 0.62405045], [ 0.0183161 , -0.42458339]], [[ 0.00276003, 0.25519974], [-0.29860681, -0.19277402], [ 0.36346475, 0.07670103]], [[-0.2414894 , 0.04928607], [-0.53921085, 0.55625126], [ 0.33501048, 0.14937114]]], [[[ 0.47162932, 0.17082597], [ 0.06865947, -0.28654631], [-0.46735522, -0.20633878]], [[ 0.24972016, -0.17040072], [ 0.15429501, 0.4294151 ], [-0.19904102, -0.00177625]], [[ 0.05496409, 0.03333935], [-0.25443675, 0.27334373], [ 0.05015645, 0.10742787]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAL, _aea46cAAAAM, _aea46cAAAAC, _aea46cAAAAK, k1,1], tags={I1,1, X1, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAN, _aea46cAAAAO, _aea46cAAAAE, _aea46cAAAAM, k1,2], tags={I1,2, X1, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAP, _aea46cAAAAQ, _aea46cAAAAG, _aea46cAAAAO, k1,3], tags={I1,3, X1, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAR, _aea46cAAAAI, _aea46cAAAAQ, k1,4], tags={I1,4, X1, Y4}),
backend=numpy, dtype=float64, data=array([[[[ 0.36548229, -0.26015584], [ 0.14163331, -0.06427805], [ 0.3257745 , -0.53845238]], [[ 0.49660934, 0.35980179], [ 0.35161007, -0.26212529], [ 0.17691887, -0.41049041]], [[ 0.35321357, 0.14903971], [ 0.58041384, -0.14440401], [ 0.10477843, 0.04271563]]], [[[-0.18523296, 0.08600995], [-0.00249853, 0.00309299], [-0.38302772, -0.11931442]], [[-0.01032181, 0.35569799], [-0.1177868 , 0.09307973], [-0.32977233, 0.31827419]], [[-0.01066864, 0.5333739 ], [-0.51256 , 0.03966059], [ 0.25838267, -0.18445352]]], [[[ 0.45910942, 0.03237033], [ 0.1103594 , -0.06656127], [-0.28261971, 0.47622606]], [[ 0.2713872 , 0.22772949], [-0.70921321, -0.6142656 ], [-0.22789126, -0.07517024]], [[-0.18087422, 0.29178375], [-0.17016618, -0.13840751], [-0.15878981, -0.07968 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAS, _aea46cAAAAT, _aea46cAAAAJ, k2,0], tags={I2,0, X2, Y0}),
backend=numpy, dtype=float64, data=array([[[[-0.38056033, 0.24804757], [-0.07572871, -0.13027434], [-0.30343203, 0.09497906]], [[ 0.08621316, -0.30894061], [-0.07400557, 0.2997675 ], [ 0.13113942, -0.02904785]], [[-0.47955682, 0.73818644], [-0.08958236, -0.44780715], [-0.27007575, -0.09415205]]], [[[-0.1108852 , 0.0971295 ], [-0.19637978, -0.23722133], [-0.3326612 , -0.14791084]], [[-0.1607138 , -0.3585758 ], [ 0.17374931, 0.07621275], [-0.13889808, 0.31498138]], [[-0.00429754, 0.35580526], [ 0.23141829, -0.10033515], [ 0.08118212, -0.37380152]]], [[[ 0.28702139, -0.00675585], [ 0.26061321, 0.16028784], [ 0.58456152, 0.66808804]], [[ 0.12426176, -0.21271792], [-0.57620289, 0.1145728 ], [-0.12986616, -0.36577064]], [[ 0.18087245, 0.12187611], [ 0.2093346 , -0.4805098 ], [ 0.38713581, -0.1013577 ]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAU, _aea46cAAAAV, _aea46cAAAAL, _aea46cAAAAT, k2,1], tags={I2,1, X2, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAW, _aea46cAAAAX, _aea46cAAAAN, _aea46cAAAAV, k2,2], tags={I2,2, X2, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAY, _aea46cAAAAZ, _aea46cAAAAP, _aea46cAAAAX, k2,3], tags={I2,3, X2, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAa, _aea46cAAAAR, _aea46cAAAAZ, k2,4], tags={I2,4, X2, Y4}),
backend=numpy, dtype=float64, data=array([[[[ 0.01567375, -0.09310011], [ 0.24768273, -0.11738978], [-0.251629 , -0.1782275 ]], [[-0.26829665, 0.31267077], [-0.22495458, -0.12581883], [ 0.26748041, -0.66605332]], [[-0.023022 , 0.11326969], [ 0.18469781, -0.55483234], [ 0.32973489, 0.27550022]]], [[[ 0.10759164, -0.63445143], [ 0.03337969, 0.25331677], [ 0.45157972, -0.17408386]], [[ 0.20383984, 0.45867942], [ 0.01499983, -0.2965261 ], [-0.19994835, 0.14174105]], [[ 0.19374226, -0.60597725], [ 0.49222259, 0.19789102], [ 0.20171385, 0.0422929 ]]], [[[-0.26715396, -0.16995193], [ 0.34863328, 0.45914815], [ 0.08663278, 0.61174177]], [[ 0.22506451, -0.12569846], [-0.27588113, -0.29585981], [ 0.17803576, 0.11039606]], [[-0.03518468, -0.36600593], [ 0.64683561, 0.09689121], [-0.27371473, -0.15114634]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAb, _aea46cAAAAc, _aea46cAAAAS, k3,0], tags={I3,0, X3, Y0}),
backend=numpy, dtype=float64, data=array([[[[-0.03287723, 0.22373023], [ 0.21720609, -0.12940337], [ 0.26421373, 0.12598597]], [[-0.05993477, 0.23901176], [-0.5080131 , 0.1581344 ], [-0.2468453 , -0.24597057]], [[ 0.05509204, 0.20433684], [ 0.25810118, 0.6133055 ], [ 0.12314849, 0.09794608]]], [[[ 0.26466672, 0.46330901], [-0.37261901, -0.14613522], [-0.04725875, -0.05370155]], [[-0.21671809, -0.6030256 ], [ 0.18518784, 0.51043185], [ 0.17336402, 0.17334707]], [[ 0.23415478, 0.31106511], [-0.08608762, 0.33643773], [-0.02513669, 0.29852203]]], [[[ 0.11660528, -0.63708811], [ 0.29317834, 0.55391842], [ 0.22281977, 0.02624954]], [[-0.61615086, 0.31477655], [-0.21857305, -0.23485264], [-0.07015365, 0.18019487]], [[ 0.47228582, -0.02025982], [ 0.03324436, -0.05201856], [ 0.08216902, -0.15068886]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAd, _aea46cAAAAe, _aea46cAAAAU, _aea46cAAAAc, k3,1], tags={I3,1, X3, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAf, _aea46cAAAAg, _aea46cAAAAW, _aea46cAAAAe, k3,2], tags={I3,2, X3, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAh, _aea46cAAAAi, _aea46cAAAAY, _aea46cAAAAg, k3,3], tags={I3,3, X3, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAj, _aea46cAAAAa, _aea46cAAAAi, k3,4], tags={I3,4, X3, Y4}),
backend=numpy, dtype=float64, data=array([[[[-0.02785434, -0.19377183], [ 0.13567531, -0.10062713], [-0.07749432, 0.35753385]], [[-0.25709318, -0.08090333], [ 0.10074147, 0.21459987], [-0.05594702, 0.48585484]], [[-0.02995602, -0.12112102], [ 0.14817227, 0.37143844], [ 0.09314821, 0.2501424 ]]], [[[-0.22927907, -0.16533426], [-0.19022857, -0.49516235], [ 0.03630534, -0.491662 ]], [[ 0.66526663, -0.06528429], [ 0.19440541, -0.33161728], [-0.22234613, -0.22712846]], [[-0.21079084, -0.07107046], [-0.19357984, -0.570392 ], [ 0.49999969, 0.07619666]]], [[[-0.36850847, 0.26388082], [-0.02058343, -0.5785781 ], [-0.13305771, -0.17363738]], [[-0.01600171, -0.25669566], [-0.07669599, 0.34866238], [ 0.53794805, -0.77247211]], [[ 0.46701018, -0.03136358], [-0.36865922, 0.55544779], [-0.05441975, 0.31138795]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAk, _aea46cAAAAb, k4,0], tags={I4,0, X4, Y0}),
backend=numpy, dtype=float64, data=array([[[-0.03622255, -0.64783791], [-0.35413836, -0.06839641], [-0.26610905, -0.4381159 ]], [[ 0.30796793, -0.02458458], [ 0.29830521, -0.13475392], [ 0.05871056, -0.29670865]], [[ 0.08531347, -0.27240719], [ 0.03741549, 0.46378323], [-0.29799446, -0.68974713]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAl, _aea46cAAAAd, _aea46cAAAAk, k4,1], tags={I4,1, X4, Y1}),
backend=numpy, dtype=float64, data=array([[[[ 7.32071132e-02, 1.63793612e-01], [ 1.95103932e-02, 6.34924932e-02], [-1.86589186e-01, 5.02850574e-01]], [[ 2.21822008e-02, 1.45419471e-01], [ 1.70098419e-02, -3.45904379e-01], [ 1.17070971e-01, 7.49301787e-01]], [[ 1.82502382e-01, 1.30361449e-01], [-6.40960880e-02, -6.50550425e-01], [-1.58615286e-01, -2.17396291e-01]]], [[[ 3.36823530e-01, 4.77320168e-01], [ 3.33942936e-02, -3.22675181e-01], [ 3.00501540e-01, -1.30890164e-01]], [[-4.93261133e-02, 1.80571112e-01], [-8.34259724e-02, -1.36661366e-01], [ 6.47967822e-01, 2.89957316e-01]], [[ 3.51996531e-01, -2.58543810e-01], [ 3.93574280e-01, 2.09913863e-01], [-1.49833263e-04, -3.14774589e-01]]], [[[ 1.95185567e-01, -3.00442172e-01], [ 5.46766593e-01, 2.17461520e-01], [ 5.47755703e-01, 1.47049000e-01]], [[-2.89939243e-02, -2.29325724e-01], [-2.19042143e-01, -5.19124212e-01], [-2.76151915e-01, -3.36271916e-01]], [[ 5.01194142e-01, 1.12354943e-01], [-2.74712104e-01, 1.17000234e-01], [ 1.01969558e-02, -1.37528548e-01]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAm, _aea46cAAAAf, _aea46cAAAAl, k4,2], tags={I4,2, X4, Y2}),
backend=numpy, dtype=float64, data=array([[[[-0.04691427, 0.04518512], [-0.48821014, 0.14472043], [ 0.2289111 , -0.49996531]], [[-0.22946103, -0.56242939], [-0.1519321 , -0.08036349], [-0.07974806, -0.12597931]], [[ 0.16025181, 0.3009493 ], [-0.21928384, -0.14216206], [-0.56038647, 0.15624933]]], [[[ 0.24839524, -0.28966023], [-0.20838007, -0.18817065], [ 0.17665091, -0.02378777]], [[ 0.35291229, -0.26963928], [ 0.16652744, 0.39175549], [ 0.00254081, -0.59435346]], [[ 0.36046884, -0.19522254], [-0.00934237, 0.10191553], [-0.62675368, 0.20896072]]], [[[ 0.22663422, -0.21799479], [-0.10634787, -0.2027503 ], [ 0.68532395, -0.02940163]], [[ 0.1583736 , 0.1362018 ], [-0.14871838, 0.16141379], [ 0.33185367, 0.43178459]], [[-0.06391033, 0.27971557], [-0.20968179, -0.51190256], [ 0.29081901, 0.09433118]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAn, _aea46cAAAAh, _aea46cAAAAm, k4,3], tags={I4,3, X4, Y3}),
backend=numpy, dtype=float64, data=array([[[[-0.04268813, 0.65947468], [-0.00643255, -0.57697121], [ 0.57728807, 0.70715589]], [[-0.02511551, 0.29979619], [ 0.25984809, 0.37272275], [-0.23439044, -0.13467509]], [[ 0.06414487, 0.11633378], [-0.17244477, -0.11933729], [-0.06883606, 0.03145422]]], [[[-0.40488939, 0.19470758], [ 0.12764037, -0.56489277], [-0.18223419, -0.34254078]], [[ 0.41968604, 0.19940955], [ 0.21937432, 0.17137236], [-0.09779707, -0.3709037 ]], [[ 0.09661398, -0.59484165], [ 0.16929148, 0.24812902], [ 0.23701328, 0.24395429]]], [[[-0.01667156, -0.10023877], [-0.00398862, -0.02343363], [ 0.47390102, 0.32692523]], [[ 0.70393136, 0.02803209], [-0.21699308, -0.21125616], [ 0.30153273, 0.38770508]], [[-0.16267959, -0.18765657], [ 0.00855063, -0.16643927], [-0.19250898, 0.23623521]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAj, _aea46cAAAAn, k4,4], tags={I4,4, X4, Y4}),
backend=numpy, dtype=float64, data=array([[[ 0.04200821, 0.31899505], [-0.21784933, -0.42481105], [-0.45498257, 0.35867999]], [[ 0.24995048, -0.17124387], [ 0.52845545, 0.69610531], [ 0.18589178, -0.07414434]], [[-0.25978338, -0.16469329], [ 0.01989423, -0.17488996], [-0.23159834, -0.48782655]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAs, _aea46cAAAAo, k0,0], tags={I0,0, X0, Y0}),
backend=numpy, dtype=float64, data=array([[[ 0.19758123, -0.20600803], [-0.02115149, -0.30155026], [ 0.08369179, 0.42321298]], [[-0.78599677, 0.27198615], [-0.01315806, -0.26534693], [-0.00531344, 0.33645332]], [[-0.57577375, 0.10554638], [-0.07281841, 0.45726951], [ 0.26362141, -0.08463805]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAt, _aea46cAAAAp, _aea46cAAAAo, k0,1], tags={I0,1, X0, Y1}),
backend=numpy, dtype=float64, data=array([[[[-0.0886793 , 0.38960521], [-0.07864096, -0.1405622 ], [-0.27039043, 0.40912656]], [[-0.25722849, -0.3621938 ], [-0.01145245, 0.07481682], [-0.04101569, -0.31399061]], [[-0.0585233 , 0.08844857], [-0.34306234, 0.14325768], [ 0.44382168, -0.17613362]]], [[[-0.11086622, -0.07888345], [-0.08731526, -0.1098593 ], [-0.08997919, -0.25855771]], [[-0.00974778, -0.06474578], [-0.53768285, 0.26626594], [ 0.1852418 , -0.17064799]], [[-0.23546533, 0.10044162], [-0.04641026, -0.33127844], [ 0.31312999, 0.24287011]]], [[[-0.41959896, -0.14805525], [ 0.02569746, -0.49149678], [-0.08605362, 0.07599989]], [[-0.19989431, -0.1171608 ], [-0.27427135, -0.18171656], [-0.35111996, -0.0948195 ]], [[ 0.33734665, -0.66881823], [ 0.2574683 , -0.32198307], [-0.44438948, 0.2297073 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAv, _aea46cAAAAq, _aea46cAAAAp, k0,2], tags={I0,2, X0, Y2}),
backend=numpy, dtype=float64, data=array([[[[ 0.00787712, 0.07483492], [ 0.23423454, -0.41977078], [-0.07098577, -0.08227457]], [[ 0.58049387, -0.28265144], [-0.50102255, -0.1383515 ], [ 0.46154386, 0.15899825]], [[-0.48357646, -0.32435753], [-0.24554998, -0.0063898 ], [-0.4288379 , 0.28063253]]], [[[ 0.4529943 , 0.12319876], [-0.12452825, -0.25212084], [ 0.07434282, 0.07358095]], [[-0.07124641, -0.06452709], [-0.10609616, 0.06050403], [-0.27691535, 0.18652204]], [[ 0.18944672, 0.28066808], [-0.26338667, 0.05858565], [ 0.17191266, 0.09251535]]], [[[-0.40473276, -0.77385977], [ 0.15369863, 0.34102213], [-0.3052184 , 0.00141725]], [[ 0.07717418, 0.39021751], [ 0.37797629, -0.3581846 ], [-0.00915705, -0.21592738]], [[ 0.21857823, 0.02861824], [-0.12619608, 0.21470106], [ 0.26837599, 0.3497904 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAx, _aea46cAAAAr, _aea46cAAAAq, k0,3], tags={I0,3, X0, Y3}),
backend=numpy, dtype=float64, data=array([[[[-0.35302799, -0.18588165], [ 0.06628363, 0.18146305], [-0.64362369, -0.2252469 ]], [[ 0.08364773, 0.01679925], [ 0.18941434, -0.14216882], [-0.07795615, 0.24121163]], [[ 0.36766087, 0.18291524], [ 0.48242292, 0.17032754], [-0.18111091, 0.32120585]]], [[[-0.73965826, 0.12207832], [-0.21999 , -0.35361801], [-0.36855658, -0.31388888]], [[ 0.41657027, 0.14911351], [-0.03321268, -0.036751 ], [ 0.27384496, -0.24498083]], [[ 0.35392829, 0.46963827], [-0.28648917, -0.16491934], [ 0.08454636, 0.3485048 ]]], [[[-0.2487877 , -0.81637444], [-0.11929533, 0.21710726], [-0.05459544, -0.16750029]], [[-0.12530134, -0.44630833], [ 0.22974167, -0.14514381], [ 0.32546501, -0.07342843]], [[-0.26259823, 0.26310325], [-0.1439656 , 0.08012546], [ 0.14057252, -0.31473198]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAAAz, _aea46cAAAAr, k0,4], tags={I0,4, X0, Y4}),
backend=numpy, dtype=float64, data=array([[[ 0.43152581, -0.23969586], [-0.16808012, 0.08247557], [ 0.33020835, -0.28069495]], [[-0.15814594, -0.3455025 ], [-0.4347297 , -0.65814361], [ 0.24335002, 0.01839728]], [[-0.18092796, 0.07677303], [-0.27159058, -0.12283561], [-0.37800116, -0.40040474]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABB, _aea46cAAAAu, _aea46cAAAAs, k1,0], tags={I1,0, X1, Y0}),
backend=numpy, dtype=float64, data=array([[[[ 0.78977302, 0.20610627], [-0.17232708, -0.32686794], [ 0.12781562, -0.11373377]], [[ 0.09609733, 0.32360355], [-0.14147276, 0.08949845], [-0.14720314, -0.19955648]], [[-0.2027934 , -0.11879961], [-0.14779857, 0.06389199], [-0.06141446, -0.08943344]]], [[[ 0.01172702, 0.65384372], [-0.4016258 , 0.62405045], [ 0.0183161 , -0.42458339]], [[ 0.00276003, 0.25519974], [-0.29860681, -0.19277402], [ 0.36346475, 0.07670103]], [[-0.2414894 , 0.04928607], [-0.53921085, 0.55625126], [ 0.33501048, 0.14937114]]], [[[ 0.47162932, 0.17082597], [ 0.06865947, -0.28654631], [-0.46735522, -0.20633878]], [[ 0.24972016, -0.17040072], [ 0.15429501, 0.4294151 ], [-0.19904102, -0.00177625]], [[ 0.05496409, 0.03333935], [-0.25443675, 0.27334373], [ 0.05015645, 0.10742787]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABC, _aea46cAAAAw, _aea46cAAAAt, _aea46cAAAAu, k1,1], tags={I1,1, X1, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABE, _aea46cAAAAy, _aea46cAAAAv, _aea46cAAAAw, k1,2], tags={I1,2, X1, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABG, _aea46cAAABA, _aea46cAAAAx, _aea46cAAAAy, k1,3], tags={I1,3, X1, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABI, _aea46cAAAAz, _aea46cAAABA, k1,4], tags={I1,4, X1, Y4}),
backend=numpy, dtype=float64, data=array([[[[ 0.36548229, -0.26015584], [ 0.14163331, -0.06427805], [ 0.3257745 , -0.53845238]], [[ 0.49660934, 0.35980179], [ 0.35161007, -0.26212529], [ 0.17691887, -0.41049041]], [[ 0.35321357, 0.14903971], [ 0.58041384, -0.14440401], [ 0.10477843, 0.04271563]]], [[[-0.18523296, 0.08600995], [-0.00249853, 0.00309299], [-0.38302772, -0.11931442]], [[-0.01032181, 0.35569799], [-0.1177868 , 0.09307973], [-0.32977233, 0.31827419]], [[-0.01066864, 0.5333739 ], [-0.51256 , 0.03966059], [ 0.25838267, -0.18445352]]], [[[ 0.45910942, 0.03237033], [ 0.1103594 , -0.06656127], [-0.28261971, 0.47622606]], [[ 0.2713872 , 0.22772949], [-0.70921321, -0.6142656 ], [-0.22789126, -0.07517024]], [[-0.18087422, 0.29178375], [-0.17016618, -0.13840751], [-0.15878981, -0.07968 ]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABK, _aea46cAAABD, _aea46cAAABB, k2,0], tags={I2,0, X2, Y0}),
backend=numpy, dtype=float64, data=array([[[[-0.38056033, 0.24804757], [-0.07572871, -0.13027434], [-0.30343203, 0.09497906]], [[ 0.08621316, -0.30894061], [-0.07400557, 0.2997675 ], [ 0.13113942, -0.02904785]], [[-0.47955682, 0.73818644], [-0.08958236, -0.44780715], [-0.27007575, -0.09415205]]], [[[-0.1108852 , 0.0971295 ], [-0.19637978, -0.23722133], [-0.3326612 , -0.14791084]], [[-0.1607138 , -0.3585758 ], [ 0.17374931, 0.07621275], [-0.13889808, 0.31498138]], [[-0.00429754, 0.35580526], [ 0.23141829, -0.10033515], [ 0.08118212, -0.37380152]]], [[[ 0.28702139, -0.00675585], [ 0.26061321, 0.16028784], [ 0.58456152, 0.66808804]], [[ 0.12426176, -0.21271792], [-0.57620289, 0.1145728 ], [-0.12986616, -0.36577064]], [[ 0.18087245, 0.12187611], [ 0.2093346 , -0.4805098 ], [ 0.38713581, -0.1013577 ]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABL, _aea46cAAABF, _aea46cAAABC, _aea46cAAABD, k2,1], tags={I2,1, X2, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABN, _aea46cAAABH, _aea46cAAABE, _aea46cAAABF, k2,2], tags={I2,2, X2, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABP, _aea46cAAABJ, _aea46cAAABG, _aea46cAAABH, k2,3], tags={I2,3, X2, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABR, _aea46cAAABI, _aea46cAAABJ, k2,4], tags={I2,4, X2, Y4}),
backend=numpy, dtype=float64, data=array([[[[ 0.01567375, -0.09310011], [ 0.24768273, -0.11738978], [-0.251629 , -0.1782275 ]], [[-0.26829665, 0.31267077], [-0.22495458, -0.12581883], [ 0.26748041, -0.66605332]], [[-0.023022 , 0.11326969], [ 0.18469781, -0.55483234], [ 0.32973489, 0.27550022]]], [[[ 0.10759164, -0.63445143], [ 0.03337969, 0.25331677], [ 0.45157972, -0.17408386]], [[ 0.20383984, 0.45867942], [ 0.01499983, -0.2965261 ], [-0.19994835, 0.14174105]], [[ 0.19374226, -0.60597725], [ 0.49222259, 0.19789102], [ 0.20171385, 0.0422929 ]]], [[[-0.26715396, -0.16995193], [ 0.34863328, 0.45914815], [ 0.08663278, 0.61174177]], [[ 0.22506451, -0.12569846], [-0.27588113, -0.29585981], [ 0.17803576, 0.11039606]], [[-0.03518468, -0.36600593], [ 0.64683561, 0.09689121], [-0.27371473, -0.15114634]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABT, _aea46cAAABM, _aea46cAAABK, k3,0], tags={I3,0, X3, Y0}),
backend=numpy, dtype=float64, data=array([[[[-0.03287723, 0.22373023], [ 0.21720609, -0.12940337], [ 0.26421373, 0.12598597]], [[-0.05993477, 0.23901176], [-0.5080131 , 0.1581344 ], [-0.2468453 , -0.24597057]], [[ 0.05509204, 0.20433684], [ 0.25810118, 0.6133055 ], [ 0.12314849, 0.09794608]]], [[[ 0.26466672, 0.46330901], [-0.37261901, -0.14613522], [-0.04725875, -0.05370155]], [[-0.21671809, -0.6030256 ], [ 0.18518784, 0.51043185], [ 0.17336402, 0.17334707]], [[ 0.23415478, 0.31106511], [-0.08608762, 0.33643773], [-0.02513669, 0.29852203]]], [[[ 0.11660528, -0.63708811], [ 0.29317834, 0.55391842], [ 0.22281977, 0.02624954]], [[-0.61615086, 0.31477655], [-0.21857305, -0.23485264], [-0.07015365, 0.18019487]], [[ 0.47228582, -0.02025982], [ 0.03324436, -0.05201856], [ 0.08216902, -0.15068886]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABU, _aea46cAAABO, _aea46cAAABL, _aea46cAAABM, k3,1], tags={I3,1, X3, Y1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABW, _aea46cAAABQ, _aea46cAAABN, _aea46cAAABO, k3,2], tags={I3,2, X3, Y2}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAABY, _aea46cAAABS, _aea46cAAABP, _aea46cAAABQ, k3,3], tags={I3,3, X3, Y3}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABa, _aea46cAAABR, _aea46cAAABS, k3,4], tags={I3,4, X3, Y4}),
backend=numpy, dtype=float64, data=array([[[[-0.02785434, -0.19377183], [ 0.13567531, -0.10062713], [-0.07749432, 0.35753385]], [[-0.25709318, -0.08090333], [ 0.10074147, 0.21459987], [-0.05594702, 0.48585484]], [[-0.02995602, -0.12112102], [ 0.14817227, 0.37143844], [ 0.09314821, 0.2501424 ]]], [[[-0.22927907, -0.16533426], [-0.19022857, -0.49516235], [ 0.03630534, -0.491662 ]], [[ 0.66526663, -0.06528429], [ 0.19440541, -0.33161728], [-0.22234613, -0.22712846]], [[-0.21079084, -0.07107046], [-0.19357984, -0.570392 ], [ 0.49999969, 0.07619666]]], [[[-0.36850847, 0.26388082], [-0.02058343, -0.5785781 ], [-0.13305771, -0.17363738]], [[-0.01600171, -0.25669566], [-0.07669599, 0.34866238], [ 0.53794805, -0.77247211]], [[ 0.46701018, -0.03136358], [-0.36865922, 0.55544779], [-0.05441975, 0.31138795]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAABV, _aea46cAAABT, k4,0], tags={I4,0, X4, Y0}),
backend=numpy, dtype=float64, data=array([[[-0.03622255, -0.64783791], [-0.35413836, -0.06839641], [-0.26610905, -0.4381159 ]], [[ 0.30796793, -0.02458458], [ 0.29830521, -0.13475392], [ 0.05871056, -0.29670865]], [[ 0.08531347, -0.27240719], [ 0.03741549, 0.46378323], [-0.29799446, -0.68974713]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABX, _aea46cAAABU, _aea46cAAABV, k4,1], tags={I4,1, X4, Y1}),
backend=numpy, dtype=float64, data=array([[[[ 7.32071132e-02, 1.63793612e-01], [ 1.95103932e-02, 6.34924932e-02], [-1.86589186e-01, 5.02850574e-01]], [[ 2.21822008e-02, 1.45419471e-01], [ 1.70098419e-02, -3.45904379e-01], [ 1.17070971e-01, 7.49301787e-01]], [[ 1.82502382e-01, 1.30361449e-01], [-6.40960880e-02, -6.50550425e-01], [-1.58615286e-01, -2.17396291e-01]]], [[[ 3.36823530e-01, 4.77320168e-01], [ 3.33942936e-02, -3.22675181e-01], [ 3.00501540e-01, -1.30890164e-01]], [[-4.93261133e-02, 1.80571112e-01], [-8.34259724e-02, -1.36661366e-01], [ 6.47967822e-01, 2.89957316e-01]], [[ 3.51996531e-01, -2.58543810e-01], [ 3.93574280e-01, 2.09913863e-01], [-1.49833263e-04, -3.14774589e-01]]], [[[ 1.95185567e-01, -3.00442172e-01], [ 5.46766593e-01, 2.17461520e-01], [ 5.47755703e-01, 1.47049000e-01]], [[-2.89939243e-02, -2.29325724e-01], [-2.19042143e-01, -5.19124212e-01], [-2.76151915e-01, -3.36271916e-01]], [[ 5.01194142e-01, 1.12354943e-01], [-2.74712104e-01, 1.17000234e-01], [ 1.01969558e-02, -1.37528548e-01]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABZ, _aea46cAAABW, _aea46cAAABX, k4,2], tags={I4,2, X4, Y2}),
backend=numpy, dtype=float64, data=array([[[[-0.04691427, 0.04518512], [-0.48821014, 0.14472043], [ 0.2289111 , -0.49996531]], [[-0.22946103, -0.56242939], [-0.1519321 , -0.08036349], [-0.07974806, -0.12597931]], [[ 0.16025181, 0.3009493 ], [-0.21928384, -0.14216206], [-0.56038647, 0.15624933]]], [[[ 0.24839524, -0.28966023], [-0.20838007, -0.18817065], [ 0.17665091, -0.02378777]], [[ 0.35291229, -0.26963928], [ 0.16652744, 0.39175549], [ 0.00254081, -0.59435346]], [[ 0.36046884, -0.19522254], [-0.00934237, 0.10191553], [-0.62675368, 0.20896072]]], [[[ 0.22663422, -0.21799479], [-0.10634787, -0.2027503 ], [ 0.68532395, -0.02940163]], [[ 0.1583736 , 0.1362018 ], [-0.14871838, 0.16141379], [ 0.33185367, 0.43178459]], [[-0.06391033, 0.27971557], [-0.20968179, -0.51190256], [ 0.29081901, 0.09433118]]]])Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAABb, _aea46cAAABY, _aea46cAAABZ, k4,3], tags={I4,3, X4, Y3}),
backend=numpy, dtype=float64, data=array([[[[-0.04268813, 0.65947468], [-0.00643255, -0.57697121], [ 0.57728807, 0.70715589]], [[-0.02511551, 0.29979619], [ 0.25984809, 0.37272275], [-0.23439044, -0.13467509]], [[ 0.06414487, 0.11633378], [-0.17244477, -0.11933729], [-0.06883606, 0.03145422]]], [[[-0.40488939, 0.19470758], [ 0.12764037, -0.56489277], [-0.18223419, -0.34254078]], [[ 0.41968604, 0.19940955], [ 0.21937432, 0.17137236], [-0.09779707, -0.3709037 ]], [[ 0.09661398, -0.59484165], [ 0.16929148, 0.24812902], [ 0.23701328, 0.24395429]]], [[[-0.01667156, -0.10023877], [-0.00398862, -0.02343363], [ 0.47390102, 0.32692523]], [[ 0.70393136, 0.02803209], [-0.21699308, -0.21125616], [ 0.30153273, 0.38770508]], [[-0.16267959, -0.18765657], [ 0.00855063, -0.16643927], [-0.19250898, 0.23623521]]]])Tensor(shape=(3, 3, 2), inds=[_aea46cAAABa, _aea46cAAABb, k4,4], tags={I4,4, X4, Y4}),
backend=numpy, dtype=float64, data=array([[[ 0.04200821, 0.31899505], [-0.21784933, -0.42481105], [-0.45498257, 0.35867999]], [[ 0.24995048, -0.17124387], [ 0.52845545, 0.69610531], [ 0.18589178, -0.07414434]], [[-0.25978338, -0.16469329], [ 0.01989423, -0.17488996], [-0.23159834, -0.48782655]]])norm.draw(color=norm.site_tags, figsize=(4, 4))
6.3. Contracting 2D Tensor Networks¶
Note that unlike 1D tensor networks, 2D tensor networks cannot be efficiently
contracted exactly, and so care should taken when calling .contract
directly. Our PEPS here is still small enough however for our memory:
norm.contract(all, optimize='auto-hq')
0.5077521135992215
The contract
function then treats it as any other tensor network.
More generally, one would want to use boundary contraction to approximately contract any 2D tensor networks, using one of the following methods:
contract_boundary_from_bottom()
,contract_boundary_from_left()
,contract_boundary_from_top()
,contract_boundary_from_right()
,
Here, one compresses between tensors as we contract to limit bonds from growing beyond a maximum size:
%%time
norm.contract_boundary(max_bond=32)
CPU times: user 1.62 s, sys: 34.8 ms, total: 1.65 s
Wall time: 234 ms
0.506999178700516
We can see here than the answer is slightly off, even with a large bond
dimension of 64
(random PEPS are harder than ‘physical’ PEPS to
contract usually).
Warning
The default options for
contract_boundary()
are those
of tensor_split()
, meaning
max_bond=None
(no dimension limit) and cutoff=1e-10
(only remove
very small singular values). These won’t be nearly aggressive enough to
contract most 2D TNs efficiently - you should set these!
By default contract_boundary
also flattens the TN as it goes.
If you want to do a multilayer boundary contraction you need to tag
the different layers and specify them:
peps.add_tag('KET')
pepsH = peps.conj().retag({'KET': 'BRA'})
norm = pepsH & peps
norm.draw(color=['KET', 'BRA'], figsize=(3, 3))
Now we can specify layer_tags=['KET', 'BRA']
to any of the boundary
contraction methods. Here we perform an inplace boundary contraction around
the sites (2, 2)
and (2, 3)
.
norm.contract_boundary_(max_bond=64, layer_tags=['KET', 'BRA'], around=((2, 2), (2, 3)))
TensorNetwork2D(tensors=15, indices=29, Lx=5, Ly=5, max_bond=64)
Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAW, _aea46cAAAAX, _aea46cAAAAN, _aea46cAAAAV, k2,2], tags={I2,2, X2, Y2, BRA}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAAAY, _aea46cAAAAZ, _aea46cAAAAP, _aea46cAAAAX, k2,3], tags={I2,3, X2, Y3, BRA}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAAAa, _aea46cAAAAR, _aea46cAAAAZ, k2,4], tags={I2,4, X2, Y4, BRA}),
backend=numpy, dtype=float64, data=array([[[[ 0.01567375, -0.09310011], [ 0.24768273, -0.11738978], [-0.251629 , -0.1782275 ]], [[-0.26829665, 0.31267077], [-0.22495458, -0.12581883], [ 0.26748041, -0.66605332]], [[-0.023022 , 0.11326969], [ 0.18469781, -0.55483234], [ 0.32973489, 0.27550022]]], [[[ 0.10759164, -0.63445143], [ 0.03337969, 0.25331677], [ 0.45157972, -0.17408386]], [[ 0.20383984, 0.45867942], [ 0.01499983, -0.2965261 ], [-0.19994835, 0.14174105]], [[ 0.19374226, -0.60597725], [ 0.49222259, 0.19789102], [ 0.20171385, 0.0422929 ]]], [[[-0.26715396, -0.16995193], [ 0.34863328, 0.45914815], [ 0.08663278, 0.61174177]], [[ 0.22506451, -0.12569846], [-0.27588113, -0.29585981], [ 0.17803576, 0.11039606]], [[-0.03518468, -0.36600593], [ 0.64683561, 0.09689121], [-0.27371473, -0.15114634]]]])Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAACl, _aea46cAAACf, _aea46cAAACc, _aea46cAAACd, k2,2], tags={I2,2, X2, Y2, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 3, 2), inds=[_aea46cAAACn, _aea46cAAACh, _aea46cAAACe, _aea46cAAACf, k2,3], tags={I2,3, X2, Y3, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 3, 3, 2), inds=[_aea46cAAACp, _aea46cAAACg, _aea46cAAACh, k2,4], tags={I2,4, X2, Y4, KET}),
backend=numpy, dtype=float64, data=array([[[[ 0.01567375, -0.09310011], [ 0.24768273, -0.11738978], [-0.251629 , -0.1782275 ]], [[-0.26829665, 0.31267077], [-0.22495458, -0.12581883], [ 0.26748041, -0.66605332]], [[-0.023022 , 0.11326969], [ 0.18469781, -0.55483234], [ 0.32973489, 0.27550022]]], [[[ 0.10759164, -0.63445143], [ 0.03337969, 0.25331677], [ 0.45157972, -0.17408386]], [[ 0.20383984, 0.45867942], [ 0.01499983, -0.2965261 ], [-0.19994835, 0.14174105]], [[ 0.19374226, -0.60597725], [ 0.49222259, 0.19789102], [ 0.20171385, 0.0422929 ]]], [[[-0.26715396, -0.16995193], [ 0.34863328, 0.45914815], [ 0.08663278, 0.61174177]], [[ 0.22506451, -0.12569846], [-0.27588113, -0.29585981], [ 0.17803576, 0.11039606]], [[-0.03518468, -0.36600593], [ 0.64683561, 0.09689121], [-0.27371473, -0.15114634]]]])Tensor(shape=(3, 64, 64, 3), inds=[_aea46cAAAAN, _aea46cAAAAO, _aea46cAAAAM, _aea46cAAACc], tags={I1,2, X1, Y2, BRA, I0,2, X0, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 9, 64, 3), inds=[_aea46cAAAAP, _aea46cAAAAQ, _aea46cAAAAO, _aea46cAAACe], tags={I1,3, X1, Y3, BRA, I0,3, X0, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 9, 3), inds=[_aea46cAAAAR, _aea46cAAAAQ, _aea46cAAACg], tags={I1,4, X1, Y4, BRA, I0,4, X0, KET}),
backend=numpy, dtype=float64, data=array([[[ 3.56981949e-01, -1.00848316e-01, -2.99876514e-02], [-7.47813095e-02, 5.10592372e-02, 9.14969049e-02], [ 5.78916294e-02, 6.67496076e-02, 2.51375552e-02], [ 1.95345094e-02, -2.59605747e-02, 4.49697344e-02], [-2.49502542e-16, 2.33798059e-03, -1.79005072e-02], [-9.95379525e-17, 6.49172701e-03, -6.21682059e-02], [ 1.72158407e-02, 2.49273391e-02, -1.80900169e-02], [ 3.13082868e-02, -6.19052797e-03, 1.26882184e-02], [ 9.54505940e-18, -2.92696256e-02, -3.10374293e-03]], [[-1.00848316e-01, 2.18405978e-01, 7.80502424e-02], [ 5.10592372e-02, -3.02687053e-02, 3.19057027e-02], [ 6.67496076e-02, 5.33148577e-02, -3.61814356e-02], [-2.59605747e-02, 2.70028274e-02, 4.04028883e-02], [-2.33798059e-03, 1.77209692e-16, 7.02352038e-02], [-6.49172701e-03, -2.46153143e-16, -1.60606062e-02], [ 2.49273391e-02, -2.13476966e-02, 3.43397018e-02], [-6.19052797e-03, -4.52032230e-02, -1.07501528e-02], [ 2.92696256e-02, -2.88552932e-17, 1.83287627e-04]], [[-2.99876514e-02, 7.80502424e-02, 4.03700019e-01], [ 9.14969049e-02, 3.19057027e-02, 1.09269202e-01], [ 2.51375552e-02, -3.61814356e-02, -2.89616215e-02], [ 4.49697344e-02, 4.04028883e-02, -5.37950028e-02], [ 1.79005072e-02, -7.02352038e-02, 4.56094424e-16], [ 6.21682059e-02, 1.60606062e-02, 2.28696561e-17], [-1.80900169e-02, 3.43397018e-02, -7.18582529e-03], [ 1.26882184e-02, -1.07501528e-02, -2.80812365e-04], [ 3.10374293e-03, -1.83287627e-04, 2.38880536e-18]]])Tensor(shape=(64, 3, 64, 3), inds=[_aea46cAAAAg, _aea46cAAAAW, _aea46cAAAAe, _aea46cAAACl], tags={I3,2, X3, Y2, BRA, I4,2, X4, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(9, 3, 64, 3), inds=[_aea46cAAAAi, _aea46cAAAAY, _aea46cAAAAg, _aea46cAAACn], tags={I3,3, X3, Y3, BRA, I4,3, X4, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(3, 9, 3), inds=[_aea46cAAAAa, _aea46cAAAAi, _aea46cAAACp], tags={I3,4, X3, Y4, BRA, I4,4, X4, KET}),
backend=numpy, dtype=float64, data=array([[[ 5.68399455e-01, 2.42506402e-01, 3.33555033e-01], [ 1.25079009e-01, 3.22513869e-02, -6.98697546e-02], [ 1.36470626e-01, 2.04575948e-01, 7.27566005e-02], [-2.52472701e-15, 7.86496048e-02, 2.75969908e-01], [-1.37359123e-01, -6.42711321e-02, -1.05580199e-01], [-1.97268264e-16, 5.12335106e-02, 1.36836294e-02], [ 7.72843563e-02, 6.63680258e-02, -1.45256898e-01], [ 1.46159349e-01, -8.93871796e-02, -6.26766907e-03], [-3.92703429e-15, -1.29140581e-01, 4.03399323e-02]], [[ 2.42506402e-01, 1.00877466e+00, 3.27177597e-01], [ 3.22513869e-02, 3.95720591e-01, -3.10805564e-01], [ 2.04575948e-01, 4.24565134e-02, 1.44756191e-01], [-7.86496048e-02, 4.75938793e-17, 3.54393752e-02], [-6.42711321e-02, 1.77794095e-01, 1.21196914e-01], [-5.12335106e-02, -3.61675374e-16, -2.20256855e-01], [ 6.63680258e-02, -5.24617194e-02, 5.14089461e-03], [-8.93871796e-02, -8.18299437e-03, 2.68972269e-02], [ 1.29140581e-01, 2.83517873e-16, -2.75329848e-02]], [[ 3.33555033e-01, 3.27177597e-01, 1.27000956e+00], [-6.98697546e-02, -3.10805564e-01, -1.85779727e-01], [ 7.27566005e-02, 1.44756191e-01, -2.85729711e-01], [-2.75969908e-01, -3.54393752e-02, 3.63606034e-15], [-1.05580199e-01, 1.21196914e-01, -6.21878949e-02], [-1.36836294e-02, 2.20256855e-01, 6.31910812e-17], [-1.45256898e-01, 5.14089461e-03, 5.53875299e-02], [-6.26766907e-03, 2.68972269e-02, -3.53440529e-02], [-4.03399323e-02, 2.75329848e-02, 8.59657667e-16]]])Tensor(shape=(64, 64), inds=[_aea46cAAAAL, _aea46cAAAAM], tags={I1,0, X1, Y0, BRA, I0,0, X0, KET, I1,1, Y1, I0,1}),
backend=numpy, dtype=float64, data=...Tensor(shape=(64, 3, 64, 3), inds=[_aea46cAAAAS, _aea46cAAAAV, _aea46cAAAAL, _aea46cAAACd], tags={I2,1, X2, Y1, BRA, I2,0, Y0, KET}),
backend=numpy, dtype=float64, data=...Tensor(shape=(64, 64), inds=[_aea46cAAAAS, _aea46cAAAAe], tags={I3,0, X3, Y0, BRA, I4,0, X4, KET, I3,1, Y1, I4,1}),
backend=numpy, dtype=float64, data=...norm.draw(color=[norm.site_tag(2, 2), norm.site_tag(2, 3)], show_tags=False)
Note the tensors on the right haven’t been flattened as they on the boundary already.
6.4. Computing Quantites¶
Contracting the boundary of two sandwiched PEPS around regions (which
can be thought of as the approximate partial trace) is also the main routine
required inside
compute_local_expectation()
.
# two spin operator
H2 = qu.ham_heis(2)
# coordinates to act with operator on
coo_a = (2, 2)
coo_b = (2, 3)
# compute expectation
peps.compute_local_expectation(
{(coo_a, coo_b): H2},
max_bond=64,
normalized=True,
)
0.0004870786802363588
Note
We have specified the boundary contraction option max_bond
, and also
the normalized=True
option, which computes
which reuses the environments to ‘locally’ normalize the state rather than doing it in a separate step. By default, two layer boundary contraction is also used since this is more efficient (but this can be turned off).
Often we want to compute many of these at once, e.g. when computing the energy of a Hamiltonian, without repeating many boundary boundary contractions:
# compute the heisenberg interaction for every bond in the PEPS lattice
terms = {
(coo_a, coo_b): H2
for coo_a, coo_b in peps.gen_bond_coos()
}
peps.compute_local_expectation(
terms,
max_bond=64,
normalized=True,
)
0.26752530504966576
This automatically calculates which ‘plaquette’ environments are required then
computes them in at most one boundary contraction inwards from each direction.
There are various options for manually controlling this, with the main driver
function being
compute_plaquette_environments()
.
6.5. Specifying 2D Hamiltonians¶
Such a dictionary of terms can also be generated by instantiating a
LocalHam2D
, which additionally
sums two site and one site terms so there is at most one term per pair
can generate commuting term groupings for arbitrary range interactions
can plot the Hamiltonian for interactive usage with
graph()
This is the object that is required for both the
SimpleUpdate
and
FullUpdate
algorithms.
Here we’ll first make the translationally invariant Heisenberg Hamiltonian:
Lx = 4
Ly = 4
ham = qtn.LocalHam2D(Lx, Ly, H2=H2)
ham.draw()
(<Figure size 400x400 with 1 Axes>, <Axes: >)
The H2
kwarg describes two site interactions. If an operator is given directly (as here)
it is used as a default term for all nearest neighbor interactions, as can be seen in the
visualization above.
We can also mix default single and two body terms and those for specific sites:
# the default two body term
H2 = {None: qu.ham_heis(2)}
# single site terms
H1 = {}
for i in range(Lx):
for j in range(Ly):
# add next nearest neighbor interactions
if (i + 1 < Lx) and (j - 1 >= 0):
H2[(i, j), (i + 1, j - 1)] = 0.5 * qu.ham_heis(2)
if (i + 1 < Lx) and (j + 1 < Ly):
H2[(i, j), (i + 1, j + 1)] = 0.5 * qu.ham_heis(2)
# add a random field
H1[i, j] = qu.randn() * qu.spin_operator('Z')
ham_nn_r = qtn.LocalHam2D(Lx, Ly, H2=H2, H1=H1)
ham_nn_r.draw()
(<Figure size 400x400 with 1 Axes>, <Axes: >)
The coloring shows a potential grouping of commuting two site terms.
This object has the .terms
attribute which can be supplied to
compute_local_expectation()
peps.compute_local_expectation(ham_nn_r.terms, max_bond=32)
0.1123889724020653
In the next few sections we’ll try and find the groundstate of the 4x4 Heisenberg lattice:
Lx = 4
Ly = 4
ham = qtn.LocalHam2D(Lx, Ly, H2=qu.ham_heis(2))
This is small enough to easily compute the exact groundstate energy:
energy_exact = qu.groundenergy(qu.ham_heis_2D(Lx, Ly, sparse=True)) / (Lx * Ly)
energy_exact
-0.5743254415745597
6.6. Simple Update¶
We can use our LocalHam2D
object as the
input to the ‘Simple Update’ (SU) algorithm, for performing imaginary time evolution.
Here we’ll find the $D=4$ SU groundstate of the Heisenberg Hamiltonian:
D = 4
psi0 = qtn.PEPS.rand(Lx, Ly, bond_dim=D, seed=666)
su = qtn.SimpleUpdate(
psi0,
ham,
chi=32, # boundary contraction bond dim for computing energy
compute_energy_every=10,
compute_energy_per_site=True,
keep_best=True,
)
for tau in [0.3, 0.1, 0.03, 0.01]:
su.evolve(100, tau=tau)
n=100, tau=0.3000, energy~-0.560196: 100%|##########| 100/100 [00:11<00:00, 8.39it/s]
n=200, tau=0.1000, energy~-0.562994: 100%|##########| 100/100 [00:09<00:00, 11.08it/s]
n=300, tau=0.0300, energy~-0.562883: 100%|##########| 100/100 [00:06<00:00, 15.06it/s]
n=400, tau=0.0100, energy~-0.562843: 100%|##########| 100/100 [00:07<00:00, 13.68it/s]
The current state can be retrieved from su.state
, or, if you have specified the
keep_best
option, the lowest energy state seen can be found in su.best['state']
.
su.best
{'energy': -0.5633772517149431,
'state': <PEPS(tensors=16, indices=40, Lx=4, Ly=4, max_bond=4)>,
'it': 110}
from matplotlib import pyplot as plt
with plt.style.context(qu.NEUTRAL_STYLE):
plt.plot(su.its, su.energies)
plt.axhline(energy_exact, color='black')
plt.title('Simple Update Convergence')
plt.ylabel('Energy')
plt.xlabel('Iteration');
6.7. Full Update¶
Simple Update assumes a particular environment when truncating after each local application of the imaginary time evolution operators - a product of diagonal operators - while very cheap this can be innacurate. Full Update instead fits the new PEPS after each local evolution using the local tensors as well as a boundary contracted environment.
# use the best SU state as the starting point for FU
psi0 = su.best['state'].copy()
The way these algorithms are written using autoray means that we can convert the backend arrays of our PEPS and Hamiltonian to e.g. GPU arrays and everything should still run smoothly.
In the following (optional) cell, we convert to the arrays to single
precision cupy
arrays, since FU is a good candidate for GPU acceleration.
def to_backend(x):
import cupy as cp
return cp.asarray(x).astype('float32')
psi0.apply_to_arrays(to_backend)
ham.apply_to_arrays(to_backend)
fu = qtn.FullUpdate(
psi0=psi0,
ham=ham,
# chi again is the boundary contraction max_bond
# now used for the envs as well as any energy calc
chi=32,
# we thus can cheaply compute the energy at every step
compute_energy_every=1,
compute_energy_per_site=True,
keep_best=True,
)
fu.evolve(50, tau=0.1)
n=50, tau=0.1000, energy~-0.571752: 100%|##########| 50/50 [01:10<00:00, 1.42s/it]
fu.evolve(50, tau=0.03)
n=100, tau=0.0300, energy~-0.573182: 100%|##########| 50/50 [00:57<00:00, 1.14s/it]
fu.evolve(50, tau=0.01)
n=150, tau=0.0100, energy~-0.573563: 100%|##########| 50/50 [00:55<00:00, 1.11s/it]
We can see we have improved on the SU groundstate significantly.
with plt.style.context(qu.NEUTRAL_STYLE):
plt.plot(fu.its, fu.energies, color='green')
plt.axhline(energy_exact, color='black')
plt.title('Full Update Convergence')
plt.ylabel('Energy')
plt.xlabel('Iteration');
Full Update has many options relating to the fitting of the imaginary time evolution gates, controlling tradeoff between efficiency and accuracy, you can view them like so:
fu.fit_opts
{'tol': 1e-10,
'steps': 20,
'init_simple_guess': True,
'condition_tensors': True,
'condition_maintain_norms': True,
'als_dense': True,
'als_solver': 'solve',
'als_enforce_pos': False,
'als_enforce_pos_smudge': 1e-06,
'autodiff_backend': 'autograd',
'autodiff_optimizer': 'L-BFGS-B'}
For example, the following might be helpful to converge to very high accuracy:
fu.fit_opts['als_enforce_pos'] = True
6.8. Global Autodiff Optmization¶
Because of the aforementioned array agnoticism that quimb
tries to adopt, we can
also perform nearly all 2D calculations using arrays/tensors from an autodiff library,
to compute gradients and thus efficiently optimize entire tensor networks at once.
The TNOptimizer
object handles injecting autodiff
arrays from one of several libraries currently):
then using the automatically generated gradients from any expression to feed to scipy’s optimize function. Optimizing for a 2D PEPS energy is a great example of this. All we need to do is setup a function (a ‘loss’) that returns a real scalar to minimize.
Lx = Ly = 4
psi0 = qtn.PEPS.rand(Lx, Ly, bond_dim=4)
ham = qtn.LocalHam2D(Lx, Ly, H2=qu.ham_heis(2))
def loss(psi, terms):
# the following functions simply scale the various tensors
# for the sake of numerical stability
psi.balance_bonds_()
psi.equalize_norms_(1.0)
# then we just compute the energy of all the terms
return psi.compute_local_expectation(
terms,
max_bond=32,
cutoff=0.0,
normalized=True
) / (Lx * Ly)
(Setting cutoff=0.0
is required here so that the autodiff doesn’t encounter
bahavior/shapes dependent on actual array values.)
Next we create a TNOptimizer
object:
tnopt = qtn.TNOptimizer(
# initial TN to optimize
psi0,
# the function to minimize
loss_fn=loss,
# constant TNs, tensors, arrays
loss_constants={'terms': ham.terms},
# the library that computes the gradient
autodiff_backend='jax',
# the scipy optimizer that makes use of the gradient
optimizer='L-BFGS-B',
)
The first step might be slow (e.g. with 'jax'
) as it compiles the whole
energy and gradient computation:
tnopt.optimize(1)
-0.103467911482 [best: -0.103467911482] : : 2it [00:48, 24.42s/it]
<PEPS(tensors=16, indices=40, Lx=4, Ly=4, max_bond=4)>
Subsequent optimization steps should be very quick, especially on a GPU:
psi_opt = tnopt.optimize(999)
-0.574177205563 [best: -0.574177205563] : 20%|█▉ | 198/999 [00:32<02:12, 6.06it/s]
We can then check the convergence:
with plt.style.context(qu.NEUTRAL_STYLE):
plt.plot(tnopt.losses, color='purple')
plt.axhline(energy_exact, color='black')
plt.title('Global Autodiff Optimize Convergence')
plt.ylabel('Energy')
plt.ylim(-0.575, -0.563)
plt.xlabel('Iteration');
We can see that we have rapidly achieved a lower energy than Full Update.
Warning
Global autodiff optimization can be too powerful for TN computations that involve approximate contraction in the sense that the optimization starts to exploit the small errors in the approximation to yield wildly low but innacurate energies. That is part of the reason for including the conditioning steps:
psi.balance_bonds_()
psi.equalize_norms_(1.0)
in our loss function as well as ‘locally normalizing’ the energies. It is also thus worth checking with a large bond dimension what our final energy is more accurately. We can see below it matches well here.
psi_opt.compute_local_expectation(
ham.terms, normalized=True, max_bond=100
) / (Lx * Ly)
-0.5741719873138484