"""SamplingExecuter - Experiment (:mod:`qurry.qurries.samplingqurry.experiment`)
It is only for pendings and retrieve to remote backend.
"""
from typing import Union, Optional, Type, Any
from collections.abc import Hashable
import tqdm
from qiskit import QuantumCircuit
from .arguments import QurryArguments, SHORT_NAME
from .analysis import QurryAnalysis
from ...qurrium import ExperimentPrototype, Commonparams
from ...exceptions import QurryExperimentCountsNotCompleted
[docs]
class QurryExperiment(ExperimentPrototype[QurryArguments, QurryAnalysis]):
"""Experiment instance for QurryV9."""
__name__ = "QurryExperiment"
@property
def arguments_instance(self) -> Type[QurryArguments]:
"""The arguments instance for this experiment."""
return QurryArguments
@property
def analysis_instance(self) -> Type[QurryAnalysis]:
"""The analysis instance for this experiment."""
return QurryAnalysis
[docs]
@classmethod
def params_control(
cls,
targets: list[tuple[Hashable, QuantumCircuit]],
exp_name: str = "exps",
sampling: int = 1,
**custom_kwargs: Any,
) -> tuple[QurryArguments, Commonparams, dict[str, Any]]:
"""Control the experiment's parameters.
Args:
targets (list[tuple[Hashable, QuantumCircuit]]):
The circuits of the experiment.
exp_name (str):
The name of the experiment. Defaults to "exps".
sampling (int, optional):
The number of sampling. Defaults to 1.
custom_kwargs (Any):
The custom parameters.
Raises:
ValueError: The number of target circuits should be only one.
Returns:
tuple[QurryArguments, Commonparams, dict[str, Any]]:
The arguments of the experiment, the common parameters, and the custom parameters
"""
if len(targets) != 1:
raise ValueError("The number of target circuits should be only one.")
exp_name = f"{exp_name}.times_{sampling}.{SHORT_NAME}"
# pylint: disable=protected-access
return QurryArguments._filter(
exp_name=exp_name,
target_keys=[targets[0][0]],
sampling=sampling,
**custom_kwargs,
)
# pylint: enable=protected-access
[docs]
@classmethod
def method(
cls,
targets: list[tuple[Hashable, QuantumCircuit]],
arguments: QurryArguments,
pbar: Optional[tqdm.tqdm] = None,
multiprocess: bool = True,
) -> tuple[list[QuantumCircuit], dict[str, Any]]:
"""The method to construct circuit.
Args:
targets (list[tuple[Hashable, QuantumCircuit]]):
The circuits of the experiment.
arugments (ArgumentsPrototype):
The arguments of the experiment.
pbar (Optional[tqdm.tqdm], optional):
The progress bar for showing the progress of the experiment.
Defaults to None.
multiprocess (bool, optional):
Whether to use multiprocess. Defaults to `True`.
Returns:
tuple[list[QuantumCircuit], dict[str, Any]]:
The circuits of the experiment and the side products.
"""
if pbar is not None:
pbar.set_description("| Loading circuits")
the_chosen_key, q = targets[0]
the_chosen_key = "" if isinstance(the_chosen_key, int) else str(the_chosen_key)
old_name = "" if isinstance(q.name, str) else q.name
old_name = "" if len(old_name) < 1 else old_name
q_copy = q.copy()
if len(q_copy.cregs) < 1:
raise ValueError(
"| No classical register in the given circuits, counts will be empty. "
+ "Please add classical register to the circuit. "
+ "(Don't be frustrated, I did the same thing on unit test. "
+ "It made me confused and thought what's wrong for a while before ('_').)"
)
q_copy.name = ".".join(
[n for n in [arguments.exp_name, the_chosen_key, old_name] if len(n) > 0]
)
return [q_copy.copy() for _ in range(arguments.sampling)], {}
[docs]
@classmethod
def quantities(
cls,
shots: Optional[int] = None,
counts: Optional[list[dict[str, int]]] = None,
) -> dict[str, Union[float, int]]:
"""Computing specific squantity.
Args:
shots (Optional[int], optional):
The number of shots.
counts (Optional[list[dict[str, int]]], optional):
The counts of the experiment.
Returns:
dict[str, Union[float, int]]: Counts, purity, entropy of experiment.
"""
if shots is None or counts is None:
print(
"| shots or counts is None, "
+ "but it doesn't matter with ultimate question over all."
)
dummy = -100
return {
"dummy": dummy,
"ultimate_answer": 42,
}
[docs]
def analyze(
self,
ultimate_question: str = "",
shots: Optional[int] = None,
pbar: Optional[tqdm.tqdm] = None,
) -> QurryAnalysis:
"""Analysis of the experiment.
Args:
ultimate_question (str, optional):
The ultimate question of the universe.
shots (Optional[int], optional):
The number of shots.
pbar (Optional[tqdm.tqdm], optional):
The progress bar for showing the progress of the experiment.
Defaults to None.
Returns:
QurryAnalysis: The analysis of the experiment.
"""
if pbar is not None:
pbar.set_description("What is the ultimate question of the universe?")
if shots is None:
shots = self.commons.shots
if len(self.afterwards.counts) < 1:
raise QurryExperimentCountsNotCompleted(
"The counts of the experiment is not completed. So there is no data to analyze."
)
qs = self.quantities(shots=shots, counts=self.afterwards.counts)
serial = len(self.reports)
analysis = self.analysis_instance(
ultimate_question=ultimate_question,
serial=serial,
**qs, # type: ignore
)
self.reports[serial] = analysis
return analysis