Skip to content

qLDPC Codes & BP-OSD Decoder

quanta.qec.qldpc

quanta.qec.qldpc -- Quantum Low-Density Parity-Check (qLDPC) codes.

Implements Bivariate Bicycle (BB) codes over the polynomial group ring R = F_2[x, y] / , specifically the Gross [[144, 12, 12]] code, alongside native BP-OSD (Belief Propagation with Ordered Statistics Decoding) decoders.

Reference

Bravyi, Cross, Gambetta, Maslov, Rall, Yoder, "High-threshold and low-overhead fault-tolerant quantum memory", Nature 627, 778–782 (2024).

BPOSDDecoder

Belief Propagation with Ordered Statistics Decoding (BP-OSD).

Combines iterative soft-decision Belief Propagation (normalized Min-Sum) with post-processing Ordered Statistics Decoding (OSD-0 / OSD-W) using Gaussian elimination over GF(2) on the most reliable basis (MRB).

Parameters:

Name Type Description Default
parity_check_matrix ndarray

Binary parity-check matrix H of shape (m, n).

required
max_bp_iter int

Maximum number of BP message passing rounds (default: 30).

30
osd_order int

OSD search order (default: 10).

10
error_probability float

Channel prior physical error probability (default: 0.01).

0.01
Source code in quanta/qec/qldpc.py
class BPOSDDecoder:
    """Belief Propagation with Ordered Statistics Decoding (BP-OSD).

    Combines iterative soft-decision Belief Propagation (normalized Min-Sum)
    with post-processing Ordered Statistics Decoding (OSD-0 / OSD-W) using
    Gaussian elimination over GF(2) on the most reliable basis (MRB).

    Args:
        parity_check_matrix: Binary parity-check matrix H of shape (m, n).
        max_bp_iter: Maximum number of BP message passing rounds (default: 30).
        osd_order: OSD search order (default: 10).
        error_probability: Channel prior physical error probability (default: 0.01).
    """

    def __init__(
        self,
        parity_check_matrix: np.ndarray,
        max_bp_iter: int = 30,
        osd_order: int = 10,
        error_probability: float = 0.01,
    ) -> None:
        self.H = parity_check_matrix.copy() % 2
        self.m, self.n = self.H.shape
        self.max_bp_iter = max_bp_iter
        self.osd_order = osd_order
        self.error_probability = error_probability

        # Precompute graph adjacencies for high speed
        self.edges_v_to_c = [np.where(self.H[:, v] == 1)[0] for v in range(self.n)]
        self.edges_c_to_v = [np.where(self.H[c, :] == 1)[0] for c in range(self.m)]

    def decode(self, syndrome: np.ndarray) -> BPOSDResult:
        """Decodes syndrome vector into physical Pauli correction vector.

        Args:
            syndrome: Binary syndrome array of length m.

        Returns:
            BPOSDResult with correction qubit indices and convergence statistics.
        """
        syn = (syndrome.copy() % 2).astype(int)
        if not np.any(syn):
            zero_vec = np.zeros(self.n, dtype=int)
            return BPOSDResult(
                correction=(),
                success=True,
                weight=0,
                converged_bp=True,
                bp_iterations=0,
                correction_vector=zero_vec,
                residual_syndrome=np.zeros(self.m, dtype=int),
            )

        p = max(1e-6, min(0.499, self.error_probability))
        init_llr = float(np.log((1.0 - p) / p))
        llrs = np.full(self.n, init_llr)

        # Message dictionaries:
        # q_vc: variable node v -> check node c
        # r_cv: check node c -> variable node v
        q_vc: dict[tuple[int, int], float] = {
            (v, c): llrs[v] for v in range(self.n) for c in self.edges_v_to_c[v]
        }
        r_cv: dict[tuple[int, int], float] = {
            (c, v): 0.0 for c in range(self.m) for v in self.edges_c_to_v[c]
        }

        bp_iter = 0
        total_llrs = llrs.copy()

        # Step 1: Normalized Min-Sum Belief Propagation
        alpha = 0.75
        for it in range(self.max_bp_iter):
            bp_iter = it + 1
            # Check node update
            for c in range(self.m):
                v_nodes = self.edges_c_to_v[c]
                if len(v_nodes) == 0:
                    continue

                q_vals = [q_vc[(v, c)] for v in v_nodes]
                signs = np.array([1 if x >= 0 else -1 for x in q_vals], dtype=int)
                mags = np.array([abs(x) for x in q_vals], dtype=float)

                prod_sign = ((-1) ** syn[c]) * int(np.prod(signs))
                for idx, v in enumerate(v_nodes):
                    other_mags = np.delete(mags, idx)
                    min_val = float(np.min(other_mags)) if len(other_mags) > 0 else 0.0
                    edge_sign = prod_sign * signs[idx]
                    r_cv[(c, v)] = alpha * edge_sign * min_val

            # Variable node update & calculate marginal LLR
            total_llrs = llrs.copy()
            for v in range(self.n):
                c_nodes = self.edges_v_to_c[v]
                sum_r = sum(r_cv[(c, v)] for c in c_nodes)
                total_llrs[v] += sum_r
                for c in c_nodes:
                    q_vc[(v, c)] = llrs[v] + (sum_r - r_cv[(c, v)])

            # Hard-decision check
            candidate = (total_llrs < 0).astype(int)
            res_syn = (self.H @ candidate) % 2
            if np.all(res_syn == syn):
                corr_tuple = tuple(int(x) for x in np.where(candidate == 1)[0])
                return BPOSDResult(
                    correction=corr_tuple,
                    success=True,
                    weight=int(candidate.sum()),
                    converged_bp=True,
                    bp_iterations=bp_iter,
                    correction_vector=candidate,
                    residual_syndrome=np.zeros(self.m, dtype=int),
                )

        # Step 2: Ordered Statistics Decoding (OSD-0 / MRB Gauss elimination)
        # Order variable nodes by descending reliability |LLR|
        reliability_order = np.argsort(-np.abs(total_llrs))
        Hp = self.H[:, reliability_order].copy()
        syn_work = syn.copy()

        pivot_cols: list[int] = []
        pivot_rows: list[int] = []
        curr_r = 0

        for col_idx in range(self.n):
            candidates = np.where(Hp[curr_r:, col_idx] == 1)[0]
            if len(candidates) == 0:
                continue
            p_row = candidates[0] + curr_r
            if p_row != curr_r:
                Hp[[curr_r, p_row]] = Hp[[p_row, curr_r]]
                syn_work[[curr_r, p_row]] = syn_work[[p_row, curr_r]]

            for r in range(self.m):
                if r != curr_r and Hp[r, col_idx] == 1:
                    Hp[r] = (Hp[r] + Hp[curr_r]) % 2
                    syn_work[r] = (syn_work[r] + syn_work[curr_r]) % 2

            pivot_cols.append(col_idx)
            pivot_rows.append(curr_r)
            curr_r += 1
            if curr_r == self.m:
                break

        # Solve system on MRB pivot columns
        sol_perm = np.zeros(self.n, dtype=int)
        for r, c in zip(pivot_rows, pivot_cols, strict=True):
            sol_perm[c] = syn_work[r]

        correction_vec = np.zeros(self.n, dtype=int)
        correction_vec[reliability_order] = sol_perm

        residual = (self.H @ correction_vec ^ syn) % 2
        success = bool(np.all(residual == 0))
        corr_tuple = tuple(int(x) for x in np.where(correction_vec == 1)[0])

        return BPOSDResult(
            correction=corr_tuple,
            success=success,
            weight=int(correction_vec.sum()),
            converged_bp=False,
            bp_iterations=bp_iter,
            correction_vector=correction_vec,
            residual_syndrome=residual,
        )
