-
Notifications
You must be signed in to change notification settings - Fork 57
Description
EDIT: versions of the functions below were merged in as part of PR #410. I'm sure work remains on this issue (e.g., points raised by Corey below) so I'm leaving it open.
Consider the following fact.
Let
$M_1$ be a model (e.g., an ExplicitOpModel) with parameterization$P_1$ (e.g., "CPTPLND" or "full TP"). Next, let$M_2$ be the representation of$M_1$ under a parameterization$P_2$ , where$P_2$ allows for a strictly larger hypothesis class than does$P_1$ .We can't, in general, get confidence intervals for
$M_1$ by looking at the likelihood function for$M_2$ .
This fact is troublesome for computing confidence intervals of gauge-dependent quantities, since pyGSTi's gauge optimization tends to be performed in an expanded hypothesis class. This is the case even if we do gauge optimization on a CPTP model (CPTPLND parameterization) over the unitary group.
It's nominally straightforward to avoid this issue by gauge optimizing in whatever parameterization we want (e.g., Full), getting the gauge transformation, and then substituting modelmembers with suitably-transformed versions of themselves. The transformation + substitution can be facilitated with ComposedState, ComposedOp, and ComposedPOVM, as shown in the following code.
def transform_composedop_model(mdl : ExplicitOpModel, s : GaugeGroupElement):
oldmdl = mdl
mdl = oldmdl.copy()
U = StaticArbitraryOp(s.transform_matrix, basis=oldmdl.basis)
invU = StaticArbitraryOp(s.transform_matrix_inverse, basis=oldmdl.basis)
for key, rho in oldmdl.preps.items():
assert isinstance(rho, ComposedState)
static_rho = rho.state_vec
errmap = ComposedOp([rho.error_map, invU])
mdl.preps[key] = ComposedState(static_rho, errmap)
for key, povm in oldmdl.povms.items():
assert isinstance(povm, ComposedPOVM)
static_povm = povm.base_povm
errmap = ComposedOp([U, povm.error_map])
mdl.povms[key] = ComposedPOVM(errmap, static_povm, mx_basis=oldmdl.basis)
for key, op in oldmdl.operations.items():
op_s = ComposedOp([U, op, invU])
mdl.operations[key] = op_s
assert len(oldmdl.factories) == 0
assert len(oldmdl.instruments) == 0
mdl._clean_paramvec() # transform may leave dirty members
return mdl
A whole gauge optimization pipeline could look something like this.
def add_param_preserving_gauge_opt(results: ModelEstimateResults, est_key: str, gop_params: GSTGaugeOptSuite):
from pygsti.protocols.gst import _add_gauge_opt
est = results.estimates[est_key]
seed_mdl = est.models['final iteration estimate']
_add_gauge_opt(results, est_key, gop_params, seed_mdl)
# ^ That can convert to whatever parameterization it wants. It'll write to
# est._gaugeopt_suite.
gop_params_dict = gop_params.to_dictionary(seed_mdl)
# ^ If we modified _add_gauge_opt to accept both GSTGaugeOptSuite objects and
# the output of the .to_dictionary(...) method of such objects, then we could avoid
# this awkward call to .to_dictionary(...) after the call to _add_gauge_opt.
for gop_name in gop_params_dict.keys():
ggel = est._gaugeopt_suite.gaugeopt_argument_dicts[gop_name]['_gaugeGroupEl']
model_implicit_gauge = transform_composed_model(est.models['final iteration estimate'], ggel)
est.models[gop_name] = model_implicit_gauge
return
I want to integrate this into pyGSTi's default gauge optimization procedures that get executed when run(...)
is called on a GateSetTomography object. For example, maybe we allow passing gaugeopt_suite='stdgaugeopt-keep-params'
to the GateSetTomography constructor, and we get behavior that's just like if we used gaugeopt_suite='stdgaugeopt'
without having to accept the change in model parameterization.
Here are some observations for myself as I try to sort this out.
- GateSetTomography.run calls _add_gaugeopt_and_badfit, which calls _add_gauge_opt and _add_badfit_estimates. Meanwhile, _add_badfit_estimates can call _add_gauge_opt.
- If we look at _add_gauge_opt we see that it takes in a GSTGaugeOptSuite object, which it immediately converts to a dict representation with a call to the object's
.to_dictionary
function (note: that function requires that we specify a starting model for gauge optimization, since no models are stored in GSTGaugeOptSuite objects). Then _add_gauge_opt makes calls to the add_gaugeoptimized instance function of Estimate objects from the.estimates
field ofresults
(which is a ModelEstimateResults object).