Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions pygsti/algorithms/gaugeopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
TrivialGaugeGroupElement as _TrivialGaugeGroupElement,
GaugeGroupElement as _GaugeGroupElement
)
from pygsti.models import ExplicitOpModel
from pygsti.modelmembers.operations import LinearOperator as _LinearOperator

from typing import Callable, Union, Optional

Expand Down Expand Up @@ -360,8 +362,10 @@ def _call_jacobian_fn(gauge_group_el_vec):

GGElJacobian = Union[None, Callable[[_GaugeGroupElement], _np.ndarray]]

LabelLike = Union[str, _baseobjs.Label]

def _create_objective_fn(model, target_model, item_weights: Optional[dict[str,float]]=None,

def _create_objective_fn(model, target_model, item_weights: Optional[dict[LabelLike, float]]=None,
cptp_penalty_factor: float=0.0, spam_penalty_factor: float=0.0,
gates_metric="frobenius", spam_metric="frobenius",
method=None, comm=None, check_jac=False, n_leak=0) -> tuple[GGElObjective, GGElJacobian]:
Expand Down Expand Up @@ -625,8 +629,14 @@ def _mock_objective_fn(v):
# ^ It would be equivalent to set this to a pair of IdentityOperator objects.

def _objective_fn(gauge_group_el, oob_check):
mdl = _transform_with_oob_check(model, gauge_group_el, oob_check)
ret = 0
mdl : ExplicitOpModel = _transform_with_oob_check(model, gauge_group_el, oob_check)
mdl_ops : dict[_baseobjs.Label, _LinearOperator] = mdl._excalc().operations
tgt_ops : dict[_baseobjs.Label, _LinearOperator] = dict()
if target_model is not None:
tgt_ops.update(target_model._excalc().operations)
# ^ Use these dicts instead of mdl.operations and target_model.operations,
# since these dicts are updated to include instruments.
ret = 0.0

if cptp_penalty_factor > 0:
mdl.basis = mxBasis # set basis for jamiolkowski iso
Expand All @@ -645,30 +655,27 @@ def _objective_fn(gauge_group_el, oob_check):
if spam_metric == gates_metric:
val = mdl.frobeniusdist(target_model, transform_mx_arg, item_weights)
else:
wts = item_weights.copy()
wts['spam'] = 0.0
for k in wts:
if k in mdl.preps or k in mdl.povms:
wts[k] = 0.0
val = mdl.frobeniusdist(target_model, transform_mx_arg, wts, n_leak)
non_gates = {'spam'}.union(set(mdl.preps)).union(set(mdl.povms))
temp_wts = {k: (0.0 if k in non_gates else v) for (k, v) in item_weights.items()}
val = mdl.frobeniusdist(target_model, transform_mx_arg, temp_wts)
if "squared" in gates_metric:
val = val ** 2
ret += val

elif gates_metric == "fidelity":
# If n_leak==0, then subspace_entanglement_fidelity is just entanglement_fidelity
for opLbl in mdl.operations:
for opLbl in mdl_ops:
wt = item_weights.get(opLbl, opWeight)
top = target_model.operations[opLbl].to_dense()
mop = mdl.operations[opLbl].to_dense()
top = tgt_ops[opLbl].to_dense()
mop = mdl_ops[opLbl].to_dense()
ret += wt * (1.0 - _tools.subspace_entanglement_fidelity(top, mop, mxBasis, n_leak))**2

elif gates_metric == "tracedist":
# If n_leak==0, then subspace_jtracedist is just jtracedist.
for opLbl in mdl.operations:
for opLbl in mdl_ops:
wt = item_weights.get(opLbl, opWeight)
top = target_model.operations[opLbl].to_dense()
mop = mdl.operations[opLbl].to_dense()
top = tgt_ops[opLbl].to_dense()
mop = mdl_ops[opLbl].to_dense()
ret += wt * _tools.subspace_jtracedist(top, mop, mxBasis, n_leak)

else:
Expand All @@ -680,11 +687,9 @@ def _objective_fn(gauge_group_el, oob_check):

if "frobenius" in spam_metric:
# SPAM and gates can have different choices for squared vs non-squared.
wts = item_weights.copy(); wts['gates'] = 0.0
for k in wts:
if k in mdl.operations or k in mdl.instruments:
wts[k] = 0.0
val = mdl.frobeniusdist(target_model, transform_mx_arg, wts)
non_spam = {'gates'}.union(set(mdl_ops)) # use mdl_ops, not mdl.operations!
temp_wts = {k: (0.0 if k in non_spam else v) for (k, v) in item_weights.items()}
val = mdl.frobeniusdist(target_model, transform_mx_arg, temp_wts)
if "squared" in spam_metric:
val = val ** 2
ret += val
Expand Down
6 changes: 3 additions & 3 deletions pygsti/data/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,18 +575,18 @@ def _get_counts(self, timestamp=None, all_outcomes=False):
cntDict.setitem_unsafe(ol, cnt)
else:
for ol, i in self.dataset.olIndex.items():
inds = oli_tslc[oli_tslc == i]
inds = _np.where(oli_tslc == i)[0]
if len(inds) > 0 or all_outcomes:
cntDict.setitem_unsafe(ol, float(sum(self.reps[tslc][inds])))
else:
if self.reps is None:
for ol_index in oli_tslc:
ol = self.dataset.ol[ol_index]
cntDict.setitem_unsafe(ol, 1.0 + cntDict.getitem_unsafe(ol, 0.0))
cntDict.setitem_unsafe(ol, float(1.0 + cntDict.getitem_unsafe(ol, 0.0)))
else:
for ol_index, reps in zip(oli_tslc, self.reps[tslc]):
ol = self.dataset.ol[ol_index]
cntDict.setitem_unsafe(ol, reps + cntDict.getitem_unsafe(ol, 0.0))
cntDict.setitem_unsafe(ol, float(reps + cntDict.getitem_unsafe(ol, 0.0)))

return cntDict

Expand Down
20 changes: 9 additions & 11 deletions pygsti/modelmembers/operations/linearop.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,8 @@ def jtracedist(self, other_op, transform=None, inv_transform=None):
if transform is None and inv_transform is None:
return _ot.jtracedist(self.to_dense("minimal"), other_op.to_dense("minimal"))
else:
return _ot.jtracedist(_np.dot(
inv_transform, _np.dot(self.to_dense("minimal"), transform)),
other_op.to_dense("minimal"))
arg = inv_transform @ self.to_dense("minimal") @ transform
return _ot.jtracedist(arg, other_op.to_dense("minimal"))

def diamonddist(self, other_op, transform=None, inv_transform=None):
"""
Expand All @@ -535,9 +534,8 @@ def diamonddist(self, other_op, transform=None, inv_transform=None):
if transform is None and inv_transform is None:
return _ot.diamonddist(self.to_dense("minimal"), other_op.to_dense("minimal"))
else:
return _ot.diamonddist(_np.dot(
inv_transform, _np.dot(self.to_dense("minimal"), transform)),
other_op.to_dense("minimal"))
arg = inv_transform @ self.to_dense("minimal") @ transform
return _ot.diamonddist(arg, other_op.to_dense("minimal"))

def transform_inplace(self, s):
"""
Expand All @@ -563,7 +561,7 @@ def transform_inplace(self, s):
"""
Smx = s.transform_matrix
Si = s.transform_matrix_inverse
self.set_dense(_np.dot(Si, _np.dot(self.to_dense("minimal"), Smx)))
self.set_dense(Si @ self.to_dense("minimal") @ Smx)

def spam_transform_inplace(self, s, typ):
"""
Expand Down Expand Up @@ -591,9 +589,9 @@ def spam_transform_inplace(self, s, typ):
None
"""
if typ == 'prep':
self.set_dense(_np.dot(s.transform_matrix_inverse, self.to_dense("minimal")))
self.set_dense(s.transform_matrix_inverse @ self.to_dense("minimal"))
elif typ == 'effect':
self.set_dense(_np.dot(self.to_dense("minimal"), s.transform_matrix))
self.set_dense(self.to_dense("minimal") @ s.transform_matrix)
else:
raise ValueError("Invalid `typ` argument: %s" % typ)

Expand Down Expand Up @@ -627,7 +625,7 @@ def depolarize(self, amount):
else:
assert(len(amount) == self.dim - 1)
D = _np.diag([1] + list(1.0 - _np.array(amount, 'd')))
self.set_dense(_np.dot(D, self.to_dense("minimal")))
self.set_dense(D @ self.to_dense("minimal"))

def rotate(self, amount, mx_basis="gm"):
"""
Expand Down Expand Up @@ -658,7 +656,7 @@ def rotate(self, amount, mx_basis="gm"):
None
"""
rotnMx = _ot.rotation_gate_mx(amount, mx_basis)
self.set_dense(_np.dot(rotnMx, self.to_dense("minimal")))
self.set_dense(rotnMx @ self.to_dense("minimal"))

def deriv_wrt_params(self, wrt_filter=None):
"""
Expand Down
Loading
Loading