Download

Download this file as Jupyter notebook: estimate_collections.ipynb.

Parsing Estimate Collections

The standard workflow for diagnostic and suppression protocols is to invoke their generation functions to create a circuit collection, run each of the circuits on a device or simulator, populate each circuit’s results with the observed data, and finally invoke the fit() method to produce estimates of the quantities of interest.

We now follow this procedure to create a rich EstimateCollection instance that can be used throughout this guide. First, we create a large circuit collection with many types of circuits.

[2]:
import trueq as tq
import trueq.simulation as tqs

# add single-qubit simultaneous SRB, XRB, IRB on a 4 qubit system
circuits = tq.make_srb(range(4), [2, 16, 32])
circuits += tq.make_xrb(range(4), [2, 16, 32])
circuits += tq.make_irb({range(4): tq.Gate.h}, [2, 8, 16])

# add two-qubit simultaneous SRB, XRB, IRB on a 4 qubit system
circuits += tq.make_srb([[0, 1], [2, 3]], [2, 10, 20])
circuits += tq.make_irb({(0, 1): tq.Gate.cx, (2, 3): tq.Gate.cx}, [2, 10, 20])

# add CB for two cycles on a 4 qubit system
circuits += tq.make_cb({(0, 1): tq.Gate.cz, (2, 3): tq.Gate.cz}, [2, 10, 20])
circuits += tq.make_cb({(0, 1): tq.Gate.cx, (2, 3): tq.Gate.cx}, [2, 10, 20])

# add single-body noise reconstruction for two cycles on a 4 qubit system
pauli_twirl = tq.Twirl("P", range(4))
circuits += tq.make_knr({(0, 1): tq.Gate.cz}, [2, 10, 20], twirl=pauli_twirl)
circuits += tq.make_knr({(0, 1): tq.Gate.cx}, [2, 10, 20], twirl=pauli_twirl)

# add some readout calibration circuits
circuits += tq.make_rcal(range(4))

Next, we simulate all of the circuits with a noisy simulator.

[3]:
sim = tq.Simulator()
sim.add_overrotation(0.04, 0.03)
for label, p in enumerate([0.01, 0.005, 0.03, 0.02]):
    sim.add_stochastic_pauli(pz=p, match=tqs.LabelMatch(label))
sim.add_stochastic_pauli(px=0.01, match=tqs.GateMatch(tq.Gate.cx))
sim.add_readout_error([0.01, 0.05])

# run RCAL with more shots than any other protocol
sim.run(circuits.subset(protocol="RCAL"), n_shots=4096)
sim.run(circuits.subset(has_results=False), n_shots=64)

Finally, we produce an EstimateCollection from these simulations by calling fit() with the default options.

[4]:
fit = circuits.fit()

What is an Estimate Collection

The variable fit, defined just above, is an EstimateCollection, which itself is a list-like object whose entries are Estimate objects. Each individual estimate object contains estimated values for some particular context. For example, the SRB diagnostic protocol produces an estimate object for each subsystem, each of which contains estimated values for the subsystem infidelity e_F, the SPAM constant A, and the decay parameter p.

[5]:
# number of estimates in the collection
len(fit)
[5]:
25
[6]:
# the first estimate object
fit[0]
[6]:
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
SRB
Streamlined Randomized Benchmarking
Cliffords
(0,)
Key:
  • labels: (0,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
${e}_{F}$
The probability of an error acting on the targeted systems during a random gate.
1.4e-02 (1.1e-03)
0.01391653828711592, 0.0010795258872437275
${p}$
Decay parameter of the exponential decay $Ap^m$.
9.8e-01 (1.4e-03)
0.9814446156171788, 0.0014393678496583031
${A}$
SPAM parameter of the exponential decay $Ap^m$.
1.0e+00 (1.6e-02)
1.0081191480533906, 0.016086395042879585

The context of an estimate includes information such as what protocol it corresponds to, which subsystem it pertains to, what the cycle of interest is, which twirling group was used for randomization, and so on. This information is stored on the key attribute of each estimate, see Keys: Storing and Filtering Metadata for more information about using keys.

[7]:
# display the KeySet of all unique keys in the collection
fit.keys()
[7]:
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
KeySet
List of all the keys in the KeySet
protocol
The characterization protocol used to generate a circuit.
cycles labels twirl
The twirling group used to generate a circuit.
subsystems
The subsystems to analyze for a given protocol.
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),)
  • labels: (0, 1, 2, 3)
  • protocol: CB
  • twirl: Paulis on [0, 1, 2, 3]
