diff --git a/Cargo.lock b/Cargo.lock index f9a290c96d30..9cf304af1b40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1446,6 +1446,7 @@ version = "2.0.0" dependencies = [ "cbindgen", "num-complex", + "pyo3", "qiskit-accelerate", "thiserror 2.0.11", ] @@ -1478,6 +1479,7 @@ version = "2.0.0" dependencies = [ "pyo3", "qiskit-accelerate", + "qiskit-cext", "qiskit-circuit", "qiskit-qasm2", "qiskit-qasm3", diff --git a/crates/cext/Cargo.toml b/crates/cext/Cargo.toml index 2ec08c26a49d..4a744b860614 100644 --- a/crates/cext/Cargo.toml +++ b/crates/cext/Cargo.toml @@ -17,6 +17,7 @@ workspace = true thiserror.workspace = true num-complex.workspace = true qiskit-accelerate.workspace = true +pyo3.workspace = true [build-dependencies] cbindgen = "0.28" diff --git a/crates/cext/cbindgen.toml b/crates/cext/cbindgen.toml index 0c42ed598d86..ade38dede6ea 100644 --- a/crates/cext/cbindgen.toml +++ b/crates/cext/cbindgen.toml @@ -1,13 +1,13 @@ include_version = true -style = "type" +style = "type" sys_includes = ["complex.h"] after_includes = """ // Complex number typedefs -- note these are memory aligned but // not calling convention compatible. -typedef float complex QkComplex32; +typedef float complex QkComplex32; typedef double complex QkComplex64; -// Always expose [cfg(feature = "cbinding")] -- workaround for +// Always expose [cfg(feature = "cbinding")] -- workaround for // https://github.com/mozilla/cbindgen/issues/995 #define QISKIT_WITH_CBINDINGS """ @@ -24,7 +24,8 @@ prefix_with_name = true [export] prefix = "Qk" -renaming_overrides_prefixing = false +renaming_overrides_prefixing = true [export.rename] -"CSparseTerm" = "SparseTerm" +"CSparseTerm" = "QkSparseTerm" +"PyObject" = "PyObject" diff --git a/crates/cext/src/sparse_observable.rs b/crates/cext/src/sparse_observable.rs index 6f5959b1c37c..3c3994015f82 100644 --- a/crates/cext/src/sparse_observable.rs +++ b/crates/cext/src/sparse_observable.rs @@ -14,7 +14,11 @@ use std::ffi::{c_char, CString}; use crate::exit_codes::{CInputError, ExitCode}; use num_complex::Complex64; -use qiskit_accelerate::sparse_observable::{BitTerm, SparseObservable, SparseTermView}; +use pyo3::ffi::PyObject; +use pyo3::{Py, Python}; +use qiskit_accelerate::sparse_observable::{ + BitTerm, PySparseObservable, SparseObservable, SparseTermView, +}; /// @ingroup QkSparseTerm /// A term in a [SparseObservable]. @@ -847,3 +851,18 @@ pub extern "C" fn qk_bitterm_label(bit_term: BitTerm) -> u8 { .next() .expect("Label has exactly one character") as u8 } + +/// @ingroup SparseObservable +/// Convert to a Python-space [PySparseObservable]. +/// +/// @param obs The C-space [SparseObservable] pointer. +/// +/// @return A Python object representing the [PySparseObservable]. +#[no_mangle] +#[cfg(feature = "cbinding")] +pub unsafe extern "C" fn qk_obs_to_python(obs: *const SparseObservable) -> *mut PyObject { + let obs = unsafe { const_ptr_as_ref(obs) }; + let py_obs: PySparseObservable = obs.clone().into(); + + Python::with_gil(|py| Py::new(py, py_obs).expect("Shit hit the fan").into_ptr()) +} diff --git a/crates/pyext/Cargo.toml b/crates/pyext/Cargo.toml index 42962edb2fb9..b78692a89669 100644 --- a/crates/pyext/Cargo.toml +++ b/crates/pyext/Cargo.toml @@ -28,3 +28,4 @@ qiskit-accelerate.workspace = true qiskit-circuit.workspace = true qiskit-qasm2.workspace = true qiskit-qasm3.workspace = true +qiskit-cext.workspace = true diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 0e08cf72d03a..fa4145766fbb 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -11,6 +11,8 @@ // that they have been altered from the originals. use pyo3::prelude::*; +pub use qiskit_cext::sparse_observable::*; +pub use qiskit_cext::*; #[inline(always)] #[doc(hidden)] diff --git a/qiskit/__init__.py b/qiskit/__init__.py index ab585b9cf621..5cc4c9307abc 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -131,6 +131,20 @@ from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from .version import __version__ + +def get_lib() -> str: + """Get the path to the compiled library object. + + When interfacing with Qiskit's C API for a Python extension the shared library object + returned from this function must be what is linked against. This will ensure that all + objects are built using the same library file. + + Returns: + The path. + """ + return _accelerate.__file__ + + __all__ = [ "AncillaRegister", "ClassicalRegister",