"""Sampler implementation using QasmSimulatorBackend."""
from __future__ import annotations
import math
from typing import TYPE_CHECKING, Any, Mapping, Sequence, Union
from qiskit.primitives import SamplerResult
from qiskit.primitives.sampler import Sampler as QiskitSampler
from qiskit.result import QuasiDistribution, Result
from mqt.ddsim.qasmsimulator import QasmSimulatorBackend
if TYPE_CHECKING:
from qiskit.circuit import Parameter
from qiskit.circuit.parameterexpression import ParameterValueType
Parameters = Union[Mapping[Parameter, ParameterValueType], Sequence[ParameterValueType]]
[docs]
class Sampler(QiskitSampler): # type: ignore[misc]
_BACKEND = QasmSimulatorBackend()
def __init__(
self,
*,
options: dict[str, Any] | None = None,
) -> None:
"""Initialize a new DDSIM Sampler
Args:
options: Default options.
"""
super().__init__(options=options)
@property
def backend(self) -> QasmSimulatorBackend:
return self._BACKEND
@property
def num_circuits(self) -> int:
"""The number of circuits stored in the sampler."""
return len(self._circuits)
def _call(
self,
circuits: Sequence[int],
parameter_values: Sequence[Parameters],
**run_options: Any,
) -> SamplerResult:
"""Runs DDSIM backend
Args:
circuits: List of circuit indices to simulate
parameter_values: List of parameters associated with those circuits
run_options: Additional run options.
Returns:
The result of the sampling process.
"""
result = self.backend.run([self._circuits[i] for i in circuits], parameter_values, **run_options).result()
return self._postprocessing(result, circuits)
@staticmethod
def _postprocessing(result: Result, circuits: Sequence[int]) -> SamplerResult:
"""Converts counts into quasi-probability distributions
Args:
result: Result from DDSIM backend
circuits: List of circuit indices
Returns:
The result of the sampling process.
"""
counts = result.get_counts()
if not isinstance(counts, list):
counts = [counts]
shots = sum(counts[0].values())
metadata: list[dict[str, Any]] = [{"shots": shots} for _ in range(len(circuits))]
probabilities = [
QuasiDistribution(
{k: v / shots for k, v in count.items()},
shots=shots,
stddev_upper_bound=1 / math.sqrt(shots),
)
for count in counts
]
return SamplerResult(probabilities, metadata)