pyGSTi 0.9.12.1__cp310-cp310-win_amd64.whl → 0.9.13__cp310-cp310-win_amd64.whl
Sign up to get free protection for your applications and to get access to all the features.
- pyGSTi-0.9.13.dist-info/METADATA +197 -0
- {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/RECORD +207 -217
- {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/WHEEL +1 -1
- pygsti/_version.py +2 -2
- pygsti/algorithms/contract.py +1 -1
- pygsti/algorithms/core.py +42 -28
- pygsti/algorithms/fiducialselection.py +17 -8
- pygsti/algorithms/gaugeopt.py +2 -2
- pygsti/algorithms/germselection.py +87 -77
- pygsti/algorithms/mirroring.py +0 -388
- pygsti/algorithms/randomcircuit.py +165 -1333
- pygsti/algorithms/rbfit.py +0 -234
- pygsti/baseobjs/basis.py +94 -396
- pygsti/baseobjs/errorgenbasis.py +0 -132
- pygsti/baseobjs/errorgenspace.py +0 -10
- pygsti/baseobjs/label.py +52 -168
- pygsti/baseobjs/opcalc/fastopcalc.cp310-win_amd64.pyd +0 -0
- pygsti/baseobjs/opcalc/fastopcalc.pyx +2 -2
- pygsti/baseobjs/polynomial.py +13 -595
- pygsti/baseobjs/statespace.py +1 -0
- pygsti/circuits/__init__.py +1 -1
- pygsti/circuits/circuit.py +682 -505
- pygsti/circuits/circuitconstruction.py +0 -4
- pygsti/circuits/circuitlist.py +47 -5
- pygsti/circuits/circuitparser/__init__.py +8 -8
- pygsti/circuits/circuitparser/fastcircuitparser.cp310-win_amd64.pyd +0 -0
- pygsti/circuits/circuitstructure.py +3 -3
- pygsti/circuits/cloudcircuitconstruction.py +1 -1
- pygsti/data/datacomparator.py +2 -7
- pygsti/data/dataset.py +46 -44
- pygsti/data/hypothesistest.py +0 -7
- pygsti/drivers/bootstrap.py +0 -49
- pygsti/drivers/longsequence.py +2 -1
- pygsti/evotypes/basereps_cython.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/chp/opreps.py +0 -61
- pygsti/evotypes/chp/statereps.py +0 -32
- pygsti/evotypes/densitymx/effectcreps.cpp +9 -10
- pygsti/evotypes/densitymx/effectreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/densitymx/effectreps.pyx +1 -1
- pygsti/evotypes/densitymx/opreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/densitymx/opreps.pyx +2 -2
- pygsti/evotypes/densitymx/statereps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/densitymx/statereps.pyx +1 -1
- pygsti/evotypes/densitymx_slow/effectreps.py +7 -23
- pygsti/evotypes/densitymx_slow/opreps.py +16 -23
- pygsti/evotypes/densitymx_slow/statereps.py +10 -3
- pygsti/evotypes/evotype.py +39 -2
- pygsti/evotypes/stabilizer/effectreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
- pygsti/evotypes/stabilizer/opreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/opreps.pyx +0 -4
- pygsti/evotypes/stabilizer/statereps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/statereps.pyx +1 -5
- pygsti/evotypes/stabilizer/termreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/termreps.pyx +0 -7
- pygsti/evotypes/stabilizer_slow/effectreps.py +0 -22
- pygsti/evotypes/stabilizer_slow/opreps.py +0 -4
- pygsti/evotypes/stabilizer_slow/statereps.py +0 -4
- pygsti/evotypes/statevec/effectreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/effectreps.pyx +1 -1
- pygsti/evotypes/statevec/opreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/opreps.pyx +2 -2
- pygsti/evotypes/statevec/statereps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/statereps.pyx +1 -1
- pygsti/evotypes/statevec/termreps.cp310-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/termreps.pyx +0 -7
- pygsti/evotypes/statevec_slow/effectreps.py +0 -3
- pygsti/evotypes/statevec_slow/opreps.py +0 -5
- pygsti/extras/__init__.py +0 -1
- pygsti/extras/drift/stabilityanalyzer.py +3 -1
- pygsti/extras/interpygate/__init__.py +12 -0
- pygsti/extras/interpygate/core.py +0 -36
- pygsti/extras/interpygate/process_tomography.py +44 -10
- pygsti/extras/rpe/rpeconstruction.py +0 -2
- pygsti/forwardsims/__init__.py +1 -0
- pygsti/forwardsims/forwardsim.py +14 -55
- pygsti/forwardsims/mapforwardsim.py +69 -18
- pygsti/forwardsims/mapforwardsim_calc_densitymx.cp310-win_amd64.pyd +0 -0
- pygsti/forwardsims/mapforwardsim_calc_densitymx.pyx +65 -66
- pygsti/forwardsims/mapforwardsim_calc_generic.py +91 -13
- pygsti/forwardsims/matrixforwardsim.py +63 -15
- pygsti/forwardsims/termforwardsim.py +8 -110
- pygsti/forwardsims/termforwardsim_calc_stabilizer.cp310-win_amd64.pyd +0 -0
- pygsti/forwardsims/termforwardsim_calc_statevec.cp310-win_amd64.pyd +0 -0
- pygsti/forwardsims/termforwardsim_calc_statevec.pyx +0 -651
- pygsti/forwardsims/torchfwdsim.py +265 -0
- pygsti/forwardsims/weakforwardsim.py +2 -2
- pygsti/io/__init__.py +1 -2
- pygsti/io/mongodb.py +0 -2
- pygsti/io/stdinput.py +6 -22
- pygsti/layouts/copalayout.py +10 -12
- pygsti/layouts/distlayout.py +0 -40
- pygsti/layouts/maplayout.py +103 -25
- pygsti/layouts/matrixlayout.py +99 -60
- pygsti/layouts/prefixtable.py +1534 -52
- pygsti/layouts/termlayout.py +1 -1
- pygsti/modelmembers/instruments/instrument.py +3 -3
- pygsti/modelmembers/instruments/tpinstrument.py +2 -2
- pygsti/modelmembers/modelmember.py +0 -17
- pygsti/modelmembers/operations/__init__.py +2 -4
- pygsti/modelmembers/operations/affineshiftop.py +1 -0
- pygsti/modelmembers/operations/composederrorgen.py +1 -1
- pygsti/modelmembers/operations/composedop.py +1 -24
- pygsti/modelmembers/operations/denseop.py +5 -5
- pygsti/modelmembers/operations/eigpdenseop.py +2 -2
- pygsti/modelmembers/operations/embeddederrorgen.py +1 -1
- pygsti/modelmembers/operations/embeddedop.py +0 -1
- pygsti/modelmembers/operations/experrorgenop.py +2 -2
- pygsti/modelmembers/operations/fullarbitraryop.py +1 -0
- pygsti/modelmembers/operations/fullcptpop.py +2 -2
- pygsti/modelmembers/operations/fulltpop.py +28 -6
- pygsti/modelmembers/operations/fullunitaryop.py +5 -4
- pygsti/modelmembers/operations/lindbladcoefficients.py +93 -78
- pygsti/modelmembers/operations/lindbladerrorgen.py +268 -441
- pygsti/modelmembers/operations/linearop.py +7 -27
- pygsti/modelmembers/operations/opfactory.py +1 -1
- pygsti/modelmembers/operations/repeatedop.py +1 -24
- pygsti/modelmembers/operations/staticstdop.py +1 -1
- pygsti/modelmembers/povms/__init__.py +3 -3
- pygsti/modelmembers/povms/basepovm.py +7 -36
- pygsti/modelmembers/povms/complementeffect.py +4 -9
- pygsti/modelmembers/povms/composedeffect.py +0 -320
- pygsti/modelmembers/povms/computationaleffect.py +1 -1
- pygsti/modelmembers/povms/computationalpovm.py +3 -1
- pygsti/modelmembers/povms/effect.py +3 -5
- pygsti/modelmembers/povms/marginalizedpovm.py +0 -79
- pygsti/modelmembers/povms/tppovm.py +74 -2
- pygsti/modelmembers/states/__init__.py +2 -5
- pygsti/modelmembers/states/composedstate.py +0 -317
- pygsti/modelmembers/states/computationalstate.py +3 -3
- pygsti/modelmembers/states/cptpstate.py +4 -4
- pygsti/modelmembers/states/densestate.py +6 -4
- pygsti/modelmembers/states/fullpurestate.py +0 -24
- pygsti/modelmembers/states/purestate.py +1 -1
- pygsti/modelmembers/states/state.py +5 -6
- pygsti/modelmembers/states/tpstate.py +28 -10
- pygsti/modelmembers/term.py +3 -6
- pygsti/modelmembers/torchable.py +50 -0
- pygsti/modelpacks/_modelpack.py +1 -1
- pygsti/modelpacks/smq1Q_ZN.py +3 -1
- pygsti/modelpacks/smq2Q_XXYYII.py +2 -1
- pygsti/modelpacks/smq2Q_XY.py +3 -3
- pygsti/modelpacks/smq2Q_XYI.py +2 -2
- pygsti/modelpacks/smq2Q_XYICNOT.py +3 -3
- pygsti/modelpacks/smq2Q_XYICPHASE.py +3 -3
- pygsti/modelpacks/smq2Q_XYXX.py +1 -1
- pygsti/modelpacks/smq2Q_XYZICNOT.py +3 -3
- pygsti/modelpacks/smq2Q_XYZZ.py +1 -1
- pygsti/modelpacks/stdtarget.py +0 -121
- pygsti/models/cloudnoisemodel.py +1 -2
- pygsti/models/explicitcalc.py +3 -3
- pygsti/models/explicitmodel.py +3 -13
- pygsti/models/fogistore.py +5 -3
- pygsti/models/localnoisemodel.py +1 -2
- pygsti/models/memberdict.py +0 -12
- pygsti/models/model.py +800 -65
- pygsti/models/modelconstruction.py +4 -4
- pygsti/models/modelnoise.py +2 -2
- pygsti/models/modelparaminterposer.py +1 -1
- pygsti/models/oplessmodel.py +1 -1
- pygsti/models/qutrit.py +15 -14
- pygsti/objectivefns/objectivefns.py +73 -138
- pygsti/objectivefns/wildcardbudget.py +2 -7
- pygsti/optimize/__init__.py +1 -0
- pygsti/optimize/arraysinterface.py +28 -0
- pygsti/optimize/customcg.py +0 -12
- pygsti/optimize/customlm.py +129 -323
- pygsti/optimize/customsolve.py +2 -2
- pygsti/optimize/optimize.py +0 -84
- pygsti/optimize/simplerlm.py +841 -0
- pygsti/optimize/wildcardopt.py +19 -598
- pygsti/protocols/confidenceregionfactory.py +28 -14
- pygsti/protocols/estimate.py +31 -14
- pygsti/protocols/gst.py +142 -68
- pygsti/protocols/modeltest.py +6 -10
- pygsti/protocols/protocol.py +9 -37
- pygsti/protocols/rb.py +450 -79
- pygsti/protocols/treenode.py +8 -2
- pygsti/protocols/vb.py +108 -206
- pygsti/protocols/vbdataframe.py +1 -1
- pygsti/report/factory.py +0 -15
- pygsti/report/fogidiagram.py +1 -17
- pygsti/report/modelfunction.py +12 -3
- pygsti/report/mpl_colormaps.py +1 -1
- pygsti/report/plothelpers.py +8 -2
- pygsti/report/reportables.py +41 -37
- pygsti/report/templates/offline/pygsti_dashboard.css +6 -0
- pygsti/report/templates/offline/pygsti_dashboard.js +12 -0
- pygsti/report/workspace.py +2 -14
- pygsti/report/workspaceplots.py +326 -504
- pygsti/tools/basistools.py +9 -36
- pygsti/tools/edesigntools.py +124 -96
- pygsti/tools/fastcalc.cp310-win_amd64.pyd +0 -0
- pygsti/tools/fastcalc.pyx +35 -81
- pygsti/tools/internalgates.py +151 -15
- pygsti/tools/jamiolkowski.py +5 -5
- pygsti/tools/lindbladtools.py +19 -11
- pygsti/tools/listtools.py +0 -114
- pygsti/tools/matrixmod2.py +1 -1
- pygsti/tools/matrixtools.py +173 -339
- pygsti/tools/nameddict.py +1 -1
- pygsti/tools/optools.py +154 -88
- pygsti/tools/pdftools.py +0 -25
- pygsti/tools/rbtheory.py +3 -320
- pygsti/tools/slicetools.py +64 -12
- pyGSTi-0.9.12.1.dist-info/METADATA +0 -155
- pygsti/algorithms/directx.py +0 -711
- pygsti/evotypes/qibo/__init__.py +0 -33
- pygsti/evotypes/qibo/effectreps.py +0 -78
- pygsti/evotypes/qibo/opreps.py +0 -376
- pygsti/evotypes/qibo/povmreps.py +0 -98
- pygsti/evotypes/qibo/statereps.py +0 -174
- pygsti/extras/rb/__init__.py +0 -13
- pygsti/extras/rb/benchmarker.py +0 -957
- pygsti/extras/rb/dataset.py +0 -378
- pygsti/extras/rb/io.py +0 -814
- pygsti/extras/rb/simulate.py +0 -1020
- pygsti/io/legacyio.py +0 -385
- pygsti/modelmembers/povms/denseeffect.py +0 -142
- {pyGSTi-0.9.12.1.dist-info → pyGSTi-0.9.13.dist-info}/LICENSE +0 -0
- {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
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
#
|
1662
|
-
|
1663
|
-
|
1664
|
-
#
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
#
|
1669
|
-
|
1670
|
-
|
1671
|
-
|
1672
|
-
#
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
1676
|
-
#
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
#
|
1687
|
-
#
|
1688
|
-
#
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
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
|
-
|
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
|
"""
|