Skip to content

Commit a4c91c7

Browse files
committed
Add psi exchange, start writing README.md
1 parent aed4b7c commit a4c91c7

File tree

7 files changed

+143
-24
lines changed

7 files changed

+143
-24
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,26 @@ in Qiskit.
66

77
## GS preparation
88
### Matching boundary conditions
9+
For matching boundary condition, boundary plaquettes are all of the same type and the ground state is unique.
10+
We implement linear algorithm for preparing ground state of the toric code proposed in the paper.
911
### Mixed boundary conditions
12+
For mixed boundary condition, boundary plaquettes are of different types, and there is ground state degeneracy,
13+
which allows us to encode logical qubits in the system state.
14+
Not implemented yet.
15+
1016
## Entropy and topological entropy
17+
We implement the measurement of the second Rényi entropy as described in paper, and use it
18+
to calculate topological entropy, acquiring non-trivial value for various subsystems.
19+
20+
For 2x2 and 2x3 subsystem it is possible to perform determenistic calculation, while for
21+
3x3 system only randomized calculation is feasible.
22+
23+
## Braiding
24+
There are 4 particle types in toric code: `e`, `m`, `psi` and `1`, for total of 6 possible
25+
mutual statistics and 3 exchange statistic. Out of those 4 are non-trivial -- `em`, `epsi`,
26+
`mpsi` and `psipsi`, resulting in phase of π.
1127

12-
## Braiding
28+
We implement the required operators (without optiimization), and demonstrate part of the braidings
29+
and exchanges.
30+
## Logical qubit.
31+
Not implemented yet.

tests/test_braiding.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from qiskit import Aer
55
from qiskit import transpile
66

7-
from topo_braiding import create_e_particles, create_m_particles, apply_cxxxx_on_square
7+
from topo_braiding import create_e_particles, create_m_particles, apply_cxxxx_on_square, apply_cxxyyzz_on_rectangle
88
from toric_code import get_toric_code
99

1010

@@ -41,6 +41,76 @@ def test_em_braiding(self):
4141
expected_res = -1. if sq in [(0, 2), (0, 3)] else 1.
4242
np.testing.assert_allclose(cos_theta, expected_res)
4343

44+
def test_psipsi_exchange(self):
45+
x, y = 5, 7
46+
backend = Aer.get_backend('aer_simulator')
47+
sq = (0, 3)
48+
tc = get_toric_code(x, y, classical_bit_count=1, ancillas_count=1)
49+
50+
x_strings = [[(2, 1), (2, 2)],
51+
[(1, 4), (3, 4)]]
52+
for x_string in x_strings:
53+
create_e_particles(tc, x_string)
54+
55+
z_strings = [[(2, 3), (3, 3), (4, 3)],
56+
[(3, 1), (4, 1), (3, 2)], ]
57+
for z_string in z_strings:
58+
create_m_particles(tc, z_string)
59+
60+
tc.circ.h(tc.ancillas[0])
61+
apply_cxxyyzz_on_rectangle(tc, sq)
62+
tc.circ.h(tc.ancillas[0])
63+
64+
tc.circ.measure(tc.ancillas[0], 0)
65+
Nshots = 10000
66+
job = backend.run(transpile(tc.circ, backend), shots=Nshots)
67+
result = job.result()
68+
counts = result.get_counts(tc.circ)
69+
70+
if '0' not in counts:
71+
counts['0'] = 0
72+
if '1' not in counts:
73+
counts['1'] = 0
74+
print(counts)
75+
76+
cos_theta = (counts['0'] - counts['1']) / Nshots
77+
expected_res = -1.
78+
np.testing.assert_allclose(cos_theta, expected_res)
79+
80+
def test_psione_braiding(self):
81+
x, y = 5, 7
82+
backend = Aer.get_backend('aer_simulator')
83+
sq = (0, 3)
84+
tc = get_toric_code(x, y, classical_bit_count=1, ancillas_count=1)
85+
86+
x_strings = [[(1, 4), (3, 4)]]
87+
for x_string in x_strings:
88+
create_e_particles(tc, x_string)
89+
90+
z_strings = [[(2, 3), (3, 3), (4, 3)], ]
91+
for z_string in z_strings:
92+
create_m_particles(tc, z_string)
93+
94+
tc.circ.h(tc.ancillas[0])
95+
apply_cxxyyzz_on_rectangle(tc, sq)
96+
tc.circ.h(tc.ancillas[0])
97+
98+
tc.circ.measure(tc.ancillas[0], 0)
99+
Nshots = 10000
100+
job = backend.run(transpile(tc.circ, backend), shots=Nshots)
101+
result = job.result()
102+
counts = result.get_counts(tc.circ)
103+
104+
if '0' not in counts:
105+
counts['0'] = 0
106+
if '1' not in counts:
107+
counts['1'] = 0
108+
print(counts)
109+
110+
cos_theta = (counts['0'] - counts['1']) / Nshots
111+
expected_res = 1.
112+
np.testing.assert_allclose(cos_theta, expected_res)
113+
44114
def test_e_trivial_braiding(self):
45115
x, y = 5, 7
46116
backend = Aer.get_backend('aer_simulator')

