@@ -21,8 +21,8 @@ use pyo3::exceptions::PyIndexError;
2121use pyo3:: intern;
2222use pyo3:: prelude:: * ;
2323use qiskit_circuit:: Qubit ;
24- use qiskit_circuit:: circuit_data:: CircuitData ;
25- use qiskit_circuit:: dag_circuit:: { DAGCircuit , NodeType } ;
24+ use qiskit_circuit:: circuit_data:: { CircuitData , CircuitDataError } ;
25+ use qiskit_circuit:: dag_circuit:: { DAGCircuit , DAGCircuitInnerError , NodeType } ;
2626use qiskit_circuit:: gate_matrix:: {
2727 CH_GATE , CX_GATE , CY_GATE , CZ_GATE , DCX_GATE , ECR_GATE , ISWAP_GATE , ONE_QUBIT_IDENTITY ,
2828} ;
@@ -46,6 +46,39 @@ use crate::passes::unitary_synthesis::{PARAM_SET, TWO_QUBIT_BASIS_SET};
4646use crate :: target:: { Qargs , Target } ;
4747use qiskit_circuit:: PhysicalQubit ;
4848
49+ /// Possible errors coming from the `ConsolidateBlocks` pass.
50+ #[ derive( Debug , thiserror:: Error ) ]
51+ pub enum ConsolidateBlocksError {
52+ #[ error( "node index in run or block was not a valid operation" ) ]
53+ InvalidIndexOp ,
54+ #[ error( transparent) ]
55+ DAGCircuit ( #[ from] DAGCircuitInnerError ) ,
56+ #[ error( transparent) ]
57+ Circuit ( #[ from] CircuitDataError ) ,
58+ #[ error( transparent) ]
59+ // TODO: Replace with decomposer rust native error
60+ PyTwoQubitBasisDecomposer ( PyErr ) ,
61+ #[ error( transparent) ]
62+ PyMatrixError ( PyErr ) ,
63+ #[ error( transparent) ]
64+ PyTwoQubitControlledU ( PyErr ) ,
65+ }
66+
67+ impl From < ConsolidateBlocksError > for PyErr {
68+ fn from ( value : ConsolidateBlocksError ) -> Self {
69+ match value {
70+ ConsolidateBlocksError :: DAGCircuit ( dagcircuit_inner_error) => {
71+ dagcircuit_inner_error. into ( )
72+ }
73+ ConsolidateBlocksError :: Circuit ( circuit_data_error) => circuit_data_error. into ( ) ,
74+ ConsolidateBlocksError :: InvalidIndexOp => PyIndexError :: new_err ( value. to_string ( ) ) ,
75+ ConsolidateBlocksError :: PyMatrixError ( py_err)
76+ | ConsolidateBlocksError :: PyTwoQubitBasisDecomposer ( py_err)
77+ | ConsolidateBlocksError :: PyTwoQubitControlledU ( py_err) => py_err,
78+ }
79+ }
80+ }
81+
4982static IDENTITY_2Q : Matrix4 < Complex64 > = Matrix4 :: new (
5083 // Row 1
5184 Complex64 :: ONE ,
@@ -232,6 +265,32 @@ fn py_run_consolidate_blocks(
232265 runs : Option < Vec < Vec < usize > > > ,
233266 qubit_map : Option < Vec < PhysicalQubit > > ,
234267) -> PyResult < ( ) > {
268+ inner_run_consolidate_blocks (
269+ dag,
270+ decomposer,
271+ basis_gate_name,
272+ force_consolidate,
273+ target,
274+ basis_gates,
275+ blocks,
276+ runs,
277+ qubit_map,
278+ )
279+ . map_err ( Into :: into)
280+ }
281+
282+ #[ allow( clippy:: too_many_arguments) ]
283+ fn inner_run_consolidate_blocks (
284+ dag : & mut DAGCircuit ,
285+ decomposer : Option < DecomposerType > ,
286+ basis_gate_name : & str ,
287+ force_consolidate : bool ,
288+ target : Option < & Target > ,
289+ basis_gates : Option < HashSet < String > > ,
290+ blocks : Option < Vec < Vec < usize > > > ,
291+ runs : Option < Vec < Vec < usize > > > ,
292+ qubit_map : Option < Vec < PhysicalQubit > > ,
293+ ) -> Result < ( ) , ConsolidateBlocksError > {
235294 // If we don't have a decomposer and force consolidate is not set then there is not any
236295 // consolidation to do.
237296 if decomposer. is_none ( ) && !force_consolidate {
@@ -241,15 +300,14 @@ fn py_run_consolidate_blocks(
241300 // trust that they come from a correct analysis (or the block/run collection might have been
242301 // invalidated). Rather than panicking, we should raise Python-space exceptions. We don't have
243302 // to check indices that are generated by trusted Rust-only methods within this function.
244- let valid_op_node = |dag : & mut DAGCircuit , index : usize | -> PyResult < NodeIndex > {
245- let index = NodeIndex :: new ( index) ;
246- match dag. dag ( ) . node_weight ( index) {
247- Some ( NodeType :: Operation ( _) ) => Ok ( index) ,
248- _ => Err ( PyIndexError :: new_err (
249- "node index in run or block was not a valid operation" ,
250- ) ) ,
251- }
252- } ;
303+ let valid_op_node =
304+ |dag : & mut DAGCircuit , index : usize | -> Result < NodeIndex , ConsolidateBlocksError > {
305+ let index = NodeIndex :: new ( index) ;
306+ match dag. dag ( ) . node_weight ( index) {
307+ Some ( NodeType :: Operation ( _) ) => Ok ( index) ,
308+ _ => Err ( ConsolidateBlocksError :: InvalidIndexOp ) ,
309+ }
310+ } ;
253311 let blocks = match blocks {
254312 Some ( runs) => runs
255313 . into_iter ( )
@@ -385,7 +443,8 @@ fn py_run_consolidate_blocks(
385443 . as_array ( )
386444 . to_owned ( ) ;
387445 Ok ( matrix)
388- } ) ?;
446+ } )
447+ . map_err ( ConsolidateBlocksError :: PyMatrixError ) ?;
389448 let identity: Array2 < Complex64 > = Array2 :: eye ( 2usize . pow ( block_qargs. len ( ) as u32 ) ) ;
390449 if approx:: abs_diff_eq!( identity, matrix. view( ) ) {
391450 for node in block {
@@ -422,19 +481,19 @@ fn py_run_consolidate_blocks(
422481 } else {
423482 let num_basis_gates = if let Some ( ref decomposer) = decomposer {
424483 match decomposer {
425- DecomposerType :: TwoQubitBasis ( decomp) => {
426- decomp. num_basis_gates_inner ( nalgebra_array_view :: <
427- Complex64 ,
428- U4 ,
429- U4 ,
430- > (
431- matrix. as_view ( )
432- ) ) ?
433- }
484+ DecomposerType :: TwoQubitBasis ( decomp) => decomp
485+ . num_basis_gates_inner ( nalgebra_array_view :: < Complex64 , U4 , U4 > (
486+ matrix. as_view ( ) ,
487+ ) )
488+ . map_err ( ConsolidateBlocksError :: PyTwoQubitBasisDecomposer ) ?,
434489 DecomposerType :: TwoQubitControlledU ( decomp) => decomp
435490 . num_basis_gates_inner ( nalgebra_array_view :: < Complex64 , U4 , U4 > (
436491 matrix. as_view ( ) ,
437- ) ) ?,
492+ ) )
493+ // The only way this throws an error is if it deals with a
494+ // bad Python operation. So we can just wrap it into its own
495+ // special case.
496+ . map_err ( ConsolidateBlocksError :: PyTwoQubitControlledU ) ?,
438497 }
439498 } else {
440499 unreachable ! ( "A decomposer is always set unless force_consolidate is true" ) ;
@@ -576,10 +635,10 @@ pub fn run_consolidate_blocks(
576635 force_consolidate : bool ,
577636 approximation_degree : Option < f64 > ,
578637 target : Option < & Target > ,
579- ) -> PyResult < ( ) > {
638+ ) -> Result < ( ) , ConsolidateBlocksError > {
580639 let approximation_degree = approximation_degree. unwrap_or ( 1.0 ) ;
581640 if force_consolidate {
582- py_run_consolidate_blocks (
641+ inner_run_consolidate_blocks (
583642 dag,
584643 None ,
585644 "cx" ,
@@ -593,7 +652,7 @@ pub fn run_consolidate_blocks(
593652 )
594653 } else {
595654 let ( decomposer, basis_gate) = get_decomposer_and_basis_gate ( target, approximation_degree) ;
596- py_run_consolidate_blocks (
655+ inner_run_consolidate_blocks (
597656 dag,
598657 Some ( decomposer) ,
599658 basis_gate. name ( ) ,
0 commit comments