pyGSTi 0.9.12.1__cp38-cp38-win32.whl → 0.9.13__cp38-cp38-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 +185 -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.cp38-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.cp38-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.cp38-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.cp38-win32.pyd +0 -0
  39. pygsti/evotypes/densitymx/effectreps.pyx +1 -1
  40. pygsti/evotypes/densitymx/opreps.cp38-win32.pyd +0 -0
  41. pygsti/evotypes/densitymx/opreps.pyx +2 -2
  42. pygsti/evotypes/densitymx/statereps.cp38-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.cp38-win32.pyd +0 -0
  49. pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
  50. pygsti/evotypes/stabilizer/opreps.cp38-win32.pyd +0 -0
  51. pygsti/evotypes/stabilizer/opreps.pyx +0 -4
  52. pygsti/evotypes/stabilizer/statereps.cp38-win32.pyd +0 -0
  53. pygsti/evotypes/stabilizer/statereps.pyx +1 -5
  54. pygsti/evotypes/stabilizer/termreps.cp38-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.cp38-win32.pyd +0 -0
  60. pygsti/evotypes/statevec/effectreps.pyx +1 -1
  61. pygsti/evotypes/statevec/opreps.cp38-win32.pyd +0 -0
  62. pygsti/evotypes/statevec/opreps.pyx +2 -2
  63. pygsti/evotypes/statevec/statereps.cp38-win32.pyd +0 -0
  64. pygsti/evotypes/statevec/statereps.pyx +1 -1
  65. pygsti/evotypes/statevec/termreps.cp38-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.cp38-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.cp38-win32.pyd +0 -0
  84. pygsti/forwardsims/termforwardsim_calc_statevec.cp38-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.cp38-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
@@ -7,6 +7,7 @@ import numpy as _np
7
7
  import numpy.linalg as _lin
8
8
 
9
9
  from pygsti.tools.basistools import change_basis
10
+ from pygsti.tools.legacytools import deprecate
10
11
 
11
12
 
12
13
  #Helper functions
@@ -15,8 +16,11 @@ def multi_kron(*a):
15
16
  return reduce(_np.kron, a)
16
17
 
17
18
 
19
+ @deprecate("Calls to this function should be replaced with in-lined code: matrix.reshape((matrix.size, 1), 'F')")
18
20
  def vec(matrix):
19
- """A function that vectorizes a matrix.
21
+ """
22
+ Returns an explicit column-vector representation of a square matrix, obtained by reading
23
+ from the square matrix in column-major order.
20
24
 
21
25
  Args:
22
26
  matrix (list,numpy.ndarray): NxN matrix
@@ -30,11 +34,12 @@ def vec(matrix):
30
34
  """
31
35
  matrix = _np.array(matrix)
32
36
  if matrix.shape == (len(matrix), len(matrix)):
33
- return _np.array([_np.concatenate(_np.array(matrix).T)]).T
37
+ return matrix.reshape(shape=(matrix.size, 1), order='F')
34
38
  else:
35
39
  raise ValueError('The input matrix must be square.')
36
40
 
37
41
 
42
+ @deprecate("Calls to this function should be replaced by unvec_square(vectorized, 'F')")
38
43
  def unvec(vectorized):
39
44
  """A function that vectorizes a process in the basis of matrix units, sorted first
40
45
  by column, then row.
@@ -49,13 +54,42 @@ def unvec(vectorized):
49
54
  ValueError: If the length of the input is not a perfect square
50
55
 
