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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. pyGSTi-0.9.13.dist-info/METADATA +197 -0
  2. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/RECORD +207 -217
  3. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/WHEEL +1 -1
  4. pygsti/_version.py +2 -2
  5. pygsti/algorithms/contract.py +1 -1
  6. pygsti/algorithms/core.py +42 -28
  7. pygsti/algorithms/fiducialselection.py +17 -8
  8. pygsti/algorithms/gaugeopt.py +2 -2
  9. pygsti/algorithms/germselection.py +87 -77
  10. pygsti/algorithms/mirroring.py +0 -388
  11. pygsti/algorithms/randomcircuit.py +165 -1333
  12. pygsti/algorithms/rbfit.py +0 -234
  13. pygsti/baseobjs/basis.py +94 -396
  14. pygsti/baseobjs/errorgenbasis.py +0 -132
  15. pygsti/baseobjs/errorgenspace.py +0 -10
  16. pygsti/baseobjs/label.py +52 -168
  17. pygsti/baseobjs/opcalc/fastopcalc.cp39-win32.pyd +0 -0
  18. pygsti/baseobjs/opcalc/fastopcalc.pyx +2 -2
  19. pygsti/baseobjs/polynomial.py +13 -595
  20. pygsti/baseobjs/statespace.py +1 -0
  21. pygsti/circuits/__init__.py +1 -1
  22. pygsti/circuits/circuit.py +682 -505
  23. pygsti/circuits/circuitconstruction.py +0 -4
  24. pygsti/circuits/circuitlist.py +47 -5
  25. pygsti/circuits/circuitparser/__init__.py +8 -8
  26. pygsti/circuits/circuitparser/fastcircuitparser.cp39-win32.pyd +0 -0
  27. pygsti/circuits/circuitstructure.py +3 -3
  28. pygsti/circuits/cloudcircuitconstruction.py +1 -1
  29. pygsti/data/datacomparator.py +2 -7
  30. pygsti/data/dataset.py +46 -44
  31. pygsti/data/hypothesistest.py +0 -7
  32. pygsti/drivers/bootstrap.py +0 -49
  33. pygsti/drivers/longsequence.py +2 -1
  34. pygsti/evotypes/basereps_cython.cp39-win32.pyd +0 -0
  35. pygsti/evotypes/chp/opreps.py +0 -61
  36. pygsti/evotypes/chp/statereps.py +0 -32
  37. pygsti/evotypes/densitymx/effectcreps.cpp +9 -10
  38. pygsti/evotypes/densitymx/effectreps.cp39-win32.pyd +0 -0
  39. pygsti/evotypes/densitymx/effectreps.pyx +1 -1
  40. pygsti/evotypes/densitymx/opreps.cp39-win32.pyd +0 -0
  41. pygsti/evotypes/densitymx/opreps.pyx +2 -2
  42. pygsti/evotypes/densitymx/statereps.cp39-win32.pyd +0 -0
  43. pygsti/evotypes/densitymx/statereps.pyx +1 -1
  44. pygsti/evotypes/densitymx_slow/effectreps.py +7 -23
  45. pygsti/evotypes/densitymx_slow/opreps.py +16 -23
  46. pygsti/evotypes/densitymx_slow/statereps.py +10 -3
  47. pygsti/evotypes/evotype.py +39 -2
  48. pygsti/evotypes/stabilizer/effectreps.cp39-win32.pyd +0 -0
  49. pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
  50. pygsti/evotypes/stabilizer/opreps.cp39-win32.pyd +0 -0
  51. pygsti/evotypes/stabilizer/opreps.pyx +0 -4
  52. pygsti/evotypes/stabilizer/statereps.cp39-win32.pyd +0 -0
  53. pygsti/evotypes/stabilizer/statereps.pyx +1 -5
  54. pygsti/evotypes/stabilizer/termreps.cp39-win32.pyd +0 -0
  55. pygsti/evotypes/stabilizer/termreps.pyx +0 -7
  56. pygsti/evotypes/stabilizer_slow/effectreps.py +0 -22
  57. pygsti/evotypes/stabilizer_slow/opreps.py +0 -4
  58. pygsti/evotypes/stabilizer_slow/statereps.py +0 -4
  59. pygsti/evotypes/statevec/effectreps.cp39-win32.pyd +0 -0
  60. pygsti/evotypes/statevec/effectreps.pyx +1 -1
  61. pygsti/evotypes/statevec/opreps.cp39-win32.pyd +0 -0
  62. pygsti/evotypes/statevec/opreps.pyx +2 -2
  63. pygsti/evotypes/statevec/statereps.cp39-win32.pyd +0 -0
  64. pygsti/evotypes/statevec/statereps.pyx +1 -1
  65. pygsti/evotypes/statevec/termreps.cp39-win32.pyd +0 -0
  66. pygsti/evotypes/statevec/termreps.pyx +0 -7
  67. pygsti/evotypes/statevec_slow/effectreps.py +0 -3
  68. pygsti/evotypes/statevec_slow/opreps.py +0 -5
  69. pygsti/extras/__init__.py +0 -1
  70. pygsti/extras/drift/stabilityanalyzer.py +3 -1
  71. pygsti/extras/interpygate/__init__.py +12 -0
  72. pygsti/extras/interpygate/core.py +0 -36
  73. pygsti/extras/interpygate/process_tomography.py +44 -10
  74. pygsti/extras/rpe/rpeconstruction.py +0 -2
  75. pygsti/forwardsims/__init__.py +1 -0
  76. pygsti/forwardsims/forwardsim.py +14 -55
  77. pygsti/forwardsims/mapforwardsim.py +69 -18
  78. pygsti/forwardsims/mapforwardsim_calc_densitymx.cp39-win32.pyd +0 -0
  79. pygsti/forwardsims/mapforwardsim_calc_densitymx.pyx +65 -66
  80. pygsti/forwardsims/mapforwardsim_calc_generic.py +91 -13
  81. pygsti/forwardsims/matrixforwardsim.py +63 -15
  82. pygsti/forwardsims/termforwardsim.py +8 -110
  83. pygsti/forwardsims/termforwardsim_calc_stabilizer.cp39-win32.pyd +0 -0
  84. pygsti/forwardsims/termforwardsim_calc_statevec.cp39-win32.pyd +0 -0
  85. pygsti/forwardsims/termforwardsim_calc_statevec.pyx +0 -651
  86. pygsti/forwardsims/torchfwdsim.py +265 -0
  87. pygsti/forwardsims/weakforwardsim.py +2 -2
  88. pygsti/io/__init__.py +1 -2
  89. pygsti/io/mongodb.py +0 -2
  90. pygsti/io/stdinput.py +6 -22
  91. pygsti/layouts/copalayout.py +10 -12
  92. pygsti/layouts/distlayout.py +0 -40
  93. pygsti/layouts/maplayout.py +103 -25
  94. pygsti/layouts/matrixlayout.py +99 -60
  95. pygsti/layouts/prefixtable.py +1534 -52
  96. pygsti/layouts/termlayout.py +1 -1
  97. pygsti/modelmembers/instruments/instrument.py +3 -3
  98. pygsti/modelmembers/instruments/tpinstrument.py +2 -2
  99. pygsti/modelmembers/modelmember.py +0 -17
  100. pygsti/modelmembers/operations/__init__.py +2 -4
  101. pygsti/modelmembers/operations/affineshiftop.py +1 -0
  102. pygsti/modelmembers/operations/composederrorgen.py +1 -1
  103. pygsti/modelmembers/operations/composedop.py +1 -24
  104. pygsti/modelmembers/operations/denseop.py +5 -5
  105. pygsti/modelmembers/operations/eigpdenseop.py +2 -2
  106. pygsti/modelmembers/operations/embeddederrorgen.py +1 -1
  107. pygsti/modelmembers/operations/embeddedop.py +0 -1
  108. pygsti/modelmembers/operations/experrorgenop.py +2 -2
  109. pygsti/modelmembers/operations/fullarbitraryop.py +1 -0
  110. pygsti/modelmembers/operations/fullcptpop.py +2 -2
  111. pygsti/modelmembers/operations/fulltpop.py +28 -6
  112. pygsti/modelmembers/operations/fullunitaryop.py +5 -4
  113. pygsti/modelmembers/operations/lindbladcoefficients.py +93 -78
  114. pygsti/modelmembers/operations/lindbladerrorgen.py +268 -441
  115. pygsti/modelmembers/operations/linearop.py +7 -27
  116. pygsti/modelmembers/operations/opfactory.py +1 -1
  117. pygsti/modelmembers/operations/repeatedop.py +1 -24
  118. pygsti/modelmembers/operations/staticstdop.py +1 -1
  119. pygsti/modelmembers/povms/__init__.py +3 -3
  120. pygsti/modelmembers/povms/basepovm.py +7 -36
  121. pygsti/modelmembers/povms/complementeffect.py +4 -9
  122. pygsti/modelmembers/povms/composedeffect.py +0 -320
  123. pygsti/modelmembers/povms/computationaleffect.py +1 -1
  124. pygsti/modelmembers/povms/computationalpovm.py +3 -1
  125. pygsti/modelmembers/povms/effect.py +3 -5
  126. pygsti/modelmembers/povms/marginalizedpovm.py +0 -79
  127. pygsti/modelmembers/povms/tppovm.py +74 -2
  128. pygsti/modelmembers/states/__init__.py +2 -5
  129. pygsti/modelmembers/states/composedstate.py +0 -317
  130. pygsti/modelmembers/states/computationalstate.py +3 -3
  131. pygsti/modelmembers/states/cptpstate.py +4 -4
  132. pygsti/modelmembers/states/densestate.py +6 -4
  133. pygsti/modelmembers/states/fullpurestate.py +0 -24
  134. pygsti/modelmembers/states/purestate.py +1 -1
  135. pygsti/modelmembers/states/state.py +5 -6
  136. pygsti/modelmembers/states/tpstate.py +28 -10
  137. pygsti/modelmembers/term.py +3 -6
  138. pygsti/modelmembers/torchable.py +50 -0
  139. pygsti/modelpacks/_modelpack.py +1 -1
  140. pygsti/modelpacks/smq1Q_ZN.py +3 -1
  141. pygsti/modelpacks/smq2Q_XXYYII.py +2 -1
  142. pygsti/modelpacks/smq2Q_XY.py +3 -3
  143. pygsti/modelpacks/smq2Q_XYI.py +2 -2
  144. pygsti/modelpacks/smq2Q_XYICNOT.py +3 -3
  145. pygsti/modelpacks/smq2Q_XYICPHASE.py +3 -3
  146. pygsti/modelpacks/smq2Q_XYXX.py +1 -1
  147. pygsti/modelpacks/smq2Q_XYZICNOT.py +3 -3
  148. pygsti/modelpacks/smq2Q_XYZZ.py +1 -1
  149. pygsti/modelpacks/stdtarget.py +0 -121
  150. pygsti/models/cloudnoisemodel.py +1 -2
  151. pygsti/models/explicitcalc.py +3 -3
  152. pygsti/models/explicitmodel.py +3 -13
  153. pygsti/models/fogistore.py +5 -3
  154. pygsti/models/localnoisemodel.py +1 -2
  155. pygsti/models/memberdict.py +0 -12
  156. pygsti/models/model.py +800 -65
  157. pygsti/models/modelconstruction.py +4 -4
  158. pygsti/models/modelnoise.py +2 -2
  159. pygsti/models/modelparaminterposer.py +1 -1
  160. pygsti/models/oplessmodel.py +1 -1
  161. pygsti/models/qutrit.py +15 -14
  162. pygsti/objectivefns/objectivefns.py +73 -138
  163. pygsti/objectivefns/wildcardbudget.py +2 -7
  164. pygsti/optimize/__init__.py +1 -0
  165. pygsti/optimize/arraysinterface.py +28 -0
  166. pygsti/optimize/customcg.py +0 -12
  167. pygsti/optimize/customlm.py +129 -323
  168. pygsti/optimize/customsolve.py +2 -2
  169. pygsti/optimize/optimize.py +0 -84
  170. pygsti/optimize/simplerlm.py +841 -0
  171. pygsti/optimize/wildcardopt.py +19 -598
  172. pygsti/protocols/confidenceregionfactory.py +28 -14
  173. pygsti/protocols/estimate.py +31 -14
  174. pygsti/protocols/gst.py +142 -68
  175. pygsti/protocols/modeltest.py +6 -10
  176. pygsti/protocols/protocol.py +9 -37
  177. pygsti/protocols/rb.py +450 -79
  178. pygsti/protocols/treenode.py +8 -2
  179. pygsti/protocols/vb.py +108 -206
  180. pygsti/protocols/vbdataframe.py +1 -1
  181. pygsti/report/factory.py +0 -15
  182. pygsti/report/fogidiagram.py +1 -17
  183. pygsti/report/modelfunction.py +12 -3
  184. pygsti/report/mpl_colormaps.py +1 -1
  185. pygsti/report/plothelpers.py +8 -2
  186. pygsti/report/reportables.py +41 -37
  187. pygsti/report/templates/offline/pygsti_dashboard.css +6 -0
  188. pygsti/report/templates/offline/pygsti_dashboard.js +12 -0
  189. pygsti/report/workspace.py +2 -14
  190. pygsti/report/workspaceplots.py +326 -504
  191. pygsti/tools/basistools.py +9 -36
  192. pygsti/tools/edesigntools.py +124 -96
  193. pygsti/tools/fastcalc.cp39-win32.pyd +0 -0
  194. pygsti/tools/fastcalc.pyx +35 -81
  195. pygsti/tools/internalgates.py +151 -15
  196. pygsti/tools/jamiolkowski.py +5 -5
  197. pygsti/tools/lindbladtools.py +19 -11
  198. pygsti/tools/listtools.py +0 -114
  199. pygsti/tools/matrixmod2.py +1 -1
  200. pygsti/tools/matrixtools.py +173 -339
  201. pygsti/tools/nameddict.py +1 -1
  202. pygsti/tools/optools.py +154 -88
  203. pygsti/tools/pdftools.py +0 -25
  204. pygsti/tools/rbtheory.py +3 -320
  205. pygsti/tools/slicetools.py +64 -12
  206. pyGSTi-0.9.12.1.dist-info/METADATA +0 -155
  207. pygsti/algorithms/directx.py +0 -711
  208. pygsti/evotypes/qibo/__init__.py +0 -33
  209. pygsti/evotypes/qibo/effectreps.py +0 -78
  210. pygsti/evotypes/qibo/opreps.py +0 -376
  211. pygsti/evotypes/qibo/povmreps.py +0 -98
  212. pygsti/evotypes/qibo/statereps.py +0 -174
  213. pygsti/extras/rb/__init__.py +0 -13
  214. pygsti/extras/rb/benchmarker.py +0 -957
  215. pygsti/extras/rb/dataset.py +0 -378
  216. pygsti/extras/rb/io.py +0 -814
  217. pygsti/extras/rb/simulate.py +0 -1020
  218. pygsti/io/legacyio.py +0 -385
  219. pygsti/modelmembers/povms/denseeffect.py +0 -142
  220. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/LICENSE +0 -0
  221. {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/top_level.txt +0 -0
@@ -198,139 +198,6 @@ def find_all_sets_of_compatible_two_q_gates(edgelist, n, gatename='Gcnot', aslab
198
198
  return co2Qgates
199
199
 
200
200
 
201
- # TJP: I am not aware this is ever used anymore, and it's functionality is possibly even included in the
202
- # other samplers.
203
- # def sample_circuit_layer_by_pairing_qubits(pspec, qubit_labels=None, two_q_prob=0.5, one_q_gate_names='all',
204
- # two_q_gate_names='all', modelname='clifford', rand_state=None):
205
- # """
206
- # Creates a circuit by randomply placing 2-qubit gates on qubit pairs.
207
-
208
- # Samples a random circuit layer by pairing up qubits and picking a two-qubit gate for a pair
209
- # with the specificed probability. This sampler *assumes* all-to-all connectivity, and does
210
- # not check that this condition is satisfied (more generally, it assumes that all gates can be
211
- # applied in parallel in any combination that would be well-defined).
212
-
213
- # The sampler works as follows: If there are an odd number of qubits, one qubit is chosen at
214
- # random to have a uniformly random 1-qubit gate applied to it (from all possible 1-qubit gates,
215
- # or those in `one_q_gate_names` if not None). Then, the remaining qubits are paired up, uniformly
216
- # at random. A uniformly random 2-qubit gate is then chosen for a pair with probability `two_q_prob`
217
- # (from all possible 2-qubit gates, or those in `two_q_gate_names` if not None). If a 2-qubit gate
218
- # is not chosen to act on a pair, then each qubit is independently and uniformly randomly assigned
219
- # a 1-qubit gate.
220
-
221
- # Parameters
222
- # ----------
223
- # pspec : QubitProcessorSpec
224
- # The QubitProcessorSpec for the device that the circuit layer is being sampled for. This
225
- # function assumes all-to-all connectivity, but does not check this is satisfied. Unless
226
- # `qubit_labels` is not None, a circuit layer is sampled over all the qubits in `pspec`.
227
-
228
- # qubit_labels : list, optional
229
- # If not None, a list of the qubits to sample the circuit layer for. This is a subset of
230
- # `pspec.qubit_labels`. If None, the circuit layer is sampled to acton all the qubits
231
- # in `pspec`.
232
-
233
- # two_q_prob : float, optional
234
- # A probability for a two-qubit gate to be applied to a pair of qubits. So, the expected
235
- # number of 2-qubit gates in the sampled layer is two_q_prob*floor(n/2).
236
-
237
- # one_q_gate_names : 'all' or list, optional
238
- # If not 'all', a list of the names of the 1-qubit gates to be sampled from when applying
239
- # a 1-qubit gate to a qubit. If this is 'all', the full set of 1-qubit gate names is extracted
240
- # from the QubitProcessorSpec.
241
-
242
- # two_q_gate_names : 'all' or list, optional
243
- # If not 'all', a list of the names of the 2-qubit gates to be sampled from when applying
244
- # a 2-qubit gate to a pair of qubits. If this is 'all', the full set of 2-qubit gate names is
245
- # extracted from the QubitProcessorSpec.
246
-
247
- # modelname : str, optional
248
- # Only used if one_q_gate_names or two_q_gate_names is None. Specifies which of the
249
- # `pspec.models` to use to extract the gate-set. The `clifford` default is suitable
250
- # for Clifford or direct RB, but will not use any non-Clifford gates in the gate-set.
251
-
252
- # rand_state: RandomState, optional
253
- # A np.random.RandomState object for seeding RNG
254
-
255
- # Returns
256
- # -------
257
- # list of Labels
258
- # A list of gate Labels that defines a "complete" circuit layer (there is one and only
259
- # one gate acting on each qubit in `pspec` or `qubit_labels`).
260
- # """
261
- # if rand_state is None:
262
- # rand_state = _np.random.RandomState()
263
-
264
- # if qubit_labels is None: n = pspec.num_qubits
265
- # else:
266
- # assert(isinstance(qubit_labels, list) or isinstance(qubit_labels, tuple)), \
267
- # "SubsetQs must be a list or a tuple!"
268
- # n = len(qubit_labels)
269
-
270
- # # If the one qubit and/or two qubit gate names are only specified as 'all', construct them.
271
- # if (one_q_gate_names == 'all') or (two_q_gate_names == 'all'):
272
- # if one_q_gate_names == 'all':
273
- # oneQpopulate = True
274
- # one_q_gate_names = []
275
- # else:
276
- # oneQpopulate = False
277
- # if two_q_gate_names == 'all':
278
- # twoQpopulate = True
279
- # two_q_gate_names = []
280
- # else:
281
- # twoQpopulate = False
282
-
283
- # operationlist = pspec.models[modelname].primitive_op_labels
284
- # for gate in operationlist:
285
- # if oneQpopulate:
286
- # if (gate.num_qubits == 1) and (gate.name not in one_q_gate_names):
287
- # one_q_gate_names.append(gate.name)
288
- # if twoQpopulate:
289
- # if (gate.num_qubits == 2) and (gate.name not in two_q_gate_names):
290
- # two_q_gate_names.append(gate.name)
291
-
292
- # # Basic variables required for sampling the circuit layer.
293
- # if qubit_labels is None:
294
- # qubits = list(pspec.qubit_labels[:]) # copy this list
295
- # else:
296
- # qubits = list(qubit_labels[:]) # copy this list
297
- # sampled_layer = []
298
- # num_oneQgatenames = len(one_q_gate_names)
299
- # num_twoQgatenames = len(two_q_gate_names)
300
-
301
- # # If there is an odd number of qubits, begin by picking one to have a 1-qubit gate.
302
- # if n % 2 != 0:
303
- # q = qubits[rand_state.randint(0, n)]
304
- # name = one_q_gate_names[rand_state.randint(0, num_oneQgatenames)]
305
- # del qubits[q] # XXX is this correct?
306
- # sampled_layer.append(_lbl.Label(name, q))
307
-
308
- # # Go through n//2 times until all qubits have been paired up and gates on them sampled
309
- # for i in range(n // 2):
310
-
311
- # # Pick two of the remaining qubits : each qubit that is picked is deleted from the list.
312
- # index = rand_state.randint(0, len(qubits))
313
- # q1 = qubits[index]
314
- # del qubits[index]
315
- # index = rand_state.randint(0, len(qubits))
316
- # q2 = qubits[index]
317
- # del qubits[index]
318
-
319
- # # Flip a coin to decide whether to act a two-qubit gate on that qubit
320
- # if rand_state.binomial(1, two_q_prob) == 1:
321
- # # If there is more than one two-qubit gate on the pair, pick a uniformly random one.
322
- # name = two_q_gate_names[rand_state.randint(0, num_twoQgatenames)]
323
- # sampled_layer.append(_lbl.Label(name, (q1, q2)))
324
- # else:
325
- # # Independently, pick uniformly random 1-qubit gates to apply to each qubit.
326
- # name1 = one_q_gate_names[rand_state.randint(0, num_oneQgatenames)]
327
- # name2 = one_q_gate_names[rand_state.randint(0, num_oneQgatenames)]
328
- # sampled_layer.append(_lbl.Label(name1, q1))
329
- # sampled_layer.append(_lbl.Label(name2, q2))
330
-
331
- # return sampled_layer
332
-
333
-
334
201
  def sample_circuit_layer_by_edgegrab(pspec, qubit_labels=None, two_q_gate_density=0.25, one_q_gate_names=None,
335
202
  gate_args_lists=None, rand_state=None):
336
203
  """
@@ -908,446 +775,6 @@ def create_random_circuit(pspec, length, qubit_labels=None, sampler='Qeliminatio
908
775
  circuit.done_editing()
909
776
  return circuit
910
777
 
911
- #### Commented out as this code has not been tested since a much older version of pyGSTi and it is probably
912
- #### not being used.
913
- # def sample_simultaneous_random_circuit(pspec, length, structure='1Q', sampler='Qelimination', samplerargs=[],
914
- # addlocal=False, lsargs=[]):
915
- # """
916
- # Generates a random circuit of the specified length.
917
-
918
- # Parameters
919
- # ----------
920
- # pspec : QubitProcessorSpec
921
- # The QubitProcessorSpec for the device that the circuit is being sampled for, which defines the
922
- # "native" gate-set and the connectivity of the device. The returned circuit will be over
923
- # the gates in `pspec`, and will respect the connectivity encoded by `pspec`. Note that `pspec`
924
- # is always handed to the sampler, as the first argument of the sampler function (this is only
925
- # of importance when not using an in-built sampler).
926
-
927
- # length : int
928
- # The length of the circuit. Todo: update for varying length in different subsets.
929
-
930
- # structure : str or tuple, optional
931
- # todo.
932
-
933
- # sampler : str or function, optional
934
- # If a string, this should be one of: {'pairingQs', 'Qelimination', 'co2Qgates', 'local'}.
935
- # Except for 'local', this corresponds to sampling layers according to the sampling function
936
- # in rb.sampler named circuit_layer_by* (with * replaced by 'sampler'). For 'local', this
937
- # corresponds to sampling according to rb.sampler.circuit_layer_of_oneQgates.
938
- # If `sampler` is a function, it should be a function that takes as the first argument a
939
- # QubitProcessorSpec, and returns a random circuit layer as a list of gate Label objects. Note that
940
- # the default 'Qelimination' is not necessarily the most useful in-built sampler, but it is
941
- # the only sampler that requires no parameters beyond the QubitProcessorSpec *and* works for arbitrary
942
- # connectivity devices. See the docstrings for each of these samplers for more information.
943
-
944
- # samplerargs : list, optional
945
- # A list of arguments that are handed to the sampler function, specified by `sampler`.
946
- # The first argument handed to the sampler is `pspec`, the second argument is `qubit_labels`,
947
- # and `samplerargs` lists the remaining arguments handed to the sampler. This is not
948
- # optional for some choices of `sampler`.
949
-
950
- # addlocal : bool, optional
951
- # Whether to follow each layer in the circuit, sampled according to `sampler` with
952
- # a layer of 1-qubit gates. If this is True then the length of the circuit is double
953
- # the requested length.
954
-
955
- # lsargs : list, optional
956
- # Only used if addlocal is True. A list of optional arguments handed to the 1Q gate
957
- # layer sampler circuit_layer_by_oneQgate(). Specifies how to sample 1Q-gate layers.
958
-
959
- # Returns
960
- # -------
961
- # Circuit
962
- # A random circuit sampled as specified.
963
- # Tuple
964
- # A length-n tuple of floats in [0,1], corresponding to the error-free *marginalized* probabilities
965
- # for the "1" outcome of a computational basis measurement at the end of this circuit, with the standard
966
- # input state (with the outcomes ordered to be the same as the wires in the circuit).
967
- # """
968
- # if isinstance(structure, str):
969
- # assert(structure == '1Q'), "The only default `structure` option is the string '1Q'"
970
- # structure = tuple([(q,) for q in pspec.qubit_labels])
971
- # n = pspec.num_qubits
972
- # else:
973
- # assert(isinstance(structure, list) or isinstance(structure, tuple)
974
- # ), "If not a string, `structure` must be a list or tuple."
975
- # qubits_used = []
976
- # for qubit_labels in structure:
977
- # assert(isinstance(qubit_labels, list) or isinstance(
978
- # qubit_labels, tuple)), "SubsetQs must be a list or a tuple!"
979
- # qubits_used = qubits_used + list(qubit_labels)
980
- # assert(len(set(qubits_used)) == len(qubits_used)
981
- # ), "The qubits in the tuples/lists of `structure must all be unique!"
982
-
983
- # assert(set(qubits_used).issubset(set(pspec.qubit_labels))
984
- # ), "The qubits to benchmark must all be in the QubitProcessorSpec `pspec`!"
985
- # n = len(qubits_used)
986
-
987
- # # Creates a empty circuit over no wires
988
- # circuit = _cir.Circuit(num_lines=0, editable=True)
989
-
990
- # s_rc_dict = {}
991
- # p_rc_dict = {}
992
- # circuit_dict = {}
993
-
994
- # if isinstance(length, _np.int64):
995
- # length_per_subset = [length for i in range(len(structure))]
996
- # else:
997
- # length_per_subset = length
998
- # assert(len(length) == len(structure)), "If `length` is a list it must be the same length as `structure`"
999
-
1000
- # for ssQs_ind, qubit_labels in enumerate(structure):
1001
- # qubit_labels = tuple(qubit_labels)
1002
- # # Sample a random circuit of "native gates" over this set of qubits, with the
1003
- # # specified sampling.
1004
- # subset_circuit = create_random_circuit(pspec=pspec, length=length_per_subset[ssQs_ind],
1005
- # qubit_labels=qubit_labels, sampler=sampler, samplerargs=samplerargs,
1006
- # addlocal=addlocal, lsargs=lsargs)
1007
- # circuit_dict[qubit_labels] = subset_circuit
1008
- # # find the symplectic matrix / phase vector this circuit implements.
1009
- # s_rc_dict[qubit_labels], p_rc_dict[qubit_labels] = _symp.symplectic_rep_of_clifford_circuit(
1010
- # subset_circuit, pspec=pspec)
1011
- # # Tensors this circuit with the current circuit
1012
- # circuit.tensor_circuit_inplace(subset_circuit)
1013
-
1014
- # circuit.done_editing()
1015
-
1016
- # # Find the expected outcome of the circuit.
1017
- # s_out, p_out = _symp.symplectic_rep_of_clifford_circuit(circuit, pspec=pspec)
1018
- # s_inputstate, p_inputstate = _symp.prep_stabilizer_state(n, zvals=None)
1019
- # s_outstate, p_outstate = _symp.apply_clifford_to_stabilizer_state(s_out, p_out, s_inputstate, p_inputstate)
1020
- # idealout = []
1021
- # for qubit_labels in structure:
1022
- # subset_idealout = []
1023
- # for q in qubit_labels:
1024
- # qind = circuit.line_labels.index(q)
1025
- # measurement_out = _symp.pauli_z_measurement(s_outstate, p_outstate, qind)
1026
- # subset_idealout.append(measurement_out[1])
1027
- # idealout.append(tuple(subset_idealout))
1028
- # idealout = tuple(idealout)
1029
-
1030
- # return circuit, idealout
1031
-
1032
-
1033
- # def _get_setting(l, circuitindex, substructure, depths, circuits_per_length, structure):
1034
-
1035
- # lind = depths.index(l)
1036
- # settingDict = {}
1037
-
1038
- # for s in structure:
1039
- # if s in substructure:
1040
- # settingDict[s] = len(depths) + lind * circuits_per_length + circuitindex
1041
- # else:
1042
- # settingDict[s] = lind
1043
-
1044
- # return settingDict
1045
-
1046
-
1047
- # def create_simultaneous_random_circuits_experiment(pspec, depths, circuits_per_length, structure='1Q',
1048
- # sampler='Qelimination', samplerargs=[], addlocal=False,
1049
- # lsargs=[], set_isolated=True, setcomplement_isolated=False,
1050
- # descriptor='A set of simultaneous random circuits', verbosity=1):
1051
- # """
1052
- # Generates a set of simultaneous random circuits of the specified depths.
1053
-
1054
- # Parameters
1055
- # ----------
1056
- # pspec : QubitProcessorSpec
1057
- # The QubitProcessorSpec for the device that the circuit is being sampled for, which defines the
1058
- # "native" gate-set and the connectivity of the device. The returned circuit will be over
1059
- # the gates in `pspec`, and will respect the connectivity encoded by `pspec`. Note that `pspec`
1060
- # is always handed to the sampler, as the first argument of the sampler function (this is only
1061
- # of importance when not using an in-built sampler).
1062
-
1063
- # depths : int
1064
- # Todo : update (needs to include list option)
1065
- # The set of depths for the circuits.
1066
-
1067
- # circuits_per_length : int
1068
- # The number of (possibly) different circuits sampled at each length.
1069
-
1070
- # structure : str or tuple.
1071
- # Defines the "structure" of the simultaneous circuit. TODO : more details.
1072
-
1073
- # sampler : str or function, optional
1074
- # If a string, this should be one of: {'pairingQs', 'Qelimination', 'co2Qgates', 'local'}.
1075
- # Except for 'local', this corresponds to sampling layers according to the sampling function
1076
- # in rb.sampler named circuit_layer_by* (with * replaced by 'sampler'). For 'local', this
1077
- # corresponds to sampling according to rb.sampler.circuit_layer_of_oneQgates.
1078
- # If `sampler` is a function, it should be a function that takes as the first argument a
1079
- # QubitProcessorSpec, and returns a random circuit layer as a list of gate Label objects. Note that
1080
- # the default 'Qelimination' is not necessarily the most useful in-built sampler, but it is the
1081
- # only sampler that requires no parameters beyond the QubitProcessorSpec *and* works for arbitrary
1082
- # connectivity devices. See the docstrings for each of these samplers for more information.
1083
-
1084
- # samplerargs : list, optional
1085
- # A list of arguments that are handed to the sampler function, specified by `sampler`.
1086
- # The first argument handed to the sampler is `pspec`, the second argument is `qubit_labels`,
1087
- # and `samplerargs` lists the remaining arguments handed to the sampler. This is not
1088
- # optional for some choices of `sampler`.
1089
-
1090
- # addlocal : bool, optional
1091
- # Whether to follow each layer in the "core" circuits, sampled according to `sampler` with
1092
- # a layer of 1-qubit gates.
1093
-
1094
- # lsargs : list, optional
1095
- # Only used if addlocal is True. A list of optional arguments handed to the 1Q gate
1096
- # layer sampler circuit_layer_by_oneQgate(). Specifies how to sample 1Q-gate layers.
1097
-
1098
- # set_isolated : bool, optional
1099
- # Todo
1100
-
1101
- # setcomplement_isolated : bool, optional
1102
- # Todo
1103
-
1104
- # descriptor : str, optional
1105
- # A description of the experiment being generated. Stored in the output dictionary.
1106
-
1107
- # verbosity : int, optional
1108
- # If > 0 the number of circuits generated so far is shown.
1109
-
1110
- # Returns
1111
- # -------
1112
- # dict
1113
- # A dictionary containing the generated random circuits, the error-free outputs of the circuit,
1114
- # and the specification used to generate the circuits. The keys are:
1115
-
1116
- # - 'circuits'. A dictionary of the sampled circuits. The circuit with key(l,k) is the kth circuit
1117
- # at length l.
1118
-
1119
- # - 'probs'. A dictionary of the error-free *marginalized* probabilities for the "1" outcome of
1120
- # a computational basis measurement at the end of each circuit, with the standard input state.
1121
- # The ith element of this tuple corresponds to this probability for the qubit on the ith wire of
1122
- # the output circuit.
1123
-
1124
- # - 'qubitordering'. The ordering of the qubits in the 'target' tuples.
1125
-
1126
- # - 'spec'. A dictionary containing all of the parameters handed to this function, except `pspec`.
1127
- # This then specifies how the circuits where generated.
1128
- # """
1129
- # experiment_dict = {}
1130
- # experiment_dict['spec'] = {}
1131
- # experiment_dict['spec']['depths'] = depths
1132
- # experiment_dict['spec']['circuits_per_length'] = circuits_per_length
1133
- # experiment_dict['spec']['sampler'] = sampler
1134
- # experiment_dict['spec']['samplerargs'] = samplerargs
1135
- # experiment_dict['spec']['addlocal'] = addlocal
1136
- # experiment_dict['spec']['lsargs'] = lsargs
1137
- # experiment_dict['spec']['descriptor'] = descriptor
1138
- # experiment_dict['spec']['createdby'] = 'extras.rb.sample.simultaneous_random_circuits_experiment'
1139
-
1140
- # if isinstance(structure, str):
1141
- # assert(structure == '1Q'), "The only default `structure` option is the string '1Q'"
1142
- # structure = tuple([(q,) for q in pspec.qubit_labels])
1143
- # else:
1144
- # assert(isinstance(structure, list) or isinstance(structure, tuple)), \
1145
- # "If not a string, `structure` must be a list or tuple."
1146
- # qubits_used = []
1147
- # for qubit_labels in structure:
1148
- # assert(isinstance(qubit_labels, list) or isinstance(
1149
- # qubit_labels, tuple)), "SubsetQs must be a list or a tuple!"
1150
- # qubits_used = qubits_used + list(qubit_labels)
1151
- # assert(len(set(qubits_used)) == len(qubits_used)), \
1152
- # "The qubits in the tuples/lists of `structure must all be unique!"
1153
-
1154
- # assert(set(qubits_used).issubset(set(pspec.qubit_labels))), \
1155
- # "The qubits to benchmark must all be in the QubitProcessorSpec `pspec`!"
1156
-
1157
- # experiment_dict['spec']['structure'] = structure
1158
- # experiment_dict['circuits'] = {}
1159
- # experiment_dict['probs'] = {}
1160
- # experiment_dict['settings'] = {}
1161
-
1162
- # for lnum, l in enumerate(depths):
1163
- # if verbosity > 0:
1164
- # print('- Sampling {} circuits at length {} ({} of {} depths)'.format(circuits_per_length, l,
1165
- # lnum + 1, len(depths)))
1166
- # print(' - Number of circuits sampled = ', end='')
1167
- # for j in range(circuits_per_length):
1168
- # circuit, idealout = sample_simultaneous_random_circuit(pspec, l, structure=structure, sampler=sampler,
1169
- # samplerargs=samplerargs, addlocal=addlocal,
1170
- # lsargs=lsargs)
1171
-
1172
- # if (not set_isolated) and (not setcomplement_isolated):
1173
- # experiment_dict['circuits'][l, j] = circuit
1174
- # experiment_dict['probs'][l, j] = idealout
1175
- # experiment_dict['settings'][l, j] = {
1176
- # s: len(depths) + lnum * circuits_per_length + j for s in tuple(structure)}
1177
- # else:
1178
- # experiment_dict['circuits'][l, j] = {}
1179
- # experiment_dict['probs'][l, j] = {}
1180
- # experiment_dict['settings'][l, j] = {}
1181
- # experiment_dict['circuits'][l, j][tuple(structure)] = circuit
1182
- # experiment_dict['probs'][l, j][tuple(structure)] = idealout
1183
- # experiment_dict['settings'][l, j][tuple(structure)] = _get_setting(l, j, structure, depths,
1184
- # circuits_per_length, structure)
1185
- # if set_isolated:
1186
- # for subset_ind, subset in enumerate(structure):
1187
- # subset_circuit = circuit.copy(editable=True)
1188
- # #print(subset)
1189
- # for q in circuit.line_labels:
1190
- # if q not in subset:
1191
- # #print(subset_circuit, q)
1192
- # subset_circuit.replace_with_idling_line_inplace(q)
1193
- # subset_circuit.done_editing()
1194
- # experiment_dict['circuits'][l, j][(tuple(subset),)] = subset_circuit
1195
- # experiment_dict['probs'][l, j][(tuple(subset),)] = idealout[subset_ind]
1196
- # # setting = {}
1197
- # # for s in structure:
1198
- # # if s in subset:
1199
- # # setting[s] = len(depths) + lnum*circuits_per_length + j
1200
- # # else:
1201
- # # setting[s] = lnum
1202
- # experiment_dict['settings'][l, j][(tuple(subset),)] = _get_setting(l, j, (tuple(subset),), depths,
1203
- # circuits_per_length, structure)
1204
- # # print(subset)
1205
- # # print(_get_setting(l, j, subset, depths, circuits_per_length, structure))
1206
-
1207
- # if setcomplement_isolated:
1208
- # for subset_ind, subset in enumerate(structure):
1209
- # subsetcomplement_circuit = circuit.copy(editable=True)
1210
- # for q in circuit.line_labels:
1211
- # if q in subset:
1212
- # subsetcomplement_circuit.replace_with_idling_line_inplace(q)
1213
- # subsetcomplement_circuit.done_editing()
1214
- # subsetcomplement = list(_copy.copy(structure))
1215
- # subsetcomplement_idealout = list(_copy.copy(idealout))
1216
- # del subsetcomplement[subset_ind]
1217
- # del subsetcomplement_idealout[subset_ind]
1218
- # subsetcomplement = tuple(subsetcomplement)
1219
- # subsetcomplement_idealout = tuple(subsetcomplement_idealout)
1220
- # experiment_dict['circuits'][l, j][subsetcomplement] = subsetcomplement_circuit
1221
- # experiment_dict['probs'][l, j][subsetcomplement] = subsetcomplement_idealout
1222
-
1223
- # # for s in structure:
1224
- # # if s in subsetcomplement:
1225
- # # setting[s] = len(depths) + lnum*circuits_per_length + j
1226
- # # else:
1227
- # # setting[s] = lnum
1228
- # experiment_dict['settings'][l, j][subsetcomplement] = _get_setting(l, j, subsetcomplement, depths,
1229
- # circuits_per_length, structure)
1230
-
1231
- # if verbosity > 0: print(j + 1, end=',')
1232
- # if verbosity > 0: print('')
1233
-
1234
- # return experiment_dict
1235
-
1236
-
1237
- # def create_exhaustive_independent_random_circuits_experiment(pspec, allowed_depths, circuits_per_subset,
1238
- # structure='1Q',
1239
- # sampler='Qelimination', samplerargs=[], descriptor='',
1240
- # verbosity=1, seed=None):
1241
- # """
1242
- # Todo
1243
-
1244
- # Parameters
1245
- # ----------
1246
- # pspec : QubitProcessorSpec
1247
- # The QubitProcessorSpec for the device that the circuit is being sampled for, which defines the
1248
- # "native" gate-set and the connectivity of the device. The returned circuit will be over
1249
- # the gates in `pspec`, and will respect the connectivity encoded by `pspec`. Note that `pspec`
1250
- # is always handed to the sampler, as the first argument of the sampler function (this is only
1251
- # of importance when not using an in-built sampler).
1252
-
1253
- # allowed_depths : <TODO typ>
1254
- # <TODO description>
1255
-
1256
- # circuits_per_subset : <TODO typ>
1257
- # <TODO description>
1258
-
1259
- # structure : str or tuple.
1260
- # Defines the "structure" of the simultaneous circuit. TODO : more details.
1261
-
1262
- # sampler : str or function, optional
1263
- # If a string, this should be one of: {'pairingQs', 'Qelimination', 'co2Qgates', 'local'}.
1264
- # Except for 'local', this corresponds to sampling layers according to the sampling function
1265
- # in rb.sampler named circuit_layer_by* (with * replaced by 'sampler'). For 'local', this
1266
- # corresponds to sampling according to rb.sampler.circuit_layer_of_oneQgates.
1267
- # If `sampler` is a function, it should be a function that takes as the first argument a
1268
- # QubitProcessorSpec, and returns a random circuit layer as a list of gate Label objects. Note that
1269
- # the default 'Qelimination' is not necessarily the most useful in-built sampler, but it is the
1270
- # only sampler that requires no parameters beyond the QubitProcessorSpec *and* works for arbitrary
1271
- # connectivity devices. See the docstrings for each of these samplers for more information.
1272
-
1273
- # samplerargs : list, optional
1274
- # A list of arguments that are handed to the sampler function, specified by `sampler`.
1275
- # The first argument handed to the sampler is `pspec`, the second argument is `qubit_labels`,
1276
- # and `samplerargs` lists the remaining arguments handed to the sampler. This is not
1277
- # optional for some choices of `sampler`.
1278
-
1279
- # descriptor : str, optional
1280
- # A description of the experiment being generated. Stored in the output dictionary.
1281
-
1282
- # verbosity : int, optional
1283
- # How much output to sent to stdout.
1284
-
1285
- # seed : int, optional
1286
- # Seed for RNG
1287
-
1288
- # Returns
1289
- # -------
1290
- # dict
1291
- # """
1292
- # experiment_dict = {}
1293
- # experiment_dict['spec'] = {}
1294
- # experiment_dict['spec']['allowed_depths'] = allowed_depths
1295
- # experiment_dict['spec']['circuits_per_subset'] = circuits_per_subset
1296
- # experiment_dict['spec']['sampler'] = sampler
1297
- # experiment_dict['spec']['samplerargs'] = samplerargs
1298
- # experiment_dict['spec']['descriptor'] = descriptor
1299
-
1300
- # if isinstance(structure, str):
1301
- # assert(structure == '1Q'), "The only default `structure` option is the string '1Q'"
1302
- # structure = tuple([(q,) for q in pspec.qubit_labels])
1303
- # else:
1304
- # assert(isinstance(structure, list) or isinstance(structure, tuple)), \
1305
- # "If not a string, `structure` must be a list or tuple."
1306
- # qubits_used = []
1307
- # for qubit_labels in structure:
1308
- # assert(isinstance(qubit_labels, list) or isinstance(
1309
- # qubit_labels, tuple)), "SubsetQs must be a list or a tuple!"
1310
- # qubits_used = qubits_used + list(qubit_labels)
1311
- # assert(len(set(qubits_used)) == len(qubits_used)), \
1312
- # "The qubits in the tuples/lists of `structure must all be unique!"
1313
-
1314
- # assert(set(qubits_used).issubset(set(pspec.qubit_labels))), \
1315
- # "The qubits to benchmark must all be in the QubitProcessorSpec `pspec`!"
1316
-
1317
- # rand_state = _np.random.RandomState(seed) # OK if seed is None
1318
-
1319
- # experiment_dict['spec']['structure'] = structure
1320
- # experiment_dict['circuits'] = {}
1321
- # experiment_dict['probs'] = {}
1322
-
1323
- # if circuits_per_subset**len(structure) >> 10000:
1324
- # print("Warning: {} circuits are going to be generated by this function!".format(
1325
- # circuits_per_subset**len(structure)))
1326
-
1327
- # circuits = {}
1328
-
1329
- # for ssQs_ind, qubit_labels in enumerate(structure):
1330
- # circuits[qubit_labels] = []
1331
- # for i in range(circuits_per_subset):
1332
- # l = allowed_depths[rand_state.randint(len(allowed_depths))]
1333
- # circuits[qubit_labels].append(create_random_circuit(pspec, l, qubit_labels=qubit_labels,
1334
- # sampler=sampler, samplerargs=samplerargs))
1335
-
1336
- # experiment_dict['subset_circuits'] = circuits
1337
-
1338
- # parallel_circuits = {}
1339
- # it = [range(circuits_per_subset) for i in range(len(structure))]
1340
- # for setting_comb in _itertools.product(*it):
1341
- # pcircuit = _cir.Circuit(num_lines=0, editable=True)
1342
- # for ssQs_ind, qubit_labels in enumerate(structure):
1343
- # pcircuit.tensor_circuit_inplace(circuits[qubit_labels][setting_comb[ssQs_ind]])
1344
- # pcircuit.done_editing() # TIM: is this indented properly?
1345
- # parallel_circuits[setting_comb] = pcircuit
1346
-
1347
- # experiment_dict['circuits'] = parallel_circuits
1348
-
1349
- # return experiment_dict
1350
-
1351
778
 
1352
779
  def create_direct_rb_circuit(pspec, clifford_compilations, length, qubit_labels=None, sampler='Qelimination',
1353
780
  samplerargs=None, addlocal=False, lsargs=None, randomizeout=True, cliffordtwirl=True,
@@ -1578,568 +1005,130 @@ def create_direct_rb_circuit(pspec, clifford_compilations, length, qubit_labels=
1578
1005
 
1579
1006
  return outcircuit, idealout
1580
1007
 
1581
- #### Commented out as all of this functionality should be reproducable using simulataneous experiment designs applied
1582
- #### to DirectRB experiment designs.
1583
- # def sample_simultaneous_direct_rb_circuit(pspec, clifford_compilations, length, structure='1Q',
1584
- # sampler='Qelimination',
1585
- # samplerargs=[], addlocal=False, lsargs=[], randomizeout=True,
1586
- # cliffordtwirl=True, conditionaltwirl=True, citerations=20, compilerargs=[],
1587
- # partitioned=False, seed=1234):
1588
- # """
1589
- # Generates a simultaneous "direct randomized benchmarking" (DRB) circuit.
1590
-
1591
- # DRB is the protocol introduced in arXiv:1807.07975 (2018). An n-qubit DRB circuit consists of
1592
- # (1) a circuit the prepares a uniformly random stabilizer state; (2) a length-l circuit
1593
- # (specified by `length`) consisting of circuit layers sampled according to some user-specified
1594
- # distribution (specified by `sampler`), (3) a circuit that maps the output of the preceeding
1595
- # circuit to a computational basis state. See arXiv:1807.07975 (2018) for further details. Todo :
1596
- # what SDRB is.
1597
-
1598
- # Parameters
1599
- # ----------
1600
- # pspec : QubitProcessorSpec
1601
- # The QubitProcessorSpec for the device that the circuit is being sampled for, which defines the
1602
- # "native" gate-set and the connectivity of the device. The returned DRB circuit will be over
1603
- # the gates in `pspec`, and will respect the connectivity encoded by `pspec`. Note that `pspec`
1604
- # is always handed to the sampler, as the first argument of the sampler function (this is only
1605
- # of importance when not using an in-built sampler for the "core" of the DRB circuit). Unless
1606
- # `qubit_labels` is not None, the circuit is sampled over all the qubits in `pspec`.
1607
-
1608
- # clifford_compilations : dict
1609
- # A dictionary with the potential keys `'absolute'` and `'paulieq'` and corresponding
1610
- # :class:`CompilationRules` values. These compilation rules specify how to compile the
1611
- # "native" gates of `pspec` into Clifford gates.
1612
-
1613
- # length : int
1614
- # The "direct RB length" of the circuit, which is closely related to the circuit depth. It
1615
- # must be an integer >= 0. Unless `addlocal` is True, it is the depth of the "core" random
1616
- # circuit, sampled according to `sampler`, specified in step (2) above. If `addlocal` is True,
1617
- # each layer in the "core" circuit sampled according to "sampler` is followed by a layer of
1618
- # 1-qubit gates, with sampling specified by `lsargs` (and the first layer is proceeded by a
1619
- # layer of 1-qubit gates), and so the circuit of step (2) is length 2*`length` + 1.
1620
-
1621
- # structure : str or tuple, optional
1622
- # todo.
1623
-
1624
- # sampler : str or function, optional
1625
- # If a string, this should be one of: {'pairingQs', 'Qelimination', 'co2Qgates', 'local'}.
1626
- # Except for 'local', this corresponds to sampling layers according to the sampling function
1627
- # in rb.sampler named circuit_layer_by* (with * replaced by 'sampler'). For 'local', this
1628
- # corresponds to sampling according to rb.sampler.circuit_layer_of_oneQgates [which is not
1629
- # a valid form of sampling for n-qubit DRB, but is not explicitly forbidden in this function].
1630
- # If `sampler` is a function, it should be a function that takes as the first argument a
1631
- # QubitProcessorSpec, and returns a random circuit layer as a list of gate Label objects. Note that
1632
- # the default 'Qelimination' is not necessarily the most useful in-built sampler, but it is
1633
- # the only sampler that requires no parameters beyond the QubitProcessorSpec *and* works for arbitrary
1634
- # connectivity devices. See the docstrings for each of these samplers for more information.
1635
-
1636
- # samplerargs : list, optional
1637
- # A list of arguments that are handed to the sampler function, specified by `sampler`.
1638
- # The first argument handed to the sampler is `pspec`, the second argument is `qubit_labels`,
1639
- # and `samplerargs` lists the remaining arguments handed to the sampler. This is not
1640
- # optional for some choices of `sampler`.
1641
-
1642
- # addlocal : bool, optional
1643
- # Whether to follow each layer in the "core" circuit, sampled according to `sampler` with
1644
- # a layer of 1-qubit gates.
1645
-
1646
- # lsargs : list, optional
1647
- # Only used if addlocal is True. A list of optional arguments handed to the 1Q gate
1648
- # layer sampler circuit_layer_by_oneQgate(). Specifies how to sample 1Q-gate layers.
1649
-
1650
- # randomizeout : bool, optional
1651
- # If False, the ideal output of the circuit (the "success" or "survival" outcome) is the all-zeros
1652
- # bit string. If True, the ideal output of the circuit is randomized to a uniformly random bit-string.
1653
- # This setting is useful for, e.g., detecting leakage/loss/measurement-bias etc.
1654
-
1655
- # cliffordtwirl : bool, optional
1656
- # Wether to begin the circuit with a sequence that generates a random stabilizer state. For
1657
- # standard DRB this should be set to True. There are a variety of reasons why it is better
1658
- # to have this set to True.
1659
-
1660
- # conditionaltwirl : bool, optional
1661
- # DRB only requires that the initial/final sequences of step (1) and (3) create/measure
1662
- # a uniformly random / particular stabilizer state, rather than implement a particular unitary.
1663
- # step (1) and (3) can be achieved by implementing a uniformly random Clifford gate and the
1664
- # unique inversion Clifford, respectively. This is implemented if `conditionaltwirl` is False.
1665
- # However, steps (1) and (3) can be implemented much more efficiently than this: the sequences
1666
- # of (1) and (3) only need to map a particular input state to a particular output state,
1667
- # if `conditionaltwirl` is True this more efficient option is chosen -- this is option corresponds
1668
- # to "standard" DRB. (the term "conditional" refers to the fact that in this case we essentially
1669
- # implementing a particular Clifford conditional on a known input).
1670
-
1671
- # citerations : int, optional
1672
- # Some of the stabilizer state / Clifford compilation algorithms in pyGSTi (including the default
1673
- # algorithms) are randomized, and the lowest-cost circuit is chosen from all the circuit generated
1674
- # in the iterations of the algorithm. This is the number of iterations used. The time required to
1675
- # generate a DRB circuit is linear in `citerations`. Lower-depth / lower 2-qubit gate count
1676
- # compilations of steps (1) and (3) are important in order to successfully implement DRB on as many
1677
- # qubits as possible.
1678
-
1679
- # compilerargs : list, optional
1680
- # A list of arguments that are handed to the compile_stabilier_state/measurement()functions (or the
1681
- # compile_clifford() function if `conditionaltwirl `is False). This includes all the optional
1682
- # arguments of these functions *after* the `iterations` option (set by `citerations`). For most
1683
- # purposes the default options will be suitable (or at least near-optimal from the compilation methods
1684
- # in-built into pyGSTi). See the docstrings of these functions for more information.
1685
-
1686
- # partitioned : bool, optional
1687
- # If False, a single circuit is returned consisting of the full circuit. If True, three circuits
1688
- # are returned in a list consisting of: (1) the stabilizer-prep circuit, (2) the core random circuit,
1689
- # (3) the pre-measurement circuit. In that case the full circuit is obtained by appended (2) to (1)
1690
- # and then (3) to (1).
1691
-
1692
- # seed: int, optional
1693
- # Seed for RNG
1694
-
1695
- # Returns
1696
- # -------
1697
- # Circuit or list of Circuits
1698
- # If partioned is False, a random DRB circuit sampled as specified. If partioned is True, a list of
1699
- # three circuits consisting of (1) the stabilizer-prep circuit, (2) the core random circuit,
1700
- # (3) the pre-measurement circuit. In that case the full circuit is obtained by appended (2) to (1)
1701
- # and then (3) to (1) [except in the case of cliffordtwirl=False, when it is a list of two circuits].
1702
- # Tuple
1703
- # A length-n tuple of integers in [0,1], corresponding to the error-free outcome of the
1704
- # circuit. Always all zeros if `randomizeout` is False. The ith element of the tuple
1705
- # corresponds to the error-free outcome for the qubit labelled by: the ith element of
1706
- # `qubit_labels`, if `qubit_labels` is not None; the ith element of `pspec.qubit_labels`, otherwise.
1707
- # In both cases, the ith element of the tuple corresponds to the error-free outcome for the
1708
- # qubit on the ith wire of the output circuit.
1709
- # """
1710
- # if isinstance(structure, str):
1711
- # assert(structure == '1Q'), "The only default `structure` option is the string '1Q'"
1712
- # structure = tuple([(q,) for q in pspec.qubit_labels])
1713
- # n = pspec.num_qubits
1714
- # else:
1715
- # assert(isinstance(structure, list) or isinstance(structure, tuple)
1716
- # ), "If not a string, `structure` must be a list or tuple."
1717
- # qubits_used = []
1718
- # for qubit_labels in structure:
1719
- # assert(isinstance(qubit_labels, list) or isinstance(
1720
- # qubit_labels, tuple)), "SubsetQs must be a list or a tuple!"
1721
- # qubits_used = qubits_used + list(qubit_labels)
1722
- # assert(len(set(qubits_used)) == len(qubits_used)
1723
- # ), "The qubits in the tuples/lists of `structure must all be unique!"
1724
-
1725
- # assert(set(qubits_used).issubset(set(pspec.qubit_labels))
1726
- # ), "The qubits to benchmark must all be in the QubitProcessorSpec `pspec`!"
1727
- # n = len(qubits_used)
1728
-
1729
- # for qubit_labels in structure:
1730
- # subgraph = pspec.qubit_graph.subgraph(list(qubit_labels)) # or pspec.compute_clifford_2Q_connectivity?
1731
- # assert(subgraph.is_connected_graph()), "Each subset of qubits in `structure` must be connected!"
1732
-
1733
- # rand_state = _np.random.RandomState(seed) # OK if seed is None
1734
-
1735
- # # Creates a empty circuit over no wires
1736
- # circuit = _cir.Circuit(num_lines=0, editable=True)
1737
-
1738
- # s_rc_dict = {}
1739
- # p_rc_dict = {}
1740
- # circuit_dict = {}
1741
-
1742
- # for qubit_labels in structure:
1743
- # qubit_labels = tuple(qubit_labels)
1744
- # # Sample a random circuit of "native gates" over this set of qubits, with the
1745
- # # specified sampling.
1746
- # subset_circuit = create_random_circuit(pspec=pspec, length=length, qubit_labels=qubit_labels, sampler=sampler,
1747
- # samplerargs=samplerargs, addlocal=addlocal, lsargs=lsargs,
1748
- # rand_state=rand_state)
1749
- # circuit_dict[qubit_labels] = subset_circuit
1750
- # # find the symplectic matrix / phase vector this circuit implements.
1751
- # s_rc_dict[qubit_labels], p_rc_dict[qubit_labels] = _symp.symplectic_rep_of_clifford_circuit(
1752
- # subset_circuit, pspec=pspec)
1753
- # # Tensors this circuit with the current circuit
1754
- # circuit.tensor_circuit_inplace(subset_circuit)
1755
-
1756
- # # Creates empty circuits over no wires
1757
- # inversion_circuit = _cir.Circuit(num_lines=0, editable=True)
1758
- # if cliffordtwirl:
1759
- # initial_circuit = _cir.Circuit(num_lines=0, editable=True)
1760
-
1761
- # for qubit_labels in structure:
1762
- # qubit_labels = tuple(qubit_labels)
1763
- # subset_n = len(qubit_labels)
1764
- # # If we are clifford twirling, we do an initial random circuit that is either a uniformly random
1765
- # # cliffor or creates a uniformly random stabilizer state from the standard input.
1766
- # if cliffordtwirl:
1767
-
1768
- # # Sample a uniformly random Clifford.
1769
- # s_initial, p_initial = _symp.random_clifford(subset_n, rand_state=rand_state)
1770
- # # Find the composite action of this uniformly random clifford and the random circuit.
1771
- # s_composite, p_composite = _symp.compose_cliffords(s_initial, p_initial, s_rc_dict[qubit_labels],
1772
- # p_rc_dict[qubit_labels])
1773
-
1774
- # # If conditionaltwirl we do a stabilizer prep (a conditional Clifford).
1775
- # if conditionaltwirl:
1776
- # subset_initial_circuit = _cmpl.compile_stabilizer_state(s_initial, p_initial, pspec,
1777
- # clifford_compilations.get('absolute', None),
1778
- # clifford_compilations.get('paulieq', None),
1779
- # qubit_labels,
1780
- # citerations, *compilerargs,
1781
- # rand_state=rand_state)
1782
- # # If not conditionaltwirl, we do a full random Clifford.
1783
- # else:
1784
- # subset_initial_circuit = _cmpl.compile_clifford(s_initial, p_initial, pspec,
1785
- # clifford_compilations.get('absolute', None),
1786
- # clifford_compilations.get('paulieq', None),
1787
- # qubit_labels, citerations,
1788
- # *compilerargs, rand_state=rand_state)
1789
-
1790
- # initial_circuit.tensor_circuit_inplace(subset_initial_circuit)
1791
-
1792
- # # If we are not Clifford twirling, we just copy the effect of the random circuit as the effect
1793
- # # of the "composite" prep + random circuit (as here the prep circuit is the null circuit).
1794
- # else:
1795
- # s_composite = _copy.deepcopy(s_rc_dict[qubit_labels])
1796
- # p_composite = _copy.deepcopy(p_rc_dict[qubit_labels])
1797
-
1798
- # if conditionaltwirl:
1799
- # # If we want to randomize the expected output then randomize the p vector, otherwise
1800
- # # it is left as p. Note that, unlike with compile_clifford, we don't invert (s,p)
1801
- # # before handing it to the stabilizer measurement function.
1802
- # if randomizeout: p_for_measurement = _symp.random_phase_vector(s_composite, subset_n,
1803
- # rand_state=rand_state)
1804
- # else: p_for_measurement = p_composite
1805
- # subset_inversion_circuit = _cmpl.compile_stabilizer_measurement(
1806
- # s_composite, p_for_measurement, pspec,
1807
- # clifford_compilations.get('absolute', None),
1808
- # clifford_compilations.get('paulieq', None),
1809
- # qubit_labels, citerations, *compilerargs,
1810
- # rand_state=rand_state)
1811
- # else:
1812
- # # Find the Clifford that inverts the circuit so far. We
1813
- # s_inverse, p_inverse = _symp.inverse_clifford(s_composite, p_composite)
1814
- # # If we want to randomize the expected output then randomize the p_inverse vector, otherwise
1815
- # # do not.
1816
- # if randomizeout: p_for_inversion = _symp.random_phase_vector(s_inverse, subset_n, rand_state=rand_state)
1817
- # else: p_for_inversion = p_inverse
1818
- # # Compile the Clifford.
1819
- # subset_inversion_circuit = _cmpl.compile_clifford(s_inverse, p_for_inversion, pspec,
1820
- # clifford_compilations.get('absolute', None),
1821
- # clifford_compilations.get('paulieq', None),
1822
- # qubit_labels, citerations, *compilerargs,
1823
- # rand_state=rand_state)
1824
-
1825
- # inversion_circuit.tensor_circuit_inplace(subset_inversion_circuit)
1826
-
1827
- # inversion_circuit.done_editing()
1828
-
1829
- # if cliffordtwirl:
1830
- # full_circuit = initial_circuit.copy(editable=True)
1831
- # full_circuit.append_circuit_inplace(circuit)
1832
- # full_circuit.append_circuit_inplace(inversion_circuit)
1833
- # else:
1834
- # full_circuit = _copy.deepcopy(circuit)
1835
- # full_circuit.append_circuit_inplace(inversion_circuit)
1836
-
1837
- # full_circuit.done_editing()
1838
-
1839
- # # Find the expected outcome of the circuit.
1840
- # s_out, p_out = _symp.symplectic_rep_of_clifford_circuit(full_circuit, pspec=pspec)
1841
- # if conditionaltwirl: # s_out is not always the identity with a conditional twirl,
1842
- # # only conditional on prep/measure.
1843
- # assert(_np.array_equal(s_out[:n, n:], _np.zeros((n, n), _np.int64))), "Compiler has failed!"
1844
- # else: assert(_np.array_equal(s_out, _np.identity(2 * n, _np.int64))), "Compiler has failed!"
1845
-
1846
- # # Find the ideal output of the circuit.
1847
- # s_inputstate, p_inputstate = _symp.prep_stabilizer_state(n, zvals=None)
1848
- # s_outstate, p_outstate = _symp.apply_clifford_to_stabilizer_state(s_out, p_out, s_inputstate, p_inputstate)
1849
- # idealout = []
1850
- # for qubit_labels in structure:
1851
- # subset_idealout = []
1852
- # for q in qubit_labels:
1853
- # qind = circuit.line_labels.index(q)
1854
- # measurement_out = _symp.pauli_z_measurement(s_outstate, p_outstate, qind)
1855
- # bit = measurement_out[1]
1856
- # assert(bit == 0 or bit == 1), "Ideal output is not a computational basis state!"
1857
- # if not randomizeout:
1858
- # assert(bit == 0), "Ideal output is not the all 0s computational basis state!"
1859
- # subset_idealout.append(int(bit))
1860
- # idealout.append(tuple(subset_idealout))
1861
- # idealout = tuple(idealout)
1862
-
1863
- # if not partitioned: outcircuit = full_circuit
1864
- # else:
1865
- # if cliffordtwirl: outcircuit = [initial_circuit, circuit, inversion_circuit]
1866
- # else: outcircuit = [circuit, inversion_circuit]
1867
-
1868
- # return outcircuit, idealout
1869
-
1870
-
1871
- # def create_simultaneous_direct_rb_experiment(pspec, depths, circuits_per_length, structure='1Q',
1872
- # sampler='Qelimination',
1873
- # samplerargs=[], addlocal=False, lsargs=[], randomizeout=False,
1874
- # cliffordtwirl=True, conditionaltwirl=True, citerations=20,
1875
- # compilerargs=[],
1876
- # partitioned=False, set_isolated=True, setcomplement_isolated=False,
1877
- # descriptor='A set of simultaneous DRB experiments', verbosity=1,
1878
- # seed=1234):
1879
- # """
1880
- # Generates a simultaneous "direct randomized benchmarking" (DRB) experiments (circuits).
1881
-
1882
- # DRB is the protocol introduced in arXiv:1807.07975 (2018).
1883
- # An n-qubit DRB circuit consists of (1) a circuit the prepares a uniformly random stabilizer state;
1884
- # (2) a length-l circuit (specified by `length`) consisting of circuit layers sampled according to
1885
- # some user-specified distribution (specified by `sampler`), (3) a circuit that maps the output of
1886
- # the preceeding circuit to a computational basis state. See arXiv:1807.07975 (2018) for further
1887
- # details. In simultaneous DRB ...... <TODO more description>.
1888
-
1889
- # Parameters
1890
- # ----------
1891
- # pspec : QubitProcessorSpec
1892
- # The QubitProcessorSpec for the device that the circuit is being sampled for, which defines the
1893
- # "native" gate-set and the connectivity of the device. The returned DRB circuit will be over
1894
- # the gates in `pspec`, and will respect the connectivity encoded by `pspec`. Note that `pspec`
1895
- # is always handed to the sampler, as the first argument of the sampler function (this is only
1896
- # of importance when not using an in-built sampler for the "core" of the DRB circuit). Unless
1897
- # `qubit_labels` is not None, the circuit is sampled over all the qubits in `pspec`.
1898
-
1899
- # depths : int
1900
- # The set of "direct RB depths" for the circuits. The DRB depths must be integers >= 0.
1901
- # Unless `addlocal` is True, the DRB length is the depth of the "core" random circuit,
1902
- # sampled according to `sampler`, specified in step (2) above. If `addlocal` is True,
1903
- # each layer in the "core" circuit sampled according to "sampler` is followed by a layer of
1904
- # 1-qubit gates, with sampling specified by `lsargs` (and the first layer is proceeded by a
1905
- # layer of 1-qubit gates), and so the circuit of step (2) is length 2*`length` + 1.
1906
-
1907
- # circuits_per_length : int
1908
- # The number of (possibly) different DRB circuits sampled at each length.
1909
-
1910
- # structure : str or tuple.
1911
- # Defines the "structure" of the simultaneous DRB experiment. TODO : more details.
1912
-
1913
- # sampler : str or function, optional
1914
- # If a string, this should be one of: {'pairingQs', 'Qelimination', 'co2Qgates', 'local'}.
1915
- # Except for 'local', this corresponds to sampling layers according to the sampling function
1916
- # in rb.sampler named circuit_layer_by* (with * replaced by 'sampler'). For 'local', this
1917
- # corresponds to sampling according to rb.sampler.circuit_layer_of_oneQgates [which is not
1918
- # a valid form of sampling for n-qubit DRB, but is not explicitly forbidden in this function].
1919
- # If `sampler` is a function, it should be a function that takes as the first argument a
1920
- # QubitProcessorSpec, and returns a random circuit layer as a list of gate Label objects. Note that
1921
- # the default 'Qelimination' is not necessarily the most useful in-built sampler, but it is the
1922
- # only sampler that requires no parameters beyond the QubitProcessorSpec *and* works for arbitrary
1923
- # connectivity devices. See the docstrings for each of these samplers for more information.
1924
-
1925
- # samplerargs : list, optional
1926
- # A list of arguments that are handed to the sampler function, specified by `sampler`.
1927
- # The first argument handed to the sampler is `pspec`, the second argument is `qubit_labels`,
1928
- # and `samplerargs` lists the remaining arguments handed to the sampler. This is not
1929
- # optional for some choices of `sampler`.
1930
-
1931
- # addlocal : bool, optional
1932
- # Whether to follow each layer in the "core" circuits, sampled according to `sampler` with
1933
- # a layer of 1-qubit gates.
1934
-
1935
- # lsargs : list, optional
1936
- # Only used if addlocal is True. A list of optional arguments handed to the 1Q gate
1937
- # layer sampler circuit_layer_by_oneQgate(). Specifies how to sample 1Q-gate layers.
1938
-
1939
- # randomizeout : bool, optional
1940
- # If False, the ideal output of the circuits (the "success" or "survival" outcome) is the all-zeros
1941
- # bit string. If True, the ideal output of each circuit is randomized to a uniformly random bit-string.
1942
- # This setting is useful for, e.g., detecting leakage/loss/measurement-bias etc.
1943
-
1944
- # cliffordtwirl : bool, optional
1945
- # Wether to begin the circuit with a sequence that generates a random stabilizer state. For
1946
- # standard DRB this should be set to True. There are a variety of reasons why it is better
1947
- # to have this set to True.
1948
-
1949
- # conditionaltwirl : bool, optional
1950
- # DRB only requires that the initial/final sequences of step (1) and (3) create/measure
1951
- # a uniformly random / particular stabilizer state, rather than implement a particular unitary.
1952
- # step (1) and (3) can be achieved by implementing a uniformly random Clifford gate and the
1953
- # unique inversion Clifford, respectively. This is implemented if `conditionaltwirl` is False.
1954
- # However, steps (1) and (3) can be implemented much more efficiently than this: the sequences
1955
- # of (1) and (3) only need to map a particular input state to a particular output state,
1956
- # if `conditionaltwirl` is True this more efficient option is chosen -- this is option corresponds
1957
- # to "standard" DRB. (the term "conditional" refers to the fact that in this case we essentially
1958
- # implementing a particular Clifford conditional on a known input).
1959
-
1960
- # citerations : int, optional
1961
- # Some of the stabilizer state / Clifford compilation algorithms in pyGSTi (including the default
1962
- # algorithms) are randomized, and the lowest-cost circuit is chosen from all the circuits generated
1963
- # in the iterations of the algorithm. This is the number of iterations used. The time required to
1964
- # generate a DRB circuit is linear in `citerations`. Lower-depth / lower 2-qubit gate count
1965
- # compilations of steps (1) and (3) are important in order to successfully implement DRB on as many
1966
- # qubits as possible.
1967
-
1968
- # compilerargs : list, optional
1969
- # A list of arguments that are handed to the compile_stabilier_state/measurement()functions (or the
1970
- # compile_clifford() function if `conditionaltwirl `is False). This includes all the optional
1971
- # arguments of these functions *after* the `iterations` option (set by `citerations`). For most
1972
- # purposes the default options will be suitable (or at least near-optimal from the compilation methods
1973
- # in-built into pyGSTi). See the docstrings of these functions for more information.
1974
-
1975
- # partitioned : bool, optional
1976
- # If False, each circuit is returned as a single full circuit. If True, each circuit is returned as
1977
- # a list of three circuits consisting of: (1) the stabilizer-prep circuit, (2) the core random circuit,
1978
- # (3) the pre-measurement circuit. In that case the full circuit is obtained by appended (2) to (1)
1979
- # and then (3) to (1).
1980
-
1981
- # set_isolated : bool, optional
1982
- # Todo
1983
-
1984
- # setcomplement_isolated : bool, optional
1985
- # Todo
1986
-
1987
- # descriptor : str, optional
1988
- # A description of the experiment being generated. Stored in the output dictionary.
1989
-
1990
- # verbosity : int, optional
1991
- # If > 0 the number of circuits generated so far is shown.
1992
-
1993
- # seed: int, optional
1994
- # Seed for RNG
1995
-
1996
- # Returns
1997
- # -------
1998
- # Circuit or list of Circuits
1999
- # If partioned is False, a random DRB circuit sampled as specified. If partioned is True, a list of
2000
- # three circuits consisting of (1) the stabilizer-prep circuit, (2) the core random circuit,
2001
- # (3) the pre-measurement circuit. In that case the full circuit is obtained by appended (2) to (1)
2002
- # and then (3) to (1).
2003
- # Tuple
2004
- # A length-n tuple of integers in [0,1], corresponding to the error-free outcome of the
2005
- # circuit. Always all zeros if `randomizeout` is False. The ith element of the tuple
2006
- # corresponds to the error-free outcome for the qubit labelled by: the ith element of
2007
- # `qubit_labels`, if `qubit_labels` is not None; the ith element of `pspec.qubit_labels`, otherwise.
2008
- # In both cases, the ith element of the tuple corresponds to the error-free outcome for the
2009
- # qubit on the ith wire of the output circuit.
2010
- # dict
2011
- # A dictionary containing the generated RB circuits, the error-free outputs of the circuit,
2012
- # and the specification used to generate the circuits. The keys are:
2013
-
2014
- # - 'circuits'. A dictionary of the sampled circuits. The circuit with key(l,k) is the kth circuit
2015
- # at DRB length l.
2016
-
2017
- # - 'idealout'. A dictionary of the error-free outputs of the circuits as tuples. The tuple with
2018
- # key(l,k) is the error-free output of the (l,k) circuit. The ith element of this tuple corresponds
2019
- # to the error-free outcome for the qubit on the ith wire of the output circuit and/or the ith element
2020
- # of the list at the key 'qubitordering'. These tuples will all be (0,0,0,...) when `randomizeout` is
2021
- # False
2022
-
2023
- # - 'qubitordering'. The ordering of the qubits in the 'idealout' tuples.
2024
-
2025
- # - 'spec'. A dictionary containing all of the parameters handed to this function, except `pspec`.
2026
- # This then specifies how the circuits where generated.
2027
- # """
2028
-
2029
- # experiment_dict = {}
2030
- # experiment_dict['spec'] = {}
2031
- # experiment_dict['spec']['depths'] = depths
2032
- # experiment_dict['spec']['circuits_per_length'] = circuits_per_length
2033
- # experiment_dict['spec']['sampler'] = sampler
2034
- # experiment_dict['spec']['samplerargs'] = samplerargs
2035
- # experiment_dict['spec']['addlocal'] = addlocal
2036
- # experiment_dict['spec']['lsargs'] = lsargs
2037
- # experiment_dict['spec']['randomizeout'] = randomizeout
2038
- # experiment_dict['spec']['cliffordtwirl'] = cliffordtwirl
2039
- # experiment_dict['spec']['conditionaltwirl'] = conditionaltwirl
2040
- # experiment_dict['spec']['citerations'] = citerations
2041
- # experiment_dict['spec']['compilerargs'] = compilerargs
2042
- # experiment_dict['spec']['partitioned'] = partitioned
2043
- # experiment_dict['spec']['descriptor'] = descriptor
2044
- # experiment_dict['spec']['createdby'] = 'extras.rb.sample.simultaneous_direct_rb_experiment'
2045
-
2046
- # #rand_state = _np.random.RandomState(seed) # OK if seed is None
2047
-
2048
- # if isinstance(structure, str):
2049
- # assert(structure == '1Q'), "The only default `structure` option is the string '1Q'"
2050
- # structure = tuple([(q,) for q in pspec.qubit_labels])
2051
- # else:
2052
- # assert(isinstance(structure, list) or isinstance(structure, tuple)), \
2053
- # "If not a string, `structure` must be a list or tuple."
2054
- # qubits_used = []
2055
- # for qubit_labels in structure:
2056
- # assert(isinstance(qubit_labels, list) or isinstance(
2057
- # qubit_labels, tuple)), "SubsetQs must be a list or a tuple!"
2058
- # qubits_used = qubits_used + list(qubit_labels)
2059
- # assert(len(set(qubits_used)) == len(qubits_used)), \
2060
- # "The qubits in the tuples/lists of `structure must all be unique!"
2061
-
2062
- # assert(set(qubits_used).issubset(set(pspec.qubit_labels))), \
2063
- # "The qubits to benchmark must all be in the QubitProcessorSpec `pspec`!"
2064
-
2065
- # experiment_dict['spec']['structure'] = structure
2066
- # experiment_dict['circuits'] = {}
2067
- # experiment_dict['target'] = {}
2068
- # experiment_dict['settings'] = {}
2069
-
2070
- # for qubit_labels in structure:
2071
- # subgraph = pspec.qubit_graph.subgraph(list(qubit_labels)) # or pspec.compute_clifford_2Q_connectivity?
2072
- # assert(subgraph.is_connected_graph()), "Each subset of qubits in `structure` must be connected!"
2073
-
2074
- # for lnum, l in enumerate(depths):
2075
- # lseed = seed + lnum * circuits_per_length
2076
- # if verbosity > 0:
2077
- # print('- Sampling {} circuits at DRB length {} ({} of {} depths) with seed {}'.format(circuits_per_length,
2078
- # l, lnum + 1,
2079
- # len(depths), lseed))
2080
- # print(' - Number of circuits sampled = ', end='')
2081
- # for j in range(circuits_per_length):
2082
- # circuit, idealout = sample_simultaneous_direct_rb_circuit(pspec, l, structure=structure, sampler=sampler,
2083
- # samplerargs=samplerargs, addlocal=addlocal,
2084
- # lsargs=lsargs, randomizeout=randomizeout,
2085
- # cliffordtwirl=cliffordtwirl,
2086
- # conditionaltwirl=conditionaltwirl,
2087
- # citerations=citerations,
2088
- # compilerargs=compilerargs,
2089
- # partitioned=partitioned,
2090
- # seed=lseed + j)
2091
-
2092
- # if (not set_isolated) and (not setcomplement_isolated):
2093
- # experiment_dict['circuits'][l, j] = circuit
2094
- # experiment_dict['target'][l, j] = idealout
2095
-
2096
- # else:
2097
- # experiment_dict['circuits'][l, j] = {}
2098
- # experiment_dict['target'][l, j] = {}
2099
- # experiment_dict['settings'][l, j] = {}
2100
- # experiment_dict['circuits'][l, j][tuple(structure)] = circuit
2101
- # experiment_dict['target'][l, j][tuple(structure)] = idealout
2102
- # experiment_dict['settings'][l, j][tuple(structure)] = _get_setting(l, j, structure, depths,
2103
- # circuits_per_length, structure)
2104
-
2105
- # if set_isolated:
2106
- # for subset_ind, subset in enumerate(structure):
2107
- # subset_circuit = circuit.copy(editable=True)
2108
- # for q in circuit.line_labels:
2109
- # if q not in subset:
2110
- # subset_circuit.replace_with_idling_line_inplace(q)
2111
- # subset_circuit.done_editing()
2112
- # experiment_dict['circuits'][l, j][(tuple(subset),)] = subset_circuit
2113
- # experiment_dict['target'][l, j][(tuple(subset),)] = (idealout[subset_ind],)
2114
- # experiment_dict['settings'][l, j][(tuple(subset),)] = _get_setting(l, j, (tuple(subset),), depths,
2115
- # circuits_per_length, structure)
2116
-
2117
- # if setcomplement_isolated:
2118
- # for subset_ind, subset in enumerate(structure):
2119
- # subsetcomplement_circuit = circuit.copy(editable=True)
2120
- # for q in circuit.line_labels:
2121
- # if q in subset:
2122
- # subsetcomplement_circuit.replace_with_idling_line_inplace(q)
2123
- # subsetcomplement_circuit.done_editing()
2124
- # subsetcomplement = list(_copy.copy(structure))
2125
- # subsetcomplement_idealout = list(_copy.copy(idealout))
2126
- # del subsetcomplement[subset_ind]
2127
- # del subsetcomplement_idealout[subset_ind]
2128
- # subsetcomplement = tuple(subsetcomplement)
2129
- # subsetcomplement_idealout = tuple(subsetcomplement_idealout)
2130
- # experiment_dict['circuits'][l, j][subsetcomplement] = subsetcomplement_circuit
2131
- # experiment_dict['target'][l, j][subsetcomplement] = subsetcomplement_idealout
2132
- # experiment_dict['settings'][l, j][subsetcomplement] = _get_setting(l, j, subsetcomplement, depths,
2133
- # circuits_per_length, structure)
2134
-
2135
- # if verbosity > 0: print(j + 1, end=',')
2136
- # if verbosity > 0: print('')
2137
-
2138
- # return experiment_dict
1008
+
1009
+ def _sample_clifford_circuit(pspec, clifford_compilations, qubit_labels, citerations,
1010
+ compilerargs, exact_compilation_key, srep_cache, rand_state):
1011
+ """Helper function to compile a random Clifford circuit.
1012
+
1013
+ Parameters
1014
+ ----------
1015
+ pspec : QubitProcessorSpec
1016
+ The QubitProcessorSpec for the device that the circuit is being sampled for, which defines the
1017
+ "native" gate-set and the connectivity of the device. The returned CRB circuit will be over
1018
+ the gates in `pspec`, and will respect the connectivity encoded by `pspec`.
1019
+
1020
+ clifford_compilations : dict
1021
+ A dictionary with at least the potential keys `'absolute'` and `'paulieq'` and corresponding
1022
+ :class:`CompilationRules` values. These compilation rules specify how to compile the
1023
+ "native" gates of `pspec` into Clifford gates. Additional :class:`CompilationRules` can be
1024
+ provided, particularly for use with `exact_compilation_key`.
1025
+
1026
+ qubit_labels : list
1027
+ A list of the qubits that the RB circuit is to be sampled for.
1028
+
1029
+ citerations : int
1030
+ Some of the Clifford compilation algorithms in pyGSTi (including the default algorithm) are
1031
+ randomized, and the lowest-cost circuit is chosen from all the circuit generated in the
1032
+ iterations of the algorithm. This is the number of iterations used. The time required to
1033
+ generate a CRB circuit is linear in `citerations` * (`length` + 2). Lower-depth / lower 2-qubit
1034
+ gate count compilations of the Cliffords are important in order to successfully implement
1035
+ CRB on more qubits.
1036
+
1037
+ compilerargs : list
1038
+ A list of arguments that are handed to compile_clifford() function, which includes all the
1039
+ optional arguments of compile_clifford() *after* the `iterations` option (set by `citerations`).
1040
+ In order, this list should be values for:
1041
+
1042
+ algorithm : str. A string that specifies the compilation algorithm. The default in
1043
+ compile_clifford() will always be whatever we consider to be the 'best' all-round
1044
+ algorithm
1045
+
1046
+ aargs : list. A list of optional arguments for the particular compilation algorithm.
1047
+
1048
+ costfunction : 'str' or function. The cost-function from which the "best" compilation
1049
+ for a Clifford is chosen from all `citerations` compilations. The default costs a
1050
+ circuit as 10x the num. of 2-qubit gates in the circuit + 1x the depth of the circuit.
1051
+
1052
+ prefixpaulis : bool. Whether to prefix or append the Paulis on each Clifford.
1053
+
1054
+ paulirandomize : bool. Whether to follow each layer in the Clifford circuit with a
1055
+ random Pauli on each qubit (compiled into native gates). I.e., if this is True the
1056
+ native gates are Pauli-randomized. When True, this prevents any coherent errors adding
1057
+ (on average) inside the layers of each compiled Clifford, at the cost of increased
1058
+ circuit depth. Defaults to False.
1059
+
1060
+ For more information on these options, see the `:func:compile_clifford()` docstring.
1061
+
1062
+ exact_compilation_key: str, optional
1063
+ The key into `clifford_compilations` to use for exact deterministic complation of Cliffords.
1064
+ The underlying :class:`CompilationRules` object must provide compilations for all possible
1065
+ n-qubit Cliffords that will be generated. This also requires the pspec is able to generate the
1066
+ symplectic representations for all n-qubit Cliffords in :meth:`compute_clifford_symplectic_reps`.
1067
+ This is currently generally intended for use out-of-the-box with 1-qubit Clifford RB;
1068
+ however, larger number of qubits can be used so long as the user specifies the processor spec and
1069
+ compilation rules properly.
1070
+
1071
+ srep_cache: dict
1072
+ Keys are gate labels and values are precomputed symplectic representations.
1073
+
1074
+ rand_state: np.random.RandomState
1075
+ A RandomState to use for RNG
1076
+
1077
+ Returns
1078
+ -------
1079
+ clifford_circuit : Circuit
1080
+ The compiled Clifford circuit
1081
+
1082
+ s:
1083
+ The symplectic matrix of the Clifford
1084
+
1085
+ p:
1086
+ The symplectic phase vector of the Clifford
1087
+ """
1088
+ # Find the labels of the qubits to create the circuit for.
1089
+ if qubit_labels is not None: qubits = qubit_labels[:] # copy this list
1090
+ else: qubits = pspec.qubit_labels[:] # copy this list
1091
+ # The number of qubits the circuit is over.
1092
+ n = len(qubits)
1093
+
1094
+ if exact_compilation_key is not None:
1095
+ # Deterministic compilation based on a provided clifford compilation
1096
+ assert exact_compilation_key in clifford_compilations, \
1097
+ f"{exact_compilation_key} not provided in `clifford_compilations`"
1098
+
1099
+ # Pick clifford
1100
+ cidx = rand_state.randint(_symp.compute_num_cliffords(n))
1101
+ lbl = _lbl.Label(f'C{cidx}', qubits)
1102
+
1103
+ # Try to do deterministic compilation
1104
+ try:
1105
+ circuit = clifford_compilations[exact_compilation_key].retrieve_compilation_of(lbl)
1106
+ except AssertionError:
1107
+ raise ValueError(
1108
+ f"Failed to compile n-qubit Clifford 'C{cidx}'. Ensure this is provided in the " + \
1109
+ "compilation rules, or use a compilation algorithm to synthesize it by not " + \
1110
+ "specifying `exact_compilation_key`."
1111
+ )
1112
+
1113
+ # compute the symplectic rep of the chosen clifford
1114
+ # TODO: Note that this is inefficient. For speed, we could implement the pair to
1115
+ # _symp.compute_symplectic_matrix and just calculate s and p directly
1116
+ s, p = _symp.symplectic_rep_of_clifford_circuit(circuit, srep_cache)
1117
+ else:
1118
+ # Random compilation
1119
+ s, p = _symp.random_clifford(n, rand_state=rand_state)
1120
+ circuit = _cmpl.compile_clifford(s, p, pspec,
1121
+ clifford_compilations.get('absolute', None),
1122
+ clifford_compilations.get('paulieq', None),
1123
+ qubit_labels=qubit_labels, iterations=citerations, *compilerargs,
1124
+ rand_state=rand_state)
1125
+
1126
+ return circuit, s, p
2139
1127
 
2140
1128
 
2141
1129
  def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_labels=None, randomizeout=False,
2142
- citerations=20, compilerargs=None, interleaved_circuit=None, seed=None):
1130
+ citerations=20, compilerargs=None, interleaved_circuit=None, seed=None,
1131
+ return_native_gate_counts=False, exact_compilation_key=None):
2143
1132
  """
2144
1133
  Generates a "Clifford randomized benchmarking" (CRB) circuit.
2145
1134
 
@@ -2165,9 +1154,10 @@ def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_label
2165
1154
  the gates in `pspec`, and will respect the connectivity encoded by `pspec`.
2166
1155
 
2167
1156
  clifford_compilations : dict
2168
- A dictionary with the potential keys `'absolute'` and `'paulieq'` and corresponding
1157
+ A dictionary with at least the potential keys `'absolute'` and `'paulieq'` and corresponding
2169
1158
  :class:`CompilationRules` values. These compilation rules specify how to compile the
2170
- "native" gates of `pspec` into Clifford gates.
1159
+ "native" gates of `pspec` into Clifford gates. Additional :class:`CompilationRules` can be
1160
+ provided, particularly for use with `exact_compilation_key`.
2171
1161
 
2172
1162
  length : int
2173
1163
  The "CRB length" of the circuit -- an integer >= 0 -- which is the number of Cliffords in the
@@ -2223,6 +1213,18 @@ def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_label
2223
1213
  seed : int, optional
2224
1214
  A seed to initialize the random number generator used for creating random clifford
2225
1215
  circuits.
1216
+
1217
+ return_native_gate_counts: bool, optional
1218
+ Whether to return the number of native gates in the first `length`+1 compiled Cliffords
1219
+
1220
+ exact_compilation_key: str, optional
1221
+ The key into `clifford_compilations` to use for exact deterministic complation of Cliffords.
1222
+ The underlying :class:`CompilationRules` object must provide compilations for all possible
1223
+ n-qubit Cliffords that will be generated. This also requires the pspec is able to generate the
1224
+ symplectic representations for all n-qubit Cliffords in :meth:`compute_clifford_symplectic_reps`.
1225
+ This is currently generally intended for use out-of-the-box with 1-qubit Clifford RB;
1226
+ however, larger number of qubits can be used so long as the user specifies the processor spec and
1227
+ compilation rules properly.
2226
1228
 
2227
1229
  Returns
2228
1230
  -------
@@ -2236,6 +1238,10 @@ def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_label
2236
1238
  `qubit_labels`, if `qubit_labels` is not None; the ith element of `pspec.qubit_labels`, otherwise.
2237
1239
  In both cases, the ith element of the tuple corresponds to the error-free outcome for the
2238
1240
  qubit on the ith wire of the output circuit.
1241
+
1242
+ native_gate_counts: dict
1243
+ Total number of native gates, native 2q gates, and native circuit size in the
1244
+ first `length`+1 compiled Cliffords. Only returned when `return_num_native_gates` is True
2239
1245
  """
2240
1246
  if compilerargs is None:
2241
1247
  compilerargs = []
@@ -2245,6 +1251,12 @@ def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_label
2245
1251
  # The number of qubits the circuit is over.
2246
1252
  n = len(qubits)
2247
1253
 
1254
+ srep_cache = {}
1255
+ if exact_compilation_key is not None:
1256
+ # Precompute some of the symplectic reps if we are doing exact compilation
1257
+ srep_cache = _symp.compute_internal_gate_symplectic_representations()
1258
+ srep_cache.update(pspec.compute_clifford_symplectic_reps())
1259
+
2248
1260
  rand_state = _np.random.RandomState(seed) # OK if seed is None
2249
1261
 
2250
1262
  # Initialize the identity circuit rep.
@@ -2255,14 +1267,17 @@ def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_label
2255
1267
 
2256
1268
  # Sample length+1 uniformly random Cliffords (we want a circuit of length+2 Cliffords, in total), compile
2257
1269
  # them, and append them to the current circuit.
2258
- for i in range(0, length + 1):
1270
+ num_native_gates = 0
1271
+ num_native_2q_gates = 0
1272
+ native_size = 0
1273
+ for _ in range(0, length + 1):
1274
+ # Perform sampling
1275
+ circuit, s, p = _sample_clifford_circuit(pspec, clifford_compilations, qubit_labels, citerations,
1276
+ compilerargs, exact_compilation_key, srep_cache, rand_state)
1277
+ num_native_gates += circuit.num_gates
1278
+ num_native_2q_gates += circuit.num_nq_gates(2)
1279
+ native_size += circuit.size
2259
1280
 
2260
- s, p = _symp.random_clifford(n, rand_state=rand_state)
2261
- circuit = _cmpl.compile_clifford(s, p, pspec,
2262
- clifford_compilations.get('absolute', None),
2263
- clifford_compilations.get('paulieq', None),
2264
- qubit_labels=qubit_labels, iterations=citerations, *compilerargs,
2265
- rand_state=rand_state)
2266
1281
  # Keeps track of the current composite Clifford
2267
1282
  s_composite, p_composite = _symp.compose_cliffords(s_composite, p_composite, s, p)
2268
1283
  full_circuit.append_circuit_inplace(circuit)
@@ -2306,6 +1321,15 @@ def create_clifford_rb_circuit(pspec, clifford_compilations, length, qubit_label
2306
1321
  idealout = tuple(idealout)
2307
1322
 
2308
1323
  full_circuit.done_editing()
1324
+
1325
+ native_gate_counts = {
1326
+ "native_gate_count": num_native_gates,
1327
+ "native_2q_gate_count": num_native_2q_gates,
1328
+ "native_size": native_size
1329
+ }
1330
+
1331
+ if return_native_gate_counts:
1332
+ return full_circuit, idealout, native_gate_counts
2309
1333
  return full_circuit, idealout
2310
1334
 
2311
1335
 
@@ -2620,198 +1644,6 @@ def create_mirror_rb_circuit(pspec, absolute_compilation, length, qubit_labels=N
2620
1644
 
2621
1645
  return circuit, idealout
2622
1646
 
2623
- #### Commented out as most of this functionality can be found elsewhere and this code has not been tested recently.
2624
- # def sample_one_q_generalized_rb_circuit(m, group_or_model, inverse=True, random_pauli=False, interleaved=None,
2625
- # group_inverse_only=False, group_prep=False, compilation=None,
2626
- # generated_group=None, model_to_group_labels=None, seed=None, rand_state=None):
2627
- # """
2628
- # Makes a random 1-qubit RB circuit, with RB over an arbitrary group.
2629
-
2630
- # This function also contains a range of other options that allow circuits for many
2631
- # types of RB to be generated, including:
2632
-
2633
- # - Clifford RB
2634
- # - Direct RB
2635
- # - Interleaved Clifford or direct RB
2636
- # - Unitarity Clifford or direct RB
2637
-
2638
- # The function can in-principle be used beyond 1-qubit RB, but it relies on explicit matrix representation
2639
- # of a group, which is infeasble for, e.g., the many-qubit Clifford group.
2640
-
2641
- # Note that this function has *not* been carefully tested. This will be rectified in the future,
2642
- # or this function will be replaced.
2643
-
2644
- # Parameters
2645
- # ----------
2646
- # m : int
2647
- # The number of random gates in the circuit.
2648
-
2649
- # group_or_model : Model or MatrixGroup
2650
- # Which Model of MatrixGroup to create the random circuit for. If
2651
- # inverse is true and this is a Model, the Model gates must form
2652
- # a group (so in this case it requires the *target model* rather than
2653
- # a noisy model). When inverse is true, the MatrixGroup for the model
2654
- # is generated. Therefore, if inverse is true and the function is called
2655
- # multiple times, it will be much faster if the MatrixGroup is provided.
2656
-
2657
- # inverse : Bool, optional
2658
- # If true, the random circuit is followed by its inverse gate. The model
2659
- # must form a group if this is true. If it is true then the circuit
2660
- # returned is length m+1 (2m+1) if interleaved is False (True).
2661
-
2662
- # random_pauli : <TODO typ>, optional
2663
- # <TODO description>
2664
-
2665
- # interleaved : Str, optional
2666
- # If not None, then a oplabel string. When a oplabel string is provided,
2667
- # every random gate is followed by this gate. So the returned circuit is of
2668
- # length 2m+1 (2m) if inverse is True (False).
2669
-
2670
- # group_inverse_only : <TODO typ>, optional
2671
- # <TODO description>
2672
-
2673
- # group_prep : bool, optional
2674
- # If group_inverse_only is True and inverse is True, setting this to true
2675
- # creates a "group pre-twirl". Does nothing otherwise (which should be changed
2676
- # at some point).
2677
-
2678
- # compilation : <TODO typ>, optional
2679
- # <TODO description>
2680
-
2681
- # generated_group : <TODO typ>, optional
2682
- # <TODO description>
2683
-
2684
- # model_to_group_labels : <TODO typ>, optional
2685
- # <TODO description>
2686
-
2687
- # seed : int, optional
2688
- # Seed for random number generator; optional.
2689
-
2690
- # rand_state : numpy.random.RandomState, optional
2691
- # A RandomState object to generate samples from. Can be useful to set
2692
- # instead of `seed` if you want reproducible distribution samples across
2693
- # multiple random function calls but you don't want to bother with
2694
- # manually incrementing seeds between those calls.
2695
-
2696
- # Returns
2697
- # -------
2698
- # Circuit
2699
- # The random circuit of length:
2700
- # m if inverse = False, interleaved = None
2701
- # m + 1 if inverse = True, interleaved = None
2702
- # 2m if inverse = False, interleaved not None
2703
- # 2m + 1 if inverse = True, interleaved not None
2704
- # """
2705
- # assert hasattr(group_or_model, 'gates') or hasattr(group_or_model,
2706
- # 'product'), 'group_or_model must be a MatrixGroup of Model'
2707
- # group = None
2708
- # model = None
2709
- # if hasattr(group_or_model, 'gates'):
2710
- # model = group_or_model
2711
- # if hasattr(group_or_model, 'product'):
2712
- # group = group_or_model
2713
-
2714
- # if rand_state is None:
2715
- # rndm = _np.random.RandomState(seed) # ok if seed is None
2716
- # else:
2717
- # rndm = rand_state
2718
-
2719
- # if (inverse) and (not group_inverse_only):
2720
- # if model:
2721
- # group = _rbobjs.MatrixGroup(group_or_model.operations.values(),
2722
- # group_or_model.operations.keys())
2723
-
2724
- # rndm_indices = rndm.randint(0, len(group), m)
2725
- # if interleaved:
2726
- # interleaved_index = group.label_indices[interleaved]
2727
- # interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64)
2728
- # interleaved_indices[:, 0] = rndm_indices
2729
- # rndm_indices = interleaved_indices.flatten()
2730
-
2731
- # random_string = [group.labels[i] for i in rndm_indices]
2732
- # effective_op = group.product(random_string)
2733
- # inv = group.inverse_index(effective_op)
2734
- # random_string.append(inv)
2735
-
2736
- # if (inverse) and (group_inverse_only):
2737
- # assert (model is not None), "gateset_or_group should be a Model!"
2738
- # assert (compilation is not None), "Compilation of group elements to model needs to be specified!"
2739
- # assert (generated_group is not None), "Generated group needs to be specified!"
2740
- # if model_to_group_labels is None:
2741
- # model_to_group_labels = {}
2742
- # for gate in model.primitive_op_labels:
2743
- # assert(gate in generated_group.labels), "model labels are not in \
2744
- # the generated group! Specify a model_to_group_labels dictionary."
2745
- # model_to_group_labels = {'gate': 'gate'}
2746
- # else:
2747
- # for gate in model.primitive_op_labels:
2748
- # assert(gate in model_to_group_labels.keys()), "model to group labels \
2749
- # are invalid!"
2750
- # assert(model_to_group_labels[gate] in generated_group.labels), "model to group labels \
2751
- # are invalid!"
2752
-
2753
- # opLabels = model.primitive_op_labels
2754
- # rndm_indices = rndm.randint(0, len(opLabels), m)
2755
- # if interleaved:
2756
- # interleaved_index = opLabels.index(interleaved)
2757
- # interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64)
2758
- # interleaved_indices[:, 0] = rndm_indices
2759
- # rndm_indices = interleaved_indices.flatten()
2760
-
2761
- # # This bit of code is a quick hashed job. Needs to be checked at somepoint
2762
- # if group_prep:
2763
- # rndm_group_index = rndm.randint(0, len(generated_group))
2764
- # prep_random_string = compilation[generated_group.labels[rndm_group_index]]
2765
- # prep_random_string_group = [generated_group.labels[rndm_group_index], ]
2766
-
2767
- # random_string = [opLabels[i] for i in rndm_indices]
2768
- # random_string_group = [model_to_group_labels[opLabels[i]] for i in rndm_indices]
2769
- # # This bit of code is a quick hashed job. Needs to be checked at somepoint
2770
- # if group_prep:
2771
- # random_string = prep_random_string + random_string
2772
- # random_string_group = prep_random_string_group + random_string_group
2773
- # #print(random_string)
2774
- # inversion_group_element = generated_group.inverse_index(generated_group.product(random_string_group))
2775
-
2776
- # # This bit of code is a quick hash job, and only works when the group is the 1-qubit Cliffords
2777
- # if random_pauli:
2778
- # pauli_keys = ['Gc0', 'Gc3', 'Gc6', 'Gc9']
2779
- # rndm_index = rndm.randint(0, 4)
2780
-
2781
- # if rndm_index == 0 or rndm_index == 3:
2782
- # bitflip = False
2783
- # else:
2784
- # bitflip = True
2785
- # inversion_group_element = generated_group.product([inversion_group_element, pauli_keys[rndm_index]])
2786
-
2787
- # inversion_sequence = compilation[inversion_group_element]
2788
- # random_string.extend(inversion_sequence)
2789
-
2790
- # if not inverse:
2791
- # if model:
2792
- # opLabels = model.primitive_op_labels
2793
- # rndm_indices = rndm.randint(0, len(opLabels), m)
2794
- # if interleaved:
2795
- # interleaved_index = opLabels.index(interleaved)
2796
- # interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64)
2797
- # interleaved_indices[:, 0] = rndm_indices
2798
- # rndm_indices = interleaved_indices.flatten()
2799
- # random_string = [opLabels[i] for i in rndm_indices]
2800
-
2801
- # else:
2802
- # rndm_indices = rndm.randint(0, len(group), m)
2803
- # if interleaved:
2804
- # interleaved_index = group.label_indices[interleaved]
2805
- # interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64)
2806
- # interleaved_indices[:, 0] = rndm_indices
2807
- # rndm_indices = interleaved_indices.flatten()
2808
- # random_string = [group.labels[i] for i in rndm_indices]
2809
-
2810
- # if not random_pauli:
2811
- # return _cir.Circuit(random_string)
2812
- # if random_pauli:
2813
- # return _cir.Circuit(random_string), bitflip
2814
-
2815
1647
 
2816
1648
  def create_random_germ(pspec, depths, interacting_qs_density, qubit_labels, rand_state=None):
2817
1649
  """