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

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

Open
nquetschlich opened this issue Jan 27, 2025 · 1 comment · May be fixed by #13762
Open

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

nquetschlich opened this issue Jan 27, 2025 · 1 comment · May be fixed by #13762
Assignees
Labels
bug Something isn't working
Milestone

Comments

@nquetschlich
Copy link

nquetschlich commented Jan 27, 2025

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.

@nquetschlich nquetschlich added the bug Something isn't working label Jan 27, 2025
@Cryoris
Copy link
Contributor

Cryoris commented Jan 30, 2025

Thanks for the report! Here's a more minimal reproducer:

import numpy as np
from qiskit.circuit.library import RXXGate, UGate, RGate
from qiskit.circuit.commutation_library import SessionCommutationChecker as scc

res = scc.commute(RXXGate(np.pi / 2), [0, 1], [], RGate(2, 2), [1], [])
print(res)

This only breaks if the second gate has more than 1 parameter (e.g. U2 or U), but works for gates with a single or no parameter...

@Cryoris Cryoris linked a pull request Jan 30, 2025 that will close this issue
@1ucian0 1ucian0 added this to the 1.4.0 milestone Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants