Skip to content

Commit

Permalink
Further encoding circuis and tweak to encoder synthesis.
Browse files Browse the repository at this point in the history
  • Loading branch information
pehamTom committed Sep 9, 2024
1 parent c9817f4 commit d274fe1
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 2 deletions.
47 changes: 46 additions & 1 deletion src/mqt/qecc/circuit_synthesis/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import functools
import logging
import operator
from typing import TYPE_CHECKING

import numpy as np
Expand All @@ -21,12 +22,15 @@
logger = logging.getLogger(__name__)


def heuristic_encoding_circuit(code: CSSCode, optimize_depth: bool = True) -> QuantumCircuit:
def heuristic_encoding_circuit(
code: CSSCode, optimize_depth: bool = True, balance_checks: bool = True
) -> QuantumCircuit:
"""Synthesize an encoding circuit for the given CSS code using a heuristic greedy search.
Args:
code: The CSS code to synthesize the encoding circuit for.
optimize_depth: Whether to optimize the depth of the circuit.
balance_checks: Whether to balance the entries of the stabilizer matrix via row operations.
Returns:
The synthesized encoding circuit and the qubits that are used to encode the logical qubits.
Expand All @@ -35,6 +39,10 @@ def heuristic_encoding_circuit(code: CSSCode, optimize_depth: bool = True) -> Qu

checks, logicals, use_x_checks = _get_matrix_with_fewest_checks(code)
n_checks = checks.shape[0]

if balance_checks:
_balance_matrix(logicals)

checks, cnots = heuristic_gaussian_elimination(
np.vstack((checks, logicals)),
parallel_elimination=optimize_depth,
Expand Down Expand Up @@ -210,3 +218,40 @@ def _build_css_encoder_from_cnot_list(
hadamards = np.setdiff1d(hadamards, encoding_qubits)
circ = build_css_circuit_from_cnot_list(checks_and_logicals.shape[1], cnots, list(hadamards))
return circ, encoding_qubits


def _balance_matrix(m: npt.NDArray[np.int8]) -> None:
"""Balance the columns of the matrix.
Try to balance the number of 1's in each column via row operations without increasing the row-weight.
"""
variance = np.var(m.sum(axis=0))
reduced = False

while not reduced:
reduced = True
# compute row operations that do not increase the row-weights
row_ops = []
for i, row_1 in enumerate(m):
for j, row_2 in enumerate(m):
if i == j:
continue
s = (row_1 + row_2) % 2
if s.sum() > row_1.sum() or s.sum() > row_2.sum():
continue
# compute associated column weights
m[j] = s # noqa: B909

new_variance = np.var(m.sum(axis=0))
if new_variance < variance:
row_ops.append((i, j, new_variance))

m[j] = row_2 # noqa: B909
# sort by lowest variance
row_ops.sort(key=operator.itemgetter(2))
# apply best row operation
if row_ops:
i, j = row_ops[0][:2]
m[i] = (m[i] + m[j]) % 2
reduced = False
variance = row_ops[0][2]
31 changes: 31 additions & 0 deletions src/mqt/qecc/circuit_synthesis/encoding_circuits/carbon.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Encoding Qubits: 0,4
OPENQASM 2.0;
include "qelib1.inc";
qreg q[12];
h q[5];
h q[8];
h q[9];
h q[10];
h q[11];
cx q[9],q[2];
cx q[5],q[2];
cx q[11],q[1];
cx q[8],q[7];
cx q[5],q[4];
cx q[10],q[3];
cx q[9],q[1];
cx q[2],q[0];
cx q[11],q[7];
cx q[0],q[6];
cx q[1],q[4];
cx q[8],q[3];
cx q[4],q[7];
cx q[10],q[6];
cx q[3],q[2];
cx q[1],q[0];
cx q[6],q[11];
cx q[5],q[10];
cx q[7],q[9];
cx q[0],q[8];
cx q[2],q[1];
cx q[4],q[3];
43 changes: 43 additions & 0 deletions src/mqt/qecc/circuit_synthesis/encoding_circuits/hamming.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Encoding Qubits: 0,1,2,3,4,6,12
OPENQASM 2.0;
include "qelib1.inc";
qreg q[15];
h q[7];
h q[10];
h q[11];
h q[13];
cx q[13],q[8];
cx q[7],q[1];
cx q[7],q[8];
cx q[1],q[6];
cx q[13],q[9];
cx q[6],q[8];
cx q[8],q[12];
cx q[2],q[9];
cx q[1],q[9];
cx q[12],q[5];
cx q[11],q[4];
cx q[10],q[5];
cx q[8],q[4];
cx q[9],q[0];
cx q[11],q[14];
cx q[2],q[10];
cx q[5],q[4];
cx q[1],q[3];
cx q[7],q[0];
cx q[6],q[14];
cx q[10],q[13];
cx q[4],q[12];
cx q[3],q[11];
cx q[0],q[5];
cx q[13],q[14];
cx q[6],q[10];
cx q[11],q[8];
cx q[5],q[3];
cx q[4],q[2];
cx q[12],q[11];
cx q[9],q[7];
cx q[5],q[2];
cx q[8],q[0];
cx q[4],q[6];
cx q[14],q[10];
15 changes: 15 additions & 0 deletions src/mqt/qecc/circuit_synthesis/encoding_circuits/shor.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Encoding Qubits: 2
OPENQASM 2.0;
include "qelib1.inc";
qreg q[9];
h q[0];
h q[6];
cx q[6],q[2];
cx q[0],q[3];
cx q[6],q[8];
cx q[3],q[4];
cx q[2],q[0];
cx q[6],q[7];
cx q[4],q[5];
cx q[3],q[2];
cx q[0],q[1];
16 changes: 16 additions & 0 deletions src/mqt/qecc/circuit_synthesis/encoding_circuits/steane.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Encoding Qubits: 2
OPENQASM 2.0;
include "qelib1.inc";
qreg q[7];
h q[4];
h q[5];
h q[6];
cx q[5],q[1];
cx q[1],q[2];
cx q[4],q[0];
cx q[6],q[4];
cx q[5],q[3];
cx q[2],q[0];
cx q[6],q[3];
cx q[4],q[5];
cx q[0],q[1];
17 changes: 17 additions & 0 deletions src/mqt/qecc/circuit_synthesis/encoding_circuits/surface.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Encoding Qubits: 0
OPENQASM 2.0;
include "qelib1.inc";
qreg q[9];
h q[3];
h q[5];
h q[6];
h q[7];
cx q[7],q[4];
cx q[3],q[0];
cx q[3],q[4];
cx q[5],q[2];
cx q[0],q[1];
cx q[7],q[8];
cx q[4],q[5];
cx q[1],q[2];
cx q[6],q[3];
32 changes: 32 additions & 0 deletions src/mqt/qecc/circuit_synthesis/encoding_circuits/tetrahedral.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Encoding Qubits: 8
OPENQASM 2.0;
include "qelib1.inc";
qreg q[15];
h q[0];
h q[1];
h q[2];
h q[14];
cx q[8],q[10];
cx q[2],q[9];
cx q[1],q[12];
cx q[0],q[7];
cx q[14],q[7];
cx q[12],q[8];
cx q[10],q[0];
cx q[9],q[11];
cx q[2],q[5];
cx q[1],q[4];
cx q[14],q[12];
cx q[11],q[13];
cx q[9],q[10];
cx q[5],q[6];
cx q[2],q[3];
cx q[7],q[4];
cx q[0],q[1];
cx q[14],q[13];
cx q[12],q[11];
cx q[8],q[9];
cx q[7],q[6];
cx q[0],q[3];
cx q[4],q[5];
cx q[1],q[2];
28 changes: 27 additions & 1 deletion test/python/circuit_synthesis/test_encoder_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@ def steane_code() -> CSSCode:
return CSSCode.from_code_name("Steane")


@pytest.fixture
def surface_3() -> CSSCode:
"""Return the surface code."""
return CSSCode.from_code_name("surface", 3)


@pytest.fixture
def tetrahedral() -> CSSCode:
"""Return the tetrahedral code."""
return CSSCode.from_code_name("tetrahedral")


@pytest.fixture
def hamming() -> CSSCode:
"""Return the Hamming code."""
return CSSCode.from_code_name("Hamming")


@pytest.fixture
def shor() -> CSSCode:
"""Return the Shor code."""
return CSSCode.from_code_name("Shor")


@pytest.fixture
def css_4_2_2_code() -> CSSCode:
"""Return the 4,2,2 code."""
Expand Down Expand Up @@ -69,7 +93,9 @@ def _assert_correct_encoding_circuit(encoder: QuantumCircuit, encoding_qubits: l
assert in_span(np.vstack((code.Hx, code.Lx)), logical)


@pytest.mark.parametrize("code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code"])
@pytest.mark.parametrize(
"code", ["steane_code", "css_4_2_2_code", "css_6_2_2_code", "tetrahedral", "surface_3", "hamming", "shor"]
)
def test_heuristic_encoding_consistent(code: CSSCode, request) -> None: # type: ignore[no-untyped-def]
"""Check that heuristic_encoding_circuit returns a valid circuit with the correct stabilizers."""
code = request.getfixturevalue(code)
Expand Down

0 comments on commit d274fe1

Please sign in to comment.