diff --git a/qiskit/evaluators/__init__.py b/qiskit/evaluators/__init__.py new file mode 100644 index 000000000000..cc834119ece4 --- /dev/null +++ b/qiskit/evaluators/__init__.py @@ -0,0 +1,20 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Evaluators (:mod:`qiskit.evaluators`) +========================================== +It contains evaluator primitives. +""" + +from .expectation_value import ExactExpectationValue, PauliExpectationValue +from .framework import HistoryEvaluator, JointEvaluator diff --git a/qiskit/evaluators/backends/__init__.py b/qiskit/evaluators/backends/__init__.py new file mode 100644 index 000000000000..93f9fde5f152 --- /dev/null +++ b/qiskit/evaluators/backends/__init__.py @@ -0,0 +1,18 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Backend wrapper classes +""" + +from .backend_wrapper import BackendWrapper, BaseBackendWrapper, ReadoutErrorMitigation, Retry +from .shot_backend_wrapper import ShotBackendWrapper, ShotResult diff --git a/qiskit/evaluators/backends/backend_wrapper.py b/qiskit/evaluators/backends/backend_wrapper.py new file mode 100644 index 000000000000..bb9764835028 --- /dev/null +++ b/qiskit/evaluators/backends/backend_wrapper.py @@ -0,0 +1,356 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Backend wrapper classes +""" + +from __future__ import annotations + +import logging +from abc import ABC, abstractmethod +from datetime import datetime, timedelta +from typing import TYPE_CHECKING, Generic, TypeVar, Union + +from qiskit.circuit import QuantumCircuit +from qiskit.exceptions import MissingOptionalLibraryError +from qiskit.providers.backend import BackendV1 +from qiskit.result import Counts, Result + +logger = logging.getLogger(__name__) + +if TYPE_CHECKING: + from .shot_backend_wrapper import ShotBackendWrapper + +T = TypeVar("T") # pylint: disable=invalid-name + + +class BaseBackendWrapper(ABC, Generic[T]): + """ + TODO + """ + + @abstractmethod + def run_and_wait(self, circuits: Union[QuantumCircuit, list[QuantumCircuit]], **options) -> T: + """ + TODO + """ + return NotImplemented + + @property + @abstractmethod + def backend(self) -> BackendV1: + """ + TODO + """ + return NotImplemented + + +class BackendWrapper(BaseBackendWrapper[Result]): + """ + TODO + """ + + def __init__(self, backend: BackendV1): + """ + TODO + """ + self._backend = backend + + @property + def backend(self) -> BackendV1: + """ + TODO + """ + return self._backend + + def run_and_wait( + self, circuits: Union[QuantumCircuit, list[QuantumCircuit]], **options + ) -> Result: + """ + TODO + """ + job = self._backend.run(circuits, **options) + return job.result() + + @classmethod + def from_backend(cls, backend: Union[BackendV1, BaseBackendWrapper]) -> BaseBackendWrapper: + """ + TODO + """ + if isinstance(backend, BackendV1): + return cls(backend) + return backend + + @staticmethod + def to_backend(backend: Union[BackendV1, BaseBackendWrapper, ShotBackendWrapper]) -> BackendV1: + """ + TODO + """ + if isinstance(backend, BackendV1): + return backend + return backend.backend + + +class Retry(BaseBackendWrapper): + """ + TODO + """ + + def __init__(self, backend: BackendV1): + """ + TODO + """ + self._backend = backend + + @property + def backend(self): + """ + TODO + """ + return self._backend + + @staticmethod + def _get_result(job): + """Get a result of a job. Will retry when ``IBMQJobApiError`` (i.e., network error) + + ``IBMQJob.result`` raises the following errors. + - IBMQJobInvalidStateError: If the job was cancelled. + - IBMQJobFailureError: If the job failed. + - IBMQJobApiError: If an unexpected error occurred when communicating with the server. + """ + try: + from qiskit.providers.ibmq.job import IBMQJobApiError + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="qiskit-ibmq-provider", + name="IBMQ Provider", + pip_install="pip install qiskit-ibmq-provider", + ) from ex + + while True: + try: + return job.result() + except IBMQJobApiError as ex: # network error, will retry to get a result + logger.warning(ex.message) + + def run_and_wait( + self, circuits: Union[QuantumCircuit, list[QuantumCircuit]], **options + ) -> Result: + """ + TODO + """ + try: + from qiskit.providers.ibmq.job import IBMQJobFailureError, IBMQJobInvalidStateError + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="qiskit-ibmq-provider", + name="IBMQ Provider", + pip_install="pip install qiskit-ibmq-provider", + ) from ex + + while True: + job = self._backend.run(circuits, **options) + try: + result = self._get_result(job) + except IBMQJobInvalidStateError as ex: # cancelled, will retry to submit a job + logger.warning(ex.message) + logger.info("Job was cancelled %s. Retry another job.", job.job_id()) + continue + except IBMQJobFailureError as ex: # job failed, will terminate + logger.warning(ex.message) + raise ex + + if result.success: + return result + else: + logger.warning("job finished unsuccessfully %s", job.job_id()) + + +class ReadoutErrorMitigation(BaseBackendWrapper): + """ + TODO + """ + + # need to move to the new mitigator class in the future + # https://github.com/Qiskit/qiskit-terra/pull/6485 + # need to support M3 https://github.com/Qiskit-Partners/mthree + # need to use Terra's error mitigation after merge of + # https://github.com/Qiskit/qiskit-terra/pull/6867 + def __init__( + self, + backend: Union[BackendV1, BaseBackendWrapper], + mitigation: str, + refresh: float, + shots: int, + **cal_options, + ): + """ + TODO + """ + self._backend = BackendWrapper.from_backend(backend) + self._mitigation = mitigation + self._refresh = timedelta(seconds=refresh) + self._shots = shots + self._time_threshold = datetime.fromordinal(1) + self._cal_options = cal_options + + try: + from qiskit.ignis.mitigation.measurement import CompleteMeasFitter, TensoredMeasFitter + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="qiskit-ignis", + name="execute", + pip_install="pip install qiskit-ignis", + ) from ex + try: + from mthree import M3Mitigation + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="mthree", + name="execute", + pip_install="pip install mthree", + ) from ex + self._meas_fitter: dict[ + datetime, Union[CompleteMeasFitter, TensoredMeasFitter, M3Mitigation] + ] = {} + + @property + def backend(self): + """ + TODO + """ + if isinstance(self._backend, BaseBackendWrapper): + return self._backend.backend + return self._backend + + @property + def mitigation(self): + """ + TODO + """ + return self._mitigation + + @property + def refresh(self): + """ + TODO + """ + return self._refresh + + @property + def cal_options(self): + """ + TODO + """ + return self._cal_options + + @property + def shots(self): + """ + TODO + """ + return self._shots + + @staticmethod + def _datetime(data): + """ + TODO + """ + # Aer's result.data is str, but IBMQ's result.data is datetime + if isinstance(data, str): + return datetime.fromisoformat(data) + return data + + def _maybe_calibrate(self): + now = datetime.now() + if now <= self._time_threshold: + return + logger.info("readout error mitigation calibration %s at %s", self._mitigation, now) + if self._mitigation == "tensored": + try: + from qiskit.ignis.mitigation.measurement import ( + TensoredMeasFitter, + tensored_meas_cal, + ) + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="qiskit-ignis", + name="execute", + pip_install="pip install qiskit-ignis", + ) from ex + meas_calibs, state_labels = tensored_meas_cal(**self._cal_options) + cal_results = self._backend.run_and_wait(meas_calibs, shots=self._shots) + self._meas_fitter[now] = TensoredMeasFitter(cal_results, **self._cal_options) + elif self._mitigation == "complete": + try: + from qiskit.ignis.mitigation.measurement import ( + CompleteMeasFitter, + complete_meas_cal, + ) + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="qiskit-ignis", + name="execute", + pip_install="pip install qiskit-ignis", + ) from ex + meas_calibs, state_labels = complete_meas_cal(**self._cal_options) + cal_results = self._backend.run_and_wait(meas_calibs, shots=self._shots) + self._meas_fitter[now] = CompleteMeasFitter( + cal_results, state_labels, **self._cal_options + ) + elif self._mitigation == "mthree": + try: + from mthree import M3Mitigation + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="mthree", + name="execute", + pip_install="pip install mthree", + ) from ex + mit = M3Mitigation(self._backend.backend) + mit.cals_from_system(shots=self._shots, **self._cal_options) + self._meas_fitter[now] = mit + self._time_threshold = now + self._refresh + + def _apply_mitigation(self, result: Result) -> list[Counts]: + result_dt = self._datetime(result.date) + fitters = [ + (abs(date - result_dt), date, fitter) for date, fitter in self._meas_fitter.items() + ] + _, min_date, min_fitter = min(fitters, key=lambda e: e[0]) + logger.info("apply mitigation data at %s", min_date) + if self._mitigation in ["complete", "tensored"]: + return min_fitter.filter.apply(result).get_counts() + else: + counts = result.get_counts() + quasis = min_fitter.apply_correction(counts, self._cal_options["qubits"]) + ret = [] + for quasi, shots in zip(quasis, quasis.shots): + ret.append(Counts({key: val * shots for key, val in quasi.items()})) + return ret + + def apply_mitigation(self, results: list[Result]) -> list[list[Counts]]: + """ + TODO + """ + return [self._apply_mitigation(result) for result in results] + + def run_and_wait( + self, circuits: Union[QuantumCircuit, list[QuantumCircuit]], **options + ) -> Result: + """ + TODO + """ + self._maybe_calibrate() + result = self._backend.run_and_wait(circuits, **options) + self._maybe_calibrate() + return result diff --git a/qiskit/evaluators/backends/shot_backend_wrapper.py b/qiskit/evaluators/backends/shot_backend_wrapper.py new file mode 100644 index 000000000000..70679ef26ed4 --- /dev/null +++ b/qiskit/evaluators/backends/shot_backend_wrapper.py @@ -0,0 +1,247 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Shot Backend wrapper class +""" + +from __future__ import annotations + +import logging +from collections import Counter +from dataclasses import dataclass +from typing import Union + +from qiskit.circuit import QuantumCircuit +from qiskit.exceptions import MissingOptionalLibraryError, QiskitError +from qiskit.providers.backend import BackendV1 +from qiskit.result import Counts, Result + +from .backend_wrapper import ( + BackendWrapper, + BaseBackendWrapper, + ReadoutErrorMitigation, +) + +logger = logging.getLogger(__name__) + + +@dataclass +class ShotResult: + """ + Dataclass for shot results + """ + + counts: list[Counts] + shots: int + raw_results: list[Result] + metadata: list[dict] + + def __getitem__(self, key): + return ShotResult(self.counts[key], self.shots, self.raw_results, self.metadata[key]) + + +class ShotBackendWrapper(BaseBackendWrapper[ShotResult]): + """Backend wrapper to return a list of counts""" + + def __init__(self, backend: Union[BackendV1, BaseBackendWrapper]): + self._backend = BackendWrapper.from_backend(backend) + + config = self._backend.backend.configuration() + self._max_shots = config.max_shots + if hasattr(config, "max_experiments"): + self._max_experiments = config.max_experiments + else: + self._max_experiments = 1 if self.is_aer(self._backend.backend) else 1_000_000 + logger.info( + "no max_experiments for backend '%s'. Set %d as max_experiments.", + self._backend.backend.name(), + self._max_experiments, + ) + self._num_circuits = 0 + self._num_splits = 0 + self._raw_results: list[Result] = [] + + @staticmethod + def is_aer(backend: BackendV1): + """ + Returns True if the backend is a subclass of AerProvider. + """ + try: + from qiskit.providers.aer import AerProvider + + return isinstance(backend.provider(), AerProvider) + except ImportError as ex: + raise MissingOptionalLibraryError( + libname="qiskit-aer", + name="Qiskit Aer", + pip_install="pip install qiskit-aer", + ) from ex + + @property + def backend(self) -> BackendV1: + """ + TODO + + Returns: + backend + """ + return self._backend.backend + + @property + def max_shots(self) -> int: + """ + TODO + + Returns: + max_shots + """ + return self._max_shots + + @property + def max_experiments(self) -> int: + """ + TODO + + Returns: + max_experiments + """ + return self._max_experiments + + @staticmethod + def from_backend( + backend: Union[BackendV1, BaseBackendWrapper, ShotBackendWrapper] + ) -> ShotBackendWrapper: + """ + Backend to ShotBackendWrapper + + Returns: + wrapped backend + """ + if isinstance(backend, (BackendV1, BaseBackendWrapper)): + return ShotBackendWrapper(backend) + return backend + + def _split_experiments( + self, circuits: list[QuantumCircuit], shots: int + ) -> list[tuple[list[QuantumCircuit], int]]: + assert self._num_circuits > self._max_experiments + ret = [] + remaining_shots = shots + splits = [] + for i in range(0, self._num_circuits, self._max_experiments): + splits.append(circuits[i : min(i + self._max_experiments, self._num_circuits)]) + self._num_splits = len(splits) + logger.info("Number of circuits %d, Number of splits: %d", len(circuits), self._num_splits) + while remaining_shots > 0: + shots = min(remaining_shots, self._max_shots) + remaining_shots -= shots + for circs in splits: + ret.append((circs, shots)) + return ret + + def _copy_experiments( + self, circuits: list[QuantumCircuit], shots: int, exact: bool + ) -> list[tuple[list[QuantumCircuit], int]]: + assert self._num_circuits <= self._max_experiments + max_copies = self._max_experiments // self._num_circuits + ret = [] + remaining_shots = shots + while remaining_shots > 0: + num_copies, rem = divmod(remaining_shots, self._max_shots) + if rem: + num_copies += 1 + num_copies = min(num_copies, max_copies) + + shots, rem = divmod(remaining_shots, num_copies) + if rem and not exact: + shots += 1 + shots = min(shots, self._max_shots) + logger.info( + "Number of circuits %d, number of shots: %d, number of copies: %d, " + "total number of shots: %d", + len(circuits), + shots, + num_copies, + shots * num_copies, + ) + remaining_shots -= shots * num_copies + ret.append((circuits * num_copies, shots)) + return ret + + # pylint: disable=arguments-differ + def run_and_wait( + self, + circuits: Union[QuantumCircuit, list[QuantumCircuit]], + append: bool = False, + exact_shots: bool = False, + **options, + ) -> ShotResult: + """ + TODO + + Returns: + list of counts + """ + if "shots" in options: + shots = options["shots"] + del options["shots"] + else: + shots = self._backend.backend.options.shots + if isinstance(circuits, QuantumCircuit): + circuits = [circuits] + self._num_circuits = len(circuits) + if self._num_circuits > self._max_experiments: + circs_shots = self._split_experiments(circuits, shots) + else: + circs_shots = self._copy_experiments(circuits, shots, exact_shots) + results = [] + for circs, shots in circs_shots: + result = self._backend.run_and_wait(circs, shots=shots, **options) + results.append(result) + if append: + self._raw_results.extend(results) + else: + self._raw_results = results + counts = self._get_counts(self._raw_results) + metadata = [res.header.metadata for result in results for res in result.results] + return ShotResult( + counts=counts, + shots=int(sum(counts[0].values())), + raw_results=self._raw_results, + metadata=metadata, + ) + + def _get_counts(self, results: list[Result]) -> list[Counts]: + """ + Convert Result to Counts + + Returns: + list of counts + Raises: + QiskitError: if inputs are empty + """ + if len(results) == 0: + raise QiskitError("Empty result") + if isinstance(self._backend, ReadoutErrorMitigation): + list_counts = self._backend.apply_mitigation(results) + else: + list_counts = [result.get_counts() for result in results] + counters: list[Counter] = [Counter() for _ in range(self._num_circuits)] + i = 0 + for counts in list_counts: + if isinstance(counts, Counts): + counts = [counts] + for count in counts: + counters[i % self._num_circuits].update(count) + i += 1 + # TODO: recover the metadata of Counts + return [Counts(c) for c in counters] diff --git a/qiskit/evaluators/expectation_value.ipynb b/qiskit/evaluators/expectation_value.ipynb new file mode 100644 index 000000000000..0b044273e611 --- /dev/null +++ b/qiskit/evaluators/expectation_value.ipynb @@ -0,0 +1,1016 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "21e62c44", + "metadata": {}, + "source": [ + "# New expectation value design PoC\n", + "\n", + "Takashi Imamichi and Ikko Hamamura (IBM Research - Tokyo)" + ] + }, + { + "cell_type": "markdown", + "id": "a02345fd", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "We propose a new design of the expectation value to make it generic and simple.\n", + "Essentially, we aim at the following workflow.\n", + "\n", + "```python\n", + "operator = ...\n", + "state = ...\n", + "backend = ...\n", + "expval = PauliExpectationValue(state, operator, backend)\n", + "result = expval.evaluate(parameters).value\n", + "```\n", + "\n", + "- `state` $\\psi(\\theta)$: a (parametrized) quantum circuit or a state vector to be converted into a quantum circuit.\n", + "- `observable` $H$: for simplicity, we allow opflow `PauliSumOp` (primitive is `SparsePauliOp`) or quantum_info operator `BaseOperator` that is compatible with `SparsePauliOp`.\n", + "- `backend`: Either `IBMQBackend` or `AerSimulator`. We don't support legacy simulator backends and BasicAer.\n", + "- (optional) `expval`: take an expectation value object as an input (e.g., gradient)\n", + "\n", + "`ExpectationValue.evaluate(parameters)` computes the expectation value $f(\\theta) = \\langle \\psi(\\theta) | H | \\psi(\\theta) \\rangle$ and other information (e.g., variance and confidence interval).\n", + "\n", + "`ExpectationValueGradient` may have the same interface and/or it may take `ExpectationValue` object as an input of the constructor." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "05da73c4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "id": "cdf67779", + "metadata": {}, + "source": [ + "# ExpectationValue" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "fc97bb99", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6104c3e9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "observable\n", + "-1.052373245772859 * II\n", + "+ 0.39793742484318045 * IZ\n", + "- 0.39793742484318045 * ZI\n", + "- 0.01128010425623538 * ZZ\n", + "+ 0.18093119978423156 * XX\n", + "\n", + "ansatz\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.circuit.library import RealAmplitudes\n", + "from qiskit.opflow import PauliSumOp\n", + "\n", + "observable = PauliSumOp.from_list(\n", + " [\n", + " (\"II\", -1.052373245772859),\n", + " (\"IZ\", 0.39793742484318045),\n", + " (\"ZI\", -0.39793742484318045),\n", + " (\"ZZ\", -0.01128010425623538),\n", + " (\"XX\", 0.18093119978423156),\n", + " ]\n", + ")\n", + "print(\"observable\")\n", + "print(observable)\n", + "\n", + "ansatz = RealAmplitudes(num_qubits=2, reps=2)\n", + "print(\"\\nansatz\")\n", + "ansatz.decompose().draw(\"mpl\")" + ] + }, + { + "cell_type": "markdown", + "id": "cbe27065", + "metadata": {}, + "source": [ + "### Exact expectation value using quantum_info" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ce866e21", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-1.284366511861733\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/aa406165/Git/qiskit-core/qiskit/quantum_info/states/statevector.py:444: DeprecationWarning: The SparsePauliOp.table method is deprecated as of Qiskit Terra 0.19.0 and will be removed no sooner than 3 months after the releasedate. Use SparsePauliOp.paulis method instead.\n", + " for z, x, coeff in zip(oper.table.Z, oper.table.X, oper.coeffs)\n" + ] + } + ], + "source": [ + "from qiskit.quantum_info import Statevector\n", + "\n", + "expval = Statevector(ansatz.bind_parameters([0, 1, 1, 2, 3, 5])).expectation_value(\n", + " observable.primitive\n", + ")\n", + "print(expval.real)" + ] + }, + { + "cell_type": "markdown", + "id": "3e5bc903", + "metadata": {}, + "source": [ + "## ExpectationValue class" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2dd0c134", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators import PauliExpectationValue" + ] + }, + { + "cell_type": "markdown", + "id": "01eba673", + "metadata": {}, + "source": [ + "### PauliExpectationValue\n", + "\n", + "Evaluate the expectation value by sampling. This supports both AerSimulator and IBMQ backends." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "578ae95d", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.providers.aer import AerSimulator\n", + "\n", + "backend = AerSimulator()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "624c2fc9", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.3155116621124823, variance=0.29351152286009907, confidence_interval=(-1.3439249612660715, -1.287098362958893))" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5], shos=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "49e070be", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2980371675962386, variance=0.293189378374092, confidence_interval=(-1.3264434169544754, -1.2696309182380017))" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# pre-binding\n", + "\n", + "circuit = ansatz.bind_parameters([0, 1, 1, 2, 3, 5])\n", + "expval = PauliExpectationValue(circuit, observable, backend=backend)\n", + "expval.evaluate()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "18535167", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueArrayResult(values=array([-1.28387502, -1.31399092]), variances=array([0.30387294, 0.24376268]), confidence_intervals=array([[-1.30076671, -1.26698334],\n", + " [-1.32875942, -1.29922242]]))" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# multi prameters\n", + "\n", + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate([[0, 1, 1, 2, 3, 5], [1, 1, 2, 3, 5, 8]], shots=3000)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "18ed7ddc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueArrayResult(values=array([-1.28985523, -1.31340026]), variances=array([0.29882166, 0.24406568]), confidence_intervals=array([[-1.29999462, -1.27971584],\n", + " [-1.32234687, -1.30445365]]))" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# can pass ndarray\n", + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate(np.array([[0, 1, 1, 2, 3, 5], [1, 1, 2, 3, 5, 8]]), shots=8192)" + ] + }, + { + "cell_type": "markdown", + "id": "257787d2", + "metadata": {}, + "source": [ + "### Exact simulation by SaveExpectationValueVariance" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "e602573e", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators import ExactExpectationValue" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a795bd78", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2843665118617325, variance=0.26528532962023577, confidence_interval=None)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = ExactExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "60687fe8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueArrayResult(values=array([-1.28436651, -1.31875263]), variances=array([0.26528533, 0.42691205]), confidence_intervals=array([None, None], dtype=object))" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = ExactExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate(np.array([[0, 1, 1, 2, 3, 5], [1, 1, 2, 3, 5, 8]]))" + ] + }, + { + "cell_type": "markdown", + "id": "1c94c403", + "metadata": {}, + "source": [ + "### Transpiled Circuits" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "3e1a8842", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ExpectationValueResult(value=-1.208969308596756, variance=0.3276914483078654, confidence_interval=(-1.238955981214919, -1.1789826359785933))\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.test.mock import FakeBogota\n", + "\n", + "backend = AerSimulator.from_backend(FakeBogota())\n", + "\n", + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.set_transpile_options(initial_layout=[3, 2])\n", + "print(expval.evaluate([0, 1, 1, 2, 3, 5]))\n", + "expval.transpiled_circuits[0].draw(\"mpl\")" + ] + }, + { + "cell_type": "markdown", + "id": "82a30637", + "metadata": {}, + "source": [ + "### Transpile options and Run options" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "b663b5ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2588282578099466, variance=0.31364082101353796, confidence_interval=(-1.261800109915621, -1.255856405704272))" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "# setter\n", + "expval.set_transpile_options(optimization_level=2)\n", + "expval.set_run_options(shots=100_000)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5])" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "2d5b5c32", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2611514338961236, variance=0.3121522615616594, confidence_interval=(-1.271511452685065, -1.2507914151071822))" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Method chain\n", + "expval.set_run_options(shots=8192).evaluate([0, 1, 1, 2, 3, 5])" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "45d115db", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2635998440984424, variance=0.3147367359575875, confidence_interval=(-1.3179405209467956, -1.2092591672500892))" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# evaluate's option\n", + "expval.evaluate([0, 1, 1, 2, 3, 5], shots=300)" + ] + }, + { + "cell_type": "markdown", + "id": "ec7791bb", + "metadata": {}, + "source": [ + "### Composite Evaluator" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "60e1deaa", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators import JointEvaluator" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "c7bff8ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(expval.transpiled_circuits)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "c2b25c81", + "metadata": {}, + "outputs": [], + "source": [ + "joint_evaluator = JointEvaluator(\n", + " [expval, expval, expval]\n", + ") # can be different evaluators" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "43412a24", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(joint_evaluator.transpiled_circuits) # 5 × 3" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "cf8466ff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "CompositeResult(items=[ExpectationValueResult(value=-1.2676419951102753, variance=0.3140277746649887, confidence_interval=(-1.2970349136340102, -1.2382490765865404)), ExpectationValueResult(value=-1.2676419951102753, variance=0.3140277746649887, confidence_interval=(-1.2970349136340102, -1.2382490765865404)), ExpectationValueResult(value=-1.2676419951102753, variance=0.3140277746649887, confidence_interval=(-1.2970349136340102, -1.2382490765865404))])" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "joint_evaluator.evaluate([[0, 1, 1, 2, 3, 5], [1, 1, 2, 3, 5, 8], [1, 2, 3, 5, 8, 13]])" + ] + }, + { + "cell_type": "markdown", + "id": "9185b9ae", + "metadata": {}, + "source": [ + "### Large number of shots" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "620b76bb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "max_shots 8192\n", + "Number of shots specified: 10000 exceeds max_shots property of the backend: 8192.\n" + ] + } + ], + "source": [ + "try:\n", + " from qiskit import QiskitError, QuantumCircuit\n", + "\n", + " qc = QuantumCircuit(1, 1)\n", + " qc.h(0)\n", + " qc.measure(0, 0)\n", + " from qiskit import IBMQ\n", + "\n", + " prov = IBMQ.load_account()\n", + " ibmq_qasm_sim = prov.get_backend(\"ibmq_qasm_simulator\")\n", + " print(f\"max_shots {backend.configuration().max_shots}\")\n", + " ibmq_qasm_sim.run(qc, shots=10000).result().get_counts()\n", + "except QiskitError as ex:\n", + " print(ex.message)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "9cb73555", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2841014508669142, variance=0.3001270329625955, confidence_interval=(-1.2932986115415759, -1.2749042901922525))" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = PauliExpectationValue(ansatz, observable, backend=ibmq_qasm_sim)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5], shots=10000)" + ] + }, + { + "cell_type": "markdown", + "id": "88234028", + "metadata": {}, + "source": [ + "### Readout error mitigation" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "c992bb1f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "w/o mitigation shots=4000, result=ExpectationValueResult(value=-1.2584498578829133, variance=0.3129770743816941, confidence_interval=(-1.273294109935479, -1.2436056058303475))\n", + "w/ tensored mitigation shots=4000, result=ExpectationValueResult(value=-1.2896337126825879, variance=0.3040081286375543, confidence_interval=(-1.3042704592106231, -1.2749969661545526))\n", + "w/ M3 mitigation shots=4000, result=ExpectationValueResult(value=-1.285562853844149, variance=0.30684023527137716, confidence_interval=(-1.3002648125049854, -1.2708608951833127))\n" + ] + } + ], + "source": [ + "from qiskit.evaluators.backends import ReadoutErrorMitigation\n", + "\n", + "backend = AerSimulator.from_backend(FakeBogota())\n", + "mit_tensored = ReadoutErrorMitigation(\n", + " backend, mitigation=\"tensored\", refresh=600, shots=2000, mit_pattern=[[0], [1]]\n", + ")\n", + "mit_mthree = ReadoutErrorMitigation(\n", + " backend, mitigation=\"mthree\", refresh=600, shots=2000, qubits=[0, 1]\n", + ")\n", + "expval_raw = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval_tensored = PauliExpectationValue(ansatz, observable, backend=mit_tensored)\n", + "expval_mthree = PauliExpectationValue(ansatz, observable, backend=mit_mthree)\n", + "shots = 4000\n", + "print(\n", + " f\"w/o mitigation shots={shots}, result={expval_raw.evaluate([0, 1, 1, 2, 3, 5], shots=shots)}\"\n", + ")\n", + "print(\n", + " f\"w/ tensored mitigation shots={shots}, result={expval_tensored.evaluate([0, 1, 1, 2, 3, 5], shots=shots)}\"\n", + ")\n", + "print(\n", + " f\"w/ M3 mitigation shots={shots}, result={expval_mthree.evaluate([0, 1, 1, 2, 3, 5], shots=shots)}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ce3810ee", + "metadata": {}, + "source": [ + "### Gradient of expectation value for simple cases" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "3070586b", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators.expectation_value import (\n", + " FiniteDiffGradient,\n", + " ParameterShiftGradient,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "06c9d4ac", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fin diff of exact [ 0.28213347 0.42656751 0.20442583 0.42656749 -0.17291453 0.0589814 ]\n", + "param shift of exact [ 0.28213349 0.42656754 0.20442588 0.42656754 -0.17291452 0.05898141]\n", + "fin diff w/o mit [ 0.48224909 0.34955732 0.48872711 0.34560585 -0.07533641 -0.2590175 ]\n", + "param shift w/o mit [ 0.23356077 0.38077996 0.18163219 0.38573547 -0.13631766 0.08069058]\n", + "fin diff w/ mit [ 0.2821584 0.53273375 0.28362032 0.44092049 -0.17398857 -0.0261243 ]\n", + "param shift w/ mit [ 0.2586877 0.41629731 0.20081363 0.40798981 -0.16167768 0.04086822]\n" + ] + } + ], + "source": [ + "parameters = [0, 1, 1, 2, 3, 5]\n", + "\n", + "exact_expval = ExactExpectationValue(ansatz, observable, backend=AerSimulator())\n", + "exact_findiff = FiniteDiffGradient(exact_expval, 1e-8)\n", + "print(f\"fin diff of exact {exact_findiff.evaluate(parameters).values}\")\n", + "\n", + "exact_expval = ExactExpectationValue(ansatz, observable, backend=AerSimulator())\n", + "exact_findiff = ParameterShiftGradient(exact_expval)\n", + "print(f\"param shift of exact {exact_findiff.evaluate([0, 1, 1, 2, 3, 5]).values}\")\n", + "\n", + "shots = 2000\n", + "findiff = FiniteDiffGradient(expval_raw, 1e-1)\n", + "paramshift = ParameterShiftGradient(expval_raw)\n", + "print(f\"fin diff w/o mit {findiff.evaluate(parameters, shots=shots).values}\")\n", + "print(f\"param shift w/o mit {paramshift.evaluate(parameters, shots=shots).values}\")\n", + "\n", + "findiff = FiniteDiffGradient(expval_mthree, 1e-1)\n", + "paramshift = ParameterShiftGradient(expval_mthree)\n", + "print(f\"fin diff w/ mit {findiff.evaluate([0, 1, 1, 2, 3, 5], shots=shots).values}\")\n", + "print(f\"param shift w/ mit {paramshift.evaluate(parameters, shots=shots).values}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f05981d1", + "metadata": {}, + "source": [ + "### Opflow-based gradient for complicated cases" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "1af01f52", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "observable\n", + "-1.052373245772859 * II\n", + "+ 0.39793742484318045 * IZ\n", + "- 0.39793742484318045 * ZI\n", + "- 0.01128010425623538 * ZZ\n", + "+ 0.18093119978423156 * XX\n", + "\n", + "ansatz\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAB7CAYAAAAossl+AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAhb0lEQVR4nO3de1xUdf7H8dfMAIKgApKiqCgCuqIiKpqIgmlqrmv6K03FinKz0MpLdtlVW1tbLdc2a/NamVvrpTLXW3bREhTF0lQUNfFGinjBCyLIfeb3xyTKbQbkMOcMfp6PB4/knMP3vPl0hvnMuepMJpMJIYQQQggF6NUOIIQQQojaQxoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRhoLIYQQQijGQe0AWnfsR7hxSZ1112sEbR5QZ91qkFrbjj3W2t4yq5n3Tvfatm1v7G27rgxpLKy4cQkyUtVOcW+QWtuOPdba3jLbW16hjtq4ncihECGEEEIoRhoLIYQQQihGGgshhBBCKEYaCyGEEEIoRk7eVMhLiyI5+lsCBoMjer0Bb49WjO47jYjg4WpHq1WkzrZjr7W2x9z2mFmIikhjoaCofjOI6jedoqJC1u/6gDkrR+PvE4KPl7/a0WoVqbPt2Gut7TG3PWYW6ijdiDbx9COq73R6dXxE7WiAHAqpEQaDAw91f4YiYyEn0w6oHafWkjrbjr3W2h5z22NmYXtR/Waw8R9ZrJ15hT6dRvHmisdITU9WOxYgjUWNKCjMZ9OuRQA08wpUOU3tJXW2HXuttT3mtsfMQj0GgwNDwsZjNBZx+vwhteMA0lgoauUP/2DoDHcG/9WFT76bzpThH+HXtCMAs1eMZveRTcXL/m35UPYe+16tqBXKK4QbOVBYpHaSitWGOgPkFphrXWRUO0nF7LXWlnKfu3yC8fO7UFCYD8AXsf9k+XevqxkXsN9a24rRCPnZUJindhJtKSjMZ/2uBTgYHPFrGqx2HEDjjYXRaGTevHkEBATg7OxMcHAwcXFxtGnThnHjxqkdr4zRfaexblYGa2ZeplvbQSSe2FY8L+bh+Sz/bgY5eVnsOLQWV+cGdG3TX8W0JZ28BB/Gwmufw4y18Jcv4Yuf4UqW2snKsuc6Axw5Bwu2wmtfmGs9bQ2s+wUyc9ROVpa91tpSbh8vf8I7PMLqH+dw/uppYg+sZnTfaSqmNbPXWte0glw4EQ87FsH2RRD7b/h5BVw8pnYydd1qREe/2YyEw+t5/YmvNHM+jqZP3hw7dixr165lxowZdOnShV27djFq1CjS09OZMmWK2vEqVK+uB1OGf8STb7VmV9J6wto/jIdbI4aFT2TB+hc5mXaAt8dtVTtmsb2nYcUu879Nv08rKIKE43DgN3i+HzT1UC1eheytzgDbjsL6faDT3Z6WWwCxv8L+32Bif/B0Uy9fReyx1lB+boARkS8z8YMwfj72DTFD5uPkUEflpLfZa61rQv5N2LsKbl4rOT3zAhzaCDcugn9vdbKpbXTfaUT1m652jHJpdo/FqlWrWL58ORs2bGDq1Kn06dOHadOm0aNHDwoLC+ncubPaES2qX9eTR3pNYdm3f8VoNO/rHhAaTWp6MkN7vkj9up4qJzS7lg0rE8wNhanUPBOQUwDLdoCx9EyNsJc6A5y9Ym4qAEzl1DMzB1Yk2DZTVdhTre9UXm4HgyMd/HqTlXON9q3CVU5Ylr3WWmm/bi3bVADFf6xSfoYrp20aSVSCZhuL2bNnM3DgQCIiIkpM9/f3x9HRkY4dzcceU1JSiIiIIDAwkA4dOrBjxw414pZrWK+JXM08z5ZfPi2e1rShv2Z2VwHsOm65aTCZ4PINOH7Bdpmqyh7qDLAjGXQW5pswH5I6n2GjQHfBXmpdWuncKRcOczhlJyH+/dj804cqpyufvdZaKbk34NJxKwvp4Ox+m8QRVaDJxiI1NZWkpCSGDy97c5gzZ84QFBREnTrmXZfPPvssjz32GMnJySxZsoSRI0eSn59vdR06na5SX3FxsZXK/E5MbJndUq7O9Vn796sMCI2u1BilxcXFVjrn3X59ui4BU3kfn+9gMpl4auI/ajxLZWpdE3W2Va1/2HOmzF6h8gwc8bzUugZfi0ajkffWPscLwxbw50FvsW7nv7l246LimSubtzKZq8MW23ZNfA3s9VjZ3ailmSD115uqZ63p12JNqcq2URWabSwAvL29S0zPyckhLi6u+DDI5cuXiY+PZ+zYsQCEhYXRtGlTtm3bhqgcnd5QiY3GhF5vsEme2kxXyRpKrWvWxoRFBPh0IbBZF+o61yN6wCwWbpikdixRil5X2deLJt/GalR5jaiW6EzWPq6q4MSJEwQEBPDuu+8yadKk4ulvvPEGM2fOZMGCBYwfP559+/bx6KOPcurUqeJlRowYQb9+/RS7amTvashIVWSoKnNvBl1H1uw61vwM8dZ2NwLR4dDJt2az1PZafxwHSanWP4S9+CD4NarZLPZYa3vLrGbeO9li264J2VchYZmVhXTQoAmEjrZJpBphb9t1ZWjyqhA/Pz86duzI7Nmz8fT0xMfHhzVr1rB582YAunTponLC2qNnoOXGQge41oEOzW0WqdYKD4RDFv6A6IDGDaDVfTaLJIRmuXqCR3O4lkrF3bgJmofYMpWoDE3uQ9Lr9Xz55ZcEBQURExPDU089hZeXFxMmTMBgMBSfuNmiRQsuXrxIXt7tO6acPn0aX98a/mhdizRxh4EdzP8ufUBEh/myyDE9waDJLcW+BHpDWED583Q6cHSAqB4lL0UV4l7W9kFwqEOFZz03CoTGbWwaSVSCJvdYAAQGBpY5V+Lxxx+nXbt2uLi4AODl5UXPnj35+OOPGT9+PLt27eLcuXP06dNHjch2a2BH8HCFLUlw+Y4bYvk1gj8G1/xu+XuFTgfDQ6FRfdh2BK7fcUOsPzSBwZ20eb8QIdTi6gndouDEjt+vEPl9z4WjCzTvDC27g04+9GiOZhuL8uzdu5f777+/xLTFixcTHR3N/PnzcXJyYtWqVTg5OamU0H51bw3d/GDySvP304eAVz11M9VGOh1EtoXegTBllXnazGHgXlfdXLVRVk5G8UO8WjftBFDi+7Ppx1i8YTI6nZ42zUOJGfJujeQ4euanMuvJyskgKyeDxJOx9Gw/FDcX92qv5+dfv2HxhsnUd/Vi/oT46gfXiLoe0HEI5GWb774J0Os5kHOcLZu7OpqoftNVuTzZbhqLrKwskpOTGT9+fInpfn5+bN++XaVUZh9v/guHU3YS1LInze5rw+ptc5j0yFKCW0fwRew/2XV4PY09fHn5seUUFObxytJ++DT057XR/1U1d2l37oLXalNRUa0bebRg7uon0KHDq0EzXh31GQa9genLBpOVk6G5P7R3nsiu1abC0nYNsOPQWhatn8jK6WfJycvS3HaddDqenUn/w4SJ7NxM9Dp9ie/bNu/GP5/9ESdHZ+asjOL0+UO0atJB8RyN3X3LrCc7N5P4Q19x8dpv6HV6Huz6RKXG+m7Pcrw9WxLcOrLMvD+0uJ/FUxJ5ZUlfhX8Dbajjevvf0lSYffr9TPp3jcbbs6XaUUqwm51Ibm5uFBUV8cILL6gdpYTTF5LIzs3kX+O3k3nzCrn52QyPeJng1hFcy7rEgZPbmD8hnlZNOrIzaR0uddyYFrVa7dh2yVKt3ZzdefOpTfxr/Ha8PVvx86/mE33ffHqTlVFFeSzV+pYdB9dwn7v5rF4tbNeXr6cxdXEfJi0I5/21460u71nfGydHZwAMescau8y3MuspLCrg5SV9mbKwN2/85xGKjFV/CmC9uh6aujW5uHtV3ZYrsvrHOUxZ2NvmD9mzmz0WWpV0Op6ugeaHAXUOeJDMm1eK5yWf3UuwX+Tv8/rx474VRASXvemXqBxLta5X9/bJCQ4Gx0pfAy/KZ6nWAD8d3UzngH58u8fa9YC208DVi7ef2YLB4MBbK8fgUa8x/bo8Dtw+FOJSx63E9wCn0g5yPTsd38btajTfnevJysnAq4EPiSdj6RE0BIPegTef3kQdRxc++XY6B078SJfAB2s0j9Cu0ttyavpxmt1XwZnfFnTyf4CXRnzM9GWDuXz9HF4NfGogbVnSWFTTjZtX2ZSwmK92mI+bRgSPwN3NfLZjdm4GdZ3rA+Dq3ICs3AwVk9o/S7W+5fL1NH5J3kJUX+3ePMYeWKv1ll/+w6sjP9NUY5F58wrvr40hKyeDi9dSeKj7M2UOGZT+PvPmVT5Y9zzTx3xRw9lKrsfNxR03F3e8PaMByMnL4t0147iceY6MGxfx8Sr5JrJx1yJiEz/n2o0LODo44+bizrDwiYR3GFajuYU6Sm/LVzLTSjQW//nubxw8FcfFaynsOfYtTg7OjH1oDu1a9igxjr+P+VrcVt4duHD1tDQW9qJeXU+eHPB3woKGsPvIJtKv375RgatzA9J/v/PJzdxM3JzdVUpZO1iqNUB+YR7//PxJpgz/EINBNu3qsFTr/Sd+pJ1vDxwdtHWS9I/7VxIWNJQBodHMWRmFtVuRFRUV8taqMYwbPA/P+t4Wl62Oyqxn77HvaHZfIH+NWsmyb6aVuc3+n8Ji+FNYjMVzLETtYW1bfnLAG4D1cyxOpiXi27gdKReSGBI2oYZT32Y351hoVftW4Rw6ZT55NPFkLMY7jo0GNg/l4Kk4APYd38offO8vdwxROZZqDTB/zTiGhE2o8V3a9wJLtU65kETC4Q385cOB/HbxMJ98q429QyH+D7Bm+zv8bflQcvOzrS4fd/BLks/u4cOvX+GlRZEcSamZR8tWZj1tW3Qn4cgGpi8bzMVrKXe1nmNn9/LKkn6kXEjilSX9yC/IrWZyoZaqbssVOXgqjskLe+HXNJj73JspmNAy+VhXTa282+NgcOSlRZG08+2Bs5MrRcZCADzcGtHBrzeTFoTTyL0F/9drkrph7ZylWh9JSSA+aS0Xr/3G2h3zZTdxNVmq9bDwFxkW/iIAkxaE89TAN9WMWszfJ4QPXzpU6eUfCBnFAyGjajBR5ddzn3szFk3aZ3UsSw8ka9O8K3Of3VrVeEKDKrstP9F/ZoXzXhm5XLlAVSSNhQLGDppT/O/tB9ewettb+HgFENw6gpF9XmVkn1eL5+fkZfHWqjG0aR6qRlS7Z6nWG968UWb56csG41m/iS0j1hqWan3Lrct4ZbsWQtwijYXCend8lN4dH61wvksdN83dU8FeWas1yOWmSpHtWghRWdJYWFFPxdtZq7luNUitbccea21vmZXIe+upl9U5PH6vbdv2xt6268qQxsKKNg+oneDeIbW2HXustb1lViLv1nnm/9rjY89F5djbdl0ZclWIEEIIIRQjjYUQQohaYenSpURGRhIZGUlERAROTk689957ZaZlZ5e8hHPevHns37/f4thpaWl07twZZ2dnCgsLy8yfPHkyvXr1YuLEicXTMjIyiI2NJTY2loyMjDI/k5iYyNy5c+/ul9UwaSyEEELUCuPGjSt+Ix8+fDivvvoqEydOLDPN1fX2E82MRiM7d+4kJCTE4tienp788MMPZZ6wDbBv3z6ysrLYsWMH+fn57NmzB4D4+Hg+++wzPv3003IflhkcHExCQkKZG6LZOznHQgghRK1y+vRpVqxYQVxcnMVpYN5r4O9v/dHizs7OODs7lztv9+7dPPig+dku/fr1IyEhgdDQspdep6WlERUVRUFBAR07dmThwoUEBASwf/9+OnfuXJVfUdOksRBCCFFrmEwmnn32WT744AOcnJwqnHbL8ePHadmyZbXWmZGRgZ+fHwANGjTg8OHDAISHh+PmZn7wXadOnahbty5btmzBwcGBMWPGcPz4cfz8/Pj111+lsRBCCCG0aNGiRYSGhtKlSxeL08pz4cIFRo4seQmOt7c3q1evtvhzDRo0IDMzE4DMzEzc3d0BcHd3JzIysni58+fPExMTQ0ZGBikpKaSlpVXhN7Mf0lgIIYSoFVJSUvjss89KHO4ob9qdAgICis+J8Pb2JjY2tsrr7dGjB0uWLGHEiBFs3bqV6OjocpdbuXIlQ4cOJTo6mqioKEwmE6dOnSrTzNg7aSyEEELUCnPnziU9PZ3+/fsXT/Pz8ysz7dNPP6VFixaA+QTKmTNnWh27oKCAhx56iMTERAYMGMDs2bPx9fXl448/Ztq0aTg7O9OrVy86depEt27dyh3jgQce4IknnmDdunXF05KTk+nUqdNd/b5aJY2FEEKIWmHhwoVV/hm9Xk+vXr3Yv3+/xStDHB0d2bq17EPepk2bBsB7771ndV0hISEcOnT74WKJiYn06NEDvb52XaApjYUQQoh72tSpU1VZb3BwMMHBwaqsuybVrjZJCCGEEKqSxkIIIYQQipHGQgghhBCKkXMsrDj2I9y4pM666zWqnU++q4jU2nak1kKoR83XX0WUfF1KY2HFjUuQkap2inuD1Np2pNZCqKe2v/7kUIgQQgghFCONhRBCCCEUI4dCBNey4eBZSL16e9r730NTD2jREDo2B2dH9fLVJhcz4cg5OHvl9rQPtoKPB/g2hPbNwElelUIIOyZ/whTy0qJIjv6WgMHgiF5vwNujFaP7TiMieLja0Sp0PgO+ToTDqWAqNe9UuvkL4Ks9ENoKHgoG1zq2TlmSPdYZIOUybE6E5Atl5524aP4CcHGCMH/o3x7qqNzM2WuthRDqkkMhCorqN4ON/8hi7cwrDAiNZs7K0Zy7fELtWGUYTbAlCeZ9A0nlNBWl5RVC/HF4a5O5CVGbvdQZoMgI6/fBe9+V31SUlpMPPxyBt7+Gkxo4a9yeai3EvWDM7JZs/eW/lZ6uBmksaoDB4MBD3Z+hyFjIybQDascpwWiCz38y76koMlbtZ2/kwkdx8NPJmslWVVquM0BhESzbDtuOWm/eSruaDQt/MDd+WqD1WgshtEMaixpQUJjPpl2LAGjmFahympK+PVi9xsAErN4NR9MUi3TXtFxngDV74PC5u//5IiMs3wFnr1pftqZpvdZCCO2QxkJBK3/4B0NnuDP4ry588t10pgz/CL+mHQGYvWI0u49sKl72b8uHsvfY9zbNl3LZfAjEkvlR5i9LTJj3euTkKxatSrReZzDvadhtpYGrTK0LjbByl3nvhxrsodZCCG3RdGNhNBqZN28eAQEBODs7ExwcTFxcHG3atGHcuHFqxytjdN9prJuVwZqZl+nWdhCJJ7YVz4t5eD7Lv5tBTl4WOw6txdW5AV3b9Ldpvv/9UvVd8hXJuAlbDys0WBVpvc5Go7nWSjl/HXYeV268qtB6rWurm9fgxI7b3187CyalXrx2KC8bUn66/f2l4+bXmdAmTTcWY8eOZdasWTz77LN88803jBgxglGjRnHq1Cm6dOmidrwK1avrwZThH/HTr1+zK2k9AB5ujRgWPpEF619k5Q9v8tyQd22a6ewV+O2ysmPuPqneJ2nQZp0Bjp6HK1nKjrnzuLpvLFqtdW1jNMLRLbDr45JvpL98DntWmt9g7zW/7YH4JSUbrYPrYdeHkJWuXi61GAyOFBoLykwvLCrAwaCN+wJotrFYtWoVy5cvZ8OGDUydOpU+ffowbdo0evToQWFhIZ07d1Y7okX163rySK8pLPv2rxh/b60HhEaTmp7M0J4vUr+up03z7PtN+TGz8+DYeeXHrQqt1RlgX4ryY17KLHmfETVosda1zfFYOJdY/rzMC7B/DRhVbOZt7dxBOB4HpnL2TuRmwS9fQJ7CTbzWeXu0JK3UlVk5eVlcu3GBJg39VEpVkmYbi9mzZzNw4EAiIiJKTPf398fR0ZGOHc3HeV9//XUCAwPR6/WsWbNGjagVGtZrIlczz7Pll0+LpzVt6I+Pl7/Ns5y5Yn2ZuxpXAycWaqnOILUWdycvC87ut7CAyfwJPV2lw2K2ZjTCyZ0WFjBBQQ6kHrBVIm3o3zWazT8t5dCpHRQZi7hx8xoL10+kpXcH/JuGqB0P0OgNslJTU0lKSmLy5Mll5p05c4agoCDq1DHfqWngwIFER0fz9NNP2zpmCe/ExJaZ5upcn7V/18C7AXDheg2Nm1Ez41ZE63UuLIL0GzUzttS6drtwFOsnQekg7Qg0bmuLROq6dgbyK3HoJy0JWofXfB6t6Ns5iryCm/z7fxO4mPEbLk5udPSLYNbTGzEYtPGWro0UpaSmmi/e9/b2LjE9JyeHuLg4HnrooeJpYWFhd7UOnU5XqeXmPbeN4NaRd7WO6oqLiyV0VB9Fxhr/URaOzq7F31u7GqGi+ZNWlPx+3caveTpicDXTmdWGWju51CPmw8wS05Sq9aKlH/Fot2eqke622lDr2ubPf3yb4RFT0ess7Eg2we7t++j8iHbPMVNK385RvDbK+g2fsq8XoNM52SCRcqr7+hvU/RkGdVfmb8Et1l6Xpiqc5KXJxsLLywuA5ORkBg0aVDx97ty5nD9/XtMnblrzysjlqqy3sCC3RGOhlKL8XMXHVIJadS4qyAPML8LKNq+VHltqXatlZl+23FQARmMRGdkauCWrDVzPtn62uclk4sZN2YOmNTpTVdoQGzEajYSEhHD+/HnmzZuHj48Pa9asYfPmzZw5c4bdu3fTvXv3Ej8TGRnJ888/z6OPPqpolr2rIUOlux+6N4OuI5UZ673v4XQlzqC+9em59KflivRvD4OC7z7XnWpLrWetr9xVIVWt9aOhEK7QvalqS61rk9xMiF9qfbmgQdCkXc3nUZuxCHYsNp9HYYlvKAREWF5Ga9R8/VVEydelJk/e1Ov1fPnllwQFBRETE8NTTz2Fl5cXEyZMwGAwFJ+4KSqveQ2dsF9T49ozqbW4G871oWkHCwvooK4HNLpHbnyqN0CrHhYW0IFDHWiujfMVxR00eSgEIDAwkG3btpWY9vjjj9OuXTtcXFxUSmW/Qnxh+zFlx3RxhDZNlB2zNgjxhQNnlB2zoRs0b6jsmEJ72vaFogK4+Ctw55E0E7h6QsgjoJHz82yieQgU3ITTu3+fcKsmJnB0hk7/Z27IhLbY1Sa6d+9e7r///hLTZsyYwSeffEJ6ejqHDh1i0qRJxMXF0bp1a5VSalNLL2jmAanXlBuzW2twsqstyDbaN4MGLnDdyi7cqugZAHplT9kQGqR3gA6Dwber+WqH3BvmT+WN24BXK7ByCkato9OZr/ho0h7SDkL2VXMNvPzMNdHI/aBq3Hd7llNkLGRQ9z9X+WezcjLYmbSO4NaRuLm4szNp3V2PVVl287aQlZVFcnIy48ePLzF91qxZzJo1S6VUZh9v/guHU3YS1LInze5rw+ptc5j0yFKCWoYxZWFvTl84xOLJB/Dx8icnL4tXlvbDp6E/r4223SNudToY2gU+2KrMeG7O8GCQMmNVRUW1bukdxOufDMFgcMTVuQHTx3yO0VikSq0NenOt/xOvzHj31VPu3IqqqKjWwa0jeHhGg+Jr5v/25Frq1/Vk+rLBZOVkMH+CQr/4Pay+t/lLmNV1B//eaqewT7uPbGL3kY2cPn+Qnu2H2WSddtP/urm5UVRUxAsvvKB2lBJOX0giOzeTf43fTubNK+TmZzM84mWCW0dg0DvwRvQ6enW4fUKpSx03pkWtViWrf2OIsHL9+6QVlTuZcEQ3c3NhS5Zq7ebiwbvj4/lXTByBPl3YfWSTqrUO8TV/WVKZWut1MLqH7fcMWao1QCvvDrwTE8s7MbHFd9x88+lNloYUQpRy+XoaUxf3YdKCcN5fO97isruPbOS1Dwfw+icPU1BY/hMgT5w7wJRFEbzwfndW/jC7xDzTHTdJqcxY1WE3jYVWJZ2Op2ug+cFLnQMeRK83FM/T6XR41GusVrRyDQmBTi2qN8awLtCxuTJ5qsJSrQ16A3q9eXMuMhXh4xVg+4CljLofAqrxv1+vgzFh0Oo+5TJVlqVaA5y5dJTJC3vx0ebXqnR9uxDitgauXrz9zBbmT4jnZm4mqRZuq+ru1oi3nvmOdi3DiE9aW+4yzRu14Z3nYvn3iz+x7/gW8gpyuL/dYO5v9yeGhU+kVZMOlR6rOuzmUIhW3bh5lU0Ji/lqx7tk5WQQETwCd7dGaseqkEEPj/c0nwz445GqPe3UxREe7QZdWtZUOsus1frXMz/z/v/G4+TgzPDeL6kT8g5ODvBMpPlJpwknrC5eQj1nc2PSzqdGolllrdbLXz1OPRcP3vvqORKObCQsaIg6QYWwY5k3r/D+2hiycjK4eC2FK5lpNLuv/A9F/j7mQ4+tm3Yi+eyecpe5cPU0Sza+RG7BTVIvHSMj6xKNPXwZEBpd5bGqQxqLaqpX15MnB/ydsKAh7D6yifTrGrs4uRwGPfwpBDo0h4374aSV++0Y9BDSwvwzDeraJmN5rNW6bYtuLJy4ly/j3uHbPct4pHfZW8LbmpMDPNbdvJfo60TrzxFxNEA3P/O9QVzr2CZjeazV+tbhj7D2Qzlxbr80FkLchR/3ryQsaCgDQqOZszIKMFFUVEjmzStl9nafSkss/m+Thq3LXW5jwiIe6/Mqwa0jmbQgvMK9iaXHUpo0FtXUvlU43+9ZTljQEBJPxuLt2QqD3j7K2tILXnjQ/ByRg2fg7FXzUzQLjVDHEZq6Q4uG5nMF6tn4fIryWKp1QWE+jg7m2/q6OtenSGOPgGzTxPx15gocPmd+jP3lLCgygosT+HiAb0Po5At1NXB3Yku1zsnPxsnBGYPewOGUnbTytnTzBSFERUL8H+Dt1U+w6/C64mkXrqXw+ba3mTL8wxLLZt68wqtL++Pk6MyMx78sd7nubf/IB/97nhaN2+FoqPgPSemxlGYf74Aa1sq7PQ4GR15aFEk73x44O7lSZCwsnj/rsxEkpcRz7vJxHot8hbD2D6uYtnzeDcAe3hss1fpk2gGWfv0yep2eei6evDrqM5XTlq9FQ/OX1lmq9bn047zz5dO4OLnh7dmKJ/q/oXJaIeyTv08IH750qMS0HQe/ok/IqBLTBoRGlzmccSotscxyoW0HEtp2oMV1ljeW0qSxUMDYQXOK/7394BpWb3sLH68AgltHMOPxL0osm5OXxVurxtCmeaitY9YKlmr9r5i4EstKravHUq0XTdpXZvnpywbjWV/umCZEdfTq+Iiiy6lBk88K0RJ5poLtSK1tR2othHpq+7NCZI+FFfVUvMBDzXWrQWptO1JrIdSjxdeAkplkj4UQQgghFCM3yBJCCCGEYqSxEEIIIYRipLEQQgghhGKksRBCCCGEYqSxEEIIIYRipLEQQgghhGKksRBCCCGEYqSxEEIIIYRipLEQQgghhGKksRBCCCGEYqSxEEIIIYRipLEQQgghhGKksRBCCCGEYqSxEEIIIYRipLEQQgghhGKksRBCCCGEYqSxEEIIIYRipLEQQgghhGL+Hy2b51ufQ4QzAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.circuit import Parameter\n", + "\n", + "ansatz2 = ansatz.decompose()\n", + "a = Parameter(\"a\")\n", + "b = Parameter(\"b\")\n", + "ansatz2.rx(a * a, 0)\n", + "ansatz2.cry(2 * a + 1, 1, 0)\n", + "ansatz2.rzz(-a, 0, 1)\n", + "ansatz2.p(a + b, 0)\n", + "ansatz2.u(a, b, a * b, 1)\n", + "print(\"observable\")\n", + "print(observable)\n", + "\n", + "print(\"\\nansatz\")\n", + "ansatz2.draw(\"mpl\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "678ce6f9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "fin diff of exact\n", + "[[-0.50387423 -0.04204217 -0.02687266 -0.34543053 -0.00747777 -0.2102079\n", + " -0.01227969 0.1783854 ]\n", + " [ 0.19550173 0.26693395 0.26279436 -0.20409191 0.33825935 0.30190915\n", + " -0.27234014 0.18686265]]\n", + "\n", + "param_shift of shot-based\n", + "[[-0.52083576 -0.04191822 -0.03018229 -0.34719191 -0.00482996 -0.20497931\n", + " -0.00867835 0.17475105]\n", + " [ 0.19906325 0.26283638 0.26829321 -0.1974799 0.33984618 0.29805441\n", + " -0.2703582 0.17643717]]\n", + "\n", + "lin_comb of shot-based\n", + "[[-0.48490205 -0.08154884 -0.02104975 -0.3384358 -0.00378382 -0.22779396\n", + " -0.01809316 0.19176929]\n", + " [ 0.20990154 0.26023403 0.25998745 -0.22575058 0.32287464 0.27691383\n", + " -0.25460826 0.19822332]]\n", + "\n", + "fin_diff of shot-based\n", + "[[-15072.1926374 5570.65181318 646.1249106 4310.94510476\n", + " -2761.3735416 -4568.83150792 2289.50063268 -7827.09271964]\n", + " [ -7160.62674687 -9143.06480607 4250.10088706 -1097.74429987\n", + " 4330.8964238 -3471.73606076 4429.33163399 -818.9921735 ]]\n" + ] + } + ], + "source": [ + "from qiskit.evaluators.expectation_value import OpflowGradient\n", + "\n", + "x = [-1, 0, 1, 1, 2, 3, 5, 8]\n", + "x2 = [1, 1, 2, 2, 3, 3, 4, 4]\n", + "backend = AerSimulator()\n", + "\n", + "exact_expval = ExactExpectationValue(ansatz2, observable, backend=backend)\n", + "exact_findiff = FiniteDiffGradient(exact_expval, 1e-8)\n", + "print()\n", + "print(\"fin diff of exact\")\n", + "print(exact_findiff.evaluate([x, x2]).values)\n", + "\n", + "shots = 10000\n", + "expval = PauliExpectationValue(ansatz2, observable, backend=backend)\n", + "for method in [\n", + " \"param_shift\",\n", + " \"lin_comb\",\n", + " \"fin_diff\",\n", + "]: # fin_diff might not be so accurate\n", + " diff = OpflowGradient(expval, method)\n", + " print(f\"\\n{method} of shot-based\")\n", + " print(diff.evaluate([x, x2], shots=shots).values)" + ] + }, + { + "cell_type": "markdown", + "id": "ced77786", + "metadata": {}, + "source": [ + "### VQE by Scipy optimizer" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "7dd56dfc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " fun: -1.8642068300169663\n", + " hess_inv: array([[ 1.28677054, -0.13162706, 0.58354618, -0.20956311, 0.22466975,\n", + " 0.35656959],\n", + " [-0.13162706, 1.32750964, -0.54120534, -0.51338521, -0.60957092,\n", + " -0.19398025],\n", + " [ 0.58354618, -0.54120534, 2.30769968, -0.40896733, 0.84726221,\n", + " -0.06218398],\n", + " [-0.20956311, -0.51338521, -0.40896733, 0.91601738, 0.05881018,\n", + " -0.21701942],\n", + " [ 0.22466975, -0.60957092, 0.84726221, 0.05881018, 1.56494775,\n", + " 0.29076011],\n", + " [ 0.35656959, -0.19398025, -0.06218398, -0.21701942, 0.29076011,\n", + " 1.62686697]])\n", + " jac: array([ 0.01547791, 0.00794564, -0.00965232, -0.01743931, -0.00670695,\n", + " 0.00318172])\n", + " message: 'Desired error not necessarily achieved due to precision loss.'\n", + " nfev: 69\n", + " nit: 11\n", + " njev: 57\n", + " status: 2\n", + " success: False\n", + " x: array([ 0.89378848, -1.37531481, -0.9576132 , -0.40099486, 1.32231182,\n", + " 1.40349113])\n" + ] + } + ], + "source": [ + "from qiskit.evaluators import HistoryEvaluator\n", + "from scipy.optimize import minimize\n", + "\n", + "shots = 1000\n", + "expval = PauliExpectationValue(ansatz, observable, backend=AerSimulator())\n", + "history_eval = HistoryEvaluator(expval)\n", + "paramshift = ParameterShiftGradient(expval)\n", + "# this may take a long time...\n", + "result = minimize(\n", + " lambda x: history_eval.evaluate(x, shots=shots, seed_simulator=15).value,\n", + " np.zeros(6),\n", + " jac=lambda x: paramshift.evaluate(x, shots=shots, seed_simulator=15).values,\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "71a0aed0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plt.figure(figsize=(12, 8))\n", + "y = [h.value for h in history_eval.history]\n", + "x = list(range(len(y)))\n", + "yerr = np.array(\n", + " [\n", + " tuple(abs(c - h.value) for c in h.confidence_interval)\n", + " for h in history_eval.history\n", + " ]\n", + ").transpose()\n", + "plt.plot(y, color=\"blue\")\n", + "plt.errorbar(\n", + " x,\n", + " y,\n", + " yerr=yerr,\n", + " capsize=5,\n", + " fmt=\"o\",\n", + " markersize=8,\n", + " ecolor=\"blue\",\n", + " markeredgecolor=\"blue\",\n", + " color=\"w\",\n", + ")\n", + "plt.xlabel(\"Eval count\")\n", + "plt.ylabel(\"Energy\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba66ef99", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "55198b233f406dc59b712acd847cdd7a571fa057c585d106ba05aad0d31ffb93" + }, + "kernelspec": { + "display_name": "Terra", + "language": "python", + "name": "terra" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qiskit/evaluators/expectation_value/__init__.py b/qiskit/evaluators/expectation_value/__init__.py new file mode 100644 index 000000000000..eec94cf85e92 --- /dev/null +++ b/qiskit/evaluators/expectation_value/__init__.py @@ -0,0 +1,25 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Expectation Value +""" + +from .exact_expectation_value import ExactExpectationValue +from .base_expectation_value import BaseExpectationValue +from .expectation_value_gradient import ( + BaseExpectationValueGradient, + FiniteDiffGradient, + ParameterShiftGradient, +) +from .opflow_gradient import OpflowGradient +from .pauli_expectation_value import PauliExpectationValue diff --git a/qiskit/evaluators/expectation_value/base_expectation_value.py b/qiskit/evaluators/expectation_value/base_expectation_value.py new file mode 100644 index 000000000000..cd8b9b3b4048 --- /dev/null +++ b/qiskit/evaluators/expectation_value/base_expectation_value.py @@ -0,0 +1,171 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value base class +""" +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Optional, Union, cast + +import numpy as np + +from qiskit import QuantumCircuit +from qiskit.circuit import ParameterExpression +from qiskit.evaluators.backends import ( + BaseBackendWrapper, + ShotBackendWrapper, + ShotResult, +) +from qiskit.evaluators.framework import BaseEvaluator +from qiskit.evaluators.results import ( + CompositeResult, + ExpectationValueArrayResult, + ExpectationValueResult, +) +from qiskit.extensions import Initialize +from qiskit.opflow import PauliSumOp +from qiskit.providers import BackendV1 as Backend +from qiskit.quantum_info import SparsePauliOp, Statevector +from qiskit.quantum_info.operators.base_operator import BaseOperator + +if TYPE_CHECKING: + from typing import Any + + +class BaseExpectationValue(BaseEvaluator, ABC): + """ + Expectation Value class + """ + + def __init__( + self, + state: Union[QuantumCircuit, Statevector], + observable: Union[BaseOperator, PauliSumOp], + backend: Union[Backend, BaseBackendWrapper, ShotBackendWrapper], + ): + """ """ + super().__init__(backend=backend) + self._state = self._init_state(state) + self._observable = self._init_observable(observable) + + @property + def state(self) -> QuantumCircuit: + """Quantum Circuit that represents quantum state. + + Returns: + quantum state + """ + return self._state + + @state.setter + def state(self, state: Union[QuantumCircuit, Statevector]): + self._transpiled_circuits = None + self._state = self._init_state(state) + + @property + def observable(self) -> SparsePauliOp: + """ + SparsePauliOp that represents observable + + Returns: + observable + """ + return self._observable + + @observable.setter + def observable(self, observable: Union[BaseOperator, PauliSumOp]): + self._transpiled_circuits = None + self._observable = self._init_observable(observable) + + def set_transpile_options(self, **fields) -> BaseExpectationValue: + """Set the transpiler options for transpiler. + + Args: + fields: The fields to update the options + Returns: + self + """ + self._transpiled_circuits = None + super().set_transpile_options(**fields) + return self + + @property + def preprocessed_circuits( + self, + ) -> Union[list[QuantumCircuit], tuple[QuantumCircuit, list[QuantumCircuit]]]: + """ + Transpiled quantum circuits produced by preprocessing + + Returns: + List of the transpiled quantum circuit + """ + if self._preprocessed_circuits is None: + self._preprocessed_circuits = self._preprocessing(self.state, self.observable) + return super().preprocessed_circuits + + @staticmethod + def _init_state(state: Union[QuantumCircuit, Statevector]) -> QuantumCircuit: + if isinstance(state, QuantumCircuit): + return state + statevector = Statevector(state) + qc = QuantumCircuit(statevector.num_qubits) + qc.append( + Initialize(state.data, statevector.num_qubits), list(range(statevector.num_qubits)) + ) + return qc + + @staticmethod + def _init_observable(observable: Union[BaseOperator, PauliSumOp]) -> SparsePauliOp: + if isinstance(observable, PauliSumOp): + if isinstance(observable.coeff, ParameterExpression): + raise TypeError( + f"observable must have numerical coefficient, not {type(observable.coeff)}" + ) + return observable.coeff * observable.primitive + if isinstance(observable, SparsePauliOp): + return observable + if isinstance(observable, BaseOperator): + return SparsePauliOp.from_operator(observable) + + raise TypeError(f"Unrecognized observable {type(observable)}") + + def evaluate( + self, + parameters: Optional[ + Union[ + list[float], + list[list[float]], + "np.ndarray[Any, np.dtype[np.float64]]", + ] + ] = None, + **run_options, + ) -> Union[ExpectationValueResult, ExpectationValueArrayResult]: + res = super().evaluate(parameters, **run_options) + if isinstance(res, CompositeResult): + # TODO CompositeResult should be Generic + # pylint: disable=no-member + values = np.array([r.value for r in res.items]) # type: ignore + variances = np.array([r.variance for r in res.items]) # type: ignore + confidence_intervals = np.array([r.confidence_interval for r in res.items]) # type: ignore + return ExpectationValueArrayResult(values, variances, confidence_intervals) + return cast(ExpectationValueResult, res) + + @abstractmethod + def _postprocessing(self, result: Union[ShotResult, dict]) -> ExpectationValueResult: + return NotImplemented + + @abstractmethod + def _preprocessing( + self, state: QuantumCircuit, observable: SparsePauliOp + ) -> Union[list[QuantumCircuit], tuple[QuantumCircuit, list[QuantumCircuit]]]: + return NotImplemented diff --git a/qiskit/evaluators/expectation_value/exact_expectation_value.py b/qiskit/evaluators/expectation_value/exact_expectation_value.py new file mode 100644 index 000000000000..234568a7d184 --- /dev/null +++ b/qiskit/evaluators/expectation_value/exact_expectation_value.py @@ -0,0 +1,75 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value class +""" + +# pylint: disable=no-name-in-module, import-error + +from __future__ import annotations + +from typing import Union + +from qiskit import QuantumCircuit +from qiskit.evaluators.backends import ShotResult +from qiskit.evaluators.results import ExpectationValueResult +from qiskit.exceptions import MissingOptionalLibraryError +from qiskit.opflow import PauliSumOp +from qiskit.providers import BackendV1 as Backend +from qiskit.quantum_info import SparsePauliOp, Statevector +from qiskit.quantum_info.operators.base_operator import BaseOperator +from qiskit.utils import has_aer + +from .base_expectation_value import BaseExpectationValue + +if has_aer(): + from qiskit.providers.aer.library import SaveExpectationValueVariance + + +class ExactExpectationValue(BaseExpectationValue): + """ + Calculates the expectation value exactly (i.e. without sampling error). + """ + + def __init__( + self, + state: Union[QuantumCircuit, Statevector], + observable: Union[BaseOperator, PauliSumOp], + backend: Backend, + ): + if not has_aer(): + raise MissingOptionalLibraryError( + libname="qiskit-aer", + name="Aer provider", + pip_install="pip install qiskit-aer", + ) + + super().__init__( + state=state, + observable=observable, + backend=backend, + ) + + def _preprocessing( + self, state: QuantumCircuit, observable: SparsePauliOp + ) -> list[QuantumCircuit]: + state_copy = state.copy() + inst = SaveExpectationValueVariance(operator=observable) + state_copy.append(inst, qargs=range(state_copy.num_qubits)) + return [state_copy] + + def _postprocessing(self, result: Union[dict, ShotResult]) -> ExpectationValueResult: + + # TODO: validate + + expval, variance = result["expectation_value_variance"] + return ExpectationValueResult(expval, variance, None) diff --git a/qiskit/evaluators/expectation_value/expectation_value.py b/qiskit/evaluators/expectation_value/expectation_value.py new file mode 100644 index 000000000000..49a82d53b44c --- /dev/null +++ b/qiskit/evaluators/expectation_value/expectation_value.py @@ -0,0 +1,83 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value class +""" +from __future__ import annotations + +import sys +from typing import TYPE_CHECKING, Union + +from qiskit import QuantumCircuit +from qiskit.evaluators.backends import ( + BaseBackendWrapper, + ShotBackendWrapper, + ShotResult, +) +from qiskit.evaluators.results import ExpectationValueResult +from qiskit.opflow import PauliSumOp +from qiskit.providers import BackendV1 as Backend +from qiskit.quantum_info import SparsePauliOp, Statevector +from qiskit.quantum_info.operators.base_operator import BaseOperator + +from .base_expectation_value import BaseExpectationValue + +if TYPE_CHECKING: + from typing import Any + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from typing_extensions import Protocol + + +class Preprocessing(Protocol): + """Preprocessing Callback Protocol (PEP544)""" + + def __call__(self, state: QuantumCircuit, observable: SparsePauliOp) -> list[QuantumCircuit]: + ... + + +class Postprocessing(Protocol): + """Postprocessing Callback Protocol (PEP544)""" + + def __call__(self, result: Union[ShotResult, dict]) -> ExpectationValueResult: + ... + + +class ExpectationValue(BaseExpectationValue): + """ + Expectation Value class + """ + + def __init__( + self, + preprocessing: Preprocessing, + postprocessing: Postprocessing, + state: Union[QuantumCircuit, Statevector], + observable: Union[BaseOperator, PauliSumOp], + backend: Union[Backend, BaseBackendWrapper, ShotBackendWrapper], + ): + """ """ + super().__init__(state, observable, backend=backend) + self._state = self._init_state(state) + self._observable = self._init_observable(observable) + self._injected_preprocessing = preprocessing + self._injected_postprocessing = postprocessing + + def _preprocessing( + self, state: QuantumCircuit, observable: SparsePauliOp + ) -> Union[list[QuantumCircuit], tuple[QuantumCircuit, list[QuantumCircuit]]]: + return self._injected_preprocessing(state, observable) + + def _postprocessing(self, result: Union[ShotResult, dict]) -> ExpectationValueResult: + return self._injected_postprocessing(result) diff --git a/qiskit/evaluators/expectation_value/expectation_value_gradient.py b/qiskit/evaluators/expectation_value/expectation_value_gradient.py new file mode 100644 index 000000000000..caeda97a848e --- /dev/null +++ b/qiskit/evaluators/expectation_value/expectation_value_gradient.py @@ -0,0 +1,186 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value gradient class +""" + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Any, Optional, Union, cast + +import numpy as np + +from qiskit import QuantumCircuit +from qiskit.evaluators.backends import ShotResult +from qiskit.evaluators.framework.base_evaluator import ( + BaseEvaluator, + PreprocessedCircuits, +) +from qiskit.evaluators.results import ( + CompositeResult, + ExpectationValueGradientResult, + ExpectationValueResult, +) + +from .base_expectation_value import BaseExpectationValue + + +class BaseExpectationValueGradient(BaseEvaluator, ABC): + """ + Base class for expectation value gradient + """ + + def __init__( + self, + expectation_value: BaseExpectationValue, + ): + self._expectation_value = expectation_value + super().__init__( + backend=self._expectation_value._backend, + transpile_options=self._expectation_value.transpile_options.__dict__, + ) + + @property + def preprocessed_circuits(self) -> PreprocessedCircuits: + """ + Preprocessed quantum circuits produced by preprocessing + + Returns: + List of the transpiled quantum circuit + """ + return self._expectation_value.preprocessed_circuits + + @property + def transpiled_circuits(self) -> list[QuantumCircuit]: + """ + Transpiled quantum circuits. + + Returns: + List of the transpiled quantum circuit + """ + return self._expectation_value.transpiled_circuits + + @abstractmethod + def _eval_parameters( + self, parameters: "np.ndarray[Any, np.dtype[np.float64]]" + ) -> "np.ndarray[Any, np.dtype[np.float64]]": + return NotImplemented + + @abstractmethod + def _compute_gradient(self, results: CompositeResult, shape) -> ExpectationValueGradientResult: + return NotImplemented + + def evaluate( + self, + parameters: Optional[ + Union[list[float], list[list[float]], np.ndarray[Any, np.dtype[np.float64]]] + ] = None, + **run_options, + ) -> ExpectationValueGradientResult: + """TODO""" + if parameters is None: + raise ValueError() + + parameters = np.asarray(parameters, dtype=np.float64) + if len(parameters.shape) not in [1, 2]: + raise ValueError("parameters should be a 1D vector or 2D vectors") + param_array = self._eval_parameters(parameters) + results = cast(CompositeResult, super().evaluate(param_array, **run_options)) + return self._compute_gradient(results, parameters.shape) + + def _postprocessing(self, result: Union[ShotResult, dict]) -> ExpectationValueResult: + return self._expectation_value._postprocessing(result) + + +class FiniteDiffGradient(BaseExpectationValueGradient): + """ + Finite difference of expectation values + """ + + def __init__(self, expectation_value: BaseExpectationValue, epsilon: float): + super().__init__(expectation_value) + self._epsilon = epsilon + + def _eval_parameters( + self, parameters: "np.ndarray[Any, np.dtype[np.float64]]" + ) -> "np.ndarray[Any, np.dtype[np.float64]]": + if len(parameters.shape) == 1: + parameters = parameters.reshape((1, parameters.shape[0])) + dim = parameters.shape[-1] + ret = [] + for param in parameters: + ret.append(param) + for i in range(dim): + ei = param.copy() + ei[i] += self._epsilon + ret.append(ei) + return np.array(ret) + + def _compute_gradient(self, results: CompositeResult, shape) -> ExpectationValueGradientResult: + values = np.array([r.value for r in results.items]) # type: ignore + dim = shape[-1] + array = values.reshape((values.shape[0] // (dim + 1), dim + 1)) + ret = [] + for values in array: + grad = np.zeros(dim) + f_ref = values[0] + for i, f_i in enumerate(values[1:]): + grad[i] = (f_i - f_ref) / self._epsilon + ret.append(grad) + grad = np.array(ret).reshape(shape) + return ExpectationValueGradientResult(values=grad) + + +class ParameterShiftGradient(BaseExpectationValueGradient): + """ + Gradient of expectation values by parameter shift + """ + + def __init__(self, expectation_value: BaseExpectationValue): + super().__init__(expectation_value) + self._epsilon = np.pi / 2 + + def _eval_parameters( + self, parameters: "np.ndarray[Any, np.dtype[np.float64]]" + ) -> "np.ndarray[Any, np.dtype[np.float64]]": + if len(parameters.shape) == 1: + parameters = parameters.reshape((1, parameters.shape[0])) + dim = parameters.shape[-1] + ret = [] + for param in parameters: + for i in range(dim): + ei = param.copy() + ei[i] += self._epsilon + ret.append(ei) + + ei = param.copy() + ei[i] -= self._epsilon + ret.append(ei) + + return np.array(ret) + + def _compute_gradient(self, results: CompositeResult, shape) -> ExpectationValueGradientResult: + values = np.array([r.value for r in results.items]) # type: ignore + dim = shape[-1] + array = values.reshape((values.shape[0] // (2 * dim), 2 * dim)) + div = 2 * np.sin(self._epsilon) + ret = [] + for values in array: + grad = np.zeros(dim) + for i in range(dim): + f_plus = values[2 * i] + f_minus = values[2 * i + 1] + grad[i] = (f_plus - f_minus) / div + ret.append(grad) + grad = np.array(ret).reshape(shape) + return ExpectationValueGradientResult(values=grad) diff --git a/qiskit/evaluators/expectation_value/opflow_gradient.py b/qiskit/evaluators/expectation_value/opflow_gradient.py new file mode 100644 index 000000000000..d2539daa98da --- /dev/null +++ b/qiskit/evaluators/expectation_value/opflow_gradient.py @@ -0,0 +1,151 @@ +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value gradient class with Opflow +""" + +from __future__ import annotations + +from typing import Any, Optional, Union, cast + +import numpy as np + +from qiskit.circuit import ParameterExpression +from qiskit.evaluators.expectation_value.base_expectation_value import ( + BaseExpectationValue, +) +from qiskit.evaluators.results import ( + CompositeResult, + ExpectationValueGradientResult, + ExpectationValueResult, +) +from qiskit.exceptions import QiskitError +from qiskit.opflow import CircuitStateFn, ListOp, SummedOp +from qiskit.opflow.gradients import Gradient +from qiskit.quantum_info import Pauli + +from .expectation_value_gradient import BaseExpectationValueGradient + +Pauli_Z = Pauli("Z") + + +class OpflowGradient(BaseExpectationValueGradient): + """TODO""" + + def __init__(self, expectation_value: BaseExpectationValue, grad_method: str = "param_shift"): + super().__init__(expectation_value) + self._grad_method = grad_method + self._grad: list[list[tuple[Union[float, ParameterExpression], BaseExpectationValue]]] = [] + + def _preprocessing(self): + if self._grad: + return + + expval = self._expectation_value + op = CircuitStateFn(expval.state) + grad = cast(ListOp, Gradient(self._grad_method).convert(op)) + assert len(grad.oplist) == len(expval.state.parameters) + + def extract_circuits(list_op: ListOp): + lst = [] + if self._grad_method == "lin_comb": + mul = 2 + for i, op in enumerate(list_op.oplist): + # Note: apply `reduce` to remove IGate of the gradient of PhaseGate + op = cast(CircuitStateFn, op.reduce()) + observable = expval.observable.expand(Pauli_Z) + new_expval = expval.__class__( + state=op.primitive, observable=observable, backend=expval.backend + ) + lst.append((mul * list_op.coeff * op.coeff ** 2, new_expval)) # type: ignore + elif self._grad_method in ["param_shift", "fin_diff"]: + if "shift_constant" in list_op.combo_fn.keywords: # type: ignore + mul = list_op.combo_fn.keywords["shift_constant"] # type: ignore + else: + mul = 1 + for i, op in enumerate(list_op.oplist): + op = cast(CircuitStateFn, op) + observable = (-1) ** i * expval.observable + new_expval = expval.__class__( + state=op.primitive, observable=observable, backend=expval.backend + ) + lst.append((mul * list_op.coeff * op.coeff ** 2, new_expval)) # type: ignore + else: + raise QiskitError( + f"internal error: unsupported gradient method {self._grad_method}" + ) + + return lst + + for op in grad.oplist: + if isinstance(op, SummedOp): + lst = [] + for op2 in op.oplist: + for coeff, new_expval in extract_circuits(cast(ListOp, op2)): + lst.append((op.coeff * coeff, new_expval)) + self._grad.append(lst) + elif isinstance(op, ListOp): + self._grad.append(extract_circuits(op)) + else: + raise QiskitError("internal error: `op` should be ListOp or SummedOp.") + + def _eval_parameters( + self, parameters: np.ndarray[Any, np.dtype[np.float64]] + ) -> np.ndarray[Any, np.dtype[np.float64]]: + pass + + def _compute_gradient(self, results: CompositeResult, shape) -> ExpectationValueGradientResult: + pass + + def evaluate( # pylint: disable=signature-differs + self, + parameters: Optional[ + Union[list[float], list[list[float]], np.ndarray[Any, np.dtype[np.float64]]] + ] = None, + **run_options, + ) -> ExpectationValueGradientResult: + if parameters is None: + raise TypeError("parameters is None") + + parameters = np.asarray(parameters, dtype=np.float64) + if parameters.ndim not in [1, 2]: + raise ValueError("parameters should be a 1D vector or 2D vectors") + + num_param_sets = 1 if parameters.ndim == 1 else parameters.shape[0] + + param_map = {} + for j, param in enumerate(self._expectation_value.state.parameters): + if parameters.ndim == 1: + param_map[param, 0] = parameters[j] + else: + for i in range(num_param_sets): + param_map[param, i] = parameters[i, j] + + self._preprocessing() + + ret = np.zeros(parameters.shape) + for j, lst in enumerate(self._grad): + for coeff, expval in lst: + bound_coeff: Union[float, np.ndarray] + if isinstance(coeff, ParameterExpression): + bound_coeff = np.zeros(num_param_sets) + for i in range(num_param_sets): + local_map = {param: param_map[param, i] for param in coeff.parameters} + bound_coeff[i] = coeff.bind(local_map) + else: + bound_coeff = coeff + result = expval.evaluate(parameters, **run_options) + if isinstance(result, ExpectationValueResult): + ret[j] += bound_coeff * result.value + else: + ret[:, j] += bound_coeff * result.values + + return ExpectationValueGradientResult(values=ret) diff --git a/qiskit/evaluators/expectation_value/pauli_expectation_value.py b/qiskit/evaluators/expectation_value/pauli_expectation_value.py new file mode 100644 index 000000000000..479e6515d21c --- /dev/null +++ b/qiskit/evaluators/expectation_value/pauli_expectation_value.py @@ -0,0 +1,205 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value class +""" + +from __future__ import annotations + +import logging +from typing import Optional, Union, cast + +import numpy as np + +from qiskit import QuantumCircuit +from qiskit.evaluators.backends import ShotBackendWrapper, ShotResult +from qiskit.evaluators.results import ExpectationValueResult +from qiskit.opflow import AbelianGrouper, PauliSumOp +from qiskit.providers import BackendV1 as Backend +from qiskit.quantum_info import SparsePauliOp, Statevector +from qiskit.quantum_info.operators.base_operator import BaseOperator +from qiskit.result import Counts + +from .base_expectation_value import BaseExpectationValue + +logger = logging.getLogger(__name__) + + +class PauliExpectationValue(BaseExpectationValue): + """ + Evaluates expectation value using pauli rotation gates. + """ + + def __init__( + self, + state: Union[QuantumCircuit, Statevector], + observable: Union[BaseOperator, PauliSumOp], + backend: Union[Backend, ShotBackendWrapper], + grouping: bool = True, + ): + super().__init__( + state=state, + observable=observable, + backend=ShotBackendWrapper.from_backend(backend), + ) + self._grouping = grouping + + def _preprocessing( + self, state: QuantumCircuit, observable: SparsePauliOp + ) -> Union[list[QuantumCircuit], tuple[QuantumCircuit, list[QuantumCircuit]]]: + """ + Preprocessing for evaluation of expectation value using pauli rotation gates. + """ + diff_circuits: list[QuantumCircuit] = [] + if self._grouping: + for sumop in AbelianGrouper().convert(PauliSumOp(observable)).oplist: + op = cast(SparsePauliOp, sumop.primitive) + coeff = { + key: val.real.item() if np.isreal(val) else val.item() + for key, val in op.label_iter() + } + lst = [] + for paulis in zip(*coeff.keys()): + pauli_set = set(paulis) + pauli_set.discard("I") + lst.append(pauli_set.pop() if pauli_set else "I") + pauli = "".join(lst) + + circuit = QuantumCircuit(state.num_qubits, observable.num_qubits) + for i, val in enumerate(reversed(pauli)): + if val == "Y": + circuit.sdg(i) + if val in ["Y", "X"]: + circuit.h(i) + circuit.measure(i, i) + circuit.metadata = {"basis": pauli, "coeff": coeff} + diff_circuits.append(circuit) + else: + for pauli, coeff in observable.label_iter(): + circuit = QuantumCircuit(state.num_qubits, observable.num_qubits) + for i, val in enumerate(reversed(pauli)): + if val == "Y": + circuit.sdg(i) + if val in ["Y", "X"]: + circuit.h(i) + circuit.measure(i, i) + coeff = coeff.real.item() if np.isreal(coeff) else coeff.item() + circuit.metadata = {"basis": pauli, "coeff": coeff} + diff_circuits.append(circuit) + + return state.copy(), diff_circuits + + def _postprocessing(self, result: Union[ShotResult, dict]) -> ExpectationValueResult: + """ + Postprocessing for evaluation of expectation value using pauli rotation gates. + """ + if not isinstance(result, ShotResult): + raise TypeError(f"result must be ShotResult, not {type(result)}.") + + data = result.counts + metadata = result.metadata + + combined_expval = 0.0 + combined_variance = 0.0 + combined_stderr = 0.0 + + for datum, meta in zip(data, metadata): + basis = meta.get("basis", None) + coeff = meta.get("coeff", 1) + basis_coeff = coeff if isinstance(coeff, dict) else {basis: coeff} + for basis, coeff in basis_coeff.items(): + diagonal = _pauli_diagonal(basis) if basis is not None else None + # qubits = meta.get("qubits", None) + shots = sum(datum.values()) + + # Compute expval component + expval, var = _expval_with_variance(datum, diagonal=diagonal) + # Accumulate + combined_expval += expval * coeff + combined_variance += var * coeff ** 2 + combined_stderr += np.sqrt(max(var * coeff ** 2 / shots, 0.0)) + + return ExpectationValueResult( + combined_expval, + combined_variance, + (combined_expval - combined_stderr, combined_expval + combined_stderr), + ) + + +def _expval_with_variance( + counts: Counts, + diagonal: Optional[np.ndarray] = None, + # clbits: Optional[list[int]] = None, +) -> tuple[float, float]: + + # Marginalize counts + # if clbits is not None: + # counts = marginal_counts(counts, meas_qubits=clbits) + + # Get counts shots and probabilities + probs = np.fromiter(counts.values(), dtype=float) + shots = probs.sum() + probs = probs / shots + + # Get diagonal operator coefficients + if diagonal is None: + coeffs = np.array( + [(-1) ** (key.count("1") % 2) for key in counts.keys()], dtype=probs.dtype + ) + else: + keys = [int(key, 2) for key in counts.keys()] + coeffs = np.asarray(diagonal[keys], dtype=probs.dtype) + + # Compute expval + expval = coeffs.dot(probs) + + # Compute variance + if diagonal is None: + # The square of the parity diagonal is the all 1 vector + sq_expval = np.sum(probs) + else: + sq_expval = (coeffs ** 2).dot(probs) + variance = sq_expval - expval ** 2 + + # Compute standard deviation + if variance < 0: + if not np.isclose(variance, 0): + logger.warning( + "Encountered a negative variance in expectation value calculation." + "(%f). Setting standard deviation of result to 0.", + variance, + ) + variance = np.float64(0.0) + return expval.item(), variance.item() + + +def _pauli_diagonal(pauli: str) -> np.ndarray: + """Return diagonal for given Pauli. + + Args: + pauli: a pauli string. + + Returns: + np.ndarray: The diagonal vector for converting the Pauli basis + measurement into an expectation value. + """ + if pauli[0] in ["+", "-"]: + pauli = pauli[1:] + + diag = np.array([1]) + for i in reversed(pauli): + if i == "I": + tmp = np.array([1, 1]) + else: + tmp = np.array([1, -1]) + diag = np.kron(tmp, diag) + return diag diff --git a/qiskit/evaluators/expval_demoday.ipynb b/qiskit/evaluators/expval_demoday.ipynb new file mode 100644 index 000000000000..67624ba5ba40 --- /dev/null +++ b/qiskit/evaluators/expval_demoday.ipynb @@ -0,0 +1,815 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "21e62c44", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# New expectation value design PoC\n", + "\n", + "[Qiskit Demoday Sep 16](https://github.com/qiskit-community/feedback/wiki/DemoDay#sep-16-2021)\n", + "\n", + "Takashi Imamichi and Ikko Hamamura (IBM Research - Tokyo)" + ] + }, + { + "cell_type": "markdown", + "id": "a02345fd", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Motivation\n", + "\n", + "We propose a simple and generic interface for expectation values and their gradients.\n", + "The current workflow with opflow to get an expectation value is as follows.\n", + "```python\n", + "state = StateFn(...) # can be a circuit-based state or defined via a statevector or dictionary\n", + "operator = ... # some opflow operator, e.g. PauliSumOp\n", + "expectation = StateFn(operator, is_measurement=True) @ state\n", + "expectation_converter = PauliExpectation # method to evaluate the expected value, e.g. PauliExpectation, CVaRExpectation, AerPauliExpectation, ...\n", + "circuit_sampler = CircuitSampler(backend)\n", + "converted = expectation_converter.convert(expectation) \n", + "sampled = circuit_sampler.convert(converted, parameters)\n", + "result = sampled.eval()\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "aa82e846", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "We propose a new design of the expectation value to make it generic and simple.\n", + "Essentially, we aim at the following workflow.\n", + "\n", + "```python\n", + "operator = ... # some opflow operator, e.g. PauliSumOp\n", + "state = ... # a parametrized quantum circuit (or ansatz)\n", + "backend = ... # AerBackend or IBMQBackend\n", + "expval = PauliExpectationValue(state, operator, backend)\n", + "result = expval.evaluate(parameters).value\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "b78a5565", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Outline of the new design\n", + "\n", + "We propose an abstract class for expectation value and gradient.\n", + "An instance will be initialized with the following objects:\n", + "\n", + "- `state` $\\psi(\\theta)$: a (parametrized) quantum circuit or a state vector to be converted into a quantum circuit.\n", + "- `observable` $H$: we allow opflow `PauliSumOp` (primitive is `SparsePauliOp`) or quantum_info operator `BaseOperator` that is compatible with `SparsePauliOp` for simplicity.\n", + "- `backend`: Either `IBMQBackend` or `AerSimulator`. We don't support legacy simulator backends and BasicAer.\n", + "- (optional) `expval`: take an expectation value object as an input (e.g., gradient)\n", + "\n", + "Users use `ExpectationValue.evaluate(parameters)` to obtain the expectation value.\n", + "\n", + "Instances of our expectation value classes are immutable.\n", + "Users need to invoke the constructor to evaluate the expectation value of different states or observables." + ] + }, + { + "cell_type": "markdown", + "id": "63eaef98", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "The internal workflow consists of phases:\n", + "\n", + "1. `ExpectationValue._preprocessing` generates quantum circuits corresponding to the pair of quantum state and observable. The circuits maybe left parametrized. This will be invoked on demand to avoid overhead of the constructor.\n", + "2. `ExpectationValue.evaluate(parameters)` transpiles quantum circuits (if necessary), puts parameter values to the transpiled circuits, and executes them on the backend.\n", + "3. `ExpectationValue._postprocessing` interprets the results of the backend into an expectation value and other information as `ExpectationValueResult`.\n", + "\n", + "Note: we allow `ExpectationValue.evaluate(parameters)` to process a set of parameters and the output will be `ExpectationValueArrayResult`. See an example later.\n", + "\n", + "`ExpectationValueGradient` may have the same interface and/or it may take `ExpectationValue` object as an input of the constructor." + ] + }, + { + "cell_type": "markdown", + "id": "8765e853", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Demo" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "05da73c4", + "metadata": { + "slideshow": { + "slide_type": "skip" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "fc97bb99", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6104c3e9", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "observable\n", + "-1.052373245772859 * II\n", + "+ 0.39793742484318045 * IZ\n", + "- 0.39793742484318045 * ZI\n", + "- 0.01128010425623538 * ZZ\n", + "+ 0.18093119978423156 * XX\n", + "\n", + "ansatz\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.circuit.library import RealAmplitudes\n", + "from qiskit.opflow import PauliSumOp\n", + "\n", + "observable = PauliSumOp.from_list(\n", + " [\n", + " (\"II\", -1.052373245772859),\n", + " (\"IZ\", 0.39793742484318045),\n", + " (\"ZI\", -0.39793742484318045),\n", + " (\"ZZ\", -0.01128010425623538),\n", + " (\"XX\", 0.18093119978423156),\n", + " ]\n", + ")\n", + "print(\"observable\")\n", + "print(observable)\n", + "\n", + "ansatz = RealAmplitudes(num_qubits=2, reps=2)\n", + "print(\"\\nansatz\")\n", + "ansatz.decompose().draw(\"mpl\")" + ] + }, + { + "cell_type": "markdown", + "id": "3e5bc903", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## ExpectationValue class" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2dd0c134", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators import PauliExpectationValue" + ] + }, + { + "cell_type": "markdown", + "id": "01eba673", + "metadata": {}, + "source": [ + "### PauliExpectationValue\n", + "\n", + "Evaluate the expectation value by sampling. This supports both AerSimulator and IBMQ backends." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "578ae95d", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.providers.aer import AerSimulator\n", + "\n", + "backend = AerSimulator()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "624c2fc9", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.3045851234732189, variance=0.2985086690184938, confidence_interval=(-1.3335981061414726, -1.2755721408049652))" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5], shots=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "18535167", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueArrayResult(values=array([-1.28753097, -1.32096817]), variances=array([0.30054645, 0.24197059]), confidence_intervals=array([[-1.30433766, -1.27072428],\n", + " [-1.33568567, -1.30625067]]))" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# multi prameters\n", + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate([[0, 1, 1, 2, 3, 5], [1, 1, 2, 3, 5, 8]], shots=3000)" + ] + }, + { + "cell_type": "markdown", + "id": "257787d2", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Exact simulation by SaveExpectationValueVariance" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e602573e", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators import ExactExpectationValue" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a795bd78", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.2843665118617325, variance=0.26528532962023577, confidence_interval=None)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = ExactExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "60687fe8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueArrayResult(values=array([-1.28436651, -1.31875263]), variances=array([0.26528533, 0.42691205]), confidence_intervals=array([None, None], dtype=object))" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = ExactExpectationValue(ansatz, observable, backend=backend)\n", + "expval.evaluate(np.array([[0, 1, 1, 2, 3, 5], [1, 1, 2, 3, 5, 8]]))" + ] + }, + { + "cell_type": "markdown", + "id": "1c94c403", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Transpiled Circuits" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3e1a8842", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ExpectationValueResult(value=-1.2270449811062014, variance=0.3261140003605256, confidence_interval=(-1.2569617757694307, -1.1971281864429721))\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit.test.mock import FakeBogota\n", + "\n", + "backend = AerSimulator.from_backend(FakeBogota())\n", + "\n", + "expval = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval.set_transpile_options(initial_layout=[3, 2])\n", + "print(expval.evaluate([0, 1, 1, 2, 3, 5]))\n", + "expval.transpiled_circuits[0].draw(\"mpl\")" + ] + }, + { + "cell_type": "markdown", + "id": "9185b9ae", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Large number of shots" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "620b76bb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "max_shots 8192\n", + "Number of shots specified: 10000 exceeds max_shots property of the backend: 8192.\n" + ] + } + ], + "source": [ + "try:\n", + " from qiskit import QuantumCircuit, QiskitError\n", + " qc = QuantumCircuit(1, 1)\n", + " qc.h(0)\n", + " qc.measure(0, 0)\n", + " from qiskit import IBMQ\n", + " prov = IBMQ.load_account()\n", + " ibmq_qasm_sim = prov.get_backend('ibmq_qasm_simulator')\n", + " print(f\"max_shots {backend.configuration().max_shots}\")\n", + " ibmq_qasm_sim.run(qc, shots=10000).result().get_counts()\n", + "except QiskitError as ex:\n", + " print(ex.message)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "9cb73555", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ExpectationValueResult(value=-1.28629134229759, variance=0.3013702509749989, confidence_interval=(-1.2955064759928994, -1.2770762086022804))" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expval = PauliExpectationValue(ansatz, observable, backend=ibmq_qasm_sim)\n", + "expval.evaluate([0, 1, 1, 2, 3, 5], shots=10000)" + ] + }, + { + "cell_type": "markdown", + "id": "88234028", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Readout error mitigation" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "c992bb1f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "w/o mitigation shots=4000, result=ExpectationValueResult(value=-1.2595981522160702, variance=0.3167834517853961, confidence_interval=(-1.2745298670322645, -1.244666437399876))\n", + "w/ tensored mitigation shots=4000, result=ExpectationValueResult(value=-1.2774601799810748, variance=0.3030202762495204, confidence_interval=(-1.292072288559631, -1.2628480714025185))\n", + "w/ M3 mitigation shots=4000, result=ExpectationValueResult(value=-1.274027046504209, variance=0.3045704741174017, confidence_interval=(-1.2886772367653694, -1.2593768562430485))\n" + ] + } + ], + "source": [ + "from qiskit.evaluators.backends import ReadoutErrorMitigation\n", + "\n", + "backend = AerSimulator.from_backend(FakeBogota())\n", + "mit_tensored = ReadoutErrorMitigation(\n", + " backend, mitigation=\"tensored\", refresh=600, shots=2000, mit_pattern=[[0], [1]]\n", + ")\n", + "mit_mthree = ReadoutErrorMitigation(\n", + " backend, mitigation=\"mthree\", refresh=600, shots=2000, qubits=[0, 1]\n", + ")\n", + "expval_raw = PauliExpectationValue(ansatz, observable, backend=backend)\n", + "expval_tensored = PauliExpectationValue(ansatz, observable, backend=mit_tensored)\n", + "expval_mthree = PauliExpectationValue(ansatz, observable, backend=mit_mthree)\n", + "shots = 4000\n", + "print(f\"w/o mitigation shots={shots}, result={expval_raw.evaluate([0, 1, 1, 2, 3, 5], shots=shots)}\")\n", + "print(f\"w/ tensored mitigation shots={shots}, result={expval_tensored.evaluate([0, 1, 1, 2, 3, 5], shots=shots)}\")\n", + "print(f\"w/ M3 mitigation shots={shots}, result={expval_mthree.evaluate([0, 1, 1, 2, 3, 5], shots=shots)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "ce3810ee", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Gradient of expectation value" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "3070586b", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.evaluators.expectation_value.expectation_value_gradient import (\n", + " FiniteDiffGradient,\n", + " ParameterShiftGradient,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "06c9d4ac", + "metadata": { + "slideshow": { + "slide_type": "subslide" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fin diff of exact [ 0.28213347 0.42656751 0.20442583 0.42656749 -0.17291453 0.0589814 ]\n", + "param shift of exact [ 0.28213349 0.42656754 0.20442588 0.42656754 -0.17291452 0.05898141]\n", + "fin diff w/o mit [ 0.16262713 0.4314544 0.34752583 0.24589932 -0.12426491 0.28484219]\n", + "param shift w/o mit [ 0.24911042 0.3794629 0.17450169 0.38138296 -0.14381146 0.05720959]\n", + "fin diff w/ mit [ 0.47428411 0.28015226 0.39108048 0.59261647 -0.07708405 0.07528248]\n", + "param shift w/ mit [ 0.27310091 0.40288055 0.20674927 0.41180033 -0.16378474 0.05274286]\n" + ] + } + ], + "source": [ + "parameters = [0, 1, 1, 2, 3, 5]\n", + "\n", + "exact_expval = ExactExpectationValue(ansatz, observable, backend=AerSimulator())\n", + "exact_findiff = FiniteDiffGradient(exact_expval, 1e-8)\n", + "print(f\"fin diff of exact {exact_findiff.evaluate(parameters).values}\")\n", + "\n", + "exact_expval = ExactExpectationValue(ansatz, observable, backend=AerSimulator())\n", + "exact_findiff = ParameterShiftGradient(exact_expval)\n", + "print(f\"param shift of exact {exact_findiff.evaluate([0, 1, 1, 2, 3, 5]).values}\")\n", + "\n", + "shots = 2000\n", + "findiff = FiniteDiffGradient(expval_raw, 1e-1)\n", + "paramshift = ParameterShiftGradient(expval_raw)\n", + "print(f\"fin diff w/o mit {findiff.evaluate(parameters, shots=shots).values}\")\n", + "print(f\"param shift w/o mit {paramshift.evaluate(parameters, shots=shots).values}\")\n", + "\n", + "findiff = FiniteDiffGradient(expval_mthree, 1e-1)\n", + "paramshift = ParameterShiftGradient(expval_mthree)\n", + "print(f\"fin diff w/ mit {findiff.evaluate([0, 1, 1, 2, 3, 5], shots=shots).values}\")\n", + "print(f\"param shift w/ mit {paramshift.evaluate(parameters, shots=shots).values}\")" + ] + }, + { + "cell_type": "markdown", + "id": "ced77786", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### VQE by Scipy optimizer" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "7dd56dfc", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " fun: -1.847151931688854\n", + " hess_inv: array([[ 1.81424069e+00, -7.89703086e-01, -5.73244156e-01,\n", + " -2.21914037e-01, 5.87909808e-01, 4.22230305e-01],\n", + " [-7.89703086e-01, 1.55393010e+00, 1.62068458e-01,\n", + " 6.68346234e-02, -6.46365845e-01, -6.41520197e-01],\n", + " [-5.73244156e-01, 1.62068458e-01, 1.89981547e+00,\n", + " -1.39292826e-03, -7.06428492e-01, -1.19853898e-01],\n", + " [-2.21914037e-01, 6.68346234e-02, -1.39292826e-03,\n", + " 8.57102253e-01, -1.72732718e-01, -1.63459541e-01],\n", + " [ 5.87909808e-01, -6.46365845e-01, -7.06428492e-01,\n", + " -1.72732718e-01, 1.49153981e+00, 4.65053775e-01],\n", + " [ 4.22230305e-01, -6.41520197e-01, -1.19853898e-01,\n", + " -1.63459541e-01, 4.65053775e-01, 1.12790465e+00]])\n", + " jac: array([-0.02623533, 0.01379811, -0.00251373, 0.02619514, 0.01860486,\n", + " -0.01356285])\n", + " message: 'Desired error not necessarily achieved due to precision loss.'\n", + " nfev: 69\n", + " nit: 9\n", + " njev: 57\n", + " status: 2\n", + " success: False\n", + " x: array([-0.83416504, 1.17090196, -1.50548417, 0.83722648, -0.88745376,\n", + " -1.0932899 ])\n" + ] + } + ], + "source": [ + "from scipy.optimize import minimize\n", + "\n", + "shots = 1000\n", + "expval = PauliExpectationValue(ansatz, observable, backend=AerSimulator(), append=True)\n", + "paramshift = ParameterShiftGradient(expval)\n", + "# this may take a long time...\n", + "result = minimize(\n", + " lambda x: expval.evaluate(x, shots=shots, seed_simulator=123).value,\n", + " np.zeros(6),\n", + " jac=lambda x: paramshift.evaluate(x, shots=shots, seed_simulator=123).values,\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "71a0aed0", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "from qiskit.evaluators.results import ExpectationValueResult\n", + "\n", + "plt.figure(figsize=(12, 8))\n", + "y = [h.value for h in expval.history if isinstance(h, ExpectationValueResult)]\n", + "x = list(range(len(y)))\n", + "yerr = np.array(\n", + " [tuple(abs(c - h.value) for c in h.confidence_interval) for h in expval.history if isinstance(h, ExpectationValueResult)]\n", + ").transpose()\n", + "plt.plot(y, color=\"blue\")\n", + "plt.errorbar(x, y, yerr=yerr, capsize=5, fmt=\"o\", markersize=8, ecolor=\"blue\", markeredgecolor=\"blue\", color=\"w\")\n", + "plt.xlabel(\"Eval count\")\n", + "plt.ylabel(\"Energy\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "3d35b5d6", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Current status\n", + "\n", + "The following classes and features have been implemented.\n", + "\n", + "Expectation value classes\n", + "- `PauliExpectationValue`: expectation value for shot-based backends (both AerBackend and IBMQBackend) \n", + "- `ExactExpectationValue`: exact expectation value with `SaveExpectationValueVariance` instruction supported only by Aer\n", + "\n", + "Gradient of expectation value classes\n", + "- `FiniteDiffGradient`: finite difference gradient\n", + "- `ParameterShiftGradient`: parameter shift rule for the simple cases (parameters appears only once and they have coefficient 1)" + ] + }, + { + "cell_type": "markdown", + "id": "e2691314", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Features\n", + "- Separate transpilation of ansatz and Pauli strings\n", + " - A parameterized circuit corresponding to an ansatz is usually shared by Pauli strings that comprise the observable. This technique reduces the duplicate transpile of the shared part.\n", + "- Take a history of evaluations so that users can make a plot of optimization\n", + " - Optimization algorithms e.g., [Scipy.optimize.minimize](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html), should take care of the history. But, [OptimizeResult](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.OptimizeResult.html#scipy.optimize.OptimizeResult) is not enough to include variance and confidence interval of expectation values.\n", + "- Backend wrapper\n", + " - Retry of job submission in case of cancel and/or network error\n", + " - Split circuits if the size is larger than `max_experiments`\n", + " - Copy circutis to realize users-set `shots` that is more than `max_shots`\n", + " - Readout error mitigation (tensored, complete, M3)\n", + " - Periodical calibration, e.g., calibration every 30 minutes" + ] + }, + { + "cell_type": "markdown", + "id": "1a9eb6c2", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Questions\n", + "- Why does expval take care of backend as backend wrapper?\n", + " - `QuantumInstance` of terra and `IBMQJobManager` (ManagedJob) of IBMQ provider can take care of only the split of circuits to satisfy `max_experiments`. But, as far as we know, there is no feature to realize `shots` more than `max_shots`. If this feature is implemented as part of IBMQ provider, it cannot be used for other backends, e.g., AQT and IonQ. Should it be part of terra?\n", + " - We experimentally }implemented preemptive readout error mitigation calibration, i.e., we put the calibration job between a set of jobs generated by the split or copy of circuits" + ] + }, + { + "cell_type": "markdown", + "id": "3a4a436b", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "TODOs\n", + "- Finalize the interface of the design\n", + "- Make a PR of the first release of the expectation value\n", + "\n", + "Ultimate goals (not necessarily inclueded as part of the first PR)\n", + "- Grouping algorithms of operators, AbelienGrouper (tensor product basis grouper) and grouper with entanglement measurements\n", + "- Better gradient support (maybe based on Opflow gradient)\n", + "- Qiskit Runtime support\n", + "- Gate error mitigation, e.g., zero noise extrapolation\n", + "- Classical shadow\n", + "- Entanglement forging\n", + "- On-chip parallelization\n", + "- Bootstrap (sampling from probability distribution obtained from backend)\n", + "- Merge shots (execute the same circuits again and merge the shots to realize a larger number of shots)" + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "interpreter": { + "hash": "55198b233f406dc59b712acd847cdd7a571fa057c585d106ba05aad0d31ffb93" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qiskit/evaluators/fidelity.py b/qiskit/evaluators/fidelity.py new file mode 100644 index 000000000000..a7787c0abf87 --- /dev/null +++ b/qiskit/evaluators/fidelity.py @@ -0,0 +1,35 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Fidelity +""" +from .framework.base_evaluator import BaseEvaluator + + +class Fidelity(BaseEvaluator): + """ + The class evaluates the fidelity of two states. + """ + + # pylint: disable=unused-argument + def __init__(self, state1, state2, backend, postprocessing): + """ + TODO: write docstring + """ + super().__init__(backend, postprocessing) + pass + + def evaluate(self, parameters=None, **run_options): + """ + TODO + """ + pass diff --git a/qiskit/evaluators/framework/__init__.py b/qiskit/evaluators/framework/__init__.py new file mode 100644 index 000000000000..47e8b2cf6f7a --- /dev/null +++ b/qiskit/evaluators/framework/__init__.py @@ -0,0 +1,19 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Framework for evaluator classes. +""" + +from .base_evaluator import BaseEvaluator +from .composite import JointEvaluator +from .history_evaluator import HistoryEvaluator +from .transpiled_circuit_evaluator import TranspiledCircuitEvaluator diff --git a/qiskit/evaluators/framework/base_evaluator.py b/qiskit/evaluators/framework/base_evaluator.py new file mode 100644 index 000000000000..783a4588560d --- /dev/null +++ b/qiskit/evaluators/framework/base_evaluator.py @@ -0,0 +1,241 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Evaluator class base class +""" +from __future__ import annotations + +import copy +from abc import ABC, abstractmethod +from typing import Any, Optional, Union, cast + +import numpy as np + +from qiskit import QuantumCircuit, transpile +from qiskit.evaluators.backends import ( + BackendWrapper, + BaseBackendWrapper, + ShotBackendWrapper, + ShotResult, +) +from qiskit.evaluators.results import CompositeResult +from qiskit.evaluators.results.base_result import BaseResult +from qiskit.providers import BackendV1 as Backend +from qiskit.providers import Options +from qiskit.result import Result + +PreprocessedCircuits = Union[list[QuantumCircuit], tuple[QuantumCircuit, list[QuantumCircuit]]] + + +class BaseEvaluator(ABC): + """ + Base class for evaluator. + """ + + def __init__( + self, + backend: Union[Backend, BaseBackendWrapper], + transpile_options: Optional[dict] = None, + ): + """ + Args: + backend: backend + """ + self._backend: BaseBackendWrapper + if isinstance(backend, ShotBackendWrapper): + self._backend = backend + else: + self._backend = BackendWrapper.from_backend(backend) + self._run_options = Options() + + self._transpile_options = Options() + if transpile_options is not None: + self.set_transpile_options(**transpile_options) + + self._preprocessed_circuits: Optional[PreprocessedCircuits] = None + self._transpiled_circuits: Optional[list[QuantumCircuit]] = None + + @property + def run_options(self) -> Options: + """Return options values for the evaluator. + Returns: + run_options + """ + return self._run_options + + def set_run_options(self, **fields) -> BaseEvaluator: + """Set options values for the evaluator. + + Args: + fields: The fields to update the options + Returns: + self + """ + self._run_options.update_options(**fields) + return self + + @property + def transpile_options(self) -> Options: + """Return the transpiler options for transpiling the circuits.""" + return self._transpile_options + + def set_transpile_options(self, **fields) -> BaseEvaluator: + """Set the transpiler options for transpiler. + Args: + fields: The fields to update the options + Returns: + self + """ + self._preprosessed_circuits = None + self._transpile_options.update_options(**fields) + return self + + @property + def backend(self) -> Backend: + """Backend + + Returns: + backend + """ + return self._backend.backend + + @property + def preprocessed_circuits(self) -> Optional[PreprocessedCircuits]: + """ + Preprocessed quantum circuits produced by preprocessing + + Returns: + List of the transpiled quantum circuit + """ + return self._preprocessed_circuits + + @property + def transpiled_circuits(self) -> list[QuantumCircuit]: + """ + Transpiled quantum circuits. + + Returns: + List of the transpiled quantum circuit + """ + if self._transpiled_circuits is None: + self._transpile() + return self._transpiled_circuits + + def evaluate( + self, + parameters: Optional[ + Union[ + list[float], + list[list[float]], + np.ndarray[Any, np.dtype[np.float64]], + ] + ] = None, + **run_options, + ) -> BaseResult: + """ + TODO + """ + # Bind parameters + # TODO: support Aer parameter bind after https://github.com/Qiskit/qiskit-aer/pull/1317 + if parameters is None: + bound_circuits = self.transpiled_circuits + else: + parameters = np.asarray(parameters, dtype=np.float64) + if parameters.ndim == 1: + bound_circuits = [ + circ.bind_parameters(parameters) # type: ignore + for circ in self.transpiled_circuits + ] + elif parameters.ndim == 2: + bound_circuits = [ + circ.bind_parameters(parameter) + for parameter in parameters + for circ in self.transpiled_circuits + ] + else: + raise TypeError("The number of array dimension must be 1 or 2.") + + # Run + run_opts = copy.copy(self.run_options) + run_opts.update_options(**run_options) + + results = self._backend.run_and_wait(bound_circuits, **run_opts.__dict__) + + if parameters is None or isinstance(parameters, np.ndarray) and parameters.ndim == 1: + if isinstance(results, Result): + ret_result = self._postprocessing(results.data(0)) + else: + ret_result = self._postprocessing(results) + else: + + if isinstance(results, Result): + postprocessed = [ + self._postprocessing(results.data(i)) for i in range(len(parameters)) + ] + else: + postprocessed = [ + self._postprocessing( + results[ + i + * len(self.transpiled_circuits) : (i + 1) + * len(self.transpiled_circuits) + ] + ) + for i in range(len(parameters)) + ] + ret_result = CompositeResult(postprocessed) + + return ret_result + + def _transpile(self): + if isinstance(self.preprocessed_circuits, tuple): + # 1. transpile a common circuit + transpiled_state = self.preprocessed_circuits[0].copy() + num_qubits = transpiled_state.num_qubits + transpiled_state.measure_all() + transpiled_state = cast( + QuantumCircuit, + transpile(transpiled_state, self.backend, **self.transpile_options.__dict__), + ) + bit_map = {bit: index for index, bit in enumerate(transpiled_state.qubits)} + layout = [bit_map[qr[0]] for _, qr, _ in transpiled_state[-num_qubits:]] + transpiled_state.remove_final_measurements() + # 2. transpile diff circuits + diff_circuits = self.preprocessed_circuits[1] + transpile_opts = copy.copy(self.transpile_options) + transpile_opts.update_options(initial_layout=layout) + diff_circuits = cast( + list[QuantumCircuit], + transpile(diff_circuits, self.backend, **transpile_opts.__dict__), + ) + # 3. combine + transpiled_circuits = [] + for diff_circuit in diff_circuits: + transpiled_circuit = transpiled_state.copy() + for creg in diff_circuit.cregs: + if creg not in transpiled_circuit.cregs: + transpiled_circuit.add_register(creg) + transpiled_circuit.compose(diff_circuit, inplace=True) + transpiled_circuit.metadata = diff_circuit.metadata + transpiled_circuits.append(transpiled_circuit) + self._transpiled_circuits = transpiled_circuits + else: + self._transpiled_circuits = cast( + list[QuantumCircuit], + transpile( + self.preprocessed_circuits, self.backend, **self.transpile_options.__dict__ + ), + ) + + @abstractmethod + def _postprocessing(self, result: Union[ShotResult, dict]) -> BaseResult: + return NotImplemented diff --git a/qiskit/evaluators/framework/composite/__init__.py b/qiskit/evaluators/framework/composite/__init__.py new file mode 100644 index 000000000000..3dcdf483f335 --- /dev/null +++ b/qiskit/evaluators/framework/composite/__init__.py @@ -0,0 +1,16 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Framework for composite evaluator classes. +""" + +from .joint_evaluator import JointEvaluator diff --git a/qiskit/evaluators/framework/composite/joint_evaluator.py b/qiskit/evaluators/framework/composite/joint_evaluator.py new file mode 100644 index 000000000000..5a307e19aa22 --- /dev/null +++ b/qiskit/evaluators/framework/composite/joint_evaluator.py @@ -0,0 +1,109 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Joint evaluator class +""" + +from __future__ import annotations + +import copy +from typing import TYPE_CHECKING, Optional, Union + +import numpy as np + +from qiskit.evaluators.backends import ShotResult +from qiskit.evaluators.framework.base_evaluator import BaseEvaluator +from qiskit.evaluators.results import CompositeResult +from qiskit.evaluators.results.base_result import BaseResult + +if TYPE_CHECKING: + from typing import Any + + +class JointEvaluator(BaseEvaluator): + """Joint Evaluator""" + + def __init__(self, evaluators: list[BaseEvaluator]): + """hoge""" + + self._evaluators = evaluators + + self._counter = 0 + super().__init__(evaluators[0]._backend) + + for evaluator in evaluators: + if evaluator.backend != self.backend: + raise ValueError("") + # Should we update the run_options? + # self.run_options.update_options(**evaluator.run_options.__dict__) + + @property + def transpiled_circuits(self): + if self._transpiled_circuits is None: + self._transpiled_circuits = sum( + [evaluator.transpiled_circuits for evaluator in self._evaluators], [] + ) + return self._transpiled_circuits + + def _postprocessing(self, result: Union[dict, ShotResult]) -> BaseResult: + current_counter = self._counter + self._counter += 1 + if self._counter == len(self._evaluators): + self._counter = 0 + return self._evaluators[current_counter]._postprocessing(result) + + def evaluate( + self, + parameters: Optional[ + Union[ + list[float], + list[list[float]], + "np.ndarray[Any, np.dtype[np.float64]]", + ] + ] = None, + **run_options, + ) -> CompositeResult: + run_opts = copy.copy(self.run_options) + run_opts.update_options(**run_options) + run_opts_dict = run_opts.__dict__ + + if len(parameters) != len(self._evaluators): + raise TypeError("Length is different.") + + if parameters is None: + circuits = self.transpiled_circuits + else: + parameters = np.asarray(parameters, dtype=np.float64) + if parameters.ndim == 2: + circuits = [ + circ.bind_parameters(param) + for param in parameters + for evaluator in self._evaluators + for circ in evaluator.transpiled_circuits + ] + elif parameters.ndim == 1: + circuits = [ + circ.bind_parameters(parameters) # type: ignore + for evaluator in self._evaluators + for circ in evaluator.transpiled_circuits + ] + + results = self._backend.run_and_wait(circuits, **run_opts_dict) + + accum = 0 + postprocessed = [] + for evaluator in self._evaluators: + postprocessed.append( + self._postprocessing(results[accum : accum + len(evaluator.preprocessed_circuits)]) + ) + + return CompositeResult(postprocessed) diff --git a/qiskit/evaluators/framework/history_evaluator.py b/qiskit/evaluators/framework/history_evaluator.py new file mode 100644 index 000000000000..f8bf85ea8272 --- /dev/null +++ b/qiskit/evaluators/framework/history_evaluator.py @@ -0,0 +1,71 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Evaluator with history +""" +from __future__ import annotations + +from typing import Any, Optional, Union + +import numpy as np + +from qiskit.evaluators.backends import ShotResult +from qiskit.evaluators.results.base_result import BaseResult + +from .base_evaluator import BaseEvaluator, PreprocessedCircuits + + +class HistoryEvaluator(BaseEvaluator): + """Evaluator with history""" + + def __init__(self, evaluator: BaseEvaluator): + """ + Args: + evaluator: + """ + super().__init__( + backend=evaluator._backend, transpile_options=evaluator.transpile_options.__dict__ + ) + self._evaluator = evaluator + self._history: list[BaseResult] = [] + + @property + def history(self) -> list[BaseResult]: + """History of evaluation. + + Return: + history + """ + return self._history + + def evaluate( + self, + parameters: Optional[ + Union[ + list[float], + list[list[float]], + np.ndarray[Any, np.dtype[np.float64]], + ] + ] = None, + **run_options, + ) -> BaseResult: + + result = super().evaluate(parameters, **run_options) + self._history.append(result) + return result + + @property + def preprocessed_circuits(self) -> PreprocessedCircuits: + return self._evaluator.preprocessed_circuits + + def _postprocessing(self, result: Union[ShotResult, dict]) -> BaseResult: + return self._evaluator._postprocessing(result) diff --git a/qiskit/evaluators/framework/runtime_evaluator.py b/qiskit/evaluators/framework/runtime_evaluator.py new file mode 100644 index 000000000000..22d69eda487e --- /dev/null +++ b/qiskit/evaluators/framework/runtime_evaluator.py @@ -0,0 +1,76 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Evaluator on Qiskit Runtime +""" +from __future__ import annotations + +from base64 import b64decode, b64encode +from typing import Any, Optional, Union + +import numpy as np +from dill import dumps, loads + +from qiskit.evaluators.backends import ShotResult +from qiskit.evaluators.results.base_result import BaseResult + +from .base_evaluator import BaseEvaluator, PreprocessedCircuits + + +class RuntimeEvaluator(BaseEvaluator): + """Evaluator on runtime""" + + def __init__(self, evaluator: BaseEvaluator, provider): + """ + Args: + evaluator: + """ + super().__init__( + backend=evaluator._backend, transpile_options=evaluator.transpile_options.__dict__ + ) + self._evaluator = evaluator + self._provider = provider + + def evaluate( + self, + parameters: Optional[ + Union[ + list[float], + list[list[float]], + np.ndarray[Any, np.dtype[np.float64]], + ] + ] = None, + **run_options, + ) -> BaseResult: + # transpile + if self._transpiled_circuits is None + self.transpiled_circuits + + runtime_inputs = { + "evaluator": b64encode(dumps(self._evaluator)).decode(), + "parameters": b64encode(dumps(parameters)).decode(), + "run_options": b64encode(dumps(run_options)).decode(), + } + options = {"backend_name": self._evaluator.backend.name()} + + job = self._provider.runtime.run( + program_id="runtime-evaluator", options=options, inputs=runtime_inputs + ) + result = loads(b64decode(job.result())) + return result + + @property + def preprocessed_circuits(self) -> PreprocessedCircuits: + return self._evaluator.preprocessed_circuits + + def _postprocessing(self, result: Union[ShotResult, dict]) -> BaseResult: + return self._evaluator._postprocessing(result) diff --git a/qiskit/evaluators/framework/transpiled_circuit_evaluator.py b/qiskit/evaluators/framework/transpiled_circuit_evaluator.py new file mode 100644 index 000000000000..8ba41d274b5a --- /dev/null +++ b/qiskit/evaluators/framework/transpiled_circuit_evaluator.py @@ -0,0 +1,64 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Evaluator class base class +""" +from __future__ import annotations + +import sys +from typing import Union + +from qiskit import QuantumCircuit +from qiskit.evaluators.backends import ( + BaseBackendWrapper, + ShotBackendWrapper, + ShotResult, +) +from qiskit.evaluators.results.base_result import BaseResult +from qiskit.providers import BackendV1 as Backend + +from .base_evaluator import BaseEvaluator + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from typing_extensions import Protocol + + +class Postprocessing(Protocol): + """Postprocessing Callback Protocol (PEP544)""" + + def __call__(self, result: Union[ShotResult, dict]) -> BaseResult: + ... + + +class TranspiledCircuitEvaluator(BaseEvaluator): + """ + Evaluator for transpiled circuits. + """ + + def __init__( + self, + transpiled_circuits: list[QuantumCircuit], + postprocessing: Postprocessing, + backend: Union[Backend, BaseBackendWrapper, ShotBackendWrapper], + ): + """ + Args: + backend: backend + """ + super().__init__(backend=backend) + self._injected_postprocessing = postprocessing + self._transpiled_circuits = transpiled_circuits + + def _postprocessing(self, result) -> BaseResult: + return self._injected_postprocessing(result) diff --git a/qiskit/evaluators/histogram.py b/qiskit/evaluators/histogram.py new file mode 100644 index 000000000000..5775157764ba --- /dev/null +++ b/qiskit/evaluators/histogram.py @@ -0,0 +1,34 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Histogram +""" +from .framework.base_evaluator import BaseEvaluator + + +class Histogram(BaseEvaluator): + """ + This class evaluates histogram. + """ + + def __init__(self, backend, postprocessing): + """ + TODO + """ + super().__init__(backend, postprocessing) + pass + + def evaluate(self, parameters=None, **run_options): + """ + TODO + """ + pass diff --git a/qiskit/evaluators/results/__init__.py b/qiskit/evaluators/results/__init__.py new file mode 100644 index 000000000000..9eacf44a5fd3 --- /dev/null +++ b/qiskit/evaluators/results/__init__.py @@ -0,0 +1,18 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Result classes for evaluators.""" + +from .composite_result import CompositeResult +from .expectation_value_array_result import ExpectationValueArrayResult +from .expectation_value_gradient_result import ExpectationValueGradientResult +from .expectation_value_result import ExpectationValueResult diff --git a/qiskit/evaluators/results/base_result.py b/qiskit/evaluators/results/base_result.py new file mode 100644 index 000000000000..af688c5d0bf6 --- /dev/null +++ b/qiskit/evaluators/results/base_result.py @@ -0,0 +1,28 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Base result class +""" + +from abc import ABC +from dataclasses import dataclass + + +class BaseResult(ABC): + """ + Base result class + """ + + # pylint: disable=unused-argument + def __new__(cls, *args, **kwargs): + dataclass(cls) + return super().__new__(cls) diff --git a/qiskit/evaluators/results/composite_result.py b/qiskit/evaluators/results/composite_result.py new file mode 100644 index 000000000000..b4a251a38f15 --- /dev/null +++ b/qiskit/evaluators/results/composite_result.py @@ -0,0 +1,25 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Composite result class +""" + + +from .base_result import BaseResult + + +class CompositeResult(BaseResult): + """ + Composite Result + """ + + items: list[BaseResult] diff --git a/qiskit/evaluators/results/expectation_value_array_result.py b/qiskit/evaluators/results/expectation_value_array_result.py new file mode 100644 index 000000000000..0b492e77525c --- /dev/null +++ b/qiskit/evaluators/results/expectation_value_array_result.py @@ -0,0 +1,34 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value array result class +""" + +from __future__ import annotations + +from typing import Any + +import numpy as np + +from .base_result import BaseResult + + +class ExpectationValueArrayResult(BaseResult): + """ + Result of ExpectationValue + #TODO doc + """ + + values: np.ndarray[Any, np.dtype[np.float64]] + variances: np.ndarray[Any, np.dtype[np.float64]] + confidence_intervals: np.ndarray[Any, np.dtype[np.float64]] + # metadata: Metadata diff --git a/qiskit/evaluators/results/expectation_value_gradient_result.py b/qiskit/evaluators/results/expectation_value_gradient_result.py new file mode 100644 index 000000000000..b723fa188612 --- /dev/null +++ b/qiskit/evaluators/results/expectation_value_gradient_result.py @@ -0,0 +1,30 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value gradient result class +""" + +from __future__ import annotations + +import numpy as np + +from .base_result import BaseResult + + +class ExpectationValueGradientResult(BaseResult): + """ + Result of ExpectationValueGradient + #TODO doc + """ + + values: np.ndarray # values or array + # metadata: Metadata diff --git a/qiskit/evaluators/results/expectation_value_result.py b/qiskit/evaluators/results/expectation_value_result.py new file mode 100644 index 000000000000..d46ea881d6ac --- /dev/null +++ b/qiskit/evaluators/results/expectation_value_result.py @@ -0,0 +1,30 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Expectation value result class +""" + +from __future__ import annotations + +from .base_result import BaseResult + + +class ExpectationValueResult(BaseResult): + """ + Result of ExpectationValue + #TODO doc + """ + + value: float + variance: float + confidence_interval: tuple[float, float] + # metadata: Metadata