Skip to content

Commit

Permalink
Merge branch 'main' into reproduce-arxiv
Browse files Browse the repository at this point in the history
  • Loading branch information
perlinm committed Jan 15, 2025
2 parents a9e004c + dec84a8 commit 72f81cc
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 30 deletions.
28 changes: 15 additions & 13 deletions qldpc/codes/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,11 +663,11 @@ def __init__(
matrix: AbstractCode | npt.NDArray[np.int_] | Sequence[Sequence[int]],
field: int | None = None,
*,
skip_validation: bool = False,
validate: bool = True,
) -> None:
"""Construct a qudit code from a parity check matrix over a finite field."""
AbstractCode.__init__(self, matrix, field)
if not skip_validation:
if validate:
shape_xz = (self.num_checks, 2, -1)
matrix_xz = self.matrix.reshape(shape_xz)[:, ::-1, :].reshape(self.matrix.shape)
assert not np.any(self.matrix @ matrix_xz.T)
Expand Down Expand Up @@ -784,7 +784,7 @@ def get_stabilizers(self) -> list[str]:

@classmethod
def from_stabilizers(
cls, *stabilizers: str, field: int | None = None, skip_validation: bool = False
cls, *stabilizers: str, field: int | None = None, validate: bool = True
) -> QuditCode:
"""Construct a QuditCode from the provided stabilizers."""
field = field or DEFAULT_FIELD_ORDER
Expand All @@ -800,20 +800,22 @@ def from_stabilizers(
for qudit, op in enumerate(check_op):
matrix[check, :, qudit] = operator.from_string(op).value[::-1]

return QuditCode(
matrix.reshape(num_checks, 2 * num_qudits), field, skip_validation=skip_validation
)
return QuditCode(matrix.reshape(num_checks, 2 * num_qudits), field, validate=validate)

def conjugated(
self, qudits: slice | Sequence[int] | None = None, *, skip_validation: bool = False
self, qudits: slice | Sequence[int] | None = None, *, validate: bool = True
) -> QuditCode:
"""Apply local Fourier transforms to data qudits, swapping X-type and Z-type operators."""
if qudits is None:
qudits = self._default_conjugate if hasattr(self, "_default_conjugate") else ()
num_checks = len(self.matrix)
matrix = np.reshape(self.matrix.copy(), (num_checks, 2, -1))
matrix = self.matrix.copy().reshape(-1, 2, len(self))
matrix[:, :, qudits] = matrix[:, ::-1, qudits]
return QuditCode(matrix.reshape(num_checks, -1), skip_validation=skip_validation)
code = QuditCode(matrix.reshape(-1, 2 * len(self)), validate=validate)
if self._logical_ops is not None:
logical_ops = self._logical_ops.copy().reshape(-1, 2, len(self))
logical_ops[:, :, qudits] = logical_ops[:, ::-1, qudits]
code.set_logical_ops(logical_ops.reshape(-1, 2 * len(self)), validate=validate)
return code

def get_code_params(
self, *, bound: int | bool | None = None, **decoder_args: Any
Expand Down Expand Up @@ -1199,7 +1201,7 @@ def __init__(
field: int | None = None,
*,
promise_balanced_codes: bool = False, # do the subcodes have the same parameters [n, k, d]?
skip_validation: bool = False,
validate: bool = True,
) -> None:
"""Build a CSSCode from classical subcodes that specify X-type and Z-type parity checks."""
self.code_x = ClassicalCode(code_x, field)
Expand All @@ -1209,7 +1211,7 @@ def __init__(
raise ValueError("The sub-codes provided for this CSSCode are over different fields")
self._field = self.code_x.field

if not skip_validation and self.code_x != self.code_z:
if validate:
self._validate_subcodes()

self._balanced_codes = promise_balanced_codes or self.code_x == self.code_z
Expand Down Expand Up @@ -1640,7 +1642,7 @@ def stack(cls, *codes: QuditCode, inherit_logicals: bool = True) -> CSSCode:
code_x,
code_z,
promise_balanced_codes=all(code._balanced_codes for code in css_codes),
skip_validation=True,
validate=False,
)
if inherit_logicals:
logicals_x = [code.get_logical_ops(Pauli.X)[:, : len(code)] for code in css_codes]
Expand Down
9 changes: 6 additions & 3 deletions qldpc/codes/common_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def get_random_qudit_code(qudits: int, checks: int, field: int = 2) -> codes.Qud
"""Construct a random (but probably trivial or invalid) QuditCode."""
return codes.QuditCode(
codes.ClassicalCode.random(2 * qudits, checks, field).matrix,
skip_validation=True,
validate=False,
)


Expand Down Expand Up @@ -299,7 +299,7 @@ def test_qudit_stabilizers(field: int, bits: int = 5, checks: int = 3) -> None:
"""Stabilizers of a QuditCode."""
code_a = get_random_qudit_code(bits, checks, field)
stabilizers = code_a.get_stabilizers()
code_b = codes.QuditCode.from_stabilizers(*stabilizers, field=field, skip_validation=True)
code_b = codes.QuditCode.from_stabilizers(*stabilizers, field=field, validate=False)
assert code_a == code_b
assert stabilizers == code_b.get_stabilizers()

Expand All @@ -310,7 +310,7 @@ def test_qudit_stabilizers(field: int, bits: int = 5, checks: int = 3) -> None:
def test_trivial_deformations(num_qudits: int = 5, num_checks: int = 3, field: int = 3) -> None:
"""Trivial local Clifford deformations do not modify a code."""
code = get_random_qudit_code(num_qudits, num_checks, field)
assert code == code.conjugated(skip_validation=True)
assert code == code.conjugated(validate=False)


def test_qudit_ops() -> None:
Expand All @@ -327,6 +327,9 @@ def test_qudit_ops() -> None:
code = codes.QuditCode.from_stabilizers(*code.get_stabilizers(), "I I I I I", field=2)
assert np.array_equal(logical_ops, code.get_logical_ops())

assert code.get_stabilizers()[0] == "X Z Z X I"
assert code.conjugated([0]).get_stabilizers()[0] == "Z Z Z X I"


def test_qudit_concatenation() -> None:
"""Concatenate qudit codes."""
Expand Down
26 changes: 12 additions & 14 deletions qldpc/codes/quantum.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self) -> None:
"Z X I X Z",
field=2,
)
QuditCode.__init__(self, code, skip_validation=True)
QuditCode.__init__(self, code, validate=False)


