diff --git a/crates/accelerate/src/synthesis/permutation/mod.rs b/crates/accelerate/src/synthesis/permutation/mod.rs index 0e3900a4b8bf..fccb0cfb972e 100644 --- a/crates/accelerate/src/synthesis/permutation/mod.rs +++ b/crates/accelerate/src/synthesis/permutation/mod.rs @@ -82,11 +82,44 @@ fn _synth_permutation_acg(py: Python, pattern: PyArrayLike1) -> PyResult, +) -> PyResult { + 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) -> 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(()) } diff --git a/crates/accelerate/src/synthesis/permutation/utils.rs b/crates/accelerate/src/synthesis/permutation/utils.rs index 975635fbf8da..8f2738c078ae 100644 --- a/crates/accelerate/src/synthesis/permutation/utils.rs +++ b/crates/accelerate/src/synthesis/permutation/utils.rs @@ -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::*; @@ -144,3 +145,22 @@ pub fn decompose_cycles(cycles: &Vec>) -> 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, + 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 +} diff --git a/qiskit/synthesis/permutation/permutation_lnn.py b/qiskit/synthesis/permutation/permutation_lnn.py index f3897d63a687..d5da6929463c 100644 --- a/qiskit/synthesis/permutation/permutation_lnn.py +++ b/qiskit/synthesis/permutation/permutation_lnn.py @@ -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: @@ -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)) diff --git a/releasenotes/notes/synth_permutation_depth_lnn_kms-c444f3a363f3a903.yaml b/releasenotes/notes/synth_permutation_depth_lnn_kms-c444f3a363f3a903.yaml new file mode 100644 index 000000000000..65f81686cd33 --- /dev/null +++ b/releasenotes/notes/synth_permutation_depth_lnn_kms-c444f3a363f3a903.yaml @@ -0,0 +1,4 @@ +--- +features_synthesis: + - | + Port :func:`.synth_permutation_depth_lnn_kms`, used to synthesize permutations for linear connectivity, to Rust. \ No newline at end of file