Skip to content

Commit 2bb4dbb

Browse files
authored
Update README.md
1 parent 9855426 commit 2bb4dbb

File tree

1 file changed

+120
-1
lines changed

1 file changed

+120
-1
lines changed

README.md

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,121 @@
11
# SweepContractor.jl
2-
Julia package for contraction of tensor networks, based on the sweep line algorithm outlined in the paper "General tensor network decoding of 2D Pauli codes" (arXiv:2101.04125).
2+
3+
A Julia package for the contraction of tensor networks using the sweep-line-based contraction algorithm laid out in the paper [General tensor network decoding of 2D Pauli codes](https://arxiv.org/abs/2101.04125). This algorithm is primarily designed for two-dimensional tensor networks but contains graph manipulation tools that allow it to function for generic tensor networks.
4+
5+
Below I have provided some examples of `SweepContractor.jl` at work. Scripts with working versions of each of these examples are also included in the package. For more detailed documentation consult help pages by using `?` in the Julia REPL.
6+
7+
Feel free to contact me with any comments, questions, or suggestions at [`[email protected]`](mailto:[email protected]).
8+
9+
## Example 1: ABCD
10+
11+
Consider the following four tensor networks, taken from the tensor network review [Hand-waving and Interpretive Dance](https://arxiv.org/abs/1603.03039):
12+
13+
>![ABCD1](ABCD1.png),
14+
15+
where each tensor is defined
16+
17+
>![ABCD2](ABCD2.png)
18+
19+
First we start by including `SweepContractor.jl`, which we achieve by running
20+
```julia
21+
using Pkg; Pkg.add(url="https://github.com/chubbc/SweepContractor.jl")
22+
using SweepContractor
23+
```
24+
Next we need to define our network. We do this by initialising a `LabelledTensorNetwork`, which allows us to have a tensor network with elements labelled by an arbitrary type, in our case `Char`.
25+
```julia
26+
LTN = LabelledTensorNetwork{Char}()
27+
```
28+
Next, we populate this with our four tensors, which are each specified by giving a list of neighbouring tensors, an array consisting of the entries, and a two-dimensional location.
29+
```julia
30+
LTN['A'] = Tensor(['D','B'], [i^2-2j for i=0:2, j=0:2], 0, 1)
31+
LTN['B'] = Tensor(['A','D','C'], [-3^i*j+k for i=0:2, j=0:2, k=0:2], 0, 0)
32+
LTN['C'] = Tensor(['B','D'], [j for i=0:2, j=0:2], 1, 0)
33+
LTN['D'] = Tensor(['A','B','C'], [i*j*k for i=0:2, j=0:2, k=0:2], 1, 1)
34+
```
35+
Finally, we want to contract this network. To do this we need to specify a target bond dimension and a maximum bond-dimension. In our case, we will use `2` and `4`.
36+
```julia
37+
value = sweep_contract(LTN,2,4)
38+
```
39+
To avoid underflows or overflows in the case of large networks `sweep_contract` does not simply return a float, but returns `(f::Float64,i::Int64)`, which represents a value`f*2^i`. In this case, it returns `(1.0546875, 10)`. By running `ldexp(sweep...)` we can see that this corresponds to the exact value of the network of `1080`.
40+
41+
Note there are two speedups that can be made to this code. Firstly, `sweep_contract` copies the input tensor network, so we can use the form `sweep_contract!` which allows the function to modify the input tensor network, skipping this copy step. Secondly, `sweep_contract` is designed to function on arbitrary tensor networks, and starts by flattening the network down into two dimensions. If our network is already well-structured, we can run the contraction in fast mode skipping these steps.
42+
```julia
43+
value = sweep_contract!(LTN,2,4; fast=true)
44+
```
45+
46+
## Examples 2: 2d grid (open)
47+
48+
Next, we move on to the sort of network this code was primarily designed for, a two-dimensional network. Here consider an square grid network of linear size `L`, with each index of dimension `d`. For convenience, we can once again use a `LabelledTensorNetwork`, with labels in this case corresponding to coordinates in the grid. To construct such a network with Gaussian random entries we can use code such as:
49+
```julia
50+
LTN = LabelledTensorNetwork{Tuple{Int,Int}}();
51+
for i1:L, j1:L
52+
adj=Tuple{Int,Int}[];
53+
i>1 && push!(adj,(i-1,j))
54+
j>1 && push!(adj,(i,j-1))
55+
i<L && push!(adj,(i+1,j))
56+
j<L && push!(adj,(i,j+1))
57+
LTN[i,j] = Tensor(adj, randn(d*ones(Int,length(adj))...), i, j)
58+
end
59+
```
60+
We note that the `if` statements used have the function of imposing open boundary conditions. Once again we can now contract this by running the sweep contractor (in fast mode), for some choice of bond-dimensions χ and τ:
61+
```julia
62+
value = sweep_contract!(LTN,χ,τ; fast=true)
63+
```
64+
## Example 3: 2d grid (periodic)
65+
But what about contracting a 2d grid with *periodic* boundary conditions? Well, this contains a small number of long-range bonds. Thankfully, however `SweepContractor.jl` can run on such graphs by first planarising them.
66+
67+
We might start by taking the above code and directly changing the boundary conditions, but this will result in the boundary edges overlapping other edges in the network (e.g. the edge from `(1,1)` to `(1,2)` will overlap the edge from `(1,1)` to `(L,1)`), which the contractor cannot deal with. As a crude workaround we just slightly shift the position of each tensor:
68+
```julia
69+
LTN = LabelledTensorNetwork{Tuple{Int,Int}}();
70+
for i1:L, j1:L
71+
adj=[
72+
(mod1(i-1,L),mod1(j,L)),
73+
(mod1(i+1,L),mod1(j,L)),
74+
(mod1(i,L),mod1(j-1,L)),
75+
(mod1(i,L),mod1(j+1,L))
76+
]
77+
LTN[i,j] = Tensor(adj, randn(d,d,d,d), i+0.1*rand(), j+0.1*rand())
78+
end
79+
```
80+
Here the `mod1` function is imposing our periodic boundary condition, and `rand()` is being used to slightly move each tensor. Once again we can now run `sweep_contract` on this, but cannot use fast-mode as the network is no longer planar:
81+
```julia
82+
value = sweep_contract!(LTN,χ,τ)
83+
```
84+
## Example 4: 3d lattice
85+
If we can impose periodic boundary conditions, can we go further away from 2D? How about 3D? We sure can! For this we can just add another dimension to the above construction for a 2d grid:
86+
```julia
87+
LTN = LabelledTensorNetwork{Tuple{Int,Int,Int}}();
88+
for i1:L, j1:L, k1:L
89+
adj=Tuple{Int,Int,Int}[];
90+
i>1 && push!(adj,(i-1,j,k))
91+
i<L && push!(adj,(i+1,j,k))
92+
j>1 && push!(adj,(i,j-1,k))
93+
j<L && push!(adj,(i,j+1,k))
94+
k>1 && push!(adj,(i,j,k-1))
95+
k<L && push!(adj,(i,j,k+1))
96+
LTN[i,j,k] = Tensor(
97+
adj,
98+
randn(d*ones(Int,length(adj))...),
99+
i+0.01*randn(),
100+
j+0.01*randn()
101+
)
102+
end
103+
104+
value = sweep_contract!(LTN,χ,τ)
105+
```
106+
## Example 5: Complete network
107+
So how far can we go away from two-dimensional? The further we stray away from two-dimensional the more inefficient the contraction will be, but for small examples arbitrary connectivity is permissible. The extreme example is a completely connected network of `n` tensors:
108+
```julia
109+
TN=TensorNetwork(undef,n);
110+
for i=1:n
111+
TN[i]=Tensor(
112+
setdiff(1:n,i),
113+
randn(d*ones(Int,n-1)...),
114+
randn(),
115+
randn()
116+
)
117+
end
118+
119+
value = sweep_contract!(LTN,χ,τ)
120+
```
121+
Here we have used a `TensorNetwork` instead of a `LabelledTensorNetwork`. In a `LabelledTensorNetwork` each tensor can be labelled by an arbitrary type, which is accomplished by storing the network as a dictionary, which can incur significant overheads. `TensorNetwork` is built using vectors, which each label now needs to be labelled by an integer `1` to `n`, but can be significantly faster. While less flexible, `TensorNetwork` should be preferred in performance-sensitive settings.

0 commit comments

Comments
 (0)