"""
Copyright 2024 Entropica Labs Pte Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# pylint: disable=duplicate-code
from __future__ import annotations
from uuid import uuid4
from functools import cached_property
from pydantic.dataclasses import dataclass
from loom.eka import (
Block,
Lattice,
LatticeType,
PauliOperator,
Stabilizer,
SyndromeCircuit,
Circuit,
Channel,
)
from loom.eka.utilities import dataclass_config
[docs]
@dataclass(config=dataclass_config)
class ShorCode(Block):
"""
A sub-class of ``Block`` that represents a Shor code block.
"""
[docs]
@classmethod
def create(
cls,
lattice: Lattice,
unique_label: str | None = None,
position: tuple[int, ...] = (0,),
skip_validation: bool = False,
) -> ShorCode:
"""Create datablock of Shor Code as a Block object. The Shor Code is a
[[9, 1, 3]] quantum error-correcting CSS code, resulting from the concatenation
of two repetition codes. There are two X stabilizers of weight 6, and six Z
stabilizers of weight 2. We implement a naive syndrome extraction scheme, where
measure all X stabilizers first and all the Z stabilizers later. We choose to
embed the code in a linear lattice, where the logical operators are defined on
all the data qubits.
Parameters
----------
lattice : Lattice
Lattice on which the block is defined. The qubit indices depend on the type
of lattice.
unique_label : str, optional
Label for the block. It must be unique among all blocks in the initial CRD.
If no label is provided, a unique label is generated automatically using the
uuid module.
position : tuple[int], optional
Position of the top left boundary of the block on the lattice,
by default (0,).
skip_validation : bool, optional
Skip validation of the block object, by default False.
Returns
-------
Block
Block object for the Shor Code.
"""
# Input validation
if lattice.lattice_type != LatticeType.LINEAR:
raise ValueError(
"The creation of Shor code blocks is "
"currently only supported for 1D linear lattices. Instead "
f"the lattice is of type {lattice.lattice_type}."
)
if not isinstance(position, tuple) or any(
not isinstance(x, int) for x in position
):
raise ValueError(
f"`position` must be a tuple of integers. Got '{position}' instead."
)
if unique_label is None:
unique_label = str(uuid4())
# Define the stabilizers
x_indices = [[(i + 3 * j, 0) for i in range(6)] for j in range(2)]
x_stabilizers = [
Stabilizer(
pauli="X" * 6,
data_qubits=x_ind,
ancilla_qubits=[(i, 1)],
)
for i, x_ind in enumerate(x_indices)
]
z_indices = [
[(i + j + 3 * k, 0) for i in range(2)] for k in range(3) for j in range(2)
]
z_stabilizers = [
Stabilizer(
pauli="Z" * 2,
data_qubits=z_ind,
ancilla_qubits=[(i + 2, 1)],
)
for i, z_ind in enumerate(z_indices)
]
stabilizers = x_stabilizers + z_stabilizers
# Define the syndrome circuits
x_syndrome_circuits = cls.generate_syndrome_extraction_circuits("X" * 6)
z_syndrome_circuits = cls.generate_syndrome_extraction_circuits("Z" * 2)
syndrome_circuits = [x_syndrome_circuits, z_syndrome_circuits]
# Define mapping of stabilizers to syndrome circuits
stabilizer_to_circuit = {
stab.uuid: x_syndrome_circuits.uuid for stab in x_stabilizers
} | {stab.uuid: z_syndrome_circuits.uuid for stab in z_stabilizers}
# Define the logical operators
all_datas = [(i, 0) for i in range(9)]
logical_x_operator = PauliOperator(pauli="X" * 9, data_qubits=all_datas)
logical_z_operator = PauliOperator(pauli="Z" * 9, data_qubits=all_datas)
block = cls(
unique_label=unique_label,
stabilizers=stabilizers,
logical_x_operators=[logical_x_operator],
logical_z_operators=[logical_z_operator],
syndrome_circuits=syndrome_circuits,
stabilizer_to_circuit=stabilizer_to_circuit,
skip_validation=skip_validation,
)
if position == (0,):
return block
return block.shift(position)
# Syndrome extraction circuits
# Instance methods
def __eq__(self, other: ShorCode) -> bool:
if not isinstance(other, ShorCode):
raise NotImplementedError(f"Cannot compare ShorCode with {type(other)}")
return super().__eq__(other)
[docs]
def shift(
self, position: tuple[int, ...], new_label: str | None = None
) -> ShorCode:
return super().shift(position, new_label)
[docs]
def rename(self, name: str) -> ShorCode:
return super().rename(name)
@cached_property
def stabilizers_labels(self) -> dict[str, dict[str, tuple[int, ...]]]:
return super().stabilizers_labels