pyGSTi 0.9.12.1__cp39-cp39-win_amd64.whl → 0.9.13__cp39-cp39-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.cp39-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.cp39-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.cp39-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.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/densitymx/effectreps.pyx +1 -1
- pygsti/evotypes/densitymx/opreps.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/densitymx/opreps.pyx +2 -2
- pygsti/evotypes/densitymx/statereps.cp39-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.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
- pygsti/evotypes/stabilizer/opreps.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/opreps.pyx +0 -4
- pygsti/evotypes/stabilizer/statereps.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/stabilizer/statereps.pyx +1 -5
- pygsti/evotypes/stabilizer/termreps.cp39-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.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/effectreps.pyx +1 -1
- pygsti/evotypes/statevec/opreps.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/opreps.pyx +2 -2
- pygsti/evotypes/statevec/statereps.cp39-win_amd64.pyd +0 -0
- pygsti/evotypes/statevec/statereps.pyx +1 -1
- pygsti/evotypes/statevec/termreps.cp39-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.cp39-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.cp39-win_amd64.pyd +0 -0
- pygsti/forwardsims/termforwardsim_calc_statevec.cp39-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.cp39-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
pygsti/tools/basistools.py
CHANGED
@@ -189,9 +189,9 @@ def change_basis(mx, from_basis, to_basis):
|
|
189
189
|
if isMx:
|
190
190
|
# want ret = toMx.dot( _np.dot(mx, fromMx)) but need to deal
|
191
191
|
# with some/all args being sparse:
|
192
|
-
ret =
|
192
|
+
ret = toMx @ (mx @ fromMx)
|
193
193
|
else: # isVec
|
194
|
-
ret =
|
194
|
+
ret = toMx @ mx
|
195
195
|
|
196
196
|
if not to_basis.real:
|
197
197
|
return ret
|
@@ -199,38 +199,7 @@ def change_basis(mx, from_basis, to_basis):
|
|
199
199
|
if _mt.safe_norm(ret, 'imag') > 1e-8:
|
200
200
|
raise ValueError("Array has non-zero imaginary part (%g) after basis change (%s to %s)!\n%s" %
|
201
201
|
(_mt.safe_norm(ret, 'imag'), from_basis, to_basis, ret))
|
202
|
-
return
|
203
|
-
|
204
|
-
#def transform_matrix(from_basis, to_basis, dim_or_block_dims=None, sparse=False):
|
205
|
-
# '''
|
206
|
-
# Compute the transformation matrix between two bases
|
207
|
-
#
|
208
|
-
# Parameters
|
209
|
-
# ----------
|
210
|
-
# from_basis : Basis or str
|
211
|
-
# Basis being converted from
|
212
|
-
#
|
213
|
-
# to_basis : Basis or str
|
214
|
-
# Basis being converted to
|
215
|
-
#
|
216
|
-
# dim_or_block_dims : int or list of ints
|
217
|
-
# if strings provided as bases, the dimension of basis to use.
|
218
|
-
#
|
219
|
-
# sparse : bool, optional
|
220
|
-
# Whether to construct a sparse or dense transform matrix
|
221
|
-
# when this isn't specified already by `from_basis` or
|
222
|
-
# `to_basis` (e.g. when these are both strings).
|
223
|
-
#
|
224
|
-
# Returns
|
225
|
-
# -------
|
226
|
-
# Basis
|
227
|
-
# the composite basis created
|
228
|
-
# '''
|
229
|
-
# if dim_or_block_dims is None:
|
230
|
-
# assert isinstance(from_basis, Basis)
|
231
|
-
# else:
|
232
|
-
# from_basis = Basis(from_basis, dim_or_block_dims, sparse=sparse)
|
233
|
-
# return from_basis.transform_matrix(to_basis)
|
202
|
+
return ret.real
|
234
203
|
|
235
204
|
|
236
205
|
def create_basis_pair(mx, from_basis, to_basis):
|
@@ -507,7 +476,11 @@ def vec_to_stdmx(v, basis, keep_complex=False):
|
|
507
476
|
"""
|
508
477
|
if not isinstance(basis, _basis.Basis):
|
509
478
|
basis = _basis.BuiltinBasis(basis, len(v))
|
479
|
+
v = v.ravel()
|
510
480
|
ret = _np.zeros(basis.elshape, 'complex')
|
481
|
+
if v.ndim > 1:
|
482
|
+
assert v.size == v.shape[0]
|
483
|
+
v = v.ravel()
|
511
484
|
for i, mx in enumerate(basis.elements):
|
512
485
|
if keep_complex:
|
513
486
|
ret += v[i] * mx
|
@@ -549,9 +522,9 @@ def stdmx_to_vec(m, basis):
|
|
549
522
|
v = _np.empty((basis.size, 1))
|
550
523
|
for i, mx in enumerate(basis.elements):
|
551
524
|
if basis.real:
|
552
|
-
v[i, 0] = _np.real(
|
525
|
+
v[i, 0] = _np.real(_np.vdot(mx, m))
|
553
526
|
else:
|
554
|
-
v[i, 0] = _np.real_if_close(
|
527
|
+
v[i, 0] = _np.real_if_close(_np.vdot(mx, m))
|
555
528
|
return v
|
556
529
|
|
557
530
|
|
pygsti/tools/edesigntools.py
CHANGED
@@ -122,7 +122,7 @@ def calculate_edesign_estimated_runtime(edesign, gate_time_dict=None, gate_time_
|
|
122
122
|
return total_circ_time + total_upload_time
|
123
123
|
|
124
124
|
|
125
|
-
def calculate_fisher_information_per_circuit(
|
125
|
+
def calculate_fisher_information_per_circuit(model, circuits, approx=False, regularization=1e-8, verbosity=1, comm=None, mem_limit=None):
|
126
126
|
"""Helper function to calculate all Fisher information terms for each circuit.
|
127
127
|
|
128
128
|
This function can be used to pre-generate a cache for the
|
@@ -131,10 +131,8 @@ def calculate_fisher_information_per_circuit(regularized_model, circuits, approx
|
|
131
131
|
|
132
132
|
Parameters
|
133
133
|
----------
|
134
|
-
|
134
|
+
model: OpModel
|
135
135
|
The model used to calculate the terms of the Fisher information matrix.
|
136
|
-
This model must already be "regularized" such that there are no small probabilities,
|
137
|
-
usually by adding a small amount of SPAM error.
|
138
136
|
|
139
137
|
circuits: list
|
140
138
|
List of circuits to compute Fisher information for.
|
@@ -142,7 +140,12 @@ def calculate_fisher_information_per_circuit(regularized_model, circuits, approx
|
|
142
140
|
approx: bool, optional (default False)
|
143
141
|
When set to true use the approximate fisher information where we drop the
|
144
142
|
hessian term. Significantly faster to compute than when including the hessian.
|
145
|
-
|
143
|
+
|
144
|
+
regularization: float, optional (default 1e-8)
|
145
|
+
A regularization parameter used to set a minimum probability value for
|
146
|
+
circuits. This is needed to avoid division by zero problems in the fisher
|
147
|
+
information calculation.
|
148
|
+
|
146
149
|
verbosity: int, optional (default 1)
|
147
150
|
Used to control the level of output printed by a VerbosityPrinter object.
|
148
151
|
|
@@ -163,18 +166,28 @@ def calculate_fisher_information_per_circuit(regularized_model, circuits, approx
|
|
163
166
|
|
164
167
|
printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm)
|
165
168
|
|
166
|
-
num_params =
|
167
|
-
outcomes = regularized_model.sim.probs(()).keys()
|
169
|
+
num_params = model.num_params
|
168
170
|
|
171
|
+
#pull out the outcomes for each circuit expanding out the instruments if needed.
|
172
|
+
expanded_circuit_dict_list = model.bulk_expand_instruments_and_separate_povm(circuits)
|
173
|
+
#data structure is awkward so massage this into a nicer format for our current use.
|
174
|
+
expanded_circuit_outcomes = [ [val for val in exp_outcome_dict.values()] for exp_outcome_dict in expanded_circuit_dict_list]
|
175
|
+
#create a dictionary with circuits as keys, and list of outcome keys as values.
|
176
|
+
outcomes = {}
|
177
|
+
for exp_ckt_outcomes, ckt in zip(expanded_circuit_outcomes, circuits):
|
178
|
+
#exp_ckt_outcomes will be a list of tuples whose entries are outcome label tuples.
|
179
|
+
#flatten this into a single list of outcome labels.
|
180
|
+
outcomes[ckt] = [outcome for outcome_tuple in exp_ckt_outcomes for outcome in outcome_tuple]
|
181
|
+
|
169
182
|
resource_alloc = _baseobjs.ResourceAllocation(comm= comm, mem_limit = mem_limit)
|
170
183
|
|
171
184
|
printer.log('Calculating Probabilities, Jacobians and Hessians (if not using approx FIM).', 3)
|
172
|
-
ps =
|
173
|
-
js =
|
185
|
+
ps = model.sim.bulk_probs(circuits, resource_alloc)
|
186
|
+
js = model.sim.bulk_dprobs(circuits, resource_alloc)
|
174
187
|
#if approx is true we add in the hessian term as well.
|
175
188
|
if not approx:
|
176
189
|
printer.log('Calculating Hessians.', 3)
|
177
|
-
hs =
|
190
|
+
hs = model.sim.bulk_hprobs(circuits, resource_alloc)
|
178
191
|
|
179
192
|
if comm is not None:
|
180
193
|
#divide the job of doing the accumulation among the ranks:
|
@@ -230,15 +243,14 @@ def calculate_fisher_information_per_circuit(regularized_model, circuits, approx
|
|
230
243
|
#now calculate the fisher information terms on each rank:
|
231
244
|
printer.log('Distributed calculation of FIM.', 4)
|
232
245
|
if approx:
|
233
|
-
split_fisher_info_terms =
|
234
|
-
outcomes, ps, js,
|
235
|
-
|
236
|
-
approx=True)
|
246
|
+
split_fisher_info_terms = _accumulate_fim_matrix_per_circuit(split_circuit_list, num_params,
|
247
|
+
outcomes, ps, js, printer,
|
248
|
+
approx=True, regularization=regularization)
|
237
249
|
else:
|
238
|
-
split_fisher_info_terms, total_hterm =
|
250
|
+
split_fisher_info_terms, total_hterm = _accumulate_fim_matrix_per_circuit(split_circuit_list, num_params,
|
239
251
|
outcomes, ps, js,
|
240
|
-
printer,
|
241
|
-
|
252
|
+
printer,hs, approx=False,
|
253
|
+
regularization=regularization)
|
242
254
|
|
243
255
|
#gather these back onto rank 0.
|
244
256
|
#This should return a list of dictionaries to rank 0.
|
@@ -294,15 +306,14 @@ def calculate_fisher_information_per_circuit(regularized_model, circuits, approx
|
|
294
306
|
#otherwise do things without splitting up among multiple cores.
|
295
307
|
else:
|
296
308
|
if approx:
|
297
|
-
fisher_info_terms =
|
298
|
-
outcomes, ps, js,
|
299
|
-
|
300
|
-
approx=True)
|
309
|
+
fisher_info_terms = _accumulate_fim_matrix_per_circuit(circuits, num_params,
|
310
|
+
outcomes, ps, js, printer,
|
311
|
+
approx=True, regularization=regularization)
|
301
312
|
else:
|
302
|
-
fisher_info_terms, total_hterm =
|
313
|
+
fisher_info_terms, total_hterm = _accumulate_fim_matrix_per_circuit(circuits, num_params,
|
303
314
|
outcomes, ps, js,
|
304
|
-
printer,
|
305
|
-
|
315
|
+
printer, hs,
|
316
|
+
approx=False, regularization=regularization)
|
306
317
|
|
307
318
|
fisher_info_terms = {ckt: fisher_info_terms[i,:,:] for i, ckt in enumerate(circuits)}
|
308
319
|
if not approx:
|
@@ -315,13 +326,10 @@ def calculate_fisher_information_per_circuit(regularized_model, circuits, approx
|
|
315
326
|
|
316
327
|
|
317
328
|
def calculate_fisher_information_matrix(model, circuits, num_shots=1, term_cache=None,
|
318
|
-
|
329
|
+
regularization=1e-8, approx= False, mem_efficient_mode= False,
|
319
330
|
circuit_chunk_size = 100, verbosity=1, comm = None, mem_limit = None):
|
320
331
|
"""Calculate the Fisher information matrix for a set of circuits and a model.
|
321
332
|
|
322
|
-
Note that the model should be regularized so that no probability should be very small
|
323
|
-
for numerical stability. This is done by default for models with a dense SPAM parameterization,
|
324
|
-
but must be done manually if this is not the case (e.g. CPTP parameterization).
|
325
333
|
|
326
334
|
Parameters
|
327
335
|
----------
|
@@ -341,10 +349,10 @@ def calculate_fisher_information_matrix(model, circuits, num_shots=1, term_cache
|
|
341
349
|
will be updated with any additional circuits that need to be calculated in the given
|
342
350
|
circuit list.
|
343
351
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
352
|
+
regularization: float, optional (default 1e-8)
|
353
|
+
A regularization parameter used to set a minimum probability value for
|
354
|
+
circuits. This is needed to avoid division by zero problems in the fisher
|
355
|
+
information calculation.
|
348
356
|
|
349
357
|
approx: bool, optional (default False)
|
350
358
|
When set to true use the approximate fisher information where we drop the
|
@@ -377,11 +385,8 @@ def calculate_fisher_information_matrix(model, circuits, num_shots=1, term_cache
|
|
377
385
|
|
378
386
|
printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm)
|
379
387
|
|
380
|
-
|
381
|
-
|
382
|
-
if regularize_spam:
|
383
|
-
regularized_model = regularized_model.depolarize(spam_noise=1e-3)
|
384
|
-
num_params = regularized_model.num_params
|
388
|
+
model = model.copy()
|
389
|
+
num_params = model.num_params
|
385
390
|
|
386
391
|
if isinstance(num_shots, dict):
|
387
392
|
assert _np.all([c in num_shots for c in circuits]), \
|
@@ -400,11 +405,13 @@ def calculate_fisher_information_matrix(model, circuits, num_shots=1, term_cache
|
|
400
405
|
#might also return hessian terms if approx is False, but we currently aren't using this in
|
401
406
|
#this function.
|
402
407
|
if approx:
|
403
|
-
new_terms = calculate_fisher_information_per_circuit(
|
404
|
-
approx,
|
408
|
+
new_terms = calculate_fisher_information_per_circuit(model, needed_circuits,
|
409
|
+
approx, regularization,
|
410
|
+
verbosity=verbosity, comm=comm, mem_limit=mem_limit)
|
405
411
|
else:
|
406
|
-
new_terms, _ = calculate_fisher_information_per_circuit(
|
407
|
-
approx,
|
412
|
+
new_terms, _ = calculate_fisher_information_per_circuit(model, needed_circuits,
|
413
|
+
approx, regularization,
|
414
|
+
verbosity=verbosity, comm=comm, mem_limit=mem_limit)
|
408
415
|
if comm is None or comm.Get_rank()==0:
|
409
416
|
term_cache.update(new_terms)
|
410
417
|
|
@@ -435,11 +442,11 @@ def calculate_fisher_information_matrix(model, circuits, num_shots=1, term_cache
|
|
435
442
|
printer.show_progress(iteration = i, total=len(chunked_circuit_lists), bar_length=50,
|
436
443
|
suffix= f'Circuit chunk {i+1} out of {len(chunked_circuit_lists)}')
|
437
444
|
if approx:
|
438
|
-
fim_term_for_chunk = _calculate_fisher_information_per_chunk(
|
439
|
-
approx, num_shots, verbosity=verbosity, comm=comm, mem_limit=mem_limit)
|
445
|
+
fim_term_for_chunk = _calculate_fisher_information_per_chunk(model, ckt_chunk,
|
446
|
+
approx, num_shots, regularization, verbosity=verbosity, comm=comm, mem_limit=mem_limit)
|
440
447
|
else:
|
441
|
-
fim_term_for_chunk, _ = _calculate_fisher_information_per_chunk(
|
442
|
-
approx, num_shots, verbosity=verbosity, comm=comm, mem_limit=mem_limit)
|
448
|
+
fim_term_for_chunk, _ = _calculate_fisher_information_per_chunk(model, ckt_chunk,
|
449
|
+
approx, regularization, num_shots, verbosity=verbosity, comm=comm, mem_limit=mem_limit)
|
443
450
|
# Collect all terms, do this on rank zero:
|
444
451
|
if comm is None or comm.Get_rank() == 0:
|
445
452
|
fisher_information += fim_term_for_chunk
|
@@ -455,7 +462,7 @@ def calculate_fisher_information_matrix(model, circuits, num_shots=1, term_cache
|
|
455
462
|
return fisher_information
|
456
463
|
|
457
464
|
def calculate_fisher_information_matrices_by_L(model, circuit_lists, Ls, num_shots=1, term_cache=None,
|
458
|
-
|
465
|
+
regularization=1e-8, cumulative=True, approx = False,
|
459
466
|
mem_efficient_mode= False, circuit_chunk_size = 100,
|
460
467
|
verbosity= 1,
|
461
468
|
comm = None, mem_limit = None):
|
@@ -484,10 +491,10 @@ def calculate_fisher_information_matrices_by_L(model, circuit_lists, Ls, num_sho
|
|
484
491
|
will be updated with any additional circuits that need to be calculated in the given
|
485
492
|
circuit list.
|
486
493
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
494
|
+
regularization: float, optional (default 1e-8)
|
495
|
+
A regularization parameter used to set a minimum probability value for
|
496
|
+
circuits. This is needed to avoid division by zero problems in the fisher
|
497
|
+
information calculation.
|
491
498
|
|
492
499
|
cumulative: bool
|
493
500
|
Whether to include Fisher information matrices for lower L (True) or not.
|
@@ -521,12 +528,8 @@ def calculate_fisher_information_matrices_by_L(model, circuit_lists, Ls, num_sho
|
|
521
528
|
Dictionary with keys as circuit length L and value as Fisher information matrices
|
522
529
|
"""
|
523
530
|
|
524
|
-
printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm)
|
525
|
-
|
526
|
-
# Regularize model
|
527
|
-
regularized_model = model.copy()
|
528
|
-
if regularize_spam:
|
529
|
-
regularized_model = regularized_model.depolarize(spam_noise=1e-3)
|
531
|
+
printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm)
|
532
|
+
model = model.copy()
|
530
533
|
|
531
534
|
if isinstance(num_shots, dict):
|
532
535
|
assert _np.all([c in num_shots for ckt_list in circuit_lists for c in ckt_list]), \
|
@@ -551,10 +554,10 @@ def calculate_fisher_information_matrices_by_L(model, circuit_lists, Ls, num_sho
|
|
551
554
|
needed_circuits = [c for ckt_list in circuit_lists for c in ckt_list if c not in term_cache]
|
552
555
|
if len(needed_circuits):
|
553
556
|
if approx:
|
554
|
-
new_terms = calculate_fisher_information_per_circuit(
|
557
|
+
new_terms = calculate_fisher_information_per_circuit(model, needed_circuits, approx, regularization, verbosity=verbosity,
|
555
558
|
comm=comm, mem_limit=mem_limit)
|
556
559
|
else:
|
557
|
-
new_terms, _ = calculate_fisher_information_per_circuit(
|
560
|
+
new_terms, _ = calculate_fisher_information_per_circuit(model, needed_circuits, approx, regularization, verbosity=verbosity,
|
558
561
|
comm=comm, mem_limit=mem_limit)
|
559
562
|
if comm is None or comm.Get_rank()==0:
|
560
563
|
term_cache.update(new_terms)
|
@@ -567,9 +570,9 @@ def calculate_fisher_information_matrices_by_L(model, circuit_lists, Ls, num_sho
|
|
567
570
|
|
568
571
|
for i, (L, ckt_list) in enumerate(zip(Ls, unique_circuit_lists)):
|
569
572
|
printer.log(f'Current length L={L}', 2)
|
570
|
-
fisher_information_by_L[L] = calculate_fisher_information_matrix(
|
571
|
-
term_cache=term_cache,
|
572
|
-
if i!=0:
|
573
|
+
fisher_information_by_L[L] = calculate_fisher_information_matrix(model, ckt_list, num_shots,
|
574
|
+
term_cache=term_cache, regularization=regularization, verbosity=verbosity)
|
575
|
+
if i!=0 and cumulative:
|
573
576
|
#Add previous iteration's FIM on rank 0 (on other ranks this is None which is why we don't do it there).
|
574
577
|
fisher_information_by_L[L]=fisher_information_by_L[L] + fisher_information_by_L[Ls[i-1]]
|
575
578
|
|
@@ -583,21 +586,21 @@ def calculate_fisher_information_matrices_by_L(model, circuit_lists, Ls, num_sho
|
|
583
586
|
fisher_information_by_L = {}
|
584
587
|
for i, (L, ckt_list) in enumerate(zip(Ls, unique_circuit_lists)):
|
585
588
|
printer.log(f'Current length L={L}',2)
|
586
|
-
fisher_information_by_L[L] = calculate_fisher_information_matrix(
|
587
|
-
term_cache=None,
|
588
|
-
|
589
|
+
fisher_information_by_L[L] = calculate_fisher_information_matrix(model, ckt_list, num_shots,
|
590
|
+
term_cache=None, approx = approx,
|
591
|
+
regularization=regularization,
|
589
592
|
mem_efficient_mode=mem_efficient_mode,
|
590
593
|
circuit_chunk_size = circuit_chunk_size,
|
591
594
|
verbosity = verbosity,
|
592
595
|
comm=comm, mem_limit=mem_limit)
|
593
|
-
if i!=0 and (comm is None or comm.Get_rank()==0):
|
596
|
+
if i!=0 and (comm is None or comm.Get_rank()==0) and cumulative:
|
594
597
|
#Add previous iteration's FIM on rank 0 (on other ranks this is None which is why we don't do it there).
|
595
598
|
fisher_information_by_L[L]=fisher_information_by_L[L] + fisher_information_by_L[Ls[i-1]]
|
596
599
|
#In memory efficient mode the fisher information is None on any rank other than 0 when using MPI.
|
597
600
|
return fisher_information_by_L
|
598
601
|
|
599
602
|
#Helper function for memory efficient MPI implementation that combines the contributions for each circuit chunk together more cleverly
|
600
|
-
def _calculate_fisher_information_per_chunk(
|
603
|
+
def _calculate_fisher_information_per_chunk(model, circuits, approx=False, regularization=1e-8, num_shots=None, verbosity=1, comm = None, mem_limit = None):
|
601
604
|
"""Helper function to calculate all Fisher information terms for a chunk of circuits.
|
602
605
|
Used primarily in memory efficient MPI implementation.
|
603
606
|
|
@@ -607,10 +610,8 @@ def _calculate_fisher_information_per_chunk(regularized_model, circuits, approx=
|
|
607
610
|
|
608
611
|
Parameters
|
609
612
|
----------
|
610
|
-
|
613
|
+
model: OpModel
|
611
614
|
The model used to calculate the terms of the Fisher information matrix.
|
612
|
-
This model must already be "regularized" such that there are no small probabilities,
|
613
|
-
usually by adding a small amount of SPAM error.
|
614
615
|
|
615
616
|
circuits: list
|
616
617
|
List of circuits to compute Fisher information for.
|
@@ -619,6 +620,11 @@ def _calculate_fisher_information_per_chunk(regularized_model, circuits, approx=
|
|
619
620
|
When set to true use the approximate fisher information where we drop the
|
620
621
|
hessian term. Significantly faster to compute than when including the hessian.
|
621
622
|
|
623
|
+
regularization: float, optional (default 1e-8)
|
624
|
+
A regularization parameter used to set a minimum probability value for
|
625
|
+
circuits. This is needed to avoid division by zero problems in the fisher
|
626
|
+
information calculation.
|
627
|
+
|
622
628
|
num_shots : dict, optional (default None)
|
623
629
|
A dictionary of per circuit shot counts. When None each circuit gets assigned 1 shot.
|
624
630
|
|
@@ -642,17 +648,27 @@ def _calculate_fisher_information_per_chunk(regularized_model, circuits, approx=
|
|
642
648
|
|
643
649
|
printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm)
|
644
650
|
|
645
|
-
num_params =
|
646
|
-
|
651
|
+
num_params = model.num_params
|
652
|
+
|
653
|
+
#pull out the outcomes for each circuit expanding out the instruments if needed.
|
654
|
+
expanded_circuit_dict_list = model.bulk_expand_instruments_and_separate_povm(circuits)
|
655
|
+
#data structure is awkward so massage this into a nicer format for our current use.
|
656
|
+
expanded_circuit_outcomes = [list(exp_outcome_dict.values())[0] for exp_outcome_dict in expanded_circuit_dict_list]
|
657
|
+
#create a dictionary with circuits as keys, and list of outcome keys as values.
|
658
|
+
outcomes = {}
|
659
|
+
for exp_ckt_outcomes, ckt in zip(expanded_circuit_outcomes, circuits):
|
660
|
+
#exp_ckt_outcomes will be a list of tuples whose entries are outcome label tuples.
|
661
|
+
#flatten this into a single list of outcome labels.
|
662
|
+
outcomes[ckt] = [outcome for outcome_tuple in exp_ckt_outcomes for outcome in outcome_tuple]
|
647
663
|
|
648
664
|
resource_alloc = _baseobjs.ResourceAllocation(comm= comm, mem_limit = mem_limit)
|
649
665
|
|
650
666
|
printer.log('Calculating Probabilities, Jacobians and Hessians (if not using approx FIM).', 3)
|
651
|
-
ps =
|
652
|
-
js =
|
667
|
+
ps = model.sim.bulk_probs(circuits, resource_alloc)
|
668
|
+
js = model.sim.bulk_dprobs(circuits, resource_alloc)
|
653
669
|
#if approx is true we add in the hessian term as well.
|
654
670
|
if not approx:
|
655
|
-
hs =
|
671
|
+
hs = model.sim.bulk_hprobs(circuits, resource_alloc)
|
656
672
|
|
657
673
|
if comm is not None:
|
658
674
|
#divide the job of doing the accumulation among the ranks:
|
@@ -708,15 +724,15 @@ def _calculate_fisher_information_per_chunk(regularized_model, circuits, approx=
|
|
708
724
|
#now calculate the fisher information terms on each rank:
|
709
725
|
printer.log('Distributed accumulation of FIM.', 3)
|
710
726
|
if approx:
|
711
|
-
split_fisher_info_terms =
|
727
|
+
split_fisher_info_terms = _accumulate_fim_matrix(split_circuit_list, num_params,
|
712
728
|
num_shots, outcomes, ps, js,
|
713
|
-
printer,
|
714
|
-
|
729
|
+
printer,hs=None, approx=True,
|
730
|
+
regularization=regularization)
|
715
731
|
else:
|
716
|
-
split_fisher_info_terms, split_total_hterm =
|
732
|
+
split_fisher_info_terms, split_total_hterm = _accumulate_fim_matrix(split_circuit_list, num_params,
|
717
733
|
num_shots, outcomes, ps, js,
|
718
|
-
printer,
|
719
|
-
|
734
|
+
printer, hs, approx=False,
|
735
|
+
regularization=regularization)
|
720
736
|
|
721
737
|
if comm.Get_rank() == 0:
|
722
738
|
#1D buffer long enough to hold every element, will then reshape this later.
|
@@ -750,20 +766,20 @@ def _calculate_fisher_information_per_chunk(regularized_model, circuits, approx=
|
|
750
766
|
#otherwise do things without splitting up among multiple cores.
|
751
767
|
else:
|
752
768
|
if approx:
|
753
|
-
fisher_info_term =
|
769
|
+
fisher_info_term = _accumulate_fim_matrix(circuits, num_params, num_shots, outcomes,
|
754
770
|
ps, js, printer, hs=None,
|
755
|
-
approx=True)
|
771
|
+
approx=True, regularization=regularization)
|
756
772
|
else:
|
757
|
-
fisher_info_term, total_hterm =
|
773
|
+
fisher_info_term, total_hterm = _accumulate_fim_matrix(circuits, num_params, num_shots, outcomes,
|
758
774
|
ps, js, printer, hs,
|
759
|
-
approx=False)
|
775
|
+
approx=False, regularization=regularization)
|
760
776
|
if approx:
|
761
777
|
return fisher_info_term
|
762
778
|
else:
|
763
779
|
return fisher_info_term, total_hterm
|
764
780
|
|
765
781
|
#helper function for distribution using MPI
|
766
|
-
def
|
782
|
+
def _accumulate_fim_matrix(subcircuits, num_params, num_shots, outcomes, ps, js, printer, hs=None, approx=False, regularization=1e-8):
|
767
783
|
printer.log('Accumulating terms for per-circuit FIM.', 4)
|
768
784
|
fisher_info_terms = _np.zeros([num_params, num_params], dtype = _np.double)
|
769
785
|
if not approx:
|
@@ -775,26 +791,32 @@ def accumulate_fim_matrix(subcircuits, num_params, num_shots, outcomes, ps, js,
|
|
775
791
|
else:
|
776
792
|
num_shots_for_circuit=1
|
777
793
|
p = ps[circuit]
|
794
|
+
#regularize any probabilities that are too small.
|
795
|
+
clipped_p = _np.clip(_np.fromiter(p.values(), dtype=_np.double), a_min=regularization, a_max=None)
|
796
|
+
#renormalize this vector (probably not necessary, but better to be safe).
|
797
|
+
renormalized_clipped_p = clipped_p/_np.linalg.norm(clipped_p)
|
798
|
+
regularized_p = {outcome_lbl: val for outcome_lbl, val in zip(p.keys(), renormalized_clipped_p)}
|
799
|
+
|
778
800
|
j = js[circuit]
|
779
801
|
if not approx:
|
780
802
|
h = hs[circuit]
|
781
|
-
for i, outcome in enumerate(outcomes):
|
803
|
+
for i, outcome in enumerate(outcomes[circuit]):
|
782
804
|
if not approx:
|
783
|
-
jvec = _np.sqrt(num_shots_for_circuit/
|
784
|
-
fisher_info_terms +=
|
805
|
+
jvec = _np.sqrt(num_shots_for_circuit/regularized_p[outcome])*(j[outcome].reshape(num_params,1))
|
806
|
+
fisher_info_terms += jvec@jvec.T - num_shots_for_circuit*h[outcome]
|
785
807
|
total_hterm += num_shots_for_circuit*h[outcome]
|
786
808
|
else:
|
787
809
|
#fisher_info_terms += _np.outer(j[outcome], j[outcome]) / p[outcome]
|
788
810
|
#faster outer product
|
789
|
-
jvec = _np.sqrt(num_shots_for_circuit/
|
790
|
-
fisher_info_terms +=
|
811
|
+
jvec = _np.sqrt(num_shots_for_circuit/regularized_p[outcome])*(j[outcome].reshape(num_params,1))
|
812
|
+
fisher_info_terms += jvec@jvec.T
|
791
813
|
if approx:
|
792
814
|
return fisher_info_terms
|
793
815
|
else:
|
794
816
|
return fisher_info_terms, total_hterm
|
795
817
|
|
796
818
|
#helper function for distribution using MPI
|
797
|
-
def
|
819
|
+
def _accumulate_fim_matrix_per_circuit(subcircuits, num_params, outcomes, ps, js, printer, hs=None, approx=False, regularization=1e-8):
|
798
820
|
printer.log('Accumulating terms for per-circuit FIM.', 4)
|
799
821
|
fisher_info_terms = _np.zeros([len(subcircuits),num_params, num_params])
|
800
822
|
if not approx:
|
@@ -802,19 +824,25 @@ def accumulate_fim_matrix_per_circuit(subcircuits, num_params, outcomes, ps, js,
|
|
802
824
|
|
803
825
|
for k, circuit in enumerate(subcircuits):
|
804
826
|
p = ps[circuit]
|
827
|
+
#regularize any probabilities that are too small.
|
828
|
+
clipped_p = _np.clip(_np.fromiter(p.values(), dtype=_np.double), a_min=regularization, a_max=None)
|
829
|
+
#renormalize this vector (probably not necessary, but better to be safe).
|
830
|
+
renormalized_clipped_p = clipped_p/_np.linalg.norm(clipped_p)
|
831
|
+
regularized_p = {outcome_lbl: val for outcome_lbl, val in zip(p.keys(), renormalized_clipped_p)}
|
832
|
+
|
805
833
|
j = js[circuit]
|
806
834
|
if not approx:
|
807
835
|
h = hs[circuit]
|
808
|
-
for i, outcome in enumerate(outcomes):
|
836
|
+
for i, outcome in enumerate(outcomes[circuit]):
|
809
837
|
if not approx:
|
810
|
-
jvec = (1/_np.sqrt(
|
811
|
-
fisher_info_terms[k,:,:] +=
|
838
|
+
jvec = (1/_np.sqrt(regularized_p[outcome]))*(j[outcome].reshape(num_params,1))
|
839
|
+
fisher_info_terms[k,:,:] += jvec@jvec.T - h[outcome]
|
812
840
|
total_hterm[k,:,:] += h[outcome]
|
813
841
|
else:
|
814
842
|
#fisher_info_terms[circuit] += _np.outer(j[outcome], j[outcome]) / p[outcome]
|
815
843
|
#faster outer product
|
816
|
-
jvec = (1/_np.sqrt(
|
817
|
-
fisher_info_terms[k,:,:] +=
|
844
|
+
jvec = (1/_np.sqrt(regularized_p[outcome]))*(j[outcome].reshape(num_params,1))
|
845
|
+
fisher_info_terms[k,:,:] += jvec@jvec.T
|
818
846
|
if approx:
|
819
847
|
return fisher_info_terms
|
820
848
|
else:
|
Binary file
|