pyGSTi 0.9.12__cp310-cp310-win_amd64.whl → 0.9.13__cp310-cp310-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.cp310-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.cp310-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.cp310-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.cp310-win_amd64.pyd +0 -0
  41. pygsti/evotypes/densitymx/effectreps.pyx +1 -1
  42. pygsti/evotypes/densitymx/opreps.cp310-win_amd64.pyd +0 -0
  43. pygsti/evotypes/densitymx/opreps.pyx +2 -2
  44. pygsti/evotypes/densitymx/statereps.cp310-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.cp310-win_amd64.pyd +0 -0
  51. pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
  52. pygsti/evotypes/stabilizer/opreps.cp310-win_amd64.pyd +0 -0
  53. pygsti/evotypes/stabilizer/opreps.pyx +0 -4
  54. pygsti/evotypes/stabilizer/statereps.cp310-win_amd64.pyd +0 -0
  55. pygsti/evotypes/stabilizer/statereps.pyx +1 -5
  56. pygsti/evotypes/stabilizer/termreps.cp310-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.cp310-win_amd64.pyd +0 -0
  62. pygsti/evotypes/statevec/effectreps.pyx +1 -1
  63. pygsti/evotypes/statevec/opreps.cp310-win_amd64.pyd +0 -0
  64. pygsti/evotypes/statevec/opreps.pyx +2 -2
  65. pygsti/evotypes/statevec/statereps.cp310-win_amd64.pyd +0 -0
  66. pygsti/evotypes/statevec/statereps.pyx +1 -1
  67. pygsti/evotypes/statevec/termreps.cp310-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.cp310-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.cp310-win_amd64.pyd +0 -0
  87. pygsti/forwardsims/termforwardsim_calc_statevec.cp310-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.cp310-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/baseobjs/basis.py CHANGED
@@ -14,6 +14,7 @@ import copy as _copy
14
14
  import itertools as _itertools
15
15
  import warnings as _warnings
16
16
  from functools import lru_cache
17
+ from typing import Union, Tuple, List
17
18
 
18
19
  import numpy as _np
19
20
  import scipy.sparse as _sps
@@ -154,126 +155,103 @@ class Basis(_NicelySerializable):
154
155
  The "vectors" of this basis, always 1D (sparse or dense) arrays.
155
156
  """
156
157
 
158
+ # Implementation note: casting functions are classmethods, but current implementations
159
+ # could be static methods.
160
+
157
161
  @classmethod
158
- def cast(cls, name_or_basis_or_matrices, dim=None, sparse=None, classical_name='cl'):
159
- """
160
- Convert various things that can describe a basis into a `Basis` object.
162
+ def cast_from_name_and_statespace(cls, name: str, state_space: _StateSpace, sparse=None):
163
+ tpbBases = []
164
+ block_labels = state_space.tensor_product_blocks_labels
165
+ if len(block_labels) == 1 and len(block_labels[0]) == 1:
166
+ # Special case when we can actually pipe state_space to the BuiltinBasis constructor
167
+ lbl = block_labels[0][0]
168
+ nm = name if (state_space.label_type(lbl) == 'Q') else 'cl'
169
+ tpbBases.append(BuiltinBasis(nm, state_space, sparse))
170
+ else:
171
+ #TODO: add methods to StateSpace that can extract a sub-*StateSpace* object for a given label.
172
+ for tpbLabels in block_labels:
173
+ if len(tpbLabels) == 1:
174
+ nm = name if (state_space.label_type(tpbLabels[0]) == 'Q') else 'cl'
175
+ tpbBases.append(BuiltinBasis(nm, state_space.label_dimension(tpbLabels[0]), sparse))
176
+ else:
177
+ tpbBases.append(TensorProdBasis([
178
+ BuiltinBasis(name if (state_space.label_type(l) == 'Q') else 'cl',
179
+ state_space.label_dimension(l), sparse) for l in tpbLabels]))
180
+ if len(tpbBases) == 1:
181
+ return tpbBases[0]
182
+ else:
183
+ return DirectSumBasis(tpbBases)
161
184
 