tests/test_entropy.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from qiskit import transpile
77
from tqdm import tqdm
88

9-
from topo_entropy import ABC_DIVISION_2x2, ABC_DIVISION_2x3_LEFT, ABC_DIVISION_2x3_RIGHT,ABC_DIVISION_3x3
9+
from topo_entropy import ABC_DIVISION_2x2, ABC_DIVISION_2x3_LEFT, ABC_DIVISION_2x3_RIGHT, ABC_DIVISION_3x3
1010
from topo_entropy import calculate_s_subsystems
1111
from topo_entropy import get_all_2x2_non_corner, get_all_2x3_non_corner, get_all_3x3_non_corner
1212
from topo_entropy import get_all_2x3_left_non_corner, get_all_2x3_right_non_corner
@@ -30,7 +30,7 @@ def test_topo_entropy(backend, size, qubits, subsystems, expected_values, type='
3030
elif type == 'pauli':
3131
tc.measure_pauli(qubits, gates)
3232

33-
job = backend.run(transpile(tc.circ, backend), shots=15000) # note: number of shots is important
33+
job = backend.run(transpile(tc.circ, backend), shots=15000) # note: number of shots is important
3434
result = job.result()
3535
counts = result.get_counts(tc.circ)
3636
all_counts.append(counts)
@@ -71,27 +71,30 @@ def test_2x3_entropy_pauli(self):
7171
backend_sim = Aer.get_backend('aer_simulator')
7272
x, y = 5, 7
7373
for qubits in get_all_2x3_left_non_corner((x, y)):
74-
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_LEFT, expected_values, type='pauli')
74+
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_LEFT, expected_values, type='pauli',
75+
rtol=0.03)
7576
for qubits in get_all_2x3_right_non_corner((x, y)):
76-
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_RIGHT, expected_values, type='pauli')
77+
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_RIGHT, expected_values, type='pauli',
78+
rtol=0.03)
7779

7880
def test_2x3_entropy_haar(self):
7981
expected_values = [(2., 2., 2.), (4., 4., 3.), (4.,)]
8082

8183
backend_sim = Aer.get_backend('aer_simulator')
8284
x, y = 5, 7
85+
for qubits in get_all_2x3_right_non_corner((x, y)):
86+
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_RIGHT, expected_values, type='haar',
87+
cnt=100)
8388
for qubits in get_all_2x3_left_non_corner((x, y)):
8489
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_LEFT, expected_values, type='haar', cnt=100)
85-
for qubits in get_all_2x3_right_non_corner((x, y)):
86-
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_2x3_RIGHT, expected_values, type='haar', cnt=100)
8790

8891
def test_3x3_entropy_haar(self):
8992
expected_values = [(3., 3., 3.), (6., 5., 4.), (5.,)]
9093

9194
backend_sim = Aer.get_backend('aer_simulator')
9295
x, y = 5, 7
9396
for qubits in get_all_3x3_non_corner((x, y)):
94-
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_3x3, expected_values, type='haar', cnt=1000)
97+
test_topo_entropy(backend_sim, (x, y), qubits, ABC_DIVISION_3x3, expected_values, type='haar', cnt=1000)
9598

