Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help with detecting crosstalk errors of simulated data #466

Open
AxelVahur opened this issue Jul 11, 2024 · 0 comments
Open

Help with detecting crosstalk errors of simulated data #466

AxelVahur opened this issue Jul 11, 2024 · 0 comments
Milestone

Comments

@AxelVahur
Copy link

AxelVahur commented Jul 11, 2024

Hello,

As part of my master's project on crosstalk I'm using pyGSTi to simulate 2-qubit data and detect crosstalk in it, similar to https://arxiv.org/pdf/1908.09855v3 and eventually would like to detect crosstalk in the Finnish Helmi 5-qubit computer. Even after spending quite a bit of time I can't get the do_basic_crosstalk_detection function to work. Before getting to that I needed suitable circuits to simulate and attempted to use the crosstalk_detection_experiment2 function which gave errors until I changed a few lines in its definition. It then returned a reasonable looking crosstalk experiment dictionary and simulating the circuits in this dictionary worked fine.

Attempting to feed this DataSet object into the do_basic_crosstalk_detection function fails right away at the function trying to index list-generators instead of lists and changing the definition to use list() instead would give a keyerror "settings" on the next line. After that I decided to convert the dataset into a 2d numpy array myself, with each entry being a 4-element list of outcomes of region 0, region 1, settings on region 0, settings on region 1 and each of these is a list. From the article I understand that SPAM operations being the same, settings mean only the gates applied, i.e. circuits. The settings argument being a list [1, 1] was what satisfied the original np.shape checks for 2 qubits which produce 4 columns, but this is still not in the correct format.

All of these issues probably arise from not understanding how to input the settings despite reading the articles and documentation. Below are first my modified crosstalk_detection_experiment2 with the original lines commented out above my changes on lines 42, 77, 91, 95, 100, and finally my remaining code.

Windows 11
python 3.11.9
pyGSTi 0.9.12.3

import numpy as _np
import pygsti

def axel_crosstalk_detection_experiment2(pspec, lengths, circuits_per_length, circuit_population_sz, multiplier=3,
                                    idle_prob=0.1, structure='1Q',
                                    descriptor='A set of crosstalk detections experiments', verbosity=1):
	
	experiment_dict = {}
	experiment_dict['spec'] = {}
	experiment_dict['spec']['lengths'] = lengths
	experiment_dict['spec']['circuit_population_sz'] = circuit_population_sz
	experiment_dict['spec']['multiplier'] = multiplier
	experiment_dict['spec']['idle_prob'] = idle_prob
	experiment_dict['spec']['descriptor'] = descriptor
	experiment_dict['spec']['createdby'] = 'extras.crosstalk.crosstalk_detection_experiment2'

	if isinstance(structure, str):
		assert(structure == '1Q'), "The only default `structure` option is the string '1Q'"
		structure = tuple([(q,) for q in pspec.qubit_labels])
		n = pspec.num_qubits
	else:
		assert(isinstance(structure, list) or isinstance(structure, tuple)), \
			"If not a string, `structure` must be a list or tuple."
		qubits_used = []
		for subsetQs in structure:
			assert(isinstance(subsetQs, list) or isinstance(subsetQs, tuple)), "SubsetQs must be a list or a tuple!"
			qubits_used = qubits_used + list(subsetQs)
			assert(len(set(qubits_used)) == len(qubits_used)), \
				"The qubits in the tuples/lists of `structure must all be unique!"

		assert(set(qubits_used).issubset(set(pspec.qubit_labels))), \
			"The qubits to benchmark must all be in the QubitProcessorSpec `pspec`!"
		n = len(qubits_used)

	experiment_dict['spec']['circuits_per_length'] = circuits_per_length * multiplier * n

	experiment_dict['spec']['structure'] = structure
	experiment_dict['circuits'] = {}
	experiment_dict['settings'] = {}
	
	# gates_available = list(pspec.models['target'].primitive_op_labels)	#QubitProcessorSpec has no attribute models
	gates_available = list(pspec.primitive_op_labels)
	gates_by_qubit = [[] for _ in range(0, n)]
	for i in range(0, len(gates_available)):
		for q in range(0, n):
			if gates_available[i].qubits == (q,):
				gates_by_qubit[q].append(gates_available[i])

	for lnum, l in enumerate(lengths):
		# generate menu of circuits for each qubit
		circuit_menu = [[] for _ in range(0, n)]
		for q in range(0, n):
			d = len(gates_by_qubit[q])
			if d**l < circuit_population_sz:
				print(('- Warning: circuit population specified too large for qubit {}'
						' -- there will be redundant circuits').format(q))
			for rep in range(0, circuit_population_sz):
				singleQcirc = []
				for j in range(0, l): #creates an l-length single qubit circuit
					r = _np.random.randint(0, d)
					singleQcirc.append(gates_by_qubit[q][r])
				circuit_menu[q].append(singleQcirc)

		cnt = 0
		for q in range(0, n):
			print('  - Qubit {} = '.format(q))

			# need circuits_per_length number of settings for this qubit
			for j in range(circuits_per_length):
				#  iteratively choose each of the circuits in the menu
				qr = j

				# generate "multiplier" number of random circuits on the other qubits with qr setting
				#  on the central qubit
				for m in range(0, multiplier):
					# circuit = _Circuit(num_lines=0, editable=True)
					circuit = pygsti.circuits.Circuit(num_lines=0, editable=True)
					settings = {}

					for q1 in range(0, n):
						
						if q1 == q:
							# the setting for the central qubit is fixed
							r = qr
						else:
							# draw a setting
							r = _np.random.randint(0, circuit_population_sz)

						settings[(q1,)] = lnum * (circuit_population_sz + 1) + r + 1
						# singleQcircuit = _Circuit(num_lines=1, line_labels=[q1], editable=True)
						singleQcircuit = pygsti.circuits.Circuit(num_lines=1, line_labels=[q1], editable=True)
						for layer in range(0, l):
							# singleQcircuit.insert_layer(circuit_menu[q1][r][layer], layer)	# returns a Circuit but not assigned,
							# leaving singleQcircuit with 0 layers and second loop gives index error
							singleQcircuit = singleQcircuit.insert_layer(circuit_menu[q1][r][layer], layer)
						
						singleQcircuit.done_editing()
						
						# circuit.tensor_circuit(singleQcircuit)	# also not assigned
						circuit = circuit.tensor_circuit(singleQcircuit)
					
					experiment_dict['settings'][l, cnt] = settings
					# for each line, except the central qubit, replace sequence with an idle
					#  independently according to idle_prob
					if idle_prob > 0:
						for q1 in range(0, n):
							if q1 != q:
								idle = bool(_np.random.binomial(1, idle_prob))
								if idle:
									circuit.replace_with_idling_line_inplace(q1)
									# Update the setting on that qubit to the idling setting
									#  (denoted by the length index)
									experiment_dict['settings'][l, cnt][(q1,)] = lnum * (circuit_population_sz + 1)
									if verbosity > 0: print('(Idled {}) '.format(q1), end='')

					circuit.done_editing()
					experiment_dict['circuits'][l, cnt] = circuit
					cnt += 1

					if verbosity > 0: print('{}, '.format(m), end='')
				if verbosity > 0: print(')')
		print('cnt: {}'.format(cnt))
	return experiment_dict
