-
Notifications
You must be signed in to change notification settings - Fork 2
/
02_ManualMPS_QFT.Rmd
126 lines (96 loc) · 3 KB
/
02_ManualMPS_QFT.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
---
jupyter:
jupytext:
text_representation:
extension: .Rmd
format_name: rmarkdown
format_version: '1.2'
jupytext_version: 1.9.1
kernelspec:
display_name: Python 3
language: python
name: python3
---
```{python}
#---Linear algebra libraries---#
import numpy as np
from numpy import linalg as LA
from ncon import ncon #Tensor contractions
#---Plotting---#
import matplotlib.pyplot as plt
#---MPS library---#
import quimb
#---Utilities---#
from copy import deepcopy
#---Our functions---#
from MPS_QFT.helper import print_state, right_contract, left_contract
from MPS_QFT.helper import to_full_MPS, to_dense, to_approx_MPS
from MPS_QFT.manual import apply_one_qubit_gate, apply_two_qubit_gate_full, apply_two_qubit_gate, max_bond_dimension, left_canonize, right_canonize
from MPS_QFT.gates import cphase_swap_quimb
from MPS_QFT.circuit import qft_circuit_swap_full, qft_circuit_swap_approx
from MPS_QFT.checks import check_left_canonization, check_right_canonization
```
## Graphs for Testing
```{python}
#Test precision with a random state
N = 6
d = 2
sample_state = np.random.rand(d**N)
chis = [2,3,4,5,6,7,8,9,10]
errors = []
for chi in chis:
approx_MPS = to_approx_MPS(sample_state, N, d, chi)
errors.append(LA.norm(sample_state - to_dense(approx_MPS).flatten()))
plt.xlabel('$\chi$')
plt.ylabel('Error')
plt.plot(chis, errors)
#note that for N=6 and d=2, the maximum bond dimension is 2^3 = 8
#Like this: o-2-o-4-o-8-o-4-o-2-o
#And in fact the error is minimum at chi = 8, and remains 0 afterwards!
```
```{python}
#Let's try with a GHZ state. Since it can be written as a combination of only 2 separable states, we expect a chi=2 to suffice
N = 6
d = 2
ghz_state = np.zeros(d**N)
ghz_state[0] = 1
ghz_state[-1] = 1
chis = [1,2,3,4,5,6,7,8,9,10]
errors = []
for chi in chis:
approx_MPS = to_approx_MPS(ghz_state, N, d, chi)
errors.append(LA.norm(ghz_state - to_dense(approx_MPS).flatten()))
plt.xlabel('$\chi$')
plt.ylabel('Error')
plt.plot(chis, errors)
#Yay!
```
```{python}
N=10
chi=2
ghz = np.zeros(2**N)
ghz[0] = 1
ghz[-1] = 1
ghz = ghz/np.sqrt(2)
print("Initial state")
print_state(ghz)
MPS_ghz = to_approx_MPS(ghz, d=2, N=N, chi=chi)
quimb.tensor.MatrixProductState(MPS_ghz, shape='lpr').show()
manual_qft = qft_circuit_swap_approx(MPS_ghz, N, chi=chi)
manual_qft_dense = to_dense(manual_qft).flatten()
#Check bond dimensions
assert max_bond_dimension(MPS_ghz) == chi, "Bond dimension error"
assert max_bond_dimension(manual_qft) == chi, "Bond dimension error"
print("MPS after QFT")
quimb.tensor.MatrixProductState(manual_qft, shape='lpr').show()
```
## Quimb implementation
```{python}
from MPS_QFT.circuit import qft_circuit_quimb
from MPS_QFT.helper import Fidelity
psi0 = quimb.tensor.tensor_gen.MPS_ghz_state(N)
qft_circuit_quimb(psi0, N, chi=2)
psi0.graph(color=['psi0', 'H', 'Cphase_swap'], show_inds=True) #Plot the network
result = psi0.to_dense()
print("Fidelity between QFT results from manual (chi=2) and quimb: ", Fidelity(manual_qft_dense, result))
```