51
56
  """
52
- vectorized = _np.array(vectorized)
53
- length = int(_np.sqrt(max(vectorized.shape)))
54
- if len(vectorized) == length ** 2:
55
- return _np.reshape(vectorized, [length, length]).T
57
+ return unvec_square(vectorized, order='F')
58
+
59
+
60
+ def unvec_square(vectorized, order):
61
+ """
62
+ Takes a vector whose length is a perfect square, and returns a square matrix
63
+ representation by reading from the vectors entries to define the matrix in
64
+ column-major order (order='F') or row-major order (order='C').
65
+
66
+ Args:
67
+ vectorized: array-like, where np.array(vectorized).size is a perfect square.
68
+ order: 'F' or 'C'
69
+
70
+ Returns:
71
+ numpy.ndarray: NxN dimensional array
72
+
73
+ Raises:
74
+ ValueError: If the length of the input is not a perfect square.
75
+
76
+ """
77
+ assert order == 'F' or order == 'C'
78
+ if not isinstance(vectorized, _np.ndarray):
79
+ vectorized = _np.array(vectorized)
80
+
81
+ if vectorized.ndim == 2:
82
+ assert min(vectorized.shape) == 1
83
+ vectorized = vectorized.ravel()
84
+ elif vectorized.ndim > 2:
85
+ raise ValueError('vectorized.ndim must be <= 2.')
86
+
87
+ n = int(_np.sqrt(max(vectorized.shape)))
88
+ if len(vectorized) == n ** 2:
89
+ return vectorized.reshape((n, n), order=order)
56
90
  else:
57
- raise ValueError(
58
- 'The input vector length must be a perfect square, but this input has length %d.' % len(vectorized))
91
+ msg = 'The input vector length must be a perfect square, but this input has length %d.' % len(vectorized)
92
+ raise ValueError(msg)
59
93
 
60
94
 
61
95
  def split(n, a):
@@ -129,7 +163,7 @@ def run_process_tomography(state_to_density_matrix_fn, n_qubits=1, comm=None,
129
163
  states = _itertools.product(one_qubit_states, repeat=n_qubits)
130
164
  states = [multi_kron(*state) for state in states]
131
165
  in_density_matrices = [_np.outer(state, state.conj()) for state in states]
132
- in_states = _np.column_stack(list([vec(rho) for rho in in_density_matrices]))
166
+ in_states = _np.column_stack(list([rho.ravel(order='F') for rho in in_density_matrices]))
133
167
  my_states = split(size, states)[rank]
134
168
  if verbose:
135
169
  print("Process %d of %d evaluating %d input states." % (rank, size, len(my_states)))
@@ -150,7 +184,7 @@ def run_process_tomography(state_to_density_matrix_fn, n_qubits=1, comm=None,
150
184
  out_density_matrices = _np.array([y for x in gathered_out_density_matrices for y in x])
151
185
  # Sort the list by time
152
186
  out_density_matrices = _np.transpose(out_density_matrices, [1, 0, 2, 3])
153
- out_states = [_np.column_stack(list([vec(rho) for rho in density_matrices_at_time]))
187
+ out_states = [_np.column_stack(list([rho.ravel(order='F') for rho in density_matrices_at_time]))
154
188
  for density_matrices_at_time in out_density_matrices]
155
189
  process_matrices = [_np.dot(out_states_at_time, _lin.inv(in_states)) for out_states_at_time in out_states]
156
190
  process_matrices = [change_basis(process_matrix_at_time, 'col', basis)
@@ -113,8 +113,6 @@ def create_parameterized_rpe_model(alpha_true, epsilon_true, aux_rot, spam_depol
113
113
 
114
114
  return outputModel
115
115
 
116
- #def make_rpe_alpha_str_lists(k_list,angleStr,rpeconfig_inst):
117
-
118
116
 
119
117
  def create_rpe_angle_circuit_lists(k_list, angle_name, rpeconfig_inst):
120
118
  """
@@ -12,6 +12,7 @@ pyGSTi Forward Simulators Python Package
12
12
 
13
13
  from .forwardsim import ForwardSimulator
14
14
  from .mapforwardsim import SimpleMapForwardSimulator, MapForwardSimulator
15
+ from .torchfwdsim import TorchForwardSimulator
15
16
  from .matrixforwardsim import SimpleMatrixForwardSimulator, MatrixForwardSimulator
16
17
  from .termforwardsim import TermForwardSimulator
17
18
  from .weakforwardsim import WeakForwardSimulator
@@ -63,9 +63,7 @@ class ForwardSimulator(_NicelySerializable):
63
63
  if isinstance(obj, ForwardSimulator):
64
64
  return obj
65
65
  elif isinstance(obj, str):
66
- if obj == "auto":
67
- return _MapFSim() if (num_qubits is None or num_qubits > 2) else _MatrixFSim()
68
- elif obj == "map":
66
+ if obj == "auto" or obj == "map":
69
67
  return _MapFSim()
70
68
  elif obj == "matrix":
71
69
  return _MatrixFSim()
@@ -147,57 +145,6 @@ class ForwardSimulator(_NicelySerializable):
147
145
  `evotype` will be `None` when the current model is None"""
148
146
  pass
149
147
 
150
- #def to_vector(self):
151
- # """
152
- # Returns the parameter vector of the associated Model.
153
- #
154
- # Returns
155
- # -------
156
- # numpy array
157
- # The vectorized model parameters.
158
- # """
159
- # return self.paramvec
160
- #
161
- #def from_vector(self, v, close=False, nodirty=False):
162
- # """
163
- # The inverse of to_vector.
164
- #
165
- # Initializes the Model-like members of this
166
- # calculator based on `v`. Used for computing finite-difference derivatives.
167
- #
168
- # Parameters
169
- # ----------
170
- # v : numpy.ndarray
171
- # The parameter vector.
172
- #
173
- # close : bool, optional
174
- # Set to `True` if `v` is close to the current parameter vector.
175
- # This can make some operations more efficient.
176
- #
177
- # nodirty : bool, optional
178
- # If True, the framework for marking and detecting when operations
179
- # have changed and a Model's parameter-vector needs to be updated
180
- # is disabled. Disabling this will increases the speed of the call.
181
- #
182
- # Returns
183
- # -------
184
- # None
185
- # """
186
- # #Note: this *will* initialize the parent Model's objects too,
187
- # # since only references to preps, effects, and gates are held
188
- # # by the calculator class. ORDER is important, as elements of
189
- # # POVMs and Instruments rely on a fixed from_vector ordering
190
- # # of their simplified effects/gates.
191
- # self.paramvec = v.copy() # now self.paramvec is *not* the same as the Model's paramvec
192
- # self.sos.from_vector(v, close, nodirty) # so don't always want ", nodirty=True)" - we
193
- # # need to set dirty flags so *parent* will re-init it's paramvec...
194
- #
195
- # #Re-init reps for computation
196
- # #self.operationreps = { i:self.operations[lbl].torep() for lbl,i in self.operation_lookup.items() }
197
- # #self.operationreps = { lbl:g.torep() for lbl,g in gates.items() }
198
- # #self.prepreps = { lbl:p.torep('prep') for lbl,p in preps.items() }
199
- # #self.effectreps = { lbl:e.torep('effect') for lbl,e in effects.items() }
200
-
201
148
  def _compute_circuit_outcome_probabilities(self, array_to_fill, circuit, outcomes, resource_alloc, time=None):
