3
3
from pygsti .processors .processorspec import QubitProcessorSpec as QPS
4
4
from pygsti .extras .ml .tools import create_error_propagation_matrix , index_to_error_gen , error_gen_to_index
5
5
from tqdm import trange
6
+ import time
6
7
7
8
###### Functions that encode a circuit into a tensor ###
8
9
@@ -110,7 +111,8 @@ def t_bar_gate_to_index(g, q, pspec)-> int:
110
111
assert (q in g .qubits )
111
112
single_qubit_gates = list (pspec .gate_names )
112
113
single_qubit_gates .remove ('Gcnot' )
113
- if g .name == 'Gcnot' :
114
+ single_qubit_gates .remove ('Gecres' )
115
+ if g .name == 'Gcnot' or g .name == 'Gecres' :
114
116
if g .qubits in [(0 ,1 ), (1 ,2 )]:
115
117
if q == g .qubits [0 ]: return 0
116
118
else : return 1
@@ -134,9 +136,11 @@ def t_bar_gate_to_index(g, q, pspec)-> int:
134
136
def ring_gate_to_index (g , q , pspec ):
135
137
assert (q in g .qubits )
136
138
num_qubits = pspec .num_qubits
137
- single_qubit_gates = list (pspec .gate_names )
138
- single_qubit_gates .remove ('Gcnot' )
139
- if g .name == 'Gcnot' :
139
+ multi_quibit_list = ['Gecr' , 'Gecres' , 'Gcnot' ]
140
+ single_qubit_gates = [gate for gate in list (pspec .gate_names ) if gate not in multi_quibit_list ]
141
+ # single_qubit_gates = list(pspec.gate_names)
142
+ # single_qubit_gates.remove('Gecr')
143
+ if g .name in multi_quibit_list :
140
144
qs = g .qubits
141
145
if q == g .qubits [0 ] and clockwise_cnot (g , num_qubits ):
142
146
return 0
@@ -150,7 +154,7 @@ def ring_gate_to_index(g, q, pspec):
150
154
raise ValueError ('Invalid gate name for this encoding!' )
151
155
elif g .name in pspec .gate_names :
152
156
# We have a single-qubit gate
153
- return 4 + single_qubit_gates .index (g .name ) # we put the single-qubit gates after the CNOT channels.
157
+ return 4 + single_qubit_gates .index (g .name ) # we put the single-qubit gates after the CNOT/ECR channels.
154
158
else :
155
159
raise ValueError ('Invalid gate name for this encoding!' )
156
160
@@ -174,7 +178,7 @@ def layer_to_matrix(layer, num_qubits = None, num_channels = None,
174
178
for q in g .qubits :
175
179
if type (q ) == str : q_index = int (q [1 :])
176
180
else : q_index = q
177
- mat [q_index , indexmapper (g , q , ** indexmapper_kwargs )] = valuemapper (g , ** valuemapper_kwargs )
181
+ mat [q_index , indexmapper (g , q , ** indexmapper_kwargs )- 1 ] = valuemapper (g , ** valuemapper_kwargs )
178
182
return mat
179
183
180
184
def circuit_to_tensor (circ , depth = None , num_qubits = None , num_channels = None , add_measurements = False ,
@@ -409,7 +413,8 @@ def create_probability_data(circs:list,
409
413
approximate_probabilities :list ,
410
414
# rate_values:list,
411
415
tracked_error_gens : list ,
412
- pspec , geometry : str , num_qubits = None , num_channels = None ,
416
+ pspec , geometry : str , true_probabilities = None ,
417
+ num_qubits = None , num_channels = None ,
413
418
measurement_encoding = None , idealouts = None ,
414
419
indexmapper = None , indexmapper_kwargs = {},
415
420
valuemapper = None , valuemapper_kwargs = {},
@@ -426,107 +431,129 @@ def create_probability_data(circs:list,
426
431
- num_channels: the number of channels used to embed a (qubit, gate) pair (optional, if pspec and geometry are specified.)
427
432
- indexmapper: function specifying how to map a gate to a channel.
428
433
- valuemapper: function specifying how to encode each gate in pspec (optional, defaults to assigning each gate a value of 1)
429
- - measurement_encoding: int or NoneType specifying how to encode measurements.
430
- - If NoneType, then no measurements are returned.
431
- - If 1, then measurements are encoded as extra channels in the circuit tensor.
432
- - If 2, then the measurements are returned separately in a tensor of shape (num_qubits,)
433
- - list of each circuit's target outcome. Only used when measurement_encoding = 2.
434
434
'''
435
435
num_circs = len (circs )
436
436
num_error_gens = len (tracked_error_gens )
437
437
438
438
439
439
if max_depth is None : max_depth = _np .max ([c .depth for c in circs ])
440
- # print(max_depth)
441
-
442
440
if num_channels is None : num_channels = compute_channels (pspec , geometry )
443
- encode_measurements = False
444
- if measurement_encoding == 1 :
445
- _warnings .warn ('Measurement encoding scheme 1 is not implemented yet!' )
446
- encode_measurements = True
447
- num_channels += 1
448
- max_depth += 1 # adding an additional layer to each circuit for the measurements.
449
- elif measurement_encoding == 2 :
450
- # Encodes the measurements as a seperate vector.
451
- measurements = _np .zeros ((num_circs , num_qubits ))
452
- x_zmask = _np .zeros ((num_circs , max_depth , num_error_gens ), int )
453
- elif measurement_encoding == 3 :
454
- # Encodes the measurements as a seperate vector and returns a measurement mask.
455
- measurements = _np .zeros ((num_circs , num_qubits ))
456
- x_zmask = _np .zeros ((num_circs , max_depth , num_error_gens ), int )
457
- x_mmask = _np .zeros ((num_circs , num_error_gens ), int )
458
- tracked_error_indices = _np .array ([error_gen_to_index (error [0 ], error [1 ]) for error in tracked_error_gens ])
459
-
460
441
if num_qubits is None : num_qubits = len (pspec .qubit_labels )
461
442
if valuemapper is None : valuemapper = lambda x : 1
462
443
assert (indexmapper is not None ), 'I need a way to map gates to an index!!!!'
463
444
464
445
x_circs = _np .zeros ((num_circs , num_qubits , max_depth , num_channels ), float )
465
446
x_signs = _np .zeros ((num_circs , max_depth , num_error_gens ), int )
466
447
x_indices = _np .zeros ((num_circs , max_depth , num_error_gens ), int )
467
- y = _np .array (approximate_probabilities )
448
+ y_true = _np .array (true_probabilities )
449
+ y_approx = _np .array (approximate_probabilities )
468
450
469
451
for i in trange (len (circs ), smoothing = 0 ):
470
452
c = circs [i ]
471
- # if i % 200 == 0:
472
- # print(i, end=',', flush = True)
473
453
x_circs [i , :, :, :] = circuit_to_tensor (c , max_depth , num_qubits , num_channels , encode_measurements ,
474
454
indexmapper , indexmapper_kwargs ,
475
455
valuemapper , valuemapper_kwargs
476
456
)
477
457
c_indices , c_signs = create_error_propagation_matrix (c , tracked_error_gens , stim_dict = stimDict )
478
- if large_encoding :
479
- mapping = unique_value_mapping (c_indices )
480
- c_indices = map_array_values (c_indices , mapping )
481
458
x_indices [i , 0 :c .depth , :] = c_indices # deprecated: np.rint(c_indices)
482
459
x_signs [i , 0 :c .depth , :] = c_signs # deprecated: np.rint(c_signs)
483
- if measurement_encoding == 1 :
484
- # This is where update the signs and indices to account for the measurements
485
- # NOT IMPLEMENTED!!!!!
486
- x_signs [i , :, - 1 ] = 1
487
- x_indices [i , :, - 1 ] = 0 # ??? Need to figure this out ??? Need to take the tracked error gens and map them to their unique id
488
- elif measurement_encoding == 2 :
489
- measurements [i , :] = active_qubits (x_circs [i , :, :, :])
490
- measurements [i , ::- 1 ] = measurements [i , :] # flip it and reverse it
491
- x_zmask [i , 0 :c .depth , :] = z_mask (c_indices , measurements [i , :])
492
- elif measurement_encoding == 3 :
493
- measurements [i , :] = active_qubits (x_circs [i , :, :, :])
494
- measurements [i , ::- 1 ] = measurements [i , :] # flip it and reverse it
495
- x_zmask [i , 0 :c .depth , :] = z_mask (c_indices , measurements [i , :]) # Update this
496
- x_mmask [i , :] = z_mask (tracked_error_indices , measurements [i , :]) # Update this
497
460
498
461
x_alpha = _np .array (alpha_values )
499
462
x_px = _np .array (ideal_probabilities )
500
- if return_separate :
501
- xc_reshaped = _np .zeros ((x_circs .shape [0 ], x_circs .shape [2 ], x_circs .shape [1 ] * x_circs .shape [3 ]), float )
502
- for qi in range (num_qubits ):
503
- for ci in range (num_channels ):
504
- xc_reshaped [:, :, qi * num_channels + ci ] = x_circs [:, qi , :, ci ].copy ()
505
-
506
- return xc_reshaped , x_signs , x_indices , x_alpha , x_px , y
463
+ xc_reshaped = _np .zeros ((x_circs .shape [0 ], x_circs .shape [2 ], x_circs .shape [1 ] * x_circs .shape [3 ]), float )
464
+ for qi in range (num_qubits ):
465
+ for ci in range (num_channels ):
466
+ xc_reshaped [:, :, qi * num_channels + ci ] = x_circs [:, qi , :, ci ].copy ()
467
+
468
+ # if y_true.shape[0] > 0:
469
+ # return xc_reshaped, x_signs, x_indices, x_alpha, x_px, y_approx, y_true
470
+ # else:
471
+ return xc_reshaped , x_signs , x_indices , x_alpha , x_px , y_approx
472
+
473
+ def create_probability_data_test (circs : list ,
474
+ ideal_probabilities : list ,
475
+ alpha_values : list ,
476
+ approximate_probabilities : list ,
477
+ tracked_error_gens : list ,
478
+ pspec , geometry : str , true_probabilities = None ,
479
+ num_qubits = None , num_channels = None ,
480
+ measurement_encoding = None , idealouts = None ,
481
+ indexmapper = None , indexmapper_kwargs = {},
482
+ valuemapper = None , valuemapper_kwargs = {},
483
+ max_depth = None , return_separate = False , stimDict = None ,
484
+ large_encoding = False ):
485
+ '''
486
+ Maps a list of circuits and fidelities to numpy arrays of encoded circuits and fidelities.
487
+
488
+ Args:
489
+ - tracked_error_gens: a list of the tracked error generators.
490
+ - pspec: the processor on which the circuits are defined. Used to determine the number of qubits and channels (optional)
491
+ - geometry: the geometry in which you plan to embed the circuits (i.e., ring, grid, linear). Optional.
492
+ - num_qubits: the number of qubits (optional, if pspec and geometry are specified)
493
+ - num_channels: the number of channels used to embed a (qubit, gate) pair (optional, if pspec and geometry are specified.)
494
+ - indexmapper: function specifying how to map a gate to a channel.
495
+ - valuemapper: function specifying how to encode each gate in pspec (optional, defaults to assigning each gate a value of 1)
496
+ '''
497
+ num_circs = len (circs )
498
+ num_error_gens = len (tracked_error_gens )
499
+
500
+ if max_depth is None :
501
+ max_depth = np .max ([c .depth for c in circs ])
502
+ if num_channels is None :
503
+ num_channels = compute_channels (pspec , geometry )
504
+ if num_qubits is None :
505
+ num_qubits = len (pspec .qubit_labels )
506
+ if valuemapper is None :
507
+ valuemapper = lambda x : 1
508
+ assert indexmapper is not None , 'I need a way to map gates to an index!!!!'
509
+
510
+ x_circs = _np .zeros ((num_circs , num_qubits , max_depth , num_channels ), float )
511
+ x_signs = _np .zeros ((num_circs , max_depth , num_error_gens ), int )
512
+ x_indices = _np .zeros ((num_circs , max_depth , num_error_gens ), int )
513
+ y_true = _np .array (true_probabilities )
514
+ y_approx = _np .array (approximate_probabilities )
515
+
516
+ time_circuit_to_tensor = 0
517
+ time_create_error_propagation_matrix = 0
518
+ time_rest = 0
519
+
520
+ start_time = time .time ()
521
+ for i in trange (len (circs ), smoothing = 0 ):
522
+ c = circs [i ]
523
+
524
+ start = time .time ()
525
+ x_circs [i , :, :, :] = circuit_to_tensor (c , max_depth , num_qubits , num_channels , measurement_encoding ,
526
+ indexmapper , indexmapper_kwargs , valuemapper , valuemapper_kwargs )
527
+ time_circuit_to_tensor += time .time () - start
528
+
529
+ start = time .time ()
530
+ c_indices , c_signs = create_error_propagation_matrix (c , tracked_error_gens , stim_dict = stimDict )
531
+ time_create_error_propagation_matrix += time .time () - start
507
532
533
+ x_indices [i , 0 :c .depth , :] = c_indices
534
+ x_signs [i , 0 :c .depth , :] = c_signs
535
+
536
+ x_alpha = _np .array (alpha_values )
537
+ x_px = _np .array (ideal_probabilities )
538
+ xc_reshaped = _np .zeros ((x_circs .shape [0 ], x_circs .shape [2 ], x_circs .shape [1 ] * x_circs .shape [3 ]), float )
539
+
540
+ start = time .time ()
541
+ for qi in range (num_qubits ):
542
+ for ci in range (num_channels ):
543
+ xc_reshaped [:, :, qi * num_channels + ci ] = x_circs [:, qi , :, ci ].copy ()
544
+ time_rest += time .time () - start
545
+
546
+ total_time = time .time () - start_time
547
+
548
+ print (f"Time for circuit_to_tensor: { time_circuit_to_tensor :.6f} seconds" )
549
+ print (f"Time for create_error_propagation_matrix: { time_create_error_propagation_matrix :.6f} seconds" )
550
+ print (f"Time for the rest of the function: { time_rest :.6f} seconds" )
551
+ print (f"Total time: { total_time :.6f} seconds" )
552
+ if true_probabilities is not None :
553
+ return xc_reshaped , x_signs , x_indices , x_alpha , x_px , y_approx , y_true
508
554
else :
509
- len_gate_encoding = num_qubits * num_channels
510
- xc_reshaped = _np .zeros ((x_circs .shape [0 ], x_circs .shape [2 ], x_circs .shape [1 ] * x_circs .shape [3 ]), float )
511
- for qi in range (num_qubits ):
512
- for ci in range (num_channels ):
513
- xc_reshaped [:, :, qi * num_channels + ci ] = x_circs [:, qi , :, ci ].copy ()
514
-
515
- x = _np .zeros ((x_indices .shape [0 ], x_indices .shape [1 ], 2 * num_error_gens + len_gate_encoding ), float )
516
- x [:, :, 0 :len_gate_encoding ] = xc_reshaped [:, :, :]
517
- x [:, :, len_gate_encoding :num_error_gens + len_gate_encoding ] = x_indices [:, :, :]
518
- x [:, :, num_error_gens + len_gate_encoding :2 * num_error_gens + len_gate_encoding ] = x_signs [:, :, :]
519
- if measurement_encoding == 2 :
520
- if idealouts is not None :
521
- target_outcomes = _np .array ([list (idealout ) for idealout in idealouts ], dtype = float )
522
- return x , y , measurements , target_outcomes , x_zmask
523
- return x , y , measurements , x_zmask ,
524
- elif measurement_encoding == 3 :
525
- if idealouts is not None :
526
- target_outcomes = _np .array ([list (idealout ) for idealout in idealouts ], dtype = float )
527
- return x , y , measurements , target_outcomes , x_zmask , x_mmask
528
- return x , y , measurements , x_zmask , x_mmask
555
+ return xc_reshaped , x_signs , x_indices , x_alpha , x_px , y_approx
556
+
529
557
530
- return x , y
531
558
532
559
0 commit comments