跳转至

CnotBipartite

QuICT.qcda.optimization.cnot_dag.CnotBipartite

Optimize a bipartite CNOT circuit. A CNOT circuit is said to be bipartite if all the control qubits and target qubits of CNOT gates can be grouped into 2 seperated subset of qubits.

Examples:

from QuICT.qcda.optimization.cnot_dag import CnotBipartite cb = CnotBipartite()

Input circuit has 3 qubits on each side of bipartite.

Every qubit is connected with all qubits on the other side.

circ = cb.execute(3, 3, [(0, 3), (0, 4), (0, 5), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)])

execute classmethod

execute(left: int, right: int, edges: List[Tuple[int, int]], n_ancilla: int = 0) -> Circuit

Execute optimization.

Parameters:

  • left (int) –

    The number of qubits on left side of bipartite.

  • right (int) –

    The number of qubits on right side of bipartite.

  • edges (List[Tuple[int, int]]) –

    All CNOT gates as edges starting from control qubits and ending at target qubits.

  • n_ancilla (int, default: 0 ) –

    The number of ancillary qubits, default 0. If provided, ancillae number must be larger than number of edges.

Source code in QuICT/qcda/optimization/cnot_dag/bipartite.py
@classmethod
def execute(
        cls, left: int, right: int, edges: List[Tuple[int, int]], n_ancilla: int = 0,
) -> Circuit:
    """Execute optimization.

    Args:
        left (int): The number of qubits on left side of bipartite.
        right (int): The number of qubits on right side of bipartite.
        edges (List[Tuple[int, int]]): All CNOT gates as edges starting from control qubits and ending
            at target qubits.
        n_ancilla (int): The number of ancillary qubits, default 0. If provided, ancillae number must
            be larger than number of edges.
    """
    n = left + right + n_ancilla
    if n_ancilla > 0:
        assert n_ancilla == len(
            edges), "If using ancilla, the number of ancillary qubits must be the same with bipartite edges."

    circ = Circuit(n)

    if len(edges) == 0:
        return circ

    if n <= 2:
        for c, t in edges:
            CX | circ([c, t])
        return circ

    e_from = {}
    e_to = {}
    e_ancillae = {}
    _a = n - n_ancilla
    for f, t in edges:
        assert f < left, "Edge must start from left part of bipartite!"
        assert left <= t < left + right, "Edge must end in right part of bipartite!"
        e_ancillae[f, t] = _a
        _a += 1
        if f not in e_from:
            e_from[f] = []
        e_from[f].append(t)
        if t not in e_to:
            e_to[t] = []
        e_to[t].append(f)

    # if no ancilla, we use part of original qubits.
    if n_ancilla == 0:
        seg = n // 3
        part_n_ancilla = n - 2 * seg

        for i in range((len(edges) + seg - 1) // seg):
            start = i * seg
            end = min((i + 1) * seg, len(edges))
            circ = cls._partition_exec(circ=circ, edges=edges[start:end], n_ancilla=part_n_ancilla)
        return circ

    e_ancillae = {}
    _a = n - n_ancilla
    for f, t in edges:
        e_ancillae[f, t] = _a
        _a += 1

    circ = cls._start(circ, e_from, e_ancillae)
    circ = cls._to(circ, e_to, e_ancillae)
    circ = cls._start(circ, e_from, e_ancillae)
    circ = cls._to(circ, e_to, e_ancillae)

    return circ