Skip to content

Commit 733e967

Browse files
authored
Update hello quantum game engine
- added lines describing y measurement outputs - minor improvements
1 parent fda30ac commit 733e967

File tree

1 file changed

+72
-36
lines changed

1 file changed

+72
-36
lines changed

games/game_engines/hello_quantum.py

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from qiskit import IBMQ
21
from qiskit import BasicAer as Aer
32
from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
43
from qiskit import execute
@@ -8,12 +7,7 @@
87
from matplotlib.patches import Circle, Rectangle
98
import copy
109
from ipywidgets import widgets
11-
from IPython.display import display, clear_output
12-
13-
try:
14-
IBMQ.load_accounts()
15-
except:
16-
pass
10+
from IPython.display import display, clear_output
1711

1812
class run_game():
1913
# Implements a puzzle, which is defined by the given inputs.
@@ -43,7 +37,9 @@ def __init__(self,initialize, success_condition, allowed_gates, vi, qubit_names,
4337
shots=1024
4438
Number of shots used to to calculate expectation values.
4539
mode='circle'
46-
Either the standard 'Hello Quantum' visualization can be used (with mode='circle') or the alternative line based one (mode='line').
40+
Either the standard 'Hello Quantum' visualization can be used (with mode='circle'), or the extended one (mode='y') or the alternative line based one (mode='line').
41+
y_boxes = False
42+
Whether to show expectation values involving y.
4743
verbose=False
4844
"""
4945

@@ -79,6 +75,9 @@ def get_success(required_gates):
7975
for gate in required_gates[qubit]:
8076
success = success and (required_gates[qubit][gate]==0)
8177
return success
78+
79+
def show_circuit():
80+
gates = get_total_gate_list
8281

8382
def get_command(gate,qubit):
8483
# For a given gate and qubit, return the string describing the corresoinding Qiskit string.
@@ -96,6 +95,9 @@ def get_command(gate,qubit):
9695
elif gate in ['ry(pi/4)','ry(-pi/4)']:
9796
real_command = 'grid.qc.ry('+'-'*(gate=='ry(-pi/4)')+'np.pi/4,grid.qr['+qubit+'])'
9897
clean_command = 'qc.ry('+'-'*(gate=='ry(-pi/4)')+'np.pi/4,'+qubit_name+')'
98+
elif gate in ['rx(pi/4)','rx(-pi/4)']:
99+
real_command = 'grid.qc.rx('+'-'*(gate=='rx(-pi/4)')+'np.pi/4,grid.qr['+qubit+'])'
100+
clean_command = 'qc.rx('+'-'*(gate=='rx(-pi/4)')+'np.pi/4,'+qubit_name+')'
99101
elif gate in ['cz','cx','swap']:
100102
real_command = 'grid.qc.'+gate+'(grid.qr['+'0'*(qubit=='1')+'1'*(qubit=='0')+'],grid.qr['+qubit+'])'
101103
clean_command = 'qc.'+gate+'('+other_name+','+qubit_name+')'
@@ -105,7 +107,10 @@ def get_command(gate,qubit):
105107
bloch = [None]
106108

107109
# set up initial state and figure
108-
grid = pauli_grid(backend=backend,shots=shots,mode=mode)
110+
if mode=='y':
111+
grid = pauli_grid(backend=backend,shots=shots,mode='circle',y_boxes=True)
112+
else:
113+
grid = pauli_grid(backend=backend,shots=shots,mode=mode)
109114
for gate in initialize:
110115
eval( get_command(gate[0],gate[1])[0] )
111116

@@ -147,8 +152,8 @@ def get_command(gate,qubit):
147152

148153
boxes = widgets.VBox([gate,qubit,action])
149154
display(boxes)
150-
if vi[1]:
151-
print('\nYour quantum program so far\n')
155+
if qubit_names=={'0':'q[0]', '1':'q[1]'}:
156+
print('\nYour quantum program so far:\n\n q = QuantumRegister(2)\n b = ClassicalRegister(2)\n qc = QuantumCircuit(q,b)\n')
152157
self.program = []
153158

154159
def given_gate(a):
@@ -202,8 +207,8 @@ def given_action(c):
202207
else:
203208
command = get_command(q_gate,q01)
204209
eval(command[0])
205-
if vi[1]:
206-
print(command[1])
210+
if qubit_names in [{'0':'q[0]', '1':'q[1]'},{'0':'A', '1':'B'}]:
211+
print(' ' + command[1])
207212
self.program.append( command[1] )
208213
if required_gates[q01][gate.value]>0:
209214
required_gates[q01][gate.value] -= 1
@@ -225,24 +230,41 @@ def given_action(c):
225230
qubit.observe(given_qubit)
226231
action.observe(given_action)
227232

233+
def get_circuit(puzzle):
234+
235+
q = QuantumRegister(2,'q')
236+
b = ClassicalRegister(2,'b')
237+
qc = QuantumCircuit(q,b)
238+
239+
for line in puzzle.program:
240+
eval(line)
228241

242+
return qc
243+
229244
class pauli_grid():
230245
# Allows a quantum circuit to be created, modified and implemented, and visualizes the output in the style of 'Hello Quantum'.
231246

232-
def __init__(self,backend=Aer.get_backend('qasm_simulator'),shots=1024,mode='circle'):
247+
def __init__(self,backend=Aer.get_backend('qasm_simulator'),shots=1024,mode='circle',y_boxes=False):
233248
"""
234249
backend=Aer.get_backend('qasm_simulator')
235250
Backend to be used by Qiskit to calculate expectation values (defaults to local simulator).
236251
shots=1024
237252
Number of shots used to to calculate expectation values.
238253
mode='circle'
239-
Either the standard 'Hello Quantum' visualization can be used (with mode='circle') or the alternative line based one (mode='line').
254+
Either the standard 'Hello Quantum' visualization can be used (with mode='circle') or the alternative line based one (mode='line').
255+
y_boxes=True
256+
Whether to display full grid that includes Y expectation values.
240257
"""
241258

242259
self.backend = backend
243260
self.shots = shots
244-
245-
self.box = {'ZI':(-1, 2),'XI':(-2, 3),'IZ':( 1, 2),'IX':( 2, 3),'ZZ':( 0, 3),'ZX':( 1, 4),'XZ':(-1, 4),'XX':( 0, 5)}
261+
262+
self.y_boxes = y_boxes
263+
if self.y_boxes:
264+
self.box = {'ZI':(-1, 2),'XI':(-3, 4),'IZ':( 1, 2),'IX':( 3, 4),'ZZ':( 0, 3),'ZX':( 2, 5),'XZ':(-2, 5),'XX':( 0, 7),
265+
'YY':(0,5), 'YI':(-2,3), 'IY':(2,3), 'YZ':(-1,4), 'ZY':(1,4), 'YX':(1,6), 'XY':(-1,6) }
266+
else:
267+
self.box = {'ZI':(-1, 2),'XI':(-2, 3),'IZ':( 1, 2),'IX':( 2, 3),'ZZ':( 0, 3),'ZX':( 1, 4),'XZ':(-1, 4),'XX':( 0, 5)}
246268

247269
self.rho = {}
248270
for pauli in self.box:
@@ -278,51 +300,62 @@ def __init__(self,backend=Aer.get_backend('qasm_simulator'),shots=1024,mode='cir
278300

279301

280302
def get_rho(self):
281-
# Runs the circuit specified by self.qc and determines the expectation values for 'ZI', 'IZ', 'ZZ', 'XI', 'IX', 'XX', 'ZX' and 'XZ'.
303+
# Runs the circuit specified by self.qc and determines the expectation values for 'ZI', 'IZ', 'ZZ', 'XI', 'IX', 'XX', 'ZX' and 'XZ' (and the ones with Ys too if needed).
304+
305+
if self.y_boxes:
306+
corr = ['ZZ','ZX','XZ','XX','YY','YX','YZ','XY','ZY']
307+
ps = ['X','Y','Z']
308+
else:
309+
corr = ['ZZ','ZX','XZ','XX']
310+
ps = ['X','Z']
282311

283-
bases = ['ZZ','ZX','XZ','XX']
284312
results = {}
285-
for basis in bases:
313+
for basis in corr:
286314
temp_qc = copy.deepcopy(self.qc)
287315
for j in range(2):
288316
if basis[j]=='X':
289317
temp_qc.h(self.qr[j])
318+
elif basis[j]=='Y':
319+
temp_qc.sdg(self.qr[j])
320+
temp_qc.h(self.qr[j])
290321
temp_qc.barrier(self.qr)
291322
temp_qc.measure(self.qr,self.cr)
292323
job = execute(temp_qc, backend=self.backend, shots=self.shots)
293324
results[basis] = job.result().get_counts()
294325
for string in results[basis]:
295326
results[basis][string] = results[basis][string]/self.shots
296-
327+
297328
prob = {}
298329
# prob of expectation value -1 for single qubit observables
299330
for j in range(2):
300-
for p in ['X','Z']:
331+
332+
for p in ps:
301333
pauli = {}
302-
for pp in 'IXZ':
334+
for pp in ['I']+ps:
303335
pauli[pp] = (j==1)*pp + p + (j==0)*pp
304336
prob[pauli['I']] = 0
305-
for basis in [pauli['X'],pauli['Z']]:
337+
for ppp in ps:
338+
basis = pauli[ppp]
306339
for string in results[basis]:
307340
if string[(j+1)%2]=='1':
308-
prob[pauli['I']] += results[basis][string]/2
341+
prob[pauli['I']] += results[basis][string]/(2+self.y_boxes)
342+
309343
# prob of expectation value -1 for two qubit observables
310-
for basis in ['ZZ','ZX','XZ','XX']:
344+
for basis in corr:
311345
prob[basis] = 0
312346
for string in results[basis]:
313347
if string[0]!=string[1]:
314348
prob[basis] += results[basis][string]
315349

316350
for pauli in prob:
317351
self.rho[pauli] = 1-2*prob[pauli]
318-
319352

320353
def update_grid(self,rho=None,labels=False,bloch=None,hidden=[],qubit=True,corr=True,message=""):
321354
"""
322355
rho = None
323356
Dictionary of expectation values for 'ZI', 'IZ', 'ZZ', 'XI', 'IX', 'XX', 'ZX' and 'XZ'. If supplied, this will be visualized instead of the results of running self.qc.
324-
labels = None
325-
Dictionary of strings for 'ZI', 'IZ', 'ZZ', 'XI', 'IX', 'XX', 'ZX' and 'XZ' that are printed in the corresponding boxes.
357+
labels = False
358+
Determines whether basis labels are printed in the corresponding boxes.
326359
bloch = None
327360
If a qubit name is supplied, and if mode='line', Bloch circles are displayed for this qubit
328361
hidden = []
@@ -387,7 +420,7 @@ def add_line(line,pauli_pos,pauli):
387420
self.lines[pauli]['w'] = plt.plot( [a[0],b[0]], [a[1],b[1]], color=(1.0,1.0,1.0), lw=lw )
388421
self.lines[pauli]['b'] = plt.plot( [b[0],c[0]], [b[1],c[1]], color=(0.0,0.0,0.0), lw=lw )
389422
return coord
390-
423+
391424
l = 0.9 # line length
392425
r = 0.6 # circle radius
393426
L = 0.98*np.sqrt(2) # box height and width
@@ -442,11 +475,14 @@ def add_line(line,pauli_pos,pauli):
442475
self.bottom.set_text(message)
443476

444477
if labels:
445-
for pauli in box:
446-
plt.text(self.box[pauli][0]-0.05,self.box[pauli][1]-0.85, pauli)
478+
for pauli in self.box:
479+
plt.text(self.box[pauli][0]-0.18,self.box[pauli][1]-0.85, pauli)
447480

448-
self.ax.set_xlim([-3,3])
449-
self.ax.set_ylim([0,6])
481+
if self.y_boxes:
482+
self.ax.set_xlim([-4,4])
483+
self.ax.set_ylim([0,8])
484+
else:
485+
self.ax.set_xlim([-3,3])
486+
self.ax.set_ylim([0,6])
450487

451-
self.fig.canvas.draw()
452-
488+
self.fig.canvas.draw()

0 commit comments

Comments
 (0)