import pygsti
import pygsti.extras.crosstalk as crosstalk
import numpy as np

processorSpec = pygsti.processors.QubitProcessorSpec(2, ["Gxpi2", "Gypi2", "Gi"], geometry = "line")
mdlCn = pygsti.models.create_cloud_crosstalk_model(processorSpec,
	lindblad_error_coeffs={
		("Gxpi2",0): {("S","X:1"): 0.1} #"H", "S" Hamiltonian and Pauli-Stochastic errors
	},
	simulator="map"
)

ctDict = axel_crosstalk_detection_experiment2(processorSpec, [4], 10, 20, verbosity=0, multiplier=3)
circuitList = list(ctDict["circuits"].values())
tdds = pygsti.data.datasetconstruction.simulate_data(mdlCn, circuitList, num_samples=100, sample_error='multinomial', seed=557, times=[0.0])

print("circuitList: ", circuitList)
print("settings: ", ctDict["settings"])

aggre0 = pygsti.data.datasetconstruction.aggregate_dataset_outcomes(tdds, {"0":["00","01"],"1":["10","11"]}) #outcomes of qubit 0
aggre1 = pygsti.data.datasetconstruction.aggregate_dataset_outcomes(tdds, {"0":["00","10"],"1":["11","01"]}) #outcomes of qubit 1

print("row1 of dataset: ", tdds[circuitList[0]])
print("row1 of qubit0: ", aggre0[circuitList[0]])
print("row1 of qubit1: ", aggre1[circuitList[0]])

myList = []
mySettings = [1, 1]

for i in range(0, len(circuitList), 1):
	tempCircuit = circuitList[i]	#pick ith circuit from circuitList
	expList = []

	q0outcomeList = list(aggre0[tempCircuit])
	count0 = list(q0outcomeList[0])[2]
	count1 = list(q0outcomeList[1])[2]
	q0arr = [count0, count1]
	expList.append(q0arr)
	
	q1outcomeList = list(aggre1[tempCircuit])
	count0 = list(q1outcomeList[0])[2]
	count1 = list(q1outcomeList[1])[2]
	q1arr = [count0, count1]
	expList.append(q1arr)
	
	expList.append(list(tempCircuit)) # settings of region 0
	expList.append(list(tempCircuit)) # settings of region 1 (same)
	myList.append(expList)

npList = np.array(myList, dtype=object)

print("\n", myList[0])
print("\n", npList[0])

crosstalk.do_basic_crosstalk_detection(npList, 2, [1,1])
@sserita sserita added this to the 0.9.14 milestone Sep 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants