herutriana44's picture
First Commit
b7d9967 verified
raw
history blame contribute delete
No virus
7.52 kB
# This code is part of Qiskit.
#
# (C) Copyright IBM 2020, 2023.
#
# 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.
"""EvolutionOp Class"""
from typing import List, Optional, Set, Union, cast
import numpy as np
import scipy
from qiskit.circuit import Instruction, ParameterExpression
from qiskit.opflow.exceptions import OpflowError
from qiskit.opflow.list_ops.composed_op import ComposedOp
from qiskit.opflow.list_ops.list_op import ListOp
from qiskit.opflow.list_ops.summed_op import SummedOp
from qiskit.opflow.list_ops.tensored_op import TensoredOp
from qiskit.opflow.operator_base import OperatorBase
from qiskit.opflow.primitive_ops.matrix_op import MatrixOp
from qiskit.opflow.primitive_ops.primitive_op import PrimitiveOp
from qiskit.quantum_info import Statevector
from qiskit.utils.deprecation import deprecate_func
class EvolvedOp(PrimitiveOp):
r"""
Deprecated: Class for wrapping Operator Evolutions for compilation (``convert``) by an EvolutionBase
method later, essentially acting as a placeholder. Note that EvolvedOp is a weird case of
PrimitiveOp. It happens to be that it fits into the PrimitiveOp interface nearly perfectly,
and it essentially represents a placeholder for a PrimitiveOp later, even though it doesn't
actually hold a primitive object. We could have chosen for it to be an OperatorBase,
but would have ended up copying and pasting a lot of code from PrimitiveOp."""
primitive: PrimitiveOp
@deprecate_func(
since="0.24.0",
additional_msg="For code migration guidelines, visit https://qisk.it/opflow_migration.",
)
def __init__(
self, primitive: OperatorBase, coeff: Union[complex, ParameterExpression] = 1.0
) -> None:
"""
Args:
primitive: The operator being wrapped to signify evolution later.
coeff: A coefficient multiplying the operator
"""
super().__init__(primitive, coeff=coeff)
def primitive_strings(self) -> Set[str]:
return self.primitive.primitive_strings()
@property
def num_qubits(self) -> int:
return self.primitive.num_qubits
def add(self, other: OperatorBase) -> Union["EvolvedOp", SummedOp]:
if not self.num_qubits == other.num_qubits:
raise ValueError(
"Sum over operators with different numbers of qubits, {} and {}, is not well "
"defined".format(self.num_qubits, other.num_qubits)
)
if isinstance(other, EvolvedOp) and self.primitive == other.primitive:
return EvolvedOp(self.primitive, coeff=self.coeff + other.coeff)
if isinstance(other, SummedOp):
op_list = [cast(OperatorBase, self)] + other.oplist
return SummedOp(op_list)
return SummedOp([self, other])
def adjoint(self) -> "EvolvedOp":
return EvolvedOp(self.primitive.adjoint() * -1, coeff=self.coeff.conjugate())
def equals(self, other: OperatorBase) -> bool:
if not isinstance(other, EvolvedOp) or not self.coeff == other.coeff:
return False
return self.primitive == other.primitive
def tensor(self, other: OperatorBase) -> TensoredOp:
if isinstance(other, TensoredOp):
return TensoredOp([cast(OperatorBase, self)] + other.oplist)
return TensoredOp([self, other])
def _expand_dim(self, num_qubits: int) -> TensoredOp:
# pylint: disable=cyclic-import
from ..operator_globals import I
return self.tensor(I ^ num_qubits)
def permute(self, permutation: List[int]) -> "EvolvedOp":
return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff)
def compose(
self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False
) -> OperatorBase:
new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
if front:
return other.compose(new_self)
if isinstance(other, ComposedOp):
return ComposedOp([new_self] + other.oplist)
return ComposedOp([new_self, other])
def __str__(self) -> str:
prim_str = str(self.primitive)
if self.coeff == 1.0:
return f"e^(-i*{prim_str})"
else:
return f"{self.coeff} * e^(-i*{prim_str})"
def __repr__(self) -> str:
return f"EvolvedOp({repr(self.primitive)}, coeff={self.coeff})"
def reduce(self) -> "EvolvedOp":
return EvolvedOp(self.primitive.reduce(), coeff=self.coeff)
def assign_parameters(self, param_dict: dict) -> Union["EvolvedOp", ListOp]:
param_value = self.coeff
if isinstance(self.coeff, ParameterExpression):
unrolled_dict = self._unroll_param_dict(param_dict)
if isinstance(unrolled_dict, list):
return ListOp([self.assign_parameters(param_dict) for param_dict in unrolled_dict])
if self.coeff.parameters <= set(unrolled_dict.keys()):
binds = {param: unrolled_dict[param] for param in self.coeff.parameters}
param_value = float(self.coeff.bind(binds))
return EvolvedOp(self.primitive.bind_parameters(param_dict), coeff=param_value)
def eval(
self, front: Optional[Union[str, dict, np.ndarray, OperatorBase, Statevector]] = None
) -> Union[OperatorBase, complex]:
return cast(Union[OperatorBase, complex], self.to_matrix_op().eval(front=front))
def to_matrix(self, massive: bool = False) -> np.ndarray:
if (
isinstance(self.primitive, ListOp)
and self.primitive.__class__.__name__ == ListOp.__name__
):
return np.array(
[
op.exp_i().to_matrix(massive=massive) * self.primitive.coeff * self.coeff
for op in self.primitive.oplist
],
dtype=complex,
)
prim_mat = -1.0j * self.primitive.to_matrix()
return scipy.linalg.expm(prim_mat) * self.coeff
def to_matrix_op(self, massive: bool = False) -> Union[ListOp, MatrixOp]:
"""Returns a ``MatrixOp`` equivalent to this Operator."""
primitive = self.primitive
if isinstance(primitive, ListOp) and primitive.__class__.__name__ == ListOp.__name__:
return ListOp(
[op.exp_i().to_matrix_op() for op in primitive.oplist],
coeff=primitive.coeff * self.coeff,
)
prim_mat = EvolvedOp(primitive).to_matrix(massive=massive)
return MatrixOp(prim_mat, coeff=self.coeff)
def log_i(self, massive: bool = False) -> OperatorBase:
return self.primitive * self.coeff
def to_instruction(self, massive: bool = False) -> Instruction:
mat_op = self.to_matrix_op(massive=massive)
if not isinstance(mat_op, MatrixOp):
raise OpflowError("to_instruction is not allowed for ListOp.")
return mat_op.to_instruction()