202
149
  raise NotImplementedError("Derived classes should implement this!")
203
150
 
@@ -323,7 +270,8 @@ class ForwardSimulator(_NicelySerializable):
323
270
  # ---------------------------------------------------------------------------
324
271
 
325
272
  def create_layout(self, circuits, dataset=None, resource_alloc=None,
326
- array_types=(), derivative_dimensions=None, verbosity=0):
273
+ array_types=(), derivative_dimensions=None, verbosity=0,
274
+ layout_creation_circuit_cache = None):
327
275
  """
328
276
  Constructs an circuit-outcome-probability-array (COPA) layout for `circuits` and `dataset`.
329
277
 
@@ -364,6 +312,8 @@ class ForwardSimulator(_NicelySerializable):
364
312
  verbosity : int or VerbosityPrinter
365
313
  Determines how much output to send to stdout. 0 means no output, higher
366
314
  integers mean more output.
315
+
316
+
367
317
 
368
318
  Returns
369
319
  -------
@@ -378,6 +328,15 @@ class ForwardSimulator(_NicelySerializable):
378
328
  derivative_dimensions = tuple()
379
329
  return _CircuitOutcomeProbabilityArrayLayout.create_from(circuits, self.model, dataset, derivative_dimensions,
380
330
  resource_alloc=resource_alloc)
331
+
332
+ @staticmethod
333
+ def create_copa_layout_circuit_cache(circuits, model, dataset=None):
334
+ """
335
+ Helper function for pre-computing/pre-processing circuits structures
336
+ used in matrix layout creation.
337
+ """
338
+ msg = "Not currently implemented for this forward simulator class."
339
+ raise NotImplementedError(msg)
381
340
 
382
341
  def bulk_probs(self, circuits, clip_to=None, resource_alloc=None, smartc=None):
383
342
  """
@@ -26,6 +26,8 @@ from pygsti.baseobjs.verbosityprinter import VerbosityPrinter as _VerbosityPrint
26
26
  from pygsti.tools import sharedmemtools as _smt
27
27
  from pygsti.tools import slicetools as _slct
28
28
  from pygsti.tools.matrixtools import _fas
29
+ from pygsti.tools import listtools as _lt
30
+ from pygsti.circuits import CircuitList as _CircuitList
29
31
 
30
32
  _dummy_profiler = _DummyProfiler()
31
33
 
@@ -49,7 +51,7 @@ class SimpleMapForwardSimulator(_ForwardSimulator):
49
51
  # If this is done, then MapForwardSimulator wouldn't need to separately subclass DistributableForwardSimulator
50
52
 
51
53
  def _compute_circuit_outcome_probabilities(self, array_to_fill, circuit, outcomes, resource_alloc, time=None):
52
- expanded_circuit_outcomes = circuit.expand_instruments_and_separate_povm(self.model, outcomes)
54
+ expanded_circuit_outcomes = self.model.expand_instruments_and_separate_povm(circuit, outcomes)
53
55
  outcome_to_index = {outc: i for i, outc in enumerate(outcomes)}
54
56
  for spc, spc_outcomes in expanded_circuit_outcomes.items(): # spc is a SeparatePOVMCircuit
55
57
  # Note: `spc.circuit_without_povm` *always* begins with a prep label.
@@ -157,7 +159,7 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
157
159
  if method_name == 'bulk_fill_timedep_dchi2': return ('p',) # just an additional parameter vector
158
160
  return super()._array_types_for_method(method_name)
159
161
 
160
- def __init__(self, model=None, max_cache_size=0, num_atoms=None, processor_grid=None, param_blk_sizes=None,
162
+ def __init__(self, model=None, max_cache_size=None, num_atoms=None, processor_grid=None, param_blk_sizes=None,
161
163
  derivative_eps=1e-7, hessian_eps=1e-5):
162
164
  #super().__init__(model, num_atoms, processor_grid, param_blk_sizes)
163
165
  _DistributableForwardSimulator.__init__(self, model, num_atoms, processor_grid, param_blk_sizes)
@@ -193,7 +195,9 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
193
195
  self._processor_grid, self._pblk_sizes)
194
196
 