162
- Parameters
163
- ----------
164
- name_or_basis_or_matrices : various
165
- Can take on a variety of values to produce different types of bases:
166
-
167
- - `None`: an empty `ExpicitBasis`
168
- - `Basis`: checked with `dim` and `sparse` and passed through.
169
- - `str`: `BuiltinBasis` or `DirectSumBasis` with the given name.
170
- - `list`: an `ExplicitBasis` if given matrices/vectors or a
171
- `DirectSumBasis` if given a `(name, dim)` pairs.
172
-
173
- dim : int or StateSpace, optional
174
- The dimension of the basis to create. Sometimes this can be
175
- inferred based on `name_or_basis_or_matrices`, other times it must
176
- be supplied. This is the dimension of the space that this basis
177
- fully or partially spans. This is equal to the number of basis
178
- elements in a "full" (ordinary) basis. When a `StateSpace`
179
- object is given, a more detailed direct-sum-of-tensor-product-blocks
180
- structure for the state space (rather than a single dimension) is
181
- described, and a basis is produced for this space. For instance,
182
- a `DirectSumBasis` basis of `TensorProdBasis` components can result
183
- when there are multiple tensor-product blocks and these blocks
184
- consist of multiple factors.
185
+ @classmethod
186
+ def cast_from_name_and_dims(cls, name: str, dim: Union[int,list,tuple], sparse=None):
187
+ if isinstance(dim, (list, tuple)): # list/tuple of block dimensions
188
+ tpbBases = []
189
+ for tpbDim in dim:
190
+ if isinstance(tpbDim, (list, tuple)): # list/tuple of tensor-product dimensions
191
+ tpbBases.append(
192
+ TensorProdBasis([BuiltinBasis(name, factorDim, sparse) for factorDim in tpbDim]))
193
+ else:
194
+ tpbBases.append(BuiltinBasis(name, tpbDim, sparse))
185
195
 
186
- sparse : bool, optional
187
- Whether the resulting basis should be "sparse", meaning that its
188
- elements will be sparse rather than dense matrices.
196
+ if len(tpbBases) == 1:
197
+ return tpbBases[0]
198
+ else:
199
+ return DirectSumBasis(tpbBases)
200
+ else:
201
+ return BuiltinBasis(name, dim, sparse)
202
+
203
+ @classmethod
204
+ def cast_from_basis(cls, basis, dim=None, sparse=None):
205
+ #then just check to make sure consistent with `dim` & `sparse`
206
+ if dim is not None:
207
+ if isinstance(dim, _StateSpace):
208
+ state_space = dim
209
+ if hasattr(basis, 'state_space'): # TODO - should *all* basis objects have a state_space?
210
+ assert(state_space.is_compatible_with(basis.state_space)), \
211
+ "Basis object has incompatible state space: %s != %s" % (str(state_space),
212
+ str(basis.state_space))
213
+ else: # assume dim is an integer
214
+ assert(dim == basis.dim or dim == basis.elsize), \
215
+ "Basis object has unexpected dimension: %d != %d or %d" % (dim, basis.dim, basis.elsize)
216
+ if sparse is not None:
217
+ basis = basis.with_sparsity(sparse)
218
+ return basis
189
219
 
190
- classical_name : str, optional
191
- An alternate builtin basis name that should be used when
192
- constructing the bases for the classical sectors of `dim`,
193
- when `dim` is a `StateSpace` object.
220
+ @classmethod
221
+ def cast_from_arrays(cls, arrays, dim=None, sparse=None):
222
+ b = ExplicitBasis(arrays, sparse=sparse)
223
+ if dim is not None:
224
+ assert(dim == b.dim), "Created explicit basis has unexpected dimension: %d vs %d" % (dim, b.dim)
225
+ if sparse is not None:
226
+ assert(sparse == b.sparse), "Basis object has unexpected sparsity: %s" % (b.sparse)
227
+ return b
194
228
 
