Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

📚 The CoCalc Library - books, templates and other resources

132923 views
License: OTHER
1
#!/usr/bin/env python
2
#
3
# Copyright 2019 the original author or authors.
4
#
5
# Licensed under the Apache License, Version 2.0 (the "License");
6
# you may not use this file except in compliance with the License.
7
# You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS,
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
# See the License for the specific language governing permissions and
15
# limitations under the License.
16
#
17
# TODO: Add user interaction:
18
# TODO: - Selecting circuit node with mouse
19
# TODO: - Same gate twice erases (e.g. pressing X key already on an X gate erases it)
20
# TODO: - If gate was rotated, make unrotated (e.g. pressing X on rotated X gate makes X)
21
# TODO: Use NUM_STATE_DIMS everywhere
22
# TODO: Fix weights on network graph
23
# TODO: Create UI component for adjacency matrix
24
# TODO: Use better looking fonts
25
# TODO: Modify NetworkGraph to:
26
# TODO: - move vertices to each's side of the cut
27
# TODO: Make TSP and other demos, including chemistry
28
# TODO: Make displays update during optimization
29
# TODO: Modify optimizer to fit pluggable Aqua framework
30
# TODO: Create network graph component?
31
# TODO: Update QSphere visualization and leverage it here
32
#
33
"""Demonstrate Variational Quantum Eigensolver (VQE) concepts using Qiskit and Pygame"""
34
35
from pygame.locals import *
36
from qiskit import ClassicalRegister
37
from qiskit import execute
38
# from qiskit_aqua.translators.ising import maxcut
39
from .containers import *
40
from .controls.circuit_grid import *
41
from .model.circuit_grid_model import *
42
from .utils.gamepad import *
43
from .utils.states import NUM_QUBITS, NUM_STATE_DIMS
44
from .viz.expectation_grid import ExpectationGrid
45
from .viz.network_graph import NetworkGraph
46
from .controls.adjacency_matrix import AdjacencyMatrix
47
from .controls.button import Button
48
49
WINDOW_SIZE = 1650, 950
50
NUM_OPTIMIZATION_EPOCHS = 1
51
52
53
class VQEPlayground():
54
"""Main object for application"""
55
def __init__(self):
56
self.screen = pygame.display.set_mode(WINDOW_SIZE)
57
self.background = pygame.Surface(self.screen.get_size())
58
self.circuit_grid_model = None
59
self.circuit_grid = None
60
self.top_sprites = None
61
self.right_sprites = None
62
self.expectation_grid = None
63
self.network_graph = None
64
self.adjacency_matrix = None
65
self.optimize_button = None
66
self.circ_viz_dirty = False
67
68
# Optimization state variables, so that the display can update while
69
# the optimizing algorithm is running
70
self.optimization_desired = False
71
self.optimization_initialized = False
72
self.optimized_rotations = None
73
self.cur_optimization_epoch = 0
74
self.cur_rotation_num = 0
75
self.min_distance = None
76
self.rotation_initialized = False
77
self.finished_rotating = True
78
self.rotation_iterations = 0
79
self.proposed_cur_ang_rad = 0
80
self.cur_ang_rad = 0
81
self.frequent_viz_update = True
82
83
def main(self):
84
if not pygame.font: print('Warning, fonts disabled')
85
if not pygame.mixer: print('Warning, sound disabled')
86
87
pygame.init()
88
89
pygame.joystick.init()
90
num_joysticks = pygame.joystick.get_count()
91
92
joystick = False
93
if num_joysticks > 0:
94
joystick = pygame.joystick.Joystick(0)
95
joystick.init()
96
97
self.background = pygame.Surface(self.screen.get_size())
98
self.background = self.background.convert()
99
self.background.fill(WHITE)
100
101
pygame.font.init()
102
103
self.circuit_grid_model = CircuitGridModel(NUM_QUBITS, 21)
104
105
pygame.display.set_caption('VQE Playground')
106
107
self.screen.blit(self.background, (0, 0))
108
pygame.display.flip()
109
110
# Prepare objects
111
clock = pygame.time.Clock()
112
113
self.circuit_grid_model.set_node(0, 0, CircuitGridNode(node_types.Y, np.pi))
114
self.circuit_grid_model.set_node(1, 0, CircuitGridNode(node_types.Y, np.pi))
115
self.circuit_grid_model.set_node(2, 0, CircuitGridNode(node_types.Y, np.pi))
116
self.circuit_grid_model.set_node(3, 0, CircuitGridNode(node_types.Y, np.pi))
117
self.circuit_grid_model.set_node(4, 0, CircuitGridNode(node_types.Y, np.pi))
118
119
self.circuit_grid_model.set_node(1, 1, CircuitGridNode(node_types.X, 0, 0))
120
self.circuit_grid_model.set_node(2, 2, CircuitGridNode(node_types.X, 0, 1))
121
self.circuit_grid_model.set_node(3, 3, CircuitGridNode(node_types.X, 0, 2))
122
self.circuit_grid_model.set_node(4, 4, CircuitGridNode(node_types.X, 0, 3))
123
124
self.circuit_grid_model.set_node(0, 5, CircuitGridNode(node_types.Y, np.pi))
125
self.circuit_grid_model.set_node(1, 5, CircuitGridNode(node_types.Y, np.pi))
126
self.circuit_grid_model.set_node(2, 5, CircuitGridNode(node_types.Y, np.pi))
127
self.circuit_grid_model.set_node(3, 5, CircuitGridNode(node_types.Y, np.pi))
128
self.circuit_grid_model.set_node(4, 5, CircuitGridNode(node_types.Y, np.pi))
129
130
self.circuit_grid_model.set_node(1, 6, CircuitGridNode(node_types.X, 0, 0))
131
self.circuit_grid_model.set_node(2, 7, CircuitGridNode(node_types.X, 0, 1))
132
self.circuit_grid_model.set_node(3, 8, CircuitGridNode(node_types.X, 0, 2))
133
self.circuit_grid_model.set_node(4, 9, CircuitGridNode(node_types.X, 0, 3))
134
135
self.circuit_grid_model.set_node(0, 10, CircuitGridNode(node_types.Y, np.pi))
136
self.circuit_grid_model.set_node(1, 10, CircuitGridNode(node_types.Y, np.pi))
137
self.circuit_grid_model.set_node(2, 10, CircuitGridNode(node_types.Y, np.pi))
138
self.circuit_grid_model.set_node(3, 10, CircuitGridNode(node_types.Y, np.pi))
139
self.circuit_grid_model.set_node(4, 10, CircuitGridNode(node_types.Y, np.pi))
140
141
self.circuit_grid_model.set_node(1, 11, CircuitGridNode(node_types.X, 0, 0))
142
self.circuit_grid_model.set_node(2, 12, CircuitGridNode(node_types.X, 0, 1))
143
self.circuit_grid_model.set_node(3, 13, CircuitGridNode(node_types.X, 0, 2))
144
self.circuit_grid_model.set_node(4, 14, CircuitGridNode(node_types.X, 0, 3))
145
146
self.circuit_grid_model.set_node(0, 15, CircuitGridNode(node_types.Y, np.pi))
147
self.circuit_grid_model.set_node(1, 15, CircuitGridNode(node_types.Y, np.pi))
148
self.circuit_grid_model.set_node(2, 15, CircuitGridNode(node_types.Y, np.pi))
149
self.circuit_grid_model.set_node(3, 15, CircuitGridNode(node_types.Y, np.pi))
150
self.circuit_grid_model.set_node(4, 15, CircuitGridNode(node_types.Y, np.pi))
151
152
self.circuit_grid_model.set_node(1, 16, CircuitGridNode(node_types.X, 0, 0))
153
self.circuit_grid_model.set_node(2, 17, CircuitGridNode(node_types.X, 0, 1))
154
self.circuit_grid_model.set_node(3, 18, CircuitGridNode(node_types.X, 0, 2))
155
self.circuit_grid_model.set_node(4, 19, CircuitGridNode(node_types.X, 0, 3))
156
157
self.circuit_grid_model.set_node(0, 20, CircuitGridNode(node_types.Y, np.pi))
158
self.circuit_grid_model.set_node(1, 20, CircuitGridNode(node_types.Y, np.pi))
159
self.circuit_grid_model.set_node(2, 20, CircuitGridNode(node_types.Y, np.pi))
160
self.circuit_grid_model.set_node(3, 20, CircuitGridNode(node_types.Y, np.pi))
161
self.circuit_grid_model.set_node(4, 20, CircuitGridNode(node_types.Y, np.pi))
162
163
circuit = self.circuit_grid_model.compute_circuit()
164
165
initial_adj_matrix = np.array([
166
[0, 3, 1, 3, 0],
167
[3, 0, 0, 0, 2],
168
[1, 0, 0, 3, 0],
169
[3, 0, 3, 0, 2],
170
[0, 2, 0, 2, 0]
171
])
172
173
# maxcut_op, maxcut_shift = maxcut.get_maxcut_qubitops(initial_adj_matrix)
174
# # print("maxcut_op: ", maxcut_op, ", maxcut_shift: ", maxcut_shift)
175
#
176
# # TODO: Find different approach of calculating and retrieving diagonal
177
# maxcut_op._paulis_to_matrix()
178
# eigenvectors = maxcut_op._dia_matrix
179
180
self.adjacency_matrix = AdjacencyMatrix(950, 10, initial_adj_matrix)
181
self.expectation_grid = ExpectationGrid(circuit,
182
self.adjacency_matrix.adj_matrix_numeric)
183
184
self.network_graph = NetworkGraph(self.adjacency_matrix.adj_matrix_numeric)
185
self.optimize_button = Button("Optimize", 150, 40)
186
187
self.top_sprites = HBox(50, 20, self.network_graph, self.optimize_button)
188
self.right_sprites = VBox(1010, 0, self.expectation_grid)
189
190
self.circuit_grid = CircuitGrid(10, 540, self.circuit_grid_model)
191
self.screen.blit(self.background, (0, 0))
192
193
self.top_sprites.draw(self.screen)
194
self.right_sprites.draw(self.screen)
195
self.circuit_grid.draw(self.screen)
196
self.adjacency_matrix.draw(self.screen)
197
pygame.display.flip()
198
199
gamepad_repeat_delay = 100
200
gamepad_neutral = True
201
gamepad_pressed_timer = 0
202
gamepad_last_update = pygame.time.get_ticks()
203
204
# Main Loop
205
going = True
206
while going:
207
clock.tick(30)
208
209
pygame.time.wait(10)
210
211
if joystick:
212
gamepad_move = False
213
joystick_hat = joystick.get_hat(0)
214
215
if joystick_hat == (0, 0):
216
gamepad_neutral = True
217
gamepad_pressed_timer = 0
218
else:
219
if gamepad_neutral:
220
gamepad_move = True
221
gamepad_neutral = False
222
else:
223
gamepad_pressed_timer += pygame.time.get_ticks() - gamepad_last_update
224
if gamepad_pressed_timer > gamepad_repeat_delay:
225
gamepad_move = True
226
gamepad_pressed_timer -= gamepad_repeat_delay
227
if gamepad_move:
228
if joystick_hat == (-1, 0):
229
self.move_update_circuit_grid_display(MOVE_LEFT)
230
elif joystick_hat == (1, 0):
231
self.move_update_circuit_grid_display(MOVE_RIGHT)
232
elif joystick_hat == (0, 1):
233
self.move_update_circuit_grid_display(MOVE_UP)
234
elif joystick_hat == (0, -1):
235
self.move_update_circuit_grid_display(MOVE_DOWN)
236
gamepad_last_update = pygame.time.get_ticks()
237
238
# Check left thumbstick position
239
# left_thumb_x = joystick.get_axis(0)
240
# left_thumb_y = joystick.get_axis(1)
241
242
# Handle Input Events
243
for event in pygame.event.get():
244
pygame.event.pump()
245
246
# if event.type != MOUSEMOTION:
247
# print("event: ", event)
248
if event.type == QUIT:
249
pygame.quit()
250
print("Quitting VQE Playground")
251
return
252
# going = False
253
254
elif event.type == MOUSEBUTTONDOWN:
255
if self.optimize_button.rect.collidepoint(event.pos):
256
if self.optimize_button.get_enabled():
257
self.optimize_button.set_enabled(False)
258
self.optimization_desired = True
259
else:
260
for idx, picker in enumerate(self.adjacency_matrix.number_pickers_list):
261
if picker.rect.collidepoint(event.pos):
262
self.adjacency_matrix.handle_element_clicked(picker)
263
self.expectation_grid.set_adj_matrix(self.adjacency_matrix.adj_matrix_numeric)
264
self.circ_viz_dirty = True
265
if self.adjacency_matrix.adj_matrix_graph_dirty:
266
self.network_graph.set_adj_matrix(self.adjacency_matrix.adj_matrix_numeric)
267
self.adjacency_matrix.adj_matrix_graph_dirty = False
268
self.expectation_grid.basis_state_dirty = True
269
270
elif event.type == JOYBUTTONDOWN:
271
if event.button == BTN_A:
272
# Place X gate
273
self.circuit_grid.handle_input_x()
274
self.circ_viz_dirty = True
275
elif event.button == BTN_X:
276
# Place Y gate
277
self.circuit_grid.handle_input_y()
278
self.circ_viz_dirty = True
279
elif event.button == BTN_B:
280
# Place Z gate
281
self.circuit_grid.handle_input_z()
282
self.circ_viz_dirty = True
283
elif event.button == BTN_Y:
284
# Place Hadamard gate
285
self.circuit_grid.handle_input_h()
286
self.circ_viz_dirty = True
287
elif event.button == BTN_RIGHT_TRIGGER:
288
# Delete gate
289
self.circuit_grid.handle_input_delete()
290
self.circ_viz_dirty = True
291
elif event.button == BTN_RIGHT_THUMB:
292
# Add or remove a control
293
self.circuit_grid.handle_input_ctrl()
294
self.circ_viz_dirty = True
295
296
elif event.type == JOYAXISMOTION:
297
# print("event: ", event)
298
if event.axis == AXIS_RIGHT_THUMB_X and joystick.get_axis(AXIS_RIGHT_THUMB_X) >= 0.95:
299
self.circuit_grid.handle_input_rotate(np.pi / 8)
300
self.circ_viz_dirty = True
301
if event.axis == AXIS_RIGHT_THUMB_X and joystick.get_axis(AXIS_RIGHT_THUMB_X) <= -0.95:
302
self.circuit_grid.handle_input_rotate(-np.pi / 8)
303
self.circ_viz_dirty = True
304
if event.axis == AXIS_RIGHT_THUMB_Y and joystick.get_axis(AXIS_RIGHT_THUMB_Y) <= -0.95:
305
self.circuit_grid.handle_input_move_ctrl(MOVE_UP)
306
self.circ_viz_dirty = True
307
if event.axis == AXIS_RIGHT_THUMB_Y and joystick.get_axis(AXIS_RIGHT_THUMB_Y) >= 0.95:
308
self.circuit_grid.handle_input_move_ctrl(MOVE_DOWN)
309
self.circ_viz_dirty = True
310
311
elif event.type == KEYDOWN:
312
index_increment = 0
313
if event.key == K_ESCAPE:
314
going = False
315
elif event.key == K_a:
316
self.move_update_circuit_grid_display(MOVE_LEFT)
317
elif event.key == K_d:
318
self.move_update_circuit_grid_display(MOVE_RIGHT)
319
elif event.key == K_w:
320
self.move_update_circuit_grid_display(MOVE_UP)
321
elif event.key == K_s:
322
self.move_update_circuit_grid_display(MOVE_DOWN)
323
elif event.key == K_x:
324
self.circuit_grid.handle_input_x()
325
self.circ_viz_dirty = True
326
elif event.key == K_y:
327
self.circuit_grid.handle_input_y()
328
self.circ_viz_dirty = True
329
elif event.key == K_z:
330
self.circuit_grid.handle_input_z()
331
self.circ_viz_dirty = True
332
elif event.key == K_h:
333
self.circuit_grid.handle_input_h()
334
self.circ_viz_dirty = True
335
elif event.key == K_BACKSLASH:
336
self.circuit_grid.handle_input_delete()
337
self.circ_viz_dirty = True
338
elif event.key == K_c:
339
# Add or remove a control
340
self.circuit_grid.handle_input_ctrl()
341
self.circ_viz_dirty = True
342
elif event.key == K_UP:
343
# Move a control qubit up
344
self.circuit_grid.handle_input_move_ctrl(MOVE_UP)
345
self.circ_viz_dirty = True
346
elif event.key == K_DOWN:
347
# Move a control qubit down
348
self.circuit_grid.handle_input_move_ctrl(MOVE_DOWN)
349
self.circ_viz_dirty = True
350
elif event.key == K_LEFT:
351
# Rotate a gate
352
self.circuit_grid.handle_input_rotate(-np.pi/8)
353
self.circ_viz_dirty = True
354
elif event.key == K_RIGHT:
355
# Rotate a gate
356
self.circuit_grid.handle_input_rotate(np.pi / 8)
357
self.circ_viz_dirty = True
358
elif event.key == K_o:
359
if self.optimize_button.get_enabled():
360
self.optimize_button.set_enabled(False)
361
self.optimization_desired = True
362
363
if self.optimization_desired:
364
if self.cur_optimization_epoch < NUM_OPTIMIZATION_EPOCHS:
365
if not self.optimization_initialized:
366
self.expectation_grid.draw_expectation_grid()
367
rotation_gate_nodes = self.circuit_grid_model.get_rotation_gate_nodes()
368
369
self.optimized_rotations = np.full(len(rotation_gate_nodes), np.pi)
370
self.cur_optimization_epoch = 0
371
self.cur_rotation_num = 0
372
373
rotation_bounds = np.zeros((len(rotation_gate_nodes), 2))
374
375
self.optimization_initialized = True
376
377
self.optimize_rotations(self.expectation_value_objective_function,
378
self.circuit_grid, self.expectation_grid, rotation_gate_nodes)
379
380
# print('opt_rotations: ', self.optimized_rotations)
381
382
cost, basis_state_str = self.expectation_grid.calc_expectation_value()
383
print('cost: ', cost, 'basis_state_str: ', basis_state_str)
384
385
solution = np.zeros(NUM_STATE_DIMS)
386
for idx, char in enumerate(basis_state_str):
387
solution[idx] = int(char)
388
389
# TODO: Uncomment to update display more often?
390
# self.network_graph.set_solution(solution)
391
392
else:
393
self.optimization_initialized = False
394
self.optimization_desired = False
395
self.cur_optimization_epoch = 0
396
self.optimize_button.set_enabled(True)
397
398
# Select top-left node in circuit, regardless of gate type
399
self.circuit_grid.highlight_selected_node(0, 0)
400
401
self.circ_viz_dirty = True
402
print("Finished")
403
# self.network_graph.set_solution(solution)
404
405
if self.expectation_grid.basis_state_dirty:
406
cost, basis_state_str = self.expectation_grid.calc_expectation_value()
407
408
solution = np.zeros(NUM_STATE_DIMS)
409
for idx, char in enumerate(basis_state_str):
410
solution[idx] = int(char)
411
412
self.network_graph.set_solution(solution)
413
414
self.circ_viz_dirty = True
415
self.expectation_grid.basis_state_dirty = False
416
417
if self.circ_viz_dirty:
418
self.update_circ_viz()
419
self.circ_viz_dirty = False
420
421
pygame.quit()
422
423
def optimize_rotations(self, objective_function, circuit_grid, expectation_grid, rotation_gate_nodes):
424
425
move_radians = np.pi / 8
426
427
# For each rotation this will be either 1 or -1, signifying direction of movement
428
unit_direction_array = np.ones(len(self.optimized_rotations))
429
430
self.min_distance = objective_function(circuit_grid, expectation_grid, rotation_gate_nodes)
431
432
# print('self.cur_optimization_epoch: ', self.cur_optimization_epoch)
433
# print('self.cur_rotation_num: ', self.cur_rotation_num)
434
if self.cur_optimization_epoch < NUM_OPTIMIZATION_EPOCHS:
435
if self.cur_rotation_num < len(self.optimized_rotations):
436
if not self.rotation_initialized:
437
self.cur_ang_rad = self.optimized_rotations[self.cur_rotation_num]
438
self.proposed_cur_ang_rad = self.cur_ang_rad
439
440
# Highlight gate being operated on
441
cur_wire_num = rotation_gate_nodes[self.cur_rotation_num].wire_num
442
cur_column_num = rotation_gate_nodes[self.cur_rotation_num].column_num
443
self.circuit_grid.highlight_selected_node(cur_wire_num, cur_column_num)
444
if self.frequent_viz_update:
445
self.circ_viz_dirty = True
446
447
self.rotation_initialized = True
448
449
# Decide whether to increase or decrease angle
450
unit_direction_array[self.cur_rotation_num] = 1
451
if self.cur_ang_rad > np.pi:
452
unit_direction_array[self.cur_rotation_num] = -1
453
self.proposed_cur_ang_rad += move_radians * unit_direction_array[self.cur_rotation_num]
454
if 0.0 <= self.proposed_cur_ang_rad < np.pi * 2 + 0.01:
455
self.optimized_rotations[self.cur_rotation_num] = self.proposed_cur_ang_rad
456
457
temp_distance = objective_function(circuit_grid, expectation_grid, rotation_gate_nodes)
458
if temp_distance > self.min_distance:
459
# Moving in the wrong direction so restore the angle in the array and switch direction
460
self.optimized_rotations[self.cur_rotation_num] = self.cur_ang_rad
461
unit_direction_array[self.cur_rotation_num] *= -1
462
else:
463
# Moving in the right direction so use the proposed angle
464
self.cur_ang_rad = self.proposed_cur_ang_rad
465
self.min_distance = temp_distance
466
467
self.finished_rotating = False
468
self.rotation_iterations = 0
469
470
elif self.rotation_initialized and not self.finished_rotating:
471
self.rotation_iterations += 1
472
self.proposed_cur_ang_rad += move_radians * unit_direction_array[self.cur_rotation_num]
473
if 0.0 <= self.proposed_cur_ang_rad <= np.pi * 2 + 0.01:
474
self.optimized_rotations[self.cur_rotation_num] = self.proposed_cur_ang_rad
475
temp_distance = objective_function(circuit_grid, expectation_grid, rotation_gate_nodes)
476
477
if temp_distance >= self.min_distance: # TODO: Better?
478
# if temp_distance > self.min_distance:
479
# Distance is increasing so restore the angle in the array and leave the loop
480
self.optimized_rotations[self.cur_rotation_num] = self.cur_ang_rad
481
self.finished_rotating = True
482
self.cur_rotation_num += 1
483
self.rotation_initialized = False
484
elif self.rotation_iterations > np.pi * 2 / move_radians:
485
print("Unexpected: self.rotation_iterations: ", self.rotation_iterations)
486
self.finished_rotating = True
487
self.cur_rotation_num += 1
488
self.rotation_initialized = False
489
else:
490
# Distance is not increasing, so use the proposed angle
491
self.cur_ang_rad = self.proposed_cur_ang_rad
492
self.min_distance = temp_distance
493
if self.frequent_viz_update:
494
self.circ_viz_dirty = True
495
else:
496
self.finished_rotating = True
497
self.cur_rotation_num += 1
498
self.rotation_initialized = False
499
500
# self.cur_rotation_num += 1
501
else:
502
self.cur_rotation_num = 0
503
self.cur_optimization_epoch += 1
504
# print('self.min_distance: ', self.min_distance)
505
506
objective_function(circuit_grid, expectation_grid, rotation_gate_nodes)
507
# print('exp_val: ', expectation_grid.calc_expectation_value())
508
509
510
def expectation_value_objective_function(self, circuit_grid,
511
expectation_grid, rotation_gate_nodes):
512
for idx in range(len(rotation_gate_nodes)):
513
circuit_grid.rotate_gate_absolute(rotation_gate_nodes[idx], self.optimized_rotations[idx])
514
expectation_grid.set_circuit(circuit_grid.circuit_grid_model.compute_circuit())
515
cost, basis_state = expectation_grid.calc_expectation_value()
516
517
# print("self.optimized_rotations: ", self.optimized_rotations, ", cost: ", cost, ", basis_state: ", basis_state)
518
return cost
519
520
def update_circ_viz(self):
521
# print("in update_circ_viz")
522
self.screen.blit(self.background, (0, 0))
523
circuit = self.circuit_grid_model.compute_circuit()
524
self.expectation_grid.set_circuit(circuit)
525
self.top_sprites.arrange()
526
self.right_sprites.arrange()
527
self.top_sprites.draw(self.screen)
528
self.right_sprites.draw(self.screen)
529
self.adjacency_matrix.arrange()
530
self.adjacency_matrix.draw(self.screen)
531
self.circuit_grid.draw(self.screen)
532
pygame.display.flip()
533
534
def move_update_circuit_grid_display(self, direction):
535
self.circuit_grid.move_to_adjacent_node(direction)
536
self.circuit_grid.draw(self.screen)
537
pygame.display.flip()
538
539
540
if __name__ == "__main__":
541
VQEPlayground().main()
542
543