supermarq.qcvv.base_experiment ============================== .. py:module:: supermarq.qcvv.base_experiment .. autoapi-nested-parse:: Base experiment class and tools used across all experiments. Attributes ---------- .. autoapisummary:: supermarq.qcvv.base_experiment.ResultsT Classes ------- .. autoapisummary:: supermarq.qcvv.base_experiment.QCVVExperiment supermarq.qcvv.base_experiment.QCVVResults supermarq.qcvv.base_experiment.Sample Functions --------- .. autoapisummary:: supermarq.qcvv.base_experiment.qcvv_resolver Module Contents --------------- .. py:class:: QCVVExperiment(qubits: int | collections.abc.Sequence[cirq.Qid], num_circuits: int, cycle_depths: collections.abc.Iterable[int], *, random_seed: int | numpy.random.Generator | None = None, results_cls: type[ResultsT], _samples: collections.abc.Sequence[Sample] | None = None, **kwargs: Any) Bases: :py:obj:`abc.ABC`, :py:obj:`Generic`\ [\ :py:obj:`ResultsT`\ ] Base class for gate benchmarking experiments. The interface for implementing these experiments is as follows: #. First instantiate the desired experiment object .. code:: experiment = ExampleExperiment(<>) #. Prepare the circuits and run the experiment on the desired target. This can either be a custom simulator or a real device name. For example: .. code:: noise_model = cirq.depolarize(p=0.01, n_qubits=1) sim = cirq.DensityMatrixSimulator(noise=noise_model) results = experiment.run_with_simulator(simulator=sim, <>) #. Then we analyse the results. If the target was a local simulator this will be available as soon as the :code:`run_with_simulator()` method has finished executing. On the other hand if a real device was accessed via Superstaq then it may take time for the data to be available from the server. The :code:`results.data_ready` attribute will return :code:`True` when all data has been collected and is ready to be analyzed. .. code:: if results.data_ready(): results.analyze(<>) When implementing a new experiment, 4 methods need to be implemented: #. :meth:`experiment._build_circuits()`: Given a number of circuits and an iterable of the different numbers of layers to use, return a list of :class:`Sample` objects that need to be sampled during the experiment. #. :meth:`results._analyse_results()`: Analyse the experimental data and store the final results, for example some fidelities. #. :meth:`results.plot_results()`: Produce any relevant plots that are useful for understanding the results of the experiment. #. :meth:`results.print_results()`: Prints the results to the console. .. py:method:: canonicalize_bitstring(key: int | str, num_qubits: int) -> str :staticmethod: Checks that the provided key represents a bit string for the given number of qubits. If the key is provided as an integer then this is reformatted as a bitstring. :param key: The integer or string which represents a bitstring. :param num_qubits: The number of bits that the bitstring needs to have :raises ValueError: If the key is integer and negative :raises ValueError: If the key is integer but to large for the given number of qubits. :raises ValueError: If the key is a string but the wrong length. :raises ValueError: If the key is a string but contains characters that are not 0 or 1. :raises TypeError: If the key value is not a string or integral. :returns: The canonicalized representation of the bitstring. .. py:method:: canonicalize_probabilities(results: collections.abc.Mapping[str, float] | collections.abc.Mapping[int, float], num_qubits: int) -> dict[str, float] :staticmethod: Reformats a dictionary of probabilities/counts so that all keys are bitstrings and that there are no missing values. Also renormalizes so that the resulting probabilities sum to 1 and sorts the dictionary by bitstring. :param results: The unformatted probabilities or counts :param num_qubits: The number of qubits, used to determine the bitstring length. :raises ValueError: If any counts or probabilities are negative. :raises ValueError: If there are no non-zero counts. :returns: The formatted dictionary of probabilities. .. py:method:: from_file(filename: str | pathlib.Path) -> Self :classmethod: Load the experiment from a json file. :param filename: Filename to load from. :returns: The loaded experiment. .. py:method:: results_from_records(records: _typeshed.SupportsItems[uuid.UUID | int, collections.abc.Mapping[str, float] | collections.abc.Mapping[int, float]]) -> ResultsT Creates a results object from records of the counts/probabilities for each sample circuit. This function is aimed at users who would like to use the QCVV framework to generate sample circuits and analyse the results but need to run these circuits without submitting a job to Superstaq. :param records: A dictionary of the counts/probabilities for each sample, keyed by either the sample UUID or the index of the sample in the experiment. The counts/probabilities for each sample should be provided as a dictionary of keyed by either the bitstring or the integer value of that bitstring. :returns: The experiment results object. .. py:method:: run_on_device(target: str, repetitions: int = 10000, method: str | None = None, **target_options: Any) -> ResultsT Submit the circuit samples to the desired target device and store the resulting probabilities. The set of circuits is partitioned as necessary to not exceed the maximum circuits that can be submitted to the given target device. The function then waits for the jobs to complete before saving the resulting probability distributions. :param target: The name of a Superstaq target. :param repetitions: The number of shots to sample. Defaults to 10,000. :param method: Optional method to use on the Superstaq device. Defaults to None corresponding to normal running. :param target_options: Optional configuration dictionary passed when submitting the job. :returns: The experiment results object. .. py:method:: run_with_callable(circuit_eval_func: collections.abc.Callable[[cirq.Circuit], collections.abc.Mapping[str, float] | collections.abc.Mapping[int, float]], **kwargs: Any) -> ResultsT Evaluates the probabilities for each circuit using a user provided callable function. This function should take a circuit as input and return a dictionary of probabilities for each bitstring (including states with zero probability). :param circuit_eval_func: The custom function to use when evaluating circuit probabilities. :param kwargs: Additional arguments to pass to the custom function. :returns: The experiment results object. .. py:method:: run_with_simulator(simulator: cirq.Sampler | None = None, repetitions: int = 10000) -> ResultsT Use the local simulator to sample the circuits and store the resulting probabilities. :param simulator: A local :class:`~cirq.Sampler` to use. If None then the default :class:`cirq.Simulator` simulator is used. Defaults to None. :param repetitions: The number of shots to sample. Defaults to 10,000. :returns: The experiment results object. .. py:method:: to_file(filename: str | pathlib.Path) -> None Save the experiment to a json file. :param filename: Filename to save to. .. py:property:: circuits :type: list[cirq.Circuit] All circuits in this experiment, as a list. .. py:attribute:: cycle_depths The different cycle depths to test at. .. py:attribute:: num_circuits The number of circuits to build for each cycle depth. .. py:property:: num_qubits :type: int The number of qubits used in the experiment. .. py:attribute:: qubits :type: tuple[cirq.Qid, Ellipsis] .. py:class:: QCVVResults Bases: :py:obj:`abc.ABC` A dataclass for storing the data and analyze results of the experiment. Requires subclassing for each new experiment type. .. py:method:: analyze(plot_results: bool = True, print_results: bool = True, plot_filename: str | None = None) -> None Perform the experiment analysis and store the results in the `results` attribute. :param plot_results: Whether to generate plots of the results. Defaults to True. :param print_results: Whether to print the final results. Defaults to True. :param plot_filename: Optional argument providing a filename to save the plots to. Ignored if `plot_results=False` Defaults to None, indicating not to save the plot. .. py:method:: plot_results(filename: str | None = None) -> matplotlib.pyplot.Figure :abstractmethod: Plot the results of the experiment. :param filename: Optional argument providing a filename to save the plots to. Defaults to None, indicating not to save the plot. :returns: A single matplotlib figure containing the relevant plots of the results data. .. py:method:: print_results() -> None :abstractmethod: Prints the key results data. .. py:attribute:: data :type: pandas.DataFrame | None :value: None The raw data generated. .. py:property:: data_ready :type: bool Whether the experimental data is ready to analyse. :raises RuntimeError: If their is no stored data and no Superstaq job to use to collect the results. .. py:attribute:: experiment :type: QCVVExperiment[QCVVResults] Reference to the underlying experiment that generated these results experiment. .. py:attribute:: job :type: cirq_superstaq.Job | None :value: None The associated Superstaq job (if applicable). .. py:property:: num_circuits :type: int Returns: The number of circuits in the experiment. .. py:property:: num_qubits :type: int Returns: The number of qubits in the experiment. .. py:property:: parent :type: Self .. py:property:: qubits :type: tuple[cirq.Qid, Ellipsis] .. py:property:: samples :type: collections.abc.Sequence[Sample] Returns: The number of samples used. .. py:attribute:: target :type: str The target device that was used. .. py:class:: Sample A sample circuit to use along with any data about the circuit that is needed for analysis. .. py:attribute:: circuit :type: cirq.Circuit The raw (i.e. pre-compiled) sample circuit. .. py:attribute:: circuit_realization :type: int Indicates which realization of the random circuit this sample is. There will be D samples with matching circuit realization value, one for each cycle depth being measured. This index is useful for grouping results during analysis. .. py:attribute:: data :type: dict[str, Any] The corresponding data about the circuit that is needed when analyzing results (e.g. cycle depth). .. py:attribute:: uuid :type: Sample.uuid The unique ID of the sample. .. py:function:: qcvv_resolver(cirq_type: str) -> type[Any] | None Resolves string's referencing classes in the QCVV library. Used by `cirq.read_json()` to deserialize. :param cirq_type: The type being resolved :returns: The corresponding type object (if found) else None :raises ValueError: If the provided type is not resolvable .. py:data:: ResultsT