Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update API to allow QubitMapper where QubitConverter is used. #999

Merged
merged 25 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
643cb61
Failing tests but stable QubitConverter and QubitMapper can now be i…
Anthony-Gandon Nov 29, 2022
1402cc4
Modifications of the mappers map()
Anthony-Gandon Nov 30, 2022
b8f7d7f
Update API for QubitMapper
Anthony-Gandon Dec 8, 2022
7e2e585
Adds release note
Anthony-Gandon Dec 8, 2022
0480c2c
Merge branch 'main' into refactor_qubitmapper
Anthony-Gandon Dec 8, 2022
925e821
Small corrections after first feedback.
Anthony-Gandon Dec 9, 2022
75d856c
Fix indentation:
Anthony-Gandon Dec 9, 2022
149d3da
Change for map_all to map and map to map_single.
Anthony-Gandon Dec 21, 2022
ad0ef6f
Merge branch 'main' into refactor_qubitmapper
Anthony-Gandon Dec 21, 2022
a8f0758
Updated release note
Anthony-Gandon Dec 21, 2022
f86726b
Updated release note 2
Anthony-Gandon Dec 21, 2022
265b83c
Small updates before pushing
Anthony-Gandon Dec 22, 2022
8e9f7b5
small fix spell
Anthony-Gandon Dec 22, 2022
049e372
First review of docstrings
Anthony-Gandon Dec 22, 2022
83913fc
Other docstrings
Anthony-Gandon Dec 22, 2022
4a16031
Make black
Anthony-Gandon Dec 23, 2022
15dd0e1
Merge with main and adaptqeom
Anthony-Gandon Jan 3, 2023
ab261b3
Fix mypy
Anthony-Gandon Jan 3, 2023
968d556
Merge branch 'main' into refactor_qubitmapper
Anthony-Gandon Jan 5, 2023
b5ff687
Fix comments
Anthony-Gandon Jan 5, 2023
7baf401
fix
Anthony-Gandon Jan 5, 2023
1822ef7
Rolled back the type expansion of the map and convert_match methods, …
Anthony-Gandon Jan 5, 2023
cb81678
Implement the unwrapper in the _ListOrDict class
Anthony-Gandon Jan 6, 2023
3552929
Fix spelling
Anthony-Gandon Jan 6, 2023
17f9954
Fix spell 2
Anthony-Gandon Jan 6, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from qiskit.opflow import PauliSumOp

from qiskit_nature import QiskitNatureError
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.operators import SparseLabelOp
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult
Expand All @@ -34,7 +34,7 @@ class ExcitedStatesEigensolver(ExcitedStatesSolver):

