-
Notifications
You must be signed in to change notification settings - Fork 0
/
AnalyticFermionicCommutator.py
342 lines (274 loc) · 10.1 KB
/
AnalyticFermionicCommutator.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
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!/usr/bin/env python
# coding: utf-8
import itertools
import logging
import sys
import copy
import numpy as np
from qiskit.quantum_info import Pauli
from qiskit.tools import parallel_map
from qiskit.tools.events import TextProgressBar
from qiskit.aqua import aqua_globals
logger = logging.getLogger(__name__)
class term:
#this class is for elemntary term of arbitrary order of the fermionic operator coef*adag_i*adag_k*a_l*a_j
def __init__(self, coef, indlist):
self._coef = coef # coefficient in fron of the fermionic product
self._indlist = indlist # list of indicies of the ferminonic operators in the normal form
@property
def coef(self):
return self._coef
def set_coef(self, new_coef):
self._coef = new_coef
@property
def indlist(self):
return self._indlist
@property
def order(self):
return len(self._indlist)
def h_matrix_to_terms(h,threshold=1e-12):
res = []
dim = len(h.shape)
size = h.shape[0]
for x in itertools.product(range(size),repeat = dim):
c = h[x]
if abs(c)>threshold:
res.append(term(c,list(x)))
return res
def scMult(scalar,oper,threshold=1e-12):
res = copy.deepcopy(oper)
if abs(scalar)<=threshold:
return []
else:
for x in res:
x.set_coef(x.coef*scalar)
return res
def equal(st1,st2):
return np.array_equal(np.array(st1.indlist),np.array(st2.indlist))
def smaller(st1,st2):
if len(st1.indlist)<len(st2.indlist):
return True
elif (len(st1.indlist)==len(st2.indlist))and(equal(st1,st2)==False):
# return ((np.array(st2.indlist)-np.array(st1.indlist))>=0).all()
tmp = np.array(st2.indlist)-np.array(st1.indlist)
for i in range(len(tmp)):
if tmp[i]>0:
return True
elif tmp[i]<0:
return False
else:
return False
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if smaller(x,pivot)]
middle = [x for x in arr if equal(x,pivot)]
right = [x for x in arr if smaller(pivot,x)]
return quicksort(left) + middle + quicksort(right)
def SimplifyOper(oper,threshold=1e-12):
res = copy.deepcopy(oper)
Finished = False
while Finished==False:
BoolA = []
for i in range(len(res)-1):
BoolA.append(equal(res[i],res[i+1]))
if np.array(BoolA).any()==True:
Finished = False
else:
Finished = True
if Finished==False:
for i in range(len(res)-1):
if equal(res[i],res[i+1])==True:
new_coef = res[i].coef+res[i+1].coef
if abs(new_coef)<threshold:
#kill both
res.pop(i+1)
res.pop(i)
else:
#kill i+1
res[i].set_coef(new_coef)
res.pop(i)
break
return res
def Addition(oper1,oper2,threshold=1e-12):
res = copy.deepcopy(oper1)+copy.deepcopy(oper2)
res = quicksort(res)
res = SimplifyOper(res,threshold)
return res
def Subtraction(oper1,oper2,threshold=1e-12):
res = copy.deepcopy(oper1)+scMult(-1,oper2,threshold)
res = quicksort(res)
res = SimplifyOper(res,threshold)
return res
def quicksortL(arr):
#quick sort just for arrays
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot ]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if pivot < x]
return quicksortL(left) + middle + quicksortL(right)
def order(b):
count = 0
ideal = np.array(quicksortL(b))
temp = b
DoOrder = True
while DoOrder==True:
if np.array_equal(ideal,np.array(temp))==True:
DoOrder = False
for i in range(len(temp)-1):
if temp[i]>temp[i+1]:
tmp = temp[i]
temp[i] = temp[i+1]
temp[i+1] = tmp
count +=1
break
return count
def TermMultiply(term1,term2,threshold=1e-12):
c1 = term1.coef
c2 = term2.coef
l1 = term1.indlist
l2 = term2.indlist
#adag -> 0, a -> 1
op = list(np.zeros(len(l1)//2))+list(np.ones(len(l1)//2))+list(np.zeros(len(l2)//2))+list(np.ones(len(l2)//2))
unsort = [1,l1+l2,op]
res = [unsort]
Ordered = False
forceBreak1 = False
newphase = 1
newind = []
newop = []
UpdateRes = False
while Ordered == False:
if UpdateRes == True:
res.append([newphase,newind,newop])
UpdateRes = False
BoolA = [np.array(x[2][:len(x[2])//2]).any()==1 for x in res]
Test1 = np.array(BoolA).any()==True #if test1 is True need to do ordering
Bool2 = [np.array_equal(np.array(x[1][:len(x[1])//2]),np.array(quicksortL(x[1][:len(x[1])//2]))) for x in res]
Test2 = np.array(Bool2).any()==False #if test2 is True need to do ordering of creation indexies
Bool3 = [np.array_equal(np.array(x[1][len(x[1])//2:]),np.array(quicksortL(x[1][len(x[1])//2:]))) for x in res]
Test3 = np.array(Bool3).any()==False #if test3 is True need to do ordering of annih indexies
if (Test1 == False)and(Test2==False)and(Test3==False):
Ordered = True
if Test1 == True:
for x in res:
forceBreak1 = False
forceBreak2 = False
if np.array(x[2][:len(x[2])//2]).any()==1:
#need to do a step of ordering
for i in range(len(x[2])-1):
if (x[2][i]==1)and(x[2][i+1]==0):
#do the swap
if x[1][i]!=x[1][i+1]:
#swap+phase
tmp = x[1][i]
x[1][i] = x[1][i+1]
x[1][i+1] = tmp
x[2][i]=0
x[2][i+1] = 1
x[0] *=-1
forceBreak1 = True
break
elif x[1][i]==x[1][i+1]:
#add list
newphase = copy.deepcopy(x[0])
newind = copy.deepcopy(x[1])
newind.pop(i+1)
newind.pop(i)
newop = copy.deepcopy(x[2])
newop.pop(i+1)
newop.pop(i)
UpdateRes = True
x[2][i]=0
x[2][i+1] = 1
x[0] *=-1
#swap+phase
forceBreak2 = True
break
if forceBreak1==True:
break
if forceBreak2==True:
break
if (Test1 == False)and((Test2 == True)or(Test3 == True)):
for x in res:
x_cr = x[1][:len(x[1])//2]
x_an = x[1][len(x[1])//2:]
phasefactor = 1
if (order(x_cr)+order(x_an))%2==1:
phasefactor = -1
x[0] *=phasefactor
x[1] = quicksortL(x_cr)+quicksortL(x_an)
realres = []
for x in res:
realres.append(term(c1*c2*x[0],x[1]))
realres = quicksort(realres)
realres = SimplifyOper(realres,threshold)
return realres
def Multiply(oper1,oper2,threshold=1e-12):
res = []
o1 = quicksort(oper1)
o1 = SimplifyOper(o1,threshold)
o2 = quicksort(oper2)
o2 = SimplifyOper(o2,threshold)
for x in o1:
for y in o2:
res=Addition(res,TermMultiply(x,y,threshold),threshold)
res = quicksort(res)
res = SimplifyOper(res,threshold)
return res
def RemoveDoubles(oper,threshold=1e-12):
o1 = copy.deepcopy(oper)
o1 = quicksort(o1)
o1 = SimplifyOper(o1,threshold)
Removed = False
while Removed == False:
if not o1:
Removed = True
for i in range(len(o1)):
ind = o1[i].indlist
cr_ind = ind[:len(ind)//2]
an_ind = ind[len(ind)//2:]
np_cr_ind = np.array(cr_ind)
np_an_ind = np.array(an_ind)
cp_cr_ind = np.array(list(set(cr_ind)))
cp_an_ind = np.array(list(set(an_ind)))
if (np.array_equal(np_cr_ind,cp_cr_ind)==False)or(np.array_equal(np_an_ind,cp_an_ind)==False):
o1.pop(i)
break
elif (not o1):
Removed = True
break
elif (i == len(o1)-1):
Removed = True
break
return o1
def FermCommutator(oper1,oper2,threshold=1e-12):
o1 = quicksort(oper1)
o1 = SimplifyOper(o1,threshold)
o2 = quicksort(oper2)
o2 = SimplifyOper(o2,threshold)
ab = Multiply(o1,o2,threshold)
ba = Multiply(o2,o1,threshold)
res = Subtraction(ab,ba,threshold)
res = quicksort(res)
res = SimplifyOper(res,threshold)
res = RemoveDoubles(res,threshold=1e-12)
return res
def oper_to_h(oper,nferm):
reslist = []
for x in oper:
reslist.append(int(x.order))
reslist=quicksortL(list(set(reslist)))
res = []
for dim in reslist:
res.append(np.zeros(np.full((dim,), nferm)))
for x in oper:
x_order = x.order
x_coef = x.coef
x_ind = x.indlist
res[reslist.index(x_order)][tuple(x_ind)]=x_coef
return res
# In[ ]: