pyGSTi 0.9.12__cp39-cp39-win_amd64.whl → 0.9.13__cp39-cp39-win_amd64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (225) hide show
  1. pyGSTi-0.9.13.dist-info/METADATA +197 -0
  2. {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/RECORD +211 -220
  3. {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/WHEEL +1 -1
  4. pygsti/_version.py +2 -2
  5. pygsti/algorithms/contract.py +1 -1
  6. pygsti/algorithms/core.py +62 -35
  7. pygsti/algorithms/fiducialpairreduction.py +95 -110
  8. pygsti/algorithms/fiducialselection.py +17 -8
  9. pygsti/algorithms/gaugeopt.py +2 -2
  10. pygsti/algorithms/germselection.py +87 -77
  11. pygsti/algorithms/mirroring.py +0 -388
  12. pygsti/algorithms/randomcircuit.py +165 -1333
  13. pygsti/algorithms/rbfit.py +0 -234
  14. pygsti/baseobjs/basis.py +94 -396
  15. pygsti/baseobjs/errorgenbasis.py +0 -132
  16. pygsti/baseobjs/errorgenspace.py +0 -10
  17. pygsti/baseobjs/label.py +52 -168
  18. pygsti/baseobjs/opcalc/fastopcalc.cp39-win_amd64.pyd +0 -0
  19. pygsti/baseobjs/opcalc/fastopcalc.pyx +2 -2
  20. pygsti/baseobjs/polynomial.py +13 -595
  21. pygsti/baseobjs/protectedarray.py +72 -132
  22. pygsti/baseobjs/statespace.py +1 -0
  23. pygsti/circuits/__init__.py +1 -1
  24. pygsti/circuits/circuit.py +753 -504
  25. pygsti/circuits/circuitconstruction.py +0 -4
  26. pygsti/circuits/circuitlist.py +47 -5
  27. pygsti/circuits/circuitparser/__init__.py +8 -8
  28. pygsti/circuits/circuitparser/fastcircuitparser.cp39-win_amd64.pyd +0 -0
  29. pygsti/circuits/circuitstructure.py +3 -3
  30. pygsti/circuits/cloudcircuitconstruction.py +27 -14
  31. pygsti/data/datacomparator.py +4 -9
  32. pygsti/data/dataset.py +51 -46
  33. pygsti/data/hypothesistest.py +0 -7
  34. pygsti/drivers/bootstrap.py +0 -49
  35. pygsti/drivers/longsequence.py +46 -10
  36. pygsti/evotypes/basereps_cython.cp39-win_amd64.pyd +0 -0
  37. pygsti/evotypes/chp/opreps.py +0 -61
  38. pygsti/evotypes/chp/statereps.py +0 -32
  39. pygsti/evotypes/densitymx/effectcreps.cpp +9 -10
  40. pygsti/evotypes/densitymx/effectreps.cp39-win_amd64.pyd +0 -0
  41. pygsti/evotypes/densitymx/effectreps.pyx +1 -1
  42. pygsti/evotypes/densitymx/opreps.cp39-win_amd64.pyd +0 -0
  43. pygsti/evotypes/densitymx/opreps.pyx +2 -2
  44. pygsti/evotypes/densitymx/statereps.cp39-win_amd64.pyd +0 -0
  45. pygsti/evotypes/densitymx/statereps.pyx +1 -1
  46. pygsti/evotypes/densitymx_slow/effectreps.py +7 -23
  47. pygsti/evotypes/densitymx_slow/opreps.py +16 -23
  48. pygsti/evotypes/densitymx_slow/statereps.py +10 -3
  49. pygsti/evotypes/evotype.py +39 -2
  50. pygsti/evotypes/stabilizer/effectreps.cp39-win_amd64.pyd +0 -0
  51. pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
  52. pygsti/evotypes/stabilizer/opreps.cp39-win_amd64.pyd +0 -0
  53. pygsti/evotypes/stabilizer/opreps.pyx +0 -4
  54. pygsti/evotypes/stabilizer/statereps.cp39-win_amd64.pyd +0 -0
  55. pygsti/evotypes/stabilizer/statereps.pyx +1 -5
  56. pygsti/evotypes/stabilizer/termreps.cp39-win_amd64.pyd +0 -0
  57. pygsti/evotypes/stabilizer/termreps.pyx +0 -7
  58. pygsti/evotypes/stabilizer_slow/effectreps.py +0 -22
  59. pygsti/evotypes/stabilizer_slow/opreps.py +0 -4
  60. pygsti/evotypes/stabilizer_slow/statereps.py +0 -4
  61. pygsti/evotypes/statevec/effectreps.cp39-win_amd64.pyd +0 -0
  62. pygsti/evotypes/statevec/effectreps.pyx +1 -1
  63. pygsti/evotypes/statevec/opreps.cp39-win_amd64.pyd +0 -0
  64. pygsti/evotypes/statevec/opreps.pyx +2 -2
  65. pygsti/evotypes/statevec/statereps.cp39-win_amd64.pyd +0 -0
  66. pygsti/evotypes/statevec/statereps.pyx +1 -1
  67. pygsti/evotypes/statevec/termreps.cp39-win_amd64.pyd +0 -0
  68. pygsti/evotypes/statevec/termreps.pyx +0 -7
  69. pygsti/evotypes/statevec_slow/effectreps.py +0 -3
  70. pygsti/evotypes/statevec_slow/opreps.py +0 -5
  71. pygsti/extras/__init__.py +0 -1
  72. pygsti/extras/drift/signal.py +1 -1
  73. pygsti/extras/drift/stabilityanalyzer.py +3 -1
  74. pygsti/extras/interpygate/__init__.py +12 -0
  75. pygsti/extras/interpygate/core.py +0 -36
  76. pygsti/extras/interpygate/process_tomography.py +44 -10
  77. pygsti/extras/rpe/rpeconstruction.py +0 -2
  78. pygsti/forwardsims/__init__.py +1 -0
  79. pygsti/forwardsims/forwardsim.py +50 -93
  80. pygsti/forwardsims/mapforwardsim.py +78 -20
  81. pygsti/forwardsims/mapforwardsim_calc_densitymx.cp39-win_amd64.pyd +0 -0
  82. pygsti/forwardsims/mapforwardsim_calc_densitymx.pyx +65 -66
  83. pygsti/forwardsims/mapforwardsim_calc_generic.py +91 -13
  84. pygsti/forwardsims/matrixforwardsim.py +72 -17
  85. pygsti/forwardsims/termforwardsim.py +9 -111
  86. pygsti/forwardsims/termforwardsim_calc_stabilizer.cp39-win_amd64.pyd +0 -0
  87. pygsti/forwardsims/termforwardsim_calc_statevec.cp39-win_amd64.pyd +0 -0
  88. pygsti/forwardsims/termforwardsim_calc_statevec.pyx +0 -651
  89. pygsti/forwardsims/torchfwdsim.py +265 -0
  90. pygsti/forwardsims/weakforwardsim.py +2 -2
  91. pygsti/io/__init__.py +1 -2
  92. pygsti/io/mongodb.py +0 -2
  93. pygsti/io/stdinput.py +6 -22
  94. pygsti/layouts/copalayout.py +10 -12
  95. pygsti/layouts/distlayout.py +0 -40
  96. pygsti/layouts/maplayout.py +103 -25
  97. pygsti/layouts/matrixlayout.py +99 -60
  98. pygsti/layouts/prefixtable.py +1534 -52
  99. pygsti/layouts/termlayout.py +1 -1
  100. pygsti/modelmembers/instruments/instrument.py +3 -3
  101. pygsti/modelmembers/instruments/tpinstrument.py +2 -2
  102. pygsti/modelmembers/modelmember.py +0 -17
  103. pygsti/modelmembers/operations/__init__.py +3 -4
  104. pygsti/modelmembers/operations/affineshiftop.py +206 -0
  105. pygsti/modelmembers/operations/composederrorgen.py +1 -1
  106. pygsti/modelmembers/operations/composedop.py +1 -24
  107. pygsti/modelmembers/operations/denseop.py +5 -5
  108. pygsti/modelmembers/operations/eigpdenseop.py +2 -2
  109. pygsti/modelmembers/operations/embeddederrorgen.py +1 -1
  110. pygsti/modelmembers/operations/embeddedop.py +0 -1
  111. pygsti/modelmembers/operations/experrorgenop.py +5 -2
  112. pygsti/modelmembers/operations/fullarbitraryop.py +1 -0
  113. pygsti/modelmembers/operations/fullcptpop.py +2 -2
  114. pygsti/modelmembers/operations/fulltpop.py +28 -6
  115. pygsti/modelmembers/operations/fullunitaryop.py +5 -4
  116. pygsti/modelmembers/operations/lindbladcoefficients.py +93 -78
  117. pygsti/modelmembers/operations/lindbladerrorgen.py +268 -441
  118. pygsti/modelmembers/operations/linearop.py +7 -27
  119. pygsti/modelmembers/operations/opfactory.py +1 -1
  120. pygsti/modelmembers/operations/repeatedop.py +1 -24
  121. pygsti/modelmembers/operations/staticstdop.py +1 -1
  122. pygsti/modelmembers/povms/__init__.py +3 -3
  123. pygsti/modelmembers/povms/basepovm.py +7 -36
  124. pygsti/modelmembers/povms/complementeffect.py +4 -9
  125. pygsti/modelmembers/povms/composedeffect.py +0 -320
  126. pygsti/modelmembers/povms/computationaleffect.py +1 -1
  127. pygsti/modelmembers/povms/computationalpovm.py +3 -1
  128. pygsti/modelmembers/povms/effect.py +3 -5
  129. pygsti/modelmembers/povms/marginalizedpovm.py +3 -81
  130. pygsti/modelmembers/povms/tppovm.py +74 -2
  131. pygsti/modelmembers/states/__init__.py +2 -5
  132. pygsti/modelmembers/states/composedstate.py +0 -317
  133. pygsti/modelmembers/states/computationalstate.py +3 -3
  134. pygsti/modelmembers/states/cptpstate.py +4 -4
  135. pygsti/modelmembers/states/densestate.py +10 -8
  136. pygsti/modelmembers/states/fullpurestate.py +0 -24
  137. pygsti/modelmembers/states/purestate.py +1 -1
  138. pygsti/modelmembers/states/state.py +5 -6
  139. pygsti/modelmembers/states/tpstate.py +28 -10
  140. pygsti/modelmembers/term.py +3 -6
  141. pygsti/modelmembers/torchable.py +50 -0
  142. pygsti/modelpacks/_modelpack.py +1 -1
  143. pygsti/modelpacks/smq1Q_ZN.py +3 -1
  144. pygsti/modelpacks/smq2Q_XXYYII.py +2 -1
  145. pygsti/modelpacks/smq2Q_XY.py +3 -3
  146. pygsti/modelpacks/smq2Q_XYI.py +2 -2
  147. pygsti/modelpacks/smq2Q_XYICNOT.py +3 -3
  148. pygsti/modelpacks/smq2Q_XYICPHASE.py +3 -3
  149. pygsti/modelpacks/smq2Q_XYXX.py +1 -1
  150. pygsti/modelpacks/smq2Q_XYZICNOT.py +3 -3
  151. pygsti/modelpacks/smq2Q_XYZZ.py +1 -1
  152. pygsti/modelpacks/stdtarget.py +0 -121
  153. pygsti/models/cloudnoisemodel.py +1 -2
  154. pygsti/models/explicitcalc.py +3 -3
  155. pygsti/models/explicitmodel.py +3 -13
  156. pygsti/models/fogistore.py +5 -3
  157. pygsti/models/localnoisemodel.py +1 -2
  158. pygsti/models/memberdict.py +0 -12
  159. pygsti/models/model.py +801 -68
  160. pygsti/models/modelconstruction.py +4 -4
  161. pygsti/models/modelnoise.py +2 -2
  162. pygsti/models/modelparaminterposer.py +1 -1
  163. pygsti/models/oplessmodel.py +1 -1
  164. pygsti/models/qutrit.py +15 -14
  165. pygsti/objectivefns/objectivefns.py +75 -140
  166. pygsti/objectivefns/wildcardbudget.py +2 -7
  167. pygsti/optimize/__init__.py +1 -0
  168. pygsti/optimize/arraysinterface.py +28 -0
  169. pygsti/optimize/customcg.py +0 -12
  170. pygsti/optimize/customlm.py +129 -323
  171. pygsti/optimize/customsolve.py +2 -2
  172. pygsti/optimize/optimize.py +0 -84
  173. pygsti/optimize/simplerlm.py +841 -0
  174. pygsti/optimize/wildcardopt.py +19 -598
  175. pygsti/protocols/confidenceregionfactory.py +28 -14
  176. pygsti/protocols/estimate.py +31 -14
  177. pygsti/protocols/gst.py +238 -142
  178. pygsti/protocols/modeltest.py +19 -12
  179. pygsti/protocols/protocol.py +9 -37
  180. pygsti/protocols/rb.py +450 -79
  181. pygsti/protocols/treenode.py +8 -2
  182. pygsti/protocols/vb.py +108 -206
  183. pygsti/protocols/vbdataframe.py +1 -1
  184. pygsti/report/factory.py +0 -15
  185. pygsti/report/fogidiagram.py +1 -17
  186. pygsti/report/modelfunction.py +12 -3
  187. pygsti/report/mpl_colormaps.py +1 -1
  188. pygsti/report/plothelpers.py +11 -3
  189. pygsti/report/report.py +16 -0
  190. pygsti/report/reportables.py +41 -37
  191. pygsti/report/templates/offline/pygsti_dashboard.css +6 -0
  192. pygsti/report/templates/offline/pygsti_dashboard.js +12 -0
  193. pygsti/report/workspace.py +2 -14
  194. pygsti/report/workspaceplots.py +328 -505
  195. pygsti/tools/basistools.py +9 -36
  196. pygsti/tools/edesigntools.py +124 -96
  197. pygsti/tools/fastcalc.cp39-win_amd64.pyd +0 -0
  198. pygsti/tools/fastcalc.pyx +35 -81
  199. pygsti/tools/internalgates.py +151 -15
  200. pygsti/tools/jamiolkowski.py +5 -5
  201. pygsti/tools/lindbladtools.py +19 -11
  202. pygsti/tools/listtools.py +0 -114
  203. pygsti/tools/matrixmod2.py +1 -1
  204. pygsti/tools/matrixtools.py +173 -339
  205. pygsti/tools/nameddict.py +1 -1
  206. pygsti/tools/optools.py +154 -88
  207. pygsti/tools/pdftools.py +0 -25
  208. pygsti/tools/rbtheory.py +3 -320
  209. pygsti/tools/slicetools.py +64 -12
  210. pyGSTi-0.9.12.dist-info/METADATA +0 -157
  211. pygsti/algorithms/directx.py +0 -711
  212. pygsti/evotypes/qibo/__init__.py +0 -33
  213. pygsti/evotypes/qibo/effectreps.py +0 -78
  214. pygsti/evotypes/qibo/opreps.py +0 -376
  215. pygsti/evotypes/qibo/povmreps.py +0 -98
  216. pygsti/evotypes/qibo/statereps.py +0 -174
  217. pygsti/extras/rb/__init__.py +0 -13
  218. pygsti/extras/rb/benchmarker.py +0 -957
  219. pygsti/extras/rb/dataset.py +0 -378
  220. pygsti/extras/rb/io.py +0 -814
  221. pygsti/extras/rb/simulate.py +0 -1020
  222. pygsti/io/legacyio.py +0 -385
  223. pygsti/modelmembers/povms/denseeffect.py +0 -142
  224. {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/LICENSE +0 -0
  225. {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/top_level.txt +0 -0
pygsti/protocols/gst.py CHANGED
@@ -20,6 +20,7 @@ import pathlib as _pathlib
20
20
 
21
21
  import numpy as _np
22
22
  from scipy.stats import chi2 as _chi2
23
+ from typing import Optional
23
24
 
24
25
  from pygsti.baseobjs.profiler import DummyProfiler as _DummyProfiler
25
26
  from pygsti.baseobjs.nicelyserializable import NicelySerializable as _NicelySerializable
@@ -37,6 +38,7 @@ from pygsti import baseobjs as _baseobjs
37
38
  from pygsti.processors import QuditProcessorSpec as _QuditProcessorSpec
38
39
  from pygsti.modelmembers import operations as _op
39
40
  from pygsti.models import Model as _Model
41
+ from pygsti.models.explicitmodel import ExplicitOpModel as _ExplicitOpModel
40
42
  from pygsti.models.gaugegroup import GaugeGroup as _GaugeGroup, GaugeGroupElement as _GaugeGroupElement
41
43
  from pygsti.objectivefns import objectivefns as _objfns, wildcardbudget as _wild
42
44
  from pygsti.circuits.circuitlist import CircuitList as _CircuitList
@@ -44,6 +46,7 @@ from pygsti.baseobjs.resourceallocation import ResourceAllocation as _ResourceAl
44
46
  from pygsti.modelmembers import states as _states, povms as _povms
45
47
  from pygsti.tools.legacytools import deprecate as _deprecated_fn
46
48
  from pygsti.circuits import Circuit
49
+ from pygsti.forwardsims import ForwardSimulator
47
50
 
48
51
 
49
52
  #For results object:
@@ -535,7 +538,7 @@ class GSTInitialModel(_NicelySerializable):
535
538
  if comm is None or comm.Get_rank() == 0:
536
539
  #Advanced Options can specify further manipulation of starting model
537
540
  if self.contract_start_to_cptp:
538
- mdl_start = _alg.contract(mdl_start, "CPTP")
541
+ mdl_start = _alg.contract(mdl_start, "CPTPLND")
539
542
  raise ValueError(
540
543
  "'contractStartToCPTP' has been removed b/c it can change the parameterization of a model")
541
544
  if self.depolarize_start > 0:
@@ -593,7 +596,7 @@ class GSTBadFitOptions(_NicelySerializable):
593
596
  Actions to take when a GST fit is unsatisfactory. Allowed actions include:
594
597
 
595
598
  * 'wildcard': Find an admissable wildcard model.
596
- * 'ddist_wildcard': Fits a single parameter wildcard model in which
599
+ * 'wildcard1d': Fits a single parameter wildcard model in which
597
600
  the amount of wildcard error added to an operation is proportional
598
601
  to the diamond distance between that operation and the target.
599
602
  * 'robust': scale data according out "robust statistics v1" algorithm,
@@ -637,10 +640,8 @@ class GSTBadFitOptions(_NicelySerializable):
637
640
 
638
641
  wildcard_methods: tuple, optional
639
642
  A list of the methods to use to optimize the wildcard error vector. Default is `("neldermead",)`.
640
- Options include `"neldermead"`, `"barrier"`, `"cvxopt"`, `"cvxopt_smoothed"`, `"cvxopt_small"`,
641
- and `"cvxpy_noagg"`. So many methods exist because different convex solvers behave differently
642
- (unfortunately). Leave as the default as a safe option, but `"barrier"` is pretty reliable and much
643
- faster than `"neldermead"`, and is a good option so long as it runs.
643
+ Options include `"neldermead"`, `"barrier"`, and `"cvxpy_noagg"`. Leave as the default as a safe option,
644
+ but `"barrier"` is pretty reliable and much faster than `"neldermead"`, and is a good option so long as it runs.
644
645
 
645
646
  wildcard_inadmissable_action: {"print", "raise"}, optional
646
647
  What to do when an inadmissable wildcard error vector is found. The default just prints this
@@ -839,7 +840,9 @@ class GSTGaugeOptSuite(_NicelySerializable):
839
840
  - "varyValidSpamWt" : varies spam weight with SPAM penalty == 1.
840
841
  - "toggleValidSpam" : toggles spame penalty (0 or 1); fixed SPAM wt.
841
842
  - "unreliable2Q" : adds branch to a spam suite that weights 2Q gates less
842
- - "none" : no gauge optimizations are performed.
843
+ - "none" : no gauge optimizations are performed. When passed individually
844
+ (not in a list with other suite names) then this results in an empty
845
+ GSTGaugeOptSuite object (w/gaugeopt_suite_names set to None).
843
846
 
844
847
  gaugeopt_argument_dicts : dict, optional
845
848
  A dictionary whose string-valued keys label different gauge optimizations (e.g. within a
@@ -870,8 +873,11 @@ class GSTGaugeOptSuite(_NicelySerializable):
870
873
  def __init__(self, gaugeopt_suite_names=None, gaugeopt_argument_dicts=None, gaugeopt_target=None):
871
874
  super().__init__()
872
875
  if gaugeopt_suite_names is not None:
873
- self.gaugeopt_suite_names = (gaugeopt_suite_names,) \
874
- if isinstance(gaugeopt_suite_names, str) else tuple(gaugeopt_suite_names)
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)
875
881
  else:
876
882
  self.gaugeopt_suite_names = None
877
883
 
@@ -949,6 +955,8 @@ class GSTGaugeOptSuite(_NicelySerializable):
949
955
  if hasattr(goparams, 'keys'): # goparams is a simple dict
950
956
  gaugeopt_suite_dict[lbl] = goparams.copy()
951
957
  gaugeopt_suite_dict[lbl].update({'verbosity': printer})
958
+ elif goparams is None:
959
+ gaugeopt_suite_dict[lbl] = None
952
960
  else: # assume goparams is an iterable
953
961
  assert(isinstance(goparams, (list, tuple))), \
954
962
  "If not a dictionary, gauge opt params should be a list or tuple of dicts!"
@@ -961,7 +969,13 @@ class GSTGaugeOptSuite(_NicelySerializable):
961
969
  if self.gaugeopt_target is not None:
962
970
  assert(isinstance(self.gaugeopt_target, _Model)), "`gaugeopt_target` must be None or a Model"
963
971
  for goparams in gaugeopt_suite_dict.values():
964
- goparams_list = [goparams] if hasattr(goparams, 'keys') else goparams
972
+ if hasattr(goparams, 'keys'):
973
+ goparams_list = [goparams]
974
+ elif goparams is None: #edge case for 'none' suite
975
+ continue
976
+ else:
977
+ goparams_list = goparams
978
+
965
979
  for goparams_dict in goparams_list:
966
980
  if 'target_model' in goparams_dict:
967
981
  _warnings.warn(("`gaugeOptTarget` argument is overriding"
@@ -1086,8 +1100,8 @@ class GSTGaugeOptSuite(_NicelySerializable):
1086
1100
  elif suite_name == "unreliable2Q":
1087
1101
  raise ValueError(("unreliable2Q is no longer a separate 'suite'. You should precede it with the suite"
1088
1102
  " name, e.g. 'stdgaugeopt-unreliable2Q' or 'varySpam-unreliable2Q'"))
1089
- elif suite_name == "none":
1090
- pass # add nothing
1103
+ elif suite_name == 'none':
1104
+ gaugeopt_suite_dict[root_lbl] = None
1091
1105
  else:
1092
1106
  raise ValueError("Unknown gauge-optimization suite '%s'" % suite_name)
1093
1107
 
@@ -1120,6 +1134,9 @@ class GSTGaugeOptSuite(_NicelySerializable):
1120
1134
  for lbl, goparams in self.gaugeopt_argument_dicts.items():
1121
1135
  goparams_list = [goparams] if hasattr(goparams, 'keys') else goparams
1122
1136
  serialize_list = []
1137
+ if lbl == 'trivial_gauge_opt':
1138
+ dicts_to_serialize[lbl] = None
1139
+ continue
1123
1140
  for goparams_dict in goparams_list:
1124
1141
  to_add = goparams_dict.copy()
1125
1142
  if 'target_model' in to_add:
@@ -1151,6 +1168,9 @@ class GSTGaugeOptSuite(_NicelySerializable):
1151
1168
  def _from_nice_serialization(cls, state): # memo holds already de-serialized objects
1152
1169
  gaugeopt_argument_dicts = {}
1153
1170
  for lbl, serialized_goparams_list in state['gaugeopt_argument_dicts'].items():
1171
+ if lbl == 'trivial_gauge_opt':
1172
+ gaugeopt_argument_dicts[lbl] = None
1173
+ continue
1154
1174
  goparams_list = []
1155
1175
  for serialized_goparams in serialized_goparams_list:
1156
1176
  to_add = serialized_goparams.copy()
@@ -1230,15 +1250,16 @@ class GateSetTomography(_proto.Protocol):
1230
1250
 
1231
1251
  if isinstance(optimizer, _opt.Optimizer):
1232
1252
  self.optimizer = optimizer
1233
- if isinstance(optimizer, _opt.CustomLMOptimizer) and optimizer.first_fditer is None:
1234
- #special behavior: can set optimizer's first_fditer to `None` to mean "fill with default"
1253
+ if hasattr(optimizer,'first_fditer') and optimizer.first_fditer is None:
1254
+ # special behavior: can set optimizer's first_fditer to `None` to mean "fill with default"
1235
1255
  self.optimizer = _copy.deepcopy(optimizer) # don't mess with caller's optimizer
1236
1256
  self.optimizer.first_fditer = default_first_fditer
1237
1257
  else:
1238
- if optimizer is None: optimizer = {}
1258
+ if optimizer is None:
1259
+ optimizer = {}
1239
1260
  if 'first_fditer' not in optimizer: # then add default first_fditer value
1240
1261
  optimizer['first_fditer'] = default_first_fditer
1241
- self.optimizer = _opt.CustomLMOptimizer.cast(optimizer)
1262
+ self.optimizer = _opt.SimplerLMOptimizer.cast(optimizer)
1242
1263
 
1243
1264
  self.objfn_builders = GSTObjFnBuilders.cast(objfn_builders)
1244
1265
 
@@ -1257,20 +1278,8 @@ class GateSetTomography(_proto.Protocol):
1257
1278
  self.circuit_weights = None
1258
1279
  self.unreliable_ops = ('Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz')
1259
1280
 
1260
- #TODO: Maybe make methods like this separate functions??
1261
- #def run_using_germs_and_fiducials(self, dataset, target_model, prep_fiducials, meas_fiducials, germs, max_lengths):
1262
- # design = StandardGSTDesign(target_model, prep_fiducials, meas_fiducials, germs, max_lengths)
1263
- # return self.run(_proto.ProtocolData(design, dataset))
1264
- #
1265
- #def run_using_circuit_structures(self, target_model, circuit_structs, dataset):
1266
- # design = StructuredGSTDesign(target_model, circuit_structs)
1267
- # return self.run(_proto.ProtocolData(design, dataset))
1268
- #
1269
- #def run_using_circuit_lists(self, target_model, circuit_lists, dataset):
1270
- # design = GateSetTomographyDesign(target_model, circuit_lists)
1271
- # return self.run(_proto.ProtocolData(design, dataset))
1272
-
1273
- def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, disable_checkpointing = False):
1281
+ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None, disable_checkpointing=False,
1282
+ simulator: Optional[ForwardSimulator.Castable]=None):
1274
1283
  """
1275
1284
  Run this protocol on `data`.
1276
1285
 
@@ -1303,6 +1312,11 @@ class GateSetTomography(_proto.Protocol):
1303
1312
  to disk during the course of this protocol. It is strongly recommended
1304
1313
  that this be kept set to False without good reason to disable the checkpoints.
1305
1314
 
1315
+ simulator : ForwardSimulator.Castable or None
1316
+ Ignored if None. If not None, then we call
1317
+ fwdsim = ForwardSimulator.cast(simulator),
1318
+ and we set the .sim attribute of every Model we encounter to fwdsim.
1319
+
1306
1320
  Returns
1307
1321
  -------
1308
1322
  ModelEstimateResults
@@ -1337,54 +1351,56 @@ class GateSetTomography(_proto.Protocol):
1337
1351
  tnxt = _time.time(); profiler.add_time('GST: loading', tref); tref = tnxt
1338
1352
  mdl_start = self.initial_model.retrieve_model(data.edesign, self.gaugeopt_suite.gaugeopt_target,
1339
1353
  data.dataset, comm)
1340
-
1341
- if not disable_checkpointing:
1342
- #Set the checkpoint_path variable if None
1354
+ if simulator is not None:
1355
+ mdl_start.sim = simulator
1356
+
1357
+ if disable_checkpointing:
1358
+ seed_model = mdl_start.copy()
1359
+ mdl_lsgst_list = []
1360
+ starting_idx = 0
1361
+ else:
1362
+ # Set the checkpoint_path variable if None
1343
1363
  if checkpoint_path is None:
1344
1364
  checkpoint_path = _pathlib.Path('./gst_checkpoints/' + self.name)
1345
1365
  else:
1346
- #cast this to a pathlib path with the file extension (suffix) dropped
1366
+ # cast this to a pathlib path with the file extension (suffix) dropped
1347
1367
  checkpoint_path = _pathlib.Path(checkpoint_path).with_suffix('')
1348
-
1349
- #create the parent directory of the checkpoint if needed:
1368
+
1369
+ # create the parent directory of the checkpoint if needed:
1350
1370
  checkpoint_path.parent.mkdir(parents=True, exist_ok=True)
1351
-
1352
- #If there is no checkpoint we should start from with the seed model,
1353
- #otherwise we should seed the next iteration with the last iteration's result.
1354
- #If there is no checkpoint initialize mdl_lsgst_list and final_objfn to be empty,
1355
- #otherwise re-initialize their values from the checkpoint
1371
+
1372
+ # If there is no checkpoint we should start from with the seed model,
1373
+ # otherwise we should seed the next iteration with the last iteration's result.
1374
+ # If there is no checkpoint initialize mdl_lsgst_list and final_objfn to be empty,
1375
+ # otherwise re-initialize their values from the checkpoint
1356
1376
  if checkpoint is None:
1357
1377
  seed_model = mdl_start.copy()
1358
1378
  mdl_lsgst_list = []
1359
1379
  checkpoint = GateSetTomographyCheckpoint()
1360
1380
  elif isinstance(checkpoint, GateSetTomographyCheckpoint):
1361
- #if the checkpoint's last completed iteration is non-negative
1362
- #(i.e. the checkpoint actually has data in it)
1381
+ # if the checkpoint's last completed iteration is non-negative
1382
+ # (i.e. the checkpoint actually has data in it)
1363
1383
  if checkpoint.last_completed_iter >= 0:
1364
1384
  seed_model = checkpoint.mdl_list[-1]
1365
- #otherwise seed with target
1385
+ # otherwise seed with target
1366
1386
  else:
1367
1387
  seed_model = mdl_start.copy()
1368
1388
  mdl_lsgst_list = checkpoint.mdl_list
1369
1389
  final_objfn = checkpoint.final_objfn
1370
- #final_objfn initialized to None in the GateSetTomographyCheckpoint and will be overwritten
1371
- #during the loop below unless the last completed iteration is the final iteration
1372
- #in which case the loop should be skipped. If so I think it is ok that this gets
1373
- #left set to None. There looks to be some logic for handling this and it looks
1374
- #like the serialization routines effectively do this already, as the value
1375
- #of this is lost between writing and reading.
1390
+ # final_objfn initialized to None in the GateSetTomographyCheckpoint and will be overwritten
1391
+ # during the loop below unless the last completed iteration is the final iteration
1392
+ # in which case the loop should be skipped. If so I think it is ok that this gets
1393
+ # left set to None. There looks to be some logic for handling this and it looks
1394
+ # like the serialization routines effectively do this already, as the value
1395
+ # of this is lost between writing and reading.
1376
1396
  else:
1377
- NotImplementedError('The only currently valid checkpoint inputs are None and GateSetTomographyCheckpoint.')
1378
-
1379
- #note the last_completed_iter value is initialized to -1 so the below line
1397
+ NotImplementedError(
1398
+ 'The only currently valid checkpoint inputs are None and GateSetTomographyCheckpoint.')
1399
+
1400
+ # note the last_completed_iter value is initialized to -1 so the below line
1380
1401
  # will have us correctly starting at 0 if this is a fresh checkpoint.
1381
1402
  starting_idx = checkpoint.last_completed_iter + 1
1382
1403
 
1383
- else:
1384
- seed_model = mdl_start.copy()
1385
- mdl_lsgst_list = []
1386
- starting_idx = 0
1387
-
1388
1404
  tnxt = _time.time(); profiler.add_time('GST: Prep Initial seed', tref); tref = tnxt
1389
1405
 
1390
1406
  #Run Long-sequence GST on data
@@ -1404,18 +1420,18 @@ class GateSetTomography(_proto.Protocol):
1404
1420
  #then do the final iteration slightly differently since the generator should
1405
1421
  #give three return values.
1406
1422
  if i==len(bulk_circuit_lists)-1:
1407
- mdl_iter, opt_iter, final_objfn = next(gst_iter_generator)
1423
+ mdl_iter, opt_iter, final_objfn = next(gst_iter_generator)
1408
1424
  else:
1409
1425
  mdl_iter, opt_iter = next(gst_iter_generator)
1410
1426
  mdl_lsgst_list.append(mdl_iter)
1411
1427
  optima_list.append(opt_iter)
1412
1428
 
1413
1429
  if not disable_checkpointing:
1414
- #update the checkpoint along the way:
1430
+ # update the checkpoint along the way:
1415
1431
  checkpoint.mdl_list = mdl_lsgst_list
1416
1432
  checkpoint.last_completed_iter += 1
1417
1433
  checkpoint.last_completed_circuit_list = bulk_circuit_lists[i]
1418
- #write the updated checkpoint to disk:
1434
+ # write the updated checkpoint to disk:
1419
1435
  if resource_alloc.comm_rank == 0:
1420
1436
  checkpoint.write(f'{checkpoint_path}_iteration_{i}.json')
1421
1437
 
@@ -1442,19 +1458,37 @@ class GateSetTomography(_proto.Protocol):
1442
1458
  target_model = self.gaugeopt_suite.gaugeopt_target
1443
1459
  elif self.initial_model.target_model is not None:
1444
1460
  target_model = self.initial_model.target_model.copy()
1445
- elif self.initial_model.model is not None and self.gaugeopt_suite.is_empty() is False:
1461
+ elif self.initial_model.model is not None:
1446
1462
  # when we desparately need a target model but none have been specifically given: use initial model
1447
1463
  target_model = self.initial_model.model.copy()
1448
1464
  else:
1465
+ msg = 'Could not identify a suitable target model, this may result'\
1466
+ +' in unexpected behavior or missing plots in reports.'
1467
+ _warnings.warn(msg)
1449
1468
  target_model = None
1450
1469
 
1470
+ if target_model is not None and simulator is not None:
1471
+ target_model.sim = simulator
1472
+
1451
1473
  estimate = _Estimate.create_gst_estimate(ret, target_model, mdl_start, mdl_lsgst_list, parameters)
1452
1474
  ret.add_estimate(estimate, estimate_key=self.name)
1453
1475
 
1454
- return _add_gaugeopt_and_badfit(ret, self.name, target_model,
1455
- self.gaugeopt_suite, self.unreliable_ops,
1456
- self.badfit_options, self.optimizer, resource_alloc, printer)
1457
-
1476
+ #Add some better handling for when gauge optimization is turned off (current code path isn't working.)
1477
+ if not self.gaugeopt_suite.is_empty() or len(self.badfit_options.actions) > 0: # maybe add flag to do this even when empty?
1478
+ ret = _add_gaugeopt_and_badfit(ret, self.name, target_model,
1479
+ self.gaugeopt_suite, self.unreliable_ops,
1480
+ self.badfit_options, self.optimizer,
1481
+ resource_alloc, printer)
1482
+ else:
1483
+ #add a model to the estimate that we'll call the trivial gauge optimized model which
1484
+ #will be set to be equal to the final iteration estimate.
1485
+ ret.estimates[self.name].models['trivial_gauge_opt'] = mdl_lsgst_list[-1]
1486
+ #and add a key for this to the goparameters dict (this is what the report
1487
+ #generation looks at to determine the names of the gauge optimized models).
1488
+ #Set the value to None as a placeholder.
1489
+ ret.estimates[self.name].goparameters['trivial_gauge_opt'] = None
1490
+
1491
+ return ret
1458
1492
 
1459
1493
  class LinearGateSetTomography(_proto.Protocol):
1460
1494
  """
@@ -1504,6 +1538,10 @@ class LinearGateSetTomography(_proto.Protocol):
1504
1538
  self.oplabel_aliases = None
1505
1539
  self.unreliable_ops = ('Gcnot', 'Gcphase', 'Gms', 'Gcn', 'Gcx', 'Gcz')
1506
1540
 
1541
+ self.auxfile_types['target_model'] = 'serialized-object'
1542
+ self.auxfile_types['gaugeopt_suite'] = 'serialized-object'
1543
+ self.auxfile_types['badfit_options'] = 'serialized-object'
1544
+
1507
1545
  def check_if_runnable(self, data):
1508
1546
  """
1509
1547
  Raises a ValueError if LGST cannot be run on data
@@ -1612,9 +1650,22 @@ class LinearGateSetTomography(_proto.Protocol):
1612
1650
  'final iteration estimate': mdl_lgst},
1613
1651
  parameters)
1614
1652
  ret.add_estimate(estimate, estimate_key=self.name)
1615
- return _add_gaugeopt_and_badfit(ret, self.name, target_model, self.gaugeopt_suite,
1653
+
1654
+ #Add some better handling for when gauge optimization is turned off (current code path isn't working.)
1655
+ if not self.gaugeopt_suite.is_empty():
1656
+ ret = _add_gaugeopt_and_badfit(ret, self.name, target_model, self.gaugeopt_suite,
1616
1657
  self.unreliable_ops, self.badfit_options,
1617
1658
  None, resource_alloc, printer)
1659
+ else:
1660
+ #add a model to the estimate that we'll call the trivial gauge optimized model which
1661
+ #will be set to be equal to the final iteration estimate.
1662
+ ret.estimates[self.name].models['trivial_gauge_opt'] = mdl_lgst
1663
+ #and add a key for this to the goparameters dict (this is what the report
1664
+ #generation looks at to determine the names of the gauge optimized models).
1665
+ #Set the value to None as a placeholder.
1666
+ ret.estimates[self.name].goparameters['trivial_gauge_opt'] = None
1667
+
1668
+ return ret
1618
1669
 
1619
1670
 
1620
1671
  class StandardGST(_proto.Protocol):
@@ -1629,13 +1680,13 @@ class StandardGST(_proto.Protocol):
1629
1680
  parameterizations/constraints to apply to the estimated model.
1630
1681
  The default value is usually fine. Allowed values are:
1631
1682
 
1632
- - "full" : full (completely unconstrained)
1633
- - "TP" : TP-constrained
1634
- - "CPTP" : Lindbladian CPTP-constrained
1635
- - "H+S" : Only Hamiltonian + Stochastic errors allowed (CPTP)
1636
- - "S" : Only Stochastic errors allowed (CPTP)
1637
- - "Target" : use the target (ideal) gates as the estimate
1638
- - <model> : any key in the `models_to_test` argument
1683
+ - "full" : full (completely unconstrained)
1684
+ - "TP" : TP-constrained
1685
+ - "CPTPLND" : Lindbladian CPTP-constrained
1686
+ - "H+S" : Only Hamiltonian + Stochastic errors allowed (CPTP)
1687
+ - "S" : Only Stochastic errors allowed (CPTP)
1688
+ - "Target" : use the target (ideal) gates as the estimate
1689
+ - <model> : any key in the `models_to_test` argument
1639
1690
 
1640
1691
  gaugeopt_suite : GSTGaugeOptSuite, optional
1641
1692
  Specifies which gauge optimizations to perform on each estimate. Can also
@@ -1646,6 +1697,14 @@ class StandardGST(_proto.Protocol):
1646
1697
  optimization (only), and is useful when you want to gauge optimize toward
1647
1698
  something other than the *ideal* target gates.
1648
1699
 
1700
+ target_model : Model, optional (default None)
1701
+ If specified use this Model as the target model. Depending on other
1702
+ specified keyword arguments this model may be used as the target for
1703
+ the purposes of gauge optimization, report generation/analysis, and
1704
+ initial seeding for optimization. (For almost all of these it may be the
1705
+ case that other keyword argument values override this for certain
1706
+ tasks).
1707
+
1649
1708
  models_to_test : dict, optional
1650
1709
  A dictionary of Model objects representing (gate-set) models to
1651
1710
  test against the data. These Models are essentially hypotheses for
@@ -1694,12 +1753,12 @@ class StandardGST(_proto.Protocol):
1694
1753
  self.target_model = target_model
1695
1754
  self.gaugeopt_suite = GSTGaugeOptSuite.cast(gaugeopt_suite)
1696
1755
  self.objfn_builders = GSTObjFnBuilders.cast(objfn_builders) if (objfn_builders is not None) else None
1697
- self.optimizer = _opt.CustomLMOptimizer.cast(optimizer)
1756
+ self.optimizer = _opt.SimplerLMOptimizer.cast(optimizer)
1698
1757
  self.badfit_options = GSTBadFitOptions.cast(badfit_options)
1699
1758
  self.verbosity = verbosity
1700
1759
 
1701
1760
  if not isinstance(optimizer, _opt.Optimizer) and isinstance(optimizer, dict) \
1702
- and 'first_fditer' not in optimizer: # then a dict was cast into a CustomLMOptimizer above.
1761
+ and 'first_fditer' not in optimizer: # then a dict was cast into an Optimizer above.
1703
1762
  # by default, set special "first_fditer=auto" behavior (see logic in GateSetTomography.__init__)
1704
1763
  self.optimizer.first_fditer = None
1705
1764
 
@@ -1713,12 +1772,8 @@ class StandardGST(_proto.Protocol):
1713
1772
  #Advanced options that could be changed by users who know what they're doing
1714
1773
  self.starting_point = {} # a dict whose keys are modes
1715
1774
 
1716
- #def run_using_germs_and_fiducials(self, dataset, target_model, prep_fiducials, meas_fiducials, germs, max_lengths):
1717
- # design = StandardGSTDesign(target_model, prep_fiducials, meas_fiducials, germs, max_lengths)
1718
- # data = _proto.ProtocolData(design, dataset)
1719
- # return self.run(data)
1720
-
1721
- def run(self, data, memlimit=None, comm=None, checkpoint= None, checkpoint_path=None, disable_checkpointing = False):
1775
+ def run(self, data, memlimit=None, comm=None, checkpoint=None, checkpoint_path=None,
1776
+ disable_checkpointing=False, simulator: Optional[ForwardSimulator.Castable]=None):
1722
1777
  """
1723
1778
  Run this protocol on `data`.
1724
1779
 
@@ -1751,6 +1806,11 @@ class StandardGST(_proto.Protocol):
1751
1806
  to disk during the course of this protocol. It is strongly recommended
1752
1807
  that this be kept set to False without good reason to disable the checkpoints.
1753
1808
 
1809
+ simulator : ForwardSimulator.Castable or None
1810
+ Ignored if None. If not None, then we call
1811
+ fwdsim = ForwardSimulator.cast(simulator),
1812
+ and we set the .sim attribute of every Model we encounter to fwdsim.
1813
+
1754
1814
  Returns
1755
1815
  -------
1756
1816
  ProtocolResults
@@ -1780,6 +1840,10 @@ class StandardGST(_proto.Protocol):
1780
1840
  else:
1781
1841
  target_model = None # Usually this path leads to an error being raised below.
1782
1842
 
1843
+ if target_model is not None:
1844
+ if simulator is not None:
1845
+ target_model.sim = simulator
1846
+
1783
1847
  if not disable_checkpointing:
1784
1848
  #Set the checkpoint_path variable if None
1785
1849
  if checkpoint_path is None:
@@ -1813,8 +1877,12 @@ class StandardGST(_proto.Protocol):
1813
1877
  with printer.progress_logging(1):
1814
1878
  for i, mode in enumerate(modes):
1815
1879
  printer.show_progress(i, len(modes), prefix='-- Std Practice: ', suffix=' (%s) --' % mode)
1816
- if not disable_checkpointing:
1817
- #pre python 3.9 compatible version.
1880
+ if disable_checkpointing:
1881
+ checkpoint_path = None
1882
+ child_checkpoint = None
1883
+ else:
1884
+ child_checkpoint = checkpoint.children[mode]
1885
+ #The line below is for compatibility with Python 3.8 and lower.
1818
1886
  checkpoint_path = checkpoint_path_base.with_name(f"{checkpoint_path_base.stem}_{mode.replace(' ', '_')}")
1819
1887
  #The line below only works for python 3.9+
1820
1888
  #checkpoint_path = checkpoint_path_base.with_stem(f"{checkpoint_path_base.stem}_{mode.replace(' ', '_')}")
@@ -1825,21 +1893,22 @@ class StandardGST(_proto.Protocol):
1825
1893
 
1826
1894
  mdltest = _ModelTest(target_model, target_model, self.gaugeopt_suite,
1827
1895
  mt_builder, self.badfit_options, verbosity=printer - 1, name=mode)
1828
- if not disable_checkpointing:
1829
- result = mdltest.run(data, memlimit, comm, checkpoint = checkpoint.children[mode],
1830
- checkpoint_path=checkpoint_path)
1831
- else:
1832
- result = mdltest.run(data, memlimit, comm, disable_checkpointing=True)
1896
+ result = mdltest.run(data, memlimit, comm,
1897
+ disable_checkpointing=disable_checkpointing,
1898
+ checkpoint=child_checkpoint,
1899
+ checkpoint_path=checkpoint_path)
1833
1900
  ret.add_estimates(result)
1834
1901
 
1835
1902
  elif mode in models_to_test:
1836
- mdltest = _ModelTest(models_to_test[mode], target_model, self.gaugeopt_suite,
1903
+ mdl = models_to_test[mode]
1904
+ if simulator is not None:
1905
+ mdl.sim = simulator
1906
+ mdltest = _ModelTest(mdl, target_model, self.gaugeopt_suite,
1837
1907
  None, self.badfit_options, verbosity=printer - 1, name=mode)
1838
- if not disable_checkpointing:
1839
- result = mdltest.run(data, memlimit, comm, checkpoint = checkpoint.children[mode],
1840
- checkpoint_path=checkpoint_path)
1841
- else:
1842
- result = mdltest.run(data, memlimit, comm, disable_checkpointing=True)
1908
+ result = mdltest.run(data, memlimit, comm,
1909
+ disable_checkpointing=disable_checkpointing,
1910
+ checkpoint=child_checkpoint,
1911
+ checkpoint_path=checkpoint_path)
1843
1912
  ret.add_estimates(result)
1844
1913
 
1845
1914
  else:
@@ -1849,7 +1918,7 @@ class StandardGST(_proto.Protocol):
1849
1918
 
1850
1919
  #Try to interpret `mode` as a parameterization
1851
1920
  parameterization = mode # for now, 1-1 correspondence
1852
- initial_model = target_model
1921
+ initial_model = target_model.copy()
1853
1922
 
1854
1923
  try:
1855
1924
  initial_model.set_all_parameterizations(parameterization)
@@ -1858,13 +1927,14 @@ class StandardGST(_proto.Protocol):
1858
1927
  % (mode, str(e)))
1859
1928
 
1860
1929
  initial_model = GSTInitialModel(initial_model, self.starting_point.get(mode, None))
1930
+ if simulator is not None:
1931
+ initial_model.sim = simulator
1861
1932
  gst = GST(initial_model, self.gaugeopt_suite, self.objfn_builders,
1862
1933
  self.optimizer, self.badfit_options, verbosity=printer - 1, name=mode)
1863
- if not disable_checkpointing:
1864
- result = gst.run(data, memlimit, comm, checkpoint = checkpoint.children[mode],
1865
- checkpoint_path=checkpoint_path)
1866
- else:
1867
- result = gst.run(data, memlimit, comm, disable_checkpointing=True)
1934
+ result = gst.run(data, memlimit, comm,
1935
+ disable_checkpointing=disable_checkpointing,
1936
+ checkpoint=child_checkpoint,
1937
+ checkpoint_path=checkpoint_path)
1868
1938
  ret.add_estimates(result)
1869
1939
 
1870
1940
  return ret
@@ -1945,7 +2015,7 @@ def _add_gaugeopt_and_badfit(results, estlbl, target_model, gaugeopt_suite,
1945
2015
  profiler = resource_alloc.profiler
1946
2016
 
1947
2017
  #Do final gauge optimization to *final* iteration result only
1948
- if gaugeopt_suite:
2018
+ if gaugeopt_suite is not None and not gaugeopt_suite.is_empty():
1949
2019
  model_to_gaugeopt = results.estimates[estlbl].models['final iteration estimate']
1950
2020
  if gaugeopt_suite.gaugeopt_target is None: # add a default target model to gauge opt if needed
1951
2021
  #TODO: maybe make these two lines into a method of GSTGaugeOptSuite for adding a target model?
@@ -1954,7 +2024,7 @@ def _add_gaugeopt_and_badfit(results, estlbl, target_model, gaugeopt_suite,
1954
2024
  _add_gauge_opt(results, estlbl, gaugeopt_suite,
1955
2025
  model_to_gaugeopt, unreliable_ops, comm, printer - 1)
1956
2026
  profiler.add_time('%s: gauge optimization' % estlbl, tref); tref = _time.time()
1957
-
2027
+
1958
2028
  _add_badfit_estimates(results, estlbl, badfit_options, optimizer, resource_alloc, printer, gaugeopt_suite= gaugeopt_suite)
1959
2029
  profiler.add_time('%s: add badfit estimates' % estlbl, tref); tref = _time.time()
1960
2030
  else:
@@ -2023,26 +2093,31 @@ def _add_gauge_opt(results, base_est_label, gaugeopt_suite, starting_model,
2023
2093
 
2024
2094
  printer.log("-- Performing '%s' gauge optimization on %s estimate --" % (go_label, base_est_label), 2)
2025
2095
 
2026
- #Get starting model
2027
- results.estimates[base_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3)
2096
+ #add logic for the case where no gauge optimization is performed.
2097
+ if go_label == 'none':
2098
+ results.estimates[base_est_label].add_gaugeoptimized(goparams, starting_model, go_label, comm, printer - 3)
2099
+ else:
2100
+ results.estimates[base_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3)
2101
+
2102
+ #Get starting model for next stage
2028
2103
  mdl_start = results.estimates[base_est_label].retrieve_start_model(goparams)
2029
-
2030
- #Gauge optimize data-scaled estimate also
2031
- for suffix in ROBUST_SUFFIX_LIST:
2032
- robust_est_label = base_est_label + suffix
2033
- if robust_est_label in results.estimates:
2034
- mdl_start_robust = results.estimates[robust_est_label].retrieve_start_model(goparams)
2035
-
2036
- if mdl_start_robust.frobeniusdist(mdl_start) < 1e-8:
2037
- printer.log("-- Conveying '%s' gauge optimization from %s to %s estimate --" %
2038
- (go_label, base_est_label, robust_est_label), 2)
2039
- params = results.estimates[base_est_label].goparameters[go_label] # no need to copy here
2040
- gsopt = results.estimates[base_est_label].models[go_label].copy()
2041
- results.estimates[robust_est_label].add_gaugeoptimized(params, gsopt, go_label, comm, printer - 3)
2042
- else:
2043
- printer.log("-- Performing '%s' gauge optimization on %s estimate --" %
2044
- (go_label, robust_est_label), 2)
2045
- results.estimates[robust_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3)
2104
+ if mdl_start is not None:
2105
+ #Gauge optimize data-scaled estimate also
2106
+ for suffix in ROBUST_SUFFIX_LIST:
2107
+ robust_est_label = base_est_label + suffix
2108
+ if robust_est_label in results.estimates:
2109
+ mdl_start_robust = results.estimates[robust_est_label].retrieve_start_model(goparams)
2110
+
2111
+ if mdl_start_robust.frobeniusdist(mdl_start) < 1e-8:
2112
+ printer.log("-- Conveying '%s' gauge optimization from %s to %s estimate --" %
2113
+ (go_label, base_est_label, robust_est_label), 2)
2114
+ params = results.estimates[base_est_label].goparameters[go_label] # no need to copy here
2115
+ gsopt = results.estimates[base_est_label].models[go_label].copy()
2116
+ results.estimates[robust_est_label].add_gaugeoptimized(params, gsopt, go_label, comm, printer - 3)
2117
+ else:
2118
+ printer.log("-- Performing '%s' gauge optimization on %s estimate --" %
2119
+ (go_label, robust_est_label), 2)
2120
+ results.estimates[robust_est_label].add_gaugeoptimized(goparams, None, go_label, comm, printer - 3)
2046
2121
 
2047
2122
 
2048
2123
  def _add_badfit_estimates(results, base_estimate_label, badfit_options,
@@ -2285,9 +2360,16 @@ def _compute_wildcard_budget_1d_model(estimate, objfn_cache, mdc_objfn, paramete
2285
2360
  if gaugeopt_suite is None or gaugeopt_suite.gaugeopt_suite_names is None:
2286
2361
  gaugeopt_labels = None
2287
2362
  primitive_ops = list(ref.keys())
2363
+ if sum([v**2 for v in ref.values()]) < 1e-4:
2364
+ _warnings.warn("Reference values for 1D wildcard budget are all near-zero!"
2365
+ "This usually indicates an incorrect target model and will likely cause problems computing alpha.")
2366
+
2288
2367
  else:
2289
2368
  gaugeopt_labels = gaugeopt_suite.gaugeopt_suite_names
2290
2369
  primitive_ops = list(ref[list(gaugeopt_labels)[0]].keys())
2370
+ if sum([v**2 for v in ref[list(gaugeopt_labels)[0]].values()]) < 1e-4:
2371
+ _warnings.warn("Reference values for 1D wildcard budget are all near-zero!"
2372
+ "This usually indicates an incorrect target model and will likely cause problems computing alpha.")
2291
2373
 
2292
2374
  if gaugeopt_labels is None:
2293
2375
  wcm = _wild.PrimitiveOpsSingleScaleWildcardBudget(primitive_ops, [ref[k] for k in primitive_ops],
@@ -2312,21 +2394,38 @@ def _compute_1d_reference_values_and_name(estimate, badfit_options, gaugeopt_sui
2312
2394
  if gaugeopt_suite is None or gaugeopt_suite.gaugeopt_suite_names is None:
2313
2395
  final_model = estimate.models['final iteration estimate']
2314
2396
  target_model = estimate.models['target']
2315
- gaugeopt_model = _alg.gaugeopt_to_target(final_model, target_model)
2397
+
2398
+ if isinstance(final_model, _ExplicitOpModel):
2399
+ gaugeopt_model = _alg.gaugeopt_to_target(final_model, target_model)
2400
+ operations_dict = gaugeopt_model.operations
2401
+ targetops_dict = target_model.operations
2402
+ preps_dict = gaugeopt_model.preps
2403
+ targetpreps_dict = target_model.preps
2404
+ povmops_dict = gaugeopt_model.povms
2405
+ else:
2406
+ # Local/cloud noise models don't have default_gauge_group attribute and can't be gauge
2407
+ # optimized - at least not easily.
2408
+ gaugeopt_model = final_model
2409
+ operations_dict = gaugeopt_model.operation_blks['gates']
2410
+ targetops_dict = target_model.operation_blks['gates']
2411
+ preps_dict = gaugeopt_model.prep_blks['layers']
2412
+ targetpreps_dict = target_model.prep_blks['layers']
2413
+ povmops_dict = {} # HACK - need to rewrite povm_diamonddist below to work
2414
+
2316
2415
  dd = {}
2317
- for key, op in gaugeopt_model.operations.items():
2318
- dd[key] = 0.5 * _tools.diamonddist(op.to_dense(), target_model.operations[key].to_dense())
2416
+ for key, op in operations_dict.items():
2417
+ dd[key] = 0.5 * _tools.diamonddist(op.to_dense(), targetops_dict[key].to_dense())
2319
2418
  if dd[key] < 0: # indicates that diamonddist failed (cvxpy failure)
2320
2419
  _warnings.warn(("Diamond distance failed to compute %s reference value for 1D wildcard budget!"
2321
2420
  " Falling back to trace distance.") % str(key))
2322
- dd[key] = _tools.jtracedist(op.to_dense(), target_model.operations[key].to_dense())
2421
+ dd[key] = _tools.jtracedist(op.to_dense(), targetops_dict[key].to_dense())
2323
2422
 
2324
2423
  spamdd = {}
2325
- for key, op in gaugeopt_model.preps.items():
2424
+ for key, op in preps_dict.items():
2326
2425
  spamdd[key] = _tools.tracedist(_tools.vec_to_stdmx(op.to_dense(), 'pp'),
2327
- _tools.vec_to_stdmx(target_model.preps[key].to_dense(), 'pp'))
2426
+ _tools.vec_to_stdmx(targetpreps_dict[key].to_dense(), 'pp'))
2328
2427
 
2329
- for key in gaugeopt_model.povms.keys():
2428
+ for key in povmops_dict.keys():
2330
2429
  spamdd[key] = 0.5 * _tools.optools.povm_diamonddist(gaugeopt_model, target_model, key)
2331
2430
 
2332
2431
  dd['SPAM'] = sum(spamdd.values())
@@ -2573,23 +2672,14 @@ def _compute_wildcard_budget(objfn_cache, mdc_objfn, parameters, badfit_options,
2573
2672
  elif method_name == "barrier":
2574
2673
  _opt.optimize_wildcard_budget_barrier(budget, L1weights, mdc_objfn, two_dlogl_threshold,
2575
2674
  redbox_threshold, printer, **method_options)
2576
- elif method_name == "cvxopt":
2577
- _opt.optimize_wildcard_budget_cvxopt(budget, L1weights, mdc_objfn, two_dlogl_threshold,
2578
- redbox_threshold, printer, **method_options)
2579
- elif method_name == "cvxopt_smoothed":
2580
- _opt.optimize_wildcard_budget_cvxopt_smoothed(budget, L1weights, mdc_objfn,
2581
- two_dlogl_threshold, redbox_threshold,
2582
- printer, **method_options)
2583
- elif method_name == "cvxopt_small":
2584
- _opt.optimize_wildcard_budget_cvxopt_zeroreg(budget, L1weights, mdc_objfn,
2585
- two_dlogl_threshold, redbox_threshold, printer,
2586
- **method_options)
2587
2675
  elif method_name == "cvxpy_noagg":
2588
2676
  _opt.optimize_wildcard_budget_percircuit_only_cvxpy(budget, L1weights, mdc_objfn,
2589
2677
  redbox_threshold, printer,
2590
2678
  **method_options)
2591
2679
  elif method_name == "none":
2592
2680
  pass
2681
+ elif method_name in ("cvxopt", "cvxopt_smoothed", "cvxopt_small"):
2682
+ raise ValueError(f"Support for {method_name} was removed in pyGSTi release 0.9.13.")
2593
2683
  else:
2594
2684
  raise ValueError("Invalid wildcard method name: %s" % method_name)
2595
2685
 
@@ -2983,7 +3073,8 @@ class ModelEstimateResults(_proto.ProtocolResults):
2983
3073
  self.estimates[estimate_key] = estimate
2984
3074
 
2985
3075
  def add_model_test(self, target_model, themodel,
2986
- estimate_key='test', gaugeopt_keys="auto", verbosity=2):
3076
+ estimate_key='test', gaugeopt_keys="auto", verbosity=2,
3077
+ simulator: Optional[ForwardSimulator.Castable]=None):
2987
3078
  """
2988
3079
  Add a new model-test (i.e. non-optimized) estimate to this `Results` object.
2989
3080
 
@@ -3010,6 +3101,11 @@ class ModelEstimateResults(_proto.ProtocolResults):
3010
3101
  verbosity : int, optional
3011
3102
  Level of detail printed to stdout.
3012
3103
 
3104
+ simulator : ForwardSimulator.Castable or None
3105
+ Ignored if None. If not None, then we call
3106
+ fwdsim = ForwardSimulator.cast(simulator),
3107
+ and we set the .sim attribute of every Model we encounter to fwdsim.
3108
+
3013
3109
  Returns
3014
3110
  -------
3015
3111
  None
@@ -3030,7 +3126,7 @@ class ModelEstimateResults(_proto.ProtocolResults):
3030
3126
  from .modeltest import ModelTest as _ModelTest
3031
3127
  mdltest = _ModelTest(themodel, target_model, gaugeopt_suite,
3032
3128
  objfn_builder, badfit_options, name=estimate_key, verbosity=verbosity)
3033
- test_result = mdltest.run(self.data)
3129
+ test_result = mdltest.run(self.data, simulator=simulator)
3034
3130
  self.add_estimates(test_result)
3035
3131
 
3036
3132
  def view(self, estimate_keys, gaugeopt_keys=None):