def __init__(
self,
qubit_converter: QubitConverter,
qubit_converter: Union[QubitConverter, QubitMapper],
Anthony-Gandon marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future I would like to rename this argument to qubit_mapper. This will not be an easy process so it will be done in a separate PR once all the API is updated to support QubitMapper and works. I'm mentioning it now just as an FYI.
This will not be an easy undertaking but I will start discussing some plans on how to do this properly offline.

solver: Union[Eigensolver, EigensolverFactory],
) -> None:
"""
Expand Down Expand Up @@ -70,19 +70,27 @@ def get_qubit_operators(

num_particles = getattr(problem, "num_particles", None)

main_operator = self._qubit_converter.convert(
main_second_q_op,
num_particles=num_particles,
sector_locator=problem.symmetry_sector_locator,
)
aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)
if isinstance(self._qubit_converter, QubitConverter):
main_operator = self._qubit_converter.convert(
main_second_q_op,
num_particles=num_particles,
sector_locator=problem.symmetry_sector_locator,
)
aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)

else:
main_operator = self._qubit_converter.map(main_second_q_op)
aux_ops = self._qubit_converter.map_all(aux_second_q_ops)
Anthony-Gandon marked this conversation as resolved.
Show resolved Hide resolved

if aux_operators is not None:
for name_aux, aux_op in aux_operators.items():
if isinstance(aux_op, SparseLabelOp):
converted_aux_op = self._qubit_converter.convert_match(
aux_op, suppress_none=True
)
if isinstance(self._qubit_converter, QubitConverter):
converted_aux_op = self._qubit_converter.convert_match(
aux_op, suppress_none=True
)
else:
converted_aux_op = self._qubit_converter.map_all(aux_op)
else:
converted_aux_op = aux_op
if name_aux in aux_ops.keys():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def get_qubit_operators(
) -> 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 and reduce the operators to qubit operators.
and using a QubitConverter or QubitMapper to map and reduce the operators to qubit operators.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need to do a thorough pass of the docs. Just mentioning this so its on our radar (I know that this is still a draft PR)


Args:
problem: A class encoding a problem to be solved.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
)
from qiskit.primitives import BaseEstimator

from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.operators import SparseLabelOp
from qiskit_nature.second_q.problems import (
BaseProblem,
ElectronicStructureProblem,
VibrationalStructureProblem,
EigenstateResult,
)
from qiskit_nature.second_q.problems import EigenstateResult

from .qeom_electronic_ops_builder import build_electronic_ops
from .qeom_vibrational_ops_builder import build_vibrational_ops
from .excited_states_solver import ExcitedStatesSolver
Expand Down Expand Up @@ -165,9 +165,13 @@ def solve(

num_particles = getattr(problem, "num_particles", None)

self._untapered_qubit_op_main = self._gsc.qubit_converter.convert_only(
main_second_q_op, num_particles
)
if isinstance(self._gsc.qubit_converter, QubitConverter):
self._untapered_qubit_op_main = self._gsc.qubit_converter.convert_only(
main_second_q_op, num_particles
)
else:
self._untapered_qubit_op_main = self._gsc.qubit_converter.map(main_second_q_op)

matrix_operators_dict, size = self._prepare_matrix_operators(problem)

# 3. Evaluate eom operators
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

from typing import Callable, Dict, List, Tuple

from qiskit.opflow import PauliSumOp
from qiskit.opflow import PauliSumOp, Z2Symmetries
from qiskit.tools import parallel_map
from qiskit.utils import algorithm_globals

from qiskit_nature import QiskitNatureError
from qiskit_nature.second_q.circuit.library import UCC
from qiskit_nature.second_q.operators import FermionicOp
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper


def build_electronic_ops(
Expand All @@ -36,7 +36,7 @@ def build_electronic_ops(
[int, tuple[int, int]],
list[tuple[tuple[int, ...], tuple[int, ...]]],
],
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
) -> Tuple[
Dict[str, PauliSumOp],
Dict[str, List[bool]],
Expand All @@ -56,8 +56,8 @@ def build_electronic_ops(
:meth:`generate_fermionic_excitations`.
qubit_converter: The ``QubitConverter`` to use for mapping and symmetry reduction. The Z2
symmetries stored in this instance are the basis for the commutativity
information returned by this method.

information returned by this method. These symmetries are set to `None`
when a ``QubitMapper`` is used.
Returns:
A tuple containing the hopping operators, the types of commutativities and the excitation
indices.
Expand Down Expand Up @@ -100,7 +100,7 @@ def build_electronic_ops(
def _build_single_hopping_operator(
excitation: Tuple[Tuple[int, ...], Tuple[int, ...]],
num_spatial_orbitals: int,
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
) -> Tuple[PauliSumOp, List[bool]]:
label = []
for occ in excitation[0]:
Expand All @@ -111,8 +111,13 @@ def _build_single_hopping_operator(
{" ".join(label): 4.0 ** len(excitation[0])}, num_spin_orbitals=2 * num_spatial_orbitals
)

qubit_op = qubit_converter.convert_only(fer_op, qubit_converter.num_particles)
z2_symmetries = qubit_converter.z2symmetries
if isinstance(qubit_converter, QubitConverter):
qubit_op = qubit_converter.convert_only(fer_op, num_particles=qubit_converter.num_particles)
z2_symmetries = qubit_converter.z2symmetries

else:
qubit_op = qubit_converter.map(fer_op)
z2_symmetries = Z2Symmetries([], [], [])

commutativities = []
if not z2_symmetries.is_empty():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
from qiskit.tools import parallel_map
from qiskit.utils import algorithm_globals

from qiskit_nature import QiskitNatureError
from qiskit_nature.second_q.circuit.library import UVCC
from qiskit_nature.second_q.operators import VibrationalOp
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper


def build_vibrational_ops(
Expand All @@ -34,7 +35,7 @@ def build_vibrational_ops(
[int, tuple[int, int]],
list[tuple[tuple[int, ...], tuple[int, ...]]],
],
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
) -> Tuple[
Dict[str, PauliSumOp],
Dict[str, List[bool]],
Expand Down Expand Up @@ -91,7 +92,7 @@ def build_vibrational_ops(
def _build_single_hopping_operator(
excitation: Tuple[Tuple[int, ...], Tuple[int, ...]],
num_modals: List[int],
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
) -> PauliSumOp:
label = []
for occ in excitation[0]:
Expand All @@ -100,6 +101,13 @@ def _build_single_hopping_operator(
label.append(f"-_{VibrationalOp.build_dual_index(num_modals, unocc)}")

vibrational_op = VibrationalOp({" ".join(label): 1}, num_modals)
qubit_op: PauliSumOp = qubit_converter.convert_match(vibrational_op)

qubit_op: PauliSumOp
if isinstance(qubit_converter, QubitConverter):
qubit_op = qubit_converter.convert_match(vibrational_op)
elif issubclass(type(qubit_converter), QubitMapper):
qubit_op = qubit_converter.map_all(vibrational_op)
else:
raise QiskitNatureError("QubitConverter object is not valid")
Anthony-Gandon marked this conversation as resolved.
Show resolved Hide resolved

return qubit_op
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from qiskit_nature import QiskitNatureError
from qiskit_nature.second_q.operators import SparseLabelOp
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult

Expand All @@ -31,7 +31,7 @@ class GroundStateEigensolver(GroundStateSolver):

def __init__(
self,
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
Anthony-Gandon marked this conversation as resolved.
Show resolved Hide resolved
solver: MinimumEigensolver | MinimumEigensolverFactory,
) -> None:
"""
Expand Down Expand Up @@ -68,6 +68,7 @@ def solve(
with an internally constructed auxiliary operator. Note: the names used for the
internal auxiliary operators correspond to the `Property.name` attributes which
generated the respective operators.
QiskitNatureError: Invalid type for ``QubitConverter``.

Returns:
An interpreted :class:`~.EigenstateResult`. For more information see also
Expand Down Expand Up @@ -96,20 +97,29 @@ def get_qubit_operators(
if hasattr(problem, "num_particles"):
num_particles = problem.num_particles

main_operator = self._qubit_converter.convert(
main_second_q_op,
num_particles=num_particles,
sector_locator=problem.symmetry_sector_locator,
)
aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)
if isinstance(self._qubit_converter, QubitConverter):
main_operator = self._qubit_converter.convert(
main_second_q_op,
num_particles=num_particles,
sector_locator=problem.symmetry_sector_locator,
)
aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)
else:
main_operator = self._qubit_converter.map(main_second_q_op)
aux_ops = self._qubit_converter.map_all(aux_second_q_ops)

