Skip to content

Commit a57d4f6

Browse files
committed
Merge remote-tracking branch 'upstream/master' into bondenv-ntu
2 parents b98028a + 0cda404 commit a57d4f6

File tree

6 files changed

+334
-15
lines changed

6 files changed

+334
-15
lines changed

src/algorithms/time_evolution/simpleupdate.jl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,6 @@ function su_iter(
7878
"iPEPS unit cell size for simple update should be no smaller than (2, 2)."
7979
),
8080
)
81-
# TODO: make algorithm independent on the choice of dual in the network
82-
for (r, c) in Iterators.product(1:Nr, 1:Nc)
83-
@assert [isdual(space(peps.vertices[r, c], ax)) for ax in 1:5] == [0, 1, 1, 0, 0]
84-
@assert [isdual(space(peps.weights[1, r, c], ax)) for ax in 1:2] == [0, 1]
85-
@assert [isdual(space(peps.weights[2, r, c], ax)) for ax in 1:2] == [0, 1]
86-
end
8781
peps2 = deepcopy(peps)
8882
gate_mirrored = mirror_antidiag(gate)
8983
for direction in 1:2

src/networks/tensors.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ function PEPSTensor(
8686
return f(T, ℂ^Pspace ^Nspace ^Espace (ℂ^Sspace)' (ℂ^Wspace)')
8787
end
8888

89+
mirror_antidiag(t::PEPSTensor) = permute(t, ((1,), (3, 2, 5, 4)))
8990
Base.rotl90(t::PEPSTensor) = permute(t, ((1,), (3, 4, 5, 2)))
9091
Base.rotr90(t::PEPSTensor) = permute(t, ((1,), (5, 2, 3, 4)))
9192
Base.rot180(t::PEPSTensor) = permute(t, ((1,), (4, 5, 2, 3)))

src/states/infiniteweightpeps.jl

Lines changed: 236 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ const PEPSWeight{T,S} = AbstractTensorMap{T,S,1,1}
1010
"""
1111
struct SUWeight{E<:PEPSWeight}
1212
13-
Schmidt bond weights used in simple/cluster update. Weight elements are always real.
13+
Schmidt bond weights used in simple/cluster update.
14+
Weight elements are always real and non-negative.
15+
The domain and codomain of each weight matrix
16+
must be an un-dualed `ElementarySapce`.
1417
1518
## Fields
1619
@@ -22,11 +25,21 @@ $(TYPEDFIELDS)
2225
"""
2326
struct SUWeight{E<:PEPSWeight}
2427
data::Array{E,3}
28+
SUWeight{E}(data::Array{E,3}) where {E} = new{E}(data)
29+
end
2530

26-
function SUWeight(data::Array{E,3}) where {E<:PEPSWeight}
27-
@assert eltype(data[1]) <: Real
28-
return new{E}(data)
31+
function SUWeight(data::Array{E,3}) where {E<:PEPSWeight}
32+
scalartype(data) <: Real || error("Weight elements must be real numbers.")
33+
for wt in data
34+
isa(wt, DiagonalTensorMap) ||
35+
error("Each weight matrix should be a DiagonalTensorMap")
36+
domain(wt, 1) == codomain(wt, 1) ||
37+
error("Domain and codomain of each weight matrix must be the same.")
38+
!isdual(codomain(wt, 1)) ||
39+
error("Domain and codomain of each weight matrix cannot be a dual space.")
40+
all(wt.data .>= 0) || error("Weight elements must be non-negative.")
2941
end
42+
return SUWeight{E}(data)
3043
end
3144

3245
function SUWeight(wts_mats::AbstractMatrix{E}...) where {E<:PEPSWeight}
@@ -50,6 +63,18 @@ VectorInterface.scalartype(::Type{T}) where {T<:SUWeight} = scalartype(eltype(T)
5063
Base.getindex(W::SUWeight, args...) = Base.getindex(W.data, args...)
5164
Base.setindex!(W::SUWeight, args...) = (Base.setindex!(W.data, args...); W)
5265
Base.axes(W::SUWeight, args...) = axes(W.data, args...)
66+
Base.iterate(W::SUWeight, args...) = iterate(W.data, args...)
67+
68+
## (Approximate) equality
69+
function Base.:(==)(wts1::SUWeight, wts2::SUWeight)
70+
return wts1.data == wts2.data
71+
end
72+
function Base.isapprox(wts1::SUWeight, wts2::SUWeight; kwargs...)
73+
for (wt1, wt2) in zip(wts1, wts2)
74+
!isapprox(wt1, wt2; kwargs...) && return false
75+
end
76+
return true
77+
end
5378

5479
function compare_weights(wts1::SUWeight, wts2::SUWeight)
5580
@assert size(wts1) == size(wts2)
@@ -72,6 +97,20 @@ end
7297
7398
Represents an infinite projected entangled-pair state on a 2D square lattice
7499
consisting of vertex tensors and bond weights.
100+
The vertex tensor, x-weight and y-weight at row `i`, column `j`
101+
are defined as (the numbers show the axis order)
102+
```
103+
2
104+
105+
yᵢⱼ
106+
107+
1
108+
2
109+
110+
5←-Tᵢⱼ←-3 1←-xᵢⱼ←-2
111+
↓ ↘
112+
4 1
113+
```
75114
76115
## Fields
77116
@@ -92,6 +131,7 @@ struct InfiniteWeightPEPS{T<:PEPSTensor,E<:PEPSWeight}
92131
) where {T<:PEPSTensor,E<:PEPSWeight}
93132
@assert size(vertices) == size(weights)[2:end]
94133
Nr, Nc = size(vertices)
134+
# check space matching between vertex tensors and weight matrices
95135
for (r, c) in Iterators.product(1:Nr, 1:Nc)
96136
space(weights[2, r, c], 1)' == space(vertices[r, c], 2) || throw(
97137
SpaceMismatch("South space of bond weight y$((r, c)) does not match.")
@@ -136,6 +176,9 @@ end
136176
function InfiniteWeightPEPS(
137177
f, T, Pspaces::M, Nspaces::M, Espaces::M=Nspaces
138178
) where {M<:AbstractMatrix{<:Union{Int,ElementarySpace}}}
179+
@assert all(!isdual, Pspaces)
180+
@assert all(!isdual, Nspaces)
181+
@assert all(!isdual, Espaces)
139182
vertices = InfinitePEPS(f, T, Pspaces, Nspaces, Espaces).A
140183
Nr, Nc = size(vertices)
141184
weights = map(Iterators.product(1:2, 1:Nr, 1:Nc)) do (d, r, c)
@@ -296,17 +339,201 @@ function InfiniteWeightPEPS(peps::InfinitePEPS)
296339
return InfiniteWeightPEPS(peps.A, SUWeight(weights))
297340
end
298341

342+
## (Approximate) equality (gauge freedom is not allowed)
343+
function Base.:(==)(peps1::InfiniteWeightPEPS, peps2::InfiniteWeightPEPS)
344+
return peps1.vertices == peps2.vertices && peps1.weights == peps2.weights
345+
end
346+
function Base.isapprox(peps1::InfiniteWeightPEPS, peps2::InfiniteWeightPEPS; kwargs...)
347+
for (v1, v2) in zip(peps1.vertices, peps2.vertices)
348+
!isapprox(v1, v2; kwargs...) && return false
349+
end
350+
!isapprox(peps1.weights, peps2.weights; kwargs...) && return false
351+
return true
352+
end
353+
354+
# Mirroring and rotation
355+
#= Example: 3 x 3 network
356+
357+
- Original
358+
```
359+
| | |
360+
y₁₁ y₁₂ y₁₃
361+
| | |
362+
..x₁₃...┼---x₁₁---┼---x₁₂---┼---x₁₃---
363+
| | | 2
364+
y₂₁ y₂₂ y₂₃ ↓
365+
| | | y
366+
..x₂₃...┼---x₂₁---┼---x₂₂---┼---x₂₃--- ↓
367+
| | | 1
368+
y₃₁ y₃₂ y₃₃
369+
| | | 1 ←- x ←- 2
370+
..x₃₃...┼---x₃₁---┼---x₃₂---┼---x₃₃---
371+
: : :
372+
y₁₁ y₁₂ y₁₃
373+
: : :
374+
```
375+
376+
- After `mirror_antidiag`, x/y-weights are exchanged.
377+
```
378+
| | |
379+
x₃₃ x₂₃ x₁₃
380+
| | |
381+
..y₁₃...┼---y₃₃---┼---y₂₃---┼---y₁₃---
382+
| | | 2
383+
x₃₂ x₂₂ x₁₂ ↓
384+
| | | x
385+
..y₁₂...┼---y₃₂---┼---y₂₂---┼---y₁₂--- ↓
386+
| | | 1
387+
x₃₁ x₂₁ x₁₁
388+
| | | 1 ←- y ←- 2
389+
..y₁₁...┼---y₃₁---┼---y₂₁---┼---y₁₁---
390+
: : :
391+
x₃₃ x₂₃ x₁₃
392+
: : :
393+
```
394+
No further operations are needed.
395+
396+
- After `rotl90`, x/y-weights are exchanged.
397+
```
398+
| | |
399+
x₁₃ x₂₃ x₃₃
400+
| | |
401+
--y₁₃---┼---y₂₃---┼---y₃₃---┼...y₁₃...
402+
| | | 2
403+
x₁₂ x₂₂ x₃₂ ↓
404+
| | | x
405+
--y₁₂---┼---y₂₂---┼---y₃₂---┼...y₁₂... ↓
406+
| | | 1
407+
x₁₁ x₂₁ x₃₁
408+
| | | 2 -→ y -→ 1
409+
--y₁₁---┼---y₂₁---┼---y₃₁---┼...y₁₁...
410+
: : :
411+
x₁₃ x₂₃ x₃₃
412+
: : :
413+
```
414+
We need to further:
415+
- Move 1st column of x-weights to the last column.
416+
- Permute axes of x-weights.
417+
- Flip x-arrows from → to ←.
418+
419+
- After `rotr90`, x/y-weights are exchanged.
420+
```
421+
: : :
422+
x₃₃ x₂₃ x₁₃
423+
: : :
424+
..y₁₁...┼---y₃₁---┼---y₂₁---┼---y₁₁---
425+
| | | 1 ←- y ←- 2
426+
x₃₁ x₂₁ x₁₁
427+
| | | 1
428+
..y₁₂...┼---y₃₂---┼---y₂₂---┼---y₁₂--- ↑
429+
| | | x
430+
x₃₂ x₂₂ x₁₂ ↑
431+
| | | 2
432+
..y₁₃...┼---y₃₃---┼---y₂₃---┼---y₁₃---
433+
| | |
434+
x₃₃ x₂₃ x₁₃
435+
| | |
436+
```
437+
We need to further:
438+
- Move last row of y-weights to the 1st row.
439+
- Permute axes of y-weights.
440+
- Flip y-arrows from ↑ to ↓.
441+
442+
After `rot180`, x/y-weights are not exchanged.
443+
```
444+
: : :
445+
y₁₃ y₁₂ y₁₁
446+
: : :
447+
--x₃₃---┼---x₃₂---┼---x₃₁---┼...x₃₃...
448+
| | | 2 -→ x -→ 1
449+
y₃₃ y₃₂ y₃₁
450+
| | | 1
451+
--x₂₃---┼---x₂₂---┼---x₂₁---┼...x₂₃... ↑
452+
| | | y
453+
y₂₃ y₂₂ y₂₁ ↑
454+
| | | 2
455+
--x₁₃---┼---x₁₂---┼---x₁₁---┼...x₁₃...
456+
| | |
457+
y₁₃ y₁₂ y₁₁
458+
| | |
459+
```
460+
We need to further:
461+
- Move 1st column of x-weights to the last column.
462+
- Move last row of y-weights to the 1st row.
463+
- Permute axes of all weights and twist their axis 1.
464+
- Flip x-arrows from → to ←, and y-arrows from ↑ to ↓.
465+
=#
466+
467+
"""
468+
Mirror an `SUWeight` by its anti-diagonal line.
469+
"""
470+
function mirror_antidiag(wts::SUWeight)
471+
weights2_x = mirror_antidiag(wts[2, :, :])
472+
weights2_y = mirror_antidiag(wts[1, :, :])
473+
return SUWeight(weights2_x, weights2_y)
474+
end
475+
function Base.rotl90(wts::SUWeight)
476+
wts_x = circshift(rotl90(wts[2, :, :]), (0, -1))
477+
for (i, wt) in enumerate(wts_x)
478+
wts_x[i] = DiagonalTensorMap(flip(permute(wt, ((2,), (1,))), (1, 2)))
479+
end
480+
wts_y = rotl90(wts[1, :, :])
481+
return SUWeight(wts_x, wts_y)
482+
end
483+
function Base.rotr90(wts::SUWeight)
484+
wts_x = rotr90(wts[2, :, :])
485+
wts_y = circshift(rotr90(wts[1, :, :]), (1, 0))
486+
for (i, wt) in enumerate(wts_y)
487+
wts_y[i] = DiagonalTensorMap(flip(permute(wt, ((2,), (1,))), (1, 2)))
488+
end
489+
return SUWeight(wts_x, wts_y)
490+
end
491+
function Base.rot180(wts::SUWeight)
492+
wts_x = circshift(rot180(wts[1, :, :]), (0, -1))
493+
wts_y = circshift(rot180(wts[2, :, :]), (1, 0))
494+
for (i, wt) in enumerate(wts_x)
495+
wts_x[i] = DiagonalTensorMap(flip(permute(wt, ((2,), (1,))), (1, 2)))
496+
end
497+
for (i, wt) in enumerate(wts_y)
498+
wts_y[i] = DiagonalTensorMap(flip(permute(wt, ((2,), (1,))), (1, 2)))
499+
end
500+
return SUWeight(wts_x, wts_y)
501+
end
502+
299503
"""
300504
mirror_antidiag(peps::InfiniteWeightPEPS)
301505
302-
Mirror the unit cell of an iPEPS with weights by its anti-diagonal line.
506+
Mirror an `InfiniteWeightPEPS` by its anti-diagonal line.
303507
"""
304508
function mirror_antidiag(peps::InfiniteWeightPEPS)
305509
vertices2 = mirror_antidiag(peps.vertices)
306510
for (i, t) in enumerate(vertices2)
307-
vertices2[i] = permute(t, ((1,), (3, 2, 5, 4)))
511+
vertices2[i] = mirror_antidiag(t)
512+
end
513+
weights2 = mirror_antidiag(peps.weights)
514+
return InfiniteWeightPEPS(vertices2, weights2)
515+
end
516+
function Base.rotl90(peps::InfiniteWeightPEPS)
517+
vertices2 = rotl90(peps.vertices)
518+
for (i, t) in enumerate(vertices2)
519+
vertices2[i] = flip(rotl90(t), (3, 5))
520+
end
521+
weights2 = rotl90(peps.weights)
522+
return InfiniteWeightPEPS(vertices2, weights2)
523+
end
524+
function Base.rotr90(peps::InfiniteWeightPEPS)
525+
vertices2 = rotr90(peps.vertices)
526+
for (i, t) in enumerate(vertices2)
527+
vertices2[i] = flip(rotr90(t), (2, 4))
528+
end
529+
weights2 = rotr90(peps.weights)
530+
return InfiniteWeightPEPS(vertices2, weights2)
531+
end
532+
function Base.rot180(peps::InfiniteWeightPEPS)
533+
vertices2 = rot180(peps.vertices)
534+
for (i, t) in enumerate(vertices2)
535+
vertices2[i] = flip(rot180(t), Tuple(2:5))
308536
end
309-
weights2_x = mirror_antidiag(peps.weights[2, :, :])
310-
weights2_y = mirror_antidiag(peps.weights[1, :, :])
311-
return InfiniteWeightPEPS(vertices2, weights2_x, weights2_y)
537+
weights2 = rot180(peps.weights)
538+
return InfiniteWeightPEPS(vertices2, weights2)
312539
end

src/utility/util.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ function absorb_s(U::AbstractTensorMap, S::DiagonalTensorMap, V::AbstractTensorM
102102
return U * sqrt_S, sqrt_S * V
103103
end
104104
105+
"""
106+
flip_svd(u::AbstractTensorMap, s::DiagonalTensorMap, vh::AbstractTensorMap)
107+
108+
Given `tsvd` result `u ← s ← vh`, flip the arrow between the three tensors
109+
to `u2 → s2 → vh2` such that
110+
```
111+
u * s * vh = (@tensor t2[-1; -2] := u2[-1; 1] * s2[1; 2] * vh2[2; -2])
112+
```
113+
"""
114+
function flip_svd(u::AbstractTensorMap, s::DiagonalTensorMap, vh::AbstractTensorMap)
115+
return flip(u, 2), DiagonalTensorMap(flip(s, (1, 2))), flip(vh, 1)
116+
end
117+
105118
"""
106119
twistdual(t::AbstractTensorMap, i)
107120
twistdual!(t::AbstractTensorMap, i)

test/runtests.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ end
6464
@time @safetestset "Norm-preserving retractions" begin
6565
include("utility/retractions.jl")
6666
end
67+
@time @safetestset "Rotation of InfiniteWeightPEPS" begin
68+
include("utility/iwpeps_rotation.jl")
69+
end
6770
end
6871
if GROUP == "ALL" || GROUP == "EXAMPLES"
6972
@time @safetestset "Transverse Field Ising model" begin

0 commit comments

Comments
 (0)