@@ -307,39 +307,70 @@ def execute_circuit (batched_circuit):
307307# Get circuit metrics fom the circuit passed in
308308def get_circuit_metrics (qc , qc_size ):
309309
310- # get resource info from cudaq
311- resources = cudaq .estimate_resources (qc [0 ], * qc [1 ])
312- resources_str = str (resources )
310+ # the new code is implemented in CUDA-Q ver 0.13+, if it fails fall back to old code
311+ try :
313312
314- import re
315-
316- # Get total gates (not needed as we use the .count() function)
317- #total_match = re.search(r'Total # of gates:\s*(\d+)', resources_str)
318- #total_gates = int(total_match.group(1)) if total_match else 0
319-
320- total_gates = resources .count ()
321-
322- # the resources object returned is not a dict; need to parse the string to get 2q gates
323- # Get all gate counts that start with 'c' (controlled/2-qubit gates)
324- two_qubit_gates = 0
325- for line in resources_str .split ('\n ' ):
326- match = re .match (r'\s*(c\w+)\s*:\s*(\d+)' , line )
327- if match :
328- two_qubit_gates += int (match .group (2 ))
313+ # get resource info from cudaq
314+ resources = cudaq .estimate_resources (qc [0 ], * qc [1 ])
315+ #resources_str = str(resources)
316+
317+ #print(resources)
318+
319+ # Get total gates (not needed as we use the .count() function)
320+ # import re
321+ # total_match = re.search(r'Total # of gates:\s*(\d+)', resources_str)
322+ # total_gates = int(total_match.group(1)) if total_match else 0
323+
324+ total_gates = resources .count ()
325+
326+ two_qubit_gates = 0
327+ two_qubit_gates += resources .count_controls ('x' , 1 )
328+ two_qubit_gates += resources .count_controls ('y' , 1 )
329+ two_qubit_gates += resources .count_controls ('z' , 1 )
330+ two_qubit_gates += resources .count_controls ('r1' , 1 )
331+ two_qubit_gates += resources .count_controls ('rx' , 1 )
332+ two_qubit_gates += resources .count_controls ('ry' , 1 )
333+ two_qubit_gates += resources .count_controls ('rz' , 1 )
334+
335+ #print(f"... depth = {resources.count_depth()}") # doesn't exist yet
336+ #print(f"Total: {total_gates}, 2-qubit: {two_qubit_gates}")
329337
330- # print(f"Total: {total_gates}, 2-qubit: {two_qubit_gates}")
338+ # obtain an estimate of circuit depth
339+ qc_depth = estimate_depth (qc_size , total_gates , two_qubit_gates )
340+ #print(qc_depth)
341+
342+ # this exact computation is not used, currently, as it is slow
343+ #qc_depth = compute_circuit_depth(qc[0](*qc[1]))
344+ #print(qc_depth)
345+
346+ qc_xi = two_qubit_gates / max (total_gates , 1 )
347+ qc_n2q = two_qubit_gates
348+
349+ # not currently used
350+ qc_count_ops = total_gates
351+
352+ # this is used for CUDA-Q versions 0.12 or earlier
353+ except :
354+
355+ # compute depth and gate counts based on number of qubits
356+ qc_depth = 4 * pow (qc_size , 2 )
331357
332- qc_depth = estimate_depth (qc_size , total_gates , two_qubit_gates )
333- #print(qc_depth)
334-
335- qc_xi = two_qubit_gates / max (total_gates , 1 )
336- qc_n2q = two_qubit_gates
337-
338- qc_count_ops = total_gates
358+ qc_xi = 0.5
339359
360+ qc_n2q = int (qc_depth * 0.75 )
361+ qc_tr_depth = qc_depth
362+ qc_tr_size = qc_size
363+ qc_tr_xi = qc_xi
364+ qc_tr_n2q = qc_n2q
365+
366+ # not currently used
367+ qc_count_ops = qc_depth
368+
340369 return qc_depth , qc_size , qc_count_ops , qc_xi , qc_n2q
341370
342- # Make estimate of circuit depth using heuristic approach
371+
372+ # Make estimate of circuit depth using heuristic approach; depth not provided by cudaq
373+ # This is somewhat simplistic, but we have not found better solution
343374def estimate_depth (num_qubits , total_gates , two_qubit_gates ):
344375 N = num_qubits
345376 K = two_qubit_gates
@@ -348,11 +379,23 @@ def estimate_depth(num_qubits, total_gates, two_qubit_gates):
348379 # Theoretical minimum (perfect packing - 2Qs and 1Qs and MZ)
349380 depth_min = math .ceil (2 * K / N ) + math .ceil (S / N ) + 1
350381
351- # Realistic estimate (assume 40% packing efficiency)
352- depth_estimate = depth_min * 2.5
382+ # Theoretical maximum, sparse distribution
383+ depth_max = K + S + 1
384+
385+ # use xi factor as proxy for level of sparseness in layout (larger = sparser)
386+ qc_xi = two_qubit_gates / max (total_gates , 1 )
387+ depth_range = depth_max - depth_min
388+ depth_estimate = math .ceil (depth_min + depth_range * qc_xi )
389+
390+ #print(f" ... min = {depth_min}, max = {depth_max}, depth = {depth_estimate}")
391+
392+ # Realistic estimate (assume 40% packing efficiency) (used with min only)
393+ # depth_estimate = depth_min * 2.5
353394
354395 return depth_estimate
396+
355397
398+ #########################################################################
356399
357400# klunky way to know the last group executed
358401last_group = None
@@ -530,73 +573,82 @@ def execute_circuit_immed (circuit: list, num_shots: int):
530573 if verbose :
531574 print (f'... execute_circuit_immed({ circuit } , { num_shots } )' )
532575
533- #active_circuit = copy.copy(batched_circuit)
534- #active_circuit["launch_time"] = time.time()
535-
536- #num_shots = batched_circuit["shots"]
537-
538- # Initiate execution
539- #circuit = batched_circuit["qc"]
540-
541- # create a pseudo-job to perform metrics processing upon return
542- job = Job ()
543-
544- # draw the circuit, but only for debugging
545- # print(cudaq.draw(circuit[0], *circuit[1]))
546-
547- ts = time .time ()
548-
549- # call sample() on circuit with its list of arguments
550- if verbose : print (f"... during exec, noise model is: { noise } " )
551- if noise is None :
552- if verbose : print ("... executing without noise" )
553- result = cudaq .sample (circuit [0 ], * circuit [1 ], shots_count = num_shots )
554- else :
555- if verbose : print ("... executing WITH noise" )
556- result = cudaq .sample (circuit [0 ], * circuit [1 ], shots_count = num_shots , noise_model = noise )
557-
558- # control results print at benchmark level
559- #if verbose: print(result)
576+ try :
577+ #active_circuit = copy.copy(batched_circuit)
578+ #active_circuit["launch_time"] = time.time()
560579
561- exec_time = time .time () - ts
562-
563- # store the result object on the job for processing in job_complete
564- job .executor_result = result
565- job .exec_time = exec_time
566-
567- if verbose :
568- print (f"... result = { len (result )} { result } " )
569- ''' for debugging, a better way to see the counts, as the type of result is something Quake
570- for key, val in result.items():
571- print(f"... {key}:{val}")
572- '''
573- print (f"... register names = { result .register_names } " )
574- print (result .dump ())
575- #print(f"... register dump = {result.get_register_counts('__global__').dump()}")
576- #result.get_register_counts("b1").dump()
577- #print(result.get_sequential_data())
580+ #num_shots = batched_circuit["shots"]
581+
582+ # Initiate execution
583+ #circuit = batched_circuit["qc"]
584+
585+ # create a pseudo-job to perform metrics processing upon return
586+ job = Job ()
587+
588+ # draw the circuit, but only for debugging
589+ # print(cudaq.draw(circuit[0], *circuit[1]))
590+
591+ ts = time .time ()
592+
593+ # call sample() on circuit with its list of arguments
594+ if verbose : print (f"... during exec, noise model is: { noise } " )
595+ if noise is None :
596+ if verbose : print ("... executing without noise" )
597+ result = cudaq .sample (circuit [0 ], * circuit [1 ], shots_count = num_shots )
598+ else :
599+ if verbose : print ("... executing WITH noise" )
600+ result = cudaq .sample (circuit [0 ], * circuit [1 ], shots_count = num_shots , noise_model = noise )
601+
602+ # control results print at benchmark level
603+ #if verbose: print(result)
604+
605+ exec_time = time .time () - ts
606+
607+ # store the result object on the job for processing in job_complete
608+ job .executor_result = result
609+ job .exec_time = exec_time
610+
611+ if verbose :
612+ print (f"... result = { len (result )} { result } " )
613+ ''' for debugging, a better way to see the counts, as the type of result is something Quake
614+ for key, val in result.items():
615+ print(f"... {key}:{val}")
616+ '''
617+ print (f"... register names = { result .register_names } " )
618+ print (result .dump ())
619+ #print(f"... register dump = {result.get_register_counts('__global__').dump()}")
620+ #result.get_register_counts("b1").dump()
621+ #print(result.get_sequential_data())
622+
623+ except Exception as ex :
624+ print (f"ERROR attempting to compute cicuit metrics" )
625+ print (ex )
578626
579627 # put job into the active circuits with circuit info
580628 #active_circuits[job] = active_circuit
581629 #print("... active_circuit = ", str(active_circuit))
582630
583631 # ***********************************
584-
585- # store circuit dimensional metrics
586- # DEVNOTE: this is not accurate; it is provided so the volumetric plots show something
587- """
588- # compute depth and gate counts based on number of qubits
589- qc_size = int(active_circuit["group"])
590- qc_depth = 4 * pow(qc_size, 2)
591-
592- qc_xi = 0.5
632+ qc_depth , qc_size , qc_count_ops , qc_xi , qc_n2q = 0 , 0 , 0 , 0 , 0
633+ try :
634+ # number of qubits is stored in the "group" field
635+ #qc_size = int(circuit["group"])
636+ qc_size = circuit [1 ][0 ] # the first item after the kernel is alway num_qubits
637+
638+ # obtain initial circuit metrics
639+ qc_depth , qc_size , qc_count_ops , qc_xi , qc_n2q = get_circuit_metrics (circuit , qc_size )
593640
594- qc_n2q = int(qc_depth * 0.75)
641+ except Exception as ex :
642+ print (f"ERROR attempting to compute cicuit metrics" )
643+ print (ex )
644+
595645 qc_tr_depth = qc_depth
596646 qc_tr_size = qc_size
647+ qc_tr_count_ops = qc_count_ops
597648 qc_tr_xi = qc_xi
598649 qc_tr_n2q = qc_n2q
599650
651+ """
600652 # store circuit dimensional metrics
601653 metrics.store_metric(active_circuit["group"], active_circuit["circuit"], 'depth', qc_depth)
602654 metrics.store_metric(active_circuit["group"], active_circuit["circuit"], 'size', qc_size)
@@ -607,11 +659,8 @@ def execute_circuit_immed (circuit: list, num_shots: int):
607659 metrics.store_metric(active_circuit["group"], active_circuit["circuit"], 'tr_size', qc_tr_size)
608660 metrics.store_metric(active_circuit["group"], active_circuit["circuit"], 'tr_xi', qc_tr_xi)
609661 metrics.store_metric(active_circuit["group"], active_circuit["circuit"], 'tr_n2q', qc_tr_n2q)
610-
611- ##############
612- # Here we complete the job immediately
613- job_complete(job)
614662 """
663+
615664 """
616665 # klunky way to know the last group executed
617666 #last_group = None
0 commit comments