@@ -857,6 +857,14 @@ class GSTGaugeOptSuite(_NicelySerializable):
857
857
given by the target model, which are used as the default when
858
858
`gaugeopt_target` is None.
859
859
"""
860
+
861
+ STANDARD_SUITENAMES = ("stdgaugeopt" , "stdgaugeopt-unreliable2Q" , "stdgaugeopt-tt" , "stdgaugeopt-safe" ,
862
+ "stdgaugeopt-noconversion" , "stdgaugeopt-noconversion-safe" )
863
+
864
+ SPECIAL_SUITENAMES = ("varySpam" , "varySpamWt" , "varyValidSpamWt" , "toggleValidSpam" ,
865
+ "varySpam-unreliable2Q" , "varySpamWt-unreliable2Q" ,
866
+ "varyValidSpamWt-unreliable2Q" , "toggleValidSpam-unreliable2Q" )
867
+
860
868
@classmethod
861
869
def cast (cls , obj ):
862
870
if obj is None :
@@ -872,14 +880,13 @@ def cast(cls, obj):
872
880
873
881
def __init__ (self , gaugeopt_suite_names = None , gaugeopt_argument_dicts = None , gaugeopt_target = None ):
874
882
super ().__init__ ()
875
- if gaugeopt_suite_names is not None :
876
- if gaugeopt_suite_names == 'none' :
877
- self .gaugeopt_suite_names = None
878
- else :
879
- self .gaugeopt_suite_names = (gaugeopt_suite_names ,) \
880
- if isinstance (gaugeopt_suite_names , str ) else tuple (gaugeopt_suite_names )
881
- else :
883
+ if gaugeopt_suite_names is None or gaugeopt_suite_names == 'none' :
882
884
self .gaugeopt_suite_names = None
885
+ elif isinstance (gaugeopt_suite_names , str ):
886
+ self .gaugeopt_suite_names = (gaugeopt_suite_names ,)
887
+ else :
888
+ self .gaugeopt_suite_names = tuple (gaugeopt_suite_names )
889
+
883
890
884
891
if gaugeopt_argument_dicts is not None :
885
892
self .gaugeopt_argument_dicts = gaugeopt_argument_dicts .copy ()
@@ -985,92 +992,98 @@ def to_dictionary(self, model, unreliable_ops=(), verbosity=0):
985
992
986
993
return gaugeopt_suite_dict
987
994
988
- def _update_gaugeopt_dict_from_suitename ( self , gaugeopt_suite_dict , root_lbl , suite_name , model ,
989
- unreliable_ops , printer ):
990
- if suite_name in ( "stdgaugeopt" , "stdgaugeopt-unreliable2Q" , "stdgaugeopt-tt" , "stdgaugeopt-safe" ,
991
- "stdgaugeopt-noconversion" , "stdgaugeopt-noconversion-safe" ) :
995
+ @ staticmethod
996
+ def _update_gaugeopt_dict_from_suitename ( gaugeopt_suite_dict , root_lbl , suite_name , model , unreliable_ops , printer ):
997
+
998
+ if suite_name in GSTGaugeOptSuite . STANDARD_SUITENAMES :
992
999
993
- stages = [] # multi-stage gauge opt
994
1000
gg = model .default_gauge_group
995
- convert_to = {'to_type' : "full TP" , 'flatten_structure' : True , 'set_default_gauge_group' : True } \
1001
+
1002
+ if gg is None :
1003
+ return
1004
+
1005
+ stages = [] # multi-stage gauge opt
1006
+
1007
+ from pygsti .models .gaugegroup import TrivialGaugeGroup , UnitaryGaugeGroup , \
1008
+ SpamGaugeGroup , TPSpamGaugeGroup
1009
+
1010
+ convert_to = {'to_type' : "full" , 'flatten_structure' : True , 'set_default_gauge_group' : False } \
996
1011
if ('noconversion' not in suite_name and gg .name not in ("Full" , "TP" )) else None
997
1012
998
- if isinstance (gg , _models . gaugegroup . TrivialGaugeGroup ) and convert_to is None :
1013
+ if isinstance (gg , TrivialGaugeGroup ) and convert_to is None :
999
1014
if suite_name == "stdgaugeopt-unreliable2Q" and model .dim == 16 :
1000
- if any ([gl in model .operations . keys () for gl in unreliable_ops ]):
1015
+ if any ([gl in model .operations for gl in unreliable_ops ]):
1001
1016
gaugeopt_suite_dict [root_lbl ] = {'verbosity' : printer }
1002
1017
else :
1003
1018
#just do a single-stage "trivial" gauge opts using default group
1004
1019
gaugeopt_suite_dict [root_lbl ] = {'verbosity' : printer }
1005
-
1006
- elif gg is not None :
1007
- metric = 'frobeniustt' if suite_name == 'stdgaugeopt-tt' else 'frobenius'
1008
-
1009
- #Stage 1: plain vanilla gauge opt to get into "right ballpark"
1010
- if gg .name in ("Full" , "TP" ):
1011
- stages .append (
1012
- {
1013
- 'gates_metric' : metric , 'spam_metric' : metric ,
1014
- 'item_weights' : {'gates' : 1.0 , 'spam' : 1.0 },
1015
- 'verbosity' : printer
1016
- })
1017
-
1018
- #Stage 2: unitary gauge opt that tries to nail down gates (at
1019
- # expense of spam if needed)
1020
- stages .append (
1021
- {
1022
- 'convert_model_to' : convert_to ,
1023
- 'gates_metric' : metric , 'spam_metric' : metric ,
1024
- 'item_weights' : {'gates' : 1.0 , 'spam' : 0.0 },
1025
- 'gauge_group' : _models .gaugegroup .UnitaryGaugeGroup (model .state_space ,
1026
- model .basis , model .evotype ),
1027
- 'oob_check_interval' : 1 if ('-safe' in suite_name ) else 0 ,
1028
- 'verbosity' : printer
1029
- })
1030
-
1031
- #Stage 3: spam gauge opt that fixes spam scaling at expense of
1032
- # non-unital parts of gates (but shouldn't affect these
1033
- # elements much since they should be small from Stage 2).
1034
- s3gg = _models .gaugegroup .SpamGaugeGroup if (gg .name == "Full" ) else \
1035
- _models .gaugegroup .TPSpamGaugeGroup
1036
- stages .append (
1037
- {
1038
- 'convert_model_to' : convert_to ,
1039
- 'gates_metric' : metric , 'spam_metric' : metric ,
1040
- 'item_weights' : {'gates' : 0.0 , 'spam' : 1.0 },
1041
- 'spam_penalty_factor' : 1.0 ,
1042
- 'gauge_group' : s3gg (model .state_space , model .evotype ),
1043
- 'oob_check_interval' : 1 ,
1044
- 'verbosity' : printer
1045
- })
1046
-
1047
- if suite_name == "stdgaugeopt-unreliable2Q" and model .dim == 16 :
1048
- if any ([gl in model .operations .keys () for gl in unreliable_ops ]):
1049
- stage2_item_weights = {'gates' : 1 , 'spam' : 0.0 }
1050
- for gl in unreliable_ops :
1051
- if gl in model .operations .keys (): stage2_item_weights [gl ] = 0.01
1052
- stages_2qubit_unreliable = [stage .copy () for stage in stages ] # ~deep copy of stages
1053
- istage2 = 1 if gg .name in ("Full" , "TP" ) else 0
1054
- stages_2qubit_unreliable [istage2 ]['item_weights' ] = stage2_item_weights
1055
- gaugeopt_suite_dict [root_lbl ] = stages_2qubit_unreliable # add additional gauge opt
1056
- else :
1057
- _warnings .warn (("`unreliable2Q` was given as a gauge opt suite, but none of the"
1058
- " gate names in 'unreliable_ops', i.e., %s,"
1059
- " are present in the target model. Omitting 'single-2QUR' gauge opt." )
1060
- % (", " .join (unreliable_ops )))
1020
+ return
1021
+
1022
+ metric = 'frobeniustt' if suite_name == 'stdgaugeopt-tt' else 'frobenius'
1023
+ ss = model .state_space
1024
+ et = model .evotype
1025
+
1026
+ # Stage 1: plain vanilla gauge opt to get into "right ballpark"
1027
+ if gg .name in ("Full" , "TP" ):
1028
+ stages .append ({
1029
+ 'gates_metric' : metric , 'spam_metric' : metric ,
1030
+ 'item_weights' : {'gates' : 1.0 , 'spam' : 1.0 },
1031
+ 'verbosity' : printer
1032
+ })
1033
+
1034
+ # Stage 2: unitary gauge opt that tries to nail down gates (at
1035
+ # expense of spam if needed)
1036
+ s2gg = UnitaryGaugeGroup (ss , model .basis , et )
1037
+ stages .append ({
1038
+ 'convert_model_to' : convert_to ,
1039
+ 'gates_metric' : metric , 'spam_metric' : metric ,
1040
+ 'item_weights' : {'gates' : 1.0 , 'spam' : 0.0 },
1041
+ 'gauge_group' : s2gg ,
1042
+ 'oob_check_interval' : 1 if ('-safe' in suite_name ) else 0 ,
1043
+ 'verbosity' : printer
1044
+ })
1045
+
1046
+ # Stage 3: spam gauge opt that fixes spam scaling at expense of
1047
+ # non-unital parts of gates (but shouldn't affect these
1048
+ # elements much since they should be small from Stage 2).
1049
+ s3gg = SpamGaugeGroup (ss , et ) if (gg .name == "Full" ) else TPSpamGaugeGroup (ss , et )
1050
+ stages .append ({
1051
+ 'convert_model_to' : convert_to ,
1052
+ 'gates_metric' : metric , 'spam_metric' : metric ,
1053
+ 'item_weights' : {'gates' : 0.0 , 'spam' : 1.0 },
1054
+ 'spam_penalty_factor' : 1.0 ,
1055
+ 'gauge_group' : s3gg ,
1056
+ 'oob_check_interval' : 1 ,
1057
+ 'verbosity' : printer
1058
+ })
1059
+
1060
+ if suite_name == "stdgaugeopt-unreliable2Q" and model .dim == 16 :
1061
+ if any ([gl in model .operations for gl in unreliable_ops ]):
1062
+ stage2_item_weights = {'gates' : 1.0 , 'spam' : 0.0 }
1063
+ for gl in unreliable_ops :
1064
+ if gl in model .operations :
1065
+ stage2_item_weights [gl ] = 0.01
1066
+ stages_2qubit_unreliable = [stage .copy () for stage in stages ] # ~deep copy of stages
1067
+ istage2 = 1 if gg .name in ("Full" , "TP" ) else 0
1068
+ stages_2qubit_unreliable [istage2 ]['item_weights' ] = stage2_item_weights
1069
+ gaugeopt_suite_dict [root_lbl ] = stages_2qubit_unreliable # add additional gauge opt
1061
1070
else :
1062
- gaugeopt_suite_dict [root_lbl ] = stages # can be a list of stage dictionaries
1071
+ _warnings .warn (("`unreliable2Q` was given as a gauge opt suite, but none of the"
1072
+ " gate names in 'unreliable_ops', i.e., %s,"
1073
+ " are present in the target model. Omitting 'single-2QUR' gauge opt." )
1074
+ % (", " .join (unreliable_ops )))
1075
+ else :
1076
+ gaugeopt_suite_dict [root_lbl ] = stages # can be a list of stage dictionaries
1063
1077
1064
- elif suite_name in ("varySpam" , "varySpamWt" , "varyValidSpamWt" , "toggleValidSpam" ) or \
1065
- suite_name in ("varySpam-unreliable2Q" , "varySpamWt-unreliable2Q" ,
1066
- "varyValidSpamWt-unreliable2Q" , "toggleValidSpam-unreliable2Q" ):
1078
+ elif suite_name in GSTGaugeOptSuite .SPECIAL_SUITENAMES :
1067
1079
1068
- base_wts = {'gates' : 1 }
1080
+ base_wts = {'gates' : 1.0 }
1069
1081
if suite_name .endswith ("unreliable2Q" ) and model .dim == 16 :
1070
- if any ([gl in model .operations . keys () for gl in unreliable_ops ]):
1071
- base = {'gates' : 1 }
1082
+ if any ([gl in model .operations for gl in unreliable_ops ]):
1083
+ base = {'gates' : 1.0 }
1072
1084
for gl in unreliable_ops :
1073
- if gl in model .operations .keys (): base [gl ] = 0.01
1085
+ if gl in model .operations :
1086
+ base [gl ] = 0.01
1074
1087
base_wts = base
1075
1088
1076
1089
if suite_name == "varySpam" :
@@ -1097,9 +1110,6 @@ def _update_gaugeopt_dict_from_suitename(self, gaugeopt_suite_dict, root_lbl, su
1097
1110
'item_weights' : item_weights ,
1098
1111
'spam_penalty_factor' : valid_spam , 'verbosity' : printer }
1099
1112
1100
- elif suite_name == "unreliable2Q" :
1101
- raise ValueError (("unreliable2Q is no longer a separate 'suite'. You should precede it with the suite"
1102
- " name, e.g. 'stdgaugeopt-unreliable2Q' or 'varySpam-unreliable2Q'" ))
1103
1113
elif suite_name == 'none' :
1104
1114
gaugeopt_suite_dict [root_lbl ] = None
1105
1115
else :
@@ -2091,9 +2101,9 @@ def _add_gauge_opt(results, base_est_label, gaugeopt_suite, starting_model,
2091
2101
"""
2092
2102
printer = _baseobjs .VerbosityPrinter .create_printer (verbosity , comm )
2093
2103
2094
- #Get gauge optimization dictionary
2095
- gaugeopt_suite_dict = gaugeopt_suite . to_dictionary ( starting_model ,
2096
- unreliable_ops , printer - 1 )
2104
+ gaugeopt_suite_dict = gaugeopt_suite . to_dictionary (
2105
+ starting_model , unreliable_ops , printer - 1
2106
+ )
2097
2107
2098
2108
#Gauge optimize to list of gauge optimization parameters
2099
2109
for go_label , goparams in gaugeopt_suite_dict .items ():
@@ -2505,6 +2515,7 @@ def _compute_1d_reference_values_and_name(estimate, badfit_options, gaugeopt_sui
2505
2515
spamdd [key ] = 0.5 * _tools .optools .povm_diamonddist (gaugeopt_model , target_model , key )
2506
2516
2507
2517
dd [lbl ]['SPAM' ] = sum (spamdd .values ())
2518
+
2508
2519
return dd , 'diamond distance'
2509
2520
else :
2510
2521
raise ValueError ("Invalid wildcard1d_reference value (%s) in bad-fit options!"
0 commit comments