Skip to content

Commit 972ee40

Browse files
author
Jeremiah Hauth
committed
new encoding options for true / experimental data
1 parent 5d660f5 commit 972ee40

File tree

1 file changed

+106
-79
lines changed

1 file changed

+106
-79
lines changed

Diff for: pygsti/extras/ml/encoding.py

+106-79
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pygsti.processors.processorspec import QubitProcessorSpec as QPS
44
from pygsti.extras.ml.tools import create_error_propagation_matrix, index_to_error_gen, error_gen_to_index
55
from tqdm import trange
6+
import time
67

78
###### Functions that encode a circuit into a tensor ###
89

@@ -110,7 +111,8 @@ def t_bar_gate_to_index(g, q, pspec)-> int:
110111
assert(q in g.qubits)
111112
single_qubit_gates = list(pspec.gate_names)
112113
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':
114116
if g.qubits in [(0,1), (1,2)]:
115117
if q == g.qubits[0]: return 0
116118
else: return 1
@@ -134,9 +136,11 @@ def t_bar_gate_to_index(g, q, pspec)-> int:
134136
def ring_gate_to_index(g, q, pspec):
135137
assert(q in g.qubits)
136138
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:
140144
qs = g.qubits
141145
if q == g.qubits[0] and clockwise_cnot(g, num_qubits):
142146
return 0
@@ -150,7 +154,7 @@ def ring_gate_to_index(g, q, pspec):
150154
raise ValueError('Invalid gate name for this encoding!')
151155
elif g.name in pspec.gate_names:
152156
# 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.
154158
else:
155159
raise ValueError('Invalid gate name for this encoding!')
156160

@@ -174,7 +178,7 @@ def layer_to_matrix(layer, num_qubits = None, num_channels = None,
174178
for q in g.qubits:
175179
if type(q) == str: q_index = int(q[1:])
176180
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)
178182
return mat
179183

180184
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,
409413
approximate_probabilities:list,
410414
# rate_values:list,
411415
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,
413418
measurement_encoding = None, idealouts = None,
414419
indexmapper = None, indexmapper_kwargs = {},
415420
valuemapper = None, valuemapper_kwargs = {},
@@ -426,107 +431,129 @@ def create_probability_data(circs:list,
426431
- num_channels: the number of channels used to embed a (qubit, gate) pair (optional, if pspec and geometry are specified.)
427432
- indexmapper: function specifying how to map a gate to a channel.
428433
- 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.
434434
'''
435435
num_circs = len(circs)
436436
num_error_gens = len(tracked_error_gens)
437437

438438

439439
if max_depth is None: max_depth = _np.max([c.depth for c in circs])
440-
# print(max_depth)
441-
442440
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-
460441
if num_qubits is None: num_qubits = len(pspec.qubit_labels)
461442
if valuemapper is None: valuemapper = lambda x: 1
462443
assert(indexmapper is not None), 'I need a way to map gates to an index!!!!'
463444

464445
x_circs = _np.zeros((num_circs, num_qubits, max_depth, num_channels), float)
465446
x_signs = _np.zeros((num_circs, max_depth, num_error_gens), int)
466447
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)
468450

469451
for i in trange(len(circs), smoothing=0):
470452
c = circs[i]
471-
# if i % 200 == 0:
472-
# print(i, end=',', flush = True)
473453
x_circs[i, :, :, :] = circuit_to_tensor(c, max_depth, num_qubits, num_channels, encode_measurements,
474454
indexmapper, indexmapper_kwargs,
475455
valuemapper, valuemapper_kwargs
476456
)
477457
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)
481458
x_indices[i, 0:c.depth, :] = c_indices # deprecated: np.rint(c_indices)
482459
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
497460

498461
x_alpha = _np.array(alpha_values)
499462
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
507532

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
508554
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+
529557

530-
return x, y
531558

532559

0 commit comments

Comments
 (0)