pyGSTi 0.9.12.1__cp39-cp39-win32.whl → 0.9.13__cp39-cp39-win32.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. pyGSTi-0.9.13.dist-info/METADATA +197 -0
  2. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/RECORD +207 -217
  3. {pyGSTi-0.9.12.1.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 +42 -28
  7. pygsti/algorithms/fiducialselection.py +17 -8
  8. pygsti/algorithms/gaugeopt.py +2 -2
  9. pygsti/algorithms/germselection.py +87 -77
  10. pygsti/algorithms/mirroring.py +0 -388
  11. pygsti/algorithms/randomcircuit.py +165 -1333
  12. pygsti/algorithms/rbfit.py +0 -234
  13. pygsti/baseobjs/basis.py +94 -396
  14. pygsti/baseobjs/errorgenbasis.py +0 -132
  15. pygsti/baseobjs/errorgenspace.py +0 -10
  16. pygsti/baseobjs/label.py +52 -168
  17. pygsti/baseobjs/opcalc/fastopcalc.cp39-win32.pyd +0 -0
  18. pygsti/baseobjs/opcalc/fastopcalc.pyx +2 -2
  19. pygsti/baseobjs/polynomial.py +13 -595
  20. pygsti/baseobjs/statespace.py +1 -0
  21. pygsti/circuits/__init__.py +1 -1
  22. pygsti/circuits/circuit.py +682 -505
  23. pygsti/circuits/circuitconstruction.py +0 -4
  24. pygsti/circuits/circuitlist.py +47 -5
  25. pygsti/circuits/circuitparser/__init__.py +8 -8
  26. pygsti/circuits/circuitparser/fastcircuitparser.cp39-win32.pyd +0 -0
  27. pygsti/circuits/circuitstructure.py +3 -3
  28. pygsti/circuits/cloudcircuitconstruction.py +1 -1
  29. pygsti/data/datacomparator.py +2 -7
  30. pygsti/data/dataset.py +46 -44
  31. pygsti/data/hypothesistest.py +0 -7
  32. pygsti/drivers/bootstrap.py +0 -49
  33. pygsti/drivers/longsequence.py +2 -1
  34. pygsti/evotypes/basereps_cython.cp39-win32.pyd +0 -0
  35. pygsti/evotypes/chp/opreps.py +0 -61
  36. pygsti/evotypes/chp/statereps.py +0 -32
  37. pygsti/evotypes/densitymx/effectcreps.cpp +9 -10
  38. pygsti/evotypes/densitymx/effectreps.cp39-win32.pyd +0 -0
  39. pygsti/evotypes/densitymx/effectreps.pyx +1 -1
  40. pygsti/evotypes/densitymx/opreps.cp39-win32.pyd +0 -0
  41. pygsti/evotypes/densitymx/opreps.pyx +2 -2
  42. pygsti/evotypes/densitymx/statereps.cp39-win32.pyd +0 -0
  43. pygsti/evotypes/densitymx/statereps.pyx +1 -1
  44. pygsti/evotypes/densitymx_slow/effectreps.py +7 -23
  45. pygsti/evotypes/densitymx_slow/opreps.py +16 -23
  46. pygsti/evotypes/densitymx_slow/statereps.py +10 -3
  47. pygsti/evotypes/evotype.py +39 -2
  48. pygsti/evotypes/stabilizer/effectreps.cp39-win32.pyd +0 -0
  49. pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
  50. pygsti/evotypes/stabilizer/opreps.cp39-win32.pyd +0 -0
  51. pygsti/evotypes/stabilizer/opreps.pyx +0 -4
  52. pygsti/evotypes/stabilizer/statereps.cp39-win32.pyd +0 -0
  53. pygsti/evotypes/stabilizer/statereps.pyx +1 -5
  54. pygsti/evotypes/stabilizer/termreps.cp39-win32.pyd +0 -0
  55. pygsti/evotypes/stabilizer/termreps.pyx +0 -7
  56. pygsti/evotypes/stabilizer_slow/effectreps.py +0 -22
  57. pygsti/evotypes/stabilizer_slow/opreps.py +0 -4
  58. pygsti/evotypes/stabilizer_slow/statereps.py +0 -4
  59. pygsti/evotypes/statevec/effectreps.cp39-win32.pyd +0 -0
  60. pygsti/evotypes/statevec/effectreps.pyx +1 -1
  61. pygsti/evotypes/statevec/opreps.cp39-win32.pyd +0 -0
  62. pygsti/evotypes/statevec/opreps.pyx +2 -2
  63. pygsti/evotypes/statevec/statereps.cp39-win32.pyd +0 -0
  64. pygsti/evotypes/statevec/statereps.pyx +1 -1
  65. pygsti/evotypes/statevec/termreps.cp39-win32.pyd +0 -0
  66. pygsti/evotypes/statevec/termreps.pyx +0 -7
  67. pygsti/evotypes/statevec_slow/effectreps.py +0 -3
  68. pygsti/evotypes/statevec_slow/opreps.py +0 -5
  69. pygsti/extras/__init__.py +0 -1
  70. pygsti/extras/drift/stabilityanalyzer.py +3 -1
  71. pygsti/extras/interpygate/__init__.py +12 -0
  72. pygsti/extras/interpygate/core.py +0 -36
  73. pygsti/extras/interpygate/process_tomography.py +44 -10
  74. pygsti/extras/rpe/rpeconstruction.py +0 -2
  75. pygsti/forwardsims/__init__.py +1 -0
  76. pygsti/forwardsims/forwardsim.py +14 -55
  77. pygsti/forwardsims/mapforwardsim.py +69 -18
  78. pygsti/forwardsims/mapforwardsim_calc_densitymx.cp39-win32.pyd +0 -0
  79. pygsti/forwardsims/mapforwardsim_calc_densitymx.pyx +65 -66
  80. pygsti/forwardsims/mapforwardsim_calc_generic.py +91 -13
  81. pygsti/forwardsims/matrixforwardsim.py +63 -15
  82. pygsti/forwardsims/termforwardsim.py +8 -110
  83. pygsti/forwardsims/termforwardsim_calc_stabilizer.cp39-win32.pyd +0 -0
  84. pygsti/forwardsims/termforwardsim_calc_statevec.cp39-win32.pyd +0 -0
  85. pygsti/forwardsims/termforwardsim_calc_statevec.pyx +0 -651
  86. pygsti/forwardsims/torchfwdsim.py +265 -0
  87. pygsti/forwardsims/weakforwardsim.py +2 -2
  88. pygsti/io/__init__.py +1 -2
  89. pygsti/io/mongodb.py +0 -2
  90. pygsti/io/stdinput.py +6 -22
  91. pygsti/layouts/copalayout.py +10 -12
  92. pygsti/layouts/distlayout.py +0 -40
  93. pygsti/layouts/maplayout.py +103 -25
  94. pygsti/layouts/matrixlayout.py +99 -60
  95. pygsti/layouts/prefixtable.py +1534 -52
  96. pygsti/layouts/termlayout.py +1 -1
  97. pygsti/modelmembers/instruments/instrument.py +3 -3
  98. pygsti/modelmembers/instruments/tpinstrument.py +2 -2
  99. pygsti/modelmembers/modelmember.py +0 -17
  100. pygsti/modelmembers/operations/__init__.py +2 -4
  101. pygsti/modelmembers/operations/affineshiftop.py +1 -0
  102. pygsti/modelmembers/operations/composederrorgen.py +1 -1
  103. pygsti/modelmembers/operations/composedop.py +1 -24
  104. pygsti/modelmembers/operations/denseop.py +5 -5
  105. pygsti/modelmembers/operations/eigpdenseop.py +2 -2
  106. pygsti/modelmembers/operations/embeddederrorgen.py +1 -1
  107. pygsti/modelmembers/operations/embeddedop.py +0 -1
  108. pygsti/modelmembers/operations/experrorgenop.py +2 -2
  109. pygsti/modelmembers/operations/fullarbitraryop.py +1 -0
  110. pygsti/modelmembers/operations/fullcptpop.py +2 -2
  111. pygsti/modelmembers/operations/fulltpop.py +28 -6
  112. pygsti/modelmembers/operations/fullunitaryop.py +5 -4
  113. pygsti/modelmembers/operations/lindbladcoefficients.py +93 -78
  114. pygsti/modelmembers/operations/lindbladerrorgen.py +268 -441
  115. pygsti/modelmembers/operations/linearop.py +7 -27
  116. pygsti/modelmembers/operations/opfactory.py +1 -1
  117. pygsti/modelmembers/operations/repeatedop.py +1 -24
  118. pygsti/modelmembers/operations/staticstdop.py +1 -1
  119. pygsti/modelmembers/povms/__init__.py +3 -3
  120. pygsti/modelmembers/povms/basepovm.py +7 -36
  121. pygsti/modelmembers/povms/complementeffect.py +4 -9
  122. pygsti/modelmembers/povms/composedeffect.py +0 -320
  123. pygsti/modelmembers/povms/computationaleffect.py +1 -1
  124. pygsti/modelmembers/povms/computationalpovm.py +3 -1
  125. pygsti/modelmembers/povms/effect.py +3 -5
  126. pygsti/modelmembers/povms/marginalizedpovm.py +0 -79
  127. pygsti/modelmembers/povms/tppovm.py +74 -2
  128. pygsti/modelmembers/states/__init__.py +2 -5
  129. pygsti/modelmembers/states/composedstate.py +0 -317
  130. pygsti/modelmembers/states/computationalstate.py +3 -3
  131. pygsti/modelmembers/states/cptpstate.py +4 -4
  132. pygsti/modelmembers/states/densestate.py +6 -4
  133. pygsti/modelmembers/states/fullpurestate.py +0 -24
  134. pygsti/modelmembers/states/purestate.py +1 -1
  135. pygsti/modelmembers/states/state.py +5 -6
  136. pygsti/modelmembers/states/tpstate.py +28 -10
  137. pygsti/modelmembers/term.py +3 -6
  138. pygsti/modelmembers/torchable.py +50 -0
  139. pygsti/modelpacks/_modelpack.py +1 -1
  140. pygsti/modelpacks/smq1Q_ZN.py +3 -1
  141. pygsti/modelpacks/smq2Q_XXYYII.py +2 -1
  142. pygsti/modelpacks/smq2Q_XY.py +3 -3
  143. pygsti/modelpacks/smq2Q_XYI.py +2 -2
  144. pygsti/modelpacks/smq2Q_XYICNOT.py +3 -3
  145. pygsti/modelpacks/smq2Q_XYICPHASE.py +3 -3
  146. pygsti/modelpacks/smq2Q_XYXX.py +1 -1
  147. pygsti/modelpacks/smq2Q_XYZICNOT.py +3 -3
  148. pygsti/modelpacks/smq2Q_XYZZ.py +1 -1
  149. pygsti/modelpacks/stdtarget.py +0 -121
  150. pygsti/models/cloudnoisemodel.py +1 -2
  151. pygsti/models/explicitcalc.py +3 -3
  152. pygsti/models/explicitmodel.py +3 -13
  153. pygsti/models/fogistore.py +5 -3
  154. pygsti/models/localnoisemodel.py +1 -2
  155. pygsti/models/memberdict.py +0 -12
  156. pygsti/models/model.py +800 -65
  157. pygsti/models/modelconstruction.py +4 -4
  158. pygsti/models/modelnoise.py +2 -2
  159. pygsti/models/modelparaminterposer.py +1 -1
  160. pygsti/models/oplessmodel.py +1 -1
  161. pygsti/models/qutrit.py +15 -14
  162. pygsti/objectivefns/objectivefns.py +73 -138
  163. pygsti/objectivefns/wildcardbudget.py +2 -7
  164. pygsti/optimize/__init__.py +1 -0
  165. pygsti/optimize/arraysinterface.py +28 -0
  166. pygsti/optimize/customcg.py +0 -12
  167. pygsti/optimize/customlm.py +129 -323
  168. pygsti/optimize/customsolve.py +2 -2
  169. pygsti/optimize/optimize.py +0 -84
  170. pygsti/optimize/simplerlm.py +841 -0
  171. pygsti/optimize/wildcardopt.py +19 -598
  172. pygsti/protocols/confidenceregionfactory.py +28 -14
  173. pygsti/protocols/estimate.py +31 -14
  174. pygsti/protocols/gst.py +142 -68
  175. pygsti/protocols/modeltest.py +6 -10
  176. pygsti/protocols/protocol.py +9 -37
  177. pygsti/protocols/rb.py +450 -79
  178. pygsti/protocols/treenode.py +8 -2
  179. pygsti/protocols/vb.py +108 -206
  180. pygsti/protocols/vbdataframe.py +1 -1
  181. pygsti/report/factory.py +0 -15
  182. pygsti/report/fogidiagram.py +1 -17
  183. pygsti/report/modelfunction.py +12 -3
  184. pygsti/report/mpl_colormaps.py +1 -1
  185. pygsti/report/plothelpers.py +8 -2
  186. pygsti/report/reportables.py +41 -37
  187. pygsti/report/templates/offline/pygsti_dashboard.css +6 -0
  188. pygsti/report/templates/offline/pygsti_dashboard.js +12 -0
  189. pygsti/report/workspace.py +2 -14
  190. pygsti/report/workspaceplots.py +326 -504
  191. pygsti/tools/basistools.py +9 -36
  192. pygsti/tools/edesigntools.py +124 -96
  193. pygsti/tools/fastcalc.cp39-win32.pyd +0 -0
  194. pygsti/tools/fastcalc.pyx +35 -81
  195. pygsti/tools/internalgates.py +151 -15
  196. pygsti/tools/jamiolkowski.py +5 -5
  197. pygsti/tools/lindbladtools.py +19 -11
  198. pygsti/tools/listtools.py +0 -114
  199. pygsti/tools/matrixmod2.py +1 -1
  200. pygsti/tools/matrixtools.py +173 -339
  201. pygsti/tools/nameddict.py +1 -1
  202. pygsti/tools/optools.py +154 -88
  203. pygsti/tools/pdftools.py +0 -25
  204. pygsti/tools/rbtheory.py +3 -320
  205. pygsti/tools/slicetools.py +64 -12
  206. pyGSTi-0.9.12.1.dist-info/METADATA +0 -155
  207. pygsti/algorithms/directx.py +0 -711
  208. pygsti/evotypes/qibo/__init__.py +0 -33
  209. pygsti/evotypes/qibo/effectreps.py +0 -78
  210. pygsti/evotypes/qibo/opreps.py +0 -376
  211. pygsti/evotypes/qibo/povmreps.py +0 -98
  212. pygsti/evotypes/qibo/statereps.py +0 -174
  213. pygsti/extras/rb/__init__.py +0 -13
  214. pygsti/extras/rb/benchmarker.py +0 -957
  215. pygsti/extras/rb/dataset.py +0 -378
  216. pygsti/extras/rb/io.py +0 -814
  217. pygsti/extras/rb/simulate.py +0 -1020
  218. pygsti/io/legacyio.py +0 -385
  219. pygsti/modelmembers/povms/denseeffect.py +0 -142
  220. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/LICENSE +0 -0
  221. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/top_level.txt +0 -0
@@ -51,7 +51,6 @@ def mapfill_probs_atom(fwdsim, mx_to_fill, dest_indices, layout_atom, resource_a
51
51
 
52
52
  #TODO: if layout_atom is split, distribute somehow among processors(?) instead of punting for all but rank-0 above
53
53
  for iDest, iStart, remainder, iCache in layout_atom.table.contents:
54
- remainder = remainder.circuit_without_povm.layertup
55
54
 
56
55
  if iStart is None: # then first element of remainder is a state prep label
57
56
  rholabel = remainder[0]
@@ -73,7 +72,63 @@ def mapfill_probs_atom(fwdsim, mx_to_fill, dest_indices, layout_atom, resource_a
73
72
  mx_to_fill[final_indices] = povmreps[povm_lbl].probabilities(final_state, None, effect_labels)
74
73
  else:
75
74
  ereps = [effectreps[j] for j in layout_atom.elbl_indices_by_expcircuit[iDest]]
75
+ #print(ereps)
76
+ if shared_mem_leader:
77
+ for j, erep in zip(final_indices, ereps):
78
+ mx_to_fill[j] = erep.probability(final_state) # outcome probability
79
+ #raise Exception
80
+ #Version of the probability calculation that updates circuit probabilities conditionally based on
81
+ #Whether the circuit is sensitive to the parameter. If not we leave that circuit alone.
82
+ def cond_update_probs_atom(fwdsim, mx_to_fill, dest_indices, layout_atom, param_index, resource_alloc):
83
+
84
+ # The required ending condition is that array_to_fill on each processor has been filled. But if
85
+ # memory is being shared and resource_alloc contains multiple processors on a single host, we only
86
+ # want *one* (the rank=0) processor to perform the computation, since array_to_fill will be
87
+ # shared memory that we don't want to have muliple procs using simultaneously to compute the
88
+ # same thing. Thus, we carefully guard any shared mem updates/usage
89
+ # using "if shared_mem_leader" (and barriers, if needed) below.
90
+ shared_mem_leader = resource_alloc.is_host_leader if (resource_alloc is not None) else True
91
+
92
+ dest_indices = _slct.to_array(dest_indices) # make sure this is an array and not a slice
93
+ cacheSize = layout_atom.jac_table.cache_size_by_parameter[param_index]
94
+
95
+ #Create rhoCache
96
+ rho_cache = [None] * cacheSize # so we can store (s,p) tuples in cache
97
+
98
+ #Get operationreps and ereps now so we don't make unnecessary ._rep references
99
+ rhoreps = {rholbl: fwdsim.model._circuit_layer_operator(rholbl, 'prep')._rep for rholbl in layout_atom.rho_labels}
100
+ operationreps = {gl: fwdsim.model._circuit_layer_operator(gl, 'op')._rep for gl in layout_atom.op_labels}
101
+ povmreps = {plbl: fwdsim.model._circuit_layer_operator(plbl, 'povm')._rep for plbl in layout_atom.povm_labels}
102
+ if any([(povmrep is None) for povmrep in povmreps.values()]):
103
+ effectreps = {i: fwdsim.model._circuit_layer_operator(Elbl, 'povm')._rep
104
+ for i, Elbl in enumerate(layout_atom.full_effect_labels)} # cache these in future
105
+ else:
106
+ effectreps = None # not needed, as we use povm reps directly
107
+
108
+
109
+ #TODO: if layout_atom is split, distribute somehow among processors(?) instead of punting for all but rank-0 above
110
+
111
+ for iDest, iStart, remainder, iCache in layout_atom.jac_table.contents_by_parameter[param_index]:
112
+
113
+ if iStart is None: # then first element of remainder is a state prep label
114
+ rholabel = remainder[0]
115
+ init_state = rhoreps[rholabel]
116
+ remainder = remainder[1:]
117
+ else:
118
+ init_state = rho_cache[iStart] # [:,None]
119
+
120
+ final_state = propagate_staterep(init_state, [operationreps[gl] for gl in remainder])
121
+ if iCache is not None: rho_cache[iCache] = final_state # [:,0] #store this state in the cache
122
+
123
+ final_indices = [dest_indices[j] for j in layout_atom.elindices_by_expcircuit[iDest]]
124
+
125
+ if effectreps is None:
126
+ povm_lbl, *effect_labels = layout_atom.povm_and_elbls_by_expcircuit[iDest]
76
127
 
128
+ if shared_mem_leader:
129
+ mx_to_fill[final_indices] = povmreps[povm_lbl].probabilities(final_state, None, effect_labels)
130
+ else:
131
+ ereps = [effectreps[j] for j in layout_atom.elbl_indices_by_expcircuit[iDest]]
77
132
  if shared_mem_leader:
78
133
  for j, erep in zip(final_indices, ereps):
79
134
  mx_to_fill[j] = erep.probability(final_state) # outcome probability
@@ -82,11 +137,10 @@ def mapfill_probs_atom(fwdsim, mx_to_fill, dest_indices, layout_atom, resource_a
82
137
  def mapfill_dprobs_atom(fwdsim, mx_to_fill, dest_indices, dest_param_indices, layout_atom, param_indices,
83
138
  resource_alloc, eps):
84
139
 
85
- #eps = 1e-7
86
- #shared_mem_leader = resource_alloc.is_host_leader if (resource_alloc is not None) else True
140
+ num_params = fwdsim.model.num_params
87
141
 
88
142
  if param_indices is None:
89
- param_indices = list(range(fwdsim.model.num_params))
143
+ param_indices = list(range(num_params))
90
144
  if dest_param_indices is None:
91
145
  dest_param_indices = list(range(_slct.length(param_indices)))
92
146
 
@@ -105,19 +159,43 @@ def mapfill_dprobs_atom(fwdsim, mx_to_fill, dest_indices, dest_param_indices, la
105
159
  nEls = layout_atom.num_elements
106
160
  probs, shm = _smt.create_shared_ndarray(resource_alloc, (nEls,), 'd', memory_tracker=None)
107
161
  probs2, shm2 = _smt.create_shared_ndarray(resource_alloc, (nEls,), 'd', memory_tracker=None)
162
+ #probs2_test, shm2_test = _smt.create_shared_ndarray(resource_alloc, (nEls,), 'd', memory_tracker=None)
163
+
164
+ #mx_to_fill_test = mx_to_fill.copy()
165
+
108
166
  mapfill_probs_atom(fwdsim, probs, slice(0, nEls), layout_atom, resource_alloc) # probs != shared
109
167
 
110
- for i in range(fwdsim.model.num_params):
111
- #print("dprobs cache %d of %d" % (i,self.Np))
112
- if i in iParamToFinal:
113
- iFinal = iParamToFinal[i]
114
- vec = orig_vec.copy(); vec[i] += eps
115
- fwdsim.model.from_vector(vec, close=True)
116
- mapfill_probs_atom(fwdsim, probs2, slice(0, nEls), layout_atom, resource_alloc)
117
- _fas(mx_to_fill, [dest_indices, iFinal], (probs2 - probs) / eps)
118
- fwdsim.model.from_vector(orig_vec, close=True)
168
+ #Split off the first finite difference step, as the pattern I want in the loop with each step
169
+ #is to simultaneously undo the previous update and apply the new one.
170
+ if len(param_indices)>0:
171
+ probs2[:] = probs[:]
172
+ first_param_idx = param_indices[0]
173
+ iFinal = iParamToFinal[first_param_idx]
174
+ fwdsim.model.set_parameter_value(first_param_idx, orig_vec[first_param_idx]+eps)
175
+ #mapfill_probs_atom(fwdsim, probs2, slice(0, nEls), layout_atom, resource_alloc)
176
+ cond_update_probs_atom(fwdsim, probs2, slice(0, nEls), layout_atom, first_param_idx, resource_alloc)
177
+ #assert _np.linalg.norm(probs2_test-probs2) < 1e-10
178
+ #print(f'{_np.linalg.norm(probs2_test-probs2)=}')
179
+ _fas(mx_to_fill, [dest_indices, iFinal], (probs2 - probs) / eps)
180
+
181
+
182
+ for i in range(1, len(param_indices)):
183
+ probs2[:] = probs[:]
184
+ iFinal = iParamToFinal[param_indices[i]]
185
+ fwdsim.model.set_parameter_values([param_indices[i-1], param_indices[i]],
186
+ [orig_vec[param_indices[i-1]], orig_vec[param_indices[i]]+eps])
187
+ #mapfill_probs_atom(fwdsim, probs2, slice(0, nEls), layout_atom, resource_alloc)
188
+ cond_update_probs_atom(fwdsim, probs2, slice(0, nEls), layout_atom, param_indices[i], resource_alloc)
189
+ #assert _np.linalg.norm(probs2_test-probs2) < 1e-10
190
+ #print(f'{_np.linalg.norm(probs2_test-probs2)=}')
191
+ _fas(mx_to_fill, [dest_indices, iFinal], (probs2 - probs) / eps)
192
+
193
+ #reset the final model parameter we changed to it's original value.
194
+ fwdsim.model.set_parameter_value(param_indices[-1], orig_vec[param_indices[-1]])
195
+
119
196
  _smt.cleanup_shared_ndarray(shm)
120
197
  _smt.cleanup_shared_ndarray(shm2)
198
+ #_smt.cleanup_shared_ndarray(shm2_test)
121
199
 
122
200
 
123
201
  def mapfill_TDchi2_terms(fwdsim, array_to_fill, dest_indices, num_outcomes, layout_atom, dataset_rows,
@@ -29,6 +29,8 @@ from pygsti.tools import mpitools as _mpit
29
29
  from pygsti.tools import sharedmemtools as _smt
30
30
  from pygsti.tools import slicetools as _slct
31
31
  from pygsti.tools.matrixtools import _fas
32
+ from pygsti.tools import listtools as _lt
33
+ from pygsti.circuits import CircuitList as _CircuitList
32
34
 
33
35
  _dummy_profiler = _DummyProfiler()
34
36
 
@@ -132,12 +134,18 @@ class SimpleMatrixForwardSimulator(_ForwardSimulator):
132
134
  obj_wrtFilter = [] # values = object-local param indices
133
135
  relevant_gpindices = [] # indices into original wrt_filter'd indices
134
136
 
135
- gpindices = obj.gpindices_as_array()
137
+ if isinstance(obj.gpindices, slice):
138
+ gpindices_list = _slct.indices(obj.gpindices)
139
+ elif obj.gpindices is None:
140
+ gpindices_list = []
141
+ else:
142
+ gpindices_list = list(obj.gpindices)
143
+ gpindices_set = set(gpindices_list)
136
144
 
137
145
  for ii, i in enumerate(wrt_filter):
138
- if i in gpindices:
146
+ if i in gpindices_set:
139
147
  relevant_gpindices.append(ii)
140
- obj_wrtFilter.append(list(gpindices).index(i))
148
+ obj_wrtFilter.append(gpindices_list.index(i))
141
149
  relevant_gpindices = _np.array(relevant_gpindices, _np.int64)
142
150
  if len(relevant_gpindices) == 1:
143
151
  #Don't return a length-1 list, as this doesn't index numpy arrays
@@ -590,7 +598,7 @@ class SimpleMatrixForwardSimulator(_ForwardSimulator):
590
598
  use_scaling = False # Hardcoded for now
591
599
  assert(time is None), "MatrixForwardSimulator cannot be used to simulate time-dependent circuits"
592
600
 
593
- expanded_circuit_outcomes = circuit.expand_instruments_and_separate_povm(self.model, outcomes)
601
+ expanded_circuit_outcomes = self.model.expand_instruments_and_separate_povm(circuit, outcomes)
594
602
  outcome_to_index = {outc: i for i, outc in enumerate(outcomes)}
595
603
  for spc, spc_outcomes in expanded_circuit_outcomes.items(): # spc is a SeparatePOVMCircuit
596
604
  indices = [outcome_to_index[o] for o in spc_outcomes]
@@ -1025,7 +1033,7 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1025
1033
  return hProdCache
1026
1034
 
1027
1035
  def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types=('E',),
1028
- derivative_dimensions=None, verbosity=0):
1036
+ derivative_dimensions=None, verbosity=0, layout_creation_circuit_cache= None):
1029
1037
  """
1030
1038
  Constructs an circuit-outcome-probability-array (COPA) layout for a list of circuits.
1031
1039
 
@@ -1056,6 +1064,12 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1056
1064
  Determines how much output to send to stdout. 0 means no output, higher
1057
1065
  integers mean more output.
1058
1066
 
1067
+ layout_creation_circuit_cache : dict, optional (default None)
1068
+ A precomputed dictionary serving as a cache for completed
1069
+ circuits. I.e. circuits with prep labels and POVM labels appended.
1070
+ Along with other useful pre-computed circuit structures used in layout
1071
+ creation.
1072
+
1059
1073
  Returns
1060
1074
  -------
1061
1075
  MatrixCOPALayout
@@ -1105,7 +1119,8 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1105
1119
  assert(_np.prod((na,) + npp) <= nprocs), "Processor grid size exceeds available processors!"
1106
1120
 
1107
1121
  layout = _MatrixCOPALayout(circuits, self.model, dataset, natoms,
1108
- na, npp, param_dimensions, param_blk_sizes, resource_alloc, verbosity)
1122
+ na, npp, param_dimensions, param_blk_sizes, resource_alloc, verbosity,
1123
+ layout_creation_circuit_cache=layout_creation_circuit_cache)
1109
1124
 
1110
1125
  if mem_limit is not None:
1111
1126
  loc_nparams1 = num_params / npp[0] if len(npp) > 0 else 0
@@ -1132,13 +1147,6 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1132
1147
  (blk1, blk2), max_atom_cachesize,
1133
1148
  self.model.evotype.minimal_dim(self.model.state_space))
1134
1149
 
1135
- #def approx_mem_estimate(natoms, np1, np2):
1136
- # approx_cachesize = (num_circuits / natoms) * 1.3 # inflate expected # circuits per atom => cache_size
1137
- # return _bytes_for_array_types(array_types, num_elements, num_elements / natoms,
1138
- # num_circuits, num_circuits / natoms,
1139
- # (num_params, num_params), (num_params / np1, num_params / np2),
1140
- # approx_cachesize, self.model.state_space.dim)
1141
-
1142
1150
  GB = 1.0 / 1024.0**3
1143
1151
  if mem_estimate > mem_limit:
1144
1152
  raise MemoryError("Not enough memory for desired layout! (limit=%.1fGB, required=%.1fGB)" % (
@@ -1147,6 +1155,46 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1147
1155
  printer.log(" Esimated memory required = %.1fGB" % (mem_estimate * GB))
1148
1156
 
1149
1157
  return layout
1158
+
1159
+ @staticmethod
1160
+ def create_copa_layout_circuit_cache(circuits, model, dataset=None):
1161
+ """
1162
+ Helper function for pre-computing/pre-processing circuits structures
1163
+ used in matrix layout creation.
1164
+ """
1165
+ cache = dict()
1166
+ completed_circuits, split_circuits = model.complete_circuits(circuits, return_split=True)
1167
+
1168
+ cache['completed_circuits'] = {ckt: comp_ckt for ckt, comp_ckt in zip(circuits, completed_circuits)}
1169
+ cache['split_circuits'] = {ckt: split_ckt for ckt, split_ckt in zip(circuits, split_circuits)}
1170
+
1171
+ if dataset is not None:
1172
+ aliases = circuits.op_label_aliases if isinstance(circuits, _CircuitList) else None
1173
+ ds_circuits = _lt.apply_aliases_to_circuits(circuits, aliases)
1174
+ unique_outcomes_list = []
1175
+ for ckt in ds_circuits:
1176
+ ds_row = dataset[ckt]
1177
+ unique_outcomes_list.append(ds_row.unique_outcomes if ds_row is not None else None)
1178
+ else:
1179
+ unique_outcomes_list = [None]*len(circuits)
1180
+
1181
+ expanded_circuit_outcome_list = model.bulk_expand_instruments_and_separate_povm(circuits,
1182
+ observed_outcomes_list = unique_outcomes_list,
1183
+ split_circuits = split_circuits)
1184
+
1185
+ expanded_circuit_cache = {ckt: expanded_ckt for ckt,expanded_ckt in zip(circuits, expanded_circuit_outcome_list)}
1186
+
1187
+ cache['expanded_and_separated_circuits'] = expanded_circuit_cache
1188
+
1189
+ expanded_subcircuits_no_spam_cache = dict()
1190
+ for expc_outcomes in cache['expanded_and_separated_circuits'].values():
1191
+ for sep_povm_c, _ in expc_outcomes.items(): # for each expanded cir from unique_i-th circuit
1192
+ exp_nospam_c = sep_povm_c.circuit_without_povm[1:]
1193
+ expanded_subcircuits_no_spam_cache[exp_nospam_c] = exp_nospam_c.expand_subcircuits()
1194
+
1195
+ cache['expanded_subcircuits_no_spam'] = expanded_subcircuits_no_spam_cache
1196
+
1197
+ return cache
1150
1198
 
1151
1199
  def _scale_exp(self, scale_exps):
1152
1200
  old_err = _np.seterr(over='ignore')
@@ -1194,7 +1242,8 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1194
1242
  # dp_dOps[i,j] = dot( e, dot( d_gs, rho ) )[0,i,j,0]
1195
1243
  # dp_dOps = squeeze( dot( e, dot( d_gs, rho ) ), axis=(0,3))
1196
1244
  old_err2 = _np.seterr(invalid='ignore', over='ignore')
1197
- dp_dOps = _np.squeeze(_np.dot(e, _np.dot(d_gs, rho)), axis=(0, 3)) * scale_vals[:, None]
1245
+ path = _np.einsum_path('hk,ijkl,lm->ij', e, d_gs, rho, optimize='optimal')
1246
+ dp_dOps = _np.einsum('hk,ijkl,lm->ij', e, d_gs, rho, optimize=path[0]) * scale_vals[:, None]
1198
1247
  _np.seterr(**old_err2)
1199
1248
  # may overflow, but OK ; shape == (len(circuit_list), nDerivCols)
1200
1249
  # may also give invalid value due to scale_vals being inf and dot-prod being 0. In
@@ -1234,7 +1283,6 @@ class MatrixForwardSimulator(_DistributableForwardSimulator, SimpleMatrixForward
1234
1283
  # dp_drhos[i,J0+J] = sum_kl e[0,k] gs[i,k,l] drhoP[l,J]
1235
1284
  # dp_drhos[i,J0+J] = dot(e, gs, drhoP)[0,i,J]
1236
1285
  # dp_drhos[:,J0+J] = squeeze(dot(e, gs, drhoP),axis=(0,))[:,J]
1237
-
1238
1286
  dp_drhos = _np.zeros((nCircuits, nOpDerivCols))
1239
1287
  _fas(dp_drhos, [None, rho_gpindices],
1240
1288
  _np.squeeze(_np.dot(_np.dot(e, gs),
@@ -243,16 +243,6 @@ class TermForwardSimulator(_DistributableForwardSimulator):
243
243
  # and this is done by the parent model which will cause _set_evotype to be called.
244
244
  return state
245
245
 
246
- #OLD - now we have a _set_evotype method.
247
- #@_ForwardSimulator.model.setter
248
- #def model(self, val):
249
- # _ForwardSimulator.model.fset(self, val) # set the base class property (self.model)
250
- #
251
- # #Do some additional initialization
252
- # if self.model.evotype not in ("svterm", "cterm"):
253
- # #raise ValueError(f"Evolution type {self.model.evotype} is incompatible with term-based calculations")
254
- # _warnings.warn("Evolution type %s is incompatible with term-based calculations" % self.model.evotype)
255
-
256
246
  def copy(self):
257
247
  """
258
248
  Return a shallow copy of this TermForwardSimulator.
@@ -267,7 +257,7 @@ class TermForwardSimulator(_DistributableForwardSimulator):
267
257
  self.oob_check_interval, self.cache)
268
258
 
269
259
  def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types=('E',),
270
- derivative_dimension=None, verbosity=0):
260
+ derivative_dimension=None, verbosity=0, layout_creation_circuit_cache=None):
271
261
  """
272
262
  Constructs an circuit-outcome-probability-array (COPA) layout for a list of circuits.
273
263
 
@@ -296,6 +286,12 @@ class TermForwardSimulator(_DistributableForwardSimulator):
296
286
  verbosity : int or VerbosityPrinter
297
287
  Determines how much output to send to stdout. 0 means no output, higher
298
288
  integers mean more output.
289
+
290
+ layout_creation_circuit_cache:
291
+ A precomputed dictionary serving as a cache for completed
292
+ circuits. I.e. circuits with prep labels and POVM labels appended.
293
+ Along with other useful pre-computed circuit structures used in layout
294
+ creation.
299
295
 
300
296
  Returns
301
297
  -------
@@ -330,6 +326,7 @@ class TermForwardSimulator(_DistributableForwardSimulator):
330
326
  printer.log(" %d atoms, parameter block size limits %s" % (natoms, str(param_blk_sizes)))
331
327
  assert(_np.prod((na,) + npp) <= nprocs), "Processor grid size exceeds available processors!"
332
328
 
329
+ # TODO: Layout circuit creation cache unused for TermCOPALayout
333
330
  layout = _TermCOPALayout(circuits, self.model, dataset, natoms, na, npp, param_dimensions,
334
331
  param_blk_sizes, resource_alloc, printer)
335
332
  #MEM debug_prof.print_memory("CreateLayout2 - nAtoms = %d" % len(layout.atoms), True)
@@ -409,105 +406,6 @@ class TermForwardSimulator(_DistributableForwardSimulator):
409
406
  hpolys[0], hpolys[1], self.model.to_vector(), (nEls, len(wrtInds1), len(wrtInds2)))
410
407
  _fas(array_to_fill, [slice(0, array_to_fill.shape[0]), dest_param_slice1, dest_param_slice2], hprobs)
411
408
 
412
- #DIRECT FNS - keep these around, but they need to be updated (as do routines in fastreplib.pyx)
413
- #def _prs_directly(self, layout_atom, resource_alloc): #comm=None, mem_limit=None, reset_wts=True, repcache=None):
414
- # """
415
- # Compute probabilities of `layout`'s circuits using "direct" mode.
416
- #
417
- # Parameters
418
- # ----------
419
- # layout : CircuitOutcomeProbabilityArrayLayout
420
- # The layout.
421
- #
422
- # comm : mpi4py.MPI.Comm, optional
423
- # When not None, an MPI communicator for distributing the computation
424
- # across multiple processors. Distribution is performed over
425
- # subtrees of eval_tree (if it is split).
426
- #
427
- # mem_limit : int, optional
428
- # A rough memory limit in bytes.
429
- #
430
- # reset_wts : bool, optional
431
- # Whether term magnitudes should be updated based on current term coefficients
432
- # (which are based on the current point in model-parameter space) or not.
433
- #
434
- # repcache : dict, optional
435
- # A cache of term representations for increased performance.
436
- # """
437
- # prs = _np.empty(layout_atom.num_elements, 'd')
438
- # #print("Computing prs directly for %d circuits" % len(circuit_list))
439
- # if repcache is None: repcache = {} # new repcache...
440
- # k = 0 # *linear* evaluation order so we know final indices are just running
441
- # for i in eval_tree.evaluation_order():
442
- # circuit = eval_tree[i]
443
- # #print("Computing prs directly: circuit %d of %d" % (i,len(circuit_list)))
444
- # assert(self.evotype == "svterm") # for now, just do SV case
445
- # fastmode = False # start with slow mode
446
- # wtTol = 0.1
447
- # rholabel = circuit[0]
448
- # opStr = circuit[1:]
449
- # elabels = eval_tree.simplified_circuit_elabels[i]
450
- # prs[k:k + len(elabels)] = replib.SV_prs_directly(self, rholabel, elabels, opStr,
451
- # repcache, comm, mem_limit, fastmode, wtTol, reset_wts,
452
- # self.times_debug)
453
- # k += len(elabels)
454
- # #print("PRS = ",prs)
455
- # return prs
456
- #
457
- #def _dprs_directly(self, eval_tree, wrt_slice, comm=None, mem_limit=None, reset_wts=True, repcache=None):
458
- # """
459
- # Compute probability derivatives of `eval_tree`'s circuits using "direct" mode.
460
- #
461
- # Parameters
462
- # ----------
463
- # eval_tree : TermEvalTree
464
- # The evaluation tree.
465
- #
466
- # wrt_slice : slice
467
- # A slice specifying which model parameters to differentiate with respect to.
468
- #
469
- # comm : mpi4py.MPI.Comm, optional
470
- # When not None, an MPI communicator for distributing the computation
471
- # across multiple processors. Distribution is performed over
472
- # subtrees of eval_tree (if it is split).
473
- #
474
- # mem_limit : int, optional
475
- # A rough memory limit in bytes.
476
- #
477
- # reset_wts : bool, optional
478
- # Whether term magnitudes should be updated based on current term coefficients
479
- # (which are based on the current point in model-parameter space) or not.
480
- #
481
- # repcache : dict, optional
482
- # A cache of term representations for increased performance.
483
- # """
484
- # #Note: Finite difference derivatives are SLOW!
485
- # if wrt_slice is None:
486
- # wrt_indices = list(range(self.Np))
487
- # elif isinstance(wrt_slice, slice):
488
- # wrt_indices = _slct.indices(wrt_slice)
489
- # else:
490
- # wrt_indices = wrt_slice
491
- #
492
- # eps = 1e-6 # HARDCODED
493
- # probs = self._prs_directly(eval_tree, comm, mem_limit, reset_wts, repcache)
494
- # dprobs = _np.empty((eval_tree.num_final_elements(), len(wrt_indices)), 'd')
495
- # orig_vec = self.to_vector().copy()
496
- # iParamToFinal = {i: ii for ii, i in enumerate(wrt_indices)}
497
- # for i in range(self.Np):
498
- # #print("direct dprobs cache %d of %d" % (i,self.Np))
499
- # if i in iParamToFinal: # LATER: add MPI support?
500
- # iFinal = iParamToFinal[i]
501
- # vec = orig_vec.copy(); vec[i] += eps
502
- # self.from_vector(vec, close=True)
503
- # dprobs[:, iFinal] = (self._prs_directly(eval_tree,
504
- # comm=None,
505
- # mem_limit=None,
506
- # reset_wts=False,
507
- # repcache=repcache) - probs) / eps
508
- # self.from_vector(orig_vec, close=True)
509
- # return dprobs
510
-
511
409
  ## ----- Find a "minimal" path set (i.e. find thresholds for each circuit -----
512
410
  def _compute_pruned_pathmag_threshold(self, rholabel, elabels, circuit, polynomial_vindices_per_int,
513
411
  repcache, circuitsetup_cache,