From 6192bfd529862b485ff463e4492fb8c74317df42 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 4 Apr 2022 19:46:02 -0400 Subject: [PATCH 1/7] Fix return type from schedule() with a list of one entry (#7885) This commit fixes the return type when calling schedule() with a list of a single entry. Previously this would return a single Schedule object instead of the expected list return. A similar issue was already fixed in transpile() in #5298 but schedule still had the incorrect behavior. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/compiler/scheduler.py | 6 +++++- .../fix-list-input-schedule-14fc48895a061735.yaml | 7 +++++++ test/python/scheduler/test_basic_scheduler.py | 10 ++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix-list-input-schedule-14fc48895a061735.yaml diff --git a/qiskit/compiler/scheduler.py b/qiskit/compiler/scheduler.py index 56ddc52b2bc9..715ba8b3e7c2 100644 --- a/qiskit/compiler/scheduler.py +++ b/qiskit/compiler/scheduler.py @@ -65,6 +65,7 @@ def schedule( Raises: QiskitError: If ``inst_map`` and ``meas_map`` are not passed and ``backend`` is not passed """ + arg_circuits_list = isinstance(circuits, list) start_time = time() if backend and getattr(backend, "version", 0) > 1: if inst_map is None: @@ -100,4 +101,7 @@ def schedule( schedules = [schedule_circuit(circuit, schedule_config, method) for circuit in circuits] end_time = time() _log_schedule_time(start_time, end_time) - return schedules[0] if len(schedules) == 1 else schedules + if arg_circuits_list: + return schedules + else: + return schedules[0] diff --git a/releasenotes/notes/fix-list-input-schedule-14fc48895a061735.yaml b/releasenotes/notes/fix-list-input-schedule-14fc48895a061735.yaml new file mode 100644 index 000000000000..cb326f4c39a0 --- /dev/null +++ b/releasenotes/notes/fix-list-input-schedule-14fc48895a061735.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixed an issue with the :class:`~qiskit.compiler.schedule` function where + previously passing in a ``list`` of :class:`~qiskit.circuit.QuantumCircuit` + objects with a single entry would incorrectly return a single + :class:`~.Schedule` object instead of the expected ``list`` return type. diff --git a/test/python/scheduler/test_basic_scheduler.py b/test/python/scheduler/test_basic_scheduler.py index 03a2b67d1c71..68bb76bc7d18 100644 --- a/test/python/scheduler/test_basic_scheduler.py +++ b/test/python/scheduler/test_basic_scheduler.py @@ -82,6 +82,16 @@ def test_alap_pass(self): self.assertEqual(actual[0], expected[0]) self.assertEqual(actual[1], expected[1]) + def test_single_circuit_list_schedule(self): + """Test that passing a single circuit list to schedule() returns a list.""" + q = QuantumRegister(2) + c = ClassicalRegister(2) + qc = QuantumCircuit(q, c) + sched = schedule([qc], self.backend, method="alap") + expected = Schedule() + self.assertIsInstance(sched, list) + self.assertEqual(sched[0].instructions, expected.instructions) + def test_alap_with_barriers(self): """Test that ALAP respects barriers on new qubits.""" q = QuantumRegister(2) From 0e46791d7be511fc99d7fd4fb70929ba8f881cfb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 10:14:16 +0000 Subject: [PATCH 2/7] Bump pyo3 from 0.16.2 to 0.16.3 (#7890) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.16.2 to 0.16.3. - [Release notes](https://github.com/pyo3/pyo3/releases) - [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md) - [Commits](https://github.com/pyo3/pyo3/compare/v0.16.2...v0.16.3) --- updated-dependencies: - dependency-name: pyo3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 28 +++++++++++++++++----------- Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b4e712f8f00..41a5fcde8621 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -298,9 +298,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a378727d5fdcaafd15b5afe9842cff1c25fdc43f62a162ffda2263c57ad98703" +checksum = "6b3e99c4c3e790e4fc365b42b70c1f7801f42eadc4ea648fa327e6f5ca29f215" dependencies = [ "cfg-if", "hashbrown", @@ -316,18 +316,19 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbb27a3e96edd34c13d97d0feefccc90a79270c577c66e19d95af8323823dfc" +checksum = "2486b96281859ff0a3929ba6467b13751627b974f7137362db38e2bed14b2094" dependencies = [ "once_cell", + "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b719fff844bcf3f911132112ec06527eb195f6a98e0c42cf97e1118929fd4ea" +checksum = "dd9de1d94557751599f8bd321f10e6c1ef2801067acb58c91138deef2ae83a17" dependencies = [ "libc", "pyo3-build-config", @@ -335,9 +336,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f795e52d3320abb349ca28b501a7112154a87f353fae1c811deecd58e99cfa9b" +checksum = "0b9584049129b1cfb615243391a6345c726690271ae195ffd6aa3766177296aa" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -347,12 +348,11 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e03aa57a3bb7b96982958088df38302a139df4eef54671bc595f26556cb75b" +checksum = "b6c4717e6a55c51a9958eda1f5481ff7f62cccd21f45309c10e4731cb7198dbc" dependencies = [ "proc-macro2", - "pyo3-build-config", "quote", "syn", ] @@ -495,6 +495,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "target-lexicon" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index c07161ee4296..89e8b8d15975 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ ahash = "0.7.6" num-complex = "0.4" [dependencies.pyo3] -version = "0.16.2" +version = "0.16.3" features = ["extension-module", "hashbrown", "num-complex"] [dependencies.ndarray] From b510d6a65d0c64b9543b4d31c2789b07a4cd75c4 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 5 Apr 2022 19:03:47 -0400 Subject: [PATCH 3/7] Add qiskit-bot notification config (#7811) * Add qiskit-bot notification config This commit adds a local config file for qiskit-bot. Qiskit-bot recently added a feature that enables a configurable first comment/notification (see https://github.com/Qiskit/qiskit-bot/pull/18). This feature works by adding a local in-repo configuration file that lists regex keys that match the paths modified in a PR when it is opened. If the paths match any of the regexes the listed users are mentioned in the comment the bot leaves. For this commit I picked an initial selection of users to notify we can easily modify this and add any user (whether they're a core team member, codeowner, or just an individual contributor), the bot will simply parrot whatever we put in this config on comments when the PR matches the regex. * Correct Julien's username * Update qiskit_bot.yaml Co-authored-by: Julien Gacon * Fix typo Co-authored-by: Jake Lishman Co-authored-by: Julien Gacon --- qiskit_bot.yaml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 qiskit_bot.yaml diff --git a/qiskit_bot.yaml b/qiskit_bot.yaml new file mode 100644 index 000000000000..a50d52e9d427 --- /dev/null +++ b/qiskit_bot.yaml @@ -0,0 +1,38 @@ +--- +notifications: + ".*": + - "@Qiskit/terra-core" + "visualization/pulse_v2": + - "@nkanazawa1989" + "qpy": + - "@mtreinish" + - "@nkanazawa1989" + "two_qubit_decompose": + - "@levbishop" + "quantum_info": + - "@ikkoham" + "utils/run_circuits": + - "@manoelmarques" + - "@woodsp-ibm" + "utils/quantum_instance": + - "@manoelmarques" + - "@woodsp-ibm" + "opflow": + - "@manoelmarques" + - "@woodsp-ibm" + - "@Cryoris" + "algorithms": + - "@manoelmarques" + - "@woodsp-ibm" + "circuit/library": + - "@Cryoris" + - "@ajavadia" + "primitives": + - "@ikkoham" + - "@t-imamichi" + - "@ajavadia" + - "@levbishop" + ".*rs": + - "@mtreinish" + - "@kevinhartman" +always_notify: true From 23acf363e52b6436998afc3150e117625cc6b7d6 Mon Sep 17 00:00:00 2001 From: smturro2 <42980188+smturro2@users.noreply.github.com> Date: Wed, 6 Apr 2022 04:47:43 -0500 Subject: [PATCH 4/7] Example for creating quantum circuit from unitary matrix (#7893) * Example for creating a quantum circuit from unitary matrix * Apply suggestions from code review * Apply suggestions from code review Changes we made to the example descriptions and class/method descriptions Co-authored-by: Julien Gacon Co-authored-by: Julien Gacon Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/extensions/unitary.py | 40 ++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index 4eba5ccd8308..7dc820410641 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -35,7 +35,28 @@ class UnitaryGate(Gate): - """Class for representing unitary gates""" + """Class quantum gates specified by a unitary matrix. + + Example: + + We can create a unitary gate from a unitary matrix then add it + to a quantum circuit. The matrix can also be directly applied + to the quantum circuit, see :meth:`~qiskit.QuantumCircuit.unitary`. + + .. code-block::python + + from qiskit import QuantumCircuit + from qiskit.extensions import UnitaryGate + + matrix = [[0, 0, 0, 1], + [0, 0, 1, 0], + [1, 0, 0, 0], + [0, 1, 0, 0]] + gate = UnitaryGate(matrix) + + circuit = QuantumCircuit(2) + circuit.append(gate, [0, 1]) + """ def __init__(self, data, label=None): """Create a gate from a numeric unitary matrix. @@ -215,7 +236,22 @@ def validate_parameter(self, parameter): def unitary(self, obj, qubits, label=None): - """Apply unitary gate to q.""" + """Apply unitary gate specified by ``obj`` to ``qubits``. + + Example: + + Apply a gate specified by a unitary matrix to a quantum circuit + + .. code-block::python + + from qiskit import QuantumCircuit + matrix = [[0, 0, 0, 1], + [0, 0, 1, 0], + [1, 0, 0, 0], + [0, 1, 0, 0]] + circuit = QuantumCircuit(2) + circuit.unitary(matrix, [0, 1]) + """ gate = UnitaryGate(obj, label=label) if isinstance(qubits, QuantumRegister): qubits = qubits[:] From 60fdd33b264e0a9cb538189f796ef578daae182d Mon Sep 17 00:00:00 2001 From: Ikko Hamamura Date: Thu, 7 Apr 2022 00:19:55 +0900 Subject: [PATCH 5/7] Fix init_observable for Pauli (#7898) * Fix init_observable for Pauli * add releasenote --- qiskit/primitives/utils.py | 10 +++++++--- ...imitive-init-observable-pauli-e312c05d1c3bd804.yaml | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/fix-primitive-init-observable-pauli-e312c05d1c3bd804.yaml diff --git a/qiskit/primitives/utils.py b/qiskit/primitives/utils.py index 129aca7fa407..f7c70ed964fb 100644 --- a/qiskit/primitives/utils.py +++ b/qiskit/primitives/utils.py @@ -20,6 +20,7 @@ from qiskit.opflow import PauliSumOp from qiskit.quantum_info import SparsePauliOp, Statevector from qiskit.quantum_info.operators.base_operator import BaseOperator +from qiskit.quantum_info.operators.symplectic.base_pauli import BasePauli def init_circuit(state: QuantumCircuit | Statevector) -> QuantumCircuit: @@ -37,15 +38,18 @@ def init_observable(observable: BaseOperator | PauliSumOp) -> SparsePauliOp: """Initialize observable""" if isinstance(observable, SparsePauliOp): return observable - if isinstance(observable, PauliSumOp): + elif 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, BaseOperator): + elif isinstance(observable, BasePauli): + return SparsePauliOp(observable) + elif isinstance(observable, BaseOperator): return SparsePauliOp.from_operator(observable) - return SparsePauliOp(observable) + else: + return SparsePauliOp(observable) def final_measurement_mapping(circuit: QuantumCircuit) -> dict[int, int]: diff --git a/releasenotes/notes/fix-primitive-init-observable-pauli-e312c05d1c3bd804.yaml b/releasenotes/notes/fix-primitive-init-observable-pauli-e312c05d1c3bd804.yaml new file mode 100644 index 000000000000..42e336d6ecf1 --- /dev/null +++ b/releasenotes/notes/fix-primitive-init-observable-pauli-e312c05d1c3bd804.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes the bug that take exponential time and does not terminate when + :class:`~qiskit.quantum_info.Pauli` is input to + :meth:`~qiskit.primitives.utils.init_observables`. From e3c4e76957f40ad447e471e64dc101fed418752b Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Thu, 7 Apr 2022 09:48:59 +0200 Subject: [PATCH 6/7] Fix small typos and improve consistency in primitive docs (#7897) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/primitives/base_estimator.py | 23 +++++++++++------------ qiskit/primitives/base_sampler.py | 24 ++++++++++++------------ qiskit/primitives/estimator_result.py | 9 ++++----- qiskit/primitives/sampler.py | 2 ++ qiskit/primitives/sampler_result.py | 9 ++++----- qiskit/primitives/utils.py | 26 ++++++++++++++++++++++---- 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/qiskit/primitives/base_estimator.py b/qiskit/primitives/base_estimator.py index 576797195e50..199a5b503f3a 100644 --- a/qiskit/primitives/base_estimator.py +++ b/qiskit/primitives/base_estimator.py @@ -131,16 +131,15 @@ def __init__( holds resources until the instance is ``close()`` ed or the context is exited. Args: - circuits: quantum circuits that represent quantum states - observables: observables - parameters: parameters of quantum circuits, specifying the order in which values - will be bound. - Defaults to ``[circ.parameters for circ in circuits]`` + circuits: Quantum circuits that represent quantum states. + observables: Observables. + parameters: Parameters of quantum circuits, specifying the order in which values + will be bound. Defaults to ``[circ.parameters for circ in circuits]`` The indexing is such that ``parameters[i, j]`` is the j-th formal parameter of ``circuits[i]``. Raises: - QiskitError: for mismatch of circuits and parameters list. + QiskitError: For mismatch of circuits and parameters list. """ self._circuits = tuple(circuits) self._observables = tuple(observables) @@ -176,25 +175,25 @@ def circuits(self) -> tuple[QuantumCircuit, ...]: """Quantum circuits that represents quantum states. Returns: - quantum circuits + The quantum circuits. """ return self._circuits @property def observables(self) -> tuple[SparsePauliOp, ...]: - """Observables to be estimated + """Observables to be estimated. Returns: - observables + The observables. """ return self._observables @property def parameters(self) -> tuple[ParameterView, ...]: - """Parameters of quantum circuits + """Parameters of the quantum circuits. Returns: - parameters, where ``parameters[i][j]`` is the j-th parameter of the i-th circuit. + Parameters, where ``parameters[i][j]`` is the j-th parameter of the i-th circuit. """ return self._parameters @@ -234,6 +233,6 @@ def __call__( run_options: runtime options used for circuit execution. Returns: - EstimatorResult: the result of Estimator. + EstimatorResult: The result of the estimator. """ ... diff --git a/qiskit/primitives/base_sampler.py b/qiskit/primitives/base_sampler.py index f41b0c79fe7e..28b5b69d60f9 100644 --- a/qiskit/primitives/base_sampler.py +++ b/qiskit/primitives/base_sampler.py @@ -112,12 +112,12 @@ def __init__( ): """ Args: - circuits: quantum circuits to be executed - parameters: parameters of quantum circuits - Defaults to ``[circ.parameters for circ in circuits]`` + circuits: Quantum circuits to be executed. + parameters: Parameters of each of the quantum circuits. + Defaults to ``[circ.parameters for circ in circuits]``. Raises: - QiskitError: for mismatch of circuits and parameters list. + QiskitError: For mismatch of circuits and parameters list. """ self._circuits = tuple(circuits) if parameters is None: @@ -143,19 +143,19 @@ def close(self): @property def circuits(self) -> tuple[QuantumCircuit, ...]: - """Quantum circuits + """Quantum circuits to be sampled. Returns: - quantum circuits + The quantum circuits to be sampled. """ return self._circuits @property def parameters(self) -> tuple[ParameterView, ...]: - """Parameters of quantum circuits + """Parameters of quantum circuits. Returns: - Parameter list of the quantum circuits + List of the parameters in each quantum circuit. """ return self._parameters @@ -169,12 +169,12 @@ def __call__( """Run the sampling of bitstrings. Args: - circuit_indices: indexes of the circuits to evaluate. - parameter_values: parameters to be bound. - run_options: backend runtime options used for circuit execution. + circuit_indices: Indices of the circuits to evaluate. + parameter_values: Parameters to be bound to the circuit. + run_options: Backend runtime options used for circuit execution. Returns: - the result of Sampler. The i-th result corresponds to + The result of the sampler. The i-th result corresponds to ``self.circuits[circuit_indices[i]]`` evaluated with parameters bound as ``parameter_values[i]``. """ diff --git a/qiskit/primitives/estimator_result.py b/qiskit/primitives/estimator_result.py index 8bd7aeb65d90..e26d9848c676 100644 --- a/qiskit/primitives/estimator_result.py +++ b/qiskit/primitives/estimator_result.py @@ -24,21 +24,20 @@ @dataclass(frozen=True) class EstimatorResult: - """ - Result of Estimator + """Result of Estimator. .. code-block:: python result = estimator(circuits, observables, params) where the i-th elements of ``result`` correspond to the circuit and observable given by - ``circuit_indices[i]``, ``observable_indices[i]``, and the parameter_values bounds by ``params[i]``. + ``circuit_indices[i]``, ``observable_indices[i]``, and the parameter values bounds by ``params[i]``. For example, ``results.values[i]`` gives the expectation value, and ``result.metadata[i]`` is a metadata dictionary for this circuit and parameters. Args: - values (np.ndarray): the array of the expectation values. - metadata (list[dict]): list of the metadata. + values (np.ndarray): The array of the expectation values. + metadata (list[dict]): List of the metadata. """ values: "np.ndarray[Any, np.dtype[np.float64]]" diff --git a/qiskit/primitives/sampler.py b/qiskit/primitives/sampler.py index adbcd782c087..cecb0c94809c 100644 --- a/qiskit/primitives/sampler.py +++ b/qiskit/primitives/sampler.py @@ -43,6 +43,8 @@ def __init__( """ Args: circuits: circuits to be executed + parameters: Parameters of each of the quantum circuits. + Defaults to ``[circ.parameters for circ in circuits]``. Raises: QiskitError: if some classical bits are not used for measurements. diff --git a/qiskit/primitives/sampler_result.py b/qiskit/primitives/sampler_result.py index 4d94e33c123f..5b53b10663c1 100644 --- a/qiskit/primitives/sampler_result.py +++ b/qiskit/primitives/sampler_result.py @@ -23,21 +23,20 @@ @dataclass(frozen=True) class SamplerResult: - """ - Result of Sampler + """Result of Sampler. .. code-block:: python result = sampler(circuits, params) where the i-th elements of ``result`` correspond to the circuit given by ``circuit_indices[i]``, - and the parameter_values bounds by ``params[i]``. + and the parameter values bounds by ``params[i]``. For example, ``results.quasi_dists[i]`` gives the quasi-probabilities of bitstrings, and ``result.metadata[i]`` is a metadata dictionary for this circuit and parameters. Args: - quasi_dists (list[QuasiDistribution]): list of the quasi-probabilities. - metadata (list[dict]): list of the metadata. + quasi_dists (list[QuasiDistribution]): List of the quasi-probabilities. + metadata (list[dict]): List of the metadata. """ quasi_dists: list[QuasiDistribution] diff --git a/qiskit/primitives/utils.py b/qiskit/primitives/utils.py index f7c70ed964fb..e5abc4120ddb 100644 --- a/qiskit/primitives/utils.py +++ b/qiskit/primitives/utils.py @@ -24,7 +24,14 @@ def init_circuit(state: QuantumCircuit | Statevector) -> QuantumCircuit: - """Initialize state.""" + """Initialize state by converting the input to a quantum circuit. + + Args: + state: The state as quantum circuit or statevector. + + Returns: + The state as quantum circuit. + """ if isinstance(state, QuantumCircuit): return state if not isinstance(state, Statevector): @@ -35,13 +42,24 @@ def init_circuit(state: QuantumCircuit | Statevector) -> QuantumCircuit: def init_observable(observable: BaseOperator | PauliSumOp) -> SparsePauliOp: - """Initialize observable""" + """Initialize observable by converting the input to a :class:`~qiskit.quantum_info.SparsePauliOp`. + + Args: + observable: The observable. + + Returns: + The observable as :class:`~qiskit.quantum_info.SparsePauliOp`. + + Raises: + TypeError: If the observable is a :class:`~qiskit.opflow.PauliSumOp` and has a parameterized + coefficient. + """ if isinstance(observable, SparsePauliOp): return observable elif isinstance(observable, PauliSumOp): if isinstance(observable.coeff, ParameterExpression): raise TypeError( - f"observable must have numerical coefficient, not {type(observable.coeff)}" + f"Observable must have numerical coefficient, not {type(observable.coeff)}." ) return observable.coeff * observable.primitive elif isinstance(observable, BasePauli): @@ -63,7 +81,7 @@ def final_measurement_mapping(circuit: QuantumCircuit) -> dict[int, int]: `mthree `_. Parameters: - circuit: Input Qiskit QuantumCircuit. + circuit: Input quantum circuit. Returns: Mapping of qubits to classical bits for final measurements. From 10624ae29460f029bd13a32c95bd6e77e5d4eaaf Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Thu, 7 Apr 2022 17:36:54 +0200 Subject: [PATCH 7/7] Add interfaces for a general Quantum Time Evolution Framework (#7858) * Revert "Revert "Implemented general Quantum Time Evolution Framework interfaces. (#7669)" (#7845)" This reverts commit 1b6c1b30f869d682f893138dd5b331c24e659899. Co-authored-by: dlasecki * remove Evolver base class * Don't import list or dict from MES Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com> * fix import order Co-authored-by: dlasecki Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com> --- qiskit/algorithms/__init__.py | 23 ++++++ qiskit/algorithms/aux_ops_evaluator.py | 3 +- .../algorithms/eigen_solvers/eigen_solver.py | 8 +- .../eigen_solvers/numpy_eigen_solver.py | 3 +- qiskit/algorithms/evolvers/__init__.py | 21 +++++ .../algorithms/evolvers/evolution_problem.py | 58 ++++++++++++++ .../algorithms/evolvers/evolution_result.py | 40 ++++++++++ .../algorithms/evolvers/imaginary/__init__.py | 11 +++ .../evolvers/imaginary/imaginary_evolver.py | 37 +++++++++ qiskit/algorithms/evolvers/real/__init__.py | 11 +++ .../algorithms/evolvers/real/real_evolver.py | 37 +++++++++ qiskit/algorithms/list_or_dict.py | 18 +++++ .../minimum_eigen_solver.py | 8 +- .../numpy_minimum_eigen_solver.py | 3 +- .../algorithms/minimum_eigen_solvers/vqe.py | 3 +- .../time-evo-framework-9d58827bdbbebd62.yaml | 13 ++++ test/python/algorithms/evolvers/__init__.py | 11 +++ .../evolvers/test_evolution_problem.py | 76 +++++++++++++++++++ .../evolvers/test_evolution_result.py | 48 ++++++++++++ .../algorithms/test_aux_ops_evaluator.py | 2 +- 20 files changed, 419 insertions(+), 15 deletions(-) create mode 100644 qiskit/algorithms/evolvers/__init__.py create mode 100644 qiskit/algorithms/evolvers/evolution_problem.py create mode 100644 qiskit/algorithms/evolvers/evolution_result.py create mode 100644 qiskit/algorithms/evolvers/imaginary/__init__.py create mode 100644 qiskit/algorithms/evolvers/imaginary/imaginary_evolver.py create mode 100644 qiskit/algorithms/evolvers/real/__init__.py create mode 100644 qiskit/algorithms/evolvers/real/real_evolver.py create mode 100644 qiskit/algorithms/list_or_dict.py create mode 100644 releasenotes/notes/time-evo-framework-9d58827bdbbebd62.yaml create mode 100644 test/python/algorithms/evolvers/__init__.py create mode 100644 test/python/algorithms/evolvers/test_evolution_problem.py create mode 100644 test/python/algorithms/evolvers/test_evolution_result.py diff --git a/qiskit/algorithms/__init__.py b/qiskit/algorithms/__init__.py index 73d8544ce244..0c3ed197f2c6 100644 --- a/qiskit/algorithms/__init__.py +++ b/qiskit/algorithms/__init__.py @@ -93,6 +93,22 @@ NumPyEigensolver +Evolvers +-------- + +Algorithms to evolve quantum states in time. Both real and imaginary time evolution is possible +with algorithms that support them. For machine learning, Quantum Imaginary Time Evolution might be +used to train Quantum Boltzmann Machine Neural Networks for example. + +.. autosummary:: + :toctree: ../stubs/ + :nosignatures: + + RealEvolver + ImaginaryEvolver + EvolutionResult + EvolutionProblem + Factorizers ----------- @@ -188,6 +204,9 @@ """ from .algorithm_result import AlgorithmResult +from .evolvers import EvolutionResult, EvolutionProblem +from .evolvers.real.real_evolver import RealEvolver +from .evolvers.imaginary.imaginary_evolver import ImaginaryEvolver from .variational_algorithm import VariationalAlgorithm, VariationalResult from .amplitude_amplifiers import Grover, GroverResult, AmplificationProblem, AmplitudeAmplifier from .amplitude_estimators import ( @@ -245,6 +264,10 @@ "MaximumLikelihoodAmplitudeEstimationResult", "EstimationProblem", "NumPyEigensolver", + "RealEvolver", + "ImaginaryEvolver", + "EvolutionResult", + "EvolutionProblem", "LinearSolverResult", "Eigensolver", "EigensolverResult", diff --git a/qiskit/algorithms/aux_ops_evaluator.py b/qiskit/algorithms/aux_ops_evaluator.py index 7228f45e4308..9e11604dc10c 100644 --- a/qiskit/algorithms/aux_ops_evaluator.py +++ b/qiskit/algorithms/aux_ops_evaluator.py @@ -16,7 +16,6 @@ import numpy as np from qiskit import QuantumCircuit -from qiskit.algorithms.eigen_solvers.eigen_solver import ListOrDict from qiskit.opflow import ( CircuitSampler, ListOp, @@ -28,6 +27,8 @@ from qiskit.quantum_info import Statevector from qiskit.utils import QuantumInstance +from .list_or_dict import ListOrDict + def eval_observables( quantum_instance: Union[QuantumInstance, BaseBackend, Backend], diff --git a/qiskit/algorithms/eigen_solvers/eigen_solver.py b/qiskit/algorithms/eigen_solvers/eigen_solver.py index bdb8933ac5ea..28ca3e9d1f8b 100644 --- a/qiskit/algorithms/eigen_solvers/eigen_solver.py +++ b/qiskit/algorithms/eigen_solvers/eigen_solver.py @@ -13,15 +13,13 @@ """The Eigensolver interface""" from abc import ABC, abstractmethod -from typing import Dict, Optional, List, Union, Tuple, TypeVar +from typing import Optional, List, Tuple import numpy as np + from qiskit.opflow import OperatorBase from ..algorithm_result import AlgorithmResult - -# Introduced new type to maintain readability. -_T = TypeVar("_T") # Pylint does not allow single character class names. -ListOrDict = Union[List[Optional[_T]], Dict[str, _T]] +from ..list_or_dict import ListOrDict class Eigensolver(ABC): diff --git a/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py b/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py index c30504b676d3..4abbe7ed4a26 100755 --- a/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py +++ b/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py @@ -21,7 +21,8 @@ from qiskit.opflow import I, ListOp, OperatorBase, StateFn from qiskit.utils.validation import validate_min from ..exceptions import AlgorithmError -from .eigen_solver import Eigensolver, EigensolverResult, ListOrDict +from .eigen_solver import Eigensolver, EigensolverResult +from ..list_or_dict import ListOrDict logger = logging.getLogger(__name__) diff --git a/qiskit/algorithms/evolvers/__init__.py b/qiskit/algorithms/evolvers/__init__.py new file mode 100644 index 000000000000..990c787b7c15 --- /dev/null +++ b/qiskit/algorithms/evolvers/__init__.py @@ -0,0 +1,21 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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. + +"""Quantum Time Evolution package.""" + +from .evolution_result import EvolutionResult +from .evolution_problem import EvolutionProblem + +__all__ = [ + "EvolutionResult", + "EvolutionProblem", +] diff --git a/qiskit/algorithms/evolvers/evolution_problem.py b/qiskit/algorithms/evolvers/evolution_problem.py new file mode 100644 index 000000000000..f926dbdf3d96 --- /dev/null +++ b/qiskit/algorithms/evolvers/evolution_problem.py @@ -0,0 +1,58 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# 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. + +"""Evolution problem class.""" + +from typing import Union, Optional, Dict + +from qiskit import QuantumCircuit +from qiskit.circuit import Parameter +from qiskit.opflow import OperatorBase, StateFn +from ..list_or_dict import ListOrDict + + +class EvolutionProblem: + """Evolution problem class. + + This class is the input to time evolution algorithms and contains + information on e.g. the total evolution time and under which Hamiltonian + the state is evolved. + """ + + def __init__( + self, + hamiltonian: OperatorBase, + time: float, + initial_state: Union[StateFn, QuantumCircuit], + aux_operators: Optional[ListOrDict[OperatorBase]] = None, + t_param: Optional[Parameter] = None, + hamiltonian_value_dict: Optional[Dict[Parameter, Union[complex]]] = None, + ): + """ + Args: + hamiltonian: The Hamiltonian under which to evolve the system. + time: Total time of evolution. + initial_state: Quantum state to be evolved. + aux_operators: Optional list of auxiliary operators to be evaluated with the + evolved ``initial_state`` and their expectation values returned. + t_param: Time parameter in case of a time-dependent Hamiltonian. This + free parameter must be within the ``hamiltonian``. + hamiltonian_value_dict: If the Hamiltonian contains free parameters, this + dictionary maps all these parameters to values. + """ + + self.hamiltonian = hamiltonian + self.time = time + self.initial_state = initial_state + self.aux_operators = aux_operators + self.t_param = t_param + self.hamiltonian_value_dict = hamiltonian_value_dict diff --git a/qiskit/algorithms/evolvers/evolution_result.py b/qiskit/algorithms/evolvers/evolution_result.py new file mode 100644 index 000000000000..ead37fd98dfc --- /dev/null +++ b/qiskit/algorithms/evolvers/evolution_result.py @@ -0,0 +1,40 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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. + +"""Class for holding evolution result.""" + +from typing import Optional, Union, Tuple + +from qiskit import QuantumCircuit +from qiskit.algorithms.list_or_dict import ListOrDict +from qiskit.opflow import StateFn +from ..algorithm_result import AlgorithmResult + + +class EvolutionResult(AlgorithmResult): + """Class for holding evolution result.""" + + def __init__( + self, + evolved_state: Union[StateFn, QuantumCircuit], + aux_ops_evaluated: Optional[ListOrDict[Tuple[complex, complex]]] = None, + ): + """ + Args: + evolved_state: An evolved quantum state. + aux_ops_evaluated: Optional list of observables for which expected values on an evolved + state are calculated. These values are in fact tuples formatted as (mean, standard + deviation). + """ + + self.evolved_state = evolved_state + self.aux_ops_evaluated = aux_ops_evaluated diff --git a/qiskit/algorithms/evolvers/imaginary/__init__.py b/qiskit/algorithms/evolvers/imaginary/__init__.py new file mode 100644 index 000000000000..b3ac36d2a6d9 --- /dev/null +++ b/qiskit/algorithms/evolvers/imaginary/__init__.py @@ -0,0 +1,11 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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. diff --git a/qiskit/algorithms/evolvers/imaginary/imaginary_evolver.py b/qiskit/algorithms/evolvers/imaginary/imaginary_evolver.py new file mode 100644 index 000000000000..7743597c1e31 --- /dev/null +++ b/qiskit/algorithms/evolvers/imaginary/imaginary_evolver.py @@ -0,0 +1,37 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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. + +"""Interface for Quantum Imaginary Time Evolution.""" + +from abc import ABC, abstractmethod + +from ..evolution_problem import EvolutionProblem +from ..evolution_result import EvolutionResult + + +class ImaginaryEvolver(ABC): + """Interface for Quantum Imaginary Time Evolution.""" + + @abstractmethod + def evolve(self, evolution_problem: EvolutionProblem) -> EvolutionResult: + r"""Perform imaginary time evolution :math:`\exp(-\tau H)|\Psi\rangle`. + + Evolves an initial state :math:`|\Psi\rangle` for an imaginary time :math:`\tau` + under a Hamiltonian :math:`H`, as provided in the ``evolution_problem``. + + Args: + evolution_problem: The definition of the evolution problem. + + Returns: + Evolution result which includes an evolved quantum state. + """ + raise NotImplementedError() diff --git a/qiskit/algorithms/evolvers/real/__init__.py b/qiskit/algorithms/evolvers/real/__init__.py new file mode 100644 index 000000000000..b3ac36d2a6d9 --- /dev/null +++ b/qiskit/algorithms/evolvers/real/__init__.py @@ -0,0 +1,11 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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. diff --git a/qiskit/algorithms/evolvers/real/real_evolver.py b/qiskit/algorithms/evolvers/real/real_evolver.py new file mode 100644 index 000000000000..b6c2f2b989dc --- /dev/null +++ b/qiskit/algorithms/evolvers/real/real_evolver.py @@ -0,0 +1,37 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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. + +"""Interface for Quantum Real Time Evolution.""" + +from abc import ABC, abstractmethod + +from ..evolution_problem import EvolutionProblem +from ..evolution_result import EvolutionResult + + +class RealEvolver(ABC): + """Interface for Quantum Real Time Evolution.""" + + @abstractmethod + def evolve(self, evolution_problem: EvolutionProblem) -> EvolutionResult: + r"""Perform real time evolution :math:`\exp(-i t H)|\Psi\rangle`. + + Evolves an initial state :math:`|\Psi\rangle` for a time :math:`t` + under a Hamiltonian :math:`H`, as provided in the ``evolution_problem``. + + Args: + evolution_problem: The definition of the evolution problem. + + Returns: + Evolution result which includes an evolved quantum state. + """ + raise NotImplementedError() diff --git a/qiskit/algorithms/list_or_dict.py b/qiskit/algorithms/list_or_dict.py new file mode 100644 index 000000000000..95314dd79a3b --- /dev/null +++ b/qiskit/algorithms/list_or_dict.py @@ -0,0 +1,18 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# 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. + +"""Introduced new type to maintain readability.""" + +from typing import TypeVar, List, Union, Optional, Dict + +_T = TypeVar("_T") # Pylint does not allow single character class names. +ListOrDict = Union[List[Optional[_T]], Dict[str, _T]] diff --git a/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py b/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py index 545cf289643b..7cdd245b7076 100644 --- a/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py +++ b/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py @@ -13,15 +13,13 @@ """The Minimum Eigensolver interface""" from abc import ABC, abstractmethod -from typing import Dict, Optional, List, Union, Tuple, TypeVar +from typing import Optional, Tuple import numpy as np + from qiskit.opflow import OperatorBase from ..algorithm_result import AlgorithmResult - -# Introduced new type to maintain readability. -_T = TypeVar("_T") # Pylint does not allow single character class names. -ListOrDict = Union[List[Optional[_T]], Dict[str, _T]] +from ..list_or_dict import ListOrDict class MinimumEigensolver(ABC): diff --git a/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py b/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py index 369485976cdf..5515ba92d745 100644 --- a/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py +++ b/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py @@ -18,7 +18,8 @@ from qiskit.opflow import OperatorBase from ..eigen_solvers.numpy_eigen_solver import NumPyEigensolver -from .minimum_eigen_solver import MinimumEigensolver, MinimumEigensolverResult, ListOrDict +from .minimum_eigen_solver import MinimumEigensolver, MinimumEigensolverResult +from ..list_or_dict import ListOrDict logger = logging.getLogger(__name__) diff --git a/qiskit/algorithms/minimum_eigen_solvers/vqe.py b/qiskit/algorithms/minimum_eigen_solvers/vqe.py index 4be503b25e76..e401a2b007cd 100755 --- a/qiskit/algorithms/minimum_eigen_solvers/vqe.py +++ b/qiskit/algorithms/minimum_eigen_solvers/vqe.py @@ -40,9 +40,10 @@ from qiskit.utils.validation import validate_min from qiskit.utils.backend_utils import is_aer_provider from qiskit.utils import QuantumInstance, algorithm_globals +from ..list_or_dict import ListOrDict from ..optimizers import Optimizer, SLSQP, OptimizerResult from ..variational_algorithm import VariationalAlgorithm, VariationalResult -from .minimum_eigen_solver import MinimumEigensolver, MinimumEigensolverResult, ListOrDict +from .minimum_eigen_solver import MinimumEigensolver, MinimumEigensolverResult from ..exceptions import AlgorithmError from ..aux_ops_evaluator import eval_observables diff --git a/releasenotes/notes/time-evo-framework-9d58827bdbbebd62.yaml b/releasenotes/notes/time-evo-framework-9d58827bdbbebd62.yaml new file mode 100644 index 000000000000..06bc667a96d5 --- /dev/null +++ b/releasenotes/notes/time-evo-framework-9d58827bdbbebd62.yaml @@ -0,0 +1,13 @@ +--- +features: + - | + Interfaces for the unified framework for Quantum Time Evolution are introduced. + :class:`~qiskit.algorithms.EvolutionProblem` defines an evolution problem and + can be passed to any evolution algorithm available in the framework. + :class:`~qiskit.algorithms.ImaginaryEvolver` and + :class:`~qiskit.algorithms.RealEvolver` are interfaces for + imaginary and real time evolution cases respectively. They serve as a base for any time + evolution algorithm for evolving quantum states, including evolutions based on + time-dependent Hamiltonians. + :class:`~qiskit.algorithms.EvolutionResult` is introduced as a result object + for quantum time evolution algorithms. diff --git a/test/python/algorithms/evolvers/__init__.py b/test/python/algorithms/evolvers/__init__.py new file mode 100644 index 000000000000..fdb172d367f0 --- /dev/null +++ b/test/python/algorithms/evolvers/__init__.py @@ -0,0 +1,11 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# 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. diff --git a/test/python/algorithms/evolvers/test_evolution_problem.py b/test/python/algorithms/evolvers/test_evolution_problem.py new file mode 100644 index 000000000000..cdd472247045 --- /dev/null +++ b/test/python/algorithms/evolvers/test_evolution_problem.py @@ -0,0 +1,76 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# 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. + +"""Test evolver problem class.""" +import unittest + +from test.python.algorithms import QiskitAlgorithmsTestCase +from qiskit.algorithms.evolvers.evolution_problem import EvolutionProblem +from qiskit.circuit import Parameter +from qiskit.opflow import Y, Z, One, X + + +class TestEvolutionProblem(QiskitAlgorithmsTestCase): + """Test evolver problem class.""" + + def test_init_default(self): + """Tests that all default fields are initialized correctly.""" + hamiltonian = Y + time = 2.5 + initial_state = One + + evo_problem = EvolutionProblem(hamiltonian, time, initial_state) + + expected_hamiltonian = Y + expected_time = 2.5 + expected_initial_state = One + expected_aux_operators = None + expected_t_param = None + expected_hamiltonian_value_dict = None + + self.assertEqual(evo_problem.hamiltonian, expected_hamiltonian) + self.assertEqual(evo_problem.time, expected_time) + self.assertEqual(evo_problem.initial_state, expected_initial_state) + self.assertEqual(evo_problem.aux_operators, expected_aux_operators) + self.assertEqual(evo_problem.t_param, expected_t_param) + self.assertEqual(evo_problem.hamiltonian_value_dict, expected_hamiltonian_value_dict) + + def test_init_all(self): + """Tests that all fields are initialized correctly.""" + t_parameter = Parameter("t") + hamiltonian = t_parameter * Z + Y + time = 2 + initial_state = One + aux_operators = [X, Y] + hamiltonian_value_dict = {t_parameter: 3.2} + + evo_problem = EvolutionProblem( + hamiltonian, time, initial_state, aux_operators, t_parameter, hamiltonian_value_dict + ) + + expected_hamiltonian = Y + t_parameter * Z + expected_time = 2 + expected_initial_state = One + expected_aux_operators = [X, Y] + expected_t_param = t_parameter + expected_hamiltonian_value_dict = {t_parameter: 3.2} + + self.assertEqual(evo_problem.hamiltonian, expected_hamiltonian) + self.assertEqual(evo_problem.time, expected_time) + self.assertEqual(evo_problem.initial_state, expected_initial_state) + self.assertEqual(evo_problem.aux_operators, expected_aux_operators) + self.assertEqual(evo_problem.t_param, expected_t_param) + self.assertEqual(evo_problem.hamiltonian_value_dict, expected_hamiltonian_value_dict) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/python/algorithms/evolvers/test_evolution_result.py b/test/python/algorithms/evolvers/test_evolution_result.py new file mode 100644 index 000000000000..5500b283a1cb --- /dev/null +++ b/test/python/algorithms/evolvers/test_evolution_result.py @@ -0,0 +1,48 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# 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. +"""Class for testing evolution result.""" +import unittest + +from test.python.algorithms import QiskitAlgorithmsTestCase +from qiskit.algorithms.evolvers.evolution_result import EvolutionResult +from qiskit.opflow import Zero + + +class TestEvolutionResult(QiskitAlgorithmsTestCase): + """Class for testing evolution result and relevant metadata.""" + + def test_init_state(self): + """Tests that a class is initialized correctly with an evolved_state.""" + evolved_state = Zero + evo_result = EvolutionResult(evolved_state=evolved_state) + + expected_state = Zero + expected_aux_ops_evaluated = None + + self.assertEqual(evo_result.evolved_state, expected_state) + self.assertEqual(evo_result.aux_ops_evaluated, expected_aux_ops_evaluated) + + def test_init_observable(self): + """Tests that a class is initialized correctly with an evolved_observable.""" + evolved_state = Zero + evolved_aux_ops_evaluated = [(5j, 5j), (1.0, 8j), (5 + 1j, 6 + 1j)] + evo_result = EvolutionResult(evolved_state, evolved_aux_ops_evaluated) + + expected_state = Zero + expected_aux_ops_evaluated = [(5j, 5j), (1.0, 8j), (5 + 1j, 6 + 1j)] + + self.assertEqual(evo_result.evolved_state, expected_state) + self.assertEqual(evo_result.aux_ops_evaluated, expected_aux_ops_evaluated) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/python/algorithms/test_aux_ops_evaluator.py b/test/python/algorithms/test_aux_ops_evaluator.py index 4bbcf54de538..09baf37a44b7 100644 --- a/test/python/algorithms/test_aux_ops_evaluator.py +++ b/test/python/algorithms/test_aux_ops_evaluator.py @@ -18,7 +18,7 @@ import numpy as np from ddt import ddt, data -from qiskit.algorithms.eigen_solvers.eigen_solver import ListOrDict +from qiskit.algorithms.list_or_dict import ListOrDict from qiskit.providers import BaseBackend, Backend from qiskit.quantum_info import Statevector from qiskit.algorithms import eval_observables