Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
4d160bc
Add new multithreaded TwoQubitPeepholeOptimization pass
mtreinish Nov 10, 2024
decee9a
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Dec 1, 2024
746758f
Add support for running the TwoQubitControlledUDecomposer
mtreinish Dec 1, 2024
ee70e65
Suprress clippy warning about mismatch enum variant sizes
mtreinish Dec 1, 2024
4d4df68
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Dec 1, 2024
cb6b70f
Embed 2q gate count into score as tie breaker
mtreinish Dec 2, 2024
f06a070
Release GIL during parallel portion
mtreinish Dec 2, 2024
90b16e8
Merge branch 'main' into two-qubit-peephole-parallel-pass
mtreinish Jan 13, 2025
a175ee8
Fix lint
mtreinish Jan 13, 2025
af0c144
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Jan 26, 2025
79a46c5
Update ControlledUDecomposer to ensure we only run if the gate is con…
mtreinish Jan 26, 2025
839b4c9
Add reversed synthesis for two qubit basis decomposer
mtreinish Jan 26, 2025
d9399a6
Fix handling of single direction gates
mtreinish Jan 26, 2025
b4c4360
Fix import cycle
mtreinish Jan 26, 2025
aefdc90
Merge branch 'main' into two-qubit-peephole-parallel-pass
mtreinish Feb 4, 2025
746b953
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Feb 19, 2025
f2bb1fb
Flip scoring value to (2q gate count, predicted error)
mtreinish Feb 19, 2025
55b05c0
Add docstring to new pass
mtreinish Feb 19, 2025
7756d1e
Add release note
mtreinish Feb 19, 2025
6a01332
Run serially in multiprocessing context
mtreinish Feb 19, 2025
d83562b
Fix cache build
mtreinish Feb 20, 2025
5f73b93
Add tests
mtreinish Feb 26, 2025
5e6c4cb
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Apr 11, 2025
8c7e67c
Rebase updates
mtreinish Apr 11, 2025
f41e855
Adjust tests
mtreinish Apr 11, 2025
3cdee4f
Clean-up test lint
mtreinish Apr 17, 2025
fd96145
Remove plugin method support from the new pass
mtreinish Apr 17, 2025
89931a4
Fix oversight in test code
mtreinish Apr 17, 2025
19368bb
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Apr 17, 2025
14e421c
Fix test failures
mtreinish Apr 17, 2025
02785e1
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Apr 17, 2025
c7ba671
Update target usage for recent changes
mtreinish Apr 17, 2025
089d3b6
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Apr 18, 2025
9f820c1
Simplify argument typing on new dag builder
mtreinish Apr 18, 2025
bfdfe46
Use dag builder api
mtreinish Apr 18, 2025
f72df7d
Fix error handling for target lookup
mtreinish Apr 18, 2025
bb31eb5
Fix some bugs and expand tests
mtreinish Apr 18, 2025
1985ff4
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Jun 10, 2025
ed262ac
Deduplicate synthesis path between unitary synthesis and peephole
mtreinish Jun 14, 2025
817c2b1
Fix target handling in peephole pass
mtreinish Jun 14, 2025
24b3e44
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Jun 14, 2025
dbbcb37
Fix merge conflict
mtreinish Jun 14, 2025
439e1eb
Expand test coverage to check individual gate synthesis
mtreinish Jun 14, 2025
b24088a
Fix release note example
mtreinish Jun 14, 2025
117b793
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Jul 7, 2025
3b92602
Include single qubit gate count in the heuristic
mtreinish Jul 9, 2025
0374185
Fix approximate-by-default behaviour of `UnitarySynthesis`
jakelishman Mar 13, 2026
3fce976
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 15, 2026
8acceee
Merge remote-tracking branch 'jakelishman/correct-approximation-degre…
mtreinish Mar 16, 2026
a64f6c0
Update the pass to leverage unitary synthesis logic for decomposition
mtreinish Mar 16, 2026
785a02b
Fix directionality test
mtreinish Mar 17, 2026
437e900
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 17, 2026
2f682d5
Fix dag reconstruction bug on insertion too early
mtreinish Mar 17, 2026
79f2466
Remove smallvec usage for original sequence scoring
mtreinish Mar 17, 2026
1cdaa61
Fix original score creation
mtreinish Mar 17, 2026
4503c14
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 17, 2026
a7794ff
Fix comparison between original score and new score
mtreinish Mar 17, 2026
8bcc573
Use Dashmap<NodeIndex, usize> instead of Mutex<HashMap<NodeIndex, usi…
mtreinish Mar 17, 2026
4ecb01e
Use thread local storage for decomposer cache
mtreinish Mar 18, 2026
76b40ab
Fix doc indent
mtreinish Mar 18, 2026
76f5935
Appease the lint check changing http->https in the license header
mtreinish Mar 18, 2026
2d40a18
Fix release note
mtreinish Mar 18, 2026
b88de4a
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 18, 2026
ce3dddf
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 19, 2026
158725f
Return a user error from a decomposer build with an incorrect string …
mtreinish Mar 19, 2026
a8a3fe7
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 23, 2026
a1643a8
Fix scoring of single decomposition
mtreinish Mar 23, 2026
8c58c3a
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 25, 2026
dfbe65d
Performance tuning
mtreinish Mar 26, 2026
9356125
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Mar 31, 2026
9e3a651
Don't use a hashset for tracking processed runs
mtreinish Mar 31, 2026
500a964
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Apr 2, 2026
a8dce96
Remove unnecessary empty check and use Mutex::into_inner() when no mo…
mtreinish Apr 2, 2026
2784217
Add atomic bool to tracking whether we've made a substitution
mtreinish Apr 2, 2026
469c06b
Merge remote-tracking branch 'origin/main' into two-qubit-peephole-pa…
mtreinish Apr 25, 2026
b9ce054
Add release note details to the pass docstring
mtreinish Apr 25, 2026
12b14ee
Update test module docstring
mtreinish Apr 25, 2026
f80db21
Update pass module docstring
mtreinish Apr 25, 2026
8c03af3
Fix typo in code comment
mtreinish Apr 25, 2026
819110d
Add docstrings for the new UnitarySynthesis helper methods
mtreinish Apr 25, 2026
56ea5aa
Expand 2q basis fore new tests
mtreinish Apr 25, 2026
31f616f
Use the peephole pass heuristic for best synthesis selection
mtreinish Apr 25, 2026
d91d1da
Add C API for two qubit unitary peephole optimization pass
mtreinish Apr 25, 2026
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
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions crates/cext-vtable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ mod transpiler {
export_fn!(remove_diagonal_gates_before_measure::qk_transpiler_pass_remove_diagonal_gates_before_measure),
export_fn!(remove_identity_equiv::qk_transpiler_pass_remove_identity_equivalent),
export_fn!(split_2q_unitaries::qk_transpiler_pass_split_2q_unitaries),
export_fn!(two_qubit_peephole::qk_transpiler_pass_two_qubit_peephole_optimization),
]
});
static FUNCTIONS_STANDALONE: ExportedFunctions = ExportedFunctions::leaves(50, || {
Expand All @@ -381,6 +382,7 @@ mod transpiler {
export_fn!(vf2::qk_transpiler_pass_standalone_vf2_layout_exact),
export_fn!(convert_to_pauli_rotations::qk_transpiler_pass_standalone_convert_to_pauli_rotations),
export_fn!(litinski_transformation::qk_transpiler_pass_standalone_litinski_transformation),
export_fn!(two_qubit_peephole::qk_transpiler_pass_standalone_two_qubit_peephole_optimization),
]
});
static FUNCTIONS_SABRE: ExportedFunctions = ExportedFunctions::leaves(5, || {
Expand Down
1 change: 1 addition & 0 deletions crates/cext/src/transpiler/passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ pub mod remove_diagonal_gates_before_measure;
pub mod remove_identity_equiv;
pub mod sabre_layout;
pub mod split_2q_unitaries;
pub mod two_qubit_peephole;
pub mod unitary_synthesis;
pub mod vf2;
324 changes: 324 additions & 0 deletions crates/cext/src/transpiler/passes/two_qubit_peephole.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
// This code is part of Qiskit.
//
// (C) Copyright IBM 2026
//
// 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 https://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, mut_ptr_as_ref};

use qiskit_circuit::circuit_data::CircuitData;
use qiskit_circuit::dag_circuit::DAGCircuit;
use qiskit_transpiler::passes::two_qubit_unitary_peephole_optimize;
use qiskit_transpiler::target::Target;

/// @ingroup QkTranspilerPassesStandalone
/// Run the TwoQubitPeepholeOptimization transpiler pass.
///
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we must have the same documentation twice for both functions? the standalone and the other one?
it's quite lengthy...

/// This transpiler pass is designed to perform two qubit unitary peephole
/// optimization. This pass finds all the 2 qubit blocks in the circuit,
/// computes the unitary of that block, and then synthesizes that unitary.
/// If the synthesized two qubit unitary is "better" than the original
/// subcircuit that subcircuit is used to replace the original. The heuristic
/// used to determine if it's better first looks at the two qubit gate count
/// in the circuit, and prefers the synthesis with fewer two qubit gates, if
/// the two qubit gate counts are the same then it looks at the estimated
/// fidelity of the circuit and picks the subcircuit with higher estimated
/// fidelity, and finally if needed it picks the subcircuit with the fewest
/// total gates.
///
/// In case the target is overcomplete the pass will try all the
/// decomposers supported for all the gates supported on a given qubit.
/// The decomposition that has the best expected performance using the above
/// heuristic will be selected and used to replace the block.
///
/// This pass is designed to be run on a physical circuit and the details of
/// operations on a given qubit is assumed to be the hardware qubit from the
/// target. However, the output of the pass might not use hardware operations,
/// specifically single qubit gates might be emitted outside the target's supported
/// operations, typically only if a parameterized gate supported by the
/// :class:`.TwoQubitControlledUDecomposer` is used for synthesis. As such if running
/// this pass in a physical optimization stage (such as :ref:`transpiler-preset-stage-optimization`)
/// this should be paired with passes such as :class:`.BasisTranslator` and/or
/// :class:`.Optimize1qGatesDecomposition` to ensure that these errant single qubit
/// gates are replaced with hardware supported operations prior to exiting the stage.
///
/// This pass is multithreaded, and will perform the analysis in parallel
/// and use all the cores available on your local system. You can refer to
/// the `configuration guide <https://docs.quantum.ibm.com/guides/configure-qiskit-local>`__
/// for details on how to control the threading behavior for Qiskit more broadly
/// which will also control this pass
Comment on lines +23 to +55
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In #15614 we went with the approach of having single source of truth for the general description of a given pass. We used the dag-based passes as such and had the standalone ones point to the dag-based functions for more detail. Should we follow this here as well?

///
/// @param circuit A pointer to the circuit to run TwoQubitPeepholeOptimization on
/// @param target A pointer to the target to run TwoQubitPeepholeOptimization with
/// @param approximation_degree heuristic dial used for circuit approximation
/// (1.0=no approximation, 0.0=maximal approximation). Approximation can
/// make the synthesized circuit smaller at the cost of straying from
/// the original unitary. If NAN, the target approximation is based on gate fidelities
/// in the ``target``.
///
/// # Example
///
/// ```c
/// QkTarget *target = qk_target_new(2);
/// uint32_t current_num_qubits = qk_target_num_qubits(target);
/// QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
/// for (uint32_t i = 0; i < current_num_qubits - 1; i++) {
/// uint32_t qargs[2] = {i, i + 1};
/// double inst_error = 0.0090393 * (current_num_qubits - i);
/// double inst_duration = 0.020039;
/// qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
/// }
/// QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
/// QkCircuit *qc = qk_circuit_new(2, 0);
/// uint32_t forward[2] = {0, 1};
/// uint32_t reverse[2] = {1, 0};
/// for (int i = 0; i < 10; i++) {
/// if (i % 2) {
/// qk_circuit_gate(qc, QkGate_CX, forward, NULL);
/// } else {
/// qk_circuit_gate(QkGate_CX, reverse, NULL);
/// }
/// }
/// qk_transpiler_pass_standalone_two_qubit_peephole_optimization(qc, target, 1.0);
/// ```
///
/// # Safety
///
/// Behavior is undefined if ``circuit`` or ``target`` is not a valid, non-null pointer to a ``QkCircuit`` and ``QkTarget``.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn qk_transpiler_pass_standalone_two_qubit_peephole_optimization(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A suggestion, for your discretion: replace _two_qubit_ with _2q_ to make the function names shorter.

circuit: *mut CircuitData,
target: *const Target,
approximation_degree: f64,
) {
// SAFETY: Per documentation, the pointer is non-null and aligned.
let circuit = unsafe { mut_ptr_as_ref(circuit) };
let target = unsafe { const_ptr_as_ref(target) };
let dag = match DAGCircuit::from_circuit_data(circuit, false, None, None, None, None) {
Ok(dag) => dag,
Err(e) => panic!("{}", e),
};
let approximation = if approximation_degree.is_nan() {
None
} else {
Some(approximation_degree)
};
let out_dag = match two_qubit_unitary_peephole_optimize(&dag, target.into(), approximation) {
Ok(dag) => dag,
Err(e) => panic!("{}", e),
};
if let Some(out_dag) = out_dag {
*circuit = CircuitData::from_dag_ref(&out_dag).unwrap();
}
}

/// @ingroup QkTranspilerPasses
/// Run the TwoQubitPeepholeOptimization transpiler pass.
///
/// This transpiler pass is designed to perform two qubit unitary peephole
/// optimization. This pass finds all the 2 qubit blocks in the circuit,
/// computes the unitary of that block, and then synthesizes that unitary.
/// If the synthesized two qubit unitary is "better" than the original
/// subcircuit that subcircuit is used to replace the original. The heuristic
/// used to determine if it's better first looks at the two qubit gate count
/// in the circuit, and prefers the synthesis with fewer two qubit gates, if
/// the two qubit gate counts are the same then it looks at the estimated
/// fidelity of the circuit and picks the subcircuit with higher estimated
/// fidelity, and finally if needed it picks the subcircuit with the fewest
/// total gates.
///
/// In case the target is overcomplete the pass will try all the
/// decomposers supported for all the gates supported on a given qubit.
/// The decomposition that has the best expected performance using the above
/// heuristic will be selected and used to replace the block.
///
/// This pass is designed to be run on a physical circuit and the details of
/// operations on a given qubit is assumed to be the hardware qubit from the
/// target. However, the output of the pass might not use hardware operations,
/// specifically single qubit gates might be emitted outside the target's supported
/// operations, typically only if a parameterized gate supported by the
/// :class:`.TwoQubitControlledUDecomposer` is used for synthesis. As such if running
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The Python-side Sphinx crossrefs don't render nicely on the C API pages. Should we just use backticks?

/// this pass in a physical optimization stage (such as :ref:`transpiler-preset-stage-optimization`)
/// this should be paired with passes such as :class:`.BasisTranslator` and/or
/// :class:`.Optimize1qGatesDecomposition` to ensure that these errant single qubit
/// gates are replaced with hardware supported operations prior to exiting the stage.
///
/// This pass is multithreaded, and will perform the analysis in parallel
/// and use all the cores available on your local system. You can refer to
/// the `configuration guide <https://docs.quantum.ibm.com/guides/configure-qiskit-local>`__
/// for details on how to control the threading behavior for Qiskit more broadly
/// which will also control this pass
///
/// @param circuit A pointer to the circuit to run TwoQubitPeepholeOptimization on
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
/// @param circuit A pointer to the circuit to run TwoQubitPeepholeOptimization on
/// @param dag A pointer to the DAG circuit to run TwoQubitPeepholeOptimization on

/// @param target A pointer to the target to run TwoQubitPeepholeOptimization with
/// @param approximation_degree heuristic dial used for circuit approximation
/// (1.0=no approximation, 0.0=maximal approximation). Approximation can
/// make the synthesized circuit smaller at the cost of straying from
/// the original unitary. If NAN, the target approximation is based on gate fidelities
/// in the ``target``.
///
/// # Example
///
/// ```c
/// QkTarget *target = qk_target_new(2);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nitpicking: we don't need to indent code examples anymore

/// uint32_t current_num_qubits = qk_target_num_qubits(target);
/// QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
/// for (uint32_t i = 0; i < current_num_qubits - 1; i++) {
/// uint32_t qargs[2] = {i, i + 1};
/// double inst_error = 0.0090393 * (current_num_qubits - i);
/// double inst_duration = 0.020039;
/// qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
/// }
/// QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
/// QkCircuit *qc = qk_circuit_new(2, 0);
/// uint32_t forward[2] = {0, 1};
/// uint32_t reverse[2] = {1, 0};
/// for (int i = 0; i < 10; i++) {
/// if (i % 2) {
/// qk_circuit_gate(qc, QkGate_CX, forward, NULL);
/// } else {
/// qk_circuit_gate(QkGate_CX, reverse, NULL);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
/// qk_circuit_gate(QkGate_CX, reverse, NULL);
/// qk_circuit_gate(qc, QkGate_CX, reverse, NULL);

/// }
/// }
/// QkDag *dag = qk_circuit_to_dag(qc);
/// qk_transpiler_pass_two_qubit_peephole_optimization(dag, target, 1.0);
/// ```
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it would be nice to add the qk_*_free functions here for completeness.

///
/// # Safety
///
/// Behavior is undefined if ``circuit`` or ``target`` is not a valid, non-null pointer to a ``QkCircuit`` and ``QkTarget``.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn qk_transpiler_pass_two_qubit_peephole_optimization(
dag: *mut DAGCircuit,
target: *const Target,
approximation_degree: f64,
) {
// 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 approximation = if approximation_degree.is_nan() {
None
} else {
Some(approximation_degree)
};
let out_dag = match two_qubit_unitary_peephole_optimize(&dag, target.into(), approximation) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nitpicking: I think we don't need the .into() here, do we?

