Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Rustiq-based synthesis for PauliEvolutionGate #13301

Merged
merged 48 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3a15589
py version for expand
Cryoris Oct 3, 2024
811eb68
starting to write some code
alexanderivrii Oct 6, 2024
2209e86
merge main
alexanderivrii Oct 6, 2024
669480a
implementing
alexanderivrii Oct 7, 2024
263e04e
cleanup
alexanderivrii Oct 7, 2024
48537b3
cleanup
alexanderivrii Oct 7, 2024
cea830b
Merge branch 'main' into paulievo
Cryoris Oct 7, 2024
72f2689
expand fully & simplify lie trotter
Cryoris Oct 7, 2024
8cd2c25
use examples that actually do not commute
Cryoris Oct 8, 2024
681105d
add plugin structure
Cryoris Oct 8, 2024
6cb9202
fixing global phase for all-I rotations
alexanderivrii Oct 9, 2024
d525fd7
Merge branch 'paulievo' into integrate_rustiq_plugin
alexanderivrii Oct 9, 2024
1647243
fixes
alexanderivrii Oct 9, 2024
e2aa1c4
fixing plugin names
alexanderivrii Oct 9, 2024
fcb6a36
Merge branch 'main' into integrate_rustiq_plugin
alexanderivrii Oct 9, 2024
261e92a
minor
alexanderivrii Oct 9, 2024
32ac13f
Merge branch 'integrate_rustiq_plugin' of github.com:alexanderivrii/q…
alexanderivrii Oct 9, 2024
2529974
removing a random print statement
alexanderivrii Oct 9, 2024
d47ba34
additional improvements
alexanderivrii Oct 12, 2024
0dd6516
improving rustiq plugin
alexanderivrii Oct 12, 2024
5020845
Merge branch 'main' into integrate_rustiq_plugin
alexanderivrii Oct 12, 2024
a6f0f9e
Merge branch 'main' into integrate_rustiq_plugin
alexanderivrii Oct 30, 2024
990069b
Merge branch 'main' into integrate_rustiq_plugin
alexanderivrii Oct 31, 2024
0cb2dee
merge with #13239
alexanderivrii Oct 31, 2024
ea3d1a6
Adding pauli evolution plugins to docstrings
alexanderivrii Oct 31, 2024
397e0d6
adding documentation on rustiq plugin
alexanderivrii Oct 31, 2024
e283496
fixes after refactoring
alexanderivrii Oct 31, 2024
9c8b32d
typo
alexanderivrii Oct 31, 2024
be7a1a3
more merges with #13295; adding more Rustiq tests
alexanderivrii Oct 31, 2024
87ff0b4
Merge branch 'main' into integrate_rustiq_plugin
alexanderivrii Nov 4, 2024
41ae2f3
more efficient append_sx and append_sxdg gates for cliffords
alexanderivrii Nov 5, 2024
354af6a
review comments
alexanderivrii Nov 5, 2024
73c8e44
Merge branch 'integrate_rustiq_plugin' of github.com:alexanderivrii/q…
alexanderivrii Nov 5, 2024
bfa3766
moving the pauli network synthesis logic into a separate file
alexanderivrii Nov 6, 2024
465e3bb
some code review suggestions
alexanderivrii Nov 6, 2024
b9d058e
simplifying the code by merging the oredered and unorderd version of …
alexanderivrii Nov 6, 2024
fad450f
more review comments
alexanderivrii Nov 6, 2024
2f401fa
adding python tests
alexanderivrii Nov 6, 2024
2cc9469
more code review suggestions
alexanderivrii Nov 6, 2024
5bbd849
more review comments
alexanderivrii Nov 6, 2024
5719ffd
more review comments
alexanderivrii Nov 6, 2024
273bf09
test for preserve_order
alexanderivrii Nov 6, 2024
53ae7bb
lint
alexanderivrii Nov 6, 2024
437710e
upgrading rustiq-core to 0.0.10
alexanderivrii Nov 6, 2024
a72970e
clippy: removing mutable ref
alexanderivrii Nov 6, 2024
a0f3acd
Improving PauliEvolution synthesis tests.
alexanderivrii Nov 6, 2024
6ada3cc
Merge branch 'main' into integrate_rustiq_plugin
alexanderivrii Nov 7, 2024
46055b2
documentation fixes after the merge
alexanderivrii Nov 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/accelerate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ qiskit-circuit.workspace = true
thiserror.workspace = true
ndarray_einsum_beta = "0.7"
once_cell = "1.20.2"
rustiq-core = "0.0.10"
bytemuck.workspace = true

