# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2023, 2024.
#
# 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.
"""Variational Quantum Imaginary Time Evolution algorithm."""
from __future__ import annotations
from collections.abc import Mapping, Sequence
from typing import Type, Callable
import numpy as np
from scipy.integrate import OdeSolver
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.primitives import BaseEstimator
from .solvers.ode.forward_euler_solver import ForwardEulerSolver
from .variational_principles import ImaginaryVariationalPrinciple, ImaginaryMcLachlanPrinciple
from .var_qte import VarQTE
from ..imaginary_time_evolver import ImaginaryTimeEvolver
[docs]class VarQITE(VarQTE, ImaginaryTimeEvolver):
"""Variational Quantum Imaginary Time Evolution algorithm.
.. code-block::python
import numpy as np
from qiskit_algorithms import TimeEvolutionProblem, VarQITE
from qiskit_algorithms.time_evolvers.variational import ImaginaryMcLachlanPrinciple
from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import SparsePauliOp, Pauli
from qiskit.primitives import Estimator
observable = SparsePauliOp.from_list(
[
("II", 0.2252),
("ZZ", 0.5716),
("IZ", 0.3435),
("ZI", -0.4347),
("YY", 0.091),
("XX", 0.091),
]
)
ansatz = EfficientSU2(observable.num_qubits, reps=1)
init_param_values = np.ones(len(ansatz.parameters)) * np.pi/2
var_principle = ImaginaryMcLachlanPrinciple()
time = 1
# without evaluating auxiliary operators
evolution_problem = TimeEvolutionProblem(observable, time)
var_qite = VarQITE(ansatz, init_param_values, var_principle)
evolution_result = var_qite.evolve(evolution_problem)
# evaluating auxiliary operators
aux_ops = [Pauli("XX"), Pauli("YZ")]
evolution_problem = TimeEvolutionProblem(observable, time, aux_operators=aux_ops)
var_qite = VarQITE(ansatz, init_param_values, var_principle, Estimator())
evolution_result = var_qite.evolve(evolution_problem)
"""
# pylint: disable=too-many-positional-arguments
def __init__(
self,
ansatz: QuantumCircuit,
initial_parameters: Mapping[Parameter, float] | Sequence[float],
variational_principle: ImaginaryVariationalPrinciple | None = None,
estimator: BaseEstimator | None = None,
ode_solver: Type[OdeSolver] | str = ForwardEulerSolver,
lse_solver: Callable[[np.ndarray, np.ndarray], np.ndarray] | None = None,
num_timesteps: int | None = None,
imag_part_tol: float = 1e-7,
num_instability_tol: float = 1e-7,
) -> None:
r"""
Args:
ansatz: Ansatz to be used for variational time evolution.
initial_parameters: Initial parameter values for the ansatz.
variational_principle: Variational Principle to be used. Defaults to
``ImaginaryMcLachlanPrinciple``.
estimator: An estimator primitive used for calculating expectation values of
TimeEvolutionProblem.aux_operators.
ode_solver: ODE solver callable that implements a SciPy ``OdeSolver`` interface or a
string indicating a valid method offered by SciPy.
lse_solver: Linear system of equations solver callable. It accepts ``A`` and ``b`` to
solve ``Ax=b`` and returns ``x``. If ``None``, the default ``np.linalg.lstsq``
solver is used.
num_timesteps: The number of timesteps to take. If ``None``, it is
automatically selected to achieve a timestep of approximately 0.01. Only
relevant in case of the ``ForwardEulerSolver``.
imag_part_tol: Allowed value of an imaginary part that can be neglected if no
imaginary part is expected.
num_instability_tol: The amount of negative value that is allowed to be
rounded up to 0 for quantities that are expected to be non-negative.
"""
if variational_principle is None:
variational_principle = ImaginaryMcLachlanPrinciple()
super().__init__(
ansatz,
initial_parameters,
variational_principle,
estimator,
ode_solver,
lse_solver=lse_solver,
num_timesteps=num_timesteps,
imag_part_tol=imag_part_tol,
num_instability_tol=num_instability_tol,
)