Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e3233b7
Implemented observables_evaluator.py with primitives.
Aug 30, 2022
d71f50b
Added evolvers problems and interfaces to time_evolvers package.
Aug 30, 2022
7a7c82b
Mostly updated trotter_qrte.py to use primitives.
Aug 30, 2022
54afe25
Added observables_evaluator.py that uses primitives.
Sep 1, 2022
d2b67d9
Added observables_evaluator.py that uses primitives.
Sep 1, 2022
c1276d2
Updated trotter_qrte.py to use primitives.
Sep 1, 2022
e06c6c2
Updated imports
Sep 1, 2022
5a9bebe
Updated typehints and limited use of opflow.
Sep 5, 2022
356deae
Updated typehints and limited use of opflow.
Sep 5, 2022
14ba35d
Removed files out of scope for this PR.
Sep 5, 2022
4cf6f61
Added annotations import.
Sep 5, 2022
604944c
Applied some CR comments.
Sep 6, 2022
23821e0
Added reno.
Sep 7, 2022
a2960b2
Accepting Statevector.
Sep 7, 2022
9b5f50a
Added attributes docs.
Sep 7, 2022
107dc2b
Merge branch 'main' into evolution-framework-primitives
manoelmarques Sep 8, 2022
387ce78
Add pending deprecation for evolvers
manoelmarques Sep 8, 2022
a7e2f60
Renamed classes and linked to algorithms init.
Sep 8, 2022
34c2deb
Merge remote-tracking branch 'origin/evolution-framework-primitives' …
Sep 8, 2022
5c87255
fix docstring
manoelmarques Sep 8, 2022
d03bddf
Improved reno.
Sep 9, 2022
a656db0
Merge branch 'main' into evolution-framework-primitives
Sep 9, 2022
7680019
Code refactoring.
Sep 9, 2022
1dce473
Black fix.
Sep 9, 2022
d3c601e
Applied CR comments.
Sep 11, 2022
4795b45
Add deprecation msg to evolvers package
manoelmarques Sep 12, 2022
ce6d828
Merge branch 'main' into evolution-framework-primitives
Sep 12, 2022
0552379
Merge branch 'main' into evolution-framework-primitives
woodsp-ibm Sep 12, 2022
6e834f0
Merge branch 'main' into evolution-framework-primitives
Sep 13, 2022
d9c8d84
Merge branch 'main' into evolution-framework-primitives
Sep 13, 2022
cc7d678
Merge branch 'main' into evolution-framework-primitives
Sep 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions qiskit/algorithms/time_evolvers/__init__.py
Original file line number Diff line number Diff line change
@@ -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.
96 changes: 96 additions & 0 deletions qiskit/algorithms/time_evolvers/evolution_problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# 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 __future__ import annotations
from typing import Dict

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.opflow import PauliSumOp
from ..list_or_dict import ListOrDict
from ...quantum_info.operators.base_operator import BaseOperator


class EvolutionProblem:
"""Evolution problem class.

This class is the input to time evolution algorithms and must contain information on the total
evolution time, a quantum state to be evolved and under which Hamiltonian the state is evolved.
"""

def __init__(
self,
hamiltonian: BaseOperator | PauliSumOp,
time: float,
initial_state: QuantumCircuit | None = None,
Comment thread
dlasecki marked this conversation as resolved.
Outdated
aux_operators: ListOrDict[BaseOperator | PauliSumOp] | None = None,
truncation_threshold: float = 1e-12,
t_param: Parameter | None = None,
param_value_dict: Dict[Parameter, complex]
Comment thread
dlasecki marked this conversation as resolved.
Outdated
| None = None, # parametrization will become supported in BaseOperator soon
):
"""
Args:
hamiltonian: The Hamiltonian under which to evolve the system.
time: Total time of evolution.
initial_state: The quantum state to be evolved for methods like Trotterization.
For variational time evolutions, where the evolution happens in an ansatz,
this argument is not required.
aux_operators: Optional list of auxiliary operators to be evaluated with the
evolved ``initial_state`` and their expectation values returned.
truncation_threshold: Defines a threshold under which values can be assumed to be 0.
Used when ``aux_operators`` is provided.
t_param: Time parameter in case of a time-dependent Hamiltonian. This
free parameter must be within the ``hamiltonian``.
param_value_dict: Maps free parameters in the problem to values. Depending on the
algorithm, it might refer to e.g. a Hamiltonian or an initial state.
Comment thread
Cryoris marked this conversation as resolved.
Outdated

Raises:
ValueError: If non-positive time of evolution is provided.
"""