decode
decode(syndrome: ndarray) -> BPOSDResult

Decodes syndrome vector into physical Pauli correction vector.

Parameters:

Name Type Description Default
syndrome ndarray

Binary syndrome array of length m.

required

Returns:

Type Description
BPOSDResult

BPOSDResult with correction qubit indices and convergence statistics.

Source code in quanta/qec/qldpc.py
def decode(self, syndrome: np.ndarray) -> BPOSDResult:
    """Decodes syndrome vector into physical Pauli correction vector.

    Args:
        syndrome: Binary syndrome array of length m.

    Returns:
        BPOSDResult with correction qubit indices and convergence statistics.
    """
    syn = (syndrome.copy() % 2).astype(int)
    if not np.any(syn):
        zero_vec = np.zeros(self.n, dtype=int)
        return BPOSDResult(
            correction=(),
            success=True,
            weight=0,
            converged_bp=True,
            bp_iterations=0,
            correction_vector=zero_vec,
            residual_syndrome=np.zeros(self.m, dtype=int),
        )

    p = max(1e-6, min(0.499, self.error_probability))
    init_llr = float(np.log((1.0 - p) / p))
    llrs = np.full(self.n, init_llr)

    # Message dictionaries:
    # q_vc: variable node v -> check node c
    # r_cv: check node c -> variable node v
    q_vc: dict[tuple[int, int], float] = {
        (v, c): llrs[v] for v in range(self.n) for c in self.edges_v_to_c[v]
    }
    r_cv: dict[tuple[int, int], float] = {
        (c, v): 0.0 for c in range(self.m) for v in self.edges_c_to_v[c]
    }

    bp_iter = 0
    total_llrs = llrs.copy()

    # Step 1: Normalized Min-Sum Belief Propagation
    alpha = 0.75
    for it in range(self.max_bp_iter):
        bp_iter = it + 1
        # Check node update
        for c in range(self.m):
            v_nodes = self.edges_c_to_v[c]
            if len(v_nodes) == 0:
                continue

            q_vals = [q_vc[(v, c)] for v in v_nodes]
            signs = np.array([1 if x >= 0 else -1 for x in q_vals], dtype=int)
            mags = np.array([abs(x) for x in q_vals], dtype=float)

            prod_sign = ((-1) ** syn[c]) * int(np.prod(signs))
            for idx, v in enumerate(v_nodes):
                other_mags = np.delete(mags, idx)
                min_val = float(np.min(other_mags)) if len(other_mags) > 0 else 0.0
                edge_sign = prod_sign * signs[idx]
                r_cv[(c, v)] = alpha * edge_sign * min_val

        # Variable node update & calculate marginal LLR
        total_llrs = llrs.copy()
        for v in range(self.n):
            c_nodes = self.edges_v_to_c[v]
            sum_r = sum(r_cv[(c, v)] for c in c_nodes)
            total_llrs[v] += sum_r
            for c in c_nodes:
                q_vc[(v, c)] = llrs[v] + (sum_r - r_cv[(c, v)])

        # Hard-decision check
        candidate = (total_llrs < 0).astype(int)
        res_syn = (self.H @ candidate) % 2
        if np.all(res_syn == syn):
            corr_tuple = tuple(int(x) for x in np.where(candidate == 1)[0])
            return BPOSDResult(
                correction=corr_tuple,
                success=True,
                weight=int(candidate.sum()),
                converged_bp=True,
                bp_iterations=bp_iter,
                correction_vector=candidate,
                residual_syndrome=np.zeros(self.m, dtype=int),
            )

    # Step 2: Ordered Statistics Decoding (OSD-0 / MRB Gauss elimination)
    # Order variable nodes by descending reliability |LLR|
    reliability_order = np.argsort(-np.abs(total_llrs))
    Hp = self.H[:, reliability_order].copy()
    syn_work = syn.copy()

    pivot_cols: list[int] = []
    pivot_rows: list[int] = []
    curr_r = 0

    for col_idx in range(self.n):
        candidates = np.where(Hp[curr_r:, col_idx] == 1)[0]
        if len(candidates) == 0:
            continue
        p_row = candidates[0] + curr_r
        if p_row != curr_r:
            Hp[[curr_r, p_row]] = Hp[[p_row, curr_r]]
            syn_work[[curr_r, p_row]] = syn_work[[p_row, curr_r]]

        for r in range(self.m):
            if r != curr_r and Hp[r, col_idx] == 1:
                Hp[r] = (Hp[r] + Hp[curr_r]) % 2
                syn_work[r] = (syn_work[r] + syn_work[curr_r]) % 2

        pivot_cols.append(col_idx)
        pivot_rows.append(curr_r)
        curr_r += 1
        if curr_r == self.m:
            break

    # Solve system on MRB pivot columns
    sol_perm = np.zeros(self.n, dtype=int)
    for r, c in zip(pivot_rows, pivot_cols, strict=True):
        sol_perm[c] = syn_work[r]

    correction_vec = np.zeros(self.n, dtype=int)
    correction_vec[reliability_order] = sol_perm

    residual = (self.H @ correction_vec ^ syn) % 2
    success = bool(np.all(residual == 0))
    corr_tuple = tuple(int(x) for x in np.where(correction_vec == 1)[0])

    return BPOSDResult(
        correction=corr_tuple,
        success=success,
        weight=int(correction_vec.sum()),
        converged_bp=False,
        bp_iterations=bp_iter,
        correction_vector=correction_vec,
        residual_syndrome=residual,
    )

