Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.3k stars 2.37k forks source link

Transpiler Failure #12909

Open glanzz opened 3 months ago

glanzz commented 3 months ago

Environment

What is happening?

The transpilation is throwing and error when running the following circuit with the following backend options. I have observed the same with AerSimulator, happening mostly when the optimisation value is set to 3. Compiler options:

How can we reproduce the issue?

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_aer import StatevectorSimulator
from qiskit import QuantumCircuit

qc = QuantumCircuit(3)
qc.x(0)
qc.x(1)
qc.x(2)
qc.id(0)
qc.id(0)

qc.measure_all()
print(qc)
backend = StatevectorSimulator()
options = {'layout_method': 'trivial', 'seed_transpiler': 1000, 'routing_method': 'stochastic', 'translation_method': 'synthesis'}
pass_manager = generate_preset_pass_manager(backend=backend, optimization_level=3, **options)
transpiled_circuit = pass_manager.run(qc)
print(transpiled_circuit)

print(backend.run(transpiled_circuit, shots=2034).result().get_counts())

What should happen?

Throws the following error: thread '<unnamed>' panicked at /Users/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/petgraph-0.6.5/src/graph_impl/stable_graph/mod.rs:402:17: StableGraph::add_edge: node index 20 is not a node in the graph
pyo3_runtime.PanicException: StableGraph::add_edge: node index 20 is not a node in the graph

Any suggestions?

No response

t-imamichi commented 3 months ago

I tried to shorten the script and found that the combination of optimization_level=3 and translation_method=synthesis causes the error.

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit import QuantumCircuit

qc = QuantumCircuit(2)
qc.x(0)
qc.id(0)
print(qc)
backend = AerSimulator()
for i in range(4):
    pass_manager = generate_preset_pass_manager(backend=backend, optimization_level=i, translation_method="synthesis")
    transpiled_circuit = pass_manager.run(qc)
    print("optimization level", i)
    print(transpiled_circuit)
    print()

output (both main branch and qiskit 1.1.1)

     ┌───┐┌───┐
q_0: ┤ X ├┤ I ├
     └───┘└───┘
q_1: ──────────

optimization level 0
     ┌─────────┐
q_0: ┤ Unitary ├
     └─────────┘
q_1: ───────────

optimization level 1
     ┌─────────┐
q_0: ┤ Unitary ├
     └─────────┘
q_1: ───────────

optimization level 2
     ┌─────────┐
q_0: ┤ Unitary ├
     └─────────┘
q_1: ───────────

