Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
67a495a
Initial: Introduce C-API Access to `Optimize1qGatesDecomposition`.
raynelfss Jul 9, 2025
3f053cb
Fix: Add target identity test.
raynelfss Jul 9, 2025
a77ce5e
Chore: Fix docstring and free some pointers.
raynelfss Jul 9, 2025
0fe11b8
Add: Support for optional target for `Optimize1qGatesDecomposition` C…
raynelfss Jul 10, 2025
84c6bf3
Chore: Add release note.
raynelfss Jul 10, 2025
6edc33c
Chore: Fix docstring.
raynelfss Jul 10, 2025
cfc03cb
Chore: Fix bug in release note
raynelfss Jul 10, 2025
7ee5c4a
Merge remote-tracking branch 'upstream/main' into burn-optimize-1q-de…
raynelfss Aug 12, 2025
cf16fa9
Chore: Address review comments
raynelfss Aug 12, 2025
619ec0d
Update crates/cext/src/transpiler/passes/optimize_1q_decomposition.rs
raynelfss Aug 12, 2025
7e8a147
Chore: Fix docstring
raynelfss Aug 12, 2025
b4ba388
Chore: Fix release note
raynelfss Aug 13, 2025
4ab2e26
Update test/c/test_optimize_1q_decomposition.c
raynelfss Aug 15, 2025
19f55a6
Chore: Address review comments.
raynelfss Aug 15, 2025
25cd6cf
Merge remote-tracking branch 'upstream/main' into burn-optimize-1q-de…
raynelfss Aug 15, 2025
923a8bb
Fix: Review comments
raynelfss Aug 19, 2025
0a75d7c
Fix: Address some memory leakage.
raynelfss Aug 20, 2025
01d280e
Fix: Incorrect function name call
raynelfss Aug 20, 2025
9315826
Chore: Address different review items
raynelfss Aug 20, 2025
b4bd4ba
Fix: Replace `QkOpCounts` failures until it is fixed.
raynelfss Aug 22, 2025
82ce69d
Merge remote-tracking branch 'upstream/main' into burn-optimize-1q-de…
raynelfss Aug 22, 2025
9224253
Fix: Add final review comments.
raynelfss Aug 26, 2025
b40298b
Fix: Cformatting issues.
raynelfss Aug 26, 2025
85317c9
Fix: More c formatting issues.
raynelfss Aug 26, 2025
1b86842
Merge remote-tracking branch 'upstream/main' into burn-optimize-1q-de…
raynelfss Aug 26, 2025
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
13 changes: 13 additions & 0 deletions crates/cext/src/transpiler/passes/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
// This code is part of Qiskit.
//
// (C) Copyright IBM 2025
//
// 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.

pub mod optimize_1q_decomposition;
pub mod vf2;
110 changes: 110 additions & 0 deletions crates/cext/src/transpiler/passes/optimize_1q_decomposition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// This code is part of Qiskit.
//
// (C) Copyright IBM 2025
//
// 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.

use crate::pointers::const_ptr_as_ref;
use qiskit_circuit::{
circuit_data::CircuitData, converters::dag_to_circuit, dag_circuit::DAGCircuit,
};
use qiskit_transpiler::{passes::run_optimize_1q_gates_decomposition, target::Target};

/// @ingroup QkTranspilerPasses
/// Runs the Optimize1qGatesDecomposition pass in standalone mode on a circuit.
///
/// Optimize1qGatesDecomposition, as its name implies, optimizes chains of single-qubit
/// gates by combining them into a single gate.
Comment thread
raynelfss marked this conversation as resolved.
Outdated
///
/// The decision of whether to replace the original chain depends on:
/// - If the original chain was out of basis.
/// - If the original chain was in basis but the replacement has lower error rates.
/// - If the original chain is an identity (chain gets removed).
///
/// The error is the combined multiplication of the errors of individual gates on the
/// qubit it operates on.
///
/// @param circuit A pointer to the ``QkCircuit`` object to transform.
/// @param target A pointer to the ``QkTarget`` object.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From the code it looks like this is allowed to be a null pointer. What happens in this case? We should document that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

From snippet:

/// In the case a null pointer is provided and gate errors are unknown
/// the pass will choose the sequence with the least amount of gates,
/// and will support all basis gates on its Euler basis set.

///
/// @return The circuit after applying the optimizations.
Comment thread
raynelfss marked this conversation as resolved.
Outdated
///
/// # Example
///
/// QkTarget *target_u1_u2_u3 = qk_target_new(1);
///
/// double u_errors[3] = {0., 1e-4, 1e-4};
/// QkGate u_gates[3] = {QkGate_U1, QkGate_U2, QkGate_U3};
/// // TODO: Update this part to use parameters once we support them.
/// double u1_params[1] = {3.14};
/// double u2_params[2] = {3.14, 3.14 / 2.};
/// double u3_params[3] = {3.14, 3.14 / 2., 3.14 / 4.};
///
/// double **u_params = {u1_params, u2_params, u3_params};
/// for (int idx = 0; idx < 3; idx++) {
/// QkTargetEntry *u_entry = qk_target_entry_new_fixed(u_gates[idx], u_params[idx]);
/// uint32_t qargs[1] = {
/// 0,
/// };
/// qk_target_entry_add_property(u_entry, qargs, 1, NAN, u_errors[idx]);
/// qk_target_add_instruction(target_u1_u2_u3, u_entry);
/// }
///
/// // Build circuit
/// QkCircuit *circuit = qk_circuit_new(1, 0);
/// uint32_t qubits[1] = {0};
/// for (int iter = 0; iter < 3; iter++) {
/// qk_circuit_gate(circuit, QkGate_H, qubits, NULL);
/// }
///
/// // Run transpiler pass
/// QkCircuit *circuit_result =
/// qk_transpiler_standalone_optimize_1q_gates_decomposition(circuit, target);
///
/// // Clean up
/// qk_target_free(target_u1_u2_u3);
/// qk_circuit_free(circuit);
/// qk_circuit_free(circuit_result);
Comment thread
raynelfss marked this conversation as resolved.
Outdated
///
/// # Safety
///
/// Behavior is undefined if ``circuit`` is not a valid, non-null pointer to a ``QkCircuit`` and
/// if ``target`` is not a valid pointer to a ``QkTarget``.
#[no_mangle]
#[cfg(feature = "cbinding")]
pub unsafe extern "C" fn qk_transpiler_standalone_optimize_1q_gates_decomposition(
Comment thread
raynelfss marked this conversation as resolved.
Outdated
circuit: *const CircuitData,
target: *const Target,
) -> *mut CircuitData {
// SAFETY: Per documentation, the pointer is non-null and aligned.
let target = unsafe {
if target.is_null() {
None
} else {
Some(const_ptr_as_ref(target))
}
};
// SAFETY: Per documentation, the pointer is non-null and aligned.
let circuit = unsafe { const_ptr_as_ref(circuit) };

// Convert the circuit to a DAG.
let mut circuit_as_dag = DAGCircuit::from_circuit_data(circuit, false, None, None, None, None)
.expect("Error while converting the circuit to a dag.");
Comment on lines +90 to +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It would be nice if we would have a set of TranspilerErrors which we could return here instead of just panicking... but maybe this would need to be done generally for all passes in a follow-up.


// Run the pass
run_optimize_1q_gates_decomposition(&mut circuit_as_dag, target, None, None)
.expect("Error while running the pass.");

// Convert the DAGCircuit back to an instance of CircuitData
let dag_to_circuit = dag_to_circuit(&circuit_as_dag, false)
.expect("Error while converting the dag to a circuit.");

// Convert to pointer.
Box::into_raw(Box::new(dag_to_circuit))
Comment thread
Cryoris marked this conversation as resolved.
Outdated
}
26 changes: 26 additions & 0 deletions releasenotes/notes/c-api-optimize-1q-decomp-88954adfe952e91f.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
features_c:
- |
Add support for the ``Optimize1qGatesDecomposition`` transpiler pass through
the C API, via the ``qk_transpiler_standalone_optimize_1q_gates_decomposition``
method.

Here's an example:

.. code-block:: C

// Build a circuit
QkCircuit *circuit = qk_circuit_new(1, 0);
uint32_t qubits[1] = {0};
double params_pos[1] = {3.14 / 7.};
double params_neg[1] = {-3.14 / 7.};
qk_circuit_gate(circuit, QkGate_RY, qubits, params_pos);
qk_circuit_gate(circuit, QkGate_RY, qubits, params_neg);

// Run the transpiler pass
QkCircuit *circuit_result =
qk_transpiler_standalone_optimize_1q_gates_decomposition(circuit, NULL);

// Free both circuits
qk_circuit_free(circuit);
qk_circuit_free(circuit_result);
Loading