/
modelfunction.py
378 lines (318 loc) · 14.2 KB
/
modelfunction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
""" Defines the ModelFunction class """
from __future__ import division, print_function, absolute_import, unicode_literals
#***************************************************************************************************
# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
# in this software.
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
#***************************************************************************************************
class ModelFunction(object):
"""
Encapsulates a "function of a Model" that one may want to compute
confidence-interval error bars for based on a confidence region of
the functions model argument. The "function" may have other parameters,
and the reason for defining it as a class is so that it can hold
1. relevant "meta" arguments in addition to the central Model, and
2. information to speed up function evaluations at nearby Model "points",
for computing finite-difference derivatives.
"""
def __init__(self, model, dependencies):
"""
Creates a new ModelFunction object.
Parameters
----------
model : Model
A sample model giving the constructor a template for what
type/parameterization of model to expect in calls to
:func:`evaluate`.
dependencies : list
A list of *type:label* strings, or the special strings `"all"` and
`"spam"`, indicating which Model parameters the function depends
upon. Here *type* can be `"gate"`, `"prep"`, `"povm"`, or
`"instrument"`, and *label* can be any of the corresponding labels
found in the models being evaluated. The reason for specifying
this at all is to speed up computation of the finite difference
derivative needed to find the error bars.
"""
self.base_model = model
self.dependencies = dependencies
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
return None
def evaluate_nearby(self, nearby_model):
"""
Evaluate this gate-set-function at `nearby_model`, which can
be assumed is very close to the `model` provided to the last
call to :func:`evaluate`.
"""
# do stuff assuming nearby_model is eps away from model
return self.evaluate(nearby_model)
def get_dependencies(self):
"""
Return the dependencies of this gate-set-function.
Returns
-------
list
A list of *type:label* strings, or the special strings `"all"` and
`"spam"`, indicating which Model parameters the function depends
upon. Here *type* can be `"gate"`, `"prep"`, `"povm"`, or
`"instrument"` and *label* can be any of the corresponding labels
found in the models being evaluated.
"""
return self.dependencies
#determines which variations in model are used when computing confidence regions
def spamfn_factory(fn):
"""
Ceates a class that evaluates
`fn(preps,povms,...)`, where `preps` and `povms` are lists of the
preparation SPAM vectors and POVMs of a Model, respectively,
and `...` are additional arguments (see below).
Parameters
----------
fn : function
A function of at least the two parameters as discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model, ...)` where `model` is a Model and `...` are optional
additional arguments that are passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by spamfn_factory """
def __init__(self, model, *args, **kwargs):
"""
Creates a new ModelFunction dependent only on its Model
argument's SPAM vectors.
"""
self.args = args
self.kwargs = kwargs
ModelFunction.__init__(self, model, ["spam"])
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
return fn(list(model.preps.values()),
list(model.povms.values()),
*self.args, **self.kwargs)
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp
#Note: the 'basis' argument is unnecesary here, as it could be passed as an additional arg
def opfn_factory(fn):
"""
Creates a class that evaluates `fn(gate,basis,...)`, where `gate` is a
single operation matrix, `basis` describes what basis it's in, and `...` are
additional arguments (see below).
Parameters
----------
fn : function
A function of at least the two parameters as discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model, gl, ...)` where `model` is a Model, `gl` is a gate
label, and `...` are optional additional arguments passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by opfn_factory """
def __init__(self, model, gl, *args, **kwargs):
""" Creates a new ModelFunction dependent on a single gate"""
self.gl = gl
self.args = args
self.kwargs = kwargs
ModelFunction.__init__(self, model, ["gate:" + str(gl)])
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
return fn(model.operations[self.gl].todense(), model.basis,
*self.args, **self.kwargs)
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp
#Note: the 'op2' and 'basis' arguments are unnecesary here, as they could be
# passed as additional args
def opsfn_factory(fn):
"""
Creates a class that evaluates `fn(op1,op2,basis,...)`, where `op1`
and `op2` are a single operation matrices, `basis` describes what basis they're
in, and `...` are additional arguments (see below).
Parameters
----------
fn : function
A function of at least the two parameters as discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model1, model2, gl, ...)` where `model1` and `model2` are
Models (only `model1` and `op1` are varied when computing a
confidence region), `gl` is a operation label, and `...` are optional
additional arguments passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by opsfn_factory """
def __init__(self, model1, model2, gl, *args, **kwargs):
""" Creates a new ModelFunction dependent on a single gate"""
self.other_model = model2
self.gl = gl
self.args = args
self.kwargs = kwargs
ModelFunction.__init__(self, model1, ["gate:" + str(gl)])
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
return fn(model.operations[self.gl].todense(), self.other_model.operations[self.gl].todense(),
model.basis, *self.args, **self.kwargs) # assume functions want *dense* gates
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp
def vecfn_factory(fn):
"""
Creates a class that evaluates `fn(vec,basis,...)`, where `vec` is a
single SPAM vector, `basis` describes what basis it's in, and `...` are
additional arguments (see below).
Parameters
----------
fn : function
A function of at least the two parameters as discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model, lbl, typ, ...)` where `model` is a Model, `lbl` is
SPAM vector label, `typ` is either `"prep"` or `"effect"` (the type of
the SPAM vector), and `...` are optional additional arguments
passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by vecfn_factory """
def __init__(self, model, lbl, typ, *args, **kwargs):
""" Creates a new ModelFunction dependent on a single SPAM vector"""
self.lbl = lbl
self.typ = typ
self.args = args
self.kwargs = kwargs
assert(typ in ['prep', 'effect']), "`typ` argument must be either 'prep' or 'effect'"
if typ == 'effect':
typ = "povm"
lbl, _ = lbl.split(":") # for "effect"-mode, lbl must == "povmLbl:ELbl"
# and ModelFunction depends on entire POVM
ModelFunction.__init__(self, model, [typ + ":" + str(lbl)])
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
if self.typ == "prep":
return fn(model.preps[self.lbl].todense(), model.basis,
*self.args, **self.kwargs)
else:
povmlbl, Elbl = self.lbl.split(":") # for effect, lbl must == "povmLbl:ELbl"
return fn(model.povms[povmlbl][Elbl].todense(), model.basis,
*self.args, **self.kwargs)
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp
def vecsfn_factory(fn):
"""
Creates a class that evaluates `fn(vec1, vec2, basis,...)`, where `vec1`
and `vec2` are SPAM vectors, `basis` describes what basis they're in, and
`...` are additional arguments (see below).
Parameters
----------
fn : function
A function of at least the two parameters as discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model1, model2, lbl, typ, ...)` where `model1` and `model2`
are Models (only `model1` and `vec1` are varied when computing a
confidence region), `lbl` is a SPAM vector label, `typ` is either
`"prep"` or `"effect"` (the type of the SPAM vector), and `...` are
optional additional arguments passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by vecsfn_factory """
def __init__(self, model1, model2, lbl, typ, *args, **kwargs):
""" Creates a new ModelFunction dependent on a single SPAM vector"""
self.other_model = model2
self.lbl = lbl
self.typ = typ
self.args = args
self.kwargs = kwargs
assert(typ in ['prep', 'effect']), "`typ` argument must be either 'prep' or 'effect'"
if typ == 'effect':
typ = "povm"
lbl, _ = lbl.split(":") # for "effect"-mode, lbl must == "povmLbl:ELbl"
# and ModelFunction depends on entire POVM
self.other_vecsrc = self.other_model.preps if self.typ == "prep" \
else self.other_model.povms
ModelFunction.__init__(self, model1, [typ + ":" + str(lbl)])
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
if self.typ == "prep":
return fn(model.preps[self.lbl].todense(), self.other_vecsrc[self.lbl].todense(),
model.basis, *self.args, **self.kwargs)
else:
povmlbl, Elbl = self.lbl.split(":") # for effect, lbl must == "povmLbl:ELbl"
return fn(model.povms[povmlbl][Elbl].todense(), self.other_vecsrc[povmlbl][Elbl].todense(),
model.basis, *self.args, **self.kwargs)
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp
def povmfn_factory(fn):
"""
Ceates a class that evaluates
`fn(model,...)` where `model` is the entire Model (and it is assumed
that `fn` is only a function of the POVM effect elements of the model),
and `...` are additional arguments (see below).
Parameters
----------
fn : function
A function of at least the one parameter as discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model, ...)` where `model` is a Model and `...` are optional
additional arguments that are passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by povmfn_factory """
def __init__(self, model, *args, **kwargs):
"""
Creates a new ModelFunction dependent on all of its
Model argument's effects
"""
self.args = args
self.kwargs = kwargs
dps = ["povm:%s" % l for l in model.povms]
ModelFunction.__init__(self, model, dps)
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
return fn(model, *self.args, **self.kwargs)
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp
def modelfn_factory(fn):
"""
Creates a class that evaluates `fn(model,...)`, where `model` is a
`Model` object and `...` are additional arguments (see below).
Parameters
----------
fn : function
A function of at least the single `model` parameter discussed above.
Returns
-------
cls : class
A :class:`ModelFunction`-derived class initialized by
`cls(model, ...)` where `model` is a Model, and `...` are
optional additional arguments passed to `fn`.
"""
class GSFTemp(ModelFunction):
""" ModelFunction class created by modelfn_factory """
def __init__(self, model, *args, **kwargs):
"""
Creates a new ModelFunction dependent on all of its Model
argument's paramters
"""
self.args = args
self.kwargs = kwargs
ModelFunction.__init__(self, model, ["all"])
def evaluate(self, model):
""" Evaluate this gate-set-function at `model`."""
return fn(model, *self.args, **self.kwargs)
GSFTemp.__name__ = fn.__name__ + str("_class")
return GSFTemp