9699

97100
if __name__ == '__main__':

topo_braiding.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import numpy as np
22
from qiskit import transpile
3-
from qiskit.circuit.library import MCXGate
43

54
from toric_code import get_toric_code
5+
from toric_code_matching import is_inside_matching
66

77
sz = np.array([[1, 0], [0, -1]])
88
sx = np.array([[0, 1], [1, 0]])
@@ -26,21 +26,46 @@ def apply_cxxxx_on_square(tc, upper_corner):
2626
locs = [(x, y), (x + 1, y), (x + 2, y), (x + 1, y + 1)]
2727
else:
2828
locs = [(x, y), (x + 1, y - 1), (x + 2, y), (x + 1, y)]
29-
tc.circ.mct(control_qubits=[tc.ancillas[0]], target_qubit=[tc.regs[l[0]][l[1]] for l in locs])
3029

30+
if not all([is_inside_matching((tc.x, tc.y), l) for l in locs]):
31+
return
32+
tc.circ.mct(control_qubits=[tc.ancillas[0]], target_qubit=[tc.regs[l[0]][l[1]] for l in locs])
3133

32-
def apply_cxxyyzz_on_square(tc, upper_corner):
33-
# cXXXX = np.kron(np.array([[1, 0], [0, 0]]), np.kron(sx, np.kron(sx, np.kron(sx, sx)))) + \
34-
# np.kron(np.array([[0, 0], [0, 1]]), np.kron(s0, np.kron(s0, np.kron(s0, s0))))
3534

35+
def apply_czzz_on_square(tc, upper_corner):
36+
cZZZZ = np.kron(np.array([[1, 0], [0, 0]]), np.kron(sz, np.kron(sz, np.kron(sz, sz)))) + \
37+
np.kron(np.array([[0, 0], [0, 1]]), np.kron(s0, np.kron(s0, np.kron(s0, s0))))
3638
x, y = upper_corner
3739
if x % 2 == 0:
3840
locs = [(x, y), (x + 1, y), (x + 2, y), (x + 1, y + 1)]
3941
else:
4042
locs = [(x, y), (x + 1, y - 1), (x + 2, y), (x + 1, y)]
4143

42-
tc.circ.mct(control_qubits=[tc.ancillas[0]], target_qubit=[tc.regs[l[0]][l[1]] for l in locs])
43-
# tc.circ.unitary(cXXXX, [tc.regs[l[0]][l[1]] for l in locs] + [tc.ancillas[0]])
44+
if not all([is_inside_matching((tc.x, tc.y), l) for l in locs]):
45+
return
46+
47+
tc.circ.unitary(cZZZZ, [tc.regs[l[0]][l[1]] for l in locs] + [tc.ancillas[0]])
48+
49+
50+
def apply_cxxyyzz_on_rectangle(tc, upper_corner, left=True):
51+
cXXYYZZ = np.kron(np.array([[1, 0], [0, 0]]), np.kron(sx, np.kron(sx, np.kron(sy, np.kron(sy, np.kron(sz, sz)))))) + \
52+
np.kron(np.array([[0, 0], [0, 1]]), np.kron(s0, np.kron(s0, np.kron(s0, np.kron(s0, np.kron(s0, s0))))))
53+
54+
x, y = upper_corner
55+
if left:
56+
if x % 2 == 0:
57+
locs = [(x, y), (x + 1, y + 1), (x + 1, y), (x + 2, y), (x + 2, y - 1), (x + 3, y)]
58+
else:
59+
locs = [(x, y), (x + 1, y), (x + 1, y - 1), (x + 2, y), (x + 1, y - 1), (x + 2, y - 1)]
60+
else:
61+
if x % 2 == 0:
62+
locs = [(x, y), (x + 1, y), (x + 1, y + 1), (x + 2, y), (x + 2, y + 1), (x + 3, y + 1)]
63+
else:
64+
locs = [(x, y), (x + 1, y - 1), (x + 1, y), (x + 2, y), (x + 2, y + 1), (x + 3, y)]
65+
66+
if not all([is_inside_matching((tc.x, tc.y), l) for l in locs]):
67+
return
68+
tc.circ.unitary(cXXYYZZ, [tc.regs[l[0]][l[1]] for l in locs[::-1]] + [tc.ancillas[0]])
4469

