microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
brlackey/ising-model-sample

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

samples/notebooks/carbon_error_correction/decoder.py

352lines · modecode

1#!/usr/bin/env python3
2
3# Copyright (c) Microsoft Corporation.
4# Licensed under the MIT License.
5
6import qsharp
7
8table = {
9 frozenset(): "IIIIIIIIIIII",
10 frozenset({3, 8, 9}): "XIIIIIIIIIII",
11 frozenset({0, 3, 6, 7, 8, 9}): "YIIIIIIIIIII",
12 frozenset({0, 6, 7}): "ZIIIIIIIIIII",
13 frozenset({3}): "IXIIIIIIIIII",
14 frozenset({0, 3, 6}): "IYIIIIIIIIII",
15 frozenset({0, 6}): "IZIIIIIIIIII",
16 frozenset({3, 8}): "IIXIIIIIIIII",
17 frozenset({0, 3, 8}): "IIYIIIIIIIII",
18 frozenset({0}): "IIZIIIIIIIII",
19 frozenset({3, 9}): "IIIXIIIIIIII",
20 frozenset({0, 3, 7, 9}): "IIIYIIIIIIII",
21 frozenset({0, 7}): "IIIZIIIIIIII",
22 frozenset({4, 9}): "IIIIXIIIIIII",
23 frozenset({1, 4, 7, 9}): "IIIIYIIIIIII",
24 frozenset({1, 7}): "IIIIZIIIIIII",
25 frozenset({4}): "IIIIIXIIIIII",
26 frozenset({1, 4, 6, 7}): "IIIIIYIIIIII",
27 frozenset({1, 6, 7}): "IIIIIZIIIIII",
28 frozenset({4, 8, 9}): "IIIIIIXIIIII",
29 frozenset({1, 4, 8, 9}): "IIIIIIYIIIII",
30 frozenset({1}): "IIIIIIZIIIII",
31 frozenset({4, 8}): "IIIIIIIXIIII",
32 frozenset({1, 4, 6, 8}): "IIIIIIIYIIII",
33 frozenset({1, 6}): "IIIIIIIZIIII",
34 frozenset({5, 8}): "IIIIIIIIXIII",
35 frozenset({2, 5, 6, 8}): "IIIIIIIIYIII",
36 frozenset({2, 6}): "IIIIIIIIZIII",
37 frozenset({5}): "IIIIIIIIIXII",
38 frozenset({2, 5, 7}): "IIIIIIIIIYII",
39 frozenset({2, 7}): "IIIIIIIIIZII",
40 frozenset({5, 9}): "IIIIIIIIIIXI",
41 frozenset({2, 5, 9}): "IIIIIIIIIIYI",
42 frozenset({2}): "IIIIIIIIIIZI",
43 frozenset({5, 8, 9}): "IIIIIIIIIIIX",
44 frozenset({2, 5, 6, 7, 8, 9}): "IIIIIIIIIIIY",
45 frozenset({2, 6, 7}): "IIIIIIIIIIIZ",
46 frozenset({0, 3, 6, 8, 9}): "XZIIIIIIIIII",
47 frozenset({0, 3, 6, 7}): "ZXIIIIIIIIII",
48 frozenset({0, 3, 8, 9}): "XIZIIIIIIIII",
49 frozenset({0, 3, 6, 7, 8}): "ZIXIIIIIIIII",
50 frozenset({0, 3, 7, 8, 9}): "XIIZIIIIIIII",
51 frozenset({0, 3, 6, 7, 9}): "ZIIXIIIIIIII",
52 frozenset({1, 3, 7, 8, 9}): "XIIIZIIIIIII",
53 frozenset({0, 4, 6, 7, 9}): "ZIIIXIIIIIII",
54 frozenset({1, 3, 6, 7, 8, 9}): "XIIIIZIIIIII",
55 frozenset({0, 4, 6, 7}): "ZIIIIXIIIIII",
56 frozenset({1, 3, 8, 9}): "XIIIIIZIIIII",
57 frozenset({0, 4, 6, 7, 8, 9}): "ZIIIIIXIIIII",
58 frozenset({1, 3, 6, 8, 9}): "XIIIIIIZIIII",
59 frozenset({0, 4, 6, 7, 8}): "ZIIIIIIXIIII",
60 frozenset({2, 3, 6, 8, 9}): "XIIIIIIIZIII",
61 frozenset({0, 5, 6, 7, 8}): "ZIIIIIIIXIII",
62 frozenset({2, 3, 7, 8, 9}): "XIIIIIIIIZII",
63 frozenset({0, 5, 6, 7}): "ZIIIIIIIIXII",
64 frozenset({2, 3, 8, 9}): "XIIIIIIIIIZI",
65 frozenset({0, 5, 6, 7, 9}): "ZIIIIIIIIIXI",
66 frozenset({2, 3, 6, 7, 8, 9}): "XIIIIIIIIIIZ",
67 frozenset({0, 5, 6, 7, 8, 9}): "ZIIIIIIIIIIX",
68 frozenset({0, 3}): "IXZIIIIIIIII",
69 frozenset({0, 3, 6, 8}): "IZXIIIIIIIII",
70 frozenset({0, 3, 7}): "IXIZIIIIIIII",
71 frozenset({0, 3, 6, 9}): "IZIXIIIIIIII",
72 frozenset({1, 3, 7}): "IXIIZIIIIIII",
73 frozenset({0, 4, 6, 9}): "IZIIXIIIIIII",
74 frozenset({1, 3, 6, 7}): "IXIIIZIIIIII",
75 frozenset({0, 4, 6}): "IZIIIXIIIIII",
76 frozenset({1, 3}): "IXIIIIZIIIII",
77 frozenset({0, 4, 6, 8, 9}): "IZIIIIXIIIII",
78 frozenset({1, 3, 6}): "IXIIIIIZIIII",
79 frozenset({0, 4, 6, 8}): "IZIIIIIXIIII",
80 frozenset({2, 3, 6}): "IXIIIIIIZIII",
81 frozenset({0, 5, 6, 8}): "IZIIIIIIXIII",
82 frozenset({2, 3, 7}): "IXIIIIIIIZII",
83 frozenset({0, 5, 6}): "IZIIIIIIIXII",
84 frozenset({2, 3}): "IXIIIIIIIIZI",
85 frozenset({0, 5, 6, 9}): "IZIIIIIIIIXI",
86 frozenset({2, 3, 6, 7}): "IXIIIIIIIIIZ",
87 frozenset({0, 5, 6, 8, 9}): "IZIIIIIIIIIX",
88 frozenset({0, 3, 7, 8}): "IIXZIIIIIIII",
89 frozenset({0, 3, 9}): "IIZXIIIIIIII",
90 frozenset({1, 3, 7, 8}): "IIXIZIIIIIII",
91 frozenset({0, 4, 9}): "IIZIXIIIIIII",
92 frozenset({1, 3, 6, 7, 8}): "IIXIIZIIIIII",
93 frozenset({0, 4}): "IIZIIXIIIIII",
94 frozenset({1, 3, 8}): "IIXIIIZIIIII",
95 frozenset({0, 4, 8, 9}): "IIZIIIXIIIII",
96 frozenset({1, 3, 6, 8}): "IIXIIIIZIIII",
97 frozenset({0, 4, 8}): "IIZIIIIXIIII",
98 frozenset({2, 3, 6, 8}): "IIXIIIIIZIII",
99 frozenset({0, 5, 8}): "IIZIIIIIXIII",
100 frozenset({2, 3, 7, 8}): "IIXIIIIIIZII",
101 frozenset({0, 5}): "IIZIIIIIIXII",
102 frozenset({2, 3, 8}): "IIXIIIIIIIZI",
103 frozenset({0, 5, 9}): "IIZIIIIIIIXI",
104 frozenset({2, 3, 6, 7, 8}): "IIXIIIIIIIIZ",
105 frozenset({0, 5, 8, 9}): "IIZIIIIIIIIX",
106 frozenset({1, 3, 7, 9}): "IIIXZIIIIIII",
107 frozenset({0, 4, 7, 9}): "IIIZXIIIIIII",
108 frozenset({1, 3, 6, 7, 9}): "IIIXIZIIIIII",
109 frozenset({0, 4, 7}): "IIIZIXIIIIII",
110 frozenset({1, 3, 9}): "IIIXIIZIIIII",
111 frozenset({0, 4, 7, 8, 9}): "IIIZIIXIIIII",
112 frozenset({1, 3, 6, 9}): "IIIXIIIZIIII",
113 frozenset({0, 4, 7, 8}): "IIIZIIIXIIII",
114 frozenset({2, 3, 6, 9}): "IIIXIIIIZIII",
115 frozenset({0, 5, 7, 8}): "IIIZIIIIXIII",
116 frozenset({2, 3, 7, 9}): "IIIXIIIIIZII",
117 frozenset({0, 5, 7}): "IIIZIIIIIXII",
118 frozenset({2, 3, 9}): "IIIXIIIIIIZI",
119 frozenset({0, 5, 7, 9}): "IIIZIIIIIIXI",
120 frozenset({2, 3, 6, 7, 9}): "IIIXIIIIIIIZ",
121 frozenset({0, 5, 7, 8, 9}): "IIIZIIIIIIIX",
122 frozenset({1, 4, 6, 7, 9}): "IIIIXZIIIIII",
123 frozenset({1, 4, 7}): "IIIIZXIIIIII",
124 frozenset({1, 4, 9}): "IIIIXIZIIIII",
125 frozenset({1, 4, 7, 8, 9}): "IIIIZIXIIIII",
126 frozenset({1, 4, 6, 9}): "IIIIXIIZIIII",
127 frozenset({1, 4, 7, 8}): "IIIIZIIXIIII",
128 frozenset({2, 4, 6, 9}): "IIIIXIIIZIII",
129 frozenset({1, 5, 7, 8}): "IIIIZIIIXIII",
130 frozenset({2, 4, 7, 9}): "IIIIXIIIIZII",
131 frozenset({1, 5, 7}): "IIIIZIIIIXII",
132 frozenset({2, 4, 9}): "IIIIXIIIIIZI",
133 frozenset({1, 5, 7, 9}): "IIIIZIIIIIXI",
134 frozenset({2, 4, 6, 7, 9}): "IIIIXIIIIIIZ",
135 frozenset({1, 5, 7, 8, 9}): "IIIIZIIIIIIX",
136 frozenset({1, 4}): "IIIIIXZIIIII",
137 frozenset({1, 4, 6, 7, 8, 9}): "IIIIIZXIIIII",
138 frozenset({1, 4, 6}): "IIIIIXIZIIII",
139 frozenset({1, 4, 6, 7, 8}): "IIIIIZIXIIII",
140 frozenset({2, 4, 6}): "IIIIIXIIZIII",
141 frozenset({1, 5, 6, 7, 8}): "IIIIIZIIXIII",
142 frozenset({2, 4, 7}): "IIIIIXIIIZII",
143 frozenset({1, 5, 6, 7}): "IIIIIZIIIXII",
144 frozenset({2, 4}): "IIIIIXIIIIZI",
145 frozenset({1, 5, 6, 7, 9}): "IIIIIZIIIIXI",
146 frozenset({2, 4, 6, 7}): "IIIIIXIIIIIZ",
147 frozenset({1, 5, 6, 7, 8, 9}): "IIIIIZIIIIIX",
148 frozenset({1, 4, 6, 8, 9}): "IIIIIIXZIIII",
149 frozenset({1, 4, 8}): "IIIIIIZXIIII",
150 frozenset({2, 4, 6, 8, 9}): "IIIIIIXIZIII",
151 frozenset({1, 5, 8}): "IIIIIIZIXIII",
152 frozenset({2, 4, 7, 8, 9}): "IIIIIIXIIZII",
153 frozenset({1, 5}): "IIIIIIZIIXII",
154 frozenset({2, 4, 8, 9}): "IIIIIIXIIIZI",
155 frozenset({1, 5, 9}): "IIIIIIZIIIXI",
156 frozenset({2, 4, 6, 7, 8, 9}): "IIIIIIXIIIIZ",
157 frozenset({1, 5, 8, 9}): "IIIIIIZIIIIX",
158 frozenset({2, 4, 6, 8}): "IIIIIIIXZIII",
159 frozenset({1, 5, 6, 8}): "IIIIIIIZXIII",
160 frozenset({2, 4, 7, 8}): "IIIIIIIXIZII",
161 frozenset({1, 5, 6}): "IIIIIIIZIXII",
162 frozenset({2, 4, 8}): "IIIIIIIXIIZI",
163 frozenset({1, 5, 6, 9}): "IIIIIIIZIIXI",
164 frozenset({2, 4, 6, 7, 8}): "IIIIIIIXIIIZ",
165 frozenset({1, 5, 6, 8, 9}): "IIIIIIIZIIIX",
166 frozenset({2, 5, 7, 8}): "IIIIIIIIXZII",
167 frozenset({2, 5, 6}): "IIIIIIIIZXII",
168 frozenset({2, 5, 8}): "IIIIIIIIXIZI",
169 frozenset({2, 5, 6, 9}): "IIIIIIIIZIXI",
170 frozenset({2, 5, 6, 7, 8}): "IIIIIIIIXIIZ",
171 frozenset({2, 5, 6, 8, 9}): "IIIIIIIIZIIX",
172 frozenset({2, 5}): "IIIIIIIIIXZI",
173 frozenset({2, 5, 7, 9}): "IIIIIIIIIZXI",
174 frozenset({2, 5, 6, 7}): "IIIIIIIIIXIZ",
175 frozenset({2, 5, 7, 8, 9}): "IIIIIIIIIZIX",
176 frozenset({2, 5, 6, 7, 9}): "IIIIIIIIIIXZ",
177 frozenset({2, 5, 8, 9}): "IIIIIIIIIIZX",
178}
179
180generators = [
181 "XXXXIIIIIIII",
182 "IIIIXXXXIIII",
183 "IIIIIIIIXXXX",
184 "ZZZZIIIIIIII",
185 "IIIIZZZZIIII",
186 "IIIIIIIIZZZZ",
187 "XXIIIXIXXIIX",
188 "XIIXXXIIIXIX",
189 "ZIZIIIZZZIIZ",
190 "ZIIZZIZIIIZZ",
191]
192
193logical_basis = ["XIIXIIIIIIXX", "ZIIZIIIIIZIZ", "IXIXIIIIIXXI", "ZZIIIIIIIZZI"]
194
195expanded_logical_basis = [
196 "XIIXIIIIIIXX",
197 "ZIIZIIIIIZIZ",
198 "YIIYIIIIIZXY",
199 "IXIXIIIIIXXI",
200 "ZZIIIIIIIZZI",
201 "ZYIXIIIIIYYI",
202]
203
204
205def results_as_pauli(results: list[qsharp.Result], pauli: str = "Z") -> str:
206 p = ""
207 for r in results:
208 if r == qsharp.Result.One:
209 p += pauli
210 else:
211 p += "I"
212 return p
213
214
215def pauli_as_results(p: str, basis: str = "Z", count: int = 2):
216 results = []
217 chars = "XYZ".replace(basis, "")
218 for i in range(count):
219 if p[i] in chars:
220 results.append(qsharp.Result.One)
221 else:
222 results.append(qsharp.Result.Zero)
223 return results
224
225
226def pauli_support(p: str) -> list[int]:
227 return [i for i, char in enumerate(p) if char != "I"]
228
229
230def logical_indexes_of(pauli: str):
231 for qubit in pauli_support(pauli):
232 character = pauli[qubit]
233 if character == "X":
234 yield 3 * qubit
235 if character == "Z":
236 yield 3 * qubit + 1
237 if character == "Y":
238 yield 3 * qubit + 2
239
240
241def commutes_with(pauli1: str, pauli2: str) -> bool:
242 """Check if two Pauli strings commute."""
243 assert len(pauli1) == len(pauli2)
244 anti_commute_count = 0
245 for p1, p2 in zip(pauli1, pauli2):
246 if p1 == "I" or p2 == "I":
247 continue
248 if p1 != p2:
249 anti_commute_count += 1
250 return anti_commute_count % 2 == 0
251
252
253def syndrome_of(error: str) -> list[int]:
254 syndrome = []
255 for label, generator in enumerate(generators):
256 if not commutes_with(error, generator):
257 syndrome.append(label)
258 return syndrome
259
260
261def mult_paulis(p1: str, p2: str) -> str:
262 if len(p1) < len(p2):
263 p1 = p1 + "I" * (len(p2) - len(p1))
264 elif len(p2) < len(p1):
265 p2 = p2 + "I" * (len(p1) - len(p2))
266 result = ""
267 for a, b in zip(p1, p2):
268 if a == "I":
269 result += b
270 elif b == "I":
271 result += a
272 elif a == b:
273 result += "I"
274 elif (a, b) in [("X", "Y"), ("Y", "X")]:
275 result += "Z"
276 elif (a, b) in [("Y", "Z"), ("Z", "Y")]:
277 result += "X"
278 elif (a, b) in [("Z", "X"), ("X", "Z")]:
279 result += "Y"
280 else:
281 raise ValueError(f"Unexpected Pauli characters: {a}, {b}")
282 return result
283
284
285def unsigned_logical_action_of(error: str) -> str:
286 character_of = ("Y", "Z", "X", "I")
287 commutations = list(map(lambda lb: commutes_with(error, lb), logical_basis))
288 indexes = [2 * x + z for x, z in [commutations[0:2], commutations[2:4]]]
289 characters = "".join(character_of[index] for index in indexes)
290 return characters
291
292
293def representative_of(pauli: str) -> str:
294 generators = (expanded_logical_basis[index] for index in logical_indexes_of(pauli))
295 res = "I" * 12
296 for gen in generators:
297 res = mult_paulis(res, gen)
298 return res
299
300
301def logical_action_of(error: str) -> str:
302 logical = unsigned_logical_action_of(error)
303 return logical
304
305
306def recovery_from_syndrome_measurements(
307 x_meas: list[qsharp.Result], z_meas: list[qsharp.Result]
308) -> str:
309 error_z = results_as_pauli(x_meas, pauli="Z")
310 error_x = results_as_pauli(z_meas, pauli="X")
311 error = mult_paulis(error_z, error_x)
312 syndrome = frozenset(syndrome_of(error))
313 recovery = table.get(syndrome, "IIIIIIIIIIII")
314 return logical_action_of(mult_paulis(recovery, error))
315
316
317# For each tuple of shot results, mark the shot as preselect if any preselect
318# measurement is One. Then use the rounds of error correction syndrome measurements
319# to generate Pauli corrections, collected in a frame. Use the final Pauli frame
320# to calculate the corrected logical results.
321def decode_results(results, basis: str = "Z"):
322 corrected_logical_results = []
323 for res in results:
324 corrected_logical_results.append([])
325 for shot in res:
326 if any([preselect == qsharp.Result.One for preselect in shot[0]]):
327 corrected_logical_results[-1] += ["PREselect"]
328 continue
329 recovery = "IIIIIIIIIIII"
330 r = None
331 for ec_output in shot[1]:
332 r = recovery_from_syndrome_measurements(ec_output[0], ec_output[1])
333 if r is None:
334 corrected_logical_results[-1] += ["POSTselect"]
335 break
336 recovery = mult_paulis(recovery, r)
337 if r is None:
338 corrected_logical_results[-1] += [
339 pauli_as_results(recovery, basis=basis)
340 ]
341 continue
342 if basis == "Z":
343 r = recovery_from_syndrome_measurements([], shot[2])
344 else:
345 assert basis == "X"
346 r = recovery_from_syndrome_measurements(shot[2], [])
347 if r is None:
348 corrected_logical_results[-1] += ["POSTselect"]
349 continue
350 recovery = mult_paulis(recovery, r)
351 corrected_logical_results[-1] += [pauli_as_results(recovery, basis=basis)]
352 return corrected_logical_results
353