195
197
  def create_layout(self, circuits, dataset=None, resource_alloc=None, array_types=('E',),
196
- derivative_dimensions=None, verbosity=0):
198
+ derivative_dimensions=None, verbosity=0, layout_creation_circuit_cache=None,
199
+ circuit_partition_cost_functions=('size', 'propagations'),
200
+ load_balancing_parameters=(1.15,.1)):
197
201
  """
198
202
  Constructs an circuit-outcome-probability-array (COPA) layout for a list of circuits.
199
203
 
@@ -223,6 +227,23 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
223
227
  verbosity : int or VerbosityPrinter
224
228
  Determines how much output to send to stdout. 0 means no output, higher
225
229
  integers mean more output.
230
+
231
+ layout_creation_circuit_cache : dict, optional (default None)
232
+ A precomputed dictionary serving as a cache for completed circuits. I.e. circuits
233
+ with prep labels and POVM labels appended. Along with other useful pre-computed
234
+ circuit structures used in layout creation.
235
+
236
+ circuit_partition_cost_functions : tuple of str, optional (default ('size', 'propagations'))
237
+ A tuple of strings denoting cost function to use in each of the two stages of the algorithm
238
+ for determining the partitions of the complete circuit set amongst atoms.
239
+ Allowed options are 'size', which corresponds to balancing the number of circuits,
240
+ and 'propagations', which corresponds to balancing the number of state propagations.
241
+
242
+ load_balancing_parameters : tuple of floats, optional (default (1.15, .1))
243
+ A tuple of floats used as load balancing parameters when splitting a layout across atoms,
244
+ as in the multi-processor setting when using MPI. These parameters correspond to the `imbalance_threshold`
245
+ and `minimum_improvement_threshold` parameters described in the method `find_splitting_new`
246
+ of the `PrefixTable` class.
226
247
 
227
248
  Returns
228
249
  -------
@@ -248,15 +269,15 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
248
269
  raise MemoryError("Attempted layout creation w/memory limit = %g <= 0!" % mem_limit)
249
270
  printer.log("Layout creation w/mem limit = %.2fGB" % (mem_limit * C))
250
271
 
251
- #Start with how we'd like to split processors up (without regard to memory limit):
252
-
253
- # when there are lots of processors, the from_vector calls dominante over the actual fwdsim,
254
- # but we can reduce from_vector calls by having np1, np2 > 0 (each param requires a from_vector
255
- # call when using finite diffs) - so we want to choose nc = Ng < nprocs and np1 > 1 (so nc * np1 = nprocs).
256
- #work_per_proc = self.model.dim**2
272
+ #Start with how we'd like to split processors up (without regard to memory limit):
273
+ #The current implementation of map (should) benefit more from having a matching between the number of atoms
274
+ #and the number of processors, at least for up to around two-qubits.
275
+ default_natoms = nprocs # heuristic
276
+ #TODO: factor in the mem_limit value to more intelligently set the default number of atoms.
257
277
 
258
278
  natoms, na, npp, param_dimensions, param_blk_sizes = self._compute_processor_distribution(
259
- array_types, nprocs, num_params, len(circuits), default_natoms=2 * self.model.dim) # heuristic?
279
+ array_types, nprocs, num_params, len(circuits), default_natoms=default_natoms)
280
+
260
281
  printer.log(f'Num Param Processors {npp}')
261
282
 
262
283
  printer.log("MapLayout: %d processors divided into %s (= %d) grid along circuit and parameter directions." %
@@ -265,7 +286,9 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
265
286
  assert(_np.prod((na,) + npp) <= nprocs), "Processor grid size exceeds available processors!"
266
287
 
267
288
  layout = _MapCOPALayout(circuits, self.model, dataset, self._max_cache_size, natoms, na, npp,
268
- param_dimensions, param_blk_sizes, resource_alloc, verbosity)
289
+ param_dimensions, param_blk_sizes, resource_alloc,circuit_partition_cost_functions,
290
+ verbosity, layout_creation_circuit_cache= layout_creation_circuit_cache,
291
+ load_balancing_parameters=load_balancing_parameters)
269
292
 
270
293
  if mem_limit is not None:
271
294
  loc_nparams1 = num_params / npp[0] if len(npp) > 0 else 0
@@ -291,13 +314,6 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
291
314
  layout._param_dimensions, (loc_nparams1, loc_nparams2),
292
315
  (blk1, blk2), max_atom_cachesize, self.model.dim)
293
316
 
294
- #def approx_mem_estimate(nc, np1, np2):
295
- # approx_cachesize = (num_circuits / nc) * 1.3 # inflate expected # of circuits per atom => cache_size
296
- # return _bytes_for_array_types(array_types, num_elements, num_elements / nc,
297
- # num_circuits, num_circuits / nc,
298
- # (num_params, num_params), (num_params / np1, num_params / np2),
299
- # approx_cachesize, self.model.dim)
300
-
301
317
  GB = 1.0 / 1024.0**3
302
318
  if mem_estimate > mem_limit:
303
319
  raise MemoryError("Not enough memory for desired layout! (limit=%.1fGB, required=%.1fGB)" % (
@@ -306,6 +322,41 @@ class MapForwardSimulator(_DistributableForwardSimulator, SimpleMapForwardSimula
306
322
  printer.log(" Esimated memory required = %.1fGB" % (mem_estimate * GB))
307
323
 
308
324
  return layout
325
+
326
+ @staticmethod
327
+ def create_copa_layout_circuit_cache(circuits, model, dataset=None):
328
+ """
329
+ Helper function for pre-computing/pre-processing circuits structures
330
+ used in matrix layout creation.
331
+ """
332
+ cache = dict()
333
+ completed_circuits = model.complete_circuits(circuits)
334
+
335
+ cache['completed_circuits'] = {ckt: comp_ckt for ckt, comp_ckt in zip(circuits, completed_circuits)}
336
+
337
+ split_circuits = model.split_circuits(completed_circuits, split_prep=False)
338
+ cache['split_circuits'] = {ckt: split_ckt for ckt, split_ckt in zip(circuits, split_circuits)}
339
+
340
+
341
+ if dataset is not None:
342
+ aliases = circuits.op_label_aliases if isinstance(circuits, _CircuitList) else None
343
+ ds_circuits = _lt.apply_aliases_to_circuits(circuits, aliases)
344
+ unique_outcomes_list = []
345
+ for ckt in ds_circuits:
346
+ ds_row = dataset[ckt]
347
+ unique_outcomes_list.append(ds_row.unique_outcomes if ds_row is not None else None)
348
+ else:
349
+ unique_outcomes_list = [None]*len(circuits)
350
+
351
+ expanded_circuit_outcome_list = model.bulk_expand_instruments_and_separate_povm(circuits,
352
+ observed_outcomes_list = unique_outcomes_list,
353
+ completed_circuits= completed_circuits)
354
+
355
+ expanded_circuit_cache = {ckt: expanded_ckt for ckt,expanded_ckt in zip(completed_circuits, expanded_circuit_outcome_list)}
356
+ cache['expanded_and_separated_circuits'] = expanded_circuit_cache
357
+
358
+ return cache
359
+
309
360
 
310
361
  def _bulk_fill_probs_atom(self, array_to_fill, layout_atom, resource_alloc):
311
362
  # Note: *don't* set dest_indices arg = layout.element_slice, as this is already done by caller
@@ -1,6 +1,4 @@
1
1
  # encoding: utf-8
2
- # cython: profile=False
3
- # cython: linetrace=False
4
2
 
5
3
  #***************************************************************************************************
6
4
  # Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
@@ -28,12 +26,6 @@ from ..tools import slicetools as _slct
28
26
  #from ..tools import optools as _ot
29
27
  from ..tools.matrixtools import _fas
30
28
 
31
- #DEBUG REMOVE MEMORY PROFILING
32
- #import os, psutil
33
- #process = psutil.Process(os.getpid())
34
- #def print_mem_usage(prefix):
35
- # print("%s: mem usage = %.3f GB" % (prefix, process.memory_info().rss / (1024.0**3)))
36
-
37
29
  #Use 64-bit integers
38
30
  ctypedef long long INT
39
31
  ctypedef unsigned long long UINT
@@ -59,15 +51,16 @@ def propagate_staterep(staterep, operationreps):
59
51
  # Python -> C Conversion functions
60
52
  # -----------------------------------------
61
53
 
62
- cdef vector[vector[INT]] convert_maplayout(layout_atom, operation_lookup, rho_lookup):
54
+ @cython.wraparound(False)
55
+ cdef vector[vector[INT]] convert_maplayout(prefix_table_contents, operation_lookup, rho_lookup):
63
56
  # c_layout :
64
57
  # an array of INT-arrays; each INT-array is [iDest,iStart,iCache,<remainder gate indices>]
65
58
  cdef vector[INT] intarray
66
- cdef vector[vector[INT]] c_layout_atom = vector[vector[INT]](len(layout_atom.table))
67
- for kk, (iDest, iStart, remainder, iCache) in enumerate(layout_atom.table.contents):
59
+ cdef vector[vector[INT]] c_layout_atom = vector[vector[INT]](len(prefix_table_contents))
60
+ for kk, (iDest, iStart, remainder, iCache) in enumerate(prefix_table_contents):
68
61
  if iStart is None: iStart = -1 # so always an int
69
62
  if iCache is None: iCache = -1 # so always an int
70
- remainder = remainder.circuit_without_povm.layertup
63
+ remainder = remainder
71
64
  intarray = vector[INT](3 + len(remainder))
72
65
  intarray[0] = iDest
73
66
  intarray[1] = iStart
@@ -107,6 +100,8 @@ cdef vector[vector[INT]] convert_and_wrap_dict_of_intlists(d, wrapper):
107
100
  ret[i][j] = wrapper[intlist[j]]
108
101
  return ret
109
102
 
103
+ @cython.boundscheck(False)
104
+ @cython.wraparound(False)
110
105
  cdef vector[StateCRep*] create_rhocache(INT cacheSize, INT state_dim):
111
106
  cdef INT i
112
107
  cdef vector[StateCRep*] rho_cache = vector[StateCRep_ptr](cacheSize)
@@ -114,11 +109,14 @@ cdef vector[StateCRep*] create_rhocache(INT cacheSize, INT state_dim):
114
109
  rho_cache[i] = new StateCRep(state_dim)
115
110
  return rho_cache
116
111
 
112
+ @cython.boundscheck(False)
113
+ @cython.wraparound(False)
117
114
  cdef void free_rhocache(vector[StateCRep*] rho_cache):
118
115
  cdef UINT i
119
116
  for i in range(rho_cache.size()): # fill cache with empty but alloc'd states
120
117
  del rho_cache[i]
121
118
 
119
+ @cython.wraparound(False)
122
120
  cdef vector[OpCRep*] convert_opreps(operationreps):
123
121
  # c_opreps : an array of OpCReps
124
122
  cdef vector[OpCRep*] c_opreps = vector[OpCRep_ptr](len(operationreps))
@@ -130,19 +128,20 @@ cdef StateCRep* convert_rhorep(rhorep):
130
128
  # extract c-reps from rhorep and ereps => c_rho and c_ereps
131
129
  return (<StateRep?>rhorep).c_state
132
130
 
131
+ @cython.wraparound(False)
133
132
  cdef vector[StateCRep*] convert_rhoreps(rhoreps):
134
133
  cdef vector[StateCRep*] c_rhoreps = vector[StateCRep_ptr](len(rhoreps))
135
134
  for ii,rrep in rhoreps.items(): # (ii = python variable)
136
135
  c_rhoreps[ii] = (<StateRep?>rrep).c_state
137
136
  return c_rhoreps
138
137
 
138
+ @cython.wraparound(False)
139
139
  cdef vector[EffectCRep*] convert_ereps(ereps):
140
140
  cdef vector[EffectCRep*] c_ereps = vector[EffectCRep_ptr](len(ereps))
141
141
  for i in range(len(ereps)):
142
142
  c_ereps[i] = (<EffectRep>ereps[i]).c_effect
143
143
  return c_ereps
144
144
 
145
-
146
145
  # -----------------------------------------
147
146
  # Mapfill functions
148
147
  # -----------------------------------------
@@ -159,7 +158,6 @@ def mapfill_probs_atom(fwdsim, np.ndarray[double, mode="c", ndim=1] array_to_fil
159
158
  shared_mem_leader = resource_alloc.is_host_leader if (resource_alloc is not None) else True
160
159
 
161
160
  dest_indices = _slct.to_array(dest_indices) # make sure this is an array and not a slice
162
- #dest_indices = np.ascontiguousarray(dest_indices) #unneeded
163
161
 
164
162
  #Get (extension-type) representation objects
165
163
  rho_lookup = { lbl:i for i,lbl in enumerate(layout_atom.rho_labels) } # rho labels -> ints for faster lookup
@@ -169,7 +167,7 @@ def mapfill_probs_atom(fwdsim, np.ndarray[double, mode="c", ndim=1] array_to_fil
169
167
  ereps = [fwdsim.model._circuit_layer_operator(elbl, 'povm')._rep for elbl in layout_atom.full_effect_labels] # cache these in future
170
168
 
171
169
  # convert to C-mode: evaltree, operation_lookup, operationreps
172
- cdef vector[vector[INT]] c_layout_atom = convert_maplayout(layout_atom, operation_lookup, rho_lookup)
170
+ cdef vector[vector[INT]] c_layout_atom = convert_maplayout(layout_atom.table.contents, operation_lookup, rho_lookup)
173
171
  cdef vector[StateCRep*] c_rhos = convert_rhoreps(rhoreps)
174
172
  cdef vector[EffectCRep*] c_ereps = convert_ereps(ereps)
175
173
  cdef vector[OpCRep*] c_opreps = convert_opreps(operationreps)
@@ -182,17 +180,6 @@ def mapfill_probs_atom(fwdsim, np.ndarray[double, mode="c", ndim=1] array_to_fil
182
180
  cdef vector[vector[INT]] final_indices_per_circuit = convert_and_wrap_dict_of_intlists(
183
181
  layout_atom.elindices_by_expcircuit, dest_indices)
184
182
 
185
- #DEBUG REMOVE
186
- #print_mem_usage("MAPFILL PROBS begin")
187
- #for i in [1808, 419509, 691738, 497424]:
188
- # from ..evotypes.densitymx.opreps import OpRepComposed
189
- # op = operationreps[i]
190
- # if isinstance(op.embedded_rep, OpRepComposed):
191
- # extra = " factors = " + ', '.join([str(type(opp)) for opp in op.embedded_rep.factor_reps])
192
- # else:
193
- # extra = ""
194
- # print("ID ",i,str(type(op)),str(type(op.embedded_rep)), extra)
195
-
196
183
  if shared_mem_leader:
197
184
  #Note: dm_mapfill_probs could have taken a resource_alloc to employ multiple cpus to do computation.
198
185
  # Since array_fo_fill is assumed to be shared mem it would need to only update `array_to_fill` *if*
@@ -203,6 +190,7 @@ def mapfill_probs_atom(fwdsim, np.ndarray[double, mode="c", ndim=1] array_to_fil
203
190
  free_rhocache(rho_cache) #delete cache entries
204
191
 
205
192
 
193
+ @cython.wraparound(False)
206
194
  cdef dm_mapfill_probs(double[:] array_to_fill,
207
195
  vector[vector[INT]] c_layout_atom,
208
196
  vector[OpCRep*] c_opreps,
@@ -234,7 +222,7 @@ cdef dm_mapfill_probs(double[:] array_to_fill,
234
222
  # - all rho_cache entries have been allocated via "new"
235
223
  #REMOVE print("MAPFILL PROBS begin cfn")
236
224
  for k in range(<INT>c_layout_atom.size()):
237
- t0 = pytime.time() # DEBUG
225
+ #t0 = pytime.time() # DEBUG
238
226
  intarray = c_layout_atom[k]
239
227
  i = intarray[0]
240
228
  istart = intarray[1]
@@ -298,22 +286,27 @@ cdef dm_mapfill_probs(double[:] array_to_fill,
298
286
  del prop2
299
287
  del shelved
300
288
 
301
-
289
+ @cython.wraparound(False)
302
290
  def mapfill_dprobs_atom(fwdsim,
303
291
  np.ndarray[double, ndim=2] array_to_fill,
304
292
  dest_indices,
305
293
  dest_param_indices,
306
294
  layout_atom, param_indices, resource_alloc, double eps):
307
295
 
308
- #cdef double eps = 1e-7
296
+ cdef int num_params = fwdsim.model.num_params
297
+ cdef int model_dim = fwdsim.model.dim
309
298
 
310
299
  if param_indices is None:
311
- param_indices = list(range(fwdsim.model.num_params))
300
+ param_indices = list(range(num_params))
312
301
  if dest_param_indices is None:
313
302
  dest_param_indices = list(range(_slct.length(param_indices)))
314
303
 
315
- param_indices = _slct.to_array(param_indices)
316
- dest_param_indices = _slct.to_array(dest_param_indices)
304
+ cdef np.ndarray[np.int64_t, ndim=1, mode='c'] param_indices_array = _slct.to_array(param_indices)
305
+ cdef np.ndarray[np.int64_t, ndim=1, mode='c'] dest_param_indices_array = _slct.to_array(dest_param_indices)
306
+
307
+ cdef np.int64_t[::1] param_indices_view = param_indices_array
308
+ cdef np.int64_t[::1] dest_param_indices_view = dest_param_indices_array
309
+
317
310
 
318
311
  #Get (extension-type) representation objects
319
312
  # NOTE: the circuit_layer_operator(lbl) functions cache the returned operation
@@ -327,7 +320,7 @@ def mapfill_dprobs_atom(fwdsim,
327
320
  ereps = [fwdsim.model._circuit_layer_operator(elbl, 'povm')._rep for elbl in layout_atom.full_effect_labels] # cache these in future
328
321
 
329
322
  # convert to C-mode: evaltree, operation_lookup, operationreps
330
- cdef vector[vector[INT]] c_layout_atom = convert_maplayout(layout_atom, operation_lookup, rho_lookup)
323
+ cdef vector[vector[INT]] c_layout_atom = convert_maplayout(layout_atom.table.contents, operation_lookup, rho_lookup)
331
324
  cdef vector[StateCRep*] c_rhos = convert_rhoreps(rhoreps)
332
325
  cdef vector[EffectCRep*] c_ereps = convert_ereps(ereps)
333
326
  cdef vector[OpCRep*] c_opreps = convert_opreps(operationreps)
@@ -335,53 +328,60 @@ def mapfill_dprobs_atom(fwdsim,
335
328
  # create rho_cache = vector of StateCReps
336
329
  #print "DB: creating rho_cache of size %d * %g GB => %g GB" % \
337
330
  # (layout_atom.cache_size, 8.0 * fwdsim.model.dim / 1024.0**3, layout_atom.cache_size * 8.0 * fwdsim.model.dim / 1024.0**3)
338
- cdef vector[StateCRep*] rho_cache = create_rhocache(layout_atom.cache_size, fwdsim.model.dim)
331
+ cdef vector[StateCRep*] rho_cache = create_rhocache(layout_atom.cache_size, model_dim)
339
332
 
340
333
  cdef vector[vector[INT]] elabel_indices_per_circuit = convert_dict_of_intlists(layout_atom.elbl_indices_by_expcircuit)
341
334
  cdef vector[vector[INT]] final_indices_per_circuit = convert_dict_of_intlists(layout_atom.elindices_by_expcircuit)
342
335
 
343
- orig_vec = fwdsim.model.to_vector().copy()
336
+ cdef np.ndarray[np.float64_t, ndim=1, mode='c'] orig_vec = fwdsim.model.to_vector().copy()
337
+ cdef double[::1] orig_vec_view = orig_vec
344
338
  fwdsim.model.from_vector(orig_vec, close=False) # ensure we call with close=False first
345
339
 
346
340
  nEls = layout_atom.num_elements
347
- probs = np.empty(nEls, 'd') #must be contiguous!
348
- probs2 = np.empty(nEls, 'd') #must be contiguous!
341
+ cdef np.ndarray[np.float64_t, ndim=1, mode='c'] probs = np.empty(nEls, dtype=np.float64) #must be contiguous!
342
+ cdef np.ndarray[np.float64_t, ndim=1, mode='c'] probs2 = np.empty(nEls, dtype=np.float64) #must be contiguous!
343
+
344
+ cdef double[::1] probs_view = probs
345
+ cdef double[::1] probs2_view = probs2
349
346
 
350
347
  #if resource_alloc.comm_rank == 0:
351
348
  # print("MAPFILL DPROBS ATOM 1"); t=pytime.time(); t0=pytime.time()
352
- dm_mapfill_probs(probs, c_layout_atom, c_opreps, c_rhos, c_ereps, &rho_cache,
353
- elabel_indices_per_circuit, final_indices_per_circuit, fwdsim.model.dim)
349
+ dm_mapfill_probs(probs_view, c_layout_atom, c_opreps, c_rhos, c_ereps, &rho_cache, elabel_indices_per_circuit, final_indices_per_circuit, model_dim)
354
350
  #if resource_alloc.comm_rank == 0:
355
351
  # print("MAPFILL DPROBS ATOM 2 %.3fs" % (pytime.time() - t)); t=pytime.time()
356
352
 
357
- shared_mem_leader = resource_alloc.is_host_leader
358
-
359
- #Get a map from global parameter indices to the desired
360
- # final index within array_to_fill
361
- iParamToFinal = {i: dest_index for i, dest_index in zip(param_indices, dest_param_indices)}
353
+ cdef bint shared_mem_leader = resource_alloc.is_host_leader
354
+
355
+ #add typing to indices we'll be using below:
356
+ cdef int i
357
+ cdef int first_param_idx
358
+ cdef int iFinal
359
+
360
+ #Split off the first finite difference step, as the pattern I want in the loop with each step
361
+ #is to simultaneously undo the previous update and apply the new one.
362
+ if len(param_indices_view)>0:
363
+ #probs2_view[:] = probs_view[:]
364
+ first_param_idx = param_indices_view[0]
365
+ iFinal = dest_param_indices_view[0]
366
+ fwdsim.model.set_parameter_value(first_param_idx, orig_vec_view[first_param_idx]+eps)
367
+ if shared_mem_leader: # don't fill assumed-shared array-to_fill on non-mem-leaders
368
+ dm_mapfill_probs(probs2_view, c_layout_atom, c_opreps, c_rhos, c_ereps, &rho_cache, elabel_indices_per_circuit, final_indices_per_circuit, model_dim)
369
+ array_to_fill[dest_indices, iFinal] = (probs2 - probs) / eps
370
+
371
+ for i in range(1, len(param_indices_view)):
372
+ #probs2_view[:] = probs_view[:]
373
+ iFinal = dest_param_indices_view[i]
374
+ fwdsim.model.set_parameter_values([param_indices_view[i-1], param_indices_view[i]], [orig_vec_view[param_indices_view[i-1]], orig_vec_view[param_indices_view[i]]+eps])
375
+
376
+ if shared_mem_leader: # don't fill assumed-shared array-to_fill on non-mem-leaders
377
+ dm_mapfill_probs(probs2_view, c_layout_atom, c_opreps, c_rhos, c_ereps, &rho_cache, elabel_indices_per_circuit, final_indices_per_circuit, model_dim)
378
+ array_to_fill[dest_indices, iFinal] = (probs2 - probs) / eps
379
+
380
+ #reset the final model parameter we changed to it's original value.
381
+ fwdsim.model.set_parameter_value(param_indices_view[len(param_indices_view)-1], orig_vec_view[param_indices_view[len(param_indices_view)-1]])
362
382
 
363
- for i in range(fwdsim.model.num_params):
364
- #print("dprobs cache %d of %d" % (i,self.Np))
365
- if i in iParamToFinal:
366
- #if resource_alloc.comm_rank == 0:
367
- # print("MAPFILL DPROBS ATOM 3 (i=%d) %.3fs elapssed=%.1fs" % (i, pytime.time() - t, pytime.time() - t0)); t=pytime.time()
368
- iFinal = iParamToFinal[i]
369
- vec = orig_vec.copy(); vec[i] += eps
370
- fwdsim.model.from_vector(vec, close=True)
371
- #Note: dm_mapfill_probs could have taken a resource_alloc to employ multiple cpus to do computation.
372
- # If probs2 were shared mem (seems not benefit to this?) it would need to only update `probs2` *if*
373
- # it were the host leader.
374
- if shared_mem_leader: # don't fill assumed-shared array-to_fill on non-mem-leaders
375
- dm_mapfill_probs(probs2, c_layout_atom, c_opreps, c_rhos, c_ereps, &rho_cache,
376
- elabel_indices_per_circuit, final_indices_per_circuit, fwdsim.model.dim)
377
- #_fas(array_to_fill, [dest_indices, iFinal], (probs2 - probs) / eps) # I don't think this is needed
378
- array_to_fill[dest_indices, iFinal] = (probs2 - probs) / eps
379
-
380
- #if resource_alloc.comm_rank == 0:
381
- # print("MAPFILL DPROBS ATOM 4 elapsed=%.1fs" % (pytime.time() - t0))
382
- fwdsim.model.from_vector(orig_vec, close=True)
383
383
  free_rhocache(rho_cache) #delete cache entries
384
-
384
+
385
385
 
386
386
  cdef double TDchi2_obj_fn(double p, double f, double n_i, double n, double omitted_p, double min_prob_clip_for_weighting, double extra):
387
387
  cdef double cp, v, omitted_cp
@@ -475,7 +475,6 @@ def mapfill_TDterms(fwdsim, objective, array_to_fill, dest_indices, num_outcomes
475
475
  #comm is currently ignored
476
476
  #TODO: if layout_atom is split, distribute among processors
477
477
  for iDest, iStart, remainder, iCache in layout_atom.table.contents:
478
- remainder = remainder.circuit_without_povm.layertup
479
478
  rholabel = remainder[0]; remainder = remainder[1:]
480
479
  rhoVec = fwdsim.model._circuit_layer_operator(rholabel, 'prep')
481
480