BPOSDResult dataclass

Result of BP-OSD decoding on a qLDPC code.

Attributes:

Name Type Description
correction tuple[int, ...]

Indices of data qubits to flip.

success bool

Whether the correction vector satisfies the syndrome H · c = s (mod 2).

weight int

Total Hamming weight of the correction.

converged_bp bool

Whether Belief Propagation converged without requiring OSD fallback.

bp_iterations int

Number of BP message-passing iterations executed.

correction_vector ndarray

Binary numpy array of length n representing the correction.

residual_syndrome ndarray

Residual syndrome (H · c ⊕ s) mod 2 (all zeros on success).

Source code in quanta/qec/qldpc.py
@dataclass
class BPOSDResult:
    """Result of BP-OSD decoding on a qLDPC code.

    Attributes:
        correction: Indices of data qubits to flip.
        success: Whether the correction vector satisfies the syndrome H · c = s (mod 2).
        weight: Total Hamming weight of the correction.
        converged_bp: Whether Belief Propagation converged without requiring OSD fallback.
        bp_iterations: Number of BP message-passing iterations executed.
        correction_vector: Binary numpy array of length n representing the correction.
        residual_syndrome: Residual syndrome (H · c ⊕ s) mod 2 (all zeros on success).
    """

    correction: tuple[int, ...]
    success: bool
    weight: int
    converged_bp: bool
    bp_iterations: int
    correction_vector: np.ndarray
    residual_syndrome: np.ndarray

    def __repr__(self) -> str:
        return (
            f"BPOSDResult(success={self.success}, weight={self.weight}, "
            f"converged_bp={self.converged_bp}, iter={self.bp_iterations}, "
            f"qubits={self.correction})"
        )