Ok(dag) => dag,
Err(e) => panic!("{}", e),
};
if let Some(out_dag) = out_dag {
*dag = out_dag;
}
}

#[cfg(all(test, not(miri)))]
mod tests {
use super::*;

use qiskit_circuit::Qubit;
use qiskit_circuit::bit::ShareableQubit;
use qiskit_circuit::circuit_data::CircuitData;
use qiskit_circuit::instruction::Parameters;
use qiskit_circuit::operations::{ArrayType, Param, StandardGate, UnitaryGate};
use qiskit_circuit::packed_instruction::PackedOperation;
use qiskit_circuit::parameter::parameter_expression::ParameterExpression;
use qiskit_circuit::parameter::symbol_expr::Symbol;
use smallvec::smallvec;
use std::sync::Arc;

#[test]
fn test_pass_peephole() {
let mut qc = CircuitData::new(
Some((0..3).map(|_| ShareableQubit::new_anonymous()).collect()),
None,
(0.).into(),
)
.unwrap();
let array = StandardGate::CZ.matrix(&[]).unwrap();
let gate = UnitaryGate {
array: ArrayType::NDArray(array),
};
let operation = PackedOperation::from_unitary(Box::new(gate));
qc.push_packed_operation(operation, None, &[Qubit(0), Qubit(1)], &[])
.unwrap();
let array = StandardGate::DCX.matrix(&[]).unwrap();
let gate = UnitaryGate {
array: ArrayType::NDArray(array),
};
let operation = PackedOperation::from_unitary(Box::new(gate));
qc.push_packed_operation(operation, None, &[Qubit(1), Qubit(2)], &[])
.unwrap();
let array = StandardGate::DCX.matrix(&[]).unwrap();
let gate = UnitaryGate {
array: ArrayType::NDArray(array),
};
let operation = PackedOperation::from_unitary(Box::new(gate));
qc.push_packed_operation(operation, None, &[Qubit(1), Qubit(2)], &[])
.unwrap();
let array = StandardGate::Tdg.matrix(&[]).unwrap();
let gate = UnitaryGate {
array: ArrayType::NDArray(array),
};
let operation = PackedOperation::from_unitary(Box::new(gate));
qc.push_packed_operation(operation, None, &[Qubit(1)], &[])
.unwrap();
let array = StandardGate::CY.matrix(&[]).unwrap();
let gate = UnitaryGate {
array: ArrayType::NDArray(array),
};
let operation = PackedOperation::from_unitary(Box::new(gate));
qc.push_packed_operation(operation, None, &[Qubit(0), Qubit(2)], &[])
.unwrap();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

perhaps also add to the circuit some parametrized gate as well?


let mut target = Target::new(
Some("Fake Target".to_string()),
Some(3), // num_qubits
None, // dt
None, // granularity
None, // min_length
None, // pulse_alignment
None, // acquire_alignment
None, // qubit_properties
None, // concurrent_measurements
)
.unwrap();
let params = Some(Parameters::Params(smallvec![
Param::ParameterExpression(Arc::new(ParameterExpression::from_symbol(Symbol::new(
"ϴ", None, None,
)))),
Param::ParameterExpression(Arc::new(ParameterExpression::from_symbol(Symbol::new(
"φ", None, None,
)))),
Param::ParameterExpression(Arc::new(ParameterExpression::from_symbol(Symbol::new(
"λ", None, None,
)))),
]));
target
.add_instruction(
PackedOperation::from_standard_gate(StandardGate::U),
params,
None,
None,
)
.unwrap();
target
.add_instruction(
PackedOperation::from_standard_gate(StandardGate::CX),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

perhaps also test also a parametrized 2-qubit gate in the target?

None,
None,
None,
)
.unwrap();
unsafe {
qk_transpiler_pass_standalone_two_qubit_peephole_optimization(&mut qc, &target, 1.0);
};
let mut gate_names = qc.count_ops().keys().copied().collect::<Vec<_>>();
gate_names.sort();
assert_eq!(gate_names, vec!["cx", "u"]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there any particular reason why we test this here rather than in `test_two_qubit_peephole.c'? This doesn't seem like something we can't cover in the C API testing.

}
}
5 changes: 5 additions & 0 deletions crates/pyext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ fn _accelerate(m: &Bound<PyModule>) -> PyResult<()> {
add_submodule(m, ::qiskit_transpiler::passes::high_level_synthesis_mod, "high_level_synthesis")?;
add_submodule(m, ::qiskit_transpiler::passes::remove_diagonal_gates_before_measure_mod, "remove_diagonal_gates_before_measure")?;
add_submodule(m, ::qiskit_transpiler::passes::remove_identity_equiv_mod, "remove_identity_equiv")?;
add_submodule(
m,
::qiskit_transpiler::passes::two_qubit_peephole_mod,
"two_qubit_peephole",
)?;
add_submodule(m, ::qiskit_accelerate::results::results, "results")?;
add_submodule(m, ::qiskit_transpiler::passes::sabre::sabre, "sabre")?;
add_submodule(m, ::qiskit_accelerate::sampled_exp_val::sampled_exp_val, "sampled_exp_val")?;
Expand Down
2 changes: 1 addition & 1 deletion crates/synthesis/src/qsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub fn quantum_shannon_decomposition(
smallvec![],
aview2(&qiskit_circuit::gate_matrix::CX_GATE),
1.0,
"U",
EulerBasis::U,
None,
)?;
let one_qubit_decomposer = one_qubit_decomposer_basis_set.unwrap_or(&default_1q_basis);
Expand Down
Loading
Loading