Skip to content

Add generic BackendEstimatorV2#156

Open
Polarnova wants to merge 1 commit into
Qiskit:mainfrom
Polarnova:add-backend-estimator-v2
Open

Add generic BackendEstimatorV2#156
Polarnova wants to merge 1 commit into
Qiskit:mainfrom
Polarnova:add-backend-estimator-v2

Conversation

@Polarnova
Copy link
Copy Markdown

@Polarnova Polarnova commented Jun 6, 2026

Closes #145

Summary

Add a BackendEstimatorV2 primitive that mirrors the existing BackendSamplerV2 shape: EstimatorPub carries an ISA circuit and observables, estimator.run() returns a BackendEstimatorJob, and the job result contains expectation values and standard errors.

The estimator uses the same precision-to-shots rule and Pauli expectation/std-error post-processing model as Qiskit Python BackendEstimatorV2 for the supported real-coefficient PauliSparseObservable subset.

The implementation reuses the existing BackendV2 sampler path, QuantumCircuit, SparseObservable/QkObs, BitArray, and standard-library math to extract Pauli terms, build grouped measurement circuits, execute them, and return evs/stds with shots and target_precision.

The patch includes the wrapper fixes required by the estimator and deterministic unit tests for estimator containers, observable extraction, measurement planning, and Pauli statistics.

Details

  • Add EstimatorPub, BackendEstimatorV2, BackendEstimatorJob, EstimatorPubResult, and EstimatorResult.
  • Implement a generic sampler-backed estimator path for Pauli and identity SparseObservable terms.
  • Derive backend shots from precision; the default 0.015625 matches Python BackendEstimatorV2's documented 1 / sqrt(4096) default (source), and Python maps precision to shots with ceil(1 / precision**2) (source).
  • Add qubit-wise compatible Pauli grouping, basis-rotation measurement circuits, and BitArray post-processing for evs/stds.

Execution flow

  1. BackendEstimatorV2::run() validates each EstimatorPub, resolves precision to a shot count, extracts real-coefficient Pauli terms from SparseObservable, and groups qubit-wise compatible Pauli terms into
    measurement circuits.
  2. Measurement circuits with the same shot count are submitted together through the existing BackendV2::run() sampler interface.
  3. BackendEstimatorJob::result() reads the returned BitArray samples and
    post-processes them into evs, stds, shots, and target_precision.

Scope notes

  • Input circuits with existing measurements report an explicit error in this patch. Matching Python's behavior needs estimator-owned classical registers, compose-with-clbit mapping, measurement-map remapping, and sampler-result routing by register name.
  • Measurement circuits with the same shot count are submitted together through the existing BackendV2::run() sampler interface.

Existing wrapper fixes

  1. SparseObservable
    Fix bit_terms() and boundaries() to use the QkObs C API array lengths, make indices() and the copy constructor null-safe, and add deep-copy operator=. Estimator term extraction depends on these arrays, and EstimatorPub assignment needs copied QkObs ownership rather than a shared raw handle.

  2. QuantumCircuit
    Make copy() const, add const get_measure_map(), and fix compose(circ, ...) to read instruction kinds from the source circuit. Estimator validation is read-only, and measured circuits must replay the input circuit before adding basis rotations.

  3. utils.hpp
    Replace the header-level hamming_parity/popcount function pointer variables with C++11 inline functions. This keeps Qiskit::popcount(x) call sites unchanged and avoids duplicate symbols when multiple test translation units include the header.

Testing

  • Coverage: deterministic unit tests for estimator containers, observable extraction, measurement planning, and Pauli statistics.
cmake --build test/build -j2
ctest -V -C Debug --test-dir test/build
cmake --build samples/build -j2
git diff --check

AI disclosure: I used ChatGPT/Codex for drafting and review assistance. I reviewed and own the final design, implementation, tests, and PR wording. Local checks I ran are listed above.

Add EstimatorPub, BackendEstimatorV2, BackendEstimatorJob, and estimator result containers backed by the existing BackendV2 sampler execution path.

The implementation extracts Pauli and identity terms from SparseObservable, builds estimator measurement circuits with qubit-wise compatible grouping, derives shots from precision, and post-processes BitArray samples into evs, stds, shots, and target_precision.

Include the wrapper fixes needed by the estimator: SparseObservable exposes QkObs array lengths correctly and copies safely, QuantumCircuit supports const-safe copy/measurement inspection and source-circuit compose replay, and hamming_parity/popcount are inline functions for multi-file test builds.
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Jun 6, 2026

CLA assistant check
All committers have signed the CLA.

@Polarnova
Copy link
Copy Markdown
Author

I kept the default C++ unit tests: estimator containers, QkObs/Pauli extraction, measurement planning, and Pauli statistics.

For end-to-end backend validation, would you prefer a CI test that compares this C++ estimator path against Qiskit Python/Aer on the same circuits and observables, or a separate validation script outside the default CI suite? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implementing estimator interface

2 participants