5
5
"""
6
6
7
7
import sys
8
+
8
9
sys .path .insert (0 , "../" )
9
10
10
11
import numpy as np
16
17
ctype , rtype = tc .set_dtype ("complex64" )
17
18
K = tc .set_backend ("tensorflow" )
18
19
19
- n = 10 # the number of qubits (must be even for consistency later)
20
- ncz = 2 # number of cz layers in Schrodinger circuit
21
- nlayersq = ncz + 1 # Schrodinger parameter layers
20
+ n = 10 # the number of qubits (must be even for consistency later)
21
+ ncz = 2 # number of cz layers in Schrodinger circuit
22
+ nlayersq = ncz + 1 # Schrodinger parameter layers
22
23
23
24
# training setup
24
25
epochs = 1000
28
29
h6h = np .load ("./h6_hamiltonian.npy" ) # reported in 0.99 A
29
30
hamiltonian = construct_matrix_v3 (h6h .tolist ())
30
31
32
+
31
33
def hybrid_ansatz (structure , paramq , preprocess = "direct" , train = True ):
32
34
"""_summary_
33
35
@@ -54,50 +56,51 @@ def hybrid_ansatz(structure, paramq, preprocess="direct", train=True):
54
56
pass
55
57
56
58
structure = K .cast (structure , ctype )
57
- structure = tf .reshape (structure , shape = [n // 2 , 2 ])
59
+ structure = tf .reshape (structure , shape = [n // 2 , 2 ])
58
60
59
61
# quantum variational in Schrodinger part, first consider a ring topol
60
62
for j in range (nlayersq ):
61
- if j != 0 and j != nlayersq - 1 :
62
- for i in range (j % 2 , n , 2 ):
63
- c .cz (i , (i + 1 ) % n )
63
+ if j != 0 and j != nlayersq - 1 :
64
+ for i in range (j % 2 , n , 2 ):
65
+ c .cz (i , (i + 1 ) % n )
64
66
for i in range (n ):
65
67
c .rx (i , theta = paramq [j , i , 0 ])
66
68
c .ry (i , theta = paramq [j , i , 1 ])
67
69
c .rz (i , theta = paramq [j , i , 2 ])
68
70
69
71
# Clifford part, which is actually virtual
70
72
if train :
71
- for j in range (0 ,n // 2 - 1 ):
73
+ for j in range (0 , n // 2 - 1 ):
72
74
dis = j + 1
73
- for i in range (0 ,n ):
75
+ for i in range (0 , n ):
74
76
c .unitary (
75
77
i ,
76
- (i + dis ) % n ,
78
+ (i + dis ) % n ,
77
79
unitary = structure [j , 0 ] * tc .gates .ii ().tensor
78
80
+ structure [j , 1 ] * tc .gates .cz ().tensor ,
79
81
)
80
82
81
- for i in range (0 ,n // 2 ):
83
+ for i in range (0 , n // 2 ):
82
84
c .unitary (
83
85
i ,
84
- i + n // 2 ,
85
- unitary = structure [n // 2 - 1 , 0 ] * tc .gates .ii ().tensor
86
- + structure [n // 2 - 1 , 1 ] * tc .gates .cz ().tensor ,
86
+ i + n // 2 ,
87
+ unitary = structure [n // 2 - 1 , 0 ] * tc .gates .ii ().tensor
88
+ + structure [n // 2 - 1 , 1 ] * tc .gates .cz ().tensor ,
87
89
)
88
- else : # if not for training, we just put nontrivial gates
89
- for j in range (0 ,n // 2 - 1 ):
90
+ else : # if not for training, we just put nontrivial gates
91
+ for j in range (0 , n // 2 - 1 ):
90
92
dis = j + 1
91
- for i in range (0 ,n ):
92
- if structure [j , 1 ]== 1 :
93
- c .cz (i , (i + dis ) % n )
93
+ for i in range (0 , n ):
94
+ if structure [j , 1 ] == 1 :
95
+ c .cz (i , (i + dis ) % n )
94
96
95
- for i in range (0 ,n // 2 ):
96
- if structure [j , 1 ]== 1 :
97
- c .cz (i , i + n // 2 )
97
+ for i in range (0 , n // 2 ):
98
+ if structure [j , 1 ] == 1 :
99
+ c .cz (i , i + n // 2 )
98
100
99
101
return c
100
102
103
+
101
104
def hybrid_vqe (structure , paramq , preprocess = "direct" ):
102
105
"""_summary_
103
106
@@ -118,6 +121,7 @@ def hybrid_vqe(structure, paramq, preprocess="direct"):
118
121
c = hybrid_ansatz (structure , paramq , preprocess )
119
122
return tc .templates .measurements .operator_expectation (c , hamiltonian )
120
123
124
+
121
125
def sampling_from_structure (structures , batch = 1 ):
122
126
ch = structures .shape [- 1 ]
123
127
prob = K .softmax (K .real (structures ), axis = - 1 )
@@ -137,7 +141,7 @@ def best_from_structure(structures):
137
141
138
142
139
143
def nmf_gradient (structures , oh ):
140
- """ compute the Monte Carlo gradient with respect of naive mean-field probabilistic model
144
+ """compute the Monte Carlo gradient with respect of naive mean-field probabilistic model
141
145
142
146
Parameters
143
147
----------
@@ -166,21 +170,25 @@ def nmf_gradient(structures, oh):
166
170
indices ,
167
171
tf .ones ([structures .shape [0 ]], dtype = ctype ),
168
172
)
169
- ) # in oh : 1-p, not in oh : -p
173
+ ) # in oh : 1-p, not in oh : -p
174
+
170
175
171
176
# vmap for a batch of structures
172
- nmf_gradient_vmap = K .jit (
173
- K .vmap (nmf_gradient , vectorized_argnums = 1 ))
177
+ nmf_gradient_vmap = K .jit (K .vmap (nmf_gradient , vectorized_argnums = 1 ))
174
178
175
179
# vvag for a batch of structures
176
180
vvag_hybrid = K .jit (
177
181
K .vectorized_value_and_grad (hybrid_vqe , vectorized_argnums = (0 ,), argnums = (1 ,)),
178
- static_argnums = (2 ,))
182
+ static_argnums = (2 ,),
183
+ )
184
+
179
185
180
- def train_hybrid (stddev = 0.05 , lr = None , epochs = 2000 , debug_step = 50 , batch = 256 , verbose = False ):
186
+ def train_hybrid (
187
+ stddev = 0.05 , lr = None , epochs = 2000 , debug_step = 50 , batch = 256 , verbose = False
188
+ ):
181
189
# params = K.implicit_randn([n//2, 2], stddev=stddev)
182
- params = K .ones ([n // 2 , 2 ], dtype = float )
183
- paramq = K .implicit_randn ([nlayersq , n , 3 ], stddev = stddev ) * 2 * np .pi
190
+ params = K .ones ([n // 2 , 2 ], dtype = float )
191
+ paramq = K .implicit_randn ([nlayersq , n , 3 ], stddev = stddev ) * 2 * np .pi
184
192
if lr is None :
185
193
lr = tf .keras .optimizers .schedules .ExponentialDecay (0.6 , 100 , 0.8 )
186
194
structure_opt = K .optimizer (tf .keras .optimizers .Adam (lr ))
@@ -197,7 +205,7 @@ def train_hybrid(stddev=0.05, lr=None, epochs=2000, debug_step=50, batch=256, ve
197
205
vs , gq = vvag_hybrid (batched_stucture , paramq , "direct" )
198
206
loss_history .append (np .min (vs ))
199
207
gq = gq [0 ]
200
- avcost = K .mean (vs ) # average cost of the batch
208
+ avcost = K .mean (vs ) # average cost of the batch
201
209
gs = nmf_gradient_vmap (params , batched_stucture ) # \nabla lnp
202
210
gs = K .mean (K .reshape (vs - avcost2 , [- 1 , 1 , 1 ]) * gs , axis = 0 )
203
211
# avcost2 is averaged cost in the last epoch
@@ -214,15 +222,14 @@ def train_hybrid(stddev=0.05, lr=None, epochs=2000, debug_step=50, batch=256, ve
214
222
)
215
223
216
224
# max over choices, min over layers and qubits
217
- minp = tf .math .reduce_min (tf .math .reduce_max (tf .math .softmax (params ), axis = - 1 ))
225
+ minp = tf .math .reduce_min (
226
+ tf .math .reduce_max (tf .math .softmax (params ), axis = - 1 )
227
+ )
218
228
if minp > 0.5 :
219
229
print ("probability converged" )
220
230
221
231
if verbose :
222
- print (
223
- "strcuture parameter: \n " ,
224
- params .numpy ()
225
- )
232
+ print ("strcuture parameter: \n " , params .numpy ())
226
233
227
234
cand_preset = best_from_structure (params )
228
235
print (cand_preset )
@@ -232,6 +239,8 @@ def train_hybrid(stddev=0.05, lr=None, epochs=2000, debug_step=50, batch=256, ve
232
239
return hybrid_vqe (params , paramq , "most" ), params , paramq , loss_history
233
240
234
241
235
- print ('Train hybrid.' )
236
- ee , params , paramq , loss_history = train_hybrid (epochs = epochs , batch = batch , verbose = True )
237
- print ('Energy:' , ee )
242
+ print ("Train hybrid." )
243
+ ee , params , paramq , loss_history = train_hybrid (
244
+ epochs = epochs , batch = batch , verbose = True
245
+ )
246
+ print ("Energy:" , ee )
0 commit comments