CB (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),) (0, 1, 2, 3) Paulis on [0, 1, 2, 3]
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cz, (2, 3): Gate.cz),)
  • labels: (0, 1, 2, 3)
  • protocol: CB
  • twirl: Paulis on [0, 1, 2, 3]
CB (Cycle((0, 1): Gate.cz, (2, 3): Gate.cz),) (0, 1, 2, 3) Paulis on [0, 1, 2, 3]
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),)
  • labels: (0, 1)
  • protocol: IRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
IRB (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),) (0, 1) Cliffords on [(0, 1), (2, 3)]
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),)
  • labels: (2, 3)
  • protocol: IRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
IRB (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),) (2, 3) Cliffords on [(0, 1), (2, 3)]
Key
Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (0,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
IRB (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),) (0,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (1,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
IRB (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),) (1,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (2,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
IRB (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),) (2,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (3,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
IRB (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),) (3,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cx),)
  • labels: (0, 1)
  • protocol: KNR
  • subsystems: ((0, 1),)
  • twirl: Paulis on [0, 1, 2, 3]
KNR (Cycle((0, 1): Gate.cx),) (0, 1) Paulis on [0, 1, 2, 3] ((0, 1),)
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cx),)
  • labels: (2,)
  • protocol: KNR
  • subsystems: ((2,),)
  • twirl: Paulis on [0, 1, 2, 3]
KNR (Cycle((0, 1): Gate.cx),) (2,) Paulis on [0, 1, 2, 3] ((2,),)
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cx),)
  • labels: (3,)
  • protocol: KNR
  • subsystems: ((3,),)
  • twirl: Paulis on [0, 1, 2, 3]
KNR (Cycle((0, 1): Gate.cx),) (3,) Paulis on [0, 1, 2, 3] ((3,),)
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cz),)
  • labels: (0, 1)
  • protocol: KNR
  • subsystems: ((0, 1),)
  • twirl: Paulis on [0, 1, 2, 3]
KNR (Cycle((0, 1): Gate.cz),) (0, 1) Paulis on [0, 1, 2, 3] ((0, 1),)
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cz),)
  • labels: (2,)
  • protocol: KNR
  • subsystems: ((2,),)
  • twirl: Paulis on [0, 1, 2, 3]
KNR (Cycle((0, 1): Gate.cz),) (2,) Paulis on [0, 1, 2, 3] ((2,),)
Key
Key:
  • cycles: (Cycle((0, 1): Gate.cz),)
  • labels: (3,)
  • protocol: KNR
  • subsystems: ((3,),)
  • twirl: Paulis on [0, 1, 2, 3]
KNR (Cycle((0, 1): Gate.cz),) (3,) Paulis on [0, 1, 2, 3] ((3,),)
Key
Key:
  • labels: (0, 1, 2, 3)
  • protocol: RCAL
