import galois
import numpy as np
from .layout import Layout
def check_overlap_layout_pair(layout_1: Layout, layout_2: Layout) -> None:
"""Checks if the two given layouts share any qubits for when doing
parallel logical computation with both of them.
It checks that there are no shared qubit (1) labels, (2) indices,
(3) coordinates, and (4) logical qubit labels.
Parameters
----------
layout_1
One of the layouts.
layout_2
The other layout.
"""
if not isinstance(layout_1, Layout):
raise TypeError(f"'layout_1' must be a Layout, but {type(layout_1)} was given.")
if not isinstance(layout_2, Layout):
raise TypeError(f"'layout_2' must be a Layout, but {type(layout_2)} was given.")
qubits_1 = set(layout_1.qubits)
qubits_2 = set(layout_2.qubits)
if qubits_1.intersection(qubits_2) != set():
raise ValueError("The layouts have qubits with the same label.")
inds_1 = set(layout_1.get_inds(qubits_1))
inds_2 = set(layout_2.get_inds(qubits_2))
if inds_1.intersection(inds_2) != set():
raise ValueError("The layouts have qubits with the same indices.")
coords_1 = set(map(tuple, layout_1.get_coords(qubits_1)))
coords_2 = set(map(tuple, layout_2.get_coords(qubits_2)))
if coords_1.intersection(coords_2) != set():
raise ValueError("The layouts have qubits with the same coordinates.")
log_qubits_1 = set(layout_1.logical_qubits)
log_qubits_2 = set(layout_2.logical_qubits)
if log_qubits_1.intersection(log_qubits_2) != set():
raise ValueError("The layouts have logical qubits with the same label.")
return
[docs]
def check_overlap_layouts(*layouts: Layout) -> None:
"""Checks if the given layouts share any qubits for when doing
parallel logical computation with them.
It checks that there are no shared qubit (1) labels, (2) indices,
(3) coordinates, and (4) logical qubit labels.
Parameters
----------
*layouts
Layouts.
"""
if len(layouts) == 1:
return
for k, layout in enumerate(layouts):
for other_layout in layouts[k + 1 :]:
check_overlap_layout_pair(layout, other_layout)
return
[docs]
def check_code_definition(layout: Layout) -> None:
"""Checks if the QEC code defined in the layout satisfies the following properties:
1. stabilisers commute with each other
2. logical Paulis commute with all stabilisers
3. logical Xi and Zi anticommute
4. logical Paulis are independent (i.e. no product of them is in the stabilizer group)
"""
if not isinstance(layout, Layout):
raise TypeError(f"'layout' must be a Layout, but {type(layout)} was given.")
# build parity and logical matrices
x_anc = layout.get_qubits(role="anc", stab_type="x_type")
z_anc = layout.get_qubits(role="anc", stab_type="z_type")
data_qubits = layout.data_qubits
h_x = np.zeros((len(x_anc), layout.num_data_qubits), dtype=int)
for k, anc in enumerate(x_anc):
datas = layout.get_neighbors([anc])
for data in datas:
h_x[k, data_qubits.index(data)] = True
h_z = np.zeros((len(z_anc), layout.num_data_qubits), dtype=int)
for k, anc in enumerate(z_anc):
datas = layout.get_neighbors([anc])
for data in datas:
h_z[k, data_qubits.index(data)] = True
l_x = np.zeros((layout.num_logical_qubits, layout.num_data_qubits), dtype=int)
for k, log in enumerate(layout.logical_qubits):
datas = layout.logical_param("log_x", log)
for data in datas:
l_x[k, data_qubits.index(data)] = True
l_z = np.zeros((layout.num_logical_qubits, layout.num_data_qubits), dtype=int)
for k, log in enumerate(layout.logical_qubits):
datas = layout.logical_param("log_z", log)
for data in datas:
l_z[k, data_qubits.index(data)] = True
GF = galois.GF(2)
h_x, h_z, l_x, l_z = GF(h_x), GF(h_z), GF(l_x), GF(l_z)
# check 1. stabilisers commute with each other
if not (h_x @ h_z.T == 0).all():
raise ValueError("Stabilizers do not commute with each other.")
# check 2. logical Paulis commute with all stabilisers
if not (h_x @ l_z.T == 0).all():
raise ValueError("Logical Pauli Zs anticommute with X stabilizers.")
if not (h_z @ l_x.T == 0).all():
raise ValueError("Logical Pauli Xs anticommute with Z stabilizers.")
# check 3. logical Xi and Zi anticommute
if not (l_x @ l_z.T == np.eye(layout.num_logical_qubits, dtype=int)).all():
raise ValueError(
"Logical Pauli X and Z do not follow the appropiate commutation relations"
)
# 4. logical Paulis are independent (i.e. no product of them is in the stabilizer group)
hl_x = GF(np.concatenate([h_x, l_x], axis=0, dtype=int))
if not (
np.linalg.matrix_rank(hl_x)
== np.linalg.matrix_rank(h_x) + layout.num_logical_qubits
):
raise ValueError("A product of logical Pauli X is equivalent to stabilizer(s).")
hl_z = GF(np.concatenate([h_z, l_z], axis=0, dtype=int))
if not (
np.linalg.matrix_rank(hl_z)
== np.linalg.matrix_rank(h_z) + layout.num_logical_qubits
):
raise ValueError("A product of logical Pauli Z is equivalent to stabilizer(s).")
return
[docs]
def overwrite_interaction_order(layout: Layout, schedule: dict[str, list[str]]) -> None:
"""
Overwrites (in place) any existing schedule in a layout with the specified one.
Parameters
----------
layout
Layout whose schedule is going to be overwritten.
schedule
Schedule for the syndrome extraction circuit. The format corresponds to
a dictionary whose keys correspond to the ancillas in ``layout`` and
the values correspond to a list where the ``i``th element specifies
the data qubit that the ancilla interacts with on the ``i``th CNOT layer.
If the ancilla does not interact with any data qubit, the element is ``None``.
"""
if not isinstance(layout, Layout):
raise TypeError(f"'layout' must be a Layout, but {type(layout)} was given.")
if not isinstance(schedule, dict):
raise TypeError(f"'schedule' must be a dict, but {type(schedule)} was given.")
if set(schedule) != set(layout.anc_qubits):
raise ValueError(
"The keys in 'schedule' must correspond to all the ancillas in 'layout'."
)
if any(not isinstance(s, list) for s in schedule.values()):
raise TypeError("The values in 'schedule' must be sequences.")
if len(set(len(s) for s in schedule.values())) != 1:
raise ValueError("The values in 'schedule' must have the same lenght.")
if any(
set(schedule[a]).difference([None]) != set(layout.get_neighbors([a]))
for a in layout.anc_qubits
):
raise ValueError(
"Ancillas must interact with all the qubits it has support on."
)
layout.interaction_order = schedule
return