Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
[WIP] Refactor Chemistry Drivers to also accept Molecule class (#1297)
Browse files Browse the repository at this point in the history
* Refactor Chemistry Drivers

* add some setters to molecule

* FermionicDriver & BaseDriver properties

* Updated docstrings

* Perturbation support plus unit test case

Co-authored-by: woodsp <woodsp@us.ibm.com>
  • Loading branch information
manoelmarques and woodsp-ibm committed Oct 12, 2020
1 parent b5f9a34 commit 3b6e407
Show file tree
Hide file tree
Showing 19 changed files with 994 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
from qiskit.chemistry.components.variational_forms import UCCSD
from qiskit.chemistry.core import (Hamiltonian, TransformationType, QubitMappingType,
ChemistryOperator, MolecularGroundStateResult)
from qiskit.chemistry.drivers import BaseDriver
from qiskit.chemistry.drivers import FermionicDriver


class MolecularGroundStateEnergy:
""" Molecular ground state energy chemistry application """

def __init__(self,
driver: BaseDriver,
driver: FermionicDriver,
solver: Optional[MinimumEigensolver] = None,
transformation: TransformationType = TransformationType.FULL,
qubit_mapping: QubitMappingType = QubitMappingType.PARITY,
Expand Down Expand Up @@ -69,12 +69,12 @@ def __init__(self,
self._z2symmetry_reduction = z2symmetry_reduction

@property
def driver(self) -> BaseDriver:
def driver(self) -> FermionicDriver:
""" Returns chemistry driver """
return self._driver

@driver.setter
def driver(self, driver: BaseDriver) -> None:
def driver(self, driver: FermionicDriver) -> None:
self._driver = driver

@property
Expand Down
16 changes: 12 additions & 4 deletions qiskit/chemistry/drivers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
:nosignatures:
BaseDriver
FermionicDriver
Driver Common
=============
Expand All @@ -59,8 +60,9 @@
:toctree: ../stubs/
:nosignatures:
UnitsType
Molecule
HFMethodType
UnitsType
BasisType
InitialGuess
Expand Down Expand Up @@ -111,17 +113,23 @@
"""
from ._basedriver import BaseDriver, UnitsType, HFMethodType

from .base_driver import BaseDriver
from .molecule import Molecule
from .fermionic_driver import FermionicDriver, HFMethodType
from .units_type import UnitsType
from .fcidumpd import FCIDumpDriver
from .gaussiand import GaussianDriver, GaussianLogDriver, GaussianLogResult
from .hdf5d import HDF5Driver
from .psi4d import PSI4Driver
from .pyquanted import PyQuanteDriver, BasisType
from .pyscfd import PySCFDriver, InitialGuess

__all__ = ['BaseDriver',
__all__ = ['HFMethodType',
'Molecule',
'BaseDriver',
'FermionicDriver',
'UnitsType',
'HFMethodType',
'FCIDumpDriver',
'GaussianDriver',
'GaussianLogDriver',
Expand Down
93 changes: 93 additions & 0 deletions qiskit/chemistry/drivers/base_driver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2020.
#
# 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.

"""
This module implements the abstract base class for driver modules.
"""

from typing import Optional
from abc import ABC, abstractmethod

from .molecule import Molecule
from ..qiskit_chemistry_error import QiskitChemistryError


class BaseDriver(ABC):
"""
Base class for Qiskit's chemistry drivers.
"""

@abstractmethod
def __init__(self,
molecule: Optional[Molecule] = None,
basis: str = 'sto3g',
hf_method: str = 'rhf',
supports_molecule: bool = False) -> None:
"""
Args:
molecule: molecule
basis: basis set
hf_method: Hartree-Fock Method type
supports_molecule: Indicates if driver supports molecule
Raises:
QiskitChemistryError: Molecule passed but driver doesn't support it.
"""
if molecule is not None and not supports_molecule:
raise QiskitChemistryError("Driver doesn't support molecule.")

self._molecule = molecule
self._basis = basis
self._hf_method = hf_method
self._supports_molecule = supports_molecule

@property
def supports_molecule(self) -> bool:
"""
True for derived classes that support Molecule.
Returns:
True if Molecule is supported.
"""
return self._supports_molecule

@property
def molecule(self) -> Optional[Molecule]:
""" return molecule """
return self._molecule

@molecule.setter
def molecule(self, value: Molecule) -> None:
""" set molecule """
if not self.supports_molecule:
raise QiskitChemistryError("Driver doesn't support molecule.")
self._molecule = value

@property
def basis(self) -> str:
""" return basis """
return self._basis

@basis.setter
def basis(self, value: str) -> None:
""" set basis """
self._basis = value

@property
def hf_method(self) -> str:
""" return Hartree-Fock method """
return self._hf_method

@hf_method.setter
def hf_method(self, value: str) -> None:
""" set Hartree-Fock method """
self._hf_method = value
7 changes: 4 additions & 3 deletions qiskit/chemistry/drivers/fcidumpd/fcidumpdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
"""FCIDump Driver."""

from typing import List, Optional
from qiskit.chemistry.drivers import BaseDriver
from qiskit.chemistry import QiskitChemistryError, QMolecule
from ..base_driver import BaseDriver
from ...qiskit_chemistry_error import QiskitChemistryError
from ...qmolecule import QMolecule
from .dumper import dump
from .parser import parse

Expand Down Expand Up @@ -70,7 +71,7 @@ def run(self) -> QMolecule:
q_mol.nuclear_repulsion_energy = fcidump_data.get('ecore', None)
q_mol.num_orbitals = fcidump_data.get('NORB')
q_mol.multiplicity = fcidump_data.get('MS2', 0) + 1
q_mol.charge = 0 # ensures QMolecule.log() works
q_mol.molecular_charge = 0 # ensures QMolecule.log() works
q_mol.num_beta = (fcidump_data.get('NELEC') - (q_mol.multiplicity - 1)) // 2
q_mol.num_alpha = fcidump_data.get('NELEC') - q_mol.num_beta
if self.atoms is not None:
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 2018, 2020.
# (C) Copyright IBM 2020.
#
# 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 @@ -11,19 +11,14 @@
# that they have been altered from the originals.

"""
This module implements the abstract base class for driver modules.
This module implements the abstract base class for fermionic driver modules.
"""

from abc import ABC, abstractmethod
from abc import abstractmethod
from enum import Enum

from qiskit.chemistry import QMolecule


class UnitsType(Enum):
""" Units Type Enum """
ANGSTROM = 'Angstrom'
BOHR = 'Bohr'
from ..qmolecule import QMolecule
from .base_driver import BaseDriver


class HFMethodType(Enum):
Expand All @@ -33,15 +28,11 @@ class HFMethodType(Enum):
UHF = 'uhf'


class BaseDriver(ABC):
class FermionicDriver(BaseDriver):
"""
Base class for Qiskit's chemistry drivers.
Base class for Qiskit's chemistry fermionic drivers.
"""

@abstractmethod
def __init__(self):
pass

@abstractmethod
def run(self) -> QMolecule:
"""
Expand Down
6 changes: 4 additions & 2 deletions qiskit/chemistry/drivers/gaussiand/gaussian_log_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
from typing import Union, List
import logging

from qiskit.chemistry import QiskitChemistryError
from ..base_driver import BaseDriver
from ...qiskit_chemistry_error import QiskitChemistryError
from .gaussian_utils import check_valid, run_g16
from .gaussian_log_result import GaussianLogResult

logger = logging.getLogger(__name__)


class GaussianLogDriver:
class GaussianLogDriver(BaseDriver):
""" Gaussian™ 16 log driver.
Qiskit chemistry driver using the Gaussian™ 16 program that provides the log
Expand Down Expand Up @@ -55,6 +56,7 @@ def __init__(self, jcf: Union[str, List[str]]) -> None:
jcf = '\n'.join(jcf)

self._jcf = jcf
super().__init__()

@staticmethod
def _check_valid():
Expand Down
60 changes: 49 additions & 11 deletions qiskit/chemistry/drivers/gaussiand/gaussiandriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,24 @@

""" Gaussian Driver """

from typing import Union, List
from typing import Union, List, Optional
import sys
import io
import logging
import os
import tempfile
import numpy as np
from qiskit.chemistry import QMolecule, QiskitChemistryError
from qiskit.chemistry.drivers import BaseDriver
from ..units_type import UnitsType
from ..fermionic_driver import FermionicDriver
from ...qiskit_chemistry_error import QiskitChemistryError
from ..molecule import Molecule
from ...qmolecule import QMolecule
from .gaussian_utils import check_valid, run_g16

logger = logging.getLogger(__name__)


class GaussianDriver(BaseDriver):
class GaussianDriver(FermionicDriver):
"""
Qiskit chemistry driver using the Gaussian™ 16 program.
Expand All @@ -42,29 +45,64 @@ class GaussianDriver(BaseDriver):
def __init__(self,
config: Union[str, List[str]] =
'# rhf/sto-3g scf(conventional)\n\n'
'h2 molecule\n\n0 1\nH 0.0 0.0 0.0\nH 0.0 0.0 0.735\n\n') -> None:
'h2 molecule\n\n0 1\nH 0.0 0.0 0.0\nH 0.0 0.0 0.735\n\n',
molecule: Optional[Molecule] = None,
basis: str = 'sto-3g',
hf_method: str = 'rhf') -> None:
"""
Args:
config: A molecular configuration conforming to Gaussian™ 16 format
config: A molecular configuration conforming to Gaussian™ 16 format.
molecule: A driver independent Molecule definition instance may be provided. When
a molecule is supplied the `config` parameter is ignored and the Molecule instance,
along with `basis` and `hf_method` is used to build a basic config instead.
The Molecule object is read when the driver is run and converted to the driver
dependent configuration for the computation. This allows, for example, the Molecule
geometry to be updated to compute different points.
basis: Basis set
hf_method: Hartree-Fock Method type; `rhf`, `rohf`, `uhf`
Raises:
QiskitChemistryError: Invalid Input
"""
GaussianDriver._check_valid()
if not isinstance(config, list) and not isinstance(config, str):
raise QiskitChemistryError("Invalid input for Gaussian Driver '{}'".format(config))
if not isinstance(config, str) and not isinstance(config, list):
raise QiskitChemistryError("Invalid config for Gaussian Driver '{}'".format(config))

if isinstance(config, list):
config = '\n'.join(config)

super().__init__()
super().__init__(molecule=molecule,
basis=basis,
hf_method=hf_method,
supports_molecule=True)
self._config = config

@staticmethod
def _check_valid():
check_valid()

def _from_molecule_to_str(self) -> str:
units = None
if self.molecule.units == UnitsType.ANGSTROM:
units = 'Angstrom'
elif self.molecule.units == UnitsType.BOHR:
units = 'Bohr'
else:
raise QiskitChemistryError("Unknown unit '{}'".format(self.molecule.units.value))
cfg1 = f'# {self.hf_method}/{self.basis} UNITS={units} scf(conventional)\n\n'
name = ''.join([name for (name, _) in self.molecule.geometry])
geom = '\n'.join([name + ' ' + ' '.join(map(str, coord))
for (name, coord) in self.molecule.geometry])
cfg2 = f'{name} molecule\n\n'
cfg3 = f'{self.molecule.charge} {self.molecule.multiplicity}\n{geom}\n\n'
return cfg1 + cfg2 + cfg3

def run(self) -> QMolecule:
cfg = self._config
if self.molecule is not None:
cfg = self._from_molecule_to_str()
else:
cfg = self._config

while not cfg.endswith('\n\n'):
cfg += '\n'

Expand Down Expand Up @@ -93,7 +131,7 @@ def run(self) -> QMolecule:
logger.warning("Failed to remove MatrixElement file %s", fname)

q_mol.origin_driver_name = 'GAUSSIAN'
q_mol.origin_driver_config = self._config
q_mol.origin_driver_config = cfg
return q_mol

@staticmethod
Expand Down

0 comments on commit 3b6e407

Please sign in to comment.