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

BackendEstimator support BackendV2 without coupling_map #10956

Merged
36 changes: 30 additions & 6 deletions qiskit/primitives/backend_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

from __future__ import annotations

import copy
import typing
from collections.abc import Sequence
from itertools import accumulate
Expand All @@ -29,7 +28,14 @@
from qiskit.quantum_info import Pauli, PauliList
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.result import Counts, Result
from qiskit.transpiler import PassManager
from qiskit.transpiler import CouplingMap, PassManager
from qiskit.transpiler.passes import (
ApplyLayout,
EnlargeWithAncilla,
FullAncillaAllocation,
Optimize1qGatesDecomposition,
SetLayout,
)

from .base import BaseEstimator, EstimatorResult
from .primitive_job import PrimitiveJob
Expand Down Expand Up @@ -210,9 +216,8 @@ def _transpile(self):
perm_pattern = list(range(transpiled_circuit.num_qubits))

# 2. transpile diff circuits
transpile_opts = copy.copy(self.transpile_options)
transpile_opts.update_options(initial_layout=perm_pattern)
diff_circuits = transpile(diff_circuits, self.backend, **transpile_opts.__dict__)
passmanager = _passmanager_for_measurement_circuits(perm_pattern, self.backend)
diff_circuits = passmanager.run(diff_circuits)
# 3. combine
transpiled_circuits = []
for diff_circuit in diff_circuits:
Expand Down Expand Up @@ -344,7 +349,7 @@ def _preprocessing(self) -> list[tuple[QuantumCircuit, list[QuantumCircuit]]]:
}
diff_circuits.append(meas_circuit)
else:
for basis, obs in zip(observable.paulis, observable): # type: ignore
for basis, obs in zip(observable.paulis, observable):
meas_circuit, indices = self._measurement_circuit(circuit.num_qubits, basis)
paulis = PauliList.from_symplectic(
obs.paulis.z[:, indices],
Expand Down Expand Up @@ -456,3 +461,22 @@ def _pauli_expval_with_variance(counts: Counts, paulis: PauliList) -> tuple[np.n
# Compute variance
variances = 1 - expvals**2
return expvals, variances


def _passmanager_for_measurement_circuits(layout, backend) -> PassManager:
passmanager = PassManager([SetLayout(layout)])
if isinstance(backend, BackendV2):
opt1q = Optimize1qGatesDecomposition(target=backend.target)
else:
opt1q = Optimize1qGatesDecomposition(basis=backend.configuration().basis_gates)
passmanager.append(opt1q)
if isinstance(backend, BackendV2) and isinstance(backend.coupling_map, CouplingMap):
coupling_map = backend.coupling_map
passmanager.append(FullAncillaAllocation(coupling_map))
passmanager.append(EnlargeWithAncilla())
elif isinstance(backend, BackendV1) and backend.configuration().coupling_map is not None:
coupling_map = CouplingMap(backend.configuration().coupling_map)
passmanager.append(FullAncillaAllocation(coupling_map))
passmanager.append(EnlargeWithAncilla())
passmanager.append(ApplyLayout())
return passmanager
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
fixes:
- |
Fixed a bug where :class:`.primitives.BackendEstimator` cannot be used with the
:class:`.providers.BackendV2` that does not have coupling_map.
7 changes: 4 additions & 3 deletions test/python/primitives/test_backend_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
from qiskit.primitives import BackendEstimator, EstimatorResult
from qiskit.providers import JobV1
from qiskit.providers.fake_provider import FakeNairobi, FakeNairobiV2
from qiskit.providers.fake_provider.fake_backend_v2 import FakeBackendSimple
from qiskit.quantum_info import SparsePauliOp
from qiskit.test import QiskitTestCase
from qiskit.transpiler import PassManager
from qiskit.utils import optionals

BACKENDS = [FakeNairobi(), FakeNairobiV2()]
BACKENDS = [FakeNairobi(), FakeNairobiV2(), FakeBackendSimple()]


@ddt
Expand Down Expand Up @@ -359,7 +360,7 @@ def test_layout(self, backend):
estimator = BackendEstimator(backend)
estimator.set_transpile_options(seed_transpiler=15)
value = estimator.run(qc, op, shots=10000).result().values[0]
if optionals.HAS_AER:
if optionals.HAS_AER and not isinstance(backend, FakeBackendSimple):
self.assertEqual(value, -0.916)
else:
self.assertEqual(value, -1)
Expand All @@ -374,7 +375,7 @@ def test_layout(self, backend):
estimator = BackendEstimator(backend)
estimator.set_transpile_options(initial_layout=[0, 1, 2], seed_transpiler=15)
value = estimator.run(qc, op, shots=10000).result().values[0]
if optionals.HAS_AER:
if optionals.HAS_AER and not isinstance(backend, FakeBackendSimple):
self.assertEqual(value, -0.8902)
else:
self.assertEqual(value, -1)
Expand Down