Skip to content

Commit

Permalink
Fix basis_count checking in ConsolidateBlocks
Browse files Browse the repository at this point in the history
The ConsolidateBlocks pass was ported to rust in Qiskit#13368 and as part of
that implementation a small behavior difference between the rust and
python interfaces was causing the pass to not work correctly with non-CX
gates. The internal 2q decomposer interface stores a sentinel string for
the kak gate which is used to tell the python space constructor use the
python defined gate object. However in the pass code we weren't
factoring this difference in, and for non-CX gates we were evaluating
the basis count as the number of gates with that sentinel value name
(which is almost always zero) and this was preventing the pass from
consolidating many blocks that should have been. This commit fixes this
issue by taking the name from python space and passing it through to the
rust portion of the code and using that for the comparison.

Fixes Qiskit#13459
  • Loading branch information
mtreinish committed Nov 20, 2024
1 parent 94cea41 commit f058eae
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
5 changes: 3 additions & 2 deletions crates/accelerate/src/consolidate_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ const MAX_2Q_DEPTH: usize = 20;

#[allow(clippy::too_many_arguments)]
#[pyfunction]
#[pyo3(signature = (dag, decomposer, force_consolidate, target=None, basis_gates=None, blocks=None, runs=None))]
#[pyo3(signature = (dag, decomposer, basis_gate_name, force_consolidate, target=None, basis_gates=None, blocks=None, runs=None))]
pub(crate) fn consolidate_blocks(
py: Python,
dag: &mut DAGCircuit,
decomposer: &TwoQubitBasisDecomposer,
basis_gate_name: &str,
force_consolidate: bool,
target: Option<&Target>,
basis_gates: Option<HashSet<String>>,
Expand Down Expand Up @@ -125,7 +126,7 @@ pub(crate) fn consolidate_blocks(
let inst = dag.dag()[*node].unwrap_operation();
block_qargs.extend(dag.get_qargs(inst.qubits));
all_block_gates.insert(*node);
if inst.op.name() == decomposer.gate_name() {
if inst.op.name() == basis_gate_name {
basis_count += 1;
}
if !is_supported(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def run(self, dag):
consolidate_blocks(
dag,
self.decomposer._inner_decomposer,
self.decomposer.gate.name,
self.force_consolidate,
target=self.target,
basis_gates=self.basis_gates,
Expand Down
80 changes: 78 additions & 2 deletions test/python/transpiler/test_consolidate_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,17 @@
import numpy as np
from ddt import ddt, data

from qiskit.circuit import QuantumCircuit, QuantumRegister, IfElseOp, Gate
from qiskit.circuit.library import U2Gate, SwapGate, CXGate, CZGate, UnitaryGate
from qiskit.circuit import QuantumCircuit, QuantumRegister, IfElseOp, Gate, Parameter
from qiskit.circuit.library import (
U2Gate,
SwapGate,
CXGate,
CZGate,
UnitaryGate,
SXGate,
XGate,
RZGate,
)
from qiskit.converters import circuit_to_dag
from qiskit.quantum_info.operators import Operator
from qiskit.quantum_info.operators.measures import process_fidelity
Expand Down Expand Up @@ -590,6 +599,73 @@ def test_no_kak_gates_in_preset_pm(self, opt_level):
tqc = pm.run(qc)
self.assertEqual(ref_tqc, tqc)

def test_non_cx_basis_gate(self):
"""Test a non-cx kak gate is consolidated correctly."""
qc = QuantumCircuit(2)
qc.cz(0, 1)
qc.x(0)
qc.h(1)
qc.z(1)
qc.t(1)
qc.h(0)
qc.t(0)
qc.cz(1, 0)
qc.sx(0)
qc.sx(1)
qc.cz(0, 1)
qc.sx(0)
qc.sx(1)
qc.cz(1, 0)
qc.x(0)
qc.h(1)
qc.z(1)
qc.t(1)
qc.h(0)
qc.t(0)
qc.cz(0, 1)

consolidate_pass = ConsolidateBlocks(basis_gates=["sx", "x", "rz", "cz"])
res = consolidate_pass(qc)
self.assertEqual({"unitary": 1}, res.count_ops())
self.assertEqual(Operator.from_circuit(qc), Operator(res.data[0].operation.params[0]))

def test_non_cx_target(self):
"""Test a non-cx kak gate is consolidated correctly."""
qc = QuantumCircuit(2)
qc.cz(0, 1)
qc.x(0)
qc.h(1)
qc.z(1)
qc.t(1)
qc.h(0)
qc.t(0)
qc.cz(1, 0)
qc.sx(0)
qc.sx(1)
qc.cz(0, 1)
qc.sx(0)
qc.sx(1)
qc.cz(1, 0)
qc.x(0)
qc.h(1)
qc.z(1)
qc.t(1)
qc.h(0)
qc.t(0)
qc.cz(0, 1)

phi = Parameter("phi")
target = Target(num_qubits=2)
target.add_instruction(SXGate(), {(0,): None, (1,): None})
target.add_instruction(XGate(), {(0,): None, (1,): None})
target.add_instruction(RZGate(phi), {(0,): None, (1,): None})
target.add_instruction(CZGate(), {(0, 1): None, (1, 0): None})

consolidate_pass = ConsolidateBlocks(target=target)
res = consolidate_pass(qc)
self.assertEqual({"unitary": 1}, res.count_ops())
self.assertEqual(Operator.from_circuit(qc), Operator(res.data[0].operation.params[0]))


if __name__ == "__main__":
unittest.main()

0 comments on commit f058eae

Please sign in to comment.