Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
124 changes: 122 additions & 2 deletions crates/cext/src/transpiler/transpile_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ use std::ffi::CString;
use std::ffi::c_char;

use qiskit_circuit::circuit_data::CircuitData;
use qiskit_circuit::dag_circuit::DAGCircuit;
use qiskit_transpiler::commutation_checker::get_standard_commutation_checker;
use qiskit_transpiler::target::Target;

use qiskit_transpiler::transpile;
use qiskit_transpiler::transpile_layout::TranspileLayout;
use qiskit_transpiler::transpiler::init_stage;

use crate::exit_codes::ExitCode;
use crate::pointers::const_ptr_as_ref;
use crate::pointers::{const_ptr_as_ref, mut_ptr_as_ref};

/// The container result object from ``qk_transpile``
///
Expand Down Expand Up @@ -72,6 +74,124 @@ pub extern "C" fn qk_transpiler_default_options() -> TranspileOptions {
TranspileOptions::default()
}

/// @ingroup QkTranspiler
/// Run the preset init stage of the transpiler on a circuit
///
/// The Qiskit transpiler is a quantum circuit compiler that rewrites a given
/// input circuit to match the constraints of a QPU and optimizes the circuit
/// for execution. This function runs the first stage of the transpiler,
/// **init**, which runs abstract-circuit optimizations, and reduces multi-qubit
/// operations into one- and two-qubit operations. You can refer to
/// \inlinerst ::ref:`transpiler-preset-stage-init` \endrst for more details.
///
/// This function should only be used with circuits constructed
/// using Qiskit's C API. It makes assumptions on the circuit only using features exposed via C,
/// if you are in a mixed Python and C environment it is typically better to invoke the transpiler
/// via Python.
///
/// This function is multithreaded internally and will launch a thread pool
/// with threads equal to the number of CPUs reported by the operating system by default.
/// This will include logical cores on CPUs with simultaneous multithreading. You can tune the
/// number of threads with the ``RAYON_NUM_THREADS`` environment variable. For example, setting
/// ``RAYON_NUM_THREADS=4`` would limit the thread pool to 4 threads.
///
/// @param circuit A pointer to the circuit to run the transpiler on.
/// @param target A pointer to the target to compile the circuit for.
/// @param options A pointer to an options object that defines user options. If this is a null
/// pointer the default values will be used. See ``qk_transpile_default_options``
/// for more details on the default values.
/// @param layout A pointer to a pointer to a ``QkTranspileLayout`` object. On a successful
/// execution (return code 0) a pointer to the layout object created transpiler will be written
/// to this pointer.
/// @param error A pointer to a pointer with an nul terminated string with an error description.
/// If the transpiler fails a pointer to the string with the error description will be written
/// to this pointer. That pointer needs to be freed with ``qk_str_free```. This can be a null
/// pointer in which case the error will not be written out.
///
/// @returns The return code for the transpiler, ``QkExitCode_Success`` means success and all
/// other values indicate an error.
///
/// # Safety
///
/// Behavior is undefined if ``dag``, ``target``, or ``layout``, are not valid, non-null
/// pointers to a ``QkDag``, ``QkTarget``, or a ``QkTranspileLayout`` pointer
/// respectively. ``options`` must be a valid pointer a to a ``QkTranspileOptions`` or ``NULL`.
/// ``error`` must be a valid pointer to a ``char`` pointer or ``NULL``.
#[unsafe(no_mangle)]
#[cfg(feature = "cbinding")]
pub unsafe extern "C" fn qk_transpile_stage_init(
dag: *mut DAGCircuit,
target: *const Target,
options: *const TranspileOptions,
layout: *mut *mut TranspileLayout,
error: *mut *mut c_char,
) -> ExitCode {
// SAFETY: Per documentation, the pointer is non-null and aligned.
let dag = unsafe { mut_ptr_as_ref(dag) };
let target = unsafe { const_ptr_as_ref(target) };
let mut out_layout = TranspileLayout::new(
None,
None,
dag.qubits().objects().to_owned(),
dag.num_qubits() as u32,
dag.qregs().to_vec(),
);
let options = if options.is_null() {
&TranspileOptions::default()
} else {
// SAFETY: We checked the pointer is not null, then, per documentation, it is a valid
// and aligned pointer.
unsafe { const_ptr_as_ref(options) }
};

let approximation_degree = if options.approximation_degree.is_nan() {
None
} else {
if !(0.0..=1.0).contains(&options.approximation_degree) {
panic!(
"Invalid value provided for approximation degree, only NAN or values between 0.0 and 1.0 inclusive are valid"
);
}
Some(options.approximation_degree)
};
let mut commutation_checker = get_standard_commutation_checker();

match init_stage(
dag,
target,
options.optimization_level.into(),
approximation_degree,
&mut out_layout,
&mut commutation_checker,
) {
Ok(_) => {
// SAFETY: Per the documentation result is a non-null aligned pointer to a pointer to
// a QKTranspileLayout
unsafe {
*layout = Box::into_raw(Box::new(out_layout));
}
ExitCode::Success
}
Err(e) => {
if !error.is_null() {
unsafe {
// Right now we return a backtrace of the error. This at least gives a hint as to
// which pass failed when we have rust errors normalized we can actually have error
// messages which are user facing. But most likely this will be a PyErr and panic
// when trying to extract the string.
*error = CString::new(format!(
"Transpilation failed with this backtrace: {}",
e.backtrace()
))
.unwrap()
.into_raw();
}
}
ExitCode::TranspilerError
}
}
}

/// @ingroup QkTranspiler
/// Transpile a single circuit.
///
Expand Down
2 changes: 1 addition & 1 deletion crates/transpiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub mod standard_gates_commutations;
pub mod target;
pub mod transpile_layout;

mod transpiler;
pub mod transpiler;

pub use transpiler::transpile;

Expand Down
Loading
Loading