4570

4671
def em_braiding_phase(backend, x, y):

topo_entropy.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
ABC_DIVISION_2x2 = [(0, 1), (2,), (3,)]
1212
ABC_DIVISION_2x3_RIGHT = [(1, 3), (0, 2), (4, 5)]
13-
ABC_DIVISION_2x3_LEFT = [(2, 4), (0, 1), (3, 5)]
13+
ABC_DIVISION_2x3_LEFT = [(2, 4), (0, 1), (3, 5)]
1414
ABC_DIVISION_3x3 = [(0, 1, 3), (2, 5, 7), (4, 6, 8)]
1515

1616

@@ -122,6 +122,8 @@ def get_all_2x3_left_non_corner(size):
122122
[is_corner_matching(size, s) for s in sys_l]):
123123
all_sys.append(sys_l)
124124
return all_sys
125+
126+
125127
def get_all_2x3_right_non_corner(size):
126128
x, y = size
127129
all_sys = []
@@ -135,6 +137,8 @@ def get_all_2x3_right_non_corner(size):
135137
[is_corner_matching(size, s) for s in sys_r]):
136138
all_sys.append(sys_r)
137139
return all_sys
140+
141+
138142
def get_all_2x3_non_corner(size):
139143
return get_all_2x3_left_non_corner(size) + get_all_2x3_right_non_corner(size)
140144

@@ -147,8 +151,7 @@ def get_all_3x3_non_corner(size):
147151
if rx % 2 == 0:
148152
sys = [(-1, -1)] # skip, why
149153
else:
150-
sys = (rx, ry), (rx + 1, ry - 1), (rx + 1, ry), (rx + 2, ry - 1), (rx + 2, ry), (rx + 2, ry + 1), (
151-
rx + 3, ry - 1), (rx + 3, ry), (rx + 4, ry),
154+
sys = (rx, ry), (rx + 1, ry - 1), (rx + 1, ry), (rx + 2, ry - 1), (rx + 2, ry), (rx + 2, ry + 1), (rx + 3, ry - 1), (rx + 3, ry), (rx + 4, ry),
152155
if all([is_inside_matching(size, s) for s in sys]) and not any([is_corner_matching(size, s) for s in sys]):
153156
all_sys.append(sys)
154157
return all_sys

toric_code.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
def get_toric_code(x, y, classical_bit_count=4, ancillas_count=0, boundary_condition='matching'):
66
assert boundary_condition in ('mixed', 'matching')
77
if boundary_condition == 'matching':
8-
return ToricCodeMatching(x, y, classical_bit_count,ancillas_count)
8+
return ToricCodeMatching(x, y, classical_bit_count, ancillas_count)
99
elif boundary_condition == 'mixed':
10-
return ToricCodeMixed(x, y, classical_bit_count,ancillas_count)
10+
return ToricCodeMixed(x, y, classical_bit_count, ancillas_count)

toric_code_matching.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,9 @@ def __init__(self, x, y, classical_bit_count=4, ancillas_count=0):
8383
self.star_x, self.star_y = self.x, self.y // 2 + 1
8484
# print(self.plaquette_x, self.plaquette_y)
8585
self.regs = [QuantumRegister(self.x - 1, f'l{lev}') if lev % 2 == 0 else QuantumRegister(self.x, f'l{lev}')
86-
for
87-
lev in range(self.y)] # first coordinate is row index, second is column index
86+
for lev in range(self.y)] # first coordinate is row index, second is column index
8887
self.c_reg = ClassicalRegister(classical_bit_count)
89-
if ancillas_count>0:
88+
if ancillas_count > 0:
9089
self.ancillas = QuantumRegister(ancillas_count)
9190
self.circ = QuantumCircuit(*self.regs, self.ancillas, self.c_reg)
9291
else:

0 commit comments

Comments
 (0)