/
test_composed_spam.py
257 lines (201 loc) · 9.46 KB
/
test_composed_spam.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
import numpy as np
import unittest
from ..util import BaseCase
from pygsti.circuits import Circuit
from pygsti.models import ExplicitOpModel
from pygsti.modelmembers.states import ComposedState
from pygsti.modelmembers.povms import ComposedPOVM
from pygsti.models.gaugegroup import FullGaugeGroupElement, UnitaryGaugeGroupElement
import pygsti.baseobjs.outcomelabeldict as ld
import pygsti.modelmembers.operations as op
import pygsti.modelmembers.povms as pv
import pygsti.modelmembers.states as sv
# Main test of ComposedSpamvecBase:
# Is the composed SPAM vec equivalent to applying each component separately?
class ComposedSpamvecBase(object):
base_prep_vec = sv.ComputationalBasisState([0], 'pp', 'default')
base_noise_op = op.StaticStandardOp('Gxpi2', 'pp', 'default') # X(pi/2) rotation as noise
base_povm = pv.ComputationalBasisPOVM(1, 'default') # Z-basis measurement
expected_out = ld.OutcomeLabelDict([(('0',), 0.5), (('1',), 0.5)])
def setUp(self):
self.vec = self.build_vec()
ExplicitOpModel._strict = False
def test_num_params(self):
self.assertEqual(self.vec.num_params, self.n_params)
def test_get_dimension(self):
self.assertEqual(self.vec.dim, 4)
def test_hessian(self):
if self.n_params:
self.assertTrue(self.vec.has_nonzero_hessian())
else:
self.assertFalse(self.vec.has_nonzero_hessian())
def test_forward_simulation(self):
pure_vec = self.vec.state_vec
noise_op = self.vec.error_map
# TODO: Would be nice to check more than densitymx evotype
indep_mdl = ExplicitOpModel(['Q0'], evotype='default')
indep_mdl['rho0'] = pure_vec
indep_mdl['G0'] = noise_op
indep_mdl['Mdefault'] = self.base_povm
indep_mdl.num_params # triggers paramvec rebuild
composed_mdl = ExplicitOpModel(['Q0'], evotype='default')
composed_mdl['rho0'] = self.vec
composed_mdl['Mdefault'] = self.base_povm
composed_mdl.num_params # triggers paramvec rebuild
# Sanity check
indep_circ = Circuit(['rho0', 'G0', 'Mdefault'])
indep_probs = indep_mdl.probabilities(indep_circ)
for k,v in indep_probs.items():
self.assertAlmostEqual(self.expected_out[k], v)
composed_circ = Circuit(['rho0', 'Mdefault'])
composed_probs = composed_mdl.probabilities(composed_circ)
for k,v in composed_probs.items():
self.assertAlmostEqual(self.expected_out[k], v)
# For ComposedSpamvec, the spam vec is immutable (set_value),
# but the noise op can be not (transform, depolarize)
class MutableComposedSpamvecBase(ComposedSpamvecBase):
def test_raises_on_set_value(self):
v = np.asarray(self.vec)
with self.assertRaises(ValueError):
self.vec.set_dense(v)
@unittest.skip("Transform is expected to fail while spam_transform_inplace is not available")
def test_transform(self):
S = FullGaugeGroupElement(np.identity(4, 'd'))
self.vec.transform_inplace(S)
# TODO assert correctness
def test_depolarize(self):
self.vec.depolarize(0.9)
self.vec.depolarize([0.9, 0.8, 0.7])
# TODO assert correctness
class ImmutableComposedSpamvecBase(ComposedSpamvecBase):
def test_raises_on_set_value(self):
v = np.asarray(self.vec)
with self.assertRaises(ValueError):
self.vec.set_dense(v)
@unittest.skip("Transform is expected to fail while spam_transform_inplace is not available")
def test_raises_on_transform(self):
S = FullGaugeGroupElement(np.identity(4, 'd'))
with self.assertRaises(ValueError):
self.vec.transform_inplace(S)
def test_raises_on_depolarize(self):
with self.assertRaises(ValueError):
self.vec.depolarize(0.9)
# TODO assert correctness
# Cases where noise op is also static acts like an immutable spamvec
class StandardStaticComposedSpamvecTester(ImmutableComposedSpamvecBase, BaseCase):
n_params = 0
def build_vec(self):
return ComposedState(self.base_prep_vec, self.base_noise_op)
class StaticDenseComposedSpamvecTester(ImmutableComposedSpamvecBase, BaseCase):
n_params = 0
def build_vec(self):
sdop = op.StaticArbitraryOp(self.base_noise_op.to_dense())
return ComposedState(self.base_prep_vec, sdop)
class FullDenseComposedSpamvecTester(MutableComposedSpamvecBase, BaseCase):
n_params = 16
def build_vec(self):
fdop = op.FullArbitraryOp(self.base_noise_op.to_dense())
return ComposedState(self.base_prep_vec, fdop)
# Currently not inheriting for easy merge, meaning test doesn't quite work
# class LindbladSpamvecTester(MutableComposedSpamvecBase, BaseCase):
# n_params = 12
# # Transform cannot be FullGaugeGroup for Lindblad
# def test_transform(self):
# S = UnitaryGaugeGroupElement(np.identity(4, 'd'))
# self.vec.transform_inplace(S, 'prep')
# self.vec.transform_inplace(S, 'effect')
# def build_vec(self):
# lop = op.LindbladDenseOp.from_operation_matrix(self.base_noise_op.to_dense())
# return sv.LindbladSPAMVec(self.base_prep_vec, lop, 'prep')
## POVM ##
# Main test of ComposedPovmBase:
# Is the composed POVM equivalent to applying each component separately?
class ComposedPovmBase(object):
base_prep = sv.ComputationalBasisState([0], 'pp', 'default') # 0 state prep
base_noise_op = op.StaticStandardOp('Gxpi2', 'pp', 'default') # X(pi/2) rotation as noise
base_povm = pv.ComputationalBasisPOVM(1, 'default') # Z-basis measurement
expected_out = ld.OutcomeLabelDict([(('0',), 0.5), (('1',), 0.5)])
def setUp(self):
self.povm = self.build_povm()
ExplicitOpModel._strict = False
def test_num_params(self):
self.assertEqual(self.povm.num_params, self.n_params)
def test_get_dimension(self):
self.assertEqual(self.povm.state_space.dim, 4)
def test_forward_simulation(self):
pure_povm = self.povm.base_povm
noise_op = self.povm.error_map
# TODO: Would be nice to check more than densitymx evotype
indep_mdl = ExplicitOpModel(['Q0'], evotype='default')
indep_mdl['rho0'] = self.base_prep
indep_mdl['G0'] = noise_op.copy()
indep_mdl['Mdefault'] = pure_povm
indep_mdl._clean_paramvec()
composed_mdl = ExplicitOpModel(['Q0'], evotype='default')
composed_mdl['rho0'] = self.base_prep
composed_mdl['Mdefault'] = self.povm
composed_mdl._clean_paramvec()
# Sanity check
indep_circ = Circuit(['rho0', 'G0', 'Mdefault'])
indep_probs = indep_mdl.probabilities(indep_circ)
for k,v in indep_probs.items():
self.assertAlmostEqual(self.expected_out[k], v)
composed_circ = Circuit(['rho0', 'Mdefault'])
composed_probs = composed_mdl.probabilities(composed_circ)
for k,v in composed_probs.items():
self.assertAlmostEqual(self.expected_out[k], v)
# For ComposedPOVM, the noise op could be mutable
class MutableComposedPovmBase(ComposedPovmBase):
def test_vector_conversion(self):
v = self.povm.to_vector()
self.povm.from_vector(v)
@unittest.skip("Transform is expected to fail while spam_transform_inplace is not available")
def test_transform(self):
S = FullGaugeGroupElement(np.identity(4, 'd'))
self.povm.transform_inplace(S)
# TODO assert correctness
def test_depolarize(self):
self.povm.depolarize(0.9)
self.povm.depolarize([0.9, 0.8, 0.7])
# TODO assert correctness
class ImmutableComposedPovmBase(ComposedPovmBase):
def test_vector_conversion(self):
v = self.povm.to_vector()
self.povm.from_vector(v)
# TODO:
# with self.assertRaises(ValueError):
# self.vec.set_dense(v)
@unittest.skip("Transform is expected to fail while spam_transform_inplace is not available")
def test_raises_on_transform(self):
S = FullGaugeGroupElement(np.identity(4, 'd'))
with self.assertRaises(ValueError):
self.povm.transform_inplace(S)
def test_raises_on_depolarize(self):
with self.assertRaises(ValueError):
self.povm.depolarize(0.9)
# TODO assert correctness
class StandardStaticComposedPovmTester(ImmutableComposedPovmBase, BaseCase):
n_params = 0
def build_povm(self):
return ComposedPOVM(self.base_noise_op, self.base_povm, 'pp')
class StaticDenseComposedPovmTester(ImmutableComposedPovmBase, BaseCase):
n_params = 0
def build_povm(self):
sdop = op.StaticArbitraryOp(self.base_noise_op.to_dense())
return ComposedPOVM(sdop, self.base_povm, 'pp')
class FullDenseComposedPovmTester(MutableComposedPovmBase, BaseCase):
n_params = 16
def build_povm(self):
fdop = op.FullArbitraryOp(self.base_noise_op.to_dense())
return ComposedPOVM(fdop, self.base_povm, 'pp')
# Currently not inheriting for easy merge, meaning test doesn't quite work
# class LindbladPovmTester(MutableComposedPovmBase, BaseCase):
# n_params = 12
# # Transform cannot be FullGaugeGroup for Lindblad
# def test_transform(self):
# S = UnitaryGaugeGroupElement(np.identity(4, 'd'))
# self.povm.transform_inplace(S, 'prep')
# self.povm.transform_inplace(S, 'effect')
# def build_povm(self):
# lop = op.LindbladDenseOp.from_operation_matrix(self.base_noise_op.to_dense())
# return pv.LindbladPOVM(lop, self.base_povm)