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

HDF5-Property framework integration #461

Merged
merged 82 commits into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
b38221c
WIP: HDF5-integration for property framework
mrossinek Dec 13, 2021
bcfc852
Clean up interface
mrossinek Dec 15, 2021
1ed84bb
refactor: let ElectronicIntegrals derive from PseudoProperty
mrossinek Dec 20, 2021
d350bff
refactor: let Molecule derive from PseudoProperty
mrossinek Dec 20, 2021
e0caa80
feat: implement DriverMetadata HDF5 methods
mrossinek Dec 20, 2021
ad96dbb
feat: add toggle to include PseudoProperty objects in GroupedProperty…
mrossinek Dec 20, 2021
8da5c5c
feat: implement ParticleNumber HDF5 methods
mrossinek Dec 20, 2021
f352879
feat: implement AngularMomentum and Magnetization HDF5 methods
mrossinek Dec 20, 2021
e3c781e
feat: implement ElectronicBasisTransform HDF5 methods
mrossinek Dec 20, 2021
2582792
fix: lint
mrossinek Dec 20, 2021
a53ec4e
fix: fix unittests
mrossinek Dec 20, 2021
8f16dae
remove comment
mrossinek Dec 20, 2021
01bc99f
fix: spell
mrossinek Dec 20, 2021
7513faf
feat: also store Qiskit Nature version
mrossinek Dec 22, 2021
32c0f49
handle potential error cases in Property.import_and_build_from_hdf5
mrossinek Jan 4, 2022
c765960
Fix copyright
mrossinek Jan 5, 2022
dccbf68
feat: introduce individual version numbers per Property class
mrossinek Jan 6, 2022
1c89a2b
WIP: HDF5 integration into vibrational properties
mrossinek Jan 7, 2022
bf17bd4
Fix copyright
mrossinek Jan 7, 2022
640f1ca
fix: property tutorial
mrossinek Jan 7, 2022
0c5baed
Update typehints
mrossinek Jan 7, 2022
e492add
Run black
mrossinek Jan 7, 2022
235bbb7
Remove @abstractmethod from Property.from_hdf5
mrossinek Jan 7, 2022
aed4b80
Add more missing typehints
mrossinek Jan 7, 2022
23599c9
Merge branch 'main' into hdf5-property-saving
mrossinek Jan 7, 2022
dc1078c
refactor: introduce HDF5Storable Protocol
mrossinek Jan 17, 2022
bf2fc94
refactor: remove PseudoProperty in favor of Interpretable Protocol
mrossinek Jan 21, 2022
0bac014
Fix linters
mrossinek Jan 21, 2022
e30ad1c
Fix ASTransformer caught error type
mrossinek Jan 21, 2022
3a99013
Fix copyright
mrossinek Jan 21, 2022
ca8aad3
Fix imports
mrossinek Jan 21, 2022
4c05c82
Merge branch 'main' into hdf5-property-saving
mrossinek Jan 21, 2022
5ebae89
More guards against Property type
mrossinek Jan 21, 2022
b7ffaf5
More import fixes
mrossinek Jan 21, 2022
1670ab1
fix: property tutorial
mrossinek Jan 24, 2022
453f6ef
fix: ElectronicStructureDriverResult.__str__
mrossinek Jan 24, 2022
d2a59ff
refactor: remove Property base class where not needed
mrossinek Jan 24, 2022
3d90371
test: basic hdf5 method unittests
mrossinek Jan 24, 2022
f370e6a
test: *StructureDriverResult from_hdf5 methods
mrossinek Jan 24, 2022
fa81f0b
docs: HDF5 documentation
mrossinek Jan 25, 2022
3bab27f
refactor: formally deprecate PseudoProperty class
mrossinek Jan 25, 2022
00e3f61
docs: actual HDF5 save and load examples
mrossinek Jan 25, 2022
f69ef8a
Fix spell
mrossinek Jan 25, 2022
c8322fc
Merge branch 'main' into hdf5-property-saving
mrossinek Jan 26, 2022
f2bc521
fix: avoid name clash with multiple atoms of same kind
mrossinek Jan 26, 2022
be391ff
fix: ElectronicEnergy.from_hdf5 group access
mrossinek Jan 26, 2022
78f7bc4
Update unittest HDF5 resource
mrossinek Jan 26, 2022
af6f373
fix: ParticleNumber.from_hdf5 occupation dataset access
mrossinek Jan 27, 2022
e5eda6e
Merge branch 'main' into hdf5-property-saving
mrossinek Jan 27, 2022
8c273ff
Fix #519
mrossinek Jan 27, 2022
0dd68de
Merge branch 'main' into hdf5-property-saving
mrossinek Jan 27, 2022
c75c0df
Merge branch 'main' into hdf5-property-saving
mrossinek Jan 31, 2022
2db827b
Update qiskit_nature/properties/property.py
mrossinek Feb 1, 2022
0ed5228
Update docs
mrossinek Feb 1, 2022
2d08d81
Rename save_to_hdf5(..., force -> replace)
mrossinek Feb 1, 2022
2a5097a
refactor: fix DriverMetadata HDF5 attribute names
mrossinek Feb 1, 2022
05d6da6
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 1, 2022
738c8a3
refactor: make from_hdf5 a staticmethod
mrossinek Feb 2, 2022
7a4161c
feat: store Molecule.units in HDF5
mrossinek Feb 2, 2022
4e9622a
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 2, 2022
d125694
fix: update expected HDF5 result
mrossinek Feb 2, 2022
d18efe9
docs: include backwards compatibility expectations
mrossinek Feb 3, 2022
e090bf9
feat: add skip_unreadable_data toggle to HDF5 loading methods
mrossinek Feb 3, 2022
1f38cc5
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 3, 2022
be19ba0
Fix spell
mrossinek Feb 3, 2022
f142692
docs: explicitly request error raising
mrossinek Feb 3, 2022
4060069
docs: use `:func:` instead of `:class:`
mrossinek Feb 3, 2022
d8d45b4
docs: ensure *StructureDriverResults are documented
mrossinek Feb 3, 2022
a550ef8
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 3, 2022
8323dac
refactor: enforce keyword arguments in hdf5 module
mrossinek Feb 4, 2022
887e5df
Update driver return types
mrossinek Feb 4, 2022
66564a9
Run black
mrossinek Feb 4, 2022
6826293
Add reno
mrossinek Feb 4, 2022
c5e08ed
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 9, 2022
7e89b84
feat: use Molecule.units during from_hdf5
mrossinek Feb 9, 2022
88208f8
test: refactor _hdf5 method tests
mrossinek Feb 9, 2022
4de53bb
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 9, 2022
fcf140a
fix: README test
mrossinek Feb 10, 2022
ed23adf
refactor: use only public API in PropertyTest
mrossinek Feb 10, 2022
3f13448
refactor: update type hints
mrossinek Feb 10, 2022
0a426bb
Merge branch 'main' into hdf5-property-saving
mrossinek Feb 10, 2022
404c460
fix: update TestVibrationalStructureDriverResult to G16 Rev.C01
mrossinek Feb 10, 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
3 changes: 3 additions & 0 deletions .pylintdict
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ hardcoded
hartree
hartrees
hcore
hdf
heidelberg
heisenberg
hermite
Expand All @@ -192,6 +193,7 @@ intel
intelvem
interatomic
internuclear
interpretable
ints
ising
iso
Expand Down Expand Up @@ -221,6 +223,7 @@ knowles
kohn
kwarg
kwargs
kwds
labelled
lda
len
Expand Down
17 changes: 17 additions & 0 deletions docs/apidocs/qiskit_nature.hdf5.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
HDF5
==================