if aux_operators is not None:
for name_aux, aux_op in aux_operators.items():
if isinstance(aux_op, SparseLabelOp):
converted_aux_op = self._qubit_converter.convert_match(
aux_op, suppress_none=True
)
if isinstance(self._qubit_converter, QubitConverter):
converted_aux_op = self._qubit_converter.convert_match(
aux_op, suppress_none=True
)
else:
converted_aux_op = self._qubit_converter.map_all(aux_op)
else:
converted_aux_op = aux_op

if name_aux in aux_ops.keys():
raise QiskitNatureError(
f"The key '{name_aux}' is already taken by an internally constructed "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from qiskit.quantum_info.operators.base_operator import BaseOperator

from qiskit_nature.second_q.operators import SparseLabelOp
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.problems import BaseProblem
from qiskit_nature.second_q.problems import EigenstateResult

Expand All @@ -31,7 +31,7 @@
class GroundStateSolver(ABC):
"""The ground state calculation interface."""

def __init__(self, qubit_converter: QubitConverter) -> None:
def __init__(self, qubit_converter: QubitConverter | QubitMapper) -> None:
"""
Args:
qubit_converter: A class that converts second quantized operator to qubit operator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

"""The minimum eigensolver factory for ground state calculation algorithms."""

from __future__ import annotations

from abc import ABC, abstractmethod

from qiskit.algorithms.minimum_eigensolvers import MinimumEigensolver

from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.problems import BaseProblem


Expand All @@ -25,7 +27,7 @@ class MinimumEigensolverFactory(ABC):

@abstractmethod
def get_solver(
self, problem: BaseProblem, qubit_converter: QubitConverter
self, problem: BaseProblem, qubit_converter: QubitConverter | QubitMapper
) -> MinimumEigensolver:
"""Returns a minimum eigensolver, based on the qubit operator transformation.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

"""The NumPy minimum eigensolver factory for ground state calculation algorithms."""

from __future__ import annotations

from qiskit.algorithms.minimum_eigensolvers import MinimumEigensolver, NumPyMinimumEigensolver
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.problems import BaseProblem
from .minimum_eigensolver_factory import MinimumEigensolverFactory

Expand All @@ -37,7 +39,7 @@ def __init__(
self._minimum_eigensolver = NumPyMinimumEigensolver(**kwargs)

def get_solver(
self, problem: BaseProblem, qubit_converter: QubitConverter
self, problem: BaseProblem, qubit_converter: QubitConverter | QubitMapper
) -> MinimumEigensolver:
"""Returns a NumPyMinimumEigensolver which possibly uses the default filter criterion
provided by the ``problem``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@

import logging
import numpy as np

from qiskit.algorithms.minimum_eigensolvers import MinimumEigensolver, VQE
from qiskit.algorithms.optimizers import Minimizer, Optimizer
from qiskit.circuit import QuantumCircuit
from qiskit.primitives import BaseEstimator

from qiskit_nature.second_q.circuit.library import HartreeFock, UCC
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.problems import (
ElectronicStructureProblem,
)
Expand Down Expand Up @@ -117,7 +116,7 @@ def initial_state(self, initial_state: QuantumCircuit | None) -> None:
def get_solver( # type: ignore[override]
self,
problem: ElectronicStructureProblem,
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
) -> MinimumEigensolver:
"""Returns a VQE with a UCC wavefunction ansatz, based on ``qubit_converter``.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from qiskit.primitives import BaseEstimator

from qiskit_nature.second_q.circuit.library import UVCC, VSCF
from qiskit_nature.second_q.mappers import QubitConverter
from qiskit_nature.second_q.mappers import QubitConverter, QubitMapper
from qiskit_nature.second_q.problems import (
VibrationalStructureProblem,
)
Expand Down Expand Up @@ -114,7 +114,7 @@ def initial_point(self, initial_point: np.ndarray | InitialPoint | None) -> None
def get_solver( # type: ignore[override]
self,
problem: VibrationalStructureProblem,
qubit_converter: QubitConverter,
qubit_converter: QubitConverter | QubitMapper,
) -> MinimumEigensolver:
"""Returns a VQE with a :class:`~.UVCC` wavefunction ansatz, based on ``qubit_converter``.

Expand Down
Loading