qiskit.synthesis.linear_phase.cz_depth_lnn のソースコード

# This code is part of Qiskit.
#
# (C) Copyright IBM 2023
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Synthesis of an n-qubit circuit containing only CZ gates for
linear nearest neighbor (LNN) connectivity, using CX and phase (S, Sdg or Z) gates.
The two-qubit depth of the circuit is bounded by 2*n+2.
This algorithm reverts the order of qubits.

References:
    [1]: Dmitri Maslov, Martin Roetteler,
         Shorter stabilizer circuits via Bruhat decomposition and quantum circuit transformations,
         `arXiv:1705.09176 <https://arxiv.org/abs/1705.09176>`_.
"""

import numpy as np
from qiskit.circuit import QuantumCircuit


def _append_cx_stage1(qc, n):
    """A single layer of CX gates."""
    for i in range(n // 2):
        qc.cx(2 * i, 2 * i + 1)
    for i in range((n + 1) // 2 - 1):
        qc.cx(2 * i + 2, 2 * i + 1)
    return qc


def _append_cx_stage2(qc, n):
    """A single layer of CX gates."""
    for i in range(n // 2):
        qc.cx(2 * i + 1, 2 * i)
    for i in range((n + 1) // 2 - 1):
        qc.cx(2 * i + 1, 2 * i + 2)
    return qc


def _odd_pattern1(n):
    """A pattern denoted by Pj in [1] for odd number of qubits:
    [n-2, n-4, n-4, ..., 3, 3, 1, 1, 0, 0, 2, 2, ..., n-3, n-3]
    """
    pat = []
    pat.append(n - 2)
    for i in range((n - 3) // 2):
        pat.append(n - 2 * i - 4)
        pat.append(n - 2 * i - 4)
    for i in range((n - 1) // 2):
        pat.append(2 * i)
        pat.append(2 * i)
    return pat


def _odd_pattern2(n):
    """A pattern denoted by Pk in [1] for odd number of qubits:
    [2, 2, 4, 4, ..., n-1, n-1, n-2, n-2, n-4, n-4, ..., 5, 5, 3, 3, 1]
    """
    pat = []
    for i in range((n - 1) // 2):
        pat.append(2 * i + 2)
        pat.append(2 * i + 2)
    for i in range((n - 3) // 2):
        pat.append(n - 2 * i - 2)
        pat.append(n - 2 * i - 2)
    pat.append(1)
    return pat


def _even_pattern1(n):
    """A pattern denoted by Pj in [1] for even number of qubits:
    [n-1, n-3, n-3, n-5, n-5, ..., 1, 1, 0, 0, 2, 2, ..., n-4, n-4, n-2]
    """
    pat = []
    pat.append(n - 1)
    for i in range((n - 2) // 2):
        pat.append(n - 2 * i - 3)
        pat.append(n - 2 * i - 3)
    for i in range((n - 2) // 2):
        pat.append(2 * i)
        pat.append(2 * i)
    pat.append(n - 2)
    return pat


def _even_pattern2(n):
    """A pattern denoted by Pk in [1] for even number of qubits:
    [2, 2, 4, 4, ..., n-2, n-2, n-1, n-1, ..., 3, 3, 1, 1]
    """
    pat = []
    for i in range((n - 2) // 2):
        pat.append(2 * (i + 1))
        pat.append(2 * (i + 1))
    for i in range(n // 2):
        pat.append(n - 2 * i - 1)
        pat.append(n - 2 * i - 1)
    return pat


def _create_patterns(n):
    """Creating the patterns for the phase layers."""
    if (n % 2) == 0:
        pat1 = _even_pattern1(n)
        pat2 = _even_pattern2(n)
    else:
        pat1 = _odd_pattern1(n)
        pat2 = _odd_pattern2(n)
    pats = {}

    layer = 0
    for i in range(n):
        pats[(0, i)] = (i, i)

    if (n % 2) == 0:
        ind1 = (2 * n - 4) // 2
    else:
        ind1 = (2 * n - 4) // 2 - 1
    ind2 = 0
    while layer < (n // 2):
        for i in range(n):
            pats[(layer + 1, i)] = (pat1[ind1 + i], pat2[ind2 + i])
        layer += 1
        ind1 -= 2
        ind2 += 2
    return pats


[ドキュメント]def synth_cz_depth_line_mr(mat: np.ndarray): """Synthesis of a CZ circuit for linear nearest neighbour (LNN) connectivity, based on Maslov and Roetteler. Note that this method *reverts* the order of qubits in the circuit, and returns a circuit containing CX and phase (S, Sdg or Z) gates. Args: mat: an upper-diagonal matrix representing the CZ circuit. mat[i][j]=1 for i<j represents a CZ(i,j) gate Return: QuantumCircuit: a circuit implementation of the CZ circuit of depth 2*n+2 for LNN connectivity. Reference: 1. Dmitri Maslov, Martin Roetteler, *Shorter stabilizer circuits via Bruhat decomposition and quantum circuit transformations*, `arXiv:1705.09176 <https://arxiv.org/abs/1705.09176>`_. """ num_qubits = mat.shape[0] pats = _create_patterns(num_qubits) patlist = [] # s_gates[i] = 0, 1, 2 or 3 for a gate id, sdg, z or s on qubit i respectively s_gates = np.zeros(num_qubits) qc = QuantumCircuit(num_qubits) for i in range(num_qubits): for j in range(i + 1, num_qubits): if mat[i][j]: # CZ(i,j) gate s_gates[i] += 2 # qc.z[i] s_gates[j] += 2 # qc.z[j] patlist.append((i, j - 1)) patlist.append((i, j)) patlist.append((i + 1, j - 1)) patlist.append((i + 1, j)) for i in range((num_qubits + 1) // 2): for j in range(num_qubits): if pats[(i, j)] in patlist: patcnt = patlist.count(pats[(i, j)]) for _ in range(patcnt): s_gates[j] += 1 # qc.sdg[j] # Add phase gates: s, sdg or z for j in range(num_qubits): if s_gates[j] % 4 == 1: qc.sdg(j) elif s_gates[j] % 4 == 2: qc.z(j) elif s_gates[j] % 4 == 3: qc.s(j) qc = _append_cx_stage1(qc, num_qubits) qc = _append_cx_stage2(qc, num_qubits) s_gates = np.zeros(num_qubits) if (num_qubits % 2) == 0: i = num_qubits // 2 for j in range(num_qubits): if pats[(i, j)] in patlist and pats[(i, j)][0] != pats[(i, j)][1]: patcnt = patlist.count(pats[(i, j)]) for _ in range(patcnt): s_gates[j] += 1 # qc.sdg[j] # Add phase gates: s, sdg or z for j in range(num_qubits): if s_gates[j] % 4 == 1: qc.sdg(j) elif s_gates[j] % 4 == 2: qc.z(j) elif s_gates[j] % 4 == 3: qc.s(j) qc = _append_cx_stage1(qc, num_qubits) return qc