.. _qiskit_nature-hdf5:

.. automodule:: qiskit_nature.hdf5

.. rubric:: Functions

.. autosummary::
load_from_hdf5
save_to_hdf5

.. rubric:: Classes

.. autosummary::
HDF5Storable
36 changes: 28 additions & 8 deletions docs/tutorials/08_property_framework.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -708,11 +708,11 @@
"\t\t\tAlpha\n",
"\t\t\t<(2, 2) matrix with 2 non-zero entries>\n",
"\t\t\t[0, 0] = -1.2563390730032498\n",
"\t\t\t[1, 1] = -0.4718960072811426\n",
"\t\t\t[1, 1] = -0.47189600728114245\n",
"\t\t\tBeta\n",
"\t\t\t<(2, 2) matrix with 2 non-zero entries>\n",
"\t\t\t[0, 0] = -1.2563390730032498\n",
"\t\t\t[1, 1] = -0.4718960072811426\n",
"\t\t\t[1, 1] = -0.47189600728114245\n",
"\t\t(MO) 2-Body Terms:\n",
"\t\t\tAlpha-Alpha\n",
"\t\t\t<(2, 2, 2, 2) matrix with 8 non-zero entries>\n",
Expand Down Expand Up @@ -785,15 +785,15 @@
"\t\t\t\tAlpha\n",
"\t\t\t\t<(2, 2) matrix with 4 non-zero entries>\n",
"\t\t\t\t[0, 0] = 0.6944743507776598\n",
"\t\t\t\t[0, 1] = -0.9278334704592321\n",
"\t\t\t\t[0, 1] = -0.927833470459232\n",
"\t\t\t\t[1, 0] = -0.9278334704592321\n",
"\t\t\t\t[1, 1] = 0.6944743507776601\n",
"\t\t\t\t[1, 1] = 0.6944743507776604\n",
"\t\t\t\tBeta\n",
"\t\t\t\t<(2, 2) matrix with 4 non-zero entries>\n",
"\t\t\t\t[0, 0] = 0.6944743507776598\n",
"\t\t\t\t[0, 1] = -0.9278334704592321\n",
"\t\t\t\t[0, 1] = -0.927833470459232\n",
"\t\t\t\t[1, 0] = -0.9278334704592321\n",
"\t\t\t\t[1, 1] = 0.6944743507776601\n",
"\t\t\t\t[1, 1] = 0.6944743507776604\n",
"\tAngularMomentum:\n",
"\t\t4 SOs\n",
"\tMagnetization:\n",
Expand Down Expand Up @@ -1047,6 +1047,8 @@
"from itertools import product\n",
"from typing import List\n",
"\n",
"import h5py\n",
"\n",
"from qiskit_nature.drivers import QMolecule\n",
"from qiskit_nature.operators.second_quantization import FermionicOp\n",
"from qiskit_nature.properties.second_quantization.electronic.bases import ElectronicBasis\n",
Expand Down Expand Up @@ -1078,6 +1080,16 @@
" string += [f\"\\t{self._num_molecular_orbitals} MOs\"]\n",
" return \"\\n\".join(string)\n",
"\n",
" def to_hdf5(self, parent: h5py.Group) -> None:\n",
" super().to_hdf5(parent)\n",
" group = parent.require_group(self.name)\n",
"\n",
" group.attrs[\"num_molecular_orbitals\"] = self._num_molecular_orbitals\n",
"\n",
" @classmethod\n",
" def from_hdf5(cls, h5py_group: h5py.Group) -> \"ElectronicDensity\":\n",
" return ElectronicDensity(h5py_group.attrs[\"num_molecular_orbitals\"])\n",
"\n",
" @classmethod\n",
" def from_legacy_driver_result(cls, result) -> \"ElectronicDensity\":\n",
" cls._validate_input_type(result, QMolecule)\n",
Expand Down Expand Up @@ -1217,7 +1229,7 @@
{
"data": {
"text/html": [
"<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td><code>qiskit-terra</code></td><td>0.20.0.dev0+7af16a3</td></tr><tr><td><code>qiskit-aer</code></td><td>0.10.2</td></tr><tr><td><code>qiskit-ignis</code></td><td>0.7.0</td></tr><tr><td><code>qiskit-nature</code></td><td>0.4.0</td></tr><tr><td><code>qiskit-finance</code></td><td>0.4.0</td></tr><tr><td><code>qiskit-optimization</code></td><td>0.4.0</td></tr><tr><td><code>qiskit-machine-learning</code></td><td>0.3.0</td></tr><tr><th>System information</th></tr><tr><td>Python version</td><td>3.8.12</td></tr><tr><td>Python compiler</td><td>Clang 10.0.0 </td></tr><tr><td>Python build</td><td>default, Oct 12 2021 06:23:56</td></tr><tr><td>OS</td><td>Darwin</td></tr><tr><td>CPUs</td><td>2</td></tr><tr><td>Memory (Gb)</td><td>12.0</td></tr><tr><td colspan='2'>Fri Feb 04 13:55:22 2022 EST</td></tr></table>"
"<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td><code>qiskit-terra</code></td><td>0.20.0.dev0+9a743fb</td></tr><tr><td><code>qiskit-aer</code></td><td>0.11.0</td></tr><tr><td><code>qiskit-ignis</code></td><td>0.7.0</td></tr><tr><td><code>qiskit-ibmq-provider</code></td><td>0.19.0.dev0+8455b01</td></tr><tr><td><code>qiskit-nature</code></td><td>0.4.0</td></tr><tr><th>System information</th></tr><tr><td>Python version</td><td>3.9.9</td></tr><tr><td>Python compiler</td><td>GCC 11.2.1 20210728 (Red Hat 11.2.1-1)</td></tr><tr><td>Python build</td><td>main, Nov 19 2021 00:00:00</td></tr><tr><td>OS</td><td>Linux</td></tr><tr><td>CPUs</td><td>4</td></tr><tr><td>Memory (Gb)</td><td>14.842281341552734</td></tr><tr><td colspan='2'>Mon Jan 24 14:34:24 2022 CET</td></tr></table>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
Expand Down Expand Up @@ -1245,6 +1257,14 @@
"%qiskit_version_table\n",
"%qiskit_copyright"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "889fbac9",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand All @@ -1263,7 +1283,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
"version": "3.9.9"
}
},
"nbformat": 4,
Expand Down
3 changes: 2 additions & 1 deletion qiskit_nature/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2021.
# (C) Copyright IBM 2018, 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
Expand Down Expand Up @@ -39,6 +39,7 @@
circuit
converters
drivers
hdf5
mappers
operators
problems
Expand Down
68 changes: 68 additions & 0 deletions qiskit_nature/drivers/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from typing import Callable, Tuple, List, Optional, cast
import copy

import h5py
import numpy as np
import scipy.linalg

Expand All @@ -36,6 +37,8 @@ class Molecule:
directly if its needed.
"""

VERSION = 1

def __init__(
self,
geometry: List[Tuple[str, List[float]]],
Expand Down Expand Up @@ -76,6 +79,71 @@ def __init__(

self._perturbations = None # type: Optional[List[float]]

def to_hdf5(self, parent: h5py.Group) -> None:
"""Stores this instance in an HDF5 group inside of the provided parent group.

See also :func:`~qiskit_nature.hdf5.HDF5Storable.to_hdf5` for more details.

Args:
parent: the parent HDF5 group.
"""
group = parent.require_group(self.__class__.__name__)
group.attrs["__class__"] = self.__class__.__name__
group.attrs["__module__"] = self.__class__.__module__
group.attrs["__version__"] = self.VERSION

geometry_group = group.create_group("geometry", track_order=True)
for idx, geom in enumerate(self._geometry):
symbol, coords = geom
geometry_group.create_dataset(str(idx), data=coords)
geometry_group[str(idx)].attrs["symbol"] = symbol

group.attrs["units"] = self.units.value
group.attrs["multiplicity"] = self.multiplicity
group.attrs["charge"] = self.charge

if self._masses:
group.create_dataset("masses", data=self._masses)

@staticmethod
def from_hdf5(h5py_group: h5py.Group) -> Molecule:
"""Constructs a new instance from the data stored in the provided HDF5 group.

See also :func:`~qiskit_nature.hdf5.HDF5Storable.from_hdf5` for more details.

Args:
h5py_group: the HDF5 group from which to load the data.

Returns:
A new instance of this class.
"""
geometry = []
for atom in h5py_group["geometry"].values():
geometry.append((atom.attrs["symbol"], list(atom[...])))

units: UnitsType
for unit in UnitsType:
if unit.value == h5py_group.attrs["units"]:
units = unit
break
else:
units = UnitsType.ANGSTROM

multiplicity = h5py_group.attrs["multiplicity"]
charge = h5py_group.attrs["charge"]

masses = None
if "masses" in h5py_group.keys():
masses = list(h5py_group["masses"])

return Molecule(
geometry,
multiplicity=multiplicity,
charge=charge,
units=units,
masses=masses,
)

def __str__(self) -> str:
string = ["Molecule:"]
string += [f"\tMultiplicity: {self._multiplicity}"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2020, 2021.
# (C) Copyright IBM 2020, 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
Expand All @@ -17,7 +17,7 @@
from abc import abstractmethod
from enum import Enum

from qiskit_nature.properties.second_quantization.electronic.types import GroupedElectronicProperty
from qiskit_nature.properties.second_quantization.electronic import ElectronicStructureDriverResult
from .base_driver import BaseDriver


Expand All @@ -43,6 +43,6 @@ class ElectronicStructureDriver(BaseDriver):
"""

@abstractmethod
def run(self) -> GroupedElectronicProperty:
"""Returns a GroupedElectronicProperty output as produced by the driver."""
def run(self) -> ElectronicStructureDriverResult:
"""Returns a ElectronicStructureDriverResult output as produced by the driver."""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from enum import Enum

from qiskit.exceptions import MissingOptionalLibraryError
from qiskit_nature.properties.second_quantization.electronic.types import GroupedElectronicProperty
from qiskit_nature.properties.second_quantization.electronic import ElectronicStructureDriverResult
from .electronic_structure_driver import ElectronicStructureDriver, MethodType
from ..molecule import Molecule
from ...exceptions import UnsupportMethodError
Expand Down Expand Up @@ -169,7 +169,7 @@ def driver_kwargs(self, value: Optional[Dict[str, Any]]) -> None:
"""set driver kwargs"""
self._driver_kwargs = value

def run(self) -> GroupedElectronicProperty:
def run(self) -> ElectronicStructureDriverResult:
driver_class = ElectronicStructureDriverType.driver_class_from_type(
self.driver_type, self.method
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

from qiskit_nature import QiskitNatureError
from qiskit_nature.constants import BOHR, PERIODIC_TABLE
from qiskit_nature.settings import settings
from qiskit_nature.properties.second_quantization.driver_metadata import DriverMetadata
from qiskit_nature.properties.second_quantization.electronic import (
ElectronicStructureDriverResult,
Expand Down Expand Up @@ -406,9 +405,11 @@ def _construct_driver_result(self) -> ElectronicStructureDriverResult:
self._populate_driver_result_particle_number(driver_result)
self._populate_driver_result_electronic_energy(driver_result)

if not settings.dict_aux_operators:
driver_result.add_property(AngularMomentum(self._nmo * 2))
driver_result.add_property(Magnetization(self._nmo * 2))
# TODO: once https://github.com/Qiskit/qiskit-nature/issues/312 is fixed we can stop adding
# these properties by default.
# if not settings.dict_aux_operators:
driver_result.add_property(AngularMomentum(self._nmo * 2))
driver_result.add_property(Magnetization(self._nmo * 2))

return driver_result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import numpy as np
from qiskit.utils.validation import validate_min

from qiskit_nature.properties.second_quantization.driver_metadata import DriverMetadata
from qiskit_nature.properties.second_quantization.electronic import (
ElectronicStructureDriverResult,
Expand Down Expand Up @@ -516,9 +517,9 @@ def _construct_driver_result(self) -> ElectronicStructureDriverResult:
self._populate_driver_result_electronic_energy(driver_result)
self._populate_driver_result_electronic_dipole_moment(driver_result)

# TODO: once https://github.com/Qiskit/qiskit-terra/issues/6772 is resolved, we no longer
# _have_ to add these properties. However, until then the interpret method relies on indices
# of the aux_operators which are incorrect if these properties are not added.
# TODO: once https://github.com/Qiskit/qiskit-nature/issues/312 is fixed we can stop adding
# these properties by default.
# if not settings.dict_aux_operators:
driver_result.add_property(AngularMomentum(self._mol.nao * 2))
driver_result.add_property(Magnetization(self._mol.nao * 2))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2020, 2021.
# (C) Copyright IBM 2020, 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
Expand All @@ -16,8 +16,8 @@

from abc import abstractmethod

from qiskit_nature.properties.second_quantization.vibrational.types import (
GroupedVibrationalProperty,
from qiskit_nature.properties.second_quantization.vibrational import (
VibrationalStructureDriverResult,
)
from .base_driver import BaseDriver

Expand All @@ -28,6 +28,6 @@ class VibrationalStructureDriver(BaseDriver):
"""

@abstractmethod
def run(self) -> GroupedVibrationalProperty:
"""Returns a GroupedVibrationalProperty output as produced by the driver."""
def run(self) -> VibrationalStructureDriverResult:
"""Returns a VibrationalStructureDriverResult output as produced by the driver."""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
from enum import Enum

from qiskit.exceptions import MissingOptionalLibraryError
from qiskit_nature.properties.second_quantization.vibrational.types import (
GroupedVibrationalProperty,
from qiskit_nature.properties.second_quantization.vibrational import (
VibrationalStructureDriverResult,
)
from .vibrational_structure_driver import VibrationalStructureDriver
from ..molecule import Molecule
Expand Down Expand Up @@ -146,7 +146,7 @@ def driver_kwargs(self, value: Optional[Dict[str, Any]]) -> None:
"""set driver kwargs"""
self._driver_kwargs = value

def run(self) -> GroupedVibrationalProperty:
def run(self) -> VibrationalStructureDriverResult:
driver_class = VibrationalStructureDriverType.driver_class_from_type(self.driver_type)
driver = driver_class.from_molecule( # type: ignore
self.molecule, self.basis, self.driver_kwargs
Expand Down
Loading