BivariateBicycleCode

Bivariate Bicycle (BB) qLDPC code over F_2[x, y] / .

Defines an [[n = 2lm, k, d]] CSS stabilizer code using commuting circulant blocks A and B generated by bivariate polynomials: H_X = [A | B] H_Z = [B^T | A^T]

Commutativity [A, B] = 0 over F_2 guarantees CSS orthogonality: H_X @ H_Z^T = A @ B + B @ A = 2 AB = 0 (mod 2).

Parameters:

Name Type Description Default
ell int

Cyclic shift dimension along x (default: 12).

12
m int

Cyclic shift dimension along y (default: 6).

6
A_poly list[tuple[int, int]] | None

List of (power_x, power_y) terms in polynomial A(x, y). Default: Gross code [(3, 0), (0, 1), (0, 2)] -> x^3 + y + y^2.

None
B_poly list[tuple[int, int]] | None

List of (power_x, power_y) terms in polynomial B(x, y). Default: Gross code [(0, 3), (1, 0), (2, 0)] -> y^3 + x + x^2.

None
Source code in quanta/qec/qldpc.py
class BivariateBicycleCode:
    """Bivariate Bicycle (BB) qLDPC code over F_2[x, y] / <x^l - 1, y^m - 1>.

    Defines an [[n = 2lm, k, d]] CSS stabilizer code using commuting
    circulant blocks A and B generated by bivariate polynomials:
        H_X = [A | B]
        H_Z = [B^T | A^T]

    Commutativity [A, B] = 0 over F_2 guarantees CSS orthogonality:
        H_X @ H_Z^T = A @ B + B @ A = 2 AB = 0 (mod 2).

    Args:
        ell: Cyclic shift dimension along x (default: 12).
        m: Cyclic shift dimension along y (default: 6).
        A_poly: List of (power_x, power_y) terms in polynomial A(x, y).
            Default: Gross code [(3, 0), (0, 1), (0, 2)] -> x^3 + y + y^2.
        B_poly: List of (power_x, power_y) terms in polynomial B(x, y).
            Default: Gross code [(0, 3), (1, 0), (2, 0)] -> y^3 + x + x^2.
    """

    def __init__(
        self,
        ell: int = 12,
        m: int = 6,
        A_poly: list[tuple[int, int]] | None = None,
        B_poly: list[tuple[int, int]] | None = None,
    ) -> None:
        if ell <= 0 or m <= 0:
            raise ValueError(f"Dimensions ell and m must be positive. Got ell={ell}, m={m}")

        self.l = ell
        self.ell = ell
        self.m = m
        self.n = 2 * ell * m

        # Default: Gross [[144, 12, 12]] polynomials from Bravyi et al. (Nature 2024)
        if A_poly is None:
            A_poly = [(3, 0), (0, 1), (0, 2)]
        if B_poly is None:
            B_poly = [(0, 3), (1, 0), (2, 0)]

        self.A_poly = A_poly
        self.B_poly = B_poly

        # Construct group ring circulant matrices A and B
        self.A_matrix = self._build_poly_matrix(ell, m, self.A_poly)
        self.B_matrix = self._build_poly_matrix(ell, m, self.B_poly)

        # CSS parity check matrices:
        # H_X checks phase flips (Z errors), shape (l*m, 2*l*m)
        # H_Z checks bit flips (X errors), shape (l*m, 2*l*m)
        self.H_X = np.hstack([self.A_matrix, self.B_matrix])
        self.H_Z = np.hstack([self.B_matrix.T, self.A_matrix.T])

        # Compute code parameters: k = n - rank(H_X) - rank(H_Z)
        self._rank_hx = self._gf2_rank(self.H_X)
        self._rank_hz = self._gf2_rank(self.H_Z)
        self.k = self.n - self._rank_hx - self._rank_hz
        self.d = 12 if (ell == 12 and m == 6) else max(2, min(ell, m))

    @classmethod
    def gross_144_12_12(cls) -> BivariateBicycleCode:
        """Constructs the canonical Gross [[144, 12, 12]] bivariate bicycle code."""
        return cls(ell=12, m=6, A_poly=[(3, 0), (0, 1), (0, 2)], B_poly=[(0, 3), (1, 0), (2, 0)])

    @staticmethod
    def _shift_matrix(size: int, shift: int) -> np.ndarray:
        """Constructs cyclic permutation matrix P of size with P_ij = delta_{i, (j+shift)%size}."""
        mat = np.zeros((size, size), dtype=int)
        for i in range(size):
            mat[i, (i + shift) % size] = 1
        return mat

    @classmethod
    def _build_poly_matrix(cls, ell: int, m: int, terms: list[tuple[int, int]]) -> np.ndarray:
        """Builds (ell*m) x (ell*m) binary matrix for bivariate polynomial sum x^px y^py."""
        mat = np.zeros((ell * m, ell * m), dtype=int)
        for px, py in terms:
            mx = cls._shift_matrix(ell, px % ell)
            my = cls._shift_matrix(m, py % m)
            mat = (mat + np.kron(mx, my)) % 2
        return mat

    @staticmethod
    def _gf2_rank(matrix: np.ndarray) -> int:
        """Computes matrix rank over Galois Field GF(2)."""
        m = matrix.copy() % 2
        rows, cols = m.shape
        pivot_row = 0
        for col in range(cols):
            candidates = np.where(m[pivot_row:, col] == 1)[0]
            if len(candidates) == 0:
                continue
            cand = candidates[0] + pivot_row
            if cand != pivot_row:
                m[[pivot_row, cand]] = m[[cand, pivot_row]]
            for r in range(rows):
                if r != pivot_row and m[r, col] == 1:
                    m[r] = (m[r] + m[pivot_row]) % 2
            pivot_row += 1
            if pivot_row == rows:
                break
        return pivot_row

    @property
    def is_css_orthogonal(self) -> bool:
        """Verifies CSS commutation condition H_X @ H_Z^T == 0 (mod 2)."""
        comm = (self.H_X @ self.H_Z.T) % 2
        return bool(np.all(comm == 0))

    @property
    def code_params(self) -> str:
        """Returns standard [[n, k, d]] parameter string."""
        return f"[[{self.n}, {self.k}, {self.d}]]"

    @property
    def check_weight(self) -> int:
        """Maximum row weight of stabilizer checks."""
        return int(max(self.H_X.sum(axis=1).max(), self.H_Z.sum(axis=1).max()))

    @property
    def qubit_weight(self) -> int:
        """Maximum column weight (number of checks touching each qubit)."""
        return int(max(self.H_X.sum(axis=0).max(), self.H_Z.sum(axis=0).max()))

    def get_x_syndrome(self, z_errors: np.ndarray) -> np.ndarray:
        """Extracts X-stabilizer syndrome s_X = (H_X @ e_Z) mod 2."""
        return (self.H_X @ (z_errors % 2)) % 2

    def get_z_syndrome(self, x_errors: np.ndarray) -> np.ndarray:
        """Extracts Z-stabilizer syndrome s_Z = (H_Z @ e_X) mod 2."""
        return (self.H_Z @ (x_errors % 2)) % 2

    def summary(self) -> str:
        """Returns a formatted summary of code properties."""
        lines = [
            "╔══════════════════════════════════════════════════╗",
            "║  Bivariate Bicycle qLDPC Code                    ║",
            "╠══════════════════════════════════════════════════╣",
            f"║  Parameters:                {self.code_params:<21}║",
            f"║  Physical Qubits (n):       {self.n:<21}║",
            f"║  Logical Qubits (k):        {self.k:<21}║",
            f"║  Code Distance (d):         {self.d:<21}║",
            f"║  Check Weight (row):        {self.check_weight:<21}║",
            f"║  Qubit Weight (col):        {self.qubit_weight:<21}║",
            f"║  CSS Orthogonality:         {'VALID (H_X @ H_Z^T == 0)':<21}║",
            "╚══════════════════════════════════════════════════╝",
        ]
        return "\n".join(lines)

    def __repr__(self) -> str:
        return f"BivariateBicycleCode({self.code_params}, l={self.l}, m={self.m})"
