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.14k stars 2.35k forks source link

BackendEstimator._transpile fails for BackendV2 backends #10970

Closed airwoodix closed 12 months ago

airwoodix commented 1 year ago

Environment

What is happening?

BackendEstimator(backend) with backend a BackendV2 fails in BackendEstimator._transpile due to mismatched transpilation output on the diff_circuits:

qiskit.circuit.exceptions.CircuitError: "Trying to compose with another QuantumCircuit which has more 'in' edges."

How can we reproduce the issue?

Consider a minimal BackendV2 implementation, a circuit definition, transpilation and a call to the BackendEstimator on that backend:

from math import pi
from typing import Any, List, Union

import qiskit
from qiskit import QuantumCircuit
from qiskit.circuit.library import Measure, RGate
from qiskit.circuit.parameter import Parameter
from qiskit.primitives import BackendEstimator
from qiskit.providers import BackendV2, Options
from qiskit.quantum_info import Pauli
from qiskit.transpiler import Target
from qiskit_aer import AerJob, AerProvider

class Backend(BackendV2):
    def __init__(self) -> None:
        super().__init__(name="dummy")

    @property
    def target(self) -> Target:
        theta = Parameter("theta")
        phi = Parameter("phi")

        target = Target(num_qubits=10)
        target.add_instruction(RGate(theta, phi))
        target.add_instruction(Measure())
        return target

    @property
    def max_circuits(self) -> int:
        return 100

    @classmethod
    def _default_options(cls) -> Options:
        return Options()

    def run(self, circuits: Union[QuantumCircuit, List[QuantumCircuit]], **options: Any) -> AerJob:
        sim = AerProvider().get_backend("aer_simulator")
        return sim.run(circuits, **options)

print("-- qiskit-terra version")
print(qiskit.__version__)

backend = Backend()

qc = QuantumCircuit(1)
qc.r(pi / 2, 0, 0)

opts = Options(initial_layout=[0])
r = qiskit.transpile(qc, backend, **opts.__dict__)
print("-- Transpiled layout")
print(r.layout)

print("-- Transpiled circuit")
print(r)

obs = Pauli("X")
estimator = BackendEstimator(backend)

print("-- Estimator result")
print(estimator.run(qc, obs).result())

With qiskit-terra==0.24.2, this runs as expected:

-- qiskit-terra version
0.24.2
-- Transpiled layout
TranspileLayout(initial_layout=Layout({
0: Qubit(QuantumRegister(1, 'q'), 0)
}), input_qubit_mapping={Qubit(QuantumRegister(1, 'q'), 0): 0}, final_layout=None)
-- Transpiled circuit
  ┌───────────┐┌────────┐
q ┤ R(-π/2,0) ├┤ R(π,0) ├
  └───────────┘└────────┘
-- Estimator result
EstimatorResult(values=array([-0.015625]), metadata=[{'variance': 0.999755859375, 'shots': 1024}])

With qiskit-terra>=0.25.0 however, the transpiled layout and circuit are different, and an error occurs in BackendEstimator._transpile:

-- qiskit-terra version
0.25.2
-- Transpiled layout
TranspileLayout(initial_layout=Layout({
0: Qubit(QuantumRegister(1, 'q'), 0),
1: Qubit(QuantumRegister(9, 'ancilla'), 0),
2: Qubit(QuantumRegister(9, 'ancilla'), 1),
3: Qubit(QuantumRegister(9, 'ancilla'), 2),
4: Qubit(QuantumRegister(9, 'ancilla'), 3),
5: Qubit(QuantumRegister(9, 'ancilla'), 4),
6: Qubit(QuantumRegister(9, 'ancilla'), 5),
7: Qubit(QuantumRegister(9, 'ancilla'), 6),
8: Qubit(QuantumRegister(9, 'ancilla'), 7),
9: Qubit(QuantumRegister(9, 'ancilla'), 8)
}), input_qubit_mapping={Qubit(QuantumRegister(1, 'q'), 0): 0, Qubit(QuantumRegister(9, 'ancilla'), 0): 1, Qubit(QuantumRegister(9, 'ancilla'), 1): 2, Qubit(QuantumRegister(9, 'ancilla'), 2): 3, Qubit(QuantumRegister(9, 'ancilla'), 3): 4, Qubit(QuantumRegister(9, 'ancilla'), 4): 5, Qubit(QuantumRegister(9, 'ancilla'), 5): 6, Qubit(QuantumRegister(9, 'ancilla'), 6): 7, Qubit(QuantumRegister(9, 'ancilla'), 7): 8, Qubit(QuantumRegister(9, 'ancilla'), 8): 9}, final_layout=None)
-- Transpiled circuit
               ┌───────────┐┌────────┐
      q_0 -> 0 ┤ R(-π/2,0) ├┤ R(π,0) ├
               └───────────┘└────────┘
ancilla_0 -> 1 ───────────────────────

ancilla_1 -> 2 ───────────────────────

ancilla_2 -> 3 ───────────────────────

ancilla_3 -> 4 ───────────────────────

ancilla_4 -> 5 ───────────────────────

ancilla_5 -> 6 ───────────────────────

ancilla_6 -> 7 ───────────────────────

ancilla_7 -> 8 ───────────────────────

ancilla_8 -> 9 ───────────────────────

-- Estimator result
Traceback (most recent call last):
  File "issue.py", line 62, in <module>
    print(estimator.run(qc, obs).result())
  File ".../python3.8/site-packages/qiskit/primitives/backend_estimator.py", line 222, in _transpile
    transpiled_circuit_copy.compose(diff_circuit, inplace=True)
  File ".../python3.8/site-packages/qiskit/circuit/quantumcircuit.py", line 925, in compose
    raise CircuitError(
qiskit.circuit.exceptions.CircuitError: "Trying to compose with another QuantumCircuit which has more 'in' edges."

(one can disregard that the transpiler is badly configured and produces two R gates for one in the input)

What should happen?

The code above should execute without errors also for qiskit-terra>=0.25.0.

The issue seems to come from the transpiler filling the transpiled circuit with ancilla qubits up to backend.target.num_qubits. This is not the case in either of the tested versions for BackendV1 instances (e.g. AerSimulator).

Any suggestions?

No response

ikkoham commented 1 year ago

Thank you. https://github.com/Qiskit/qiskit/pull/10956 will fix this issue.

airwoodix commented 1 year ago

Great, thanks! Sorry, I had not found this PR prior to posting the issue.