Skip to content

Commit

Permalink
refactor: deprecate qiskit_nature.ListOrDict
Browse files Browse the repository at this point in the history
This removes the usage of ListOrDict wherever possible.
The QubitConverter class is the last place this is needed, because the
UCC and UVCC ansatze pass their excitation operators for conversion as
a list.

That is fine for now, but may be improved when tackling qiskit-community#771
  • Loading branch information
mrossinek committed Aug 6, 2022
1 parent 62d0947 commit 365fe95
Show file tree
Hide file tree
Showing 22 changed files with 192 additions and 231 deletions.
10 changes: 10 additions & 0 deletions qiskit_nature/list_or_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from qiskit.algorithms.minimum_eigen_solvers.minimum_eigen_solver import (
ListOrDict as ListOrDictType,
)
from qiskit_nature.deprecation import warn_deprecated, DeprecatedType, NatureDeprecationWarning

# pylint: disable=invalid-name
T = TypeVar("T")
Expand All @@ -34,6 +35,15 @@ def __init__(self, values: Optional[ListOrDictType] = None):
Args:
values: an optional object of `list` or `dict` type.
"""
warn_deprecated(
"0.5.0",
old_type=DeprecatedType.CLASS,
old_name="qiskit_nature.ListOrDict",
additional_msg=(
". Qiskit Nature will now always produce dictionary-style auxiliary operators."
),
category=NatureDeprecationWarning,
)
if isinstance(values, list):
values = dict(enumerate(values))
elif values is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@

"""The calculation of excited states via an Eigensolver algorithm"""

from __future__ import annotations

from typing import Union, Optional, Tuple

from qiskit.algorithms import Eigensolver
from qiskit.opflow import PauliSumOp

from qiskit_nature import ListOrDictType, QiskitNatureError
from qiskit_nature import QiskitNatureError
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature import ListOrDict
from qiskit_nature.second_q.operators import SecondQuantizedOp
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult
Expand Down Expand Up @@ -60,25 +61,20 @@ def solver(self, solver: Union[Eigensolver, EigensolverFactory]) -> None:
def get_qubit_operators(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[ListOrDictType[PauliSumOp]]]:
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[dict[str, PauliSumOp]]]:
"""Gets the operator and auxiliary operators, and transforms the provided auxiliary operators"""
# Note that ``aux_ops`` contains not only the transformed ``aux_operators`` passed by the
# user but also additional ones from the transformation
second_q_ops = problem.second_q_ops()
aux_second_q_ops: ListOrDictType[SecondQuantizedOp]
if isinstance(second_q_ops, list):
main_second_q_op = second_q_ops[0]
aux_second_q_ops = second_q_ops[1:]
elif isinstance(second_q_ops, dict):
name = problem.main_property_name
main_second_q_op = second_q_ops.pop(name, None)
if main_second_q_op is None:
raise ValueError(
f"The main `SecondQuantizedOp` associated with the {name} property cannot be "
"`None`."
)
aux_second_q_ops = second_q_ops
name = problem.main_property_name
main_second_q_op = second_q_ops.pop(name, None)
if main_second_q_op is None:
raise ValueError(
f"The main `SecondQuantizedOp` associated with the {name} property cannot be "
"`None`."
)
aux_second_q_ops = second_q_ops

main_operator = self._qubit_converter.convert(
main_second_q_op,
Expand All @@ -88,24 +84,18 @@ def get_qubit_operators(
aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)

if aux_operators is not None:
wrapped_aux_operators: ListOrDict[Union[SecondQuantizedOp, PauliSumOp]] = ListOrDict(
aux_operators
)
for name_aux, aux_op in iter(wrapped_aux_operators):
for name_aux, aux_op in aux_operators.items():
if isinstance(aux_op, SecondQuantizedOp):
converted_aux_op = self._qubit_converter.convert_match(aux_op, True)
else:
converted_aux_op = aux_op
if isinstance(aux_ops, list):
aux_ops.append(converted_aux_op)
elif isinstance(aux_ops, dict):
if name_aux in aux_ops.keys():
raise QiskitNatureError(
f"The key '{name_aux}' is already taken by an internally constructed "
"auxiliary operator! Please use a different name for your custom "
"operator."
)
aux_ops[name_aux] = converted_aux_op
if name_aux in aux_ops.keys():
raise QiskitNatureError(
f"The key '{name_aux}' is already taken by an internally constructed "
"auxiliary operator! Please use a different name for your custom "
"operator."
)
aux_ops[name_aux] = converted_aux_op

if isinstance(self._solver, EigensolverFactory):
# this must be called after transformation.transform
Expand All @@ -119,7 +109,7 @@ def get_qubit_operators(
def solve(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> EigenstateResult:
"""Compute Ground and Excited States properties.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@

""" The excited states calculation interface """

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Optional, Union, Tuple

from qiskit.opflow import PauliSumOp

from qiskit_nature import ListOrDictType
from qiskit_nature.second_q.operators import SecondQuantizedOp
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult
Expand All @@ -30,7 +31,7 @@ class ExcitedStatesSolver(ABC):
def solve(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> EigenstateResult:
r"""Compute the excited states energies of the molecule that was supplied via the driver.
Expand All @@ -53,8 +54,8 @@ def solver(self):
def get_qubit_operators(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[ListOrDictType[PauliSumOp]]]:
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[dict[str, PauliSumOp]]]:
"""Construct qubit operators by getting the second quantized operators from the problem
(potentially running a driver in doing so [can be computationally expensive])
and using a QubitConverter to map + reduce the operators to qubit ops
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

"""The calculation of excited states via the qEOM algorithm"""

from __future__ import annotations

from typing import List, Union, Optional, Tuple, Dict, cast
import itertools
import logging
Expand All @@ -30,7 +32,6 @@
PauliSumOp,
)

