Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix replace_block_with_op on operations with wrong number of qubits #12637

Merged
merged 4 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,13 @@ def replace_block_with_op(
block_cargs.sort(key=wire_pos_map.get)
new_node = DAGOpNode(op, block_qargs, block_cargs, dag=self)

# check the op to insert matches the number of qubits we put it on
if op.num_qubits != len(block_qargs):
raise DAGCircuitError(
f"Number of qubits in the replacement operation ({op.num_qubits}) is not equal to "
f"the number of qubits in the block ({len(block_qargs)})!"
)

try:
new_node._node_id = self._multi_graph.contract_nodes(
block_ids, new_node, check_cycle=cycle_check
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
sub_dag = self._decompose_to_2q(dag, node.op)

block_op = Commuting2qBlock(set(sub_dag.op_nodes()))
wire_order = {wire: idx for idx, wire in enumerate(dag.qubits)}
wire_order = {
wire: idx
for idx, wire in enumerate(sub_dag.qubits)
if wire not in sub_dag.idle_wires()
}
dag.replace_block_with_op([node], block_op, wire_order)

return dag
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
Previously, :meth:`.DAGCircuit.replace_block_with_op` allowed to place an
``n``-qubit operation onto a block of ``m`` qubits, leaving the DAG in an
invalid state. This behavior has been fixed, and the attempt will raise
a :class:`.DAGCircuitError`.
16 changes: 16 additions & 0 deletions test/python/dagcircuit/test_dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2903,6 +2903,22 @@ def test_single_node_block(self):
self.assertEqual(expected_dag.count_ops(), dag.count_ops())
self.assertIsInstance(new_node.op, XGate)

def test_invalid_replacement_size(self):
"""Test inserting an operation on a wrong number of qubits raises."""

# two X gates, normal circuit
qc = QuantumCircuit(2)
qc.x(range(2))

# mutilate the DAG
dag = circuit_to_dag(qc)
to_replace = list(dag.op_nodes())
new_node = XGate()
idx_map = {node.qargs[0]: i for i, node in enumerate(to_replace)}

with self.assertRaises(DAGCircuitError):
dag.replace_block_with_op(to_replace, new_node, idx_map)

def test_replace_control_flow_block(self):
"""Test that we can replace a block of control-flow nodes with a single one."""
body = QuantumCircuit(1)
Expand Down
Loading