sinter 1.15.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sinter might be problematic. Click here for more details.
- sinter/__init__.py +47 -0
- sinter/_collection/__init__.py +10 -0
- sinter/_collection/_collection.py +480 -0
- sinter/_collection/_collection_manager.py +581 -0
- sinter/_collection/_collection_manager_test.py +287 -0
- sinter/_collection/_collection_test.py +317 -0
- sinter/_collection/_collection_worker_loop.py +35 -0
- sinter/_collection/_collection_worker_state.py +259 -0
- sinter/_collection/_collection_worker_test.py +222 -0
- sinter/_collection/_mux_sampler.py +56 -0
- sinter/_collection/_printer.py +65 -0
- sinter/_collection/_sampler_ramp_throttled.py +66 -0
- sinter/_collection/_sampler_ramp_throttled_test.py +144 -0
- sinter/_command/__init__.py +0 -0
- sinter/_command/_main.py +39 -0
- sinter/_command/_main_collect.py +350 -0
- sinter/_command/_main_collect_test.py +482 -0
- sinter/_command/_main_combine.py +84 -0
- sinter/_command/_main_combine_test.py +153 -0
- sinter/_command/_main_plot.py +817 -0
- sinter/_command/_main_plot_test.py +445 -0
- sinter/_command/_main_predict.py +75 -0
- sinter/_command/_main_predict_test.py +36 -0
- sinter/_data/__init__.py +20 -0
- sinter/_data/_anon_task_stats.py +89 -0
- sinter/_data/_anon_task_stats_test.py +35 -0
- sinter/_data/_collection_options.py +106 -0
- sinter/_data/_collection_options_test.py +24 -0
- sinter/_data/_csv_out.py +74 -0
- sinter/_data/_existing_data.py +173 -0
- sinter/_data/_existing_data_test.py +41 -0
- sinter/_data/_task.py +311 -0
- sinter/_data/_task_stats.py +244 -0
- sinter/_data/_task_stats_test.py +140 -0
- sinter/_data/_task_test.py +38 -0
- sinter/_decoding/__init__.py +16 -0
- sinter/_decoding/_decoding.py +419 -0
- sinter/_decoding/_decoding_all_built_in_decoders.py +25 -0
- sinter/_decoding/_decoding_decoder_class.py +161 -0
- sinter/_decoding/_decoding_fusion_blossom.py +193 -0
- sinter/_decoding/_decoding_mwpf.py +302 -0
- sinter/_decoding/_decoding_pymatching.py +81 -0
- sinter/_decoding/_decoding_test.py +480 -0
- sinter/_decoding/_decoding_vacuous.py +38 -0
- sinter/_decoding/_perfectionist_sampler.py +38 -0
- sinter/_decoding/_sampler.py +72 -0
- sinter/_decoding/_stim_then_decode_sampler.py +222 -0
- sinter/_decoding/_stim_then_decode_sampler_test.py +192 -0
- sinter/_plotting.py +619 -0
- sinter/_plotting_test.py +108 -0
- sinter/_predict.py +381 -0
- sinter/_predict_test.py +227 -0
- sinter/_probability_util.py +519 -0
- sinter/_probability_util_test.py +281 -0
- sinter-1.15.0.data/data/README.md +332 -0
- sinter-1.15.0.data/data/readme_example_plot.png +0 -0
- sinter-1.15.0.data/data/requirements.txt +4 -0
- sinter-1.15.0.dist-info/METADATA +354 -0
- sinter-1.15.0.dist-info/RECORD +62 -0
- sinter-1.15.0.dist-info/WHEEL +5 -0
- sinter-1.15.0.dist-info/entry_points.txt +2 -0
- sinter-1.15.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import io
|
|
3
|
+
import pathlib
|
|
4
|
+
import tempfile
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from sinter._command._main import main
|
|
8
|
+
from sinter._command._main_plot import _log_ticks, _sqrt_ticks
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_main_plot():
|
|
12
|
+
with tempfile.TemporaryDirectory() as d:
|
|
13
|
+
d = pathlib.Path(d)
|
|
14
|
+
with open(d / f'input.csv', 'w') as f:
|
|
15
|
+
print("""
|
|
16
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
17
|
+
300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""path"":""a.stim""}"
|
|
18
|
+
300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""path"":""a.stim""}"
|
|
19
|
+
9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,"{""path"":""b.stim""}"
|
|
20
|
+
""".strip(), file=f)
|
|
21
|
+
|
|
22
|
+
out = io.StringIO()
|
|
23
|
+
with contextlib.redirect_stdout(out):
|
|
24
|
+
main(command_line_args=[
|
|
25
|
+
"plot",
|
|
26
|
+
"--in",
|
|
27
|
+
str(d / "input.csv"),
|
|
28
|
+
"--out",
|
|
29
|
+
str(d / "output.png"),
|
|
30
|
+
"--x_func",
|
|
31
|
+
"int('a' in metadata['path'])",
|
|
32
|
+
"--group_func",
|
|
33
|
+
"decoder",
|
|
34
|
+
"--ymin",
|
|
35
|
+
"1e-3",
|
|
36
|
+
"--title",
|
|
37
|
+
"test_plot",
|
|
38
|
+
])
|
|
39
|
+
assert (d / "output.png").exists()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_main_plot_2():
|
|
43
|
+
with tempfile.TemporaryDirectory() as d:
|
|
44
|
+
d = pathlib.Path(d)
|
|
45
|
+
with open(d / f'input.csv', 'w') as f:
|
|
46
|
+
print("""
|
|
47
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
48
|
+
300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""path"":""a.stim""}"
|
|
49
|
+
300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""path"":""a.stim""}"
|
|
50
|
+
9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,"{""path"":""b.stim""}"
|
|
51
|
+
""".strip(), file=f)
|
|
52
|
+
|
|
53
|
+
out = io.StringIO()
|
|
54
|
+
with contextlib.redirect_stdout(out):
|
|
55
|
+
main(command_line_args=[
|
|
56
|
+
"plot",
|
|
57
|
+
"--in",
|
|
58
|
+
str(d / "input.csv"),
|
|
59
|
+
"--out",
|
|
60
|
+
str(d / "output.png"),
|
|
61
|
+
"--x_func",
|
|
62
|
+
"int('a' in metadata['path'])",
|
|
63
|
+
"--group_func",
|
|
64
|
+
"decoder",
|
|
65
|
+
"--plot_args_func",
|
|
66
|
+
"{'lw': 2, 'color': 'r' if decoder == 'never' else 'b'}",
|
|
67
|
+
])
|
|
68
|
+
assert (d / "output.png").exists()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_main_plot_failure_units():
|
|
72
|
+
with tempfile.TemporaryDirectory() as d:
|
|
73
|
+
d = pathlib.Path(d)
|
|
74
|
+
with open(d / f'input.csv', 'w') as f:
|
|
75
|
+
print("""
|
|
76
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
77
|
+
300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""r"":15,""d"":5}"
|
|
78
|
+
300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf7,"{""r"":9,""d"":3}"
|
|
79
|
+
9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,"{""r"":6,""d"":2}"
|
|
80
|
+
""".strip(), file=f)
|
|
81
|
+
|
|
82
|
+
out = io.StringIO()
|
|
83
|
+
with pytest.raises(ValueError, match="specified together"):
|
|
84
|
+
main(command_line_args=[
|
|
85
|
+
"plot",
|
|
86
|
+
"--in",
|
|
87
|
+
str(d / "input.csv"),
|
|
88
|
+
"--out",
|
|
89
|
+
str(d / "output.png"),
|
|
90
|
+
"--x_func",
|
|
91
|
+
"metadata['d']",
|
|
92
|
+
"--group_func",
|
|
93
|
+
"decoder",
|
|
94
|
+
"--failure_units_per_shot_func",
|
|
95
|
+
"metadata['r']",
|
|
96
|
+
])
|
|
97
|
+
with pytest.raises(ValueError, match="specified together"):
|
|
98
|
+
main(command_line_args=[
|
|
99
|
+
"plot",
|
|
100
|
+
"--in",
|
|
101
|
+
str(d / "input.csv"),
|
|
102
|
+
"--out",
|
|
103
|
+
str(d / "output.png"),
|
|
104
|
+
"--x_func",
|
|
105
|
+
"metadata['d']",
|
|
106
|
+
"--group_func",
|
|
107
|
+
"decoder",
|
|
108
|
+
"--failure_unit_name",
|
|
109
|
+
"Rounds",
|
|
110
|
+
])
|
|
111
|
+
assert not (d / "output.png").exists()
|
|
112
|
+
with contextlib.redirect_stdout(out):
|
|
113
|
+
main(command_line_args=[
|
|
114
|
+
"plot",
|
|
115
|
+
"--in",
|
|
116
|
+
str(d / "input.csv"),
|
|
117
|
+
"--out",
|
|
118
|
+
str(d / "output.png"),
|
|
119
|
+
"--x_func",
|
|
120
|
+
"metadata['d']",
|
|
121
|
+
"--group_func",
|
|
122
|
+
"decoder",
|
|
123
|
+
"--failure_units_per_shot_func",
|
|
124
|
+
"metadata['r']",
|
|
125
|
+
"--failure_unit_name",
|
|
126
|
+
"Rounds",
|
|
127
|
+
])
|
|
128
|
+
assert (d / "output.png").exists()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_main_plot_xaxis():
|
|
132
|
+
with tempfile.TemporaryDirectory() as d:
|
|
133
|
+
d = pathlib.Path(d)
|
|
134
|
+
with open(d / f'input.csv', 'w') as f:
|
|
135
|
+
print("""
|
|
136
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
137
|
+
300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""r"":15,""d"":5}"
|
|
138
|
+
300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf7,"{""r"":9,""d"":3}"
|
|
139
|
+
9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,"{""r"":6,""d"":2}"
|
|
140
|
+
""".strip(), file=f)
|
|
141
|
+
|
|
142
|
+
out = io.StringIO()
|
|
143
|
+
with contextlib.redirect_stdout(out):
|
|
144
|
+
main(command_line_args=[
|
|
145
|
+
"plot",
|
|
146
|
+
"--in",
|
|
147
|
+
str(d / "input.csv"),
|
|
148
|
+
"--out",
|
|
149
|
+
str(d / "output.png"),
|
|
150
|
+
"--x_func",
|
|
151
|
+
"metadata['d']",
|
|
152
|
+
"--xaxis",
|
|
153
|
+
"[sqrt]distance root",
|
|
154
|
+
])
|
|
155
|
+
assert (d / "output.png").exists()
|
|
156
|
+
|
|
157
|
+
with contextlib.redirect_stdout(out):
|
|
158
|
+
main(command_line_args=[
|
|
159
|
+
"plot",
|
|
160
|
+
"--in",
|
|
161
|
+
str(d / "input.csv"),
|
|
162
|
+
"--out",
|
|
163
|
+
str(d / "output2.png"),
|
|
164
|
+
"--x_func",
|
|
165
|
+
"metadata['d']",
|
|
166
|
+
"--xaxis",
|
|
167
|
+
"[log]distance log",
|
|
168
|
+
])
|
|
169
|
+
assert (d / "output2.png").exists()
|
|
170
|
+
|
|
171
|
+
with contextlib.redirect_stdout(out):
|
|
172
|
+
main(command_line_args=[
|
|
173
|
+
"plot",
|
|
174
|
+
"--in",
|
|
175
|
+
str(d / "input.csv"),
|
|
176
|
+
"--out",
|
|
177
|
+
str(d / "output3.png"),
|
|
178
|
+
"--x_func",
|
|
179
|
+
"metadata['d']",
|
|
180
|
+
"--xaxis",
|
|
181
|
+
"distance raw",
|
|
182
|
+
])
|
|
183
|
+
assert (d / "output3.png").exists()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_main_plot_custom_y_func():
|
|
187
|
+
with tempfile.TemporaryDirectory() as d:
|
|
188
|
+
d = pathlib.Path(d)
|
|
189
|
+
with open(d / f'input.csv', 'w') as f:
|
|
190
|
+
print("""
|
|
191
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
192
|
+
300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,"{""r"":15,""d"":5}"
|
|
193
|
+
300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf7,"{""r"":9,""d"":3}"
|
|
194
|
+
9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,"{""r"":6,""d"":2}"
|
|
195
|
+
""".strip(), file=f)
|
|
196
|
+
|
|
197
|
+
out = io.StringIO()
|
|
198
|
+
with pytest.raises(AttributeError, match="secondsX"):
|
|
199
|
+
main(command_line_args=[
|
|
200
|
+
"plot",
|
|
201
|
+
"--in",
|
|
202
|
+
str(d / "input.csv"),
|
|
203
|
+
"--out",
|
|
204
|
+
str(d / "output.png"),
|
|
205
|
+
"--x_func",
|
|
206
|
+
"metadata['d']",
|
|
207
|
+
"--group_func",
|
|
208
|
+
"decoder",
|
|
209
|
+
"--y_func",
|
|
210
|
+
"stat.secondsX",
|
|
211
|
+
"--yaxis",
|
|
212
|
+
"test axis"
|
|
213
|
+
])
|
|
214
|
+
assert not (d / "output.png").exists()
|
|
215
|
+
with contextlib.redirect_stdout(out):
|
|
216
|
+
main(command_line_args=[
|
|
217
|
+
"plot",
|
|
218
|
+
"--in",
|
|
219
|
+
str(d / "input.csv"),
|
|
220
|
+
"--out",
|
|
221
|
+
str(d / "output.png"),
|
|
222
|
+
"--x_func",
|
|
223
|
+
"metadata['d']",
|
|
224
|
+
"--group_func",
|
|
225
|
+
"decoder",
|
|
226
|
+
"--y_func",
|
|
227
|
+
"stat.seconds",
|
|
228
|
+
"--yaxis",
|
|
229
|
+
"test axis"
|
|
230
|
+
])
|
|
231
|
+
assert (d / "output.png").exists()
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_log_ticks():
|
|
235
|
+
assert _log_ticks(12, 499) == (
|
|
236
|
+
10,
|
|
237
|
+
1000,
|
|
238
|
+
[10, 100, 1000],
|
|
239
|
+
[20, 30, 40, 50, 60, 70, 80, 90, 200, 300, 400, 500, 600, 700, 800, 900],
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
assert _log_ticks(1.2, 4.9) == (
|
|
243
|
+
1,
|
|
244
|
+
10,
|
|
245
|
+
[1, 10],
|
|
246
|
+
[2, 3, 4, 5, 6, 7, 8, 9],
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def test_sqrt_ticks():
|
|
251
|
+
assert _sqrt_ticks(12, 499) == (
|
|
252
|
+
0,
|
|
253
|
+
500,
|
|
254
|
+
[0, 100, 200, 300, 400, 500],
|
|
255
|
+
[10*k for k in range(51)],
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
assert _sqrt_ticks(105, 499) == (
|
|
259
|
+
100,
|
|
260
|
+
500,
|
|
261
|
+
[100, 200, 300, 400, 500],
|
|
262
|
+
[10*k for k in range(10, 51)],
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
assert _sqrt_ticks(305, 590) == (
|
|
266
|
+
300,
|
|
267
|
+
600,
|
|
268
|
+
[300, 350, 400, 450, 500, 550, 600],
|
|
269
|
+
[10*k for k in range(30, 61)],
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
assert _sqrt_ticks(305000, 590000) == (
|
|
273
|
+
300000,
|
|
274
|
+
600000,
|
|
275
|
+
[300000, 350000, 400000, 450000, 500000, 550000, 600000],
|
|
276
|
+
[10000*k for k in range(30, 61)],
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def test_main_plot_degenerate_data():
|
|
281
|
+
with tempfile.TemporaryDirectory() as d:
|
|
282
|
+
d = pathlib.Path(d)
|
|
283
|
+
with open(d / f'input.csv', 'w') as f:
|
|
284
|
+
print("""
|
|
285
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
286
|
+
100, 0, 0, 1.00,magical,000000000,"{}"
|
|
287
|
+
""".strip(), file=f)
|
|
288
|
+
|
|
289
|
+
main(command_line_args=[
|
|
290
|
+
"plot",
|
|
291
|
+
"--in",
|
|
292
|
+
str(d / "input.csv"),
|
|
293
|
+
"--out",
|
|
294
|
+
str(d / "output.png"),
|
|
295
|
+
])
|
|
296
|
+
assert (d / "output.png").exists()
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def test_main_plot_degenerate_data_sqrt_axis():
|
|
300
|
+
with tempfile.TemporaryDirectory() as d:
|
|
301
|
+
d = pathlib.Path(d)
|
|
302
|
+
with open(d / f'input.csv', 'w') as f:
|
|
303
|
+
print("""
|
|
304
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
305
|
+
100, 0, 0, 1.00,magical,000000000,"{}"
|
|
306
|
+
""".strip(), file=f)
|
|
307
|
+
|
|
308
|
+
main(command_line_args=[
|
|
309
|
+
"plot",
|
|
310
|
+
"--in",
|
|
311
|
+
str(d / "input.csv"),
|
|
312
|
+
"--out",
|
|
313
|
+
str(d / "output.png"),
|
|
314
|
+
"--xaxis",
|
|
315
|
+
"[sqrt]x",
|
|
316
|
+
])
|
|
317
|
+
assert (d / "output.png").exists()
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def test_failure_values_func():
|
|
321
|
+
with tempfile.TemporaryDirectory() as d:
|
|
322
|
+
d = pathlib.Path(d)
|
|
323
|
+
with open(d / f'input.csv', 'w') as f:
|
|
324
|
+
print("""
|
|
325
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
326
|
+
1000, 400, 0, 1.00,magical,000000001,"{""f"":1}"
|
|
327
|
+
1000, 400, 0, 1.00,magical,000000002,"{""f"":2}"
|
|
328
|
+
1000, 400, 0, 1.00,magical,000000003,"{""f"":3}"
|
|
329
|
+
1000, 400, 0, 1.00,magical,000000005,"{""f"":5}"
|
|
330
|
+
""".strip(), file=f)
|
|
331
|
+
|
|
332
|
+
main(command_line_args=[
|
|
333
|
+
"plot",
|
|
334
|
+
"--in",
|
|
335
|
+
str(d / "input.csv"),
|
|
336
|
+
"--out",
|
|
337
|
+
str(d / "output.png"),
|
|
338
|
+
"--xaxis",
|
|
339
|
+
"values",
|
|
340
|
+
"--x_func",
|
|
341
|
+
"metadata['f']",
|
|
342
|
+
"--subtitle",
|
|
343
|
+
"test",
|
|
344
|
+
"--failure_values_func",
|
|
345
|
+
"metadata['f']",
|
|
346
|
+
"--failure_units_per_shot_func",
|
|
347
|
+
"100",
|
|
348
|
+
"--failure_unit_name",
|
|
349
|
+
"rounds",
|
|
350
|
+
])
|
|
351
|
+
assert (d / "output.png").exists()
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def test_m_fields():
|
|
355
|
+
with tempfile.TemporaryDirectory() as d:
|
|
356
|
+
d = pathlib.Path(d)
|
|
357
|
+
with open(d / f'input.csv', 'w') as f:
|
|
358
|
+
print("""
|
|
359
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata
|
|
360
|
+
1000, 400, 0, 1.00,magical,000000001,"{""f"":1}"
|
|
361
|
+
1000, 400, 0, 1.00,magical,000000002,"{""f"":2}"
|
|
362
|
+
1000, 400, 0, 1.00,magical,000000003,"{""f"":3}"
|
|
363
|
+
1000, 400, 0, 1.00,magical,000000005,"{""f"":5}"
|
|
364
|
+
""".strip(), file=f)
|
|
365
|
+
|
|
366
|
+
main(command_line_args=[
|
|
367
|
+
"plot",
|
|
368
|
+
"--in",
|
|
369
|
+
str(d / "input.csv"),
|
|
370
|
+
"--out",
|
|
371
|
+
str(d / "output.png"),
|
|
372
|
+
"--xaxis",
|
|
373
|
+
"values",
|
|
374
|
+
"--x_func",
|
|
375
|
+
"m.f",
|
|
376
|
+
"--group_func",
|
|
377
|
+
"m.g",
|
|
378
|
+
"--subtitle",
|
|
379
|
+
"test",
|
|
380
|
+
])
|
|
381
|
+
assert (d / "output.png").exists()
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def test_split_custom_counts():
|
|
385
|
+
with tempfile.TemporaryDirectory() as d:
|
|
386
|
+
d = pathlib.Path(d)
|
|
387
|
+
with open(d / f'input.csv', 'w') as f:
|
|
388
|
+
print("""
|
|
389
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata,custom_counts
|
|
390
|
+
1000, 400, 0, 1.00,magical,000000001,"{""f"":1}",
|
|
391
|
+
1000, 400, 0, 1.00,magical,000000002,"{""f"":2}","{""a"":3}"
|
|
392
|
+
1000, 400, 0, 1.00,magical,000000003,"{""f"":3}","{""b"":3,""c"":4}"
|
|
393
|
+
1000, 400, 0, 1.00,magical,000000005,"{""f"":5}",
|
|
394
|
+
""".strip(), file=f)
|
|
395
|
+
|
|
396
|
+
main(command_line_args=[
|
|
397
|
+
"plot",
|
|
398
|
+
"--in",
|
|
399
|
+
str(d / "input.csv"),
|
|
400
|
+
"--out",
|
|
401
|
+
str(d / "output.png"),
|
|
402
|
+
"--xaxis",
|
|
403
|
+
"values",
|
|
404
|
+
"--x_func",
|
|
405
|
+
"m.f",
|
|
406
|
+
"--group_func",
|
|
407
|
+
"m.g",
|
|
408
|
+
"--subtitle",
|
|
409
|
+
"test",
|
|
410
|
+
"--custom_error_count_keys",
|
|
411
|
+
"a",
|
|
412
|
+
"b",
|
|
413
|
+
])
|
|
414
|
+
assert (d / "output.png").exists()
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def test_line_fits():
|
|
418
|
+
with tempfile.TemporaryDirectory() as d:
|
|
419
|
+
d = pathlib.Path(d)
|
|
420
|
+
with open(d / f'input.csv', 'w') as f:
|
|
421
|
+
print("""
|
|
422
|
+
shots,errors,discards,seconds,decoder,strong_id,json_metadata,custom_counts
|
|
423
|
+
1000, 400, 0, 1.00,magical,000000001,"{""a"":1,""b"":1}",
|
|
424
|
+
1000, 400, 0, 1.00,magical,000000002,"{""a"":2,""b"":1}"
|
|
425
|
+
""".strip(), file=f)
|
|
426
|
+
|
|
427
|
+
main(command_line_args=[
|
|
428
|
+
"plot",
|
|
429
|
+
"--in",
|
|
430
|
+
str(d / "input.csv"),
|
|
431
|
+
"--out",
|
|
432
|
+
str(d / "output.png"),
|
|
433
|
+
"--xaxis",
|
|
434
|
+
"values",
|
|
435
|
+
"--x_func",
|
|
436
|
+
"m.a",
|
|
437
|
+
"--group_func",
|
|
438
|
+
"m.b",
|
|
439
|
+
"--xmin",
|
|
440
|
+
"0",
|
|
441
|
+
"--xmax",
|
|
442
|
+
"10",
|
|
443
|
+
"--line_fits"
|
|
444
|
+
])
|
|
445
|
+
assert (d / "output.png").exists()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from sinter._predict import predict_on_disk
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_args(args: List[str]) -> Any:
|
|
9
|
+
parser = argparse.ArgumentParser(
|
|
10
|
+
description='Predict observable flips from detector data.',
|
|
11
|
+
prog='sinter predict',
|
|
12
|
+
)
|
|
13
|
+
parser.add_argument('--dets',
|
|
14
|
+
type=str,
|
|
15
|
+
required=True,
|
|
16
|
+
help='File to read detection event data from.')
|
|
17
|
+
parser.add_argument('--dets_format',
|
|
18
|
+
type=str,
|
|
19
|
+
required=True,
|
|
20
|
+
help='Format detection event data is stored in.\n'
|
|
21
|
+
'For example: b8 or 01')
|
|
22
|
+
parser.add_argument('--dem',
|
|
23
|
+
type=str,
|
|
24
|
+
required=True,
|
|
25
|
+
help='File to read detector error model from.')
|
|
26
|
+
parser.add_argument('--decoder',
|
|
27
|
+
type=str,
|
|
28
|
+
required=True,
|
|
29
|
+
help='Decoder to use.')
|
|
30
|
+
parser.add_argument('--obs_out',
|
|
31
|
+
type=str,
|
|
32
|
+
required=True,
|
|
33
|
+
help='Location to write predictions from decoder.')
|
|
34
|
+
parser.add_argument('--obs_out_format',
|
|
35
|
+
type=str,
|
|
36
|
+
required=True,
|
|
37
|
+
help='Format to write predictions in.')
|
|
38
|
+
|
|
39
|
+
parser.add_argument('--postselect_detectors_with_non_zero_4th_coord',
|
|
40
|
+
help='Turns on postselection. '
|
|
41
|
+
'If any detector with a non-zero 4th coordinate fires, the shot is discarded.',
|
|
42
|
+
action='store_true')
|
|
43
|
+
parser.add_argument('--discards_out',
|
|
44
|
+
type=str,
|
|
45
|
+
default=None,
|
|
46
|
+
help='Location to write whether each shot should be discarded.'
|
|
47
|
+
'Specified if and only if --postselect_detectors_with_non_zero_4th_coord.')
|
|
48
|
+
parser.add_argument('--discards_out_format',
|
|
49
|
+
type=str,
|
|
50
|
+
default=None,
|
|
51
|
+
help='Format to write discard data in.'
|
|
52
|
+
'Specified if and only if --postselect_detectors_with_non_zero_4th_coord.')
|
|
53
|
+
result = parser.parse_args(args)
|
|
54
|
+
|
|
55
|
+
if result.postselect_detectors_with_non_zero_4th_coord and result.discards_out is None:
|
|
56
|
+
raise ValueError("Must specify --discards_out to record results of --postselect_detectors_with_non_zero_4th_coord.")
|
|
57
|
+
if result.discards_out is not None and result.discards_out_format is None:
|
|
58
|
+
raise ValueError("Must specify --discards_out_format to specify how to record results of --discards_out.")
|
|
59
|
+
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def main_predict(*, command_line_args: List[str]):
|
|
64
|
+
parsed = parse_args(command_line_args)
|
|
65
|
+
predict_on_disk(
|
|
66
|
+
decoder=parsed.decoder,
|
|
67
|
+
dem_path=parsed.dem,
|
|
68
|
+
dets_path=parsed.dets,
|
|
69
|
+
dets_format=parsed.dets_format,
|
|
70
|
+
obs_out_path=parsed.obs_out,
|
|
71
|
+
obs_out_format=parsed.obs_out_format,
|
|
72
|
+
postselect_detectors_with_non_zero_4th_coord=parsed.postselect_detectors_with_non_zero_4th_coord,
|
|
73
|
+
discards_out_path=parsed.discards_out,
|
|
74
|
+
discards_out_format=parsed.discards_out_format,
|
|
75
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
import tempfile
|
|
3
|
+
|
|
4
|
+
from sinter._command._main import main
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_main_predict():
|
|
8
|
+
with tempfile.TemporaryDirectory() as d:
|
|
9
|
+
d = pathlib.Path(d)
|
|
10
|
+
with open(d / f'input.dets', 'w') as f:
|
|
11
|
+
print("""
|
|
12
|
+
shot D0
|
|
13
|
+
shot
|
|
14
|
+
""", file=f)
|
|
15
|
+
with open(d / f'input.dem', 'w') as f:
|
|
16
|
+
print("""
|
|
17
|
+
error(0.1) D0 L0
|
|
18
|
+
""", file=f)
|
|
19
|
+
|
|
20
|
+
main(command_line_args=[
|
|
21
|
+
"predict",
|
|
22
|
+
"--dets",
|
|
23
|
+
str(d / "input.dets"),
|
|
24
|
+
"--dem",
|
|
25
|
+
str(d / "input.dem"),
|
|
26
|
+
"--decoder",
|
|
27
|
+
"pymatching",
|
|
28
|
+
"--dets_format",
|
|
29
|
+
"dets",
|
|
30
|
+
"--obs_out",
|
|
31
|
+
str(d / "output.01"),
|
|
32
|
+
"--obs_out_format",
|
|
33
|
+
"01",
|
|
34
|
+
])
|
|
35
|
+
with open(d / 'output.01') as f:
|
|
36
|
+
assert f.read() == '1\n0\n'
|
sinter/_data/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from sinter._data._anon_task_stats import (
|
|
2
|
+
AnonTaskStats,
|
|
3
|
+
)
|
|
4
|
+
from sinter._data._collection_options import (
|
|
5
|
+
CollectionOptions,
|
|
6
|
+
)
|
|
7
|
+
from sinter._data._csv_out import (
|
|
8
|
+
CSV_HEADER,
|
|
9
|
+
)
|
|
10
|
+
from sinter._data._existing_data import (
|
|
11
|
+
read_stats_from_csv_files,
|
|
12
|
+
stats_from_csv_files,
|
|
13
|
+
ExistingData,
|
|
14
|
+
)
|
|
15
|
+
from sinter._data._task import (
|
|
16
|
+
Task,
|
|
17
|
+
)
|
|
18
|
+
from sinter._data._task_stats import (
|
|
19
|
+
TaskStats,
|
|
20
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import dataclasses
|
|
3
|
+
from typing import Counter, Union, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from sinter._data._task_stats import TaskStats
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclasses.dataclass(frozen=True)
|
|
10
|
+
class AnonTaskStats:
|
|
11
|
+
"""Statistics sampled from an unspecified task.
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
shots: Number of times the task was sampled.
|
|
15
|
+
errors: Number of times a sample resulted in an error.
|
|
16
|
+
discards: Number of times a sample resulted in a discard. Note that
|
|
17
|
+
discarded a task is not an error.
|
|
18
|
+
seconds: The amount of CPU core time spent sampling the tasks, in
|
|
19
|
+
seconds.
|
|
20
|
+
custom_counts: A counter mapping string keys to integer values. Used for
|
|
21
|
+
tracking arbitrary values, such as per-observable error counts or
|
|
22
|
+
the number of times detectors fired. The meaning of the information
|
|
23
|
+
in the counts is not specified; the only requirement is that it
|
|
24
|
+
should be correct to add each key's counts when merging statistics.
|
|
25
|
+
|
|
26
|
+
Although this field is an editable object, it's invalid to edit the
|
|
27
|
+
counter after the stats object is initialized.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
shots: int = 0
|
|
31
|
+
errors: int = 0
|
|
32
|
+
discards: int = 0
|
|
33
|
+
seconds: float = 0
|
|
34
|
+
custom_counts: Counter[str] = dataclasses.field(default_factory=collections.Counter)
|
|
35
|
+
|
|
36
|
+
def __post_init__(self):
|
|
37
|
+
assert isinstance(self.errors, int)
|
|
38
|
+
assert isinstance(self.shots, int)
|
|
39
|
+
assert isinstance(self.discards, int)
|
|
40
|
+
assert isinstance(self.seconds, (int, float))
|
|
41
|
+
assert isinstance(self.custom_counts, collections.Counter)
|
|
42
|
+
assert self.errors >= 0
|
|
43
|
+
assert self.discards >= 0
|
|
44
|
+
assert self.seconds >= 0
|
|
45
|
+
assert self.shots >= self.errors + self.discards
|
|
46
|
+
assert all(isinstance(k, str) and isinstance(v, int) for k, v in self.custom_counts.items())
|
|
47
|
+
|
|
48
|
+
def __repr__(self) -> str:
|
|
49
|
+
terms = []
|
|
50
|
+
if self.shots != 0:
|
|
51
|
+
terms.append(f'shots={self.shots!r}')
|
|
52
|
+
if self.errors != 0:
|
|
53
|
+
terms.append(f'errors={self.errors!r}')
|
|
54
|
+
if self.discards != 0:
|
|
55
|
+
terms.append(f'discards={self.discards!r}')
|
|
56
|
+
if self.seconds != 0:
|
|
57
|
+
terms.append(f'seconds={self.seconds!r}')
|
|
58
|
+
if self.custom_counts:
|
|
59
|
+
terms.append(f'custom_counts={self.custom_counts!r}')
|
|
60
|
+
return f'sinter.AnonTaskStats({", ".join(terms)})'
|
|
61
|
+
|
|
62
|
+
def __add__(self, other: 'AnonTaskStats') -> 'AnonTaskStats':
|
|
63
|
+
"""Returns the sum of the statistics from both anonymous stats.
|
|
64
|
+
|
|
65
|
+
Adds the shots, the errors, the discards, and the seconds.
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
>>> import sinter
|
|
69
|
+
>>> a = sinter.AnonTaskStats(
|
|
70
|
+
... shots=100,
|
|
71
|
+
... errors=20,
|
|
72
|
+
... )
|
|
73
|
+
>>> b = sinter.AnonTaskStats(
|
|
74
|
+
... shots=1000,
|
|
75
|
+
... errors=200,
|
|
76
|
+
... )
|
|
77
|
+
>>> a + b
|
|
78
|
+
sinter.AnonTaskStats(shots=1100, errors=220)
|
|
79
|
+
"""
|
|
80
|
+
if isinstance(other, AnonTaskStats):
|
|
81
|
+
return AnonTaskStats(
|
|
82
|
+
shots=self.shots + other.shots,
|
|
83
|
+
errors=self.errors + other.errors,
|
|
84
|
+
discards=self.discards + other.discards,
|
|
85
|
+
seconds=self.seconds + other.seconds,
|
|
86
|
+
custom_counts=self.custom_counts + other.custom_counts,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return NotImplemented
|