195
- Returns
196
- -------
197
- Basis
198
- """
199
- #print("DB: CAST = ",name_or_basis_or_matrices,dim)
200
- from pygsti.baseobjs.statespace import StateSpace as _StateSpace
201
- if name_or_basis_or_matrices is None: # special case of empty basis
202
- return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) # empty basis
203
- elif isinstance(name_or_basis_or_matrices, Basis):
204
- #then just check to make sure consistent with `dim` & `sparse`
205
- basis = name_or_basis_or_matrices
206
- if dim is not None:
207
- if isinstance(dim, _StateSpace):
208
- state_space = dim
209
- if hasattr(basis, 'state_space'): # TODO - should *all* basis objects have a state_space?
210
- assert(state_space.is_compatible_with(basis.state_space)), \
211
- "Basis object has incompatible state space: %s != %s" % (str(state_space),
212
- str(basis.state_space))
213
- else: # assume dim is an integer
214
- assert(dim == basis.dim or dim == basis.elsize), \
215
- "Basis object has unexpected dimension: %d != %d or %d" % (dim, basis.dim, basis.elsize)
216
- if sparse is not None:
217
- basis = basis.with_sparsity(sparse)
218
- return basis
219
- elif isinstance(name_or_basis_or_matrices, str):
220
- name = name_or_basis_or_matrices
229
+ @classmethod
230
+ def cast(cls, arg, dim=None, sparse=None):
231
+ #print("DB: CAST = ",arg,dim)
232
+ if isinstance(arg, Basis):
233
+ return cls.cast_from_basis(arg, dim, sparse)
234
+ if isinstance(arg, str):
221
235
  if isinstance(dim, _StateSpace):
222
- state_space = dim
223
- tpbBases = []
224
- if len(state_space.tensor_product_blocks_labels) == 1 \
225
- and len(state_space.tensor_product_blocks_labels[0]) == 1:
226
- #Special case when we can actually pipe state_space to the BuiltinBasis constructor
227
- lbl = state_space.tensor_product_blocks_labels[0][0]
228
- nm = name if (state_space.label_type(lbl) == 'Q') else classical_name
229
- tpbBases.append(BuiltinBasis(nm, state_space, sparse))
230
- else:
231
- #TODO: add methods to StateSpace that can extract a sub-*StateSpace* object for a given label.
232
- for tpbLabels in state_space.tensor_product_blocks_labels:
233
- if len(tpbLabels) == 1:
234
- nm = name if (state_space.label_type(tpbLabels[0]) == 'Q') else classical_name
235
- tpbBases.append(BuiltinBasis(nm, state_space.label_dimension(tpbLabels[0]), sparse))
236
- else:
237
- tpbBases.append(TensorProdBasis([
238
- BuiltinBasis(name if (state_space.label_type(l) == 'Q') else classical_name,
239
- state_space.label_dimension(l), sparse) for l in tpbLabels]))
240
- if len(tpbBases) == 1:
241
- return tpbBases[0]
242
- else:
243
- return DirectSumBasis(tpbBases)
244
- elif isinstance(dim, (list, tuple)): # list/tuple of block dimensions
245
- tpbBases = []
246
- for tpbDim in dim:
247
- if isinstance(tpbDim, (list, tuple)): # list/tuple of tensor-product dimensions
248
- tpbBases.append(
249
- TensorProdBasis([BuiltinBasis(name, factorDim, sparse) for factorDim in tpbDim]))
250
- else:
251
- tpbBases.append(BuiltinBasis(name, tpbDim, sparse))
252
-
253
- if len(tpbBases) == 1:
254
- return tpbBases[0]
255
- else:
256
- return DirectSumBasis(tpbBases)
257
- else:
258
- return BuiltinBasis(name, dim, sparse)
259
- elif isinstance(name_or_basis_or_matrices, (list, tuple, _np.ndarray)):
260
- # assume a list/array of matrices or (name, dim) pairs
261
- if len(name_or_basis_or_matrices) == 0: # special case of empty basis
262
- return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) # empty basis
263
- elif isinstance(name_or_basis_or_matrices[0], _np.ndarray):
264
- b = ExplicitBasis(name_or_basis_or_matrices, sparse=sparse)
265
- if dim is not None:
266
- assert(dim == b.dim), "Created explicit basis has unexpected dimension: %d vs %d" % (dim, b.dim)
267
- if sparse is not None:
268
- assert(sparse == b.sparse), "Basis object has unexpected sparsity: %s" % (b.sparse)
269
- return b
270
- else: # assume els are (name, dim) pairs
271
- compBases = [BuiltinBasis(subname, subdim, sparse)
272
- for (subname, subdim) in name_or_basis_or_matrices]
273
- return DirectSumBasis(compBases)
236
+ return cls.cast_from_name_and_statespace(arg, dim, sparse)
237
+ return cls.cast_from_name_and_dims(arg, dim, sparse)
238
+ if (arg is None) or (hasattr(arg,'__len__') and len(arg) == 0):
239
+ return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse)
240
+ # ^ The original implementation would return this value under two conditions.
241
+ # Either arg was None, or isinstance(arg,(tuple,list,ndarray)) and len(arg) == 0.
242
+ # We're just slightly relaxing the type requirement by using this check instead.
243
+
244
+ # At this point, original behavior would check that arg is a tuple, list, or ndarray.
245
+ # Instead, we'll just require that arg[0] is well-defined. This is enough to discern
246
+ # between the two cases we can still support.
247
+ if isinstance(arg[0], _np.ndarray):
248
+ return cls.cast_from_arrays(arg, dim, sparse)
249
+ if len(arg[0]) == 2:
250
+ compBases = [BuiltinBasis(subname, subdim, sparse) for (subname, subdim) in arg]
251
+ return DirectSumBasis(compBases)
252
+
253
+ raise ValueError("Can't cast %s to be a basis!" % str(type(arg)))
274
254
 
275
- else:
276
- raise ValueError("Can't cast %s to be a basis!" % str(type(name_or_basis_or_matrices)))
277
255
 
278
256
  def __init__(self, name, longname, real, sparse):
279
257
  super().__init__()
@@ -387,6 +365,7 @@ class Basis(_NicelySerializable):
387
365
  if self.sparse:
388
366
  return [_sps.lil_matrix(el).reshape((self.elsize, 1)) for el in self.elements]
389
367
  else:
368
+ # Use flatten (rather than ravel) to ensure a copy is made.
390
369
  return [el.flatten() for el in self.elements]
391
370
 
392
371
  def copy(self):
@@ -547,8 +526,7 @@ class Basis(_NicelySerializable):
547
526
  """
