@@ -200,12 +200,12 @@ def p_expressions(self, p):
200200 def p_functioncall (self , p ):
201201 '''statement : functionsignature params SEMICOLON
202202 '''
203- p [0 ] = ('functioncall' , {'name' :p [1 ], 'arguments ' :p [2 ]})
203+ p [0 ] = ('functioncall' , {'type' : 'function' , ' name' :p [1 ], 'qargs ' :p [2 ]})
204204
205205 def p_functioncall_global (self , p ):
206206 '''statement : functionsignature indexedparams SEMICOLON
207207 '''
208- p [0 ] = ('functioncall' , {'name' :p [1 ], 'arguments ' :p [2 ]})
208+ p [0 ] = ('functioncall' , {'type' : 'function' , ' name' :p [1 ], 'qargs ' :p [2 ]})
209209
210210 def p_version (self , p ):
211211 '''globalstatement : VERSION NUMBER SEMICOLON
@@ -245,14 +245,14 @@ def p_measure(self, p):
245245 | ID LARRAY NUMBER RARRAY ASSIGN MEASURE ID LARRAY NUMBER RARRAY SEMICOLON
246246 '''
247247 if len (p ) == 5 :
248- p [0 ] = ('measure' , p [4 ], p [1 ])
248+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ p [4 ]], 'store' : p [1 ]} )
249249 elif len (p ) == 8 :
250250 if p [2 ] == '[' :
251- p [0 ] = ('measure' , p [7 ], (p [1 ], p [3 ]))
251+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ p [7 ]], 'store' : (p [1 ], p [3 ])} )
252252 else :
253- p [0 ] = ('measure' , (p [4 ], p [6 ]), p [1 ])
253+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ (p [4 ], p [6 ])], 'store' : p [1 ]} )
254254 else :
255- p [0 ] = ('measure' , (p [7 ], p [9 ]), (p [1 ], p [3 ]))
255+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ (p [7 ], p [9 ])], 'store' : (p [1 ], p [3 ])} )
256256 #
257257 #NOTE: The measurement tuples are: (Qubit to Measure, Classical Register to Store)
258258 def p_measure_old (self , p ):
@@ -262,14 +262,14 @@ def p_measure_old(self, p):
262262 | MEASURE ID LARRAY NUMBER RARRAY ASSIGNOLD ID LARRAY NUMBER RARRAY SEMICOLON
263263 '''
264264 if len (p ) == 5 :
265- p [0 ] = ('measure' , p [2 ], p [4 ])
265+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ p [2 ]], 'store' : p [4 ]} )
266266 elif len (p ) == 8 :
267267 if p [3 ] == '[' :
268- p [0 ] = ('measure' , (p [2 ], p [4 ]), p [7 ])
268+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ (p [2 ], p [4 ])], 'store' : p [7 ]} )
269269 else :
270- p [0 ] = ('measure' , p [2 ], (p [4 ], p [6 ]))
270+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ p [2 ]], 'store' : (p [4 ], p [6 ])} )
271271 else :
272- p [0 ] = ('measure' , (p [2 ], p [4 ]), (p [7 ], p [9 ]))
272+ p [0 ] = ('measure' , { 'type' : 'measure' , 'qargs' :[ (p [2 ], p [4 ])], 'store' : (p [7 ], p [9 ])} )
273273
274274
275275 def p_statements (self , p ):
@@ -341,16 +341,7 @@ def __init__(self, main_file: str, source_dirs: List[str]):
341341 self ._parse_file (cur_file )
342342 self .compiled_operations = self ._final_compile ()
343343
344- def _get_include_tree (self , cur_includes_stack : List [str ], overall_includes : List [str ], source_dirs : List [str ]):
345- current_file = cur_includes_stack [- 1 ]
346- cur_includes = self ._extract_includes (current_file , source_dirs )
347- for cur_include in cur_includes :
348- assert not cur_include in cur_includes_stack , f"There is a circular dependency with { cur_include } ."
349- self ._get_include_tree (cur_includes_stack + [cur_include ], overall_includes , source_dirs )
350- overall_includes .append (current_file )
351- return
352-
353- def _extract_includes (self , file_path : str , source_dirs : List [str ]):
344+ def _find_file (self , file_path , source_dirs ):
354345 if not os .path .exists (file_path ):
355346 found = False
356347 for cur_source_dir in source_dirs :
@@ -360,6 +351,19 @@ def _extract_includes(self, file_path: str, source_dirs: List[str]):
360351 found = True
361352 break
362353 assert found , f"Could not find file { file_path } "
354+ return file_path
355+
356+ def _get_include_tree (self , cur_includes_stack : List [str ], overall_includes : List [str ], source_dirs : List [str ]):
357+ current_file = cur_includes_stack [- 1 ]
358+ cur_includes = self ._extract_includes (current_file , source_dirs )
359+ for cur_include in cur_includes :
360+ assert not cur_include in cur_includes_stack , f"There is a circular dependency with { cur_include } ."
361+ self ._get_include_tree (cur_includes_stack + [cur_include ], overall_includes , source_dirs )
362+ overall_includes .append (self ._find_file (current_file , source_dirs ))
363+ return
364+
365+ def _extract_includes (self , file_path : str , source_dirs : List [str ]):
366+ file_path = self ._find_file (file_path , source_dirs )
363367 #################
364368 lines = self ._open_file_strip_comments (file_path )
365369 lines = "" .join (lines ).replace ('\n ' ,'' ).split (';' )
@@ -402,6 +406,8 @@ def _parse_file(self, file_path: str):
402406 self ._bits .append ((statement [1 ], statement [2 ]))
403407 elif statement [0 ] == 'functioncall' :
404408 self ._operations .append (statement [1 ])
409+ elif statement [0 ] == 'measure' :
410+ self ._operations .append (statement [1 ])
405411
406412 def _eval_expression (self , expr , wildcards ):
407413 if isinstance (expr , (int , float )):
@@ -460,18 +466,18 @@ def _replace_func_with_arguments(self, func_name, func_inputs, func_outputs):
460466 for cur_func in self ._gate_defs [func_name ]['function' ]:
461467 #Basically iterating over potential ctrl/negctrl etc...
462468 new_func = {'name' : self ._evaluate_func_signature (cur_func [1 ]['name' ],input_wildcards ),
463- 'arguments ' : [output_wildcards [x ] for x in cur_func [1 ]['arguments ' ]]}
469+ 'qargs ' : [output_wildcards [x ] for x in cur_func [1 ]['qargs ' ]]}
464470 sub_func .append (new_func )
465471 return sub_func
466472
467473
468474 def _eval_func (self , dict_operation ):
469475 if len (dict_operation ['name' ]) == 1 :
470476 if dict_operation ['name' ][0 ][0 ] == 'U' :
471- return [{'name' : [(dict_operation ['name' ][0 ][0 ], dict_operation ['name' ][0 ][1 ])], 'arguments ' : dict_operation ['arguments ' ]}]
477+ return [{'type' : 'function' , ' name' : [(dict_operation ['name' ][0 ][0 ], dict_operation ['name' ][0 ][1 ])], 'qargs ' : dict_operation ['qargs ' ]}]
472478 else :
473479 assert dict_operation ['name' ][0 ][0 ] in self ._gate_defs , f"The gate operation { dict_operation ['name' ][0 ][0 ]} is undefined."
474- temp_func_list = self ._replace_func_with_arguments (* dict_operation ['name' ][0 ], dict_operation ['arguments ' ])
480+ temp_func_list = self ._replace_func_with_arguments (* dict_operation ['name' ][0 ], dict_operation ['qargs ' ])
475481 ret_list = []
476482 for cur_func in temp_func_list :
477483 ret_list += self ._eval_func (cur_func )
@@ -495,15 +501,15 @@ def _eval_func(self, dict_operation):
495501 else :
496502 assert cur_func [0 ] in self ._gate_defs , f"Function { cur_func [0 ]} is undefined."
497503 assert len (self ._gate_defs [cur_func [0 ]]['output_args' ]) == 1 , f"The function { cur_func [0 ]} is not a single-qubit unitary!"
498- temp_func_list = self ._replace_func_with_arguments (* cur_func , dict_operation ['arguments ' ])
504+ temp_func_list = self ._replace_func_with_arguments (* cur_func , dict_operation ['qargs ' ])
499505 func_sign_args = []
500506 for cur_func in temp_func_list :
501507 func_sign_args += self ._eval_func (cur_func )
502508 ret_list = []
503509 for cur_func in func_sign_args :
504510 le_list = [x for x in new_sign_list ]
505511 le_list [found_ind ] = cur_func ['name' ][0 ]
506- ret_list .append ({'name' : le_list , 'arguments ' : dict_operation ['arguments ' ]})
512+ ret_list .append ({'type' : 'function' , ' name' : le_list , 'qargs ' : dict_operation ['qargs ' ]})
507513
508514 return ret_list
509515
@@ -523,15 +529,26 @@ def _final_compile(self):
523529 #Process operations
524530 ops = []
525531 for cur_op in self ._operations :
526- ops += self ._eval_func (cur_op )
532+ if cur_op ['type' ] == 'function' :
533+ ops += self ._eval_func (cur_op )
534+ elif cur_op ['type' ] == 'measure' :
535+ ops .append (cur_op )
527536 #Check qubit registers are valid
528537 for cur_op in ops :
529- for cur_qubit_arg in cur_op ['arguments ' ]:
538+ for cur_qubit_arg in cur_op ['qargs ' ]:
530539 if isinstance (cur_qubit_arg , (list , tuple )):
531540 assert cur_qubit_arg [1 ] < qubit_reg_offset_and_size [cur_qubit_arg [0 ]][1 ], f"Index of qubit { cur_qubit_arg [0 ]} [{ cur_qubit_arg [1 ]} ] exceeds register size of { qubit_reg_offset_and_size [cur_qubit_arg [0 ]][1 ]} ."
541+ # if cur_op['type'] == 'measure':
542+ # if isinstance(cur_op['qubit'], (list, tuple)):
543+ # assert cur_op['qubit'][1] < qubit_reg_offset_and_size[cur_op['qubit'][0]][1], f"Index of qubit {cur_op['qubit'][0]}[{cur_op['qubit'][1]}] exceeds register size of {qubit_reg_offset_and_size[cur_op['qubit'][0]][1]}."
544+ #TODO: Validate classical register sizes as well...
545+ # if isinstance(cur_op['store'], (list, tuple)):
546+ # assert cur_op['store'][1] < qubit_reg_offset_and_size[cur_op['store'][0]][1], f"Index of qubit {cur_op['store'][0]}[{cur_op['store'][1]}] exceeds register size of {qubit_reg_offset_and_size[cur_op['store'][0]][1]}."
547+
532548 #Note that the format of ops is a list of gates where each element is a dictionary with keys:
533549 # name - a list of controls with exactly one unitary in the list
534550 # arguments - the target qubits upon which to apply the controlled unitary gates
551+ #Except if it's a measure type, in which case it has 'qubit' and 'store' keys for the qubit and classical registers respectively.
535552 return ops
536553
537554 def get_axis_angle_from_unitary (self , unitary_angles ):
@@ -602,7 +619,7 @@ def plot(self):
602619 for op_ind ,cur_op in enumerate (self .compiled_operations ):
603620 cur_col = leCols [op_ind % len (leCols )]
604621 cur_qubit_indices = []
605- for m ,cur_qubit in enumerate (cur_op ['arguments ' ]):
622+ for m ,cur_qubit in enumerate (cur_op ['qargs ' ]):
606623 if isinstance (cur_qubit , tuple ):
607624 cur_qubit_indices .append (self ._qubit_reg_offset_and_size [cur_qubit [0 ]][0 ] + cur_qubit [1 ])
608625 else :
@@ -616,7 +633,9 @@ def plot(self):
616633
617634 for m ,x in enumerate (cur_qubit_indices ):
618635 qubit_positions [x ] = cur_pos
619- if isinstance (cur_op ['name' ][m ], tuple ):
636+ if cur_op ['type' ] == 'measure' :
637+ self ._plot_gate (ax , qubit_positions [x ], x , '∅' , cur_col )
638+ elif isinstance (cur_op ['name' ][m ], tuple ):
620639 if cur_op ['name' ][m ][0 ] == 'U' :
621640 axis , angle = self .get_axis_angle_from_unitary (cur_op ['name' ][m ][1 ])
622641 self ._plot_gate (ax , qubit_positions [x ], x , self .normalise_name (axis , angle ), cur_col )
@@ -632,7 +651,7 @@ def plot(self):
632651 a = 0
633652
634653
635- poqasm = ParserOpenQASM ('qpe.qasm' ,[])
636- poqasm .plot ()
637- plt .show ()
638- a = 0
654+ # poqasm = ParserOpenQASM('qpe.qasm',[])
655+ # poqasm.plot()
656+ # plt.show()
657+ # a=0
0 commit comments