from qiskit_nature import ListOrDictType
from qiskit_nature.second_q.operators import SecondQuantizedOp
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult
Expand Down Expand Up @@ -84,14 +85,14 @@ def solver(self):
def get_qubit_operators(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[ListOrDictType[PauliSumOp]]]:
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[dict[str, PauliSumOp]]]:
return self._gsc.get_qubit_operators(problem, aux_operators)

def solve(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[SecondQuantizedOp]] = None,
aux_operators: Optional[dict[str, SecondQuantizedOp]] = None,
) -> EigenstateResult:
"""Run the excited-states calculation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

"""Ground state computation using a minimum eigensolver."""

from __future__ import annotations

from typing import Union, List, Optional, Dict, Tuple

import numpy as np
Expand All @@ -22,10 +24,9 @@
from qiskit.algorithms import MinimumEigensolver
from qiskit.opflow import OperatorBase, PauliSumOp, StateFn, CircuitSampler

from qiskit_nature import ListOrDictType, QiskitNatureError
from qiskit_nature import QiskitNatureError
from qiskit_nature.second_q.operators import SecondQuantizedOp
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature import ListOrDict
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult
from .ground_state_solver import GroundStateSolver
Expand Down Expand Up @@ -67,7 +68,7 @@ def returns_groundstate(self) -> bool:
def solve(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> EigenstateResult:
"""Compute Ground State properties.
Expand Down Expand Up @@ -96,50 +97,39 @@ def solve(
def get_qubit_operators(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[ListOrDictType[PauliSumOp]]]:
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[dict[str, PauliSumOp]]]:
"""Gets the operator and auxiliary operators, and transforms the provided auxiliary operators"""
# Note that ``aux_ops`` contains not only the transformed ``aux_operators`` passed by the
# user but also additional ones from the transformation
second_q_ops = problem.second_q_ops()
aux_second_q_ops: ListOrDictType[SecondQuantizedOp]
if isinstance(second_q_ops, list):
main_second_q_op = second_q_ops[0]
aux_second_q_ops = second_q_ops[1:]
elif isinstance(second_q_ops, dict):
name = problem.main_property_name
main_second_q_op = second_q_ops.pop(name, None)
if main_second_q_op is None:
raise ValueError(
f"The main `SecondQuantizedOp` associated with the {name} property cannot be "
"`None`."
)
aux_second_q_ops = second_q_ops
name = problem.main_property_name
main_second_q_op = second_q_ops.pop(name, None)
if main_second_q_op is None:
raise ValueError(
f"The main `SecondQuantizedOp` associated with the {name} property cannot be "
"`None`."
)
aux_second_q_ops = second_q_ops
main_operator = self._qubit_converter.convert(
main_second_q_op,
num_particles=problem.num_particles,
sector_locator=problem.symmetry_sector_locator,
)
aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)
if aux_operators is not None:
wrapped_aux_operators: ListOrDict[Union[SecondQuantizedOp, PauliSumOp]] = ListOrDict(
aux_operators
)
for name_aux, aux_op in iter(wrapped_aux_operators):
for name_aux, aux_op in aux_operators.items():
if isinstance(aux_op, SecondQuantizedOp):
converted_aux_op = self._qubit_converter.convert_match(aux_op, True)
else:
converted_aux_op = aux_op
if isinstance(aux_ops, list):
aux_ops.append(converted_aux_op)
elif isinstance(aux_ops, dict):
if name_aux in aux_ops.keys():
raise QiskitNatureError(
f"The key '{name_aux}' is already taken by an internally constructed "
"auxiliary operator! Please use a different name for your custom "
"operator."
)
aux_ops[name_aux] = converted_aux_op
if name_aux in aux_ops.keys():
raise QiskitNatureError(
f"The key '{name_aux}' is already taken by an internally constructed "
"auxiliary operator! Please use a different name for your custom "
"operator."
)
aux_ops[name_aux] = converted_aux_op

if isinstance(self._solver, MinimumEigensolverFactory):
# this must be called after transformation.transform
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

"""The ground state calculation interface."""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Union, Tuple

Expand All @@ -22,7 +24,6 @@
from qiskit.result import Result
from qiskit.opflow import OperatorBase, PauliSumOp

from qiskit_nature import ListOrDictType
from qiskit_nature.second_q.operators import SecondQuantizedOp
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.problems import BaseProblem
Expand All @@ -44,7 +45,7 @@ def __init__(self, qubit_converter: QubitConverter) -> None:
def solve(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> EigenstateResult:
"""Compute the ground state energy of the molecule that was supplied via the driver.
Expand All @@ -62,8 +63,8 @@ def solve(
def get_qubit_operators(
self,
problem: BaseProblem,
aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[ListOrDictType[PauliSumOp]]]:
aux_operators: Optional[dict[str, Union[SecondQuantizedOp, PauliSumOp]]] = None,
) -> Tuple[PauliSumOp, Optional[dict[str, PauliSumOp]]]:
"""Construct qubit operators by getting the second quantized operators from the problem
(potentially running a driver in doing so [can be computationally expensive])
and using a QubitConverter to map + reduce the operators to qubit ops
Expand Down
Loading

0 comments on commit 365fe95

Please sign in to comment.