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
@@ -27,6 +27,7 @@ from pygsti.tools import mpitools as _mpit
27
27
  from pygsti.baseobjs.statespace import ExplicitStateSpace as _ExplicitStateSpace
28
28
  from pygsti.baseobjs.statespace import QuditSpace as _QuditSpace
29
29
  from pygsti.models import ExplicitOpModel as _ExplicitOpModel
30
+ from pygsti.forwardsims import MatrixForwardSimulator as _MatrixForwardSimulator
30
31
 
31
32
  FLOATSIZE = 8 # in bytes: TODO: a better way
32
33
 
@@ -57,10 +58,8 @@ def find_germs(target_model, randomize=True, randomization_strength=1e-2,
57
58
 
58
59
  Parameters
59
60
  ----------
60
- target_model : Model or list of Model
61
- The model you are aiming to implement, or a list of models that are
62
- copies of the model you are trying to implement (either with or
63
- without random unitary perturbations applied to the models).
61
+ target_model : Model
62
+ The model you are aiming to implement.
64
63
 
65
64
  randomize : bool, optional
66
65
  Whether or not to add random unitary perturbations to the model(s)
@@ -188,8 +187,14 @@ def find_germs(target_model, randomize=True, randomization_strength=1e-2,
188
187
  A list containing the germs making up the germ set.
189
188
  """
190
189
  printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm)
190
+
191
+ if not isinstance(target_model.sim, _MatrixForwardSimulator):
192
+ target_model = target_model.copy()
193
+ target_model.sim = 'matrix'
194
+
191
195
  modelList = _setup_model_list(target_model, randomize,
192
196
  randomization_strength, num_gs_copies, seed)
197
+
193
198
  gates = list(target_model.operations.keys())
194
199
  availableGermsList = []
195
200
  if candidate_germ_counts is None: candidate_germ_counts = {6: 'all upto'}
@@ -1351,6 +1356,10 @@ def test_germ_set_finitel(model, germs_to_test, length, weights=None,
1351
1356
  eigenvalues (from small to large) of the jacobian^T * jacobian
1352
1357
  matrix used to determine parameter amplification.
1353
1358
  """
1359
+ if not isinstance(model.sim, _MatrixForwardSimulator):
1360
+ model = model.copy()
1361
+ model.sim = 'matrix'
1362
+
1354
1363
  # Remove any SPAM vectors from model since we only want
1355
1364
  # to consider the set of *gate* parameters for amplification
1356
1365
  # and this makes sure our parameter counting is correct
@@ -3295,80 +3304,81 @@ def symmetric_low_rank_spectrum_update(update, orig_e, U, proj_U, force_rank_inc
3295
3304
  #return the new eigenvalues
3296
3305
  return new_evals, True
3297
3306
 
3298
- #Note: This function won't work for our purposes because of the assumptions
3299
- #about the rank of the update on the nullspace of the matrix we're updating,
3300
- #but keeping this here commented for future reference.
3301
- #Function for doing fast calculation of the updated inverse trace:
3302
- #def riedel_style_inverse_trace(update, orig_e, U, proj_U, force_rank_increase=True):
3303
- # """
3304
- # input:
3305
- #
3306
- # update : ndarray
3307
- # symmetric low-rank update to perform.
3308
- # This is the first half the symmetric rank decomposition s.t.
3309
- # update@update.T= the full update matrix.
3310
- #
3311
- # orig_e : ndarray
3312
- # Spectrum of the original matrix. This is a 1-D array.
3313
- #
3314
- # proj_U : ndarray
3315
- # Projector onto the complement of the column space of the
3316
- # original matrix's eigenvectors.
3317
- #
3318
- # output:
3319
- #
3320
- # trace : float
3321
- # Value of the trace of the updated psuedoinverse matrix.
3322
- #
3323
- # updated_rank : int
3324
- # total rank of the updated matrix.
3325
- #
3326
- # rank_increase_flag : bool
3327
- # a flag that is returned to indicate is a candidate germ failed to amplify additional parameters.
3328
- # This indicates things short circuited and so the scoring function should skip this germ.
3329
- # """
3330
- #
3331
- # #First we need to for the matrix P, whose column space
3332
- # #forms an orthonormal basis for the component of update
3333
- # #that is in the complement of U.
3334
- #
3335
- # proj_update= proj_U@update
3336
- #
3337
- # #Next take the RRQR decomposition of this matrix:
3338
- # q_update, r_update, _ = _sla.qr(proj_update, mode='economic', pivoting=True)
3339
- #
3340
- # #Construct P by taking the columns of q_update corresponding to non-zero values of r_A on the diagonal.
3341
- # nonzero_indices_update= _np.nonzero(_np.diag(r_update)>1e-10) #HARDCODED (threshold is hardcoded)
3342
- #
3343
- # #if the rank doesn't increase then we can't use the Riedel approach.
3344
- # #Abort early and return a flag to indicate the rank did not increase.
3345
- # if len(nonzero_indices_update[0])==0 and force_rank_increase:
3346
- # return None, None, False
3347
- #
3348
- # P= q_update[: , nonzero_indices_update[0]]
3349
- #
3350
- # updated_rank= len(orig_e)+ len(nonzero_indices_update[0])
3351
- #
3352
- # #Now form the matrix R_update which is given by P.T @ proj_update.
3353
- # R_update= P.T@proj_update
3354
- #
3355
- # #R_update gets concatenated with U.T@update to form
3356
- # #a block column matrixblock_column= np.concatenate([U.T@update, R_update], axis=0)
3357
- #
3358
- # Uta= U.T@update
3359
- #
3360
- # try:
3361
- # RRRDinv= R_update@_np.linalg.inv(R_update.T@R_update)
3362
- # except _np.linalg.LinAlgError as err:
3363
- # print('Numpy thinks this matrix is singular, condition number is: ', _np.linalg.cond(R_update.T@R_update))
3364
- # print((R_update.T@R_update).shape)
3365
- # raise err
3366
- # pinv_orig_e_mat= _np.diag(1/orig_e)
3367
- #
3368
- # trace= _np.sum(1/orig_e) + _np.trace( RRRDinv@(_np.eye(Uta.shape[1]) + Uta.T@pinv_orig_e_mat@Uta)@RRRDinv.T )
3369
- #
3370
- # return trace, updated_rank, True
3307
+ # Note: Th function below won't work for our purposes because of the assumptions
3308
+ # about the rank of the update on the nullspace of the matrix we're updating,
3309
+ # but keeping this here commented for future reference.
3310
+ '''
3311
+ def riedel_style_inverse_trace(update, orig_e, U, proj_U, force_rank_increase=True):
3312
+ """
3313
+ input:
3314
+
3315
+ update : ndarray
3316
+ symmetric low-rank update to perform.
3317
+ This is the first half the symmetric rank decomposition s.t.
3318
+ update@update.T= the full update matrix.
3319
+
3320
+ orig_e : ndarray
3321
+ Spectrum of the original matrix. This is a 1-D array.
3322
+
3323
+ proj_U : ndarray
3324
+ Projector onto the complement of the column space of the
3325
+ original matrix's eigenvectors.
3326
+
3327
+ output:
3328
+
3329
+ trace : float
3330
+ Value of the trace of the updated psuedoinverse matrix.
3331
+
3332
+ updated_rank : int
3333
+ total rank of the updated matrix.
3334
+
3335
+ rank_increase_flag : bool
3336
+ a flag that is returned to indicate is a candidate germ failed to amplify additional parameters.
3337
+ This indicates things short circuited and so the scoring function should skip this germ.
3338
+ """
3371
3339
 
3340
+ #First we need to for the matrix P, whose column space
3341
+ #forms an orthonormal basis for the component of update
3342
+ #that is in the complement of U.
3343
+
3344
+ proj_update= proj_U@update
3345
+
3346
+ #Next take the RRQR decomposition of this matrix:
3347
+ q_update, r_update, _ = _sla.qr(proj_update, mode='economic', pivoting=True)
3348
+
3349
+ #Construct P by taking the columns of q_update corresponding to non-zero values of r_A on the diagonal.
3350
+ nonzero_indices_update= _np.nonzero(_np.diag(r_update)>1e-10) #HARDCODED (threshold is hardcoded)
3351
+
3352
+ #if the rank doesn't increase then we can't use the Riedel approach.
3353
+ #Abort early and return a flag to indicate the rank did not increase.
3354
+ if len(nonzero_indices_update[0])==0 and force_rank_increase:
3355
+ return None, None, False
3356
+
3357
+ P= q_update[: , nonzero_indices_update[0]]
3358
+
3359
+ updated_rank= len(orig_e)+ len(nonzero_indices_update[0])
3360
+
3361
+ #Now form the matrix R_update which is given by P.T @ proj_update.
3362
+ R_update= P.T@proj_update
3363
+
3364
+ #R_update gets concatenated with U.T@update to form
3365
+ #a block column matrixblock_column= np.concatenate([U.T@update, R_update], axis=0)
3366
+
3367
+ Uta= U.T@update
3368
+
3369
+ try:
3370
+ RRRDinv= R_update@_np.linalg.inv(R_update.T@R_update)
3371
+ except _np.linalg.LinAlgError as err:
3372
+ print('Numpy thinks this matrix is singular, condition number is: ', _np.linalg.cond(R_update.T@R_update))
3373
+ print((R_update.T@R_update).shape)
3374
+ raise err
3375
+ pinv_orig_e_mat= _np.diag(1/orig_e)
3376
+
3377
+ trace= _np.sum(1/orig_e) + _np.trace( RRRDinv@(_np.eye(Uta.shape[1]) + Uta.T@pinv_orig_e_mat@Uta)@RRRDinv.T )
3378
+
3379
+ return trace, updated_rank, True
3380
+ '''
3381
+
3372
3382
  def minamide_style_inverse_trace(update, orig_e, U, proj_U, force_rank_increase=False):
3373
3383
  """
3374
3384
  This function performs a low-rank update to the components of
@@ -21,92 +21,6 @@ from pygsti.tools import compilationtools as _comp
21
21
 
22
22
  from . import randomcircuit as _rc
23
23
 
24
- # ### TODO: THIS IS TIMS OLD CODE WHICH SHOULD PERHAPS ALSO BE AN OPTION IN THE `CREATE_MIRROR_CIRCUIT` FUNCTION
25
- # def create_mirror_circuit(circ, pspec, circtype='Clifford+Gzr', pauli_labels=None, pluspi_prob=0.):
26
- # """
27
- # *****************************************************************
28
- # Function currently has the following limitations that need fixing:
29
-
30
- # - A layer contains only Clifford or Gzr gates on ALL the qubits.
31
- # - all of the Clifford gates are self inverse
32
- # - The qubits are labelled "Q0" through "Qn-1" -- THIS SHOULD NOW BE FIXED!
33
- # - Pauli's are labelled by "Gi", "Gxpi", "Gypi" and "Gzpi".
34
- # - There's no option for randomized prep/meas
35
- # - There's no option for randomly adding +/-pi to the Z rotation angles.
36
- # - There's no option for adding "barriers"
37
- # - There's no test that the 'Gzr' gate has the "correct" convention for a rotation angle
38
- # (a rotation by pi must be a Z gate) or that it's a rotation around Z.
39
- # *****************************************************************
40
- # """
41
- # assert(circtype == 'Clifford+Gzr' or circtype == 'Clifford')
42
- # n = circ.width
43
- # d = circ.depth
44
- # if pauli_labels is None: pauli_labels = ['Gi', 'Gxpi', 'Gypi', 'Gzpi']
45
- # qubits = circ.line_labels
46
- # identity = _np.identity(2 * n, _np.int64)
47
- # zrotname = 'Gzr'
48
- # # qubit_labels = ['G{}'.format(i) for i in range(n)]
49
-
50
- # _, gate_inverse = pspec.compute_one_qubit_gate_relations()
51
- # gate_inverse.update(pspec.compute_multiqubit_inversion_relations()) # add multiQ inverses
52
-
53
- # quasi_inverse_circ = []
54
- # central_pauli_circ = _cir.Circuit([[_lbl.Label(pauli_labels[_np.random.randint(0, 4)], q) for q in qubits]])
55
- # #telescoping_pauli = central_pauli_layer.copy()
56
- # # The telescoping Pauli in the symplectic rep.
57
- # telp_s, telp_p = _symp.symplectic_rep_of_clifford_circuit(central_pauli_circ, pspec=pspec)
58
- # assert(_np.sum(_np.abs(telp_s - identity)) <= 1e-8) # Check that it's a Pauli.
59
-
60
- # for d_ind in range(d):
61
- # layer = circ.layer(d - d_ind - 1)
62
- # if layer[0].name == zrotname:
63
- # quasi_inverse_layer = []
64
- # for gate in layer:
65
-
66
- # q_int = qubits.index(gate.qubits[0])
67
- # angle = float(gate.args[0])
68
-
69
- # if telp_p[n + q_int] == 0: rotation_sign = -1. # If the Pauli is Z or I.
70
- # else: rotation_sign = +1 # If the Pauli is X or Y.
71
-
72
- # # Sets the quasi inversion angle to + or - the original angle, depending on the Paul
73
- # quasi_inverse_angle = rotation_sign * angle
74
- # # Decides whether to add with to add +/- pi to the rotation angle.
75
- # if _np.random.binomial(1, pluspi_prob) == 1:
76
- # quasi_inverse_angle += _np.pi * (-1)**_np.random.binomial(1, 0.5)
77
- # quasi_inverse_angle = _comp.mod_2pi(quasi_inverse_angle)
78
- # # Updates the telescoping Pauli (in the symplectic rep_, to include this added pi-rotation,
79
- # # as we need to include it as we keep collapsing the circuit down.
80
- # telp_p[q_int] = (telp_p[q_int] + 2) % 4
81
- # # Constructs the quasi-inverse gate.
82
- # quasi_inverse_gate = _lbl.Label(zrotname, gate.qubits, args=(str(quasi_inverse_angle),))
83
- # quasi_inverse_layer.append(quasi_inverse_gate)
84
-
85
- # # We don't have to update the telescoping Pauli as it's unchanged, but when we update
86
- # # this it'll need to change.
87
- # #telp_p = telp_p
88
-
89
- # else:
90
- # quasi_inverse_layer = [_lbl.Label(gate_inverse[gate.name], gate.qubits) for gate in layer]
91
- # telp_layer = _symp.find_pauli_layer(telp_p, pauli_labels, qubits)
92
- # conjugation_circ = _cir.Circuit([layer, telp_layer, quasi_inverse_layer])
93
- # # We calculate what the new telescoping Pauli is, in the symplectic rep.
94
- # telp_s, telp_p = _symp.symplectic_rep_of_clifford_circuit(conjugation_circ, pspec=pspec)
95
-
96
- # # Check that the layer -- pauli -- quasi-inverse circuit implements a Pauli.
97
- # assert(_np.sum(_np.abs(telp_s - identity)) <= 1e-10)
98
- # # Add the quasi inverse layer that we've constructed to the end of the quasi inverse circuit.
99
- # quasi_inverse_circ.append(quasi_inverse_layer)
100
-
101
- # # now that we've completed the quasi inverse circuit we convert it to a Circuit object
102
- # quasi_inverse_circ = _cir.Circuit(quasi_inverse_circ)
103
-
104
- # # Calculate the bit string that this mirror circuit should output, from the final telescoped Pauli.
105
- # target_bitstring = ''.join(['1' if p == 2 else '0' for p in telp_p[n:]])
106
- # mirror_circuit = circ + central_pauli_circ + quasi_inverse_circ
107
-
108
- # return mirror_circuit, target_bitstring
109
-
110
24
 
111
25
  def create_mirror_circuit(circ, pspec, circ_type='clifford+zxzxz'):
112
26
  """
@@ -313,305 +227,3 @@ def create_mirror_circuit(circ, pspec, circ_type='clifford+zxzxz'):
313
227
  mirror_circuit = _cir.Circuit(mc, line_labels=circ.line_labels)
314
228
 
315
229
  return mirror_circuit, target_bitstring
316
-
317
-
318
- # #generate mirror circuits with pauli frame randomization. no random +pi needed
319
- # #as we construct the quasi-inverse, we generate random pauli layers, and compile them into the unitaries
320
- # #we'll need to recompute the angles needed for the z rotations
321
-
322
- # def create_nc_mirror_circuit(circ, pspec, circtype='Clifford+Gzr'):
323
-
324
- # assert(circtype == 'Clifford+Gzr' or circtype == 'Clifford')
325
- # n = circ.width
326
- # d = circ.depth
327
- # pauli_labels = ['I', 'X', 'Y', 'Z']
328
- # qubits = circ.line_labels
329
- # identity = _np.identity(2 * n, _np.int64)
330
- # zrotname = 'Gzr'
331
- # # qubit_labels = ['G{}'.format(i) for i in range(n)]
332
-
333
- # _, gate_inverse = pspec.compute_one_qubit_gate_relations()
334
- # gate_inverse.update(pspec.compute_multiqubit_inversion_relations()) # add multiQ inverses
335
- # #for gname in pspec.gate_names:
336
- # # assert(gname in gate_inverse), \
337
- # # "%s gate does not have an inverse in the gate-set! MRB is not possible!" % gname
338
-
339
- # quasi_inverse_circ = []
340
-
341
- # Xpi2layer = [_lbl.Label('Gc16', qubits[t]) for t in range(n)]
342
- # c = circ.copy(editable=True)
343
-
344
- # #build the inverse
345
- # d_ind = 0
346
- # while d_ind<d:
347
- # layer = circ.layer(d - d_ind - 1)
348
- # if layer[0].name == zrotname: #ask if it's a Zrot layer. It's necessary for the whole layer to have Zrot gates
349
-
350
- # current_layers = circ[d-d_ind-5:d-d_ind]
351
- # #recompile inverse of current layer
352
- # for i in range(n):
353
- # #print((i, float(current_layers[0][i].args[0]), float(current_layers[2][i].args[0]),
354
- # # float(current_layers[4][i].args[0])))
355
- # if n==1:
356
- # old_params = [(float(current_layers[0].args[0]), float(current_layers[2].args[0]),
357
- # float(current_layers[4].args[0])) for i in range(n)]
358
- # else:
359
- # old_params = [(float(current_layers[0][i].args[0]), float(current_layers[2][i].args[0]),
360
- # float(current_layers[4][i].args[0])) for i in range(n)]
361
- # layer_new_params = [_comp.inv_recompile_unitary(*p) for p in old_params] #need to write this function
362
- # theta1_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][0]),))
363
- # for i in range(len(layer_new_params))]
364
- # theta2_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][1]),))
365
- # for i in range(len(layer_new_params))]
366
- # theta3_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][2]),))
367
- # for i in range(len(layer_new_params))]
368
-
369
- # #add to mirror circuit
370
- # c.append_circuit_inplace(_cir.Circuit([theta3_layer]))
371
- # c.append_circuit_inplace(_cir.Circuit([Xpi2layer]))
372
- # c.append_circuit_inplace(_cir.Circuit([theta2_layer]))
373
- # c.append_circuit_inplace(_cir.Circuit([Xpi2layer]))
374
- # c.append_circuit_inplace(_cir.Circuit([theta1_layer]))
375
- # d_ind += 5
376
-
377
- # else:
378
- # inverse_layer = [_lbl.Label(gate_inverse[gate.name], gate.qubits) for gate in layer]
379
- # #create quasi-inverse. Right now, it's ust inverting every gate in the original layer, so a simple inverse
380
- # # Add the inverse layer that we've constructed to the end of the circuit
381
- # c.append_circuit_inplace(_cir.Circuit([inverse_layer]))
382
- # d_ind += 1
383
- # #now that we've built the simple mirror circuit, let's add pauli frame randomization
384
- # d_ind = 0
385
- # mc = []
386
- # net_paulis = [0 for q in qubits]
387
- # d = c.depth
388
-
389
-
390
- # srep_dict = _symp.compute_internal_gate_symplectic_representations(gllist=['I', 'X', 'Y', 'Z'])
391
- # # the `callable` part is a workaround to remove gates with args, defined by functions.
392
- # srep_dict.update(pspec.compute_clifford_symplectic_reps([gn for gn, u in pspec.gate_unitaries.items()
393
- # if not callable(u)]))
394
-
395
- # while d_ind<d:
396
- # layer = c.layer(d_ind)
397
- # if layer[0].name == zrotname: #ask if it's a Zrot layer. It's necessary for the whole layer to have Zrot gates
398
- # #if the layer is 1Q unitaries, pauli randomize
399
- # current_layers = c[d_ind:d_ind+5]
400
- # #generate random pauli
401
- # new_paulis = [_np.random.randint(0, 4) for q in qubits]
402
- # new_paulis_as_layer = [_lbl.Label(pauli_labels[new_paulis[i]], qubits[i]) for i in range(n)]
403
- # #compute new net pauli based on previous pauli
404
- # net_paulis_as_layer = [_lbl.Label(pauli_labels[net_paulis[i]], qubits[i]) for i in range(n)]
405
- # net_paulis = _symp.find_pauli_number(_symp.symplectic_rep_of_clifford_circuit(_cir.Circuit(
406
- # new_paulis_as_layer+net_paulis_as_layer), srep_dict=srep_dict)[1])
407
- # #depending on what the net pauli before the U gate is, might need to change parameters on the U gate to
408
- # # commute the pauli through
409
- # #recompile current layer to account for this and recompile with these paulis
410
- # if n == 1:
411
- # old_params_and_paulis = [(float(current_layers[0].args[0]), float(current_layers[2].args[0]),
412
- # float(current_layers[4].args[0]), net_paulis[i], new_paulis[i])
413
- # for i in range(n)]
414
- # else:
415
- # old_params_and_paulis = [(float(current_layers[0][i].args[0]), float(current_layers[2][i].args[0]),
416
- # float(current_layers[4][i].args[0]), net_paulis[i], new_paulis[i])
417
- # for i in range(n)]
418
- # layer_new_params = [_comp.pauli_frame_randomize_unitary(*p) for p in old_params_and_paulis]
419
- # theta1_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][0]),))
420
- # for i in range(len(layer_new_params))]
421
- # theta2_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][1]),))
422
- # for i in range(len(layer_new_params))]
423
- # theta3_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][2]),))
424
- # for i in range(len(layer_new_params))]
425
-
426
- # #add to mirror circuit
427
- # mc.append([theta1_layer])
428
- # mc.append([Xpi2layer])
429
- # mc.append([theta2_layer])
430
- # mc.append([Xpi2layer])
431
- # mc.append([theta3_layer])
432
-
433
- # d_ind += 5
434
-
435
- # else:
436
- # net_paulis_as_layer = [_lbl.Label(pauli_labels[net_paulis[i]], qubits[i]) for i in range(n)]
437
- # net_paulis = _symp.find_pauli_number(_symp.symplectic_rep_of_clifford_circuit(_cir.Circuit([layer
438
- # , net_paulis_as_layer, layer]), srep_dict=srep_dict)[1])
439
- # mc.append(layer)
440
- # #we need to account for how the net pauli changes when it gets passed through the clifford layers
441
- # d_ind += 1
442
-
443
- # #update the target pauli
444
- # pauli_layer = [_lbl.Label(pauli_labels[net_paulis[i]], qubits[i]) for i in range(len(qubits))]
445
- # conjugation_circ = _cir.Circuit([pauli_layer])
446
- # telp_s, telp_p = _symp.symplectic_rep_of_clifford_circuit(conjugation_circ, srep_dict=srep_dict)
447
-
448
- # # Calculate the bit string that this mirror circuit should output, from the final telescoped Pauli.
449
- # target_bitstring = ''.join(['1' if p == 2 else '0' for p in telp_p[n:]])
450
-
451
- # mirror_circuit = _cir.Circuit(mc)
452
-
453
- # return mirror_circuit, target_bitstring
454
-
455
- # #
456
- # def create_cz_mirror_circuit(circ, pspec, circtype='GCzr+Gzr', pauli_labels=None):
457
- # '''
458
- # Makes a mirror circuit with Pauli frame randomization from a forward circuits consisting of only Haar-random 1Q
459
- # unitary layers and CZRot layers
460
- # The 1Q unitaries must be decomposed as Zr-Xpi/2-Zr-Xpi/2-Zr
461
- # The CZRot layers must contain only Gc0/Gi and Gczr gates
462
- # '''
463
-
464
- # assert(circtype == 'GCzr+Gzr')
465
- # n = circ.width
466
- # d = circ.depth
467
- # if pauli_labels is None: pauli_labels = ['Gc0', 'Gc3', 'Gc6', 'Gc9']
468
- # qubits = circ.line_labels
469
- # zrotname = 'Gzr'
470
- # czrotname = 'Gczr'
471
-
472
- # Xpi2layer = [_lbl.Label('Gc16', q) for q in qubits]
473
-
474
- # #make an editable copy of the circuit to add the inverse on to
475
- # c = circ.copy(editable=True)
476
- # #build the inverse
477
- # d_ind = 0
478
- # while d_ind<d:
479
- # layer = circ.layer(d - d_ind - 1)
480
- # if layer[0].name == zrotname: #ask if it's a Zrot layer. It's necessary for the whole layer to have Zrot gates
481
- # #get the entire arbitrary 1q unitaries: Zrot-Xpi/2-Zrot-Xpi/2-Zrot
482
- # current_layers = circ[d-d_ind-5:d-d_ind]
483
- # #recompile inverse of current layer
484
- # for i in range(n):
485
- # if n==1:
486
- # old_params = [(float(current_layers[0].args[0]), float(current_layers[2].args[0]),
487
- # float(current_layers[4].args[0])) for i in range(n)]
488
- # else:
489
- # old_params = [(float(current_layers[0][i].args[0]), float(current_layers[2][i].args[0]),
490
- # float(current_layers[4][i].args[0])) for i in range(n)]
491
- # layer_new_params = [_comp.inv_recompile_unitary(*p) for p in old_params] #generates parameters for
492
- # # the inverse of this layer
493
- # theta1_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][0]),))
494
- # for i in range(len(layer_new_params))]
495
- # theta2_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][1]),))
496
- # for i in range(len(layer_new_params))]
497
- # theta3_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][2]),))
498
- # for i in range(len(layer_new_params))]
499
-
500
- # #add to mirror circuit
501
- # c.append_circuit_inplace(_cir.Circuit([theta3_layer]))
502
- # c.append_circuit_inplace(_cir.Circuit([Xpi2layer]))
503
- # c.append_circuit_inplace(_cir.Circuit([theta2_layer]))
504
- # c.append_circuit_inplace(_cir.Circuit([Xpi2layer]))
505
- # c.append_circuit_inplace(_cir.Circuit([theta1_layer]))
506
-
507
- # d_ind += 5
508
-
509
- # if layer[0].name == czrotname or layer[0].name == 'Gc0':
510
- # invlayer = []
511
- # for g in layer:
512
- # if g.name == czrotname:
513
- # gate_qubits = g.qubits
514
- # #get gate args
515
- # theta = float(g.args[0])
516
- # invlayer.append(_lbl.Label(czrotname, gate_qubits, args=(str(-1*theta),)))
517
- # else:
518
- # invlayer.append(g)
519
- # c.append_circuit_inplace(_cir.Circuit([invlayer]))
520
- # d_ind += 1
521
-
522
- # #now that we've built the simple mirror circuit, let's add pauli frame randomization
523
- # d_ind = 0
524
- # mc = []
525
- # net_paulis = {q:0 for q in qubits} #dictionary keeping track of the random paulis
526
- # d = c.depth
527
- # correction_angles = {q: 0 for q in qubits}
528
-
529
- # while d_ind<d:
530
- # layer = c.layer(d_ind)
531
- # if layer[0].name == zrotname:
532
- # #if the layer is 1Q unitaries, pauli randomize
533
- # current_layers = c[d_ind:d_ind+5]
534
-
535
- # #generate random pauli
536
- # new_paulis = {q: _np.random.randint(0, 4) for q in qubits}
537
- # new_paulis_as_layer = [_lbl.Label(pauli_labels[new_paulis[q]], q) for q in qubits]
538
-
539
- # #compute new net pauli based on previous pauli
540
- # net_paulis_as_layer = [_lbl.Label(pauli_labels[net_paulis[q]], q) for q in qubits]
541
-
542
- # net_pauli_numbers = _symp.find_pauli_number(_symp.symplectic_rep_of_clifford_circuit(_cir.Circuit(
543
- # new_paulis_as_layer+net_paulis_as_layer), pspec=pspec)[1])
544
- # net_paulis = {qubits[i]: net_pauli_numbers[i] for i in range(n)}
545
-
546
- # #depending on what the net pauli before the U gate is, might need to change parameters on the U gate to
547
- # # commute the pauli through
548
- # #recompile current layer to account for this and recompile with these paulis
549
- # if n == 1:
550
- # old_params_and_paulis = [(float(current_layers[0].args[0]), float(current_layers[2].args[0]),
551
- # float(current_layers[4].args[0]), net_paulis[qubits[i]], new_paulis[qubits[i]]) for i in range(n)]
552
- # else:
553
- # #problem:ordering of qubits in the layer isn't always consistent
554
- # old_params_and_paulis = [(float(current_layers[0][i].args[0]), float(current_layers[2][i].args[0]),
555
- # float(current_layers[4][i].args[0]), net_paulis[qubits[i]],
556
- # new_paulis[qubits[i]]) for i in range(n)]
557
-
558
- # layer_new_params = [_comp.pauli_frame_randomize_unitary(*p) for p in old_params_and_paulis] #need to write
559
- # # this function
560
- # #recompile any zrotation corrections from the previous Czr into the first zr of this layer
561
- # theta1_layer = [_lbl.Label(zrotname, qubits[i],
562
- # args=(str(layer_new_params[i][0]+correction_angles[qubits[i]]),)) for i in range(len(layer_new_params))]
563
- # theta2_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][1]),))
564
- # for i in range(len(layer_new_params))]
565
- # theta3_layer = [_lbl.Label(zrotname, qubits[i], args=(str(layer_new_params[i][2]),))
566
- # for i in range(len(layer_new_params))]
567
- # #add to mirror circuit
568
- # mc.append([theta1_layer])
569
- # mc.append([Xpi2layer])
570
- # mc.append([theta2_layer])
571
- # mc.append([Xpi2layer])
572
- # mc.append([theta3_layer])
573
-
574
- # correction_angles = {q: 0 for q in qubits}
575
- # d_ind += 5
576
-
577
- # if layer[0].name == czrotname or layer[0].name == 'Gc0':
578
- # quasi_inv_layer = []
579
-
580
- # #recompile layer taking into acount paulis
581
- # for g in layer:
582
- # if g.name == czrotname:
583
- # #get the qubits, figure out net pauli on those qubits
584
- # gate_qubits = g.qubits
585
- # net_paulis_for_gate = (net_paulis[gate_qubits[0]], net_paulis[gate_qubits[1]])
586
- # theta = float(g.args[0])
587
- # if ((net_paulis_for_gate[0] % 3 != 0 and net_paulis_for_gate[1] % 3 == 0)
588
- # or (net_paulis_for_gate[0] % 3 == 0 and net_paulis_for_gate[1] % 3 != 0)):
589
- # theta *= -1
590
- # quasi_inv_layer.append(_lbl.Label(czrotname, gate_qubits, args=(str(theta),)))
591
- # #for each X or Y, do a Zrotation by -theta on the other qubit after the 2Q gate.
592
- # for q in gate_qubits:
593
- # if net_paulis[q] == 1 or net_paulis[q] == 2:
594
- # for q2 in gate_qubits:
595
- # if q2 != q:
596
- # correction_angles[q2] += -1*theta
597
- # else:
598
- # gate_qubit = g.qubits
599
- # quasi_inv_layer.append(_lbl.Label('Gc0', gate_qubit))
600
- # #add to circuit
601
- # mc.append([quasi_inv_layer])
602
-
603
- # #increment position in circuit
604
- # d_ind += 1
605
-
606
- # #update the target pauli
607
- # pauli_layer = [_lbl.Label(pauli_labels[net_paulis[q]], q) for q in qubits]
608
- # conjugation_circ = _cir.Circuit([pauli_layer]) #conjugation_circ = _cir.Circuit([random_stateprep_layer,
609
- # pauli_layer, random_meas_layer])
610
- # telp_s, telp_p = _symp.symplectic_rep_of_clifford_circuit(conjugation_circ, pspec=pspec)
611
-
612
- # # Calculate the bit string that this mirror circuit should output, from the final Pauli.
613
- # target_bitstring = ''.join(['1' if p == 2 else '0' for p in telp_p[n:]])
614
-
615
- # mirror_circuit = _cir.Circuit(mc)
616
-
617
- # return mirror_circuit, target_bitstring