[dependencies.smallvec]
Expand Down
13 changes: 12 additions & 1 deletion crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use indexmap::IndexSet;
use ndarray::{s, ArrayView2};
use smallvec::smallvec;

use crate::synthesis::clifford::utils::CliffordGatesVec;
use crate::synthesis::clifford::utils::{adjust_final_pauli_gates, SymplecticMatrix};
use crate::synthesis::clifford::utils::{Clifford, CliffordGatesVec};
use qiskit_circuit::operations::StandardGate;
use qiskit_circuit::Qubit;

Expand Down Expand Up @@ -437,3 +437,14 @@ impl GreedyCliffordSynthesis<'_> {
Ok((self.num_qubits, clifford_gates))
}
}

/// Resynthesizes a clifford circuit using the greedy Clifford synthesis algorithm.
pub fn resynthesize_clifford_circuit(
num_qubits: usize,
gates: &CliffordGatesVec,
) -> Result<CliffordGatesVec, String> {
let sim_clifford = Clifford::from_gate_sequence(gates, num_qubits)?;
let mut synthesis = GreedyCliffordSynthesis::new(sim_clifford.tableau.view())?;
let (_, new_gates) = synthesis.run()?;
Ok(new_gates)
}
4 changes: 2 additions & 2 deletions crates/accelerate/src/synthesis/clifford/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
// that they have been altered from the originals.

mod bm_synthesis;
mod greedy_synthesis;
pub(crate) mod greedy_synthesis;
mod random_clifford;
mod utils;
pub(crate) mod utils;

use crate::synthesis::clifford::bm_synthesis::synth_clifford_bm_inner;
use crate::synthesis::clifford::greedy_synthesis::GreedyCliffordSynthesis;
Expand Down
39 changes: 36 additions & 3 deletions crates/accelerate/src/synthesis/clifford/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,30 @@ impl Clifford {
azip!((z in &mut z, &x in &x) *z ^= x);
}

/// Modifies the tableau in-place by appending SX-gate
pub fn append_sx(&mut self, qubit: usize) {
let (mut x, z, mut p) = self.tableau.multi_slice_mut((
s![.., qubit],
s![.., self.num_qubits + qubit],
s![.., 2 * self.num_qubits],
));

azip!((p in &mut p, &x in &x, &z in &z) *p ^= !x & z);
azip!((&z in &z, x in &mut x) *x ^= z);
}

/// Modifies the tableau in-place by appending SXDG-gate
pub fn append_sxdg(&mut self, qubit: usize) {
let (mut x, z, mut p) = self.tableau.multi_slice_mut((
s![.., qubit],
s![.., self.num_qubits + qubit],
s![.., 2 * self.num_qubits],
));

azip!((p in &mut p, &x in &x, &z in &z) *p ^= x & z);
azip!((&z in &z, x in &mut x) *x ^= z);
}

