Skip to content

Error when Executing CommutativeInverseCancellation Pass in Qiskit v1.3.2 #13742

@nquetschlich

Description

@nquetschlich

Environment

  • Qiskit version: 1.3.2
  • Python version: 3.12
  • Operating system: MacOS 15.2

What is happening?

When executing the example, an error is caused under Qiskit v1.3.2 while it works under v1.3.1:

---------------------------------------------------------------------------
PanicException                            Traceback (most recent call last)
Cell In[1], line 7
      5     new_qc = qpy.load(fd)[0]
      6 pm = PassManager(CommutativeInverseCancellation())
----> 7 altered_qc = pm.run(new_qc)

File ~/.venv/lib/python3.12/site-packages/qiskit/transpiler/passmanager.py:464, in _replace_error.<locals>.wrapper(*meth_args, **meth_kwargs)
    461 @wraps(meth)
    462 def wrapper(*meth_args, **meth_kwargs):
    463     try:
--> 464         return meth(*meth_args, **meth_kwargs)
    465     except PassManagerError as ex:
    466         raise TranspilerError(ex.message) from ex

File ~/.venv/lib/python3.12/site-packages/qiskit/transpiler/passmanager.py:226, in PassManager.run(self, circuits, output_name, callback, num_processes)
    223 if callback is not None:
    224     callback = _legacy_style_callback(callback)
--> 226 return super().run(
    227     in_programs=circuits,
    228     callback=callback,
    229     output_name=output_name,
    230     num_processes=num_processes,
    231 )

File ~/.venv/lib/python3.12/site-packages/qiskit/passmanager/passmanager.py:232, in BasePassManager.run(self, in_programs, callback, num_processes, **kwargs)
    228 # If we're not going to run in parallel, we want to avoid spending time `dill` serializing
    229 # ourselves, since that can be quite expensive.
    230 if len(in_programs) == 1 or not should_run_in_parallel(num_processes):
    231     out = [
--> 232         _run_workflow(program=program, pass_manager=self, callback=callback, **kwargs)
    233         for program in in_programs
    234     ]
    235     if len(in_programs) == 1 and not is_list:
    236         return out[0]

File ~/.venv/lib/python3.12/site-packages/qiskit/passmanager/passmanager.py:292, in _run_workflow(program, pass_manager, **kwargs)
    286 initial_status = WorkflowStatus()
    288 passmanager_ir = pass_manager._passmanager_frontend(
    289     input_program=program,
    290     **kwargs,
    291 )
--> 292 passmanager_ir, final_state = flow_controller.execute(
    293     passmanager_ir=passmanager_ir,
    294     state=PassManagerState(
    295         workflow_status=initial_status,
    296         property_set=PropertySet(),
    297     ),
    298     callback=kwargs.get("callback", None),
    299 )
    300 # The `property_set` has historically been returned as a mutable attribute on `PassManager`
    301 # This makes us non-reentrant (though `PassManager` would be dependent on its internal tasks to
    302 # be re-entrant if that was required), but is consistent with previous interfaces.  We're still
    303 # safe to be called in a serial loop, again assuming internal tasks are re-runnable.  The
    304 # conversion to the backend language is also allowed to use the property set, so it must be set
    305 # before calling it.
    306 pass_manager.property_set = final_state.property_set

File ~/.venv/lib/python3.12/site-packages/qiskit/passmanager/base_tasks.py:218, in BaseController.execute(self, passmanager_ir, state, callback)
    216     return passmanager_ir, state
    217 while True:
--> 218     passmanager_ir, state = next_task.execute(
    219         passmanager_ir=passmanager_ir,
    220         state=state,
    221         callback=callback,
    222     )
    223     try:
    224         # Sending the object through the generator implies the custom controllers
    225         # can always rely on the latest data to choose the next task to run.
    226         next_task = task_generator.send(state)

File ~/.venv/lib/python3.12/site-packages/qiskit/transpiler/basepasses.py:195, in TransformationPass.execute(self, passmanager_ir, state, callback)
    189 def execute(
    190     self,
    191     passmanager_ir: PassManagerIR,
    192     state: PassManagerState,
    193     callback: Callable = None,
    194 ) -> tuple[PassManagerIR, PassManagerState]:
--> 195     new_dag, state = super().execute(
    196         passmanager_ir=passmanager_ir,
    197         state=state,
    198         callback=callback,
    199     )
    201     if state.workflow_status.previous_run == RunState.SUCCESS:
    202         if isinstance(new_dag, DAGCircuit):
    203             # Copy calibration data from the original program

File ~/.venv/lib/python3.12/site-packages/qiskit/passmanager/base_tasks.py:98, in GenericPass.execute(self, passmanager_ir, state, callback)
     96 try:
     97     if self not in state.workflow_status.completed_passes:
---> 98         ret = self.run(passmanager_ir)
     99         run_state = RunState.SUCCESS
    100     else:

File ~/.venv/lib/python3.12/site-packages/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py:122, in CommutativeInverseCancellation.run(self, dag)
    119             matched_idx2 = idx2
    120             break
--> 122     if not self.comm_checker.commute_nodes(
    123         topo_sorted_nodes[idx1],
    124         topo_sorted_nodes[idx2],
    125         max_num_qubits=self._max_qubits,
    126     ):
    127         break
    129 if matched_idx2 != -1:

File ~/.venv/lib/python3.12/site-packages/qiskit/circuit/commutation_checker.py:45, in CommutationChecker.commute_nodes(self, op1, op2, max_num_qubits)
     38 def commute_nodes(
     39     self,
     40     op1,
     41     op2,
     42     max_num_qubits: int = 3,
     43 ) -> bool:
     44     """Checks if two DAGOpNodes commute."""
---> 45     return self.cc.commute_nodes(op1, op2, max_num_qubits)

PanicException: index out of bounds: the len is 0 but the index is 0

How can we reproduce the issue?

Unfortunately, I cannot upload the qpy file directly, but I could upload it as a zip.

errorcircuit.qpy.zip

from qiskit import qpy
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import CommutativeInverseCancellation
with open('errorcircuit.qpy', 'rb') as fd:
    qc = qpy.load(fd)[0]
pm = PassManager(CommutativeInverseCancellation())
altered_qc = pm.run(qc)

What should happen?

There should be no error.

Any suggestions?

Probably the issue is related to the CommuteChecker (

return self.cc.commute_nodes(op1, op2, max_num_qubits)
) and only appears for the CommutativeInverseCancellation pass.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions