Skip to content

Conversation

@Estebanrg21
Copy link

@Estebanrg21 Estebanrg21 commented Dec 17, 2025

Summary

This pull request implements the Suzuki-Trotter evolution within the C API.

Details and comments

1. New APIs:

  • The file with the implementation for the Suzuki-Trotter evolution at crates/circuit_library/src/suzuki_trotter.rs
  • The file with the implementation for the Suzuki-Trotter evolution at crates/synthesis/src/evolution/suzuki_trotter.rs
  • The file with the exposure of the Suzuki-Trotter evolution for the C API at crates/cext/src/synthesis/suzuki_trotter.rs

2. As part of the implementation, some APIs were made public:

  • modulesynthesis/evolution
  • Instruction struct from crates/circuit_library/src/pauli_evolution.rs
  • module crates/circuit_library/src/pauli_evolution.rs

3. The qiskit-synthesis and qiskit-quantum-info crates were added as dependencies for qiskit-circuit-library

@qiskit-bot qiskit-bot added the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Dec 17, 2025
@CLAassistant
Copy link

CLAassistant commented Dec 17, 2025

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Esteban Ramirez seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Estebanrg21 Estebanrg21 force-pushed the qamp2025-29-esteban branch 7 times, most recently from f810558 to 2bac78e Compare December 17, 2025 07:57
@Cryoris Cryoris added this to the 2.4.0 milestone Dec 17, 2025
@Cryoris Cryoris added the Changelog: New Feature Include in the "Added" section of the changelog label Dec 17, 2025
Copy link
Collaborator

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @Estebanrg21, this already looks pretty good! I think we can improve the datastructures a bit and avoid some clones and collections.

This would also need a release note 🙂

}
}

pub fn evolution(order: u32, mut paulis: Vec<StrSparseTerm>) -> Vec<StrSparseTerm> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paulis shouldn't be mutable here if we're returning a new clone, also we can should be able to change this to take a slice (paulis: &[SparseTermView]) I believe

)
}

let parsed_observable: Vec<StrSparseTerm> = observable
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SparseObservable has a iter method which returns SparseTermView objects. These are pretty close to your StrSparseTerm here. Do you think we could directly use the SparseTermView to avoid cloning into a StrSparseTerm?

};
}

pub fn reorder_terms<'a>(terms: &'a Vec<StrSparseTerm<'a>>) -> Vec<StrSparseTerm<'a>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use a slice here, that's more generic

Suggested change
pub fn reorder_terms<'a>(terms: &'a Vec<StrSparseTerm<'a>>) -> Vec<StrSparseTerm<'a>> {
pub fn reorder_terms<'a>(terms: &'a [StrSparseTerm<'a>]) -> Vec<StrSparseTerm<'a>> {

)
})
.collect_tuple()
.expect("Expected a combination of two values");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is not a C-specific function, can we make it return a proper Result<..> type, such that errors could be handled gracefully? You could just start with a &str as error type.

}

pub fn reorder_terms<'a>(terms: &'a Vec<StrSparseTerm<'a>>) -> Vec<StrSparseTerm<'a>> {
let sorted: Vec<&StrSparseTerm> = terms
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to collect this into a vec if you're just iterating over it later, i.e, we can do

let mut graph = ..
for term in terms.iter().sorted_by_key(..) {
  graph.add_node(term);
}

.sorted_by_key(|view| (view.indices, view.terms.clone()))
.collect();

let mut graph: Graph<&StrSparseTerm, Option<u8>, Undirected> = Graph::new_undirected();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to tell the graph what capacity we need, such that we can allocate the required memory only one?

};
}

pub fn reorder_terms<'a>(terms: &'a Vec<StrSparseTerm<'a>>) -> Vec<StrSparseTerm<'a>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function does a lot of collecting and cloning, that we should try to avoid. We could change e.g. to return the indices in which the terms should be applied instead of cloning and collecting into a new container.

insert_barriers: bool,
) -> Result<CircuitData, PyErr> {
if order > 1 && order % 2 == 1 {
panic!(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, could we turn this into an error instead of a panic? Panics should be reserved for cases that should not be reached -- or for C functions where we can't handle errors gracefully 🙂


#[unsafe(no_mangle)]
#[cfg(feature = "cbinding")]
pub extern "C" fn qk_circuit_library_suzuki_trotter_evolution(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we rename this to just qk_circuit_library_suzuki_trotter? The name is long enough then... 😄

use qiskit_circuit_library::suzuki_trotter::suzuki_trotter_evolution;
use qiskit_quantum_info::sparse_observable::SparseObservable;

#[unsafe(no_mangle)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function needs a docstring, see the other C functions for examples

@Cryoris Cryoris self-assigned this Dec 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: New Feature Include in the "Added" section of the changelog Community PR PRs from contributors that are not 'members' of the Qiskit repo

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

4 participants