Skip to content

Commit

Permalink
Port synth_permutation_depth_lnn_kms to Rust (Qiskit#12746)
Browse files Browse the repository at this point in the history
* added functionality for porting

* updated functionality

* formatting

* lint changes

* resolved error

* updated docstring

* formatting

* formatting
  • Loading branch information
Procatv committed Aug 1, 2024
1 parent bf697a0 commit 74dfc71
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 24 deletions.
33 changes: 33 additions & 0 deletions crates/accelerate/src/synthesis/permutation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,44 @@ fn _synth_permutation_acg(py: Python, pattern: PyArrayLike1<i64>) -> PyResult<Ci
)
}

/// Synthesize a permutation circuit for a linear nearest-neighbor
/// architecture using the Kutin, Moulton, Smithline method.
#[pyfunction]
#[pyo3(signature = (pattern))]
pub fn _synth_permutation_depth_lnn_kms(
py: Python,
pattern: PyArrayLike1<i64>,
) -> PyResult<CircuitData> {
let mut inverted = utils::invert(&pattern.as_array());
let mut view = inverted.view_mut();
let num_qubits = view.len();
let mut swap_layers: Vec<(usize, usize)> = Vec::new();

for i in 0..num_qubits {
let swap_layer: Vec<(usize, usize)> = utils::create_swap_layer(&mut view, i % 2);
swap_layers.extend(swap_layer);
}

CircuitData::from_standard_gates(
py,
num_qubits as u32,
swap_layers.iter().map(|(i, j)| {
(
StandardGate::SwapGate,
smallvec![],
smallvec![Qubit(*i as u32), Qubit(*j as u32)],
)
}),
Param::Float(0.0),
)
}

#[pymodule]
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)?)?;
Ok(())
}
20 changes: 20 additions & 0 deletions crates/accelerate/src/synthesis/permutation/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

use ndarray::ArrayViewMut1;
use ndarray::{Array1, ArrayView1};
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
Expand Down Expand Up @@ -144,3 +145,22 @@ pub fn decompose_cycles(cycles: &Vec<Vec<usize>>) -> Vec<(usize, usize)> {

swaps
}

/// Implements a single swap layer, consisting of conditional swaps between each
/// neighboring couple. The starting_point is the first qubit to use (either 0 or 1
/// for even or odd layers respectively). Mutates the permutation pattern ``pattern``.
pub fn create_swap_layer(
pattern: &mut ArrayViewMut1<usize>,
starting_point: usize,
) -> Vec<(usize, usize)> {
let num_qubits = pattern.len();
let mut gates = Vec::new();

for j in (starting_point..num_qubits - 1).step_by(2) {
if pattern[j] > pattern[j + 1] {
gates.push((j, j + 1));
pattern.swap(j, j + 1);
}
}
gates
}
26 changes: 2 additions & 24 deletions qiskit/synthesis/permutation/permutation_lnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from __future__ import annotations
import numpy as np
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .permutation_utils import _inverse_pattern
from qiskit._accelerate.synthesis.permutation import _synth_permutation_depth_lnn_kms


def synth_permutation_depth_lnn_kms(pattern: list[int] | np.ndarray[int]) -> QuantumCircuit:
Expand Down Expand Up @@ -49,26 +49,4 @@ def synth_permutation_depth_lnn_kms(pattern: list[int] | np.ndarray[int]) -> Qua
# In the permutation synthesis code below the notation is opposite:
# [2, 4, 3, 0, 1] means that 0 maps to 2, 1 to 3, 2 to 3, 3 to 0, and 4 to 1.
# This is why we invert the pattern.
cur_pattern = _inverse_pattern(pattern)

num_qubits = len(cur_pattern)
qc = QuantumCircuit(num_qubits)

# add conditional odd-even swap layers
for i in range(num_qubits):
_create_swap_layer(qc, cur_pattern, i % 2)

return qc


def _create_swap_layer(qc, pattern, starting_point):
"""Implements a single swap layer, consisting of conditional swaps between each
neighboring couple. The starting_point is the first qubit to use (either 0 or 1
for even or odd layers respectively). Mutates both the quantum circuit ``qc``
and the permutation pattern ``pattern``.
"""
num_qubits = len(pattern)
for j in range(starting_point, num_qubits - 1, 2):
if pattern[j] > pattern[j + 1]:
qc.swap(j, j + 1)
pattern[j], pattern[j + 1] = pattern[j + 1], pattern[j]
return QuantumCircuit._from_circuit_data(_synth_permutation_depth_lnn_kms(pattern))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features_synthesis:
- |
Port :func:`.synth_permutation_depth_lnn_kms`, used to synthesize permutations for linear connectivity, to Rust.

0 comments on commit 74dfc71

Please sign in to comment.