/// Modifies the tableau in-place by appending H-gate
pub fn append_h(&mut self, qubit: usize) {
let (mut x, mut z, mut p) = self.tableau.multi_slice_mut((
Expand Down Expand Up @@ -227,6 +251,18 @@ impl Clifford {
clifford.append_s(qubits[0].index());
Ok(())
}
StandardGate::SdgGate => {
clifford.append_sdg(qubits[0].0 as usize);
Ok(())
}
StandardGate::SXGate => {
clifford.append_sx(qubits[0].0 as usize);
Ok(())
}
StandardGate::SXdgGate => {
clifford.append_sxdg(qubits[0].0 as usize);
Ok(())
}
StandardGate::HGate => {
clifford.append_h(qubits[0].index());
Ok(())
Expand Down Expand Up @@ -283,21 +319,18 @@ pub fn adjust_final_pauli_gates(
// add pauli gates
for qubit in 0..num_qubits {
if delta_phase_pre[qubit] && delta_phase_pre[qubit + num_qubits] {
// println!("=> Adding Y-gate on {}", qubit);
gate_seq.push((
StandardGate::YGate,
smallvec![],
smallvec![Qubit::new(qubit)],
));
} else if delta_phase_pre[qubit] {
// println!("=> Adding Z-gate on {}", qubit);
gate_seq.push((
StandardGate::ZGate,
smallvec![],
smallvec![Qubit::new(qubit)],
));
} else if delta_phase_pre[qubit + num_qubits] {
// println!("=> Adding X-gate on {}", qubit);
gate_seq.push((
StandardGate::XGate,
smallvec![],
Expand Down
79 changes: 79 additions & 0 deletions crates/accelerate/src/synthesis/evolution/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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.

mod pauli_network;

use pyo3::prelude::*;
use pyo3::types::PyList;

use qiskit_circuit::circuit_data::CircuitData;

use crate::synthesis::evolution::pauli_network::pauli_network_synthesis_inner;

/// Calls Rustiq's pauli network synthesis algorithm and returns the
/// Qiskit circuit data with Clifford gates and rotations.
///
/// # Arguments
///
/// * py: a GIL handle, needed to add and negate rotation parameters in Python space.
/// * num_qubits: total number of qubits.
/// * pauli_network: pauli network represented in sparse format. It's a list
/// of triples such as `[("XX", [0, 3], theta), ("ZZ", [0, 1], 0.1)]`.
/// * optimize_count: if `true`, Rustiq's synthesis algorithms aims to optimize
/// the 2-qubit gate count; and if `false`, then the 2-qubit depth.
/// * preserve_order: whether the order of paulis should be preserved, up to
/// commutativity. If the order is not preserved, the returned circuit will
/// generally not be equivalent to the given pauli network.
/// * upto_clifford: if `true`, the final Clifford operator is not synthesized
/// and the returned circuit will generally not be equivalent to the given
/// pauli network. In addition, the argument `upto_phase` would be ignored.
/// * upto_phase: if `true`, the global phase of the returned circuit may differ
/// from the global phase of the given pauli network. The argument is considered
/// to be `true` when `upto_clifford` is `true`.
/// * resynth_clifford_method: describes the strategy to synthesize the final
/// Clifford operator. If `0` a naive approach is used, which doubles the number
/// of gates but preserves the global phase of the circuit. If `1`, the Clifford is
/// resynthesized using Qiskit's greedy Clifford synthesis algorithm. If `2`, it
/// is resynthesized by Rustiq itself. If `upto_phase` is `false`, the naive
/// approach is used, as neither synthesis method preserves the global phase.
///
/// If `preserve_order` is `true` and both `upto_clifford` and `upto_phase` are `false`,
/// the returned circuit is equivalent to the given pauli network.
#[pyfunction]
#[pyo3(signature = (num_qubits, pauli_network, optimize_count=true, preserve_order=true, upto_clifford=false, upto_phase=false, resynth_clifford_method=1))]
#[allow(clippy::too_many_arguments)]
pub fn pauli_network_synthesis(
py: Python,
num_qubits: usize,
pauli_network: &Bound<PyList>,
optimize_count: bool,
preserve_order: bool,
upto_clifford: bool,
upto_phase: bool,
resynth_clifford_method: usize,
) -> PyResult<CircuitData> {
pauli_network_synthesis_inner(
py,
num_qubits,
pauli_network,
optimize_count,
preserve_order,
upto_clifford,
upto_phase,
resynth_clifford_method,
)
}

pub fn evolution(m: &Bound<PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(pauli_network_synthesis, m)?)?;
Ok(())
}
Loading