diff --git a/crates/accelerate/src/unitary_synthesis.rs b/crates/accelerate/src/unitary_synthesis.rs index 439b9ba80f67..cadec93f09f8 100644 --- a/crates/accelerate/src/unitary_synthesis.rs +++ b/crates/accelerate/src/unitary_synthesis.rs @@ -17,7 +17,7 @@ use std::sync::OnceLock; use approx::relative_eq; use hashbrown::{HashMap, HashSet}; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use ndarray::prelude::*; use num_complex::{Complex, Complex64}; @@ -627,8 +627,8 @@ fn get_2q_decomposers_from_target( } let target_basis_set = get_target_basis_set(target, qubits[0]); - let available_1q_basis: HashSet<&str> = - HashSet::from_iter(target_basis_set.get_bases().map(|basis| basis.as_str())); + let available_1q_basis: IndexSet<&str> = + IndexSet::from_iter(target_basis_set.get_bases().map(|basis| basis.as_str())); let mut decomposers: Vec = Vec::new(); #[inline] @@ -689,10 +689,10 @@ fn get_2q_decomposers_from_target( // If our 2q basis gates are a subset of cx, ecr, or cz then we know TwoQubitBasisDecomposer // is an ideal decomposition and there is no need to bother calculating the XX embodiments // or try the XX decomposer - let available_basis_set: HashSet<&str> = available_2q_basis.keys().copied().collect(); + let available_basis_set: IndexSet<&str> = available_2q_basis.keys().copied().collect(); #[inline] - fn check_goodbye(basis_set: &HashSet<&str>) -> bool { + fn check_goodbye(basis_set: &IndexSet<&str>) -> bool { basis_set.iter().all(|gate| GOODBYE_SET.contains(gate)) } diff --git a/test/python/transpiler/test_unitary_synthesis.py b/test/python/transpiler/test_unitary_synthesis.py index d7940ab1a763..767b126bbb3a 100644 --- a/test/python/transpiler/test_unitary_synthesis.py +++ b/test/python/transpiler/test_unitary_synthesis.py @@ -21,7 +21,7 @@ import scipy from ddt import ddt, data -from qiskit import transpile +from qiskit import transpile, generate_preset_pass_manager from qiskit.providers.fake_provider import Fake5QV1, GenericBackendV2 from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister from qiskit.circuit.library import quantum_volume @@ -921,7 +921,6 @@ def test_3q_measure_all(self): def test_target_with_global_gates(self): """Test that 2q decomposition can handle a target with global gates.""" - basis_gates = ["h", "p", "cp", "rz", "cx", "ccx", "swap"] target = Target.from_configuration(basis_gates=basis_gates) @@ -931,9 +930,28 @@ def test_target_with_global_gates(self): bell_op = Operator(bell) qc = QuantumCircuit(2) qc.unitary(bell_op, [0, 1]) + tqc = transpile(qc, target=target) self.assertTrue(set(tqc.count_ops()).issubset(basis_gates)) + def test_determinism(self): + """Test that the decomposition is deterministic.""" + gate_counts = {"rx": 6, "rz": 12, "iswap": 2} + basis_gates = ["rx", "rz", "iswap"] + target = Target.from_configuration(basis_gates=basis_gates) + pm = generate_preset_pass_manager(target=target, optimization_level=2, seed_transpiler=42) + + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + + for _ in range(10): + out = pm.run(qc) + self.assertTrue(Operator(out).equiv(qc)) + self.assertTrue(set(out.count_ops()).issubset(basis_gates)) + for basis_gate in basis_gates: + self.assertLessEqual(out.count_ops()[basis_gate], gate_counts[basis_gate]) + if __name__ == "__main__": unittest.main()