self.t_param = t_param
self.param_value_dict = param_value_dict
self.hamiltonian = hamiltonian
self.time = time
self.initial_state = initial_state
self.aux_operators = aux_operators
self.truncation_threshold = truncation_threshold
Comment thread
dlasecki marked this conversation as resolved.

@property
def time(self) -> float:
"""Returns time."""
return self._time

@time.setter
def time(self, time: float) -> None:
"""
Sets time and validates it.

Raises:
ValueError: If time is not positive.
"""
if time <= 0:
raise ValueError(f"Evolution time must be > 0 but was {time}.")
self._time = time

def validate_params(self) -> None:
"""
Checks if all parameters present in the Hamiltonian are also present in the dictionary
that maps them to values.

Raises:
ValueError: If Hamiltonian parameters cannot be bound with data provided.
"""
if isinstance(self.hamiltonian, PauliSumOp) and self.hamiltonian.parameters:
raise ValueError("A global parametrized coefficient for PauliSumOp is not allowed.")
Comment thread
dlasecki marked this conversation as resolved.
39 changes: 39 additions & 0 deletions qiskit/algorithms/time_evolvers/evolution_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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 __future__ import annotations
from typing import Tuple

from qiskit import QuantumCircuit
from qiskit.algorithms.list_or_dict import ListOrDict
from ..algorithm_result import AlgorithmResult


class EvolutionResult(AlgorithmResult):
"""Class for holding evolution result."""

def __init__(
self,
evolved_state: QuantumCircuit,
aux_ops_evaluated: ListOrDict[Tuple[complex, complex]] | None = None,
Comment thread
dlasecki marked this conversation as resolved.
Outdated
):
"""
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
37 changes: 37 additions & 0 deletions qiskit/algorithms/time_evolvers/imaginary_evolver.py
Original file line number Diff line number Diff line change
@@ -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()
37 changes: 37 additions & 0 deletions qiskit/algorithms/time_evolvers/real_evolver.py
Original file line number Diff line number Diff line change
@@ -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()
11 changes: 11 additions & 0 deletions test/python/algorithms/time_evolvers/__init__.py
Original file line number Diff line number Diff line change
@@ -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.
101 changes: 101 additions & 0 deletions test/python/algorithms/time_evolvers/test_evolution_problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# 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 ddt import data, ddt, unpack
from numpy.testing import assert_raises
from qiskit.algorithms.time_evolvers.evolution_problem import EvolutionProblem
from qiskit.quantum_info import Pauli, SparsePauliOp
from qiskit.circuit import Parameter
from qiskit.opflow import Y, Z, One, X, Zero, PauliSumOp


@ddt
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_param_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.param_value_dict, expected_param_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]
param_value_dict = {t_parameter: 3.2}

evo_problem = EvolutionProblem(
hamiltonian,
time,
initial_state,
aux_operators,
t_param=t_parameter,
param_value_dict=param_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_param_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.param_value_dict, expected_param_value_dict)

@data([Y, -1, One], [Y, -1.2, One], [Y, 0, One])
@unpack
def test_init_errors(self, hamiltonian, time, initial_state):
"""Tests expected errors are thrown on invalid time argument."""
with assert_raises(ValueError):
_ = EvolutionProblem(hamiltonian, time, initial_state)

def test_validate_params(self):
"""Tests expected errors are thrown on parameters mismatch."""
param_x = Parameter("x")
with self.subTest(msg="Parameter missing in dict."):
hamiltonian = PauliSumOp(SparsePauliOp([Pauli("X"), Pauli("Y")]), param_x)
evolution_problem = EvolutionProblem(hamiltonian, 2, Zero)
with assert_raises(ValueError):
evolution_problem.validate_params()


if __name__ == "__main__":
unittest.main()
47 changes: 47 additions & 0 deletions test/python/algorithms/time_evolvers/test_evolution_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 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.time_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()