This notebook shows a simple example of how to use pyGSTi with Cirq. It has three sections:
import cirq
import pygsti
from pygsti.modelpacks import smq1Q_XYI
import numpy as np
import tqdm
target_model = smq1Q_XYI.target_model()
preps = smq1Q_XYI.prep_fiducials()
effects = smq1Q_XYI.meas_fiducials()
germs = smq1Q_XYI.germs()
max_lengths = list(np.logspace(0, 10, 11, base=2, dtype=int))
print(max_lengths)
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
pygsti_circuits = pygsti.construction.create_lsgst_circuits(target_model, preps, effects, germs, max_lengths)
len(pygsti_circuits)
1624
cirq.Circuit
's¶Now, we need to map the qubit names from pyGSTi (0
, 1
, etc.) into cirq qubits. There's nothing special about cirq.GridQubit(8, 3)
; it's just an example.
q0 = cirq.GridQubit(8, 3)
qubit_label_dict = {0: q0}
Do an example conversion.
pygsti_circuit = pygsti_circuits[111]
print('pyGSTi:')
print(pygsti_circuit)
print('Cirq:')
print(pygsti_circuit.convert_to_cirq(qubit_label_dict))
pyGSTi: Qubit 0 ---|Gxpi2|-|Gxpi2|-| |-| |-|Gxpi2|--- Cirq: (8, 3): ───X^0.5───X^0.5───────────X^0.5───
Do another example conversion.
pygsti_circuit = pygsti_circuits[90]
print('pyGSTi:')
print(pygsti_circuit)
print('Cirq:')
print(pygsti_circuit.convert_to_cirq(qubit_label_dict))
pyGSTi: Qubit 0 ---|Gypi2|-|Gypi2|-|Gypi2|-|Gypi2|-|Gxpi2|-|Gxpi2|-|Gxpi2|--- Cirq: (8, 3): ───Y^0.5───Y^0.5───Y^0.5───Y^0.5───X^0.5───X^0.5───X^0.5───
Now, lets try the same thing but specifing a wait duration for the idle operation.
wait_duration = cirq.Duration(nanos=100)
pygsti_circuit = pygsti_circuits[111]
print('pyGSTi:')
print(pygsti_circuit)
print('Cirq:')
print(pygsti_circuit.convert_to_cirq(qubit_label_dict, wait_duration))
pyGSTi: Qubit 0 ---|Gxpi2|-|Gxpi2|-| |-| |-|Gxpi2|--- Cirq: (8, 3): ───X^0.5───X^0.5───WaitGate(100 ns)───WaitGate(100 ns)───X^0.5───
pygsti_circuit = pygsti_circuits[90]
print('pyGSTi:')
print(pygsti_circuit)
print('Cirq:')
print(pygsti_circuit.convert_to_cirq(qubit_label_dict, wait_duration))
pyGSTi: Qubit 0 ---|Gypi2|-|Gypi2|-|Gypi2|-|Gypi2|-|Gxpi2|-|Gxpi2|-|Gxpi2|--- Cirq: (8, 3): ───Y^0.5───Y^0.5───Y^0.5───Y^0.5───X^0.5───X^0.5───X^0.5───
Now, convert all the circuits.
cirq_circuits = [c.convert_to_cirq(qubit_label_dict, wait_duration) for c in tqdm.tqdm(pygsti_circuits)]
100%|██████████| 1624/1624 [00:08<00:00, 189.73it/s]
Note that we're missing the measurments, the idle operations don't have a time associated with them, and the first circuit is empty (it's should just be an idle). Otherwise, the results look good, and those things should be easy to fix.
Add measurements to the circuits.
for circuit in cirq_circuits:
circuit.append(cirq.measure(q0, key='result'))
Simulate the circuits (or run them on a real quantum computer!)
simulator = cirq.Simulator()
results = [simulator.run(circuit, repetitions=1000) for circuit in tqdm.tqdm(cirq_circuits)]
100%|██████████| 1624/1624 [00:39<00:00, 41.60it/s]
Load everything the results into a pyGSTi dataset.
dataset = pygsti.objects.dataset.DataSet()
for pygsti_circuit, trial_result in zip(pygsti_circuits, results):
dataset.add_cirq_trial_result(pygsti_circuit, trial_result, key='result')
Perform GST.
gst_results = pygsti.run_stdpractice_gst(dataset, target_model, preps, effects, germs, max_lengths, modes="TP,Target", verbosity=1)
--- Circuit Creation --- -- Std Practice: [##################################################] 100.0% (Target) --
See what if finds.
mdl_estimate = gst_results.estimates['TP'].models['stdgaugeopt']
print("2DeltaLogL(estimate, data): ", pygsti.tools.two_delta_logl(mdl_estimate, dataset))
print("2DeltaLogL(ideal, data): ", pygsti.tools.two_delta_logl(target_model, dataset))
2DeltaLogL(estimate, data): 1102.0101377779301 2DeltaLogL(ideal, data): 1118.865389448009