Skip to content

Commit 3690893

Browse files
authored
Merge pull request #527 from sandialabs/feature-instrument-wildcard
Wildcard Support for Instruments
2 parents d5a3421 + d3be117 commit 3690893

File tree

2 files changed

+126
-29
lines changed

2 files changed

+126
-29
lines changed

pygsti/protocols/gst.py

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,43 +2294,41 @@ def _add_badfit_estimates(results, base_estimate_label, badfit_options,
22942294
def _compute_wildcard_budget_1d_model(estimate, objfn_cache, mdc_objfn, parameters, badfit_options, verbosity, gaugeopt_suite=None):
22952295
"""
22962296
Create a wildcard budget for a model estimate. This version of the function produces a wildcard estimate
2297-
using the model introduced by Tim and Stefan in the RCSGST paper.
2298-
TODO: docstring (update)
2297+
using the model introduced in https://doi.org/10.1038/s41534-023-00764-y.
22992298
23002299
Parameters
23012300
----------
2302-
model : Model
2303-
The model to add a wildcard budget to.
2301+
estimate : Estimate
2302+
The estimate object containing the model and data to be used.
23042303
2305-
ds : DataSet
2306-
The data the model predictions are being compared with.
2304+
objfn_cache : ObjectiveFunctionCache
2305+
A cache for objective function evaluations.
23072306
2308-
circuits_to_use : list
2309-
The circuits whose data are compared.
2307+
mdc_objfn : ModelDatasetCircuitsStore
2308+
An object that stores the model, dataset, and circuits to be used in the computation.
23102309
23112310
parameters : dict
23122311
Various parameters of the estimate at hand.
23132312
23142313
badfit_options : GSTBadFitOptions, optional
23152314
Options specifying what post-processing actions should be performed when
2316-
a fit is unsatisfactory. Contains detailed parameters for wildcard budget
2315+
a fit is unsatisfactory. Contains detailed parameters for wildcard budget
23172316
creation.
23182317
2319-
comm : mpi4py.MPI.Comm, optional
2320-
An MPI communicator used to run this computation in parallel.
2321-
2322-
mem_limit : int, optional
2323-
A rough per-processor memory limit in bytes.
2324-
23252318
verbosity : int, optional
23262319
Level of detail printed to stdout.
2327-
2320+
23282321
gaugeopt_suite : GSTGaugeOptSuite, optional (default None)
2329-
The 1-D wildcard models can be based on gauge-variant functions such as the diamond distance. When gauge optimization is applied this will ensure the gauge optimized models used are consistent in the wildcard model and the parent estimates.
2322+
The 1-D wildcard models can be based on gauge-variant functions such as the diamond distance.
2323+
When gauge optimization is applied, this will ensure the gauge optimized models used are consistent
2324+
in the wildcard model and the parent estimates.
23302325
23312326
Returns
23322327
-------
2333-
PrimitiveOpsWildcardBudget
2328+
PrimitiveOpsWildcardBudget or dict
2329+
The computed wildcard budget. If gauge optimization is applied, a dictionary of
2330+
budgets keyed by gauge optimization labels is returned.
2331+
23342332
"""
23352333
printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, mdc_objfn.resource_alloc)
23362334
badfit_options = GSTBadFitOptions.cast(badfit_options)
@@ -2387,9 +2385,32 @@ def _compute_wildcard_budget_1d_model(estimate, objfn_cache, mdc_objfn, paramete
23872385

23882386

23892387
def _compute_1d_reference_values_and_name(estimate, badfit_options, gaugeopt_suite=None):
2390-
'''
2391-
DOCSTRING: TODO
2392-
'''
2388+
"""
2389+
Compute the reference values and name for the 1D wildcard budget.
2390+
2391+
Parameters
2392+
----------
2393+
estimate : Estimate
2394+
The estimate object containing the models to be used.
2395+
2396+
badfit_options : GSTBadFitOptions
2397+
Options specifying what post-processing actions should be performed when
2398+
a fit is unsatisfactory. Contains detailed parameters for wildcard budget
2399+
creation.
2400+
2401+
gaugeopt_suite : GSTGaugeOptSuite, optional (default None)
2402+
The gauge optimization suite used by the estimate. If None, final iteration
2403+
estimate will be used.
2404+
2405+
Returns
2406+
-------
2407+
dict or dict of dicts
2408+
The computed reference values for the 1D wildcard budget. If gauge optimization is applied,
2409+
a dictionary of reference values keyed by gauge optimization labels is returned.
2410+
2411+
str
2412+
The name of the reference metric used.
2413+
"""
23932414
if badfit_options.wildcard1d_reference == 'diamond distance':
23942415
if gaugeopt_suite is None or gaugeopt_suite.gaugeopt_suite_names is None:
23952416
final_model = estimate.models['final iteration estimate']
@@ -2398,10 +2419,13 @@ def _compute_1d_reference_values_and_name(estimate, badfit_options, gaugeopt_sui
23982419
if isinstance(final_model, _ExplicitOpModel):
23992420
gaugeopt_model = _alg.gaugeopt_to_target(final_model, target_model)
24002421
operations_dict = gaugeopt_model.operations
2401-
targetops_dict = target_model.operations
2422+
targetops_dict = target_model.operations
24022423
preps_dict = gaugeopt_model.preps
24032424
targetpreps_dict = target_model.preps
24042425
povmops_dict = gaugeopt_model.povms
2426+
insts_dict = gaugeopt_model.instruments
2427+
targetinsts_dict = target_model.instruments
2428+
24052429
else:
24062430
# Local/cloud noise models don't have default_gauge_group attribute and can't be gauge
24072431
# optimized - at least not easily.
@@ -2419,6 +2443,14 @@ def _compute_1d_reference_values_and_name(estimate, badfit_options, gaugeopt_sui
24192443
_warnings.warn(("Diamond distance failed to compute %s reference value for 1D wildcard budget!"
24202444
" Falling back to trace distance.") % str(key))
24212445
dd[key] = _tools.jtracedist(op.to_dense(), targetops_dict[key].to_dense())
2446+
2447+
for key, op in insts_dict.items():
2448+
inst_dd = .5* _tools.instrument_diamonddist(op, targetinsts_dict[key])
2449+
if inst_dd < 0: # indicates that instrument_diamonddist failed
2450+
_warnings.warn(("Diamond distance failed to compute %s reference value for 1D wildcard budget!"
2451+
"No fallback presently available for instruments, so skipping.") % str(key))
2452+
else:
2453+
dd[key] = inst_dd
24222454

24232455
spamdd = {}
24242456
for key, op in preps_dict.items():
@@ -2444,15 +2476,22 @@ def _compute_1d_reference_values_and_name(estimate, badfit_options, gaugeopt_sui
24442476
" Falling back to trace distance.") % str(key))
24452477
dd[lbl][key] = _tools.jtracedist(op.to_dense(), target_model.operations[key].to_dense())
24462478

2447-
spamdd = {}
2448-
for key, op in gaugeopt_model.preps.items():
2449-
spamdd[key] = _tools.tracedist(_tools.vec_to_stdmx(op.to_dense(), 'pp'),
2450-
_tools.vec_to_stdmx(target_model.preps[key].to_dense(), 'pp'))
2479+
for key, op in gaugeopt_model.instruments.items():
2480+
inst_dd = .5* _tools.instrument_diamonddist(op, target_model.instruments[key], gaugeopt_model.basis)
2481+
if inst_dd < 0: # indicates that instrument_diamonddist failed
2482+
_warnings.warn(("Diamond distance failed to compute %s reference value for 1D wildcard budget!"
2483+
"No fallback presently available for instruments, so skipping.") % str(key))
2484+
else:
2485+
dd[lbl][key] = inst_dd
2486+
spamdd = {}
2487+
for key, op in gaugeopt_model.preps.items():
2488+
spamdd[key] = _tools.tracedist(_tools.vec_to_stdmx(op.to_dense(), 'pp'),
2489+
_tools.vec_to_stdmx(target_model.preps[key].to_dense(), 'pp'))
24512490

2452-
for key in gaugeopt_model.povms.keys():
2453-
spamdd[key] = 0.5 * _tools.optools.povm_diamonddist(gaugeopt_model, target_model, key)
2491+
for key in gaugeopt_model.povms.keys():
2492+
spamdd[key] = 0.5 * _tools.optools.povm_diamonddist(gaugeopt_model, target_model, key)
24542493

2455-
dd[lbl]['SPAM'] = sum(spamdd.values())
2494+
dd[lbl]['SPAM'] = sum(spamdd.values())
24562495
return dd, 'diamond distance'
24572496
else:
24582497
raise ValueError("Invalid wildcard1d_reference value (%s) in bad-fit options!"

pygsti/tools/optools.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,64 @@ def povm_diamonddist(model, target_model, povmlbl):
969969
target_povm_mx = compute_povm_map(target_model, povmlbl)
970970
return diamonddist(povm_mx, target_povm_mx, target_model.basis)
971971

972+
def instrument_infidelity(a, b, mx_basis):
973+
"""
974+
Infidelity between instruments a and b
975+
976+
Parameters
977+
----------
978+
a : Instrument
979+
The first instrument.
980+
981+
b : Instrument
982+
The second instrument.
983+
984+
mx_basis : Basis or {'pp', 'gm', 'std'}
985+
the basis that `a` and `b` are in.
986+
987+
Returns
988+
-------
989+
float
990+
"""
991+
sqrt_component_fidelities = [_np.sqrt(entanglement_fidelity(a[l], b[l], mx_basis))
992+
for l in a.keys()]
993+
return 1 - sum(sqrt_component_fidelities)**2
994+
995+
996+
def instrument_diamonddist(a, b, mx_basis):
997+
"""
998+
The diamond distance between instruments a and b.
999+
1000+
Parameters
1001+
----------
1002+
a : Instrument
1003+
The first instrument.
1004+
1005+
b : Instrument
1006+
The second instrument.
1007+
1008+
mx_basis : Basis or {'pp', 'gm', 'std'}
1009+
the basis that `a` and `b` are in.
1010+
1011+
Returns
1012+
-------
1013+
float
1014+
"""
1015+
#Turn instrument into a CPTP map on qubit + classical space.
1016+
adim = a.state_space.dim
1017+
mx_basis = _Basis.cast(mx_basis, dim=adim)
1018+
nComps = len(a.keys())
1019+
sumbasis = _DirectSumBasis([mx_basis] * nComps)
1020+
composite_op = _np.zeros((adim * nComps, adim * nComps), 'd')
1021+
composite_top = _np.zeros((adim * nComps, adim * nComps), 'd')
1022+
for i, clbl in enumerate(a.keys()):
1023+
aa, bb = i * adim, (i + 1) * adim
1024+
for j in range(nComps):
1025+
cc, dd = j * adim, (j + 1) * adim
1026+
composite_op[aa:bb, cc:dd] = a[clbl].to_dense(on_space='HilbertSchmidt')
1027+
composite_top[aa:bb, cc:dd] = b[clbl].to_dense(on_space='HilbertSchmidt')
1028+
return diamonddist(composite_op, composite_top, sumbasis)
1029+
9721030

9731031
#decompose operation matrix into axis of rotation, etc
9741032
def decompose_gate_matrix(operation_mx):

0 commit comments

Comments
 (0)