Source code for scikit_quri.backend.oqtopus_estimator
from .base_estimator import BaseEstimator
from typing import Sequence, Iterable, Optional
from quri_parts_oqtopus.backend import OqtopusConfig, OqtopusEstimationBackend
from quri_parts.circuit import NonParametricQuantumCircuit
from quri_parts.core.operator import Operator, PauliLabel
from quri_parts.core.estimator import Estimatable, Estimate
[docs]class OqtopusEstimator(BaseEstimator):
"""quri-parts-oqtopusを用いて実機で期待値を計算するEstimator Class
実行には`~/.oqtopus`の設定が必要
https://quri-parts-oqtopus.readthedocs.io/en/stable/usage/getting_started/#prepare-oqtopus-configuration-file
Args:
device_id: 実行するデバイスのID
shots: ショット数. Defaults to 1000.
config: OqtopusのConfig. Defaults to None.
"""
def __init__(
self, device_id: str, shots: int = 1000, config: Optional[OqtopusConfig] = None
) -> None:
self.backend = OqtopusEstimationBackend(config=config)
self.device_id = device_id
self.shots = shots
[docs] def estimate(self, operators, states):
"""operatorsとstatesの組み合わせに対して期待値を計算する
operatorsまたはstatesのどちらかが1つの場合、もう一方の数に合わせて繰り返す
もしくは、両方の数が同じ場合、1対1で対応させる
それ以外の場合、ValueErrorを投げる
Args:
operators: 期待値を計算する演算子のリスト
states: 期待値を計算する状態のリスト
Returns:
operatorsとstatesの組み合わせに対する期待値のリスト
Raises:
ValueError: operatorsまたはstatesが空、もしくは両方の数が異なる場合
BackendError: Oqtopusでの実行に失敗した場合
"""
num_ops = len(operators)
num_states = len(states)
# operatorが1つもしくはstateが1つの場合は、もう一方の数に合わせて繰り返す
if num_ops == 0:
raise ValueError("No operator specified.")
if num_states == 0:
raise ValueError("No state specified.")
if num_ops > 1 and num_states > 1 and num_ops != num_states:
raise ValueError(
f"Number of operators ({num_ops}) does not matchnumber of states ({num_states})."
)
if num_states == 1:
# memory節約のため、shallow copy
circuits = [states[0].circuit] * num_ops
return self._estimate_concurrently(operators, circuits)
else:
if num_ops == 1:
operators = [next(iter(operators))] * num_states
circuits = [state.circuit for state in states]
return self._estimate_concurrently(operators, circuits)
def _estimate_concurrently(
self, operators: Sequence[Estimatable], circuits: Sequence[NonParametricQuantumCircuit]
) -> Iterable[Estimate[complex]]:
"""
operatorsとcircuitsの1対1の組み合わせに対して期待値を計算する
Args:
operators: 期待値を計算する演算子のリスト
circuits: 期待値を計算する量子回路のリスト
Returns:
operatorsとcircuitsの組み合わせに対する期待値のリスト
Raises:
BackendError: Oqtopusでの実行に失敗した場合
"""
results = []
for circuit, operator in zip(circuits, operators):
# EstimatableをOperatorに統一する
if isinstance(operator, PauliLabel):
operator = Operator({operator: 1.0})
job = self.backend.estimate(
circuit, operator=operator, device_id=self.device_id, shots=self.shots
)
result = job.result()
exp_real = result.exp_value
# * success以外の場合、例外を投げるため、exp_valueがNoneになることはない
if not exp_real:
exp_real = 0.0
results.append(complex(exp_real, 0.0))
return results