check_weight property
check_weight: int

Maximum row weight of stabilizer checks.

code_params property
code_params: str

Returns standard [[n, k, d]] parameter string.

is_css_orthogonal property
is_css_orthogonal: bool

Verifies CSS commutation condition H_X @ H_Z^T == 0 (mod 2).

qubit_weight property
qubit_weight: int

Maximum column weight (number of checks touching each qubit).

get_x_syndrome
get_x_syndrome(z_errors: ndarray) -> np.ndarray

Extracts X-stabilizer syndrome s_X = (H_X @ e_Z) mod 2.

Source code in quanta/qec/qldpc.py
def get_x_syndrome(self, z_errors: np.ndarray) -> np.ndarray:
    """Extracts X-stabilizer syndrome s_X = (H_X @ e_Z) mod 2."""
    return (self.H_X @ (z_errors % 2)) % 2
get_z_syndrome
get_z_syndrome(x_errors: ndarray) -> np.ndarray

Extracts Z-stabilizer syndrome s_Z = (H_Z @ e_X) mod 2.

Source code in quanta/qec/qldpc.py
def get_z_syndrome(self, x_errors: np.ndarray) -> np.ndarray:
    """Extracts Z-stabilizer syndrome s_Z = (H_Z @ e_X) mod 2."""
    return (self.H_Z @ (x_errors % 2)) % 2
