Source code for qbraid.runtime.native.result

# Copyright (C) 2024 qBraid
#
# This file is part of the qBraid-SDK
#
# The qBraid-SDK is free software released under the GNU General Public License v3
# or later. You can redistribute and/or modify it under the terms of the GPL v3.
# See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>.
#
# THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3.

"""
Module defining QbraidResult class

"""
from dataclasses import dataclass, field
from typing import Any

import numpy as np

from qbraid.runtime.result import GateModelJobResult


[docs] @dataclass class ExperimentResult: """Class to represent the results of a quantum circuit simulation.""" measurement_counts: dict = field(default_factory=lambda: {}) execution_duration: int = -1 process_id: str = "" @staticmethod def from_result(result: dict[str, Any]): """Factory method to create JobResult from a result dictionary.""" measurement_counts = result.get("measurementCounts", {}) time_stamps = result.get("timeStamps", {}) execution_duration = time_stamps.get("executionDuration", -1) process_id = result.get("vendorJobId", "") return ExperimentResult( measurement_counts=measurement_counts, execution_duration=execution_duration, process_id=process_id, )
[docs] class QbraidJobResult(GateModelJobResult): """Class to represent the results of a quantum circuit simulation."""
[docs] def __init__(self, device_id: str, job_id: str, success: bool, result: ExperimentResult): """Create a new Result object.""" super().__init__() self.device_id = device_id self.job_id = job_id self.success = success self.result = result self._cached_histogram = None self._cached_metadata = None self._measurements = None
def __repr__(self): """Return a string representation of the Result object.""" return ( f"QbraidJobResult(device_id='{self.device_id}', job_id='{self.job_id}', " f"success={self.success})" ) def measurements(self): """Return the measurement results 2D numpy array.""" if self._measurements is None: counts = self.result.measurement_counts if counts: measurements = [] for state, count in counts.items(): measurements.extend([list(map(int, state))] * count) self._measurements = np.array(measurements, dtype=int) return self._measurements def raw_counts(self, decimal: bool = False, **kwargs): """Returns raw histogram data of the run""" measurements = self.measurements() if measurements is None: raise ValueError("No measurement data available.") counts = self._array_to_histogram(measurements) if decimal is True: counts = {int(key, 2): value for key, value in counts.items()} return counts def measurement_probabilities(self, **kwargs) -> dict[str, float]: """Calculate and return the probabilities of each measurement result.""" counts = self.measurement_counts(**kwargs) probabilities = self.counts_to_probabilities(counts) return probabilities def _array_to_histogram(self, arr: np.ndarray) -> dict[str, int]: """Implement caching mechanism here.""" if self._cached_histogram is None: row_strings = ["".join(map(str, row)) for row in arr] self._cached_histogram = {row: row_strings.count(row) for row in set(row_strings)} return self._cached_histogram @staticmethod def counts_to_probabilities(counts: dict[str, int]) -> dict[str, float]: """ Convert histogram counts to probabilities. Args: counts (Dict[str, int]): A dictionary with measurement outcomes as keys and their counts as values. Returns: Dict[str, float]: A dictionary with measurement outcomes as keys and their probabilities as values. """ total_counts = sum(counts.values()) measurement_probabilities = { outcome: count / total_counts for outcome, count in counts.items() } return measurement_probabilities def metadata(self) -> dict[str, int]: """Return metadata about the measurement results.""" if self._cached_metadata is None: num_shots, num_qubits = self.measurements().shape self._cached_metadata = { "num_shots": num_shots, "num_qubits": num_qubits, "execution_duration": self.result.execution_duration, "measurements": self.measurements(), "measurement_counts": self.measurement_counts(), "measurement_probabilities": self.measurement_probabilities(), } return self._cached_metadata