548
527
  if self.elndim == 2:
549
528
  for i, mx in enumerate(self.elements):
550
- t = _np.trace(_np.dot(mx, mx))
551
- t = _np.real(t)
529
+ t = _np.linalg.norm(mx) # == sqrt(tr(mx mx))
552
530
  if not _np.isclose(t, 1.0): return False
553
531
  return True
554
532
  elif self.elndim == 1:
@@ -1469,7 +1447,7 @@ class DirectSumBasis(LazyBasis):
1469
1447
  if self.sparse:
1470
1448
  vel = _sps.lil_matrix(el.reshape(-1, 1)) # sparse vector == sparse n x 1 matrix
1471
1449
  else:
1472
- vel = el.flatten()
1450
+ vel = el.ravel()
1473
1451
  toSimpleStd[:, i] = vel
1474
1452
  return toSimpleStd
1475
1453
 
@@ -1782,283 +1760,3 @@ class TensorProdBasis(LazyBasis):
1782
1760
  if all([c.name == first_comp_name for c in self.component_bases]):
1783
1761
  builtin_basis_name = first_comp_name # if all components have the same name
1784
1762
  return BuiltinBasis(builtin_basis_name, self.elsize, sparse=self.sparse)
1785
-
1786
-
1787
- class EmbeddedBasis(LazyBasis):
1788
- """
1789
- A basis that embeds a basis for a smaller state space within a larger state space.
1790
-
1791
- The elements of an EmbeddedBasis are therefore just embedded versions
1792
- of the elements of the basis that is embedded.
1793
-
1794
- Parameters
1795
- ----------
1796
- basis_to_embed : Basis
1797
- The basis being embedded.
1798
-
1799
- state_space_labels : StateSpaceLabels
1800
- An object describing the struture of the entire state space.
1801
-
1802
- target_labels : list or tuple
1803
- The labels contained in `stateSpaceLabels` which demarcate the
1804
- portions of the state space acted on by `basis_to_embed`.
1805
-
1806
- name : str, optional
1807
- The name of this basis. If `None`, the names of `basis_to_embed`
1808
- is joined with ':' characters to the elements of `target_labels`.
1809
-
1810
- longname : str, optional
1811
- A longer description of this basis. If `None`, then a long name is
1812
- automatically generated.
1813
- """
1814
-
1815
- @classmethod
1816
- def embed_label(cls, lbl, target_labels):
1817
- """
1818
- Gets the EmbeddedBasis label for `lbl`.
1819
-
1820
- Convenience method that gives the EmbeddedBasis label for `lbl`
1821
- without needing to construct the `EmbeddedBasis`. E.g. `"XX:1,2"`.
1822
-
1823
- Parameters
1824
- ----------
1825
- lbl : str
1826
- Un-embedded basis element label, e.g. `"XX"`.
1827
-
1828
- target_labels : tuple
1829
- The target state space labels upon which this basis element
1830
- will be embedded, e.g. `(1,2)`
1831
-
1832
- Returns
1833
- -------
1834
- str
1835
- The embedded-basis-element label as an EmbeddedBasis would
1836
- assign it. E.g. `"XX:1,2"`.
1837
- """
1838
- return "%s:%s" % (lbl, ",".join(map(str, target_labels)))
1839
-
1840
- @classmethod
1841
- def unembed_label(cls, lbl, target_labels):
1842
- """
1843
- Convenience method that performs the reverse of :meth:`embed_label`
1844
-
1845
- Parameters
1846
- ----------
1847
- lbl : str
1848
- Embedded basis element label, e.g. `"XX:1,2"`.
1849
-
1850
- target_labels : tuple
1851
- The target state space labels upon which this basis element
1852
- will be embedded, e.g. `(1,2)`
1853
-
1854
- Returns
1855
- -------
1856
- str
1857
- The un-embedded label, e.g. `"XX"`.
1858
- """
1859
- suffix = ":" + ",".join(map(str, target_labels))
1860
- if lbl.endswith(suffix):
1861
- return lbl[:-len(suffix)]
1862
- else:
1863
- raise ValueError("Cannot unembed '%s' - doesn't end in '%s'!" % (lbl, suffix))
1864
-
1865
- def __init__(self, basis_to_embed, state_space, target_labels, name=None, longname=None):
1866
- '''
1867
- Create a new EmbeddedBasis.
1868
-
1869
- Parameters
1870
- ----------
1871
- basis_to_embed : Basis
1872
- The basis being embedded.
1873
-
1874
- state_space : StateSpace
1875
- An object describing the struture of the entire state space.
1876
-
1877
- target_labels : list or tuple
1878
- The labels contained in `stateSpaceLabels` which demarcate the
1879
- portions of the state space acted on by `basis_to_embed`.
1880
-
1881
- name : str, optional
1882
- The name of this basis. If `None`, the names of `basis_to_embed`
1883
- is joined with ':' characters to the elements of `target_labels`.
1884
-
1885
- longname : str, optional
1886
- A longer description of this basis. If `None`, then a long name is
1887
- automatically generated.
1888
- '''
1889
- from pygsti.baseobjs.statespace import StateSpace as _StateSpace
1890
- self.embedded_basis = basis_to_embed
1891
- self.target_labels = target_labels
1892
- self.state_space = _StateSpace.cast(state_space)
1893
-
1894
- if name is None:
1895
- name = ':'.join((basis_to_embed.name,) + tuple(map(str, target_labels)))
1896
- if longname is None:
1897
- longname = "Embedded %s basis as %s within %s" % \
1898
- (basis_to_embed.name, ':'.join(map(str, target_labels)), str(self.state_space))
1899
-
1900
- real = basis_to_embed.real
1901
- sparse = basis_to_embed.sparse
1902
-
1903
- super(EmbeddedBasis, self).__init__(name, longname, real, sparse)
1904
-
1905
- def _to_nice_serialization(self):
1906
- state = super()._to_nice_serialization()
1907
- state.update({'name': self.name,
1908
- 'longname': self.longname,
1909
- 'state_space': self.state_space.to_nice_serialization(),
1910
- 'embedded_basis': self.embedded_basis.to_nice_serialization()
1911
- })
1912
- return state
1913
-
1914
- @classmethod
1915
- def _from_nice_serialization(cls, state):
1916
- basis_to_embed = Basis.from_nice_serialization(state['embedded_basis'])
1917
- state_space = _StateSpace.from_nice_serialization(state['state_space'])
1918
- return cls(basis_to_embed, state_space, state['target_labels'], state['name'], state['longname'])
1919
-
1920
- @property
1921
- def dim(self):
1922
- """
1923
- The dimension of the vector space this basis fully or partially
1924
- spans. Equivalently, the length of the `vector_elements` of the
1925
- basis.
1926
- """
1927
- return self.state_space.dim
1928
-
1929
- @property
1930
- def size(self):
1931
- """
1932
- The number of elements (or vector-elements) in the basis.
1933
- """
1934
- return self.embedded_basis.size
1935
-
1936
- @property
1937
- def elshape(self):
1938
- """
1939
- The shape of each element. Typically either a length-1 or length-2
1940
- tuple, corresponding to vector or matrix elements, respectively.
1941
- Note that *vector elements* always have shape `(dim,)` (or `(dim,1)`
1942
- in the sparse case).
1943
- """
1944
- elndim = self.embedded_basis.elndim
1945
- if elndim == 2: # a "matrix" basis
1946
- d = int(_np.sqrt(self.dim))
1947
- assert(d**2 == self.dim), \
1948
- "Dimension of state_space must be a perfect square when embedding a matrix basis"
1949
- elshape = (d, d)
1950
- elif elndim == 1:
1951
- elshape = (self.dim,)
1952
- else:
1953
- raise ValueError("Can only embed bases with .elndim == 1 or 2 (received %d)!" % elndim)
1954
- return elshape
1955
-
1956
- def __hash__(self):
1957
- return hash(tuple(hash(self.embedded_basis), self.target_labels, self.state_space))
1958
-
1959
- def _lazy_build_elements(self):
1960
- """ Take a dense or sparse basis matrix and embed it. """
1961
- #LAZY building of elements (in case we never need them)
1962
- if self.elndim == 2: # then use EmbeddedOp to do matrix
1963
- from ..modelmembers.operations import StaticArbitraryOp
1964
- from ..modelmembers.operations import EmbeddedOp
1965
- sslbls = self.state_space.copy()
1966
- sslbls.reduce_dims_densitymx_to_state_inplace() # because we're working with basis matrices not gates
1967
-
1968
- if self.sparse:
1969
- self._elements = []
1970
- for spmx in self.embedded_basis.elements:
1971
- mxAsOp = StaticArbitraryOp(spmx.to_dense(), evotype='statevec')
1972
- self._elements.append(EmbeddedOp(sslbls, self.target_labels,
1973
- mxAsOp).to_sparse())
1974
- else:
1975
- self._elements = _np.zeros((self.size,) + self.elshape, 'complex')
1976
- for i, mx in enumerate(self.embedded_basis.elements):
1977
- self._elements[i] = EmbeddedOp(
1978
- sslbls, self.target_labels, StaticArbitraryOp(mx, evotype='statevec')
1979
- ).to_dense(on_space='HilbertSchmidt')
1980
- else:
1981
- # we need to perform embedding using vectors rather than matrices - doable, but
1982
- # not needed yet, so defer implementation to later.
1983
- raise NotImplementedError("Embedding *vector*-type bases not implemented yet")
1984
-
1985
- def _lazy_build_labels(self):
1986
- self._labels = [EmbeddedBasis.embed_label(lbl, self.target_labels)
1987
- for lbl in self.embedded_basis.labels]
1988
-
1989
- def _copy_with_toggled_sparsity(self):
1990
- return EmbeddedBasis(self.embedded_basis._copy_with_toggled_sparsity(),
1991
- self.state_space,
1992
- self.target_labels,
1993
- self.name, self.longname)
1994
-
1995
- def is_equivalent(self, other, sparseness_must_match=True):
1996
- """
1997
- Tests whether this basis is equal to another basis, optionally ignoring sparseness.
1998
-
1999
- Parameters
2000
- -----------
2001
- other : Basis or str
2002
- The basis to compare with.
2003
-
2004
- sparseness_must_match : bool, optional
2005
- If `False` then comparison ignores differing sparseness, and this function
2006
- returns `True` when the two bases are equal except for their `.sparse` values.
2007
-
2008
- Returns
2009
- -------
2010
- bool
2011
- """
2012
- otherIsBasis = isinstance(other, EmbeddedBasis)
2013
- if not otherIsBasis: return False # can't be equal to a non-EmbeddedBasis
2014
- if self.target_labels != other.target_labels or self.state_space != other.state_space:
2015
- return False
2016
- return self.embedded_basis.is_equivalent(other.embedded_basis, sparseness_must_match)
2017
-
2018
- def create_equivalent(self, builtin_basis_name):
2019
- """
2020
- Create an equivalent basis with components of type `builtin_basis_name`.
2021
-
2022
- Create a Basis that is equivalent in structure & dimension to this
2023
- basis but whose simple components (perhaps just this basis itself) is
2024
- of the builtin basis type given by `builtin_basis_name`.
2025
-
2026
- Parameters
2027
- ----------
2028
- builtin_basis_name : str
2029
- The name of a builtin basis, e.g. `"pp"`, `"gm"`, or `"std"`. Used to
2030
- construct the simple components of the returned basis.
2031
-
2032
- Returns
2033
- -------
2034
- EmbeddedBasis
2035
- """
2036
- equiv_embedded = self.embedded_basis.create_equivalent(builtin_basis_name)
2037
- return EmbeddedBasis(equiv_embedded, self.state_space, self.target_labels)
2038
-
2039
- def create_simple_equivalent(self, builtin_basis_name=None):
2040
- """
2041
- Create a basis of type `builtin_basis_name` whose elements are compatible with this basis.
2042
-
2043
- Create a simple basis *and* one without components (e.g. a
2044
- :class:`TensorProdBasis`, is a simple basis w/components) of the
2045
- builtin type specified whose dimension is compatible with the
2046
- *elements* of this basis. This function might also be named
2047
- "element_equivalent", as it returns the `builtin_basis_name`-analogue
2048
- of the standard basis that this basis's elements are expressed in.
2049
-
2050
- Parameters
2051
- ----------
2052
- builtin_basis_name : str, optional
2053
- The name of the built-in basis to use. If `None`, then a
2054
- copy of this basis is returned (if it's simple) or this
2055
- basis's name is used to try to construct a simple and
2056
- component-free version of the same builtin-basis type.
2057
-
2058
- Returns
2059
- -------
2060
- Basis
2061
- """
2062
- if builtin_basis_name is None:
2063
- builtin_basis_name = self.embedded_basis.name # default
2064
- return BuiltinBasis(builtin_basis_name, self.elsize, sparse=self.sparse)