thread '<unnamed>' panicked at /Users/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/petgraph-0.6.5/src/graph_impl/stable_graph/mod.rs:402:17:
StableGraph::add_edge: node index 6 is not a node in the graph
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: petgraph::graph_impl::stable_graph::StableGraph<N,E,Ty,Ix>::add_edge
   3: rustworkx::digraph::PyDiGraph::__pymethod___setstate____
   4: pyo3::impl_::trampoline::trampoline
   5: rustworkx::digraph::<impl pyo3::impl_::pyclass::PyMethods<rustworkx::digraph::PyDiGraph> for pyo3::impl_::pyclass::PyClassImplCollector<rustworkx::digraph::PyDiGraph>>::py_methods::ITEMS::trampoline
   6: _method_vectorcall_VARARGS_KEYWORDS
   7: __PyEval_EvalFrameDefault
   8: _PyEval_EvalCode
   9: _run_eval_code_obj
  10: _run_mod
  11: _pyrun_file
  12: __PyRun_SimpleFileObject
  13: __PyRun_AnyFileObject
  14: _pymain_run_file_obj
  15: _pymain_run_file
  16: _Py_RunMain
  17: _pymain_main
  18: _Py_BytesMain
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Traceback (most recent call last):
  File "/Users/ima/tasks/4_2024/qiskit/terra/tmp/12909.py", line 12, in <module>
    transpiled_circuit = pass_manager.run(qc)
                         ^^^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/transpiler/passmanager.py", line 441, in run
    return super().run(circuits, output_name, callback, num_processes=num_processes)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/transpiler/passmanager.py", line 464, in wrapper
    return meth(*meth_args, **meth_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/transpiler/passmanager.py", line 226, in run
    return super().run(
           ^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/passmanager/passmanager.py", line 232, in run
    _run_workflow(program=program, pass_manager=self, callback=callback, **kwargs)
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/passmanager/passmanager.py", line 292, in _run_workflow
    passmanager_ir, final_state = flow_controller.execute(
                                  ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/passmanager/base_tasks.py", line 218, in execute
    passmanager_ir, state = next_task.execute(
                            ^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/passmanager/base_tasks.py", line 218, in execute
    passmanager_ir, state = next_task.execute(
                            ^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/transpiler/basepasses.py", line 195, in execute
    new_dag, state = super().execute(
                     ^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/passmanager/base_tasks.py", line 98, in execute
    ret = self.run(passmanager_ir)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ima/tasks/4_2024/qiskit/terra/qiskit/transpiler/passes/utils/minimum_point.py", line 100, in run
    state.dag = deepcopy(dag)
                ^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/copy.py", line 261, in _reconstruct
    y.__setstate__(state)
pyo3_runtime.PanicException: StableGraph::add_edge: node index 6 is not a node in the graph
Cryoris commented 3 months ago

This can be solved by manually cloning the DAG in the MinimumPoint transpiler pass, instead of calling deepcopy(dag). I can open a PR to fix it, but before doing so let's briefly discuss if we shouldn't override __deepcopy__ on the DAGCircuit (@mtreinish probably knows best as he wrote that transpiler pass) 🙂

glanzz commented 3 months ago

@t-imamichi this issue is reproducible even without translation_method="synthesis"

t-imamichi commented 3 months ago

Both your and my scripts do not raise the error without translation_method="synthesis" on my environment (both qiskit 1.1.1 and main branch). Could you paste the full error message?

weucode commented 3 months ago

I'm having this problem too. Here is my program:

from math import pi

from qiskit.circuit import QuantumCircuit
from qiskit import transpile

qc = QuantumCircuit(4)
qc.cx(3, 2)
qc.ry(pi, 3)
qc.ry(-pi, 3)
qc.cx(3, 2)
qc.rz(- pi / 4, 3)
qc.measure_all()

from qiskit_aer import AerSimulator
backend = AerSimulator()
transpiled_qc = transpile(qc, optimization_level=3, backend=backend)
print("transpiled_qc:")
print(transpiled_qc)

The error message displayed is:

thread '<unnamed>' panicked at /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/petgraph-0.6.5/src/graph_impl/stable_graph/mod.rs:402:17:
StableGraph::add_edge: node index 23 is not a node in the graph
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "/home/1.py", line 16, in <module>
    transpiled_qc = transpile(qc, optimization_level=3, backend=backend)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/compiler/transpiler.py", line 419, in transpile
    out_circuits = pm.run(circuits, callback=callback, num_processes=num_processes)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/transpiler/passmanager.py", line 440, in run
    return super().run(circuits, output_name, callback, num_processes=num_processes)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/transpiler/passmanager.py", line 463, in wrapper
    return meth(*meth_args, **meth_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/transpiler/passmanager.py", line 225, in run
    return super().run(
           ^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/passmanager/passmanager.py", line 232, in run
    _run_workflow(program=program, pass_manager=self, callback=callback, **kwargs)
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/passmanager/passmanager.py", line 292, in _run_workflow
    passmanager_ir, final_state = flow_controller.execute(
                                  ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/passmanager/base_tasks.py", line 218, in execute
    passmanager_ir, state = next_task.execute(
                            ^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/passmanager/base_tasks.py", line 218, in execute
    passmanager_ir, state = next_task.execute(
                            ^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/transpiler/basepasses.py", line 195, in execute
    new_dag, state = super().execute(
                     ^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/passmanager/base_tasks.py", line 98, in execute
    ret = self.run(passmanager_ir)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/site-packages/qiskit/transpiler/passes/utils/minimum_point.py", line 105, in run
    state.dag = deepcopy(dag)
                ^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/anaconda3/envs/qiskit_latest/lib/python3.12/copy.py", line 261, in _reconstruct
    y.__setstate__(state)
pyo3_runtime.PanicException: StableGraph::add_edge: node index 23 is not a node in the graph

This error does not occur consistently. I have outputted the DAG sent to MinimumPoint, resulting in two versions: DAG1: dag1

DAG2: dag2

The error is only thrown when the circuit is optimized into a unitary gate (DAG 2).

t-imamichi commented 3 months ago

Thank you for the information. It's the same reason due to MinimumPoint transpiler pass. @Cryoris is working on it now.

weucode commented 3 months ago

Thank you for your quick response! I'm also curious about why there are two versions of the DAG. I've reviewed all the passes used during the transpile process, but I haven't observed any differences between the two groups of passes that result in the different DAG versions.