Skip to content

Commit

Permalink
BackendEstimator support BackendV2 without coupling_map (#10956)
Browse files Browse the repository at this point in the history
* BackendEstimator support BackendV2 without coupling_map

* revert unnecessary type

* add unittest

* lint

* refactoring

* add release note

---------

Co-authored-by: Takashi Imamichi <[email protected]>
  • Loading branch information
ikkoham and t-imamichi authored Oct 11, 2023
1 parent 947e175 commit be2cebc
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 9 deletions.
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

0 comments on commit be2cebc

Please sign in to comment.