class SteaneCode(CSSCode):
Expand All @@ -55,7 +55,7 @@ class SteaneCode(CSSCode):
def __init__(self) -> None:
self._exact_distance_x = self._exact_distance_z = 3
code = HammingCode(3, field=2)
CSSCode.__init__(self, code, code)
CSSCode.__init__(self, code, code, validate=False)


################################################################################
Expand Down Expand Up @@ -84,12 +84,12 @@ def __init__(
field: int | None = None,
*,
promise_balanced_codes: bool = False,
skip_validation: bool = False,
validate: bool = True,
) -> None:
"""Construct a two-block quantum code."""
matrix_a = ClassicalCode(matrix_a, field).matrix
matrix_b = ClassicalCode(matrix_b, field).matrix
if not skip_validation and not np.array_equal(matrix_a @ matrix_b, matrix_b @ matrix_a):
if validate and not np.array_equal(matrix_a @ matrix_b, matrix_b @ matrix_a):
raise ValueError("The matrices provided for this TBCode are incompatible")

matrix_x = np.block([matrix_a, matrix_b])
Expand All @@ -100,7 +100,7 @@ def __init__(
matrix_z,
field,
promise_balanced_codes=promise_balanced_codes,
skip_validation=True,
validate=False,
)


Expand Down Expand Up @@ -176,7 +176,7 @@ def __init__(
matrix_a = self.eval(self.poly_a).lift()
matrix_b = self.eval(self.poly_b).lift()
TBCode.__init__(
self, matrix_a, matrix_b, field, promise_balanced_codes=True, skip_validation=True
self, matrix_a, matrix_b, field, promise_balanced_codes=True, validate=False
)

def eval(
Expand Down Expand Up @@ -574,9 +574,7 @@ def __init__(
# if Hadamard-transforming qudits, conjugate those in the (1, 1) sector by default
self._default_conjugate = slice(self.sector_size[0, 0], None)

CSSCode.__init__(
self, matrix_x.astype(int), matrix_z.astype(int), field, skip_validation=True
)
CSSCode.__init__(self, matrix_x.astype(int), matrix_z.astype(int), field, validate=False)

@classmethod
def get_matrix_product(
Expand Down Expand Up @@ -739,7 +737,7 @@ def __init__(
abstract.Protograph(matrix_x.astype(object)).lift(),
abstract.Protograph(matrix_z.astype(object)).lift(),
field,
skip_validation=True,
validate=False,
)


Expand Down Expand Up @@ -813,7 +811,7 @@ def __init__(
self.code_b = code_b
self.complex = CayleyComplex(subset_a, subset_b, bipartite=bipartite)
code_x, code_z = self.get_subcodes(self.complex, code_a, code_b)
CSSCode.__init__(self, code_x, code_z, field, skip_validation=True)
CSSCode.__init__(self, code_x, code_z, field, validate=False)

def __eq__(self, other: object) -> bool:
return (
Expand Down Expand Up @@ -1023,7 +1021,7 @@ def __init__(
matrix_z = code_ab.matrix_z
self._default_conjugate = slice(code_ab.sector_size[0, 0], None)

CSSCode.__init__(self, matrix_x, matrix_z, field=field, skip_validation=True)
CSSCode.__init__(self, matrix_x, matrix_z, field=field, validate=False)

@classmethod
def get_rotated_checks(
Expand Down Expand Up @@ -1132,7 +1130,7 @@ def __init__(
matrix_z = code_ab.matrix_z
self._default_conjugate = slice(code_ab.sector_size[0, 0], None)

CSSCode.__init__(self, matrix_x, matrix_z, field=field, skip_validation=True)
CSSCode.__init__(self, matrix_x, matrix_z, field=field, validate=False)

@classmethod
def get_rotated_checks(
Expand Down Expand Up @@ -1204,4 +1202,4 @@ def __init__(
matrix_x, matrix_z = chain.op(1), chain.op(2).T
assert not isinstance(matrix_x, abstract.Protograph)
assert not isinstance(matrix_z, abstract.Protograph)
CSSCode.__init__(self, matrix_x, matrix_z, field, skip_validation=True)
CSSCode.__init__(self, matrix_x, matrix_z, field, validate=False)

0 comments on commit 72f81cc

Please sign in to comment.