gross_144_12_12 classmethod
gross_144_12_12() -> BivariateBicycleCode

Constructs the canonical Gross [[144, 12, 12]] bivariate bicycle code.

Source code in quanta/qec/qldpc.py
@classmethod
def gross_144_12_12(cls) -> BivariateBicycleCode:
    """Constructs the canonical Gross [[144, 12, 12]] bivariate bicycle code."""
    return cls(ell=12, m=6, A_poly=[(3, 0), (0, 1), (0, 2)], B_poly=[(0, 3), (1, 0), (2, 0)])
summary
summary() -> str

Returns a formatted summary of code properties.

Source code in quanta/qec/qldpc.py
def summary(self) -> str:
    """Returns a formatted summary of code properties."""
    lines = [
        "╔══════════════════════════════════════════════════╗",
        "║  Bivariate Bicycle qLDPC Code                    ║",
        "╠══════════════════════════════════════════════════╣",
        f"║  Parameters:                {self.code_params:<21}║",
        f"║  Physical Qubits (n):       {self.n:<21}║",
        f"║  Logical Qubits (k):        {self.k:<21}║",
        f"║  Code Distance (d):         {self.d:<21}║",
        f"║  Check Weight (row):        {self.check_weight:<21}║",
        f"║  Qubit Weight (col):        {self.qubit_weight:<21}║",
        f"║  CSS Orthogonality:         {'VALID (H_X @ H_Z^T == 0)':<21}║",
        "╚══════════════════════════════════════════════════╝",
    ]
    return "\n".join(lines)