@@ -619,8 +619,6 @@ def _mock_objective_fn(v):
619619
620620 assert gates_metric != "frobeniustt"
621621 assert spam_metric != "frobeniustt"
622- assert spam_metric == gates_metric
623- metric = spam_metric
624622 # assert spam_metric == gates_metric
625623 # ^ Erik and Corey said these are rarely used. I've removed support for
626624 # them in this codepath (non-LS optimizer) in order to make it easier to
@@ -641,73 +639,103 @@ def _objective_fn(gauge_group_el, oob_check):
641639 spamPenaltyVec = _spam_penalty (mdl , spam_penalty_factor , mdl .basis )
642640 ret += _np .sum (spamPenaltyVec )
643641
644- assert target_model is not None
645- """
646- Leakage-aware metric supported, per implementation in mdl.frobeniusdist.
647- Refer to how mdl.frobeniusdist handles the case when transform_mx_arg
648- is a tuple in order to understand how the leakage-aware metric is defined.
649-
650- Idea: raise an error if mxBasis isn't leakage-friendly.
651- PROBLEM: if we're deep in the code then we end up needing to be
652- working in a basis that has the identity matrix as its
653- first element. The leakage-friendly basis doesn't even
654- have the identity matrix as an element, let alone the first element
655-
656- TODO: dig into function calls below and see where we can
657- access the mxBasis object. (I'm sure we can.)
658- Looks like it isn't accessible within ExplicitOpModelCalc objects.
659- It's most definitely available in ExplicitOpModel.
660- """
661- if "frobenius" in metric :
662- val = mdl .frobeniusdist (target_model , transform_mx_arg , item_weights )
663- if "squared" in metric :
664- val = val ** 2
665- ret += val
666- return ret
667-
668- elif metric == "fidelity" :
669- # Leakage-aware metric supported for gates, using leaky_entanglement_fidelity.
670- for opLbl in mdl .operations :
671- wt = item_weights .get (opLbl , opWeight )
672- top = target_model .operations [opLbl ].to_dense ()
673- mop = mdl .operations [opLbl ].to_dense ()
674- ret += wt * (1.0 - _tools .leaky_entanglement_fidelity (top , mop , mxBasis , n_leak ))** 2
675- # Leakage-aware metrics NOT available for SPAM
676- for preplabel , m_prep in mdl .preps .items ():
677- wt = item_weights .get (preplabel , spamWeight )
678- rhoMx1 = _tools .vec_to_stdmx (m_prep .to_dense (), mxBasis )
679- t_prep = target_model .preps [preplabel ]
680- rhoMx2 = _tools .vec_to_stdmx (t_prep .to_dense (), mxBasis )
681- ret += wt * (1.0 - _tools .fidelity (rhoMx1 , rhoMx2 ))** 2
682- for povmlabel in mdl .povms .keys ():
683- wt = item_weights .get (povmlabel , spamWeight )
684- fidelity = _tools .povm_fidelity (mdl , target_model , povmlabel )
685- ret += wt * (1.0 - fidelity )** 2
686- return ret
687-
688- elif metric == "tracedist" :
689- # Leakage-aware metric supported, using leaky_jtracedist.
690- for opLbl in mdl .operations :
691- wt = item_weights .get (opLbl , opWeight )
692- top = target_model .operations [opLbl ].to_dense ()
693- mop = mdl .operations [opLbl ].to_dense ()
694- ret += wt * _tools .leaky_jtracedist (top , mop , mxBasis , n_leak )
695- # Leakage-aware metrics NOT available for SPAM
696- for preplabel , m_prep in mdl .preps .items ():
697- wt = item_weights .get (preplabel , spamWeight )
698- rhoMx1 = _tools .vec_to_stdmx (m_prep .to_dense (), mxBasis )
699- t_prep = target_model .preps [preplabel ]
700- rhoMx2 = _tools .vec_to_stdmx (t_prep .to_dense (), mxBasis )
701- ret += wt * _tools .tracedist (rhoMx1 , rhoMx2 )
702- for povmlabel in mdl .povms .keys ():
703- wt = item_weights .get (povmlabel , spamWeight )
704- ret += wt * _tools .povm_jtracedist (mdl , target_model , povmlabel )
705- return ret
642+ if target_model is not None :
643+ """
644+ Leakage-aware metric supported, per implementation in mdl.frobeniusdist.
645+ Refer to how mdl.frobeniusdist handles the case when transform_mx_arg
646+ is a tuple in order to understand how the leakage-aware metric is defined.
647+
648+ Idea: raise an error if mxBasis isn't leakage-friendly.
649+ PROBLEM: if we're deep in the code then we end up needing to be
650+ working in a basis that has the identity matrix as its
651+ first element. The leakage-friendly basis doesn't even
652+ have the identity matrix as an element, let alone the first element
653+
654+ TODO: dig into function calls below and see where we can
655+ access the mxBasis object. (I'm sure we can.)
656+ Looks like it isn't accessible within ExplicitOpModelCalc objects.
657+ It's most definitely available in ExplicitOpModel.
658+ """
659+ if "frobenius" in gates_metric :
660+ if spam_metric == gates_metric :
661+ val = mdl .frobeniusdist (target_model , transform_mx_arg , item_weights )
662+ else :
663+ wts = item_weights .copy ()
664+ wts ['spam' ] = 0.0
665+ for k in wts :
666+ if k in mdl .preps or k in mdl .povms :
667+ wts [k ] = 0.0
668+ val = mdl .frobeniusdist (target_model , transform_mx_arg , wts , n_leak )
669+ if "squared" in gates_metric :
670+ val = val ** 2
671+ ret += val
672+
673+ elif gates_metric == "fidelity" :
674+ # Leakage-aware metric supported, using leaky_entanglement_fidelity.
675+ for opLbl in mdl .operations :
676+ wt = item_weights .get (opLbl , opWeight )
677+ top = target_model .operations [opLbl ].to_dense ()
678+ mop = mdl .operations [opLbl ].to_dense ()
679+ ret += wt * (1.0 - _tools .leaky_entanglement_fidelity (top , mop , mxBasis , n_leak ))** 2
680+
681+ elif gates_metric == "tracedist" :
682+ # Leakage-aware metric supported, using leaky_jtracedist.
683+ for opLbl in mdl .operations :
684+ wt = item_weights .get (opLbl , opWeight )
685+ top = target_model .operations [opLbl ].to_dense ()
686+ mop = mdl .operations [opLbl ].to_dense ()
687+ ret += wt * _tools .leaky_jtracedist (top , mop , mxBasis , n_leak )
688+
689+ else : raise ValueError ("Invalid gates_metric: %s" % gates_metric )
690+
691+ if "frobenius" in spam_metric and gates_metric == spam_metric :
692+ # We already handled SPAM error in this case. Just return.
693+ return ret
694+
695+ elif "frobenius" in spam_metric :
696+ # Leakage-aware metric supported in principle via implementation in
697+ # mdl.frobeniusdist (check implementation to see how it handles the
698+ # case when transform_mx_arg is a tuple).
699+ wts = item_weights .copy (); wts ['gates' ] = 0.0
700+ for k in wts :
701+ if k in mdl .operations or \
702+ k in mdl .instruments : wts [k ] = 0.0
703+ val = mdl .frobeniusdist (target_model , transform_mx_arg , wts )
704+ if "squared" in spam_metric :
705+ val = val ** 2
706+ ret += val
707+
708+ elif spam_metric == "fidelity" :
709+ # Leakage-aware metrics NOT available
710+ for preplabel , m_prep in mdl .preps .items ():
711+ wt = item_weights .get (preplabel , spamWeight )
712+ rhoMx1 = _tools .vec_to_stdmx (m_prep .to_dense (), mxBasis )
713+ t_prep = target_model .preps [preplabel ]
714+ rhoMx2 = _tools .vec_to_stdmx (t_prep .to_dense (), mxBasis )
715+ ret += wt * (1.0 - _tools .fidelity (rhoMx1 , rhoMx2 ))** 2
716+
717+ for povmlabel in mdl .povms .keys ():
718+ wt = item_weights .get (povmlabel , spamWeight )
719+ fidelity = _tools .povm_fidelity (mdl , target_model , povmlabel )
720+ ret += wt * (1.0 - fidelity )** 2
721+
722+ elif spam_metric == "tracedist" :
723+ # Leakage-aware metrics NOT available.
724+ for preplabel , m_prep in mdl .preps .items ():
725+ wt = item_weights .get (preplabel , spamWeight )
726+ rhoMx1 = _tools .vec_to_stdmx (m_prep .to_dense (), mxBasis )
727+ t_prep = target_model .preps [preplabel ]
728+ rhoMx2 = _tools .vec_to_stdmx (t_prep .to_dense (), mxBasis )
729+ ret += wt * _tools .tracedist (rhoMx1 , rhoMx2 )
730+
731+ for povmlabel in mdl .povms .keys ():
732+ wt = item_weights .get (povmlabel , spamWeight )
733+ ret += wt * _tools .povm_jtracedist (mdl , target_model , povmlabel )
734+
735+ else : raise ValueError ("Invalid spam_metric: %s" % spam_metric )
736+
737+ return ret
706738
707- else :
708- raise ValueError ("Invalid metric: %s" % metric )
709- # end _objective_fn
710-
711739 _jacobian_fn = None
712740
713741 return _objective_fn , _jacobian_fn
0 commit comments