-
Notifications
You must be signed in to change notification settings - Fork 0
/
Gates.py
322 lines (240 loc) · 8 KB
/
Gates.py
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
from numpy import array, sqrt, kron, zeros, pi, dot, trace, asarray, identity
from numpy import testing,linalg
import Operations as op
from scipy.linalg import expm
from cmath import exp
import SpecialStates as ss
from itertools import product
def x():
out = array([[0, 1], [1, 0]])
return out
def h():
out1 = 1/sqrt(2)*array([[1, 1], [1, -1]])
return out1
def id():
out2 = array([[1, 0], [0, 1]])
return out2
def y():
out3 = array([[0, -1j], [1j, 0]])
return out3
def z():
out4 = array([[1, 0], [0, -1]])
return out4
def cnot():
out5 = array([[1, 0, 0, 0, ], [0, 1, 0, 0, ], [0, 0, 1, 0], [0, 0, 0, 1]])
return out5
def cz():
out6 = array([[1, 0, 0, 0, ], [0, 1, 0, 0, ], [0, 0, 1, 0], [0, 0, 0, -1]])
return out6
def r_x(theta):
out7 = expm(-1j*theta*x()/2)
return out7
def r_y(theta):
out8 = expm(-1j*theta*y()/2)
return out8
def r_z(theta):
out8 = expm(-1j*theta*z()/2)
return out8
def r_i(theta):
out9 = expm(-1j*theta*id()/2)
return out9
def phase(theta):
out10 = array([[1, 0], [0, exp(1j*theta)]])
return out10
def b1():
out = array([[1, 0], [0, 0]])
return out
def b2():
out = array([[0, 1], [0, 0]])
return out
def b3():
out = array([[0, 0], [1, 0]])
return out
def b4():
out = array([[0, 0], [0, 1]])
return out
def swap():
out =array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])
return out
def q_Hamiltonian(ham, n, s):
"""
:param ham: hamiltonian by which the qubits will evolve by
:param s : must be a string of ones e.g 010 represents id (tensor)ham(tensor)id while 10 represents ham(tensor) id
:param n : The length of the string. This determines how many zeros there will be
:return:
"""
label = op.generatehamiltoniantring(n, s)
a = zeros((pow(2, n), pow(2, n)), dtype=complex)
terms = {
"0": id(),
"1": ham
}
for qubit in range(len(label)):
tmp = 1
for digit in label[qubit]:
tmp = kron(tmp, terms[digit])
a += tmp
return a
def e_ij(tup, i, j):
"""
:param tup: Dimension of your matrix
:param i: The row your 1 will appear
:param j: The column your 1 will appear
:return: This returns a matrix with 1 in some spot (i,j) and zeros else where
"""
k = zeros(tup)
k[i-1, j-1] = 1
return k
def c_u(u, n, i, j):
"""
This creates a controlled unitary operation on n qubits
:param u: Unitary matrix
:param n: The number of qubits to be used
:param i: the position of control qubit for the controlled operation
:param j: the position of target qubit for the controlled operation
:return: the controlled operation
"""
term_1 = {
"0": id(),
"1": e_ij((2, 2), 1, 1)
}
term_2 = {
"0": id(),
"2": u,
"1": e_ij((2, 2), 2, 2)
}
# What happens when the control qubit is in the zero state
label_1 = op.generatetensorstring(n, i)
cu_1 = op.superkron(term_1, val=1, string=label_1)
# What happens when the control bit is in the one state
label_2 = op.controlgatestring(n, ('1', i), ('2', j))
cu_2 = op.superkron(term_2, val=1, string=label_2)
return cu_1 + cu_2
def reversed_cu(u, n, i, j):
"""
This creates a controlled unitary operation on n qubits
:param u: Unitary matrix
:param n: The number of qubits to be used
:param i: the position of control qubit for the controlled operation
:param j: the position of target qubit for the controlled operation
:return: the controlled operation
"""
term_1 = {
"0": id(),
"1": e_ij((2, 2), 1, 1)
}
term_2 = {
"0": id(),
"2": u,
"1": e_ij((2, 2), 2, 2)
}
# What happens when the control qubit is in the zero state
label_1 = op.generatetensorstring(n, i)
label_1 = ''.join(list(reversed(label_1)))
cu_1 = op.superkron(term_1, val=1, string=label_1)
# What happens when the control bit is in the one state
label_2 = op.controlgatestring(n, ('1', i), ('2', j))
label_2 = ''.join(list(reversed(label_2)))
cu_2 = op.superkron(term_2, val=1, string=label_2)
return cu_1 + cu_2
def qft(n):
"""
:param n: The number of qubits
:return: outputs the quantum fourier transform for n qubits
"""
w = exp(1j*2*pi/n)
dft = zeros((n, n), dtype=complex)
for i in range(0, n):
for k in range(0, n):
dft[i, k] = pow(w, i*k)
return dft*1/sqrt(n)
def bakersmap(n):
"""
:param n: The number of qubits
:return:
"""
q = qft(n)
q_1 = qft(n/2)
out = op.ctranspose(q)*kron(id(), q_1)
return out
def multi_hadamard(n):
temp = 1
for i in range(0, n):
temp = kron(temp, h())
return temp
def pauli_group(n, full=False, normalize=True):
"""
:param n: number of qubits
:param full: If true returns the full pauli group for n qubits including group elements that differ by center
of the group
:param normalize: If true returns pauli group elements so that group are normalized
:return: Returns a dictionary of unitary representation of the single qubit pauli group
"""
if normalize:
pauli_matrix = {'I': id() / sqrt(2), 'X': x() / sqrt(2), 'Y': y() / sqrt(2), 'Z': z() / sqrt(2)}
else:
pauli_matrix = {'I': id(), 'X': x(), 'Y': y(), 'Z': z()}
center = {'i': 1j, '-i': -1j, '1': 1, '-1': -1}
pauli_labels = [''.join(i) for i in product('IXYZ', repeat=n)]
qubit_group = {}
pauli_dict ={}
if full is False:
for pl in pauli_labels:
pauli_dict[pl] = op.superkron(pauli_matrix, val=1, string=pl)
else:
for i in center:
for p in pauli_dict:
qubit_group[str(i)+str(p)] = dot(center[i], pauli_dict[p])
return pauli_dict
def pauli_expansion(rho, pauli_d):
"""
Pauli terms contributing to density matrix rho
:param rho: The density matrix for which you need the pauli expansion
:param pauli_d: The n qubit pauli group in which you write your density matrix expansion
:return:
"""
pauli_terms = {}
for i in pauli_d:
r = (trace(dot(rho,pauli_d[i])))
if r != 0:
pauli_terms[i] = r
return pauli_terms
def stabilizer(stabilizer, ancilla_label=None, n=None):
"""
Stabilizer must contain only X and Z operators
:param stabilizer: The stabilizer you want to measure
:param ancilla_label: The ancilla_label qubit used to measure the stabilizer
:param n: The number of data qubits in the circuit
:return: A unitary that represents a quantum circuit that is used to measure a specific stabilizer,
using CNOT and Hadamard gates
"""
# The numbering of qubits starts from 1 rather than 0
stabilizer_dict = {}
oper_dict = {'0': id(), '1': h()}
unitary = identity(pow(2, n))
for counter, s in enumerate(stabilizer, 1):
if s == 'I' or s == 'i':
continue
else:
stabilizer_dict[counter] = s
for s in stabilizer_dict:
if stabilizer_dict[s] == 'Z' or stabilizer_dict[s] == 'z':
unitary = dot(unitary, c_u(x(), n, s, ancilla_label))
elif stabilizer_dict[s] == 'X' or stabilizer_dict[s] == 'x':
string = op.generatehamiltoniantring(n, '1', onestring=True, pos=s-1, pad='0')
unitary = dot(unitary, op.superkron(oper_dict, val=1, string=string))
unitary = dot(unitary, c_u(x(), n, s, ancilla_label))
unitary = dot(unitary, op.superkron(oper_dict, val=1, string=string))
return unitary
if __name__ == '__main__':
d = stabilizer('XZ', ancilla_label=3, n=3)
print('Unitary from measure_stabilizer: ', d)
a = op.superkron(h(), id(), id())
b = op.superkron(id(), h(), id())
e = c_u(x(), 3, 1, 3)
f = c_u(x(), 3, 2, 3)
g = dot(a, dot(e, a))
i = dot(b, dot(f, b))
j = dot(f, g)
print('Unitary to check: ', j)
print('norm between matrices : ', linalg.norm(d-j))