mirror of https://github.com/Qiskit/qiskit.git
Port `synth_cz_depth_line_mr` to Rust (#12949)
* First pass, pre cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * optimizations and cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * more cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * broke out function Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * reformat Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * comments for append_cx Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * correct usize usage Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * added _inner to function name Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * changed directory structure Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * port _append_reverse_permutation_lnn_kms Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * concise function, added sdg comment, all to usize Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * port synth_permutation_reverse_lnn_kms to rust Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * readded Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * release notes and simplified comment Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * Update releasenotes/notes/port-synth-cz-depth-line-mr-to-rust-1376d5a41948112a.yaml Co-authored-by: Alexander Ivrii <alexi@il.ibm.com> * promoted to docstring and added new docstrings Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * Update crates/accelerate/src/synthesis/linear_phase/cz_depth_lnn.rs Co-authored-by: Julien Gacon <gaconju@gmail.com> --------- Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> Co-authored-by: Alexander Ivrii <alexi@il.ibm.com> Co-authored-by: Julien Gacon <gaconju@gmail.com>
This commit is contained in:
parent
5c8edd4040
commit
a11e76ca7d
|
@ -0,0 +1,171 @@
|
|||
// This code is part of Qiskit.
|
||||
//
|
||||
// (C) Copyright IBM 2024
|
||||
//
|
||||
// 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.
|
||||
|
||||
use std::iter::once;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use ndarray::{Array1, ArrayView2};
|
||||
|
||||
use qiskit_circuit::{
|
||||
operations::{Param, StandardGate},
|
||||
Qubit,
|
||||
};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::synthesis::permutation::{_append_cx_stage1, _append_cx_stage2};
|
||||
|
||||
// A sequence of Lnn gates
|
||||
// Represents the return type for Lnn Synthesis algorithms
|
||||
pub(crate) type LnnGatesVec = Vec<(StandardGate, SmallVec<[Param; 3]>, SmallVec<[Qubit; 2]>)>;
|
||||
|
||||
/// 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]
|
||||
fn _odd_pattern1(n: usize) -> Vec<usize> {
|
||||
once(n - 2)
|
||||
.chain((0..((n - 3) / 2)).flat_map(|i| [(n - 2 * i - 4); 2]))
|
||||
.chain((0..((n - 1) / 2)).flat_map(|i| [2 * i; 2]))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 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]
|
||||
fn _odd_pattern2(n: usize) -> Vec<usize> {
|
||||
(0..((n - 1) / 2))
|
||||
.flat_map(|i| [(2 * i + 2); 2])
|
||||
.chain((0..((n - 3) / 2)).flat_map(|i| [n - 2 * i - 2; 2]))
|
||||
.chain(once(1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 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]
|
||||
fn _even_pattern1(n: usize) -> Vec<usize> {
|
||||
once(n - 1)
|
||||
.chain((0..((n - 2) / 2)).flat_map(|i| [n - 2 * i - 3; 2]))
|
||||
.chain((0..((n - 2) / 2)).flat_map(|i| [2 * i; 2]))
|
||||
.chain(once(n - 2))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 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]
|
||||
fn _even_pattern2(n: usize) -> Vec<usize> {
|
||||
(0..((n - 2) / 2))
|
||||
.flat_map(|i| [2 * (i + 1); 2])
|
||||
.chain((0..(n / 2)).flat_map(|i| [(n - 2 * i - 1); 2]))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Creating the patterns for the phase layers.
|
||||
fn _create_patterns(n: usize) -> HashMap<(usize, usize), (usize, usize)> {
|
||||
let (pat1, pat2) = if n % 2 == 0 {
|
||||
(_even_pattern1(n), _even_pattern2(n))
|
||||
} else {
|
||||
(_odd_pattern1(n), _odd_pattern2(n))
|
||||
};
|
||||
|
||||
let ind = if n % 2 == 0 {
|
||||
(2 * n - 4) / 2
|
||||
} else {
|
||||
(2 * n - 4) / 2 - 1
|
||||
};
|
||||
|
||||
HashMap::from_iter((0..n).map(|i| ((0, i), (i, i))).chain(
|
||||
(0..(n / 2)).cartesian_product(0..n).map(|(layer, i)| {
|
||||
(
|
||||
(layer + 1, i),
|
||||
(pat1[ind - (2 * layer) + i], pat2[(2 * layer) + i]),
|
||||
)
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
/// Appends correct phase gate during CZ synthesis
|
||||
fn _append_phase_gate(pat_val: usize, gates: &mut LnnGatesVec, qubit: usize) {
|
||||
// Add phase gates: s, sdg or z
|
||||
let gate_id = pat_val % 4;
|
||||
if gate_id != 0 {
|
||||
let gate = match gate_id {
|
||||
1 => StandardGate::SdgGate,
|
||||
2 => StandardGate::ZGate,
|
||||
3 => StandardGate::SGate,
|
||||
_ => unreachable!(), // unreachable as we have modulo 4
|
||||
};
|
||||
gates.push((gate, smallvec![], smallvec![Qubit(qubit as u32)]));
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthesis of a CZ circuit for linear nearest neighbor (LNN) connectivity,
|
||||
/// based on Maslov and Roetteler.
|
||||
pub(super) fn synth_cz_depth_line_mr_inner(matrix: ArrayView2<bool>) -> (usize, LnnGatesVec) {
|
||||
let num_qubits = matrix.raw_dim()[0];
|
||||
let pats = _create_patterns(num_qubits);
|
||||
|
||||
// s_gates[i] = 0, 1, 2 or 3 for a gate id, sdg, z or s on qubit i respectively
|
||||
let mut s_gates = Array1::<usize>::zeros(num_qubits);
|
||||
|
||||
let mut patlist: Vec<(usize, usize)> = Vec::new();
|
||||
|
||||
let mut gates = LnnGatesVec::new();
|
||||
|
||||
for i in 0..num_qubits {
|
||||
for j in (i + 1)..num_qubits {
|
||||
if matrix[[i, j]] {
|
||||
// CZ(i,j) gate
|
||||
s_gates[[i]] += 2; // qc.z[i]
|
||||
s_gates[[j]] += 2; // qc.z[j]
|
||||
patlist.push((i, j - 1));
|
||||
patlist.push((i, j));
|
||||
patlist.push((i + 1, j - 1));
|
||||
patlist.push((i + 1, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..((num_qubits + 1) / 2) {
|
||||
for j in 0..num_qubits {
|
||||
let pat_val = pats[&(i, j)];
|
||||
if patlist.contains(&pat_val) {
|
||||
// patcnt should be 0 or 1, which checks if a Sdg gate should be added
|
||||
let patcnt = patlist.iter().filter(|val| **val == pat_val).count();
|
||||
s_gates[[j]] += patcnt; // qc.sdg[j]
|
||||
}
|
||||
|
||||
_append_phase_gate(s_gates[[j]], &mut gates, j)
|
||||
}
|
||||
|
||||
_append_cx_stage1(&mut gates, num_qubits);
|
||||
_append_cx_stage2(&mut gates, num_qubits);
|
||||
s_gates = Array1::<usize>::zeros(num_qubits);
|
||||
}
|
||||
|
||||
if num_qubits % 2 == 0 {
|
||||
let i = num_qubits / 2;
|
||||
|
||||
for j in 0..num_qubits {
|
||||
let pat_val = pats[&(i, j)];
|
||||
if patlist.contains(&pat_val) && pat_val.0 != pat_val.1 {
|
||||
// patcnt should be 0 or 1, which checks if a Sdg gate should be added
|
||||
let patcnt = patlist.iter().filter(|val| **val == pat_val).count();
|
||||
|
||||
s_gates[[j]] += patcnt; // qc.sdg[j]
|
||||
}
|
||||
|
||||
_append_phase_gate(s_gates[[j]], &mut gates, j)
|
||||
}
|
||||
|
||||
_append_cx_stage1(&mut gates, num_qubits);
|
||||
}
|
||||
|
||||
(num_qubits, gates)
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// This code is part of Qiskit.
|
||||
//
|
||||
// (C) Copyright IBM 2024
|
||||
//
|
||||
// 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.
|
||||
|
||||
use numpy::PyReadonlyArray2;
|
||||
use pyo3::{
|
||||
prelude::*,
|
||||
pyfunction,
|
||||
types::{PyModule, PyModuleMethods},
|
||||
wrap_pyfunction, Bound, PyResult,
|
||||
};
|
||||
use qiskit_circuit::{circuit_data::CircuitData, operations::Param};
|
||||
|
||||
pub(crate) mod cz_depth_lnn;
|
||||
|
||||
/// Synthesis of a CZ circuit for linear nearest neighbor (LNN) connectivity,
|
||||
/// based on Maslov and Roetteler.
|
||||
///
|
||||
/// Note that this method *reverts* the order of qubits in the circuit,
|
||||
/// and returns a circuit containing :class:`.CXGate`\s and phase gates
|
||||
/// (:class:`.SGate`, :class:`.SdgGate` or :class:`.ZGate`).
|
||||
///
|
||||
/// 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>`_.
|
||||
#[pyfunction]
|
||||
#[pyo3(signature = (mat))]
|
||||
fn synth_cz_depth_line_mr(py: Python, mat: PyReadonlyArray2<bool>) -> PyResult<CircuitData> {
|
||||
let view = mat.as_array();
|
||||
let (num_qubits, lnn_gates) = cz_depth_lnn::synth_cz_depth_line_mr_inner(view);
|
||||
CircuitData::from_standard_gates(py, num_qubits as u32, lnn_gates, Param::Float(0.0))
|
||||
}
|
||||
|
||||
pub fn linear_phase(m: &Bound<PyModule>) -> PyResult<()> {
|
||||
m.add_wrapped(wrap_pyfunction!(synth_cz_depth_line_mr))?;
|
||||
Ok(())
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
mod clifford;
|
||||
pub mod linear;
|
||||
pub mod linear_phase;
|
||||
mod permutation;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
|
@ -21,6 +22,10 @@ pub fn synthesis(m: &Bound<PyModule>) -> PyResult<()> {
|
|||
linear::linear(&linear_mod)?;
|
||||
m.add_submodule(&linear_mod)?;
|
||||
|
||||
let linear_phase_mod = PyModule::new_bound(m.py(), "linear_phase")?;
|
||||
linear_phase::linear_phase(&linear_phase_mod)?;
|
||||
m.add_submodule(&linear_phase_mod)?;
|
||||
|
||||
let permutation_mod = PyModule::new_bound(m.py(), "permutation")?;
|
||||
permutation::permutation(&permutation_mod)?;
|
||||
m.add_submodule(&permutation_mod)?;
|
||||
|
|
|
@ -20,6 +20,8 @@ use qiskit_circuit::circuit_data::CircuitData;
|
|||
use qiskit_circuit::operations::{Param, StandardGate};
|
||||
use qiskit_circuit::Qubit;
|
||||
|
||||
use super::linear_phase::cz_depth_lnn::LnnGatesVec;
|
||||
|
||||
mod utils;
|
||||
|
||||
/// Checks whether an array of size N is a permutation of 0, 1, ..., N - 1.
|
||||
|
@ -114,11 +116,82 @@ pub fn _synth_permutation_depth_lnn_kms(
|
|||
)
|
||||
}
|
||||
|
||||
/// A single layer of CX gates.
|
||||
pub(crate) fn _append_cx_stage1(gates: &mut LnnGatesVec, n: usize) {
|
||||
for i in 0..(n / 2) {
|
||||
gates.push((
|
||||
StandardGate::CXGate,
|
||||
smallvec![],
|
||||
smallvec![Qubit((2 * i) as u32), Qubit((2 * i + 1) as u32)],
|
||||
))
|
||||
}
|
||||
|
||||
for i in 0..((n + 1) / 2 - 1) {
|
||||
gates.push((
|
||||
StandardGate::CXGate,
|
||||
smallvec![],
|
||||
smallvec![Qubit((2 * i + 2) as u32), Qubit((2 * i + 1) as u32)],
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A single layer of CX gates.
|
||||
pub(crate) fn _append_cx_stage2(gates: &mut LnnGatesVec, n: usize) {
|
||||
for i in 0..(n / 2) {
|
||||
gates.push((
|
||||
StandardGate::CXGate,
|
||||
smallvec![],
|
||||
smallvec![Qubit((2 * i + 1) as u32), Qubit((2 * i) as u32)],
|
||||
))
|
||||
}
|
||||
|
||||
for i in 0..((n + 1) / 2 - 1) {
|
||||
gates.push((
|
||||
StandardGate::CXGate,
|
||||
smallvec![],
|
||||
smallvec![Qubit((2 * i + 1) as u32), Qubit((2 * i + 2) as u32)],
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Append reverse permutation to a QuantumCircuit for linear nearest-neighbor architectures
|
||||
/// using Kutin, Moulton, Smithline method.
|
||||
fn _append_reverse_permutation_lnn_kms(gates: &mut LnnGatesVec, num_qubits: usize) {
|
||||
(0..(num_qubits + 1) / 2).for_each(|_| {
|
||||
_append_cx_stage1(gates, num_qubits);
|
||||
_append_cx_stage2(gates, num_qubits);
|
||||
});
|
||||
|
||||
if num_qubits % 2 == 0 {
|
||||
_append_cx_stage1(gates, num_qubits);
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthesize reverse permutation for linear nearest-neighbor architectures using
|
||||
/// Kutin, Moulton, Smithline method.
|
||||
///
|
||||
/// Synthesis algorithm for reverse permutation from [1], section 5.
|
||||
/// This algorithm synthesizes the reverse permutation on :math:`n` qubits over
|
||||
/// a linear nearest-neighbor architecture using CX gates with depth :math:`2 * n + 2`.
|
||||
///
|
||||
/// References:
|
||||
/// 1. Kutin, S., Moulton, D. P., Smithline, L.,
|
||||
/// *Computation at a distance*, Chicago J. Theor. Comput. Sci., vol. 2007, (2007),
|
||||
/// `arXiv:quant-ph/0701194 <https://arxiv.org/abs/quant-ph/0701194>`_
|
||||
#[pyfunction]
|
||||
#[pyo3(signature = (num_qubits))]
|
||||
fn synth_permutation_reverse_lnn_kms(py: Python, num_qubits: usize) -> PyResult<CircuitData> {
|
||||
let mut gates = LnnGatesVec::new();
|
||||
_append_reverse_permutation_lnn_kms(&mut gates, num_qubits);
|
||||
CircuitData::from_standard_gates(py, num_qubits as u32, gates, Param::Float(0.0))
|
||||
}
|
||||
|
||||
pub fn permutation(m: &Bound<PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(_validate_permutation, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(_inverse_pattern, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(_synth_permutation_basic, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(_synth_permutation_acg, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(_synth_permutation_depth_lnn_kms, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(synth_permutation_reverse_lnn_kms, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ sys.modules["qiskit._accelerate.vf2_layout"] = _accelerate.vf2_layout
|
|||
sys.modules["qiskit._accelerate.synthesis.permutation"] = _accelerate.synthesis.permutation
|
||||
sys.modules["qiskit._accelerate.synthesis.linear"] = _accelerate.synthesis.linear
|
||||
sys.modules["qiskit._accelerate.synthesis.clifford"] = _accelerate.synthesis.clifford
|
||||
sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase
|
||||
|
||||
from qiskit.exceptions import QiskitError, MissingOptionalLibraryError
|
||||
|
||||
|
|
|
@ -24,100 +24,12 @@ References:
|
|||
|
||||
import numpy as np
|
||||
from qiskit.circuit import QuantumCircuit
|
||||
from qiskit.synthesis.permutation.permutation_reverse_lnn import (
|
||||
_append_cx_stage1,
|
||||
_append_cx_stage2,
|
||||
|
||||
from qiskit._accelerate.synthesis.linear_phase import (
|
||||
synth_cz_depth_line_mr as synth_cz_depth_line_mr_inner,
|
||||
)
|
||||
|
||||
|
||||
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) -> QuantumCircuit:
|
||||
r"""Synthesis of a CZ circuit for linear nearest neighbor (LNN) connectivity,
|
||||
based on Maslov and Roetteler.
|
||||
|
@ -139,56 +51,6 @@ def synth_cz_depth_line_mr(mat: np.ndarray) -> QuantumCircuit:
|
|||
*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
|
||||
# Call Rust implementaton
|
||||
return QuantumCircuit._from_circuit_data(synth_cz_depth_line_mr_inner(mat.astype(bool)))
|
||||
|
|
|
@ -14,6 +14,9 @@ Synthesis of a reverse permutation for LNN connectivity.
|
|||
"""
|
||||
|
||||
from qiskit.circuit import QuantumCircuit
|
||||
from qiskit._accelerate.synthesis.permutation import (
|
||||
synth_permutation_reverse_lnn_kms as synth_permutation_reverse_lnn_kms_inner,
|
||||
)
|
||||
|
||||
|
||||
def _append_cx_stage1(qc, n):
|
||||
|
@ -84,7 +87,5 @@ def synth_permutation_reverse_lnn_kms(num_qubits: int) -> QuantumCircuit:
|
|||
`arXiv:quant-ph/0701194 <https://arxiv.org/abs/quant-ph/0701194>`_
|
||||
"""
|
||||
|
||||
qc = QuantumCircuit(num_qubits)
|
||||
_append_reverse_permutation_lnn_kms(qc, num_qubits)
|
||||
|
||||
return qc
|
||||
# Call Rust implementation
|
||||
return QuantumCircuit._from_circuit_data(synth_permutation_reverse_lnn_kms_inner(num_qubits))
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features_synthesis:
|
||||
- |
|
||||
Port :func: `.synth_cz_depth_line_mr` to Rust. This function synthesizes a CZ circuit for linear nearest neighbor (LNN) connectivity, based on the Maslov and Roetteler method. On a 350x350 binary matrix, the Rust implementation yields a speedup of about 30 times.
|
||||
- |
|
||||
Port :func: `.synth_permutation_reverse_lnn_kms` to Rust, which synthesizes a reverse permutation for linear nearest-neighbor architecture using the Kutin, Moulton, Smithline method.
|
Loading…
Reference in New Issue