RCAL (0, 1, 2, 3)
Key
Key:
  • labels: (0,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
SRB (0,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (0, 1)
  • protocol: SRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
SRB (0, 1) Cliffords on [(0, 1), (2, 3)]
Key
Key:
  • labels: (1,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
SRB (1,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (2,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
SRB (2,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (2, 3)
  • protocol: SRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
SRB (2, 3) Cliffords on [(0, 1), (2, 3)]
Key
Key:
  • labels: (3,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
SRB (3,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (0,)
  • protocol: XRB
  • twirl: Cliffords on [0, 1, 2, 3]
XRB (0,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (1,)
  • protocol: XRB
  • twirl: Cliffords on [0, 1, 2, 3]
XRB (1,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (2,)
  • protocol: XRB
  • twirl: Cliffords on [0, 1, 2, 3]
XRB (2,) Cliffords on [0, 1, 2, 3]
Key
Key:
  • labels: (3,)
  • protocol: XRB
  • twirl: Cliffords on [0, 1, 2, 3]
XRB (3,) Cliffords on [0, 1, 2, 3]

Filtering Estimates

As discussed in Filtering Based on Keys, we can filter the list of all estimates by calling subset(). For example, if we only want to display estimates from IRB and SRB, then we can construct an estimate subcollection as follows:

[8]:
fit.subset(protocol={"IRB", "SRB"})
[8]:
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
SRB
Streamlined Randomized Benchmarking
Cliffords
(0,)
Key:
  • labels: (0,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords
(1,)
Key:
  • labels: (1,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords
(2,)
Key:
  • labels: (2,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords
(3,)
Key:
  • labels: (3,)
  • protocol: SRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords
(0, 1)
Key:
  • labels: (0, 1)
  • protocol: SRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
Cliffords
(2, 3)
Key:
  • labels: (2, 3)
  • protocol: SRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
${e}_{F}$
The probability of an error acting on the targeted systems during a random gate.
1.4e-02 (1.1e-03)
0.01391653828711592, 0.0010795258872437275
5.5e-03 (6.6e-04)
0.005536561202176743, 0.0006568852871612455
3.4e-02 (2.8e-03)
0.03415312887922803, 0.0028001633632462404
2.5e-02 (1.8e-03)
0.025473095964427817, 0.0018161792507994975
2.6e-03 (1.0e-03)
0.002601762039577335, 0.0010240744248159247
2.4e-03 (1.1e-03)
0.002382363944565223, 0.0010585819722223053
${p}$
Decay parameter of the exponential decay $Ap^m$.
9.8e-01 (1.4e-03)
0.9814446156171788, 0.0014393678496583031
9.9e-01 (8.8e-04)
0.9926179183970977, 0.0008758470495483274
9.5e-01 (3.7e-03)
0.954462494827696, 0.003733551150994987
9.7e-01 (2.4e-03)
0.9660358720474296, 0.00242157233439933
1.0e+00 (1.1e-03)
0.9972247871577842, 0.0010923460531369865
1.0e+00 (1.1e-03)
0.9974588117924638, 0.0011291541037037924
${A}$
SPAM parameter of the exponential decay $Ap^m$.
1.0e+00 (1.6e-02)
1.0081191480533906, 0.016086395042879585
9.9e-01 (1.2e-02)
0.9882443988640065, 0.012258365474462438
9.9e-01 (3.7e-02)
0.9912653573714596, 0.03736059921035499
1.0e+00 (2.4e-02)
1.0219986696196197, 0.023923893229874614
1.0e+00 (2.0e-02)
1.0048490598466695, 0.020280289099802604
1.0e+00 (1.2e-02)
1.0039477445266856, 0.011683169391265218
IRB
Interleaved Randomized Benchmarking
Cliffords

(0,) : Gate.h

(1,) : Gate.h

(2,) : Gate.h

(3,) : Gate.h

Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (0,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords

(0,) : Gate.h

(1,) : Gate.h

(2,) : Gate.h

(3,) : Gate.h

Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (1,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords

(0,) : Gate.h

(1,) : Gate.h

(2,) : Gate.h

(3,) : Gate.h

Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (2,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords

(0,) : Gate.h

(1,) : Gate.h

(2,) : Gate.h

(3,) : Gate.h

Key:
  • cycles: (Cycle((0,): Gate.h, (1,): Gate.h, (2,): Gate.h, (3,): Gate.h),)
  • labels: (3,)
  • protocol: IRB
  • twirl: Cliffords on [0, 1, 2, 3]
Cliffords

(0, 1) : Gate.cx

(2, 3) : Gate.cx

Key:
  • cycles: (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),)
  • labels: (0, 1)
  • protocol: IRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
Cliffords

(0, 1) : Gate.cx

(2, 3) : Gate.cx

Key:
  • cycles: (Cycle((0, 1): Gate.cx, (2, 3): Gate.cx),)
  • labels: (2, 3)
  • protocol: IRB
  • twirl: Cliffords on [(0, 1), (2, 3)]
${e}_{F}$
The probability of an error acting on the targeted systems during a dressed gate of interest.
2.1e-02 (2.1e-03)
0.021254151861219817, 0.002141592235366376
1.5e-02 (2.1e-03)
0.01516962817236861, 0.0020854164579025467
6.5e-02 (5.5e-03)
0.06474559098251292, 0.005461997398901744
4.9e-02 (4.7e-03)
0.04887125742496573, 0.004703956233372289
2.4e-02 (2.7e-03)
0.023737679704999015, 0.002655614132435191
2.6e-02 (1.9e-03)
0.026379401953861535, 0.0018936331258569425
${e}_{IU}$
An upper bound on the inferred value of $e_F$ that accounts for systematic errors in the interleaved estimate.
2.4e-02 (5.7e-03)
0.023923850659582108, 0.005731086722849162
2.3e-02 (4.9e-03)
0.023497019203954667, 0.00488787583951494
8.8e-02 (1.3e-02)
0.08805139540147058, 0.013244897453832304
7.2e-02 (1.0e-02)
0.07159804094394706, 0.010096433971482162
4.2e-02 (5.4e-03)
0.04188039591928771, 0.0053709958472657115
4.4e-02 (5.1e-03)
0.04442780897861442, 0.005138932765931735
${e}_{IL}$
A lower bound on the inferred value of $e_F$ that accounts for systematic errors in the interleaved estimate.
2.3e-03 (1.5e-03)
0.0023186368629235787, 0.0014698956569548709
4.0e-03 (1.6e-03)
0.003986367981903466, 0.001627710896455018
1.1e-02 (4.5e-03)
0.011380364977091911, 0.004467505778256754
8.0e-03 (3.1e-03)
0.008017651460054731, 0.0031027123206990963
1.1e-02 (2.7e-03)
0.010666733342741576, 0.0027335783109593867
1.3e-02 (2.8e-03)
0.012961652767904987, 0.0027994747795645376
${p}$
Decay parameter of the exponential decay $Ap^m$.
9.7e-01 (2.9e-03)
0.9716611308517069, 0.002855456313821835
9.8e-01 (2.8e-03)
0.9797738291035085, 0.0027805552772033957
9.1e-01 (7.3e-03)
0.9136725453566494, 0.007282663198535658
9.3e-01 (6.3e-03)
0.934838323433379, 0.006271941644496386
9.7e-01 (2.8e-03)
0.9746798083146677, 0.002832655074597537
9.7e-01 (2.0e-03)
0.9718619712492144, 0.0020198753342474053
${A}$
SPAM parameter of the exponential decay $Ap^m$.
9.6e-01 (2.0e-02)
0.963718966377361, 0.02033187561014349
1.0e+00 (2.0e-02)
1.0013968018075445, 0.019538597226725955
9.6e-01 (4.1e-02)
0.9581570360443663, 0.04052246467539697
1.0e+00 (3.5e-02)
1.0164589920295148, 0.035172766023475896
1.0e+00 (2.2e-02)
1.030988044505585, 0.022118973593051892
1.0e+00 (2.0e-02)
1.0218968865492961, 0.01955123113846099

Finding Particular Estimates

Estimate collections, such as the one called fit being considered in this guide, often contain many individual estimate objects. Looping through these objects and manually checking conditions in order to extract certain desired data can be tedious, and therefore this section and the next section Extracting Arrays and Dataframes highlight methods that simplify this process.

The simplest is the method one_or_none() which can be used to extract a single estimate given enough information to uniquely identify it in the collection. For example, below we extract the SRB estimate for the qubit labeled 2 by providing the protocol name and the label subset. If we didn’t provide either of these values, the request would be ambiguous and None would be returned. One can display the key table to figure out the available keynames and values to match against.

[9]:
est = fit.one_or_none(protocol="SRB", labels=(2,))

# the infidelity of the estimate we found
est.e_F
[9]:
EstimateTuple(name='e_F', val=0.03415312887922803, std=0.0028001633632462404)

In practice, this might be used in a loop in combination with subset() and keys(), as in the following example.

[10]:
# identify all twirling groups used by SRB and loop through them
twirls = fit.subset(protocol="SRB").keys().twirl
for twirl in twirls:
    print(f"SRB Twirl: {twirl}")
    # get the estimates associated with SRB and this twirling group
    subset = fit.subset(protocol="SRB", twirl=twirl)
    # find out the labels in these estimates and loop through them
    for labels in sorted(subset.keys().labels):
        est = subset.one_or_none(labels=labels)
        print(f"{str(labels):>10}: {est.e_F.val:.2g}")
    print("")
SRB Twirl: Cliffords on [(0, 1), (2, 3)]
    (0, 1): 0.0026
    (2, 3): 0.0024

SRB Twirl: Cliffords on [0, 1, 2, 3]
      (0,): 0.014
      (1,): 0.0055
      (2,): 0.034
      (3,): 0.025

The contents of fit will generally match the order of the circuits encountered inside of the circuit collection, though this is not guaranteed. We can produce new estimate collections that are sorted according to provided keynames.

[11]:
sorted_fit = fit.sorted("protocol", "labels")
sorted_fit[-1]
[11]:
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
XRB
Extended Randomized Benchmarking
Cliffords
(3,)
Key:
  • labels: (3,)
  • protocol: XRB
  • twirl: Cliffords on [0, 1, 2, 3]
${e}_{U}$
The process infidelity of the coherent error acting on the specifed systems during a random gate.
8.0e-03 (2.1e-03)
0.007960019013382946, 0.002106463125883527
${e}_{S}$
The probability of a stochastic error acting on the specified systems during a random gate.
1.8e-02 (1.1e-03)
0.01751307695104487, 0.0010670894197171933
${u}$
The unitarity of the noise, that is, the average decrease in the purity of an initial state.
9.5e-01 (2.8e-03)
0.9537074052829381, 0.0027957370682561073
${A}$
SPAM parameter of the exponential decay $Au^m$.
1.1e+00 (3.5e-02)
1.088319857580238, 0.03531413974234409

Extracting Arrays and Dataframes

The contents of an estimate collection can generally be quite ragged, containing different types of estimates with different sizes from different protocols with different parameters of interest. Therefore, estimate collections themselves are not generally conducive to rectangular data storage formats.

However, you may know that a rectangular structure of data exists within your particular estimate collection. The array() method exists to extract these (nearly-) rectangular data.

The first argument is mandatory and specifies a parameter name (or name pattern) to extract. A parameter name is a string like "e_F" (infidelity), and a name pattern is a string like "e_." specifying a regular expression for all parameter names to match. In the latter case, one axis of the extracted array will sweep over the parameter names that were matched. The remaining arguments must be keynames, and they define the subsequent axes of the extracted array, where each axis is indexed by the values of that keyname present in the collection.

In the first example, we extract an array of infidelity estimates ("e_F") for the IRB and SRB protocols, where the first axis is over protocols, and the second is over qubit labels. We can consult the key table to see which keywords and values are available.

[12]:
array = fit.subset(protocol={"IRB", "SRB"}).array("e_F", "protocol", "labels")
array
[12]:
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
labels (0,) (0, 1) (1,) (2,) (2, 3) (3,)
protocol
IRB 2.13e-02 (2.14e-03)
val=0.0212542
std=0.00214159
2.37e-02 (2.66e-03)
val=0.0237377
std=0.00265561
1.52e-02 (2.09e-03)
val=0.0151696
std=0.00208542
6.47e-02 (5.46e-03)
val=0.0647456
std=0.005462
2.64e-02 (1.89e-03)
val=0.0263794
std=0.00189363
4.89e-02 (4.70e-03)
val=0.0488713
std=0.00470396
SRB 1.39e-02 (1.08e-03)
val=0.0139165
std=0.00107953
2.60e-03 (1.02e-03)
val=0.00260176
std=0.00102407
5.54e-03 (6.57e-04)
val=0.00553656
std=0.000656885
3.42e-02 (2.80e-03)
val=0.0341531
std=0.00280016
2.38e-03 (1.06e-03)
val=0.00238236
std=0.00105858
2.55e-02 (1.82e-03)
val=0.0254731
std=0.00181618

Here, array is an EstimateArray instance that has the attribute vals which is a NumPy array of estimate values, the attribute stds which is a NumPy array of the same shape containing associated standard deviations of the estimates, and the attribute axes which is a tuple of ArrayAxis instances detailing each axis.

[13]:
# get the estimate value at this index
array.vals[1, 3]
[13]:
0.03415312887922803
[14]:
# display the axis information
array.axes
[14]:
(ArrayAxis('protocol', ('IRB', 'SRB')),
 ArrayAxis('labels', ((0,), (0, 1), (1,), (2,), (2, 3), (3,))))

If the optional dependency pandas is installed, then the array can be converted to a dataframe.

[15]:
array.to_dataframe()
[15]:
labels (0,) (0, 1) (1,) (2,) (2, 3) (3,)
val std val std val std val std val std val std
protocol
IRB 0.021254 0.002142 0.023738 0.002656 0.015170 0.002085 0.064746 0.005462 0.026379 0.001894 0.048871 0.004704
SRB 0.013917 0.001080 0.002602 0.001024 0.005537 0.000657 0.034153 0.002800 0.002382 0.001059 0.025473 0.001816

In the second example, we use the name pattern "e__[XY]" to match single-qubit X and Y errors from our KNR data. Since we have KNR data for two different cycles, we add "cycles" as an axis in addition to the qubit label. Note that, in contrast to the previous example, since multiple parameter names match the pattern, the parameter name itself will be the 0’th axis (or some other axis if name_axis is specified) of this 3-D array. Note that for the purpose of presenting a fancy view of the array in notebooks, the last index of the array appears as columns, while the remaining axes are flattened into rows.

[16]:
fit.subset(protocol={"KNR"}).array("e__[XY]", "labels", "cycles")
[16]:
True-Q formatting will not be loaded without trusting this notebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking "File -> Trust Notebook".
cycles (Cycle((0, 1): Gate.cx),) (Cycle((0, 1): Gate.cz),)
name labels
e__X (2,) 1.39e-03 (1.69e-03)
val=0.00139419
std=0.00168674
2.48e-03 (1.49e-03)
val=0.00247699
std=0.00148707
(3,) 2.56e-03 (1.17e-03)
val=0.00256457
std=0.00117239
1.42e-03 (1.32e-03)
val=0.00142324
std=0.00132022
e__Y (2,) 1.44e-03 (1.69e-03)
val=0.00143529
std=0.00168674
-5.38e-05 (1.49e-03)
val=-5.37676e-05
std=0.00148707
(3,) 2.07e-03 (1.17e-03)
val=0.00207475
std=0.00117239
1.25e-03 (1.32e-03)
val=0.00125226
std=0.00132022

Finally, note that the extracted arrays were perfectly (hyper-)rectangular in the previous two examples. If this is not the case, instead of failing, the array() method will place a numpy.nan value in every entry with no corresponding estimate. In the following example, the SRB and IRB protocols don’t have a parameter named "e_S", and therefore the corresponding array entries are NaN.

[17]:
array = fit.subset(protocol={"IRB", "SRB", "XRB"}).array("e_.", "protocol", "labels")
[18]:
array.vals[0, 2, 0]
[18]:
nan

KNR Data Tables

KNR results can be displayed as a heatmap as a part of the plotting suite.

[19]:
fit.plot.knr_heatmap(graph=tq.visualization.Graph.linear(range(4)), cutoff=0)
Warning: The set_constrained_layout_pads function will be deprecated in a future version. Use figure.get_layout_engine().set() instead.
         (/home/jenkins/workspace/release trueq legacy/trueq/visualization/plotters/nr.py:197)
../../_images/guides_fundamentals_estimate_collections_33_1.png

KNR estimates are no different than any other estimate and can be extracted using any of the methods outlined in earlier sections. For reference, one estimate object is constructed for every marginal distribution. For example, one estimate object might contain errors for I, X, Y, and Z for some particular single-qubit subsystem. In the heatmap, these appear as colums of sub-blocks, possibly with some entries missing if they are below the cutoff.

However, you might also be interested in extracting the numbers in an order exactly as shown in the heatmap. First note, as seen in this example, that these heatmaps need not be rectangular; differing degeneracies across gates can cause discrepancies in the y-axis labels. However, we can access sub-rectangles of data using the class KnrDataTable, which is used by the heatmap to organize data, and can also be used by you.

[20]:
table = tq.estimate.KnrDataTable(fit)
# if necessary, set the truncation level, which will affect the amount of data shown
table.set_truncation(0)

If we access the top-left cell of data, we see that it has 3 rows for the three Pauli errors, and two columns, one for each idling subsystem.

[21]:
# access the top-left cell seen in the figure
table.get_cell(0, 0)
[21]:
Cell(mean=array([[0.03186351, 0.0211295 ],
       [0.00139419, 0.00256457],
       [0.00143529, 0.00207475]]), std=array([[0.00168674, 0.00117239],
       [0.00168674, 0.00117239],
       [0.00168674, 0.00117239]]), subcycles=[{(2,): Gate.id}, {(3,): Gate.id}])
[22]:
# access the exterior x-axis information of the first column
table.col_info[0]
[22]:
Col(name='', cycles=(Cycle((0, 1): Gate.cx),), twirl=Twirl({(0,): 'P', (1,): 'P', (2,): 'P', (3,): 'P'}, dim=2))
[23]:
# access the exterior y-axis information of the top row
table.row_info[0]
[23]:
Row(sort_key=(False, 1, (1,)), degens=[(('Z',),), (('X',),), (('Y',),)], param_names=['e__Z', 'e__X', 'e__Y'], latex=['$e_{Z}$', '$e_{X}$', '$e_{Y}$'])

Download

Download this file as Jupyter notebook: estimate_collections.ipynb.