From 663b101e36720d238bc97be229c380ed5f29c62e Mon Sep 17 00:00:00 2001 From: Manoel Marques Date: Wed, 5 May 2021 11:43:16 -0400 Subject: [PATCH] Switch to using black for code formatting --- .pylintrc | 5 +- CONTRIBUTING.md | 4 + Makefile | 5 +- qiskit_nature/__init__.py | 4 +- qiskit_nature/algorithms/__init__.py | 47 +- .../excited_states_solvers/__init__.py | 13 +- .../eigensolver_factories/__init__.py | 4 +- .../numpy_eigensolver_factory.py | 38 +- .../excited_states_eigensolver.py | 21 +- .../excited_states_solver.py | 8 +- .../algorithms/excited_states_solvers/qeom.py | 270 +++++---- .../ground_state_solvers/__init__.py | 29 +- .../ground_state_solvers/adapt_vqe.py | 103 ++-- .../ground_state_eigensolver.py | 60 +- .../ground_state_solver.py | 30 +- .../minimum_eigensolver_factories/__init__.py | 11 +- .../minimum_eigensolver_factory.py | 8 +- .../numpy_minimum_eigensolver_factory.py | 35 +- .../vqe_ucc_factory.py | 57 +- .../vqe_uvcc_factory.py | 52 +- .../algorithms/pes_samplers/__init__.py | 46 +- .../algorithms/pes_samplers/bopes_sampler.py | 40 +- .../algorithms/pes_samplers/extrapolator.py | 184 ++++--- .../pes_samplers/potentials/__init__.py | 12 +- .../potentials/energy_surface_spline.py | 11 +- .../potentials/harmonic_potential.py | 59 +- .../potentials/morse_potential.py | 68 ++- .../pes_samplers/potentials/potential_base.py | 18 +- qiskit_nature/circuit/library/__init__.py | 25 +- .../circuit/library/ansatzes/__init__.py | 16 +- qiskit_nature/circuit/library/ansatzes/chc.py | 50 +- .../ansatzes/evolved_operator_ansatz.py | 40 +- .../circuit/library/ansatzes/puccd.py | 70 ++- .../circuit/library/ansatzes/succd.py | 71 ++- qiskit_nature/circuit/library/ansatzes/ucc.py | 138 +++-- .../circuit/library/ansatzes/uccsd.py | 33 +- .../library/ansatzes/utils/__init__.py | 4 +- .../utils/fermionic_excitation_generator.py | 44 +- .../utils/vibration_excitation_generator.py | 13 +- .../circuit/library/ansatzes/uvcc.py | 117 ++-- .../circuit/library/ansatzes/uvccsd.py | 23 +- .../library/initial_states/__init__.py | 2 +- .../library/initial_states/hartree_fock.py | 29 +- .../circuit/library/initial_states/vscf.py | 26 +- qiskit_nature/constants.py | 20 +- .../second_quantization/__init__.py | 2 +- .../second_quantization/qubit_converter.py | 163 +++--- qiskit_nature/drivers/__init__.py | 47 +- qiskit_nature/drivers/base_driver.py | 24 +- .../drivers/bosonic_bases/__init__.py | 3 +- .../drivers/bosonic_bases/bosonic_basis.py | 7 +- .../drivers/bosonic_bases/harmonic_basis.py | 250 ++++++--- qiskit_nature/drivers/fcidumpd/__init__.py | 2 +- qiskit_nature/drivers/fcidumpd/dumper.py | 89 ++- .../drivers/fcidumpd/fcidumpdriver.py | 63 ++- qiskit_nature/drivers/fcidumpd/parser.py | 182 +++--- qiskit_nature/drivers/fermionic_driver.py | 9 +- qiskit_nature/drivers/gaussiand/__init__.py | 10 +- .../gaussiand/gaussian_forces_driver.py | 49 +- .../drivers/gaussiand/gaussian_log_driver.py | 25 +- .../drivers/gaussiand/gaussian_log_result.py | 55 +- .../drivers/gaussiand/gaussian_utils.py | 24 +- .../drivers/gaussiand/gaussiandriver.py | 187 ++++--- qiskit_nature/drivers/hdf5d/__init__.py | 2 +- qiskit_nature/drivers/hdf5d/hdf5driver.py | 9 +- qiskit_nature/drivers/molecule.py | 153 +++--- qiskit_nature/drivers/psi4d/__init__.py | 2 +- qiskit_nature/drivers/psi4d/psi4driver.py | 115 ++-- qiskit_nature/drivers/pyquanted/__init__.py | 3 +- qiskit_nature/drivers/pyquanted/integrals.py | 85 +-- .../drivers/pyquanted/pyquantedriver.py | 114 ++-- qiskit_nature/drivers/pyscfd/__init__.py | 3 +- qiskit_nature/drivers/pyscfd/integrals.py | 99 ++-- qiskit_nature/drivers/pyscfd/pyscfdriver.py | 128 +++-- qiskit_nature/drivers/qmolecule.py | 371 +++++++++---- qiskit_nature/drivers/units_type.py | 7 +- qiskit_nature/exceptions.py | 1 + .../mappers/second_quantization/__init__.py | 18 +- .../bravyi_kitaev_mapper.py | 38 +- .../second_quantization/fermionic_mapper.py | 2 +- .../jordan_wigner_mapper.py | 2 +- .../second_quantization/linear_mapper.py | 48 +- .../second_quantization/parity_mapper.py | 2 +- .../second_quantization/qubit_mapper.py | 12 +- .../second_quantization/spin_mapper.py | 2 +- .../second_quantization/vibrational_mapper.py | 2 +- .../operators/second_quantization/__init__.py | 8 +- .../second_quantization/fermionic_op.py | 63 ++- .../second_quantization/qubit_converter.py | 185 ++++--- .../operators/second_quantization/spin_op.py | 58 +- .../second_quantization/star_algebra.py | 6 +- .../second_quantization/vibrational_op.py | 286 +++++++--- .../problems/second_quantization/__init__.py | 6 +- .../second_quantization/base_problem.py | 39 +- .../electronic/__init__.py | 2 +- .../builders/aux_fermionic_ops_builder.py | 36 +- .../builders/fermionic_op_builder.py | 50 +- .../builders/hopping_ops_builder.py | 87 +-- .../electronic_structure_problem.py | 84 ++- .../integrals_calculators/__init__.py | 6 +- .../angular_momentum_integrals_calculator.py | 112 ++-- .../magnetization_integrals_calculator.py | 2 +- .../electronic/result_interpreter.py | 60 +- .../builders/aux_vibrational_ops_builder.py | 15 +- .../builders/hopping_ops_builder.py | 69 ++- .../builders/vibrational_label_builder.py | 10 +- .../builders/vibrational_op_builder.py | 40 +- .../integrals_calculators/__init__.py | 2 +- ...ied_modal_per_mode_integrals_calculator.py | 8 +- .../vibrational/result_interpreter.py | 19 +- .../vibrational_structure_problem.py | 77 ++- qiskit_nature/results/__init__.py | 10 +- qiskit_nature/results/bopes_sampler_result.py | 17 +- qiskit_nature/results/eigenstate_result.py | 100 +++- .../results/electronic_structure_result.py | 302 ++++++---- .../results/vibrational_structure_result.py | 35 +- qiskit_nature/transformers/__init__.py | 6 +- .../transformers/active_space_transformer.py | 337 +++++++----- .../transformers/freeze_core_transformer.py | 20 +- qiskit_nature/version.py | 35 +- requirements-dev.txt | 2 +- test/__init__.py | 2 +- .../test_numpy_eigensolver_factory.py | 37 +- .../test_bosonic_esc_calculation.py | 81 ++- .../test_excited_states_solvers.py | 69 ++- .../test_vqe_ucc_factory.py | 21 +- .../test_vqe_uvcc_factory.py | 20 +- .../ground_state_solvers/test_adapt_vqe.py | 82 ++- .../test_advanced_ucc_variants.py | 145 +++-- .../test_groundstate_eigensolver.py | 253 +++++---- .../ground_state_solvers/test_swaprz.py | 31 +- .../pes_samplers/potentials/test_potential.py | 333 ++++++++--- .../pes_samplers/test_bopes_sampler.py | 33 +- .../pes_samplers/test_extrapolators.py | 443 ++++++++++----- test/circuit/library/ansatzes/test_chc.py | 86 +-- .../ansatzes/test_evolved_op_ansatz.py | 6 +- test/circuit/library/ansatzes/test_puccd.py | 74 ++- test/circuit/library/ansatzes/test_succd.py | 86 ++- test/circuit/library/ansatzes/test_ucc.py | 48 +- test/circuit/library/ansatzes/test_uccsd.py | 124 +++-- test/circuit/library/ansatzes/test_uvcc.py | 84 +-- .../test_fermionic_excitation_generator.py | 139 +++-- .../test_vibration_excitation_generator.py | 27 +- .../initial_states/test_hartree_fock.py | 31 +- .../library/initial_states/test_vscf.py | 8 +- test/drivers/fcidumpd/test_driver_fcidump.py | 184 ++++--- .../fcidumpd/test_driver_fcidump_dumper.py | 89 +-- .../fcidumpd/test_driver_methods_fcidump.py | 106 ++-- .../drivers/gaussiand/test_driver_gaussian.py | 26 +- .../gaussiand/test_driver_gaussian_extra.py | 24 +- .../gaussiand/test_driver_gaussian_forces.py | 112 ++-- .../test_driver_gaussian_from_mat.py | 9 +- .../gaussiand/test_driver_gaussian_log.py | 172 +++--- .../gaussiand/test_driver_methods_gaussian.py | 46 +- test/drivers/hdf5d/test_driver_hdf5.py | 7 +- test/drivers/hdf5d/test_driver_hdf5_save.py | 11 +- .../drivers/psi4d/test_driver_methods_psi4.py | 46 +- test/drivers/psi4d/test_driver_psi4.py | 35 +- test/drivers/psi4d/test_driver_psi4_extra.py | 41 +- .../pyquanted/test_driver_methods_pyquante.py | 81 ++- .../drivers/pyquanted/test_driver_pyquante.py | 18 +- .../pyscfd/test_driver_methods_pyscf.py | 273 +++++---- test/drivers/pyscfd/test_driver_pyscf.py | 18 +- .../drivers/pyscfd/test_driver_pyscf_extra.py | 53 +- test/drivers/test_driver.py | 176 +++--- test/drivers/test_driver_methods_gsc.py | 32 +- test/drivers/test_driver_molecule.py | 208 +++---- .../resources/reference_direct_mapper.py | 263 ++++----- .../test_bravyi_kitaev_mapper.py | 48 +- .../second_quantization/test_direct_mapper.py | 22 +- .../test_jordan_wigner_mapper.py | 48 +- .../second_quantization/test_linear_mapper.py | 60 +- .../second_quantization/test_parity_mapper.py | 48 +- test/nature_test_case.py | 25 +- .../second_quantization/test_fermionic_op.py | 8 +- .../test_qubit_converter.py | 210 +++---- .../second_quantization/test_spin_op.py | 34 +- .../test_vibrational_op.py | 11 +- .../builders/test_fermionic_op_builder.py | 66 ++- .../builders/test_hopping_ops_builder.py | 242 +++++--- ...t_angular_momentum_integrals_calculator.py | 76 ++- ...test_magnetization_integrals_calculator.py | 20 +- ...st_particle_number_integrals_calculator.py | 12 +- .../electronic/resources/resource_reader.py | 7 +- .../test_electronic_structure_problem.py | 47 +- .../builders/test_hopping_ops_builder.py | 240 +++++--- .../test_vibrational_label_builder.py | 23 +- .../builders/test_vibrational_op_builder.py | 22 +- .../vibrational/resources/expected_labels.py | 520 +++++++++--------- .../vibrational/test_vibrational_problem.py | 11 +- test/test_end2end_with_vqe.py | 27 +- test/test_readme_sample.py | 48 +- .../test_active_space_transformer.py | 212 ++++--- .../test_freeze_core_transformer.py | 52 +- tools/check_copyright.py | 96 ++-- tools/extract_deprecation.py | 36 +- tox.ini | 13 +- 197 files changed, 8117 insertions(+), 5026 deletions(-) diff --git a/.pylintrc b/.pylintrc index 4a4392b532..bd5cd6085a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -74,7 +74,8 @@ disable=no-self-use, # disabled as it is too verbose unnecessary-pass, # allow for methods with just "pass", for clarity no-else-return, # relax "elif" after a clause with a return docstring-first-line-empty, # relax docstring style - import-outside-toplevel + import-outside-toplevel, + bad-continuation, bad-whitespace # differences of opinion with black @@ -215,7 +216,7 @@ max-nested-blocks=5 [FORMAT] # Maximum number of characters on a single line. -max-line-length=100 +max-line-length=105 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8eebefbd7..a982478a37 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,10 @@ please ensure that: make style ``` from the root of the Nature repository clone for lint and style conformance checks. + + If your code fails the local style checks (specifically the black + code formatting check) you can use `make black` to automatically + fix update the code formatting. For unit testing please see [Testing](#testing) section below. diff --git a/Makefile b/Makefile index 75514ab50f..7649f7dff5 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,10 @@ mypy: mypy qiskit_nature test tools style: - pycodestyle qiskit_nature test tools + black --check --exclude="gauopen" qiskit_nature test tools + +black: + black --exclude="gauopen" qiskit_nature test tools test: python -m unittest discover -v test diff --git a/qiskit_nature/__init__.py b/qiskit_nature/__init__.py index 561939fe66..3f6f9fcc1a 100644 --- a/qiskit_nature/__init__.py +++ b/qiskit_nature/__init__.py @@ -50,6 +50,6 @@ from .exceptions import QiskitNatureError __all__ = [ - '__version__', - 'QiskitNatureError', + "__version__", + "QiskitNatureError", ] diff --git a/qiskit_nature/algorithms/__init__.py b/qiskit_nature/algorithms/__init__.py index ed0c07579d..665dc33535 100644 --- a/qiskit_nature/algorithms/__init__.py +++ b/qiskit_nature/algorithms/__init__.py @@ -103,25 +103,36 @@ """ -from .excited_states_solvers import (ExcitedStatesEigensolver, ExcitedStatesSolver, QEOM, - EigensolverFactory, NumPyEigensolverFactory) -from .ground_state_solvers import (AdaptVQE, GroundStateEigensolver, GroundStateSolver, - MinimumEigensolverFactory, NumPyMinimumEigensolverFactory, - VQEUCCFactory, VQEUVCCFactory) +from .excited_states_solvers import ( + ExcitedStatesEigensolver, + ExcitedStatesSolver, + QEOM, + EigensolverFactory, + NumPyEigensolverFactory, +) +from .ground_state_solvers import ( + AdaptVQE, + GroundStateEigensolver, + GroundStateSolver, + MinimumEigensolverFactory, + NumPyMinimumEigensolverFactory, + VQEUCCFactory, + VQEUVCCFactory, +) from .pes_samplers import BOPESSampler __all__ = [ - 'ExcitedStatesEigensolver', - 'ExcitedStatesSolver', - 'QEOM', - 'EigensolverFactory', - 'NumPyEigensolverFactory', - 'AdaptVQE', - 'GroundStateEigensolver', - 'GroundStateSolver', - 'MinimumEigensolverFactory', - 'NumPyMinimumEigensolverFactory', - 'VQEUCCFactory', - 'VQEUVCCFactory', - 'BOPESSampler', + "ExcitedStatesEigensolver", + "ExcitedStatesSolver", + "QEOM", + "EigensolverFactory", + "NumPyEigensolverFactory", + "AdaptVQE", + "GroundStateEigensolver", + "GroundStateSolver", + "MinimumEigensolverFactory", + "NumPyMinimumEigensolverFactory", + "VQEUCCFactory", + "VQEUVCCFactory", + "BOPESSampler", ] diff --git a/qiskit_nature/algorithms/excited_states_solvers/__init__.py b/qiskit_nature/algorithms/excited_states_solvers/__init__.py index e5a6742f8a..f72c82f4ac 100644 --- a/qiskit_nature/algorithms/excited_states_solvers/__init__.py +++ b/qiskit_nature/algorithms/excited_states_solvers/__init__.py @@ -34,9 +34,10 @@ from .eigensolver_factories import EigensolverFactory, NumPyEigensolverFactory from .excited_states_eigensolver import ExcitedStatesEigensolver -__all__ = ['ExcitedStatesSolver', - 'ExcitedStatesEigensolver', - 'EigensolverFactory', - 'NumPyEigensolverFactory', - 'QEOM' - ] +__all__ = [ + "ExcitedStatesSolver", + "ExcitedStatesEigensolver", + "EigensolverFactory", + "NumPyEigensolverFactory", + "QEOM", +] diff --git a/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/__init__.py b/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/__init__.py index 641698818d..4debd4e863 100644 --- a/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/__init__.py +++ b/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/__init__.py @@ -33,6 +33,4 @@ from .eigensolver_factory import EigensolverFactory from .numpy_eigensolver_factory import NumPyEigensolverFactory -__all__ = ['EigensolverFactory', - 'NumPyEigensolverFactory' - ] +__all__ = ["EigensolverFactory", "NumPyEigensolverFactory"] diff --git a/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/numpy_eigensolver_factory.py b/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/numpy_eigensolver_factory.py index a85a12467e..c272446f0a 100644 --- a/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/numpy_eigensolver_factory.py +++ b/qiskit_nature/algorithms/excited_states_solvers/eigensolver_factories/numpy_eigensolver_factory.py @@ -25,11 +25,14 @@ class NumPyEigensolverFactory(EigensolverFactory): """A factory to construct a NumPyEigensolver.""" - def __init__(self, - filter_criterion: Callable[[Union[List, np.ndarray], float, Optional[List[float]]], - bool] = None, - k: int = 100, - use_default_filter_criterion: bool = False) -> None: + def __init__( + self, + filter_criterion: Callable[ + [Union[List, np.ndarray], float, Optional[List[float]]], bool + ] = None, + k: int = 100, + use_default_filter_criterion: bool = False, + ) -> None: """ Args: filter_criterion: callable that allows to filter eigenvalues/eigenstates. The minimum @@ -48,36 +51,39 @@ def __init__(self, self._use_default_filter_criterion = use_default_filter_criterion @property - def filter_criterion(self) -> Callable[[Union[List, np.ndarray], float, - Optional[List[float]]], bool]: - """ returns filter criterion """ + def filter_criterion( + self, + ) -> Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool]: + """returns filter criterion""" return self._filter_criterion @filter_criterion.setter - def filter_criterion(self, value: Callable[[Union[List, np.ndarray], float, - Optional[List[float]]], bool]) -> None: - """ sets filter criterion """ + def filter_criterion( + self, + value: Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool], + ) -> None: + """sets filter criterion""" self._filter_criterion = value @property def k(self) -> int: - """ returns k (number of eigenvalues requested) """ + """returns k (number of eigenvalues requested)""" return self._k @k.setter def k(self, k: int) -> None: - """ set k (number of eigenvalues requested) """ - validate_min('k', k, 1) + """set k (number of eigenvalues requested)""" + validate_min("k", k, 1) self._k = k @property def use_default_filter_criterion(self) -> bool: - """ returns whether to use the default filter criterion """ + """returns whether to use the default filter criterion""" return self._use_default_filter_criterion @use_default_filter_criterion.setter def use_default_filter_criterion(self, value: bool) -> None: - """ sets whether to use the default filter criterion """ + """sets whether to use the default filter criterion""" self._use_default_filter_criterion = value def get_solver(self, problem: BaseProblem) -> Eigensolver: diff --git a/qiskit_nature/algorithms/excited_states_solvers/excited_states_eigensolver.py b/qiskit_nature/algorithms/excited_states_solvers/excited_states_eigensolver.py index 75c0ae0ec4..56d3435b50 100644 --- a/qiskit_nature/algorithms/excited_states_solvers/excited_states_eigensolver.py +++ b/qiskit_nature/algorithms/excited_states_solvers/excited_states_eigensolver.py @@ -32,8 +32,11 @@ class ExcitedStatesEigensolver(ExcitedStatesSolver): """The calculation of excited states via an Eigensolver algorithm""" - def __init__(self, qubit_converter: QubitConverter, - solver: Union[Eigensolver, EigensolverFactory]) -> None: + def __init__( + self, + qubit_converter: QubitConverter, + solver: Union[Eigensolver, EigensolverFactory], + ) -> None: """ Args: @@ -55,9 +58,11 @@ def solver(self, solver: Union[Eigensolver, EigensolverFactory]) -> None: """Sets the minimum eigensolver or factory.""" self._solver = solver - def solve(self, problem: BaseProblem, - aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, - ) -> EigenstateResult: + def solve( + self, + problem: BaseProblem, + aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, + ) -> EigenstateResult: """Compute Ground and Excited States properties. Args: @@ -80,7 +85,7 @@ def solve(self, problem: BaseProblem, main_operator = self._qubit_converter.convert( second_q_ops[0], num_particles=problem.num_particles, - sector_locator=problem.symmetry_sector_locator + sector_locator=problem.symmetry_sector_locator, ) aux_ops = self._qubit_converter.convert_match(second_q_ops[1:]) @@ -107,6 +112,8 @@ def solve(self, problem: BaseProblem, eigenstate_result.raw_result = raw_es_result eigenstate_result.eigenenergies = raw_es_result.eigenvalues eigenstate_result.eigenstates = raw_es_result.eigenstates - eigenstate_result.aux_operator_eigenvalues = raw_es_result.aux_operator_eigenvalues + eigenstate_result.aux_operator_eigenvalues = ( + raw_es_result.aux_operator_eigenvalues + ) result = problem.interpret(eigenstate_result) return result diff --git a/qiskit_nature/algorithms/excited_states_solvers/excited_states_solver.py b/qiskit_nature/algorithms/excited_states_solvers/excited_states_solver.py index f05a0729bd..d1317fa568 100644 --- a/qiskit_nature/algorithms/excited_states_solvers/excited_states_solver.py +++ b/qiskit_nature/algorithms/excited_states_solvers/excited_states_solver.py @@ -26,9 +26,11 @@ class ExcitedStatesSolver(ABC): """The excited states calculation interface""" @abstractmethod - def solve(self, problem: BaseProblem, - aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, - ) -> EigenstateResult: + def solve( + self, + problem: BaseProblem, + aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, + ) -> EigenstateResult: r"""Compute the excited states energies of the molecule that was supplied via the driver. Args: diff --git a/qiskit_nature/algorithms/excited_states_solvers/qeom.py b/qiskit_nature/algorithms/excited_states_solvers/qeom.py index 7af0193856..e8b924aab7 100644 --- a/qiskit_nature/algorithms/excited_states_solvers/qeom.py +++ b/qiskit_nature/algorithms/excited_states_solvers/qeom.py @@ -23,8 +23,12 @@ from qiskit.tools.events import TextProgressBar from qiskit.utils import algorithm_globals from qiskit.algorithms import AlgorithmResult -from qiskit.opflow import (Z2Symmetries, commutator, - double_commutator, PauliSumOp, ) +from qiskit.opflow import ( + Z2Symmetries, + commutator, + double_commutator, + PauliSumOp, +) from qiskit_nature.operators.second_quantization import SecondQuantizedOp from qiskit_nature.problems.second_quantization import BaseProblem @@ -38,8 +42,11 @@ class QEOM(ExcitedStatesSolver): """The calculation of excited states via the qEOM algorithm""" - def __init__(self, ground_state_solver: GroundStateSolver, - excitations: Union[str, List[List[int]]] = 'sd') -> None: + def __init__( + self, + ground_state_solver: GroundStateSolver, + excitations: Union[str, List[List[int]]] = "sd", + ) -> None: """ Args: ground_state_solver: a GroundStateSolver object. The qEOM algorithm @@ -63,14 +70,18 @@ def excitations(self, excitations: Union[str, List[List[int]]]) -> None: """The excitations to be included in the eom pseudo-eigenvalue problem. If a string then all excitations of given type will be used. Otherwise a list of custom excitations can directly be provided.""" - if isinstance(excitations, str) and excitations not in ['s', 'd', 'sd']: - raise ValueError('Excitation type must be s (singles), d (doubles) or sd ' - '(singles and doubles)') + if isinstance(excitations, str) and excitations not in ["s", "d", "sd"]: + raise ValueError( + "Excitation type must be s (singles), d (doubles) or sd " + "(singles and doubles)" + ) self._excitations = excitations - def solve(self, problem: BaseProblem, - aux_operators: Optional[List[SecondQuantizedOp]] = None - ) -> EigenstateResult: + def solve( + self, + problem: BaseProblem, + aux_operators: Optional[List[SecondQuantizedOp]] = None, + ) -> EigenstateResult: """Run the excited-states calculation. Construct and solves the EOM pseudo-eigenvalue problem to obtain the excitation energies @@ -86,28 +97,42 @@ def solve(self, problem: BaseProblem, """ if aux_operators is not None: - logger.warning("With qEOM the auxiliary operators can currently only be " - "evaluated on the ground state.") + logger.warning( + "With qEOM the auxiliary operators can currently only be " + "evaluated on the ground state." + ) # 1. Run ground state calculation groundstate_result = self._gsc.solve(problem) # 2. Prepare the excitation operators - self._untapered_qubit_op_main = self._gsc._qubit_converter.map(problem.second_q_ops()[0]) + self._untapered_qubit_op_main = self._gsc._qubit_converter.map( + problem.second_q_ops()[0] + ) matrix_operators_dict, size = self._prepare_matrix_operators(problem) # 3. Evaluate eom operators measurement_results = self._gsc.evaluate_operators( - groundstate_result.eigenstates[0], - matrix_operators_dict) + groundstate_result.eigenstates[0], matrix_operators_dict + ) measurement_results = cast(Dict[str, List[float]], measurement_results) # 4. Post-process ground_state_result to construct eom matrices - m_mat, v_mat, q_mat, w_mat, m_mat_std, v_mat_std, q_mat_std, w_mat_std = \ - self._build_eom_matrices(measurement_results, size) + ( + m_mat, + v_mat, + q_mat, + w_mat, + m_mat_std, + v_mat_std, + q_mat_std, + w_mat_std, + ) = self._build_eom_matrices(measurement_results, size) # 5. solve pseudo-eigenvalue problem - energy_gaps, expansion_coefs = self._compute_excitation_energies(m_mat, v_mat, q_mat, w_mat) + energy_gaps, expansion_coefs = self._compute_excitation_energies( + m_mat, v_mat, q_mat, w_mat + ) qeom_result = QEOMResult() qeom_result.ground_state_raw_result = groundstate_result.raw_result @@ -124,12 +149,17 @@ def solve(self, problem: BaseProblem, eigenstate_result = EigenstateResult() eigenstate_result.eigenstates = groundstate_result.eigenstates - eigenstate_result.aux_operator_eigenvalues = groundstate_result.aux_operator_eigenvalues + eigenstate_result.aux_operator_eigenvalues = ( + groundstate_result.aux_operator_eigenvalues + ) eigenstate_result.raw_result = qeom_result - eigenstate_result.eigenenergies = np.append(groundstate_result.eigenenergies, - np.asarray([groundstate_result.eigenenergies[0] - + gap for gap in energy_gaps])) + eigenstate_result.eigenenergies = np.append( + groundstate_result.eigenenergies, + np.asarray( + [groundstate_result.eigenenergies[0] + gap for gap in energy_gaps] + ), + ) result = problem.interpret(eigenstate_result) @@ -142,19 +172,20 @@ def _prepare_matrix_operators(self, problem) -> Tuple[dict, int]: a dictionary of all matrix elements operators and the number of excitations (or the size of the qEOM pseudo-eigenvalue problem) """ - data = problem.hopping_qeom_ops(self._gsc.qubit_converter, - self._excitations) + data = problem.hopping_qeom_ops(self._gsc.qubit_converter, self._excitations) hopping_operators, type_of_commutativities, excitation_indices = data size = int(len(list(excitation_indices.keys())) // 2) eom_matrix_operators = self._build_all_commutators( - hopping_operators, type_of_commutativities, size) + hopping_operators, type_of_commutativities, size + ) return eom_matrix_operators, size - def _build_all_commutators(self, hopping_operators: dict, type_of_commutativities: dict, - size: int) -> dict: + def _build_all_commutators( + self, hopping_operators: dict, type_of_commutativities: dict, size: int + ) -> dict: """Building all commutators for Q, W, M, V matrices. Args: @@ -180,29 +211,31 @@ def _build_one_sector(available_hopping_ops, untapered_op, z2_symmetries): for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] - left_op = available_hopping_ops.get('E_{}'.format(m_u)) - right_op_1 = available_hopping_ops.get('E_{}'.format(n_u)) - right_op_2 = available_hopping_ops.get('Edag_{}'.format(n_u)) + left_op = available_hopping_ops.get("E_{}".format(m_u)) + right_op_1 = available_hopping_ops.get("E_{}".format(n_u)) + right_op_2 = available_hopping_ops.get("Edag_{}".format(n_u)) to_be_computed_list.append((m_u, n_u, left_op, right_op_1, right_op_2)) if logger.isEnabledFor(logging.INFO): logger.info("Building all commutators:") TextProgressBar(sys.stderr) - results = parallel_map(self._build_commutator_routine, - to_be_computed_list, - task_args=(untapered_op, z2_symmetries), - num_processes=algorithm_globals.num_processes) + results = parallel_map( + self._build_commutator_routine, + to_be_computed_list, + task_args=(untapered_op, z2_symmetries), + num_processes=algorithm_globals.num_processes, + ) for result in results: m_u, n_u, q_mat_op, w_mat_op, m_mat_op, v_mat_op = result if q_mat_op is not None: - all_matrix_operators['q_{}_{}'.format(m_u, n_u)] = q_mat_op + all_matrix_operators["q_{}_{}".format(m_u, n_u)] = q_mat_op if w_mat_op is not None: - all_matrix_operators['w_{}_{}'.format(m_u, n_u)] = w_mat_op + all_matrix_operators["w_{}_{}".format(m_u, n_u)] = w_mat_op if m_mat_op is not None: - all_matrix_operators['m_{}_{}'.format(m_u, n_u)] = m_mat_op + all_matrix_operators["m_{}_{}".format(m_u, n_u)] = m_mat_op if v_mat_op is not None: - all_matrix_operators['v_{}_{}'.format(m_u, n_u)] = v_mat_op + all_matrix_operators["v_{}_{}".format(m_u, n_u)] = v_mat_op try: # The next step only works in the case of the FermionicTransformation. Thus, it is done @@ -212,35 +245,39 @@ def _build_one_sector(available_hopping_ops, untapered_op, z2_symmetries): z2_symmetries = Z2Symmetries([], [], []) if not z2_symmetries.is_empty(): - combinations = itertools.product([1, -1], repeat=len(z2_symmetries.symmetries)) + combinations = itertools.product( + [1, -1], repeat=len(z2_symmetries.symmetries) + ) for targeted_tapering_values in combinations: - logger.info("In sector: (%s)", ','.join([str(x) for x in targeted_tapering_values])) + logger.info( + "In sector: (%s)", + ",".join([str(x) for x in targeted_tapering_values]), + ) # remove the excited operators which are not suitable for the sector available_hopping_ops = {} - targeted_sector = (np.asarray(targeted_tapering_values) == 1) + targeted_sector = np.asarray(targeted_tapering_values) == 1 for key, value in type_of_commutativities.items(): value = np.asarray(value) if np.all(value == targeted_sector): available_hopping_ops[key] = hopping_operators[key] # untapered_qubit_op is a PauliSumOp and should not be exposed. - _build_one_sector(available_hopping_ops, - self._untapered_qubit_op_main, - z2_symmetries) + _build_one_sector( + available_hopping_ops, self._untapered_qubit_op_main, z2_symmetries + ) else: # untapered_qubit_op is a PauliSumOp and should not be exposed. - _build_one_sector(hopping_operators, - self._untapered_qubit_op_main, - z2_symmetries) + _build_one_sector( + hopping_operators, self._untapered_qubit_op_main, z2_symmetries + ) return all_matrix_operators @staticmethod - def _build_commutator_routine(params: List, operator: PauliSumOp, - z2_symmetries: Z2Symmetries - ) -> Tuple[int, int, PauliSumOp, PauliSumOp, - PauliSumOp, PauliSumOp]: + def _build_commutator_routine( + params: List, operator: PauliSumOp, z2_symmetries: Z2Symmetries + ) -> Tuple[int, int, PauliSumOp, PauliSumOp, PauliSumOp, PauliSumOp]: """Numerically computes the commutator / double commutator between operators. Args: @@ -300,9 +337,11 @@ def _build_commutator_routine(params: List, operator: PauliSumOp, return m_u, n_u, q_mat_op, w_mat_op, m_mat_op, v_mat_op - def _build_eom_matrices(self, gs_results: Dict[str, List[float]], size: int - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, - float, float, float, float]: + def _build_eom_matrices( + self, gs_results: Dict[str, List[float]], size: int + ) -> Tuple[ + np.ndarray, np.ndarray, np.ndarray, np.ndarray, float, float, float, float + ]: """Constructs the M, V, Q and W matrices from the results on the ground state Args: @@ -319,30 +358,54 @@ def _build_eom_matrices(self, gs_results: Dict[str, List[float]], size: int v_mat = np.zeros((size, size), dtype=complex) q_mat = np.zeros((size, size), dtype=complex) w_mat = np.zeros((size, size), dtype=complex) - m_mat_std, v_mat_std, q_mat_std, w_mat_std = 0., 0., 0., 0. + m_mat_std, v_mat_std, q_mat_std, w_mat_std = 0.0, 0.0, 0.0, 0.0 # evaluate results for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] - q_mat[m_u][n_u] = gs_results['q_{}_{}'.format(m_u, n_u)][0] if gs_results.get( - 'q_{}_{}'.format(m_u, n_u)) is not None else q_mat[m_u][n_u] - w_mat[m_u][n_u] = gs_results['w_{}_{}'.format(m_u, n_u)][0] if gs_results.get( - 'w_{}_{}'.format(m_u, n_u)) is not None else w_mat[m_u][n_u] - m_mat[m_u][n_u] = gs_results['m_{}_{}'.format(m_u, n_u)][0] if gs_results.get( - 'm_{}_{}'.format(m_u, n_u)) is not None else m_mat[m_u][n_u] - v_mat[m_u][n_u] = gs_results['v_{}_{}'.format(m_u, n_u)][0] if gs_results.get( - 'v_{}_{}'.format(m_u, n_u)) is not None else v_mat[m_u][n_u] - - q_mat_std += gs_results['q_{}_{}_std'.format(m_u, n_u)][0] if gs_results.get( - 'q_{}_{}_std'.format(m_u, n_u)) is not None else 0 - w_mat_std += gs_results['w_{}_{}_std'.format(m_u, n_u)][0] if gs_results.get( - 'w_{}_{}_std'.format(m_u, n_u)) is not None else 0 - m_mat_std += gs_results['m_{}_{}_std'.format(m_u, n_u)][0] if gs_results.get( - 'm_{}_{}_std'.format(m_u, n_u)) is not None else 0 - v_mat_std += gs_results['v_{}_{}_std'.format(m_u, n_u)][0] if gs_results.get( - 'v_{}_{}_std'.format(m_u, n_u)) is not None else 0 + q_mat[m_u][n_u] = ( + gs_results["q_{}_{}".format(m_u, n_u)][0] + if gs_results.get("q_{}_{}".format(m_u, n_u)) is not None + else q_mat[m_u][n_u] + ) + w_mat[m_u][n_u] = ( + gs_results["w_{}_{}".format(m_u, n_u)][0] + if gs_results.get("w_{}_{}".format(m_u, n_u)) is not None + else w_mat[m_u][n_u] + ) + m_mat[m_u][n_u] = ( + gs_results["m_{}_{}".format(m_u, n_u)][0] + if gs_results.get("m_{}_{}".format(m_u, n_u)) is not None + else m_mat[m_u][n_u] + ) + v_mat[m_u][n_u] = ( + gs_results["v_{}_{}".format(m_u, n_u)][0] + if gs_results.get("v_{}_{}".format(m_u, n_u)) is not None + else v_mat[m_u][n_u] + ) + + q_mat_std += ( + gs_results["q_{}_{}_std".format(m_u, n_u)][0] + if gs_results.get("q_{}_{}_std".format(m_u, n_u)) is not None + else 0 + ) + w_mat_std += ( + gs_results["w_{}_{}_std".format(m_u, n_u)][0] + if gs_results.get("w_{}_{}_std".format(m_u, n_u)) is not None + else 0 + ) + m_mat_std += ( + gs_results["m_{}_{}_std".format(m_u, n_u)][0] + if gs_results.get("m_{}_{}_std".format(m_u, n_u)) is not None + else 0 + ) + v_mat_std += ( + gs_results["v_{}_{}_std".format(m_u, n_u)][0] + if gs_results.get("v_{}_{}_std".format(m_u, n_u)) is not None + else 0 + ) # these matrices are numpy arrays and therefore have the ``shape`` attribute # pylint: disable=unsubscriptable-object @@ -369,8 +432,9 @@ def _build_eom_matrices(self, gs_results: Dict[str, List[float]], size: int return m_mat, v_mat, q_mat, w_mat, m_mat_std, v_mat_std, q_mat_std, w_mat_std @staticmethod - def _compute_excitation_energies(m_mat: np.ndarray, v_mat: np.ndarray, q_mat: np.ndarray, - w_mat: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: + def _compute_excitation_energies( + m_mat: np.ndarray, v_mat: np.ndarray, q_mat: np.ndarray, w_mat: np.ndarray + ) -> Tuple[np.ndarray, np.ndarray]: """Diagonalizing M, V, Q, W matrices for excitation energies. Args: @@ -383,7 +447,7 @@ def _compute_excitation_energies(m_mat: np.ndarray, v_mat: np.ndarray, q_mat: np 1-D vector stores all energy gap to reference state 2-D array storing the X and Y expansion coefficients """ - logger.debug('Diagonalizing qeom matrices for excited states...') + logger.debug("Diagonalizing qeom matrices for excited states...") a_mat = np.bmat([[m_mat, q_mat], [q_mat.T.conj(), m_mat.T.conj()]]) b_mat = np.bmat([[v_mat, w_mat], [-w_mat.T.conj(), -v_mat.T.conj()]]) # pylint: disable=too-many-function-args @@ -398,10 +462,10 @@ def _compute_excitation_energies(m_mat: np.ndarray, v_mat: np.ndarray, q_mat: np # sort the real parts and then take the upper half of the sorted values. # Since we may now have # small values (positive or negative) take the absolute and then threshold zero. - logger.debug('... %s', res[0]) + logger.debug("... %s", res[0]) w = np.sort(np.real(res[0])) - logger.debug('Sorted real parts %s', w) - w = np.abs(w[len(w) // 2:]) + logger.debug("Sorted real parts %s", w) + w = np.abs(w[len(w) // 2 :]) w[w < 1e-06] = 0 excitation_energies_gap = w @@ -420,116 +484,116 @@ def __init__(self) -> None: self._v_matrix: Optional[np.ndarray] = None self._q_matrix: Optional[np.ndarray] = None self._w_matrix: Optional[np.ndarray] = None - self._v_matrix_std: float = 0. - self._q_matrix_std: float = 0. - self._w_matrix_std: float = 0. + self._v_matrix_std: float = 0.0 + self._q_matrix_std: float = 0.0 + self._w_matrix_std: float = 0.0 @property def ground_state_raw_result(self): - """ returns ground state raw result """ + """returns ground state raw result""" return self._ground_state_raw_result @ground_state_raw_result.setter def ground_state_raw_result(self, value) -> None: - """ sets ground state raw result """ + """sets ground state raw result""" self._ground_state_raw_result = value @property def excitation_energies(self) -> Optional[np.ndarray]: - """ returns the excitation energies (energy gaps) """ + """returns the excitation energies (energy gaps)""" return self._excitation_energies @excitation_energies.setter def excitation_energies(self, value: np.ndarray) -> None: - """ sets the excitation energies (energy gaps) """ + """sets the excitation energies (energy gaps)""" self._excitation_energies = value @property def expansion_coefficients(self) -> Optional[np.ndarray]: - """ returns the X and Y expansion coefficients """ + """returns the X and Y expansion coefficients""" return self._expansion_coefficients @expansion_coefficients.setter def expansion_coefficients(self, value: np.ndarray) -> None: - """ sets the X and Y expansion coefficients """ + """sets the X and Y expansion coefficients""" self._expansion_coefficients = value @property def m_matrix(self) -> Optional[np.ndarray]: - """ returns the M matrix """ + """returns the M matrix""" return self._m_matrix @m_matrix.setter def m_matrix(self, value: np.ndarray) -> None: - """ sets the M matrix """ + """sets the M matrix""" self._m_matrix = value @property def v_matrix(self) -> Optional[np.ndarray]: - """ returns the V matrix """ + """returns the V matrix""" return self._v_matrix @v_matrix.setter def v_matrix(self, value: np.ndarray) -> None: - """ sets the V matrix """ + """sets the V matrix""" self._v_matrix = value @property def q_matrix(self) -> Optional[np.ndarray]: - """ returns the Q matrix """ + """returns the Q matrix""" return self._q_matrix @q_matrix.setter def q_matrix(self, value: np.ndarray) -> None: - """ sets the Q matrix """ + """sets the Q matrix""" self._q_matrix = value @property def w_matrix(self) -> Optional[np.ndarray]: - """ returns the W matrix """ + """returns the W matrix""" return self._w_matrix @w_matrix.setter def w_matrix(self, value: np.ndarray) -> None: - """ sets the W matrix """ + """sets the W matrix""" self._w_matrix = value @property def m_matrix_std(self) -> float: - """ returns the M matrix standard deviation """ + """returns the M matrix standard deviation""" return self._m_matrix_std @m_matrix_std.setter def m_matrix_std(self, value: float) -> None: - """ sets the M matrix standard deviation """ + """sets the M matrix standard deviation""" self._m_matrix_std = value @property def v_matrix_std(self) -> float: - """ returns the V matrix standard deviation """ + """returns the V matrix standard deviation""" return self._v_matrix_std @v_matrix_std.setter def v_matrix_std(self, value: float) -> None: - """ sets the V matrix standard deviation """ + """sets the V matrix standard deviation""" self._v_matrix_std = value @property def q_matrix_std(self) -> float: - """ returns the Q matrix standard deviation """ + """returns the Q matrix standard deviation""" return self._q_matrix_std @q_matrix_std.setter def q_matrix_std(self, value: float) -> None: - """ sets the Q matrix standard deviation """ + """sets the Q matrix standard deviation""" self._q_matrix_std = value @property def w_matrix_std(self) -> float: - """ returns the W matrix standard deviation """ + """returns the W matrix standard deviation""" return self._w_matrix_std @w_matrix_std.setter def w_matrix_std(self, value: float) -> None: - """ sets the W matrix standard deviation """ + """sets the W matrix standard deviation""" self._w_matrix_std = value diff --git a/qiskit_nature/algorithms/ground_state_solvers/__init__.py b/qiskit_nature/algorithms/ground_state_solvers/__init__.py index b8546caca0..acc14acbd4 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/__init__.py +++ b/qiskit_nature/algorithms/ground_state_solvers/__init__.py @@ -32,16 +32,19 @@ from .ground_state_solver import GroundStateSolver from .adapt_vqe import AdaptVQE from .ground_state_eigensolver import GroundStateEigensolver -from .minimum_eigensolver_factories import (MinimumEigensolverFactory, - NumPyMinimumEigensolverFactory, - VQEUCCFactory, - VQEUVCCFactory) - -__all__ = ['GroundStateSolver', - 'AdaptVQE', - 'GroundStateEigensolver', - 'MinimumEigensolverFactory', - 'NumPyMinimumEigensolverFactory', - 'VQEUCCFactory', - 'VQEUVCCFactory', - ] +from .minimum_eigensolver_factories import ( + MinimumEigensolverFactory, + NumPyMinimumEigensolverFactory, + VQEUCCFactory, + VQEUVCCFactory, +) + +__all__ = [ + "GroundStateSolver", + "AdaptVQE", + "GroundStateEigensolver", + "MinimumEigensolverFactory", + "NumPyMinimumEigensolverFactory", + "VQEUCCFactory", + "VQEUVCCFactory", +] diff --git a/qiskit_nature/algorithms/ground_state_solvers/adapt_vqe.py b/qiskit_nature/algorithms/ground_state_solvers/adapt_vqe.py index 56b0b0fc9b..ebd255d275 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/adapt_vqe.py +++ b/qiskit_nature/algorithms/ground_state_solvers/adapt_vqe.py @@ -40,12 +40,14 @@ class AdaptVQE(GroundStateEigensolver): """A ground state calculation employing the AdaptVQE algorithm.""" - def __init__(self, qubit_converter: QubitConverter, - solver: MinimumEigensolverFactory, - threshold: float = 1e-5, - delta: float = 1, - max_iterations: Optional[int] = None, - ) -> None: + def __init__( + self, + qubit_converter: QubitConverter, + solver: MinimumEigensolverFactory, + threshold: float = 1e-5, + delta: float = 1, + max_iterations: Optional[int] = None, + ) -> None: """ Args: qubit_converter: a class that converts second quantized operator to qubit operator @@ -55,8 +57,8 @@ def __init__(self, qubit_converter: QubitConverter, value of 1e-5. max_iterations: the maximum number of iterations of the AdaptVQE algorithm. """ - validate_min('threshold', threshold, 1e-15) - validate_min('delta', delta, 1e-5) + validate_min("threshold", threshold, 1e-15) + validate_min("delta", delta, 1e-5) super().__init__(qubit_converter, solver) @@ -73,10 +75,11 @@ def __init__(self, qubit_converter: QubitConverter, def returns_groundstate(self) -> bool: return True - def _compute_gradients(self, - theta: List[float], - vqe: VQE, - ) -> List[Tuple[float, PauliSumOp]]: + def _compute_gradients( + self, + theta: List[float], + vqe: VQE, + ) -> List[Tuple[float, PauliSumOp]]: """ Computes the gradients for all available excitation operators. @@ -96,7 +99,9 @@ def _compute_gradients(self, vqe.ansatz = self._ansatz ansatz_params = vqe.ansatz._parameter_table.keys() # construct the expectation operator of the VQE - vqe._expect_op = vqe.construct_expectation(ansatz_params, self._main_operator) + vqe._expect_op = vqe.construct_expectation( + ansatz_params, self._main_operator + ) # evaluate energies parameter_sets = theta + [-self._delta] + theta + [self._delta] energy_results = vqe._energy_evaluation(np.asarray(parameter_sets)) @@ -124,17 +129,19 @@ def _check_cyclicity(indices: List[int]) -> bool: # 3. ( \b\1\b)+ will match a space followed by the contents of capture group 1 (again # delimited by word boundaries to avoid separation into digits). # -> this results in any sequence of at least two numbers being detected - match = cycle_regex.search(' '.join(map(str, indices))) - logger.debug('Cycle detected: %s', match) + match = cycle_regex.search(" ".join(map(str, indices))) + logger.debug("Cycle detected: %s", match) # Additionally we also need to check whether the last two numbers are identical, because the # reg-ex above will only find cycles of at least two consecutive numbers. # It is sufficient to assert that the last two numbers are different due to the iterative # nature of the algorithm. return match is not None or (len(indices) > 1 and indices[-2] == indices[-1]) - def solve(self, problem: BaseProblem, - aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, - ) -> "AdaptVQEResult": + def solve( + self, + problem: BaseProblem, + aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, + ) -> "AdaptVQEResult": """Computes the ground state. Args: @@ -155,7 +162,7 @@ def solve(self, problem: BaseProblem, self._main_operator = self._qubit_converter.convert( second_q_ops[0], num_particles=problem.num_particles, - sector_locator=problem.symmetry_sector_locator + sector_locator=problem.symmetry_sector_locator, ) aux_ops = self._qubit_converter.convert_match(second_q_ops[1:]) @@ -172,10 +179,13 @@ def solve(self, problem: BaseProblem, vqe = self._solver if not isinstance(vqe, VQE): - raise QiskitNatureError("The AdaptVQE algorithm requires the use of the VQE solver") + raise QiskitNatureError( + "The AdaptVQE algorithm requires the use of the VQE solver" + ) if not isinstance(vqe.ansatz, UCC): raise QiskitNatureError( - "The AdaptVQE algorithm requires the use of the UCC ansatz") + "The AdaptVQE algorithm requires the use of the UCC ansatz" + ) # We construct the ansatz once to be able to extract the full set of excitation operators. self._ansatz = copy.deepcopy(vqe.ansatz) @@ -187,17 +197,18 @@ def solve(self, problem: BaseProblem, max_iterations_exceeded = False prev_op_indices: List[int] = [] theta: List[float] = [] - max_grad: Tuple[float, Optional[PauliSumOp]] = (0., None) + max_grad: Tuple[float, Optional[PauliSumOp]] = (0.0, None) iteration = 0 while self._max_iterations is None or iteration < self._max_iterations: iteration += 1 - logger.info('--- Iteration #%s ---', str(iteration)) + logger.info("--- Iteration #%s ---", str(iteration)) # compute gradients cur_grads = self._compute_gradients(theta, vqe) # pick maximum gradient - max_grad_index, max_grad = max(enumerate(cur_grads), - key=lambda item: np.abs(item[1][0])) + max_grad_index, max_grad = max( + enumerate(cur_grads), key=lambda item: np.abs(item[1][0]) + ) # store maximum gradient's index for cycle detection prev_op_indices.append(max_grad_index) # log gradients @@ -205,14 +216,16 @@ def solve(self, problem: BaseProblem, gradlog = "\nGradients in iteration #{}".format(str(iteration)) gradlog += "\nID: Excitation Operator: Gradient <(*) maximum>" for i, grad in enumerate(cur_grads): - gradlog += '\n{}: {}: {}'.format(str(i), str(grad[1]), str(grad[0])) + gradlog += "\n{}: {}: {}".format(str(i), str(grad[1]), str(grad[0])) if grad[1] == max_grad[1]: - gradlog += '\t(*)' + gradlog += "\t(*)" logger.info(gradlog) if np.abs(max_grad[0]) < self._threshold: - logger.info("Adaptive VQE terminated successfully " - "with a final maximum gradient: %s", - str(np.abs(max_grad[0]))) + logger.info( + "Adaptive VQE terminated successfully " + "with a final maximum gradient: %s", + str(np.abs(max_grad[0])), + ) threshold_satisfied = True break # check indices of picked gradients for cycles @@ -244,13 +257,15 @@ def solve(self, problem: BaseProblem, raw_vqe_result.aux_operator_eigenvalues = aux_values if threshold_satisfied: - finishing_criterion = 'Threshold converged' + finishing_criterion = "Threshold converged" elif alternating_sequence: - finishing_criterion = 'Aborted due to cyclicity' + finishing_criterion = "Aborted due to cyclicity" elif max_iterations_exceeded: - finishing_criterion = 'Maximum number of iterations reached' + finishing_criterion = "Maximum number of iterations reached" else: - raise QiskitNatureError('The algorithm finished due to an unforeseen reason!') + raise QiskitNatureError( + "The algorithm finished due to an unforeseen reason!" + ) electronic_result = problem.interpret(raw_vqe_result) @@ -260,45 +275,45 @@ def solve(self, problem: BaseProblem, result.final_max_gradient = max_grad[0] result.finishing_criterion = finishing_criterion - logger.info('The final energy is: %s', str(result.computed_energies[0])) + logger.info("The final energy is: %s", str(result.computed_energies[0])) return result class AdaptVQEResult(ElectronicStructureResult): - """ AdaptVQE Result.""" + """AdaptVQE Result.""" def __init__(self) -> None: super().__init__() self._num_iterations: int = 0 - self._final_max_gradient: float = 0. - self._finishing_criterion: str = '' + self._final_max_gradient: float = 0.0 + self._finishing_criterion: str = "" @property def num_iterations(self) -> int: - """ Returns number of iterations """ + """Returns number of iterations""" return self._num_iterations @num_iterations.setter def num_iterations(self, value: int) -> None: - """ Sets number of iterations """ + """Sets number of iterations""" self._num_iterations = value @property def final_max_gradient(self) -> float: - """ Returns final maximum gradient """ + """Returns final maximum gradient""" return self._final_max_gradient @final_max_gradient.setter def final_max_gradient(self, value: float) -> None: - """ Sets final maximum gradient """ + """Sets final maximum gradient""" self._final_max_gradient = value @property def finishing_criterion(self) -> str: - """ Returns finishing criterion """ + """Returns finishing criterion""" return self._finishing_criterion @finishing_criterion.setter def finishing_criterion(self, value: str) -> None: - """ Sets finishing criterion """ + """Sets finishing criterion""" self._finishing_criterion = value diff --git a/qiskit_nature/algorithms/ground_state_solvers/ground_state_eigensolver.py b/qiskit_nature/algorithms/ground_state_solvers/ground_state_eigensolver.py index 40869caaea..b1f14a1a26 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/ground_state_eigensolver.py +++ b/qiskit_nature/algorithms/ground_state_solvers/ground_state_eigensolver.py @@ -33,8 +33,11 @@ class GroundStateEigensolver(GroundStateSolver): """Ground state computation using a minimum eigensolver.""" - def __init__(self, qubit_converter: QubitConverter, - solver: Union[MinimumEigensolver, MinimumEigensolverFactory]) -> None: + def __init__( + self, + qubit_converter: QubitConverter, + solver: Union[MinimumEigensolver, MinimumEigensolverFactory], + ) -> None: """ Args: @@ -51,7 +54,9 @@ def solver(self) -> Union[MinimumEigensolver, MinimumEigensolverFactory]: return self._solver @solver.setter - def solver(self, solver: Union[MinimumEigensolver, MinimumEigensolverFactory]) -> None: + def solver( + self, solver: Union[MinimumEigensolver, MinimumEigensolverFactory] + ) -> None: """Sets the minimum eigensolver or factory.""" self._solver = solver @@ -59,9 +64,11 @@ def returns_groundstate(self) -> bool: """Whether the eigensolver returns the ground state or only ground state energy.""" return self._solver.supports_aux_operators() - def solve(self, problem: BaseProblem, - aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, - ) -> EigenstateResult: + def solve( + self, + problem: BaseProblem, + aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, + ) -> EigenstateResult: """Compute Ground State properties. Args: @@ -84,7 +91,7 @@ def solve(self, problem: BaseProblem, main_operator = self._qubit_converter.convert( second_q_ops[0], num_particles=problem.num_particles, - sector_locator=problem.symmetry_sector_locator + sector_locator=problem.symmetry_sector_locator, ) aux_ops = self._qubit_converter.convert_match(second_q_ops[1:]) @@ -108,14 +115,23 @@ def solve(self, problem: BaseProblem, result = problem.interpret(raw_mes_result) return result - def evaluate_operators(self, - state: Union[str, dict, Result, - list, np.ndarray, Statevector, - QuantumCircuit, Instruction, - OperatorBase], - operators: Union[PauliSumOp, OperatorBase, list, dict] - ) -> Union[Optional[float], List[Optional[float]], - Dict[str, List[Optional[float]]]]: + def evaluate_operators( + self, + state: Union[ + str, + dict, + Result, + list, + np.ndarray, + Statevector, + QuantumCircuit, + Instruction, + OperatorBase, + ], + operators: Union[PauliSumOp, OperatorBase, list, dict], + ) -> Union[ + Optional[float], List[Optional[float]], Dict[str, List[Optional[float]]] + ]: """Evaluates additional operators at the given state. Args: @@ -129,9 +145,9 @@ def evaluate_operators(self, format of the provided operators. """ # try to get a QuantumInstance from the solver - quantum_instance = getattr(self._solver, 'quantum_instance', None) + quantum_instance = getattr(self._solver, "quantum_instance", None) # and try to get an Expectation from the solver - expectation = getattr(self._solver, 'expectation', None) + expectation = getattr(self._solver, "expectation", None) if not isinstance(state, StateFn): state = StateFn(state) @@ -144,14 +160,18 @@ def evaluate_operators(self, if op is None: results.append(None) else: - results.append(self._eval_op(state, op, quantum_instance, expectation)) + results.append( + self._eval_op(state, op, quantum_instance, expectation) + ) elif isinstance(operators, dict): results = {} # type: ignore for name, op in operators.items(): if op is None: results[name] = None else: - results[name] = self._eval_op(state, op, quantum_instance, expectation) + results[name] = self._eval_op( + state, op, quantum_instance, expectation + ) else: if operators is None: results = None @@ -165,7 +185,7 @@ def _eval_op(self, state, op, quantum_instance, expectation): if op == 0: # Note, that for some reason the individual results need to be wrapped in lists. # See also: VQE._eval_aux_ops() - return [0.j] + return [0.0j] exp = ~StateFn(op) @ state # diff --git a/qiskit_nature/algorithms/ground_state_solvers/ground_state_solver.py b/qiskit_nature/algorithms/ground_state_solvers/ground_state_solver.py index 997292711d..49e040055a 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/ground_state_solver.py +++ b/qiskit_nature/algorithms/ground_state_solvers/ground_state_solver.py @@ -40,9 +40,11 @@ def __init__(self, qubit_converter: QubitConverter) -> None: self._qubit_converter = qubit_converter @abstractmethod - def solve(self, problem: BaseProblem, - aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, - ) -> EigenstateResult: + def solve( + self, + problem: BaseProblem, + aux_operators: Optional[List[Union[SecondQuantizedOp, PauliSumOp]]] = None, + ) -> EigenstateResult: """Compute the ground state energy of the molecule that was supplied via the driver. Args: @@ -66,13 +68,21 @@ def returns_groundstate(self) -> bool: raise NotImplementedError @abstractmethod - def evaluate_operators(self, - state: Union[str, dict, Result, - list, np.ndarray, Statevector, - QuantumCircuit, Instruction, - OperatorBase], - operators: Union[PauliSumOp, OperatorBase, list, dict] - ) -> Union[float, List[float], Dict[str, List[float]]]: + def evaluate_operators( + self, + state: Union[ + str, + dict, + Result, + list, + np.ndarray, + Statevector, + QuantumCircuit, + Instruction, + OperatorBase, + ], + operators: Union[PauliSumOp, OperatorBase, list, dict], + ) -> Union[float, List[float], Dict[str, List[float]]]: """Evaluates additional operators at the given state. Args: diff --git a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/__init__.py b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/__init__.py index 99c51b0575..2dd84d50b9 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/__init__.py +++ b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/__init__.py @@ -37,8 +37,9 @@ from .vqe_ucc_factory import VQEUCCFactory from .vqe_uvcc_factory import VQEUVCCFactory -__all__ = ['MinimumEigensolverFactory', - 'NumPyMinimumEigensolverFactory', - 'VQEUCCFactory', - 'VQEUVCCFactory' - ] +__all__ = [ + "MinimumEigensolverFactory", + "NumPyMinimumEigensolverFactory", + "VQEUCCFactory", + "VQEUVCCFactory", +] diff --git a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/minimum_eigensolver_factory.py b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/minimum_eigensolver_factory.py index 988920017a..7d85a92c99 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/minimum_eigensolver_factory.py +++ b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/minimum_eigensolver_factory.py @@ -24,8 +24,9 @@ class MinimumEigensolverFactory(ABC): """A factory to construct a minimum eigensolver based on a qubit operator transformation.""" @abstractmethod - def get_solver(self, problem: BaseProblem, - qubit_converter: QubitConverter) -> MinimumEigensolver: + def get_solver( + self, problem: BaseProblem, qubit_converter: QubitConverter + ) -> MinimumEigensolver: """Returns a minimum eigensolver, based on the qubit operator transformation. Args: @@ -41,6 +42,5 @@ def get_solver(self, problem: BaseProblem, @abstractmethod def supports_aux_operators(self) -> bool: - """Returns whether the eigensolver generated by this factory supports auxiliary operators. - """ + """Returns whether the eigensolver generated by this factory supports auxiliary operators.""" raise NotImplementedError diff --git a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/numpy_minimum_eigensolver_factory.py b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/numpy_minimum_eigensolver_factory.py index 15a8088808..a1077ce1b3 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/numpy_minimum_eigensolver_factory.py +++ b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/numpy_minimum_eigensolver_factory.py @@ -25,10 +25,13 @@ class NumPyMinimumEigensolverFactory(MinimumEigensolverFactory): """A factory to construct a NumPyMinimumEigensolver.""" - def __init__(self, - filter_criterion: Callable[[Union[List, np.ndarray], float, Optional[List[float]]], - bool] = None, - use_default_filter_criterion: bool = False) -> None: + def __init__( + self, + filter_criterion: Callable[ + [Union[List, np.ndarray], float, Optional[List[float]]], bool + ] = None, + use_default_filter_criterion: bool = False, + ) -> None: """ Args: filter_criterion: callable that allows to filter eigenvalues/eigenstates. The minimum @@ -44,29 +47,33 @@ def __init__(self, self._use_default_filter_criterion = use_default_filter_criterion @property - def filter_criterion(self) -> Callable[[Union[List, np.ndarray], float, Optional[List[float]]], - bool]: - """ returns filter criterion """ + def filter_criterion( + self, + ) -> Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool]: + """returns filter criterion""" return self._filter_criterion @filter_criterion.setter - def filter_criterion(self, value: Callable[[Union[List, np.ndarray], float, - Optional[List[float]]], bool]) -> None: - """ sets filter criterion """ + def filter_criterion( + self, + value: Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool], + ) -> None: + """sets filter criterion""" self._filter_criterion = value @property def use_default_filter_criterion(self) -> bool: - """ returns whether to use the default filter criterion """ + """returns whether to use the default filter criterion""" return self._use_default_filter_criterion @use_default_filter_criterion.setter def use_default_filter_criterion(self, value: bool) -> None: - """ sets whether to use the default filter criterion """ + """sets whether to use the default filter criterion""" self._use_default_filter_criterion = value - def get_solver(self, problem: BaseProblem, - qubit_converter: QubitConverter) -> MinimumEigensolver: + def get_solver( + self, problem: BaseProblem, qubit_converter: QubitConverter + ) -> MinimumEigensolver: """Returns a NumPyMinimumEigensolver which possibly uses the default filter criterion provided by the ``transformation``. diff --git a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_ucc_factory.py b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_ucc_factory.py index c8fb412d42..97b371baf6 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_ucc_factory.py +++ b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_ucc_factory.py @@ -25,23 +25,26 @@ from qiskit_nature.circuit.library import HartreeFock, UCC, UCCSD from qiskit_nature.drivers import QMolecule from qiskit_nature.converters.second_quantization import QubitConverter -from qiskit_nature.problems.second_quantization.electronic import ElectronicStructureProblem +from qiskit_nature.problems.second_quantization.electronic import ( + ElectronicStructureProblem, +) from .minimum_eigensolver_factory import MinimumEigensolverFactory class VQEUCCFactory(MinimumEigensolverFactory): """A factory to construct a VQE minimum eigensolver with UCCSD ansatz wavefunction.""" - def __init__(self, - quantum_instance: QuantumInstance, - optimizer: Optional[Optimizer] = None, - initial_point: Optional[np.ndarray] = None, - gradient: Optional[Union[GradientBase, Callable]] = None, - expectation: Optional[ExpectationBase] = None, - include_custom: bool = False, - ansatz: Optional[UCC] = None, - initial_state: Optional[QuantumCircuit] = None, - ) -> None: + def __init__( + self, + quantum_instance: QuantumInstance, + optimizer: Optional[Optimizer] = None, + initial_point: Optional[np.ndarray] = None, + gradient: Optional[Union[GradientBase, Callable]] = None, + expectation: Optional[ExpectationBase] = None, + include_custom: bool = False, + ansatz: Optional[UCC] = None, + initial_state: Optional[QuantumCircuit] = None, + ) -> None: """ Args: quantum_instance: The quantum instance used in the minimum eigensolver. @@ -76,13 +79,15 @@ def __init__(self, self.include_custom = include_custom self.ansatz = ansatz self.initial_state = initial_state - self._vqe = VQE(ansatz=None, - quantum_instance=self._quantum_instance, - optimizer=self._optimizer, - initial_point=self._initial_point, - gradient=self._gradient, - expectation=self._expectation, - include_custom=self._include_custom) + self._vqe = VQE( + ansatz=None, + quantum_instance=self._quantum_instance, + optimizer=self._optimizer, + initial_point=self._initial_point, + gradient=self._gradient, + expectation=self._expectation, + include_custom=self._include_custom, + ) @property def quantum_instance(self) -> QuantumInstance: @@ -166,8 +171,11 @@ def initial_state(self, initial_state: Optional[QuantumCircuit]) -> None: the :class:`~.HartreeFock`.""" self._initial_state = initial_state - def get_solver(self, problem: ElectronicStructureProblem, # type: ignore[override] - qubit_converter: QubitConverter) -> MinimumEigensolver: + def get_solver( # type: ignore[override] + self, + problem: ElectronicStructureProblem, + qubit_converter: QubitConverter, + ) -> MinimumEigensolver: """Returns a VQE with a UCCSD wavefunction ansatz, based on ``transformation``. This works only with a ``FermionicTransformation``. @@ -182,12 +190,17 @@ def get_solver(self, problem: ElectronicStructureProblem, # type: ignore[overri """ q_molecule_transformed = cast(QMolecule, problem.molecule_data_transformed) num_molecular_orbitals = q_molecule_transformed.num_molecular_orbitals - num_particles = (q_molecule_transformed.num_alpha, q_molecule_transformed.num_beta) + num_particles = ( + q_molecule_transformed.num_alpha, + q_molecule_transformed.num_beta, + ) num_spin_orbitals = 2 * num_molecular_orbitals initial_state = self.initial_state if initial_state is None: - initial_state = HartreeFock(num_spin_orbitals, num_particles, qubit_converter) + initial_state = HartreeFock( + num_spin_orbitals, num_particles, qubit_converter + ) ansatz = self.ansatz if ansatz is None: diff --git a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uvcc_factory.py b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uvcc_factory.py index cbf341f407..035e63edf9 100644 --- a/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uvcc_factory.py +++ b/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uvcc_factory.py @@ -24,7 +24,9 @@ from qiskit_nature.circuit.library import UVCC, UVCCSD, VSCF from qiskit_nature.drivers import WatsonHamiltonian from qiskit_nature.converters.second_quantization import QubitConverter -from qiskit_nature.problems.second_quantization.vibrational import VibrationalStructureProblem +from qiskit_nature.problems.second_quantization.vibrational import ( + VibrationalStructureProblem, +) from .minimum_eigensolver_factory import MinimumEigensolverFactory @@ -32,16 +34,17 @@ class VQEUVCCFactory(MinimumEigensolverFactory): """A factory to construct a VQE minimum eigensolver with UVCCSD ansatz wavefunction.""" - def __init__(self, - quantum_instance: QuantumInstance, - optimizer: Optional[Optimizer] = None, - initial_point: Optional[np.ndarray] = None, - gradient: Optional[Union[GradientBase, Callable]] = None, - expectation: Optional[ExpectationBase] = None, - include_custom: bool = False, - ansatz: Optional[UVCC] = None, - initial_state: Optional[QuantumCircuit] = None, - ) -> None: + def __init__( + self, + quantum_instance: QuantumInstance, + optimizer: Optional[Optimizer] = None, + initial_point: Optional[np.ndarray] = None, + gradient: Optional[Union[GradientBase, Callable]] = None, + expectation: Optional[ExpectationBase] = None, + include_custom: bool = False, + ansatz: Optional[UVCC] = None, + initial_state: Optional[QuantumCircuit] = None, + ) -> None: """ Args: quantum_instance: The quantum instance used in the minimum eigensolver. @@ -76,13 +79,15 @@ def __init__(self, self._include_custom = include_custom self.ansatz = ansatz self.initial_state = initial_state - self._vqe = VQE(ansatz=None, - quantum_instance=self._quantum_instance, - optimizer=self._optimizer, - initial_point=self._initial_point, - gradient=self._gradient, - expectation=self._expectation, - include_custom=self._include_custom) + self._vqe = VQE( + ansatz=None, + quantum_instance=self._quantum_instance, + optimizer=self._optimizer, + initial_point=self._initial_point, + gradient=self._gradient, + expectation=self._expectation, + include_custom=self._include_custom, + ) @property def quantum_instance(self) -> QuantumInstance: @@ -166,8 +171,11 @@ def initial_state(self, initial_state: Optional[QuantumCircuit]) -> None: the :class:`~.VSCF`.""" self._initial_state = initial_state - def get_solver(self, problem: VibrationalStructureProblem, # type: ignore[override] - qubit_converter: QubitConverter) -> MinimumEigensolver: + def get_solver( # type: ignore[override] + self, + problem: VibrationalStructureProblem, + qubit_converter: QubitConverter, + ) -> MinimumEigensolver: """Returns a VQE with a UVCCSD wavefunction ansatz, based on ``transformation``. This works only with a ``BosonicTransformation``. @@ -181,7 +189,9 @@ def get_solver(self, problem: VibrationalStructureProblem, # type: ignore[overr by ``transformation``. """ - watson_hamiltonian_transformed = cast(WatsonHamiltonian, problem.molecule_data_transformed) + watson_hamiltonian_transformed = cast( + WatsonHamiltonian, problem.molecule_data_transformed + ) num_modals = problem.num_modals num_modes = watson_hamiltonian_transformed.num_modes diff --git a/qiskit_nature/algorithms/pes_samplers/__init__.py b/qiskit_nature/algorithms/pes_samplers/__init__.py index 3fff20396c..4a5cd062fa 100644 --- a/qiskit_nature/algorithms/pes_samplers/__init__.py +++ b/qiskit_nature/algorithms/pes_samplers/__init__.py @@ -54,24 +54,36 @@ VibrationalStructureBase """ -from .extrapolator import (Extrapolator, DifferentialExtrapolator, PCAExtrapolator, - PolynomialExtrapolator, SieveExtrapolator, WindowExtrapolator) -from .potentials import (EnergySurface1DSpline, HarmonicPotential, MorsePotential, - EnergySurfaceBase, PotentialBase, VibrationalStructureBase) +from .extrapolator import ( + Extrapolator, + DifferentialExtrapolator, + PCAExtrapolator, + PolynomialExtrapolator, + SieveExtrapolator, + WindowExtrapolator, +) +from .potentials import ( + EnergySurface1DSpline, + HarmonicPotential, + MorsePotential, + EnergySurfaceBase, + PotentialBase, + VibrationalStructureBase, +) from .bopes_sampler import BOPESSampler __all__ = [ - 'BOPESSampler', - 'Extrapolator', - 'DifferentialExtrapolator', - 'PCAExtrapolator', - 'PolynomialExtrapolator', - 'SieveExtrapolator', - 'WindowExtrapolator', - 'EnergySurface1DSpline', - 'HarmonicPotential', - 'MorsePotential', - 'EnergySurfaceBase', - 'PotentialBase', - 'VibrationalStructureBase', + "BOPESSampler", + "Extrapolator", + "DifferentialExtrapolator", + "PCAExtrapolator", + "PolynomialExtrapolator", + "SieveExtrapolator", + "WindowExtrapolator", + "EnergySurface1DSpline", + "HarmonicPotential", + "MorsePotential", + "EnergySurfaceBase", + "PotentialBase", + "VibrationalStructureBase", ] diff --git a/qiskit_nature/algorithms/pes_samplers/bopes_sampler.py b/qiskit_nature/algorithms/pes_samplers/bopes_sampler.py index 7ae26dd28d..e3118a6c8c 100644 --- a/qiskit_nature/algorithms/pes_samplers/bopes_sampler.py +++ b/qiskit_nature/algorithms/pes_samplers/bopes_sampler.py @@ -30,12 +30,14 @@ class BOPESSampler: """Class to evaluate the Born-Oppenheimer Potential Energy Surface (BOPES).""" - def __init__(self, - gss: GroundStateSolver, - tolerance: float = 1e-3, - bootstrap: bool = True, - num_bootstrap: Optional[int] = None, - extrapolator: Optional[Extrapolator] = None) -> None: + def __init__( + self, + gss: GroundStateSolver, + tolerance: float = 1e-3, + bootstrap: bool = True, + num_bootstrap: Optional[int] = None, + extrapolator: Optional[Extrapolator] = None, + ) -> None: """ Args: gss: GroundStateSolver @@ -74,13 +76,17 @@ def __init__(self, elif num_bootstrap >= 2: if not isinstance(self._extrapolator, WindowExtrapolator): raise QiskitNatureError( - 'If num_bootstrap >= 2 then the extrapolator must be an instance ' - 'of WindowExtrapolator, got {} instead'.format(self._extrapolator)) + "If num_bootstrap >= 2 then the extrapolator must be an instance " + "of WindowExtrapolator, got {} instead".format( + self._extrapolator + ) + ) self._num_bootstrap = num_bootstrap self._extrapolator.window = num_bootstrap # window for extrapolator else: raise QiskitNatureError( - 'num_bootstrap must be None or an integer greater than or equal to 2') + "num_bootstrap must be None or an integer greater than or equal to 2" + ) if isinstance(self._gss.solver, VariationalAlgorithm): # type: ignore # Save initial point passed to min_eigensolver; @@ -105,7 +111,7 @@ def sample(self, problem: BaseProblem, points: List[float]) -> BOPESSamplerResul self._driver = problem.driver if self._driver.molecule is None: - raise QiskitNatureError('Driver MUST be configured with a Molecule.') + raise QiskitNatureError("Driver MUST be configured with a Molecule.") # full dictionary of points self._raw_results = self._run_points(points) @@ -129,14 +135,14 @@ def _run_points(self, points: List[float]) -> Dict[float, EigenstateResult]: Returns: The results for all points. """ - raw_results = dict() # type: Dict[float, EigenstateResult] + raw_results = dict() # type: Dict[float, EigenstateResult] if isinstance(self._gss.solver, VariationalAlgorithm): # type: ignore self._points_optparams = dict() self._gss.solver.initial_point = self._initial_point # type: ignore # Iterate over the points for i, point in enumerate(points): - logger.info('Point %s of %s', i + 1, len(points)) + logger.info("Point %s of %s", i + 1, len(points)) raw_result = self._run_single_point(point) # dict of results raw_results[point] = raw_result @@ -170,16 +176,18 @@ def _run_single_point(self, point: float) -> EigenstateResult: # Set initial params # if prev_points not empty if prev_points: if n_pp <= n_boot: - distances = np.array(point) - \ - np.array(prev_points).reshape(n_pp, -1) + distances = np.array(point) - np.array(prev_points).reshape( + n_pp, -1 + ) # find min 'distance' from point to previous points min_index = np.argmin(np.linalg.norm(distances, axis=1)) # update initial point self._gss.solver.initial_point = prev_params[min_index] # type: ignore else: # extrapolate using saved parameters opt_params = self._points_optparams - param_sets = self._extrapolator.extrapolate(points=[point], - param_dict=opt_params) + param_sets = self._extrapolator.extrapolate( + points=[point], param_dict=opt_params + ) # update initial point, note param_set is a dictionary self._gss.solver.initial_point = param_sets.get(point) # type: ignore diff --git a/qiskit_nature/algorithms/pes_samplers/extrapolator.py b/qiskit_nature/algorithms/pes_samplers/extrapolator.py index 98809b3d83..15e72689b4 100644 --- a/qiskit_nature/algorithms/pes_samplers/extrapolator.py +++ b/qiskit_nature/algorithms/pes_samplers/extrapolator.py @@ -53,8 +53,9 @@ class Extrapolator(ABC): """ @abstractmethod - def extrapolate(self, points: List[float], - param_dict: Dict[float, List[float]]) -> Dict[float, List[float]]: + def extrapolate( + self, points: List[float], param_dict: Dict[float, List[float]] + ) -> Dict[float, List[float]]: """ Abstract method to extrapolate point(s) of interest. @@ -70,7 +71,7 @@ def extrapolate(self, points: List[float], raise NotImplementedError() @staticmethod - def factory(mode: str, **kwargs) -> 'Extrapolator': + def factory(mode: str, **kwargs) -> "Extrapolator": """ Factory method for constructing extrapolators. @@ -89,18 +90,18 @@ def factory(mode: str, **kwargs) -> 'Extrapolator': Raises: QiskitNatureError: if specified mode is unknown. """ - if mode == 'window': + if mode == "window": return WindowExtrapolator(**kwargs) - elif mode == 'poly': + elif mode == "poly": return PolynomialExtrapolator(**kwargs) - elif mode == 'diff_model': + elif mode == "diff_model": return DifferentialExtrapolator(**kwargs) - elif mode == 'pca': + elif mode == "pca": return PCAExtrapolator(**kwargs) - elif mode == 'l1': + elif mode == "l1": return SieveExtrapolator(**kwargs) else: - raise QiskitNatureError('No extrapolator called {}'.format(mode)) + raise QiskitNatureError("No extrapolator called {}".format(mode)) class PolynomialExtrapolator(Extrapolator): @@ -122,8 +123,9 @@ def __init__(self, degree: int = 1) -> None: self._degree = degree - def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List[float]]]) \ - -> Dict[float, List[float]]: + def extrapolate( + self, points: List[float], param_dict: Optional[Dict[float, List[float]]] + ) -> Dict[float, List[float]]: """ Extrapolate at specified point of interest given a set of variational parameters. Extrapolation is based on a polynomial function/spline fitting with a user-specified @@ -161,11 +163,18 @@ class DifferentialExtrapolator(Extrapolator): point being extrapolated in the data window. """ - def __init__(self, - degree: int = 1, - model: Optional[Union[linear_model.LinearRegression, linear_model.Ridge, - linear_model.RidgeCV, linear_model.SGDRegressor]] = None) \ - -> None: + def __init__( + self, + degree: int = 1, + model: Optional[ + Union[ + linear_model.LinearRegression, + linear_model.Ridge, + linear_model.RidgeCV, + linear_model.SGDRegressor, + ] + ] = None, + ) -> None: """ Constructor. @@ -181,8 +190,9 @@ def __init__(self, self._degree = degree self._model = model or linear_model.LinearRegression() - def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List[float]]]) \ - -> Dict[float, List[float]]: + def extrapolate( + self, points: List[float], param_dict: Optional[Dict[float, List[float]]] + ) -> Dict[float, List[float]]: """ Extrapolate at specified point of interest given a set of variational parameters. Each parameter list and list of numerical gradients is treated as a single point @@ -220,10 +230,11 @@ class WindowExtrapolator(Extrapolator): ground truth parameter set to a fixed window size. """ - def __init__(self, - extrapolator: Union[PolynomialExtrapolator, - DifferentialExtrapolator] = None, - window: int = 2) -> None: + def __init__( + self, + extrapolator: Union[PolynomialExtrapolator, DifferentialExtrapolator] = None, + window: int = 2, + ) -> None: """ Constructor. @@ -237,8 +248,9 @@ def __init__(self, self._extrapolator = extrapolator self._window = window - def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List[float]]]) \ - -> Dict[float, List[float]]: + def extrapolate( + self, points: List[float], param_dict: Optional[Dict[float, List[float]]] + ) -> Dict[float, List[float]]: """ Extrapolate at specified point of interest given a set of variational parameters. Based on the specified window, a subset of the data points will be used for @@ -257,21 +269,26 @@ def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List """ ret_params = {} sorted_points = sorted(points) - reference_points = [pt for pt in sorted(param_dict.keys()) if pt < max(sorted_points)] + reference_points = [ + pt for pt in sorted(param_dict.keys()) if pt < max(sorted_points) + ] for bottom_index, bottom in enumerate(reference_points): if bottom_index < len(reference_points) - 1: top = reference_points[bottom_index + 1] else: - top = float('inf') + top = float("inf") extrapolation_group = [pt for pt in sorted_points if bottom < pt <= top] window_points = [pt for pt in reference_points if pt <= bottom] if len(window_points) > self._window: - window_points = window_points[-self._window:] + window_points = window_points[-self._window :] window_param_dict = {pt: param_dict[pt] for pt in window_points} if extrapolation_group: - ret_params.update(self._extrapolator.extrapolate(extrapolation_group, - param_dict=window_param_dict)) + ret_params.update( + self._extrapolator.extrapolate( + extrapolation_group, param_dict=window_param_dict + ) + ) return ret_params @property @@ -284,8 +301,9 @@ def extrapolator(self) -> Extrapolator: return self._extrapolator @extrapolator.setter - def extrapolator(self, extrapolator: Union[PolynomialExtrapolator, - DifferentialExtrapolator]) -> None: + def extrapolator( + self, extrapolator: Union[PolynomialExtrapolator, DifferentialExtrapolator] + ) -> None: """Sets the internal extrapolator. Args: @@ -320,11 +338,14 @@ class PCAExtrapolator(Extrapolator): A user specifies the kernel within how the PCA transformation should be done. """ - def __init__(self, - extrapolator: Optional[Union[PolynomialExtrapolator, - DifferentialExtrapolator]] = None, - kernel: Optional[str] = None, - window: int = 2) -> None: + def __init__( + self, + extrapolator: Optional[ + Union[PolynomialExtrapolator, DifferentialExtrapolator] + ] = None, + kernel: Optional[str] = None, + window: int = 2, + ) -> None: """ Constructor. @@ -339,17 +360,20 @@ def __init__(self, Raises: QiskitNatureError: if kernel is not defined in sklearn module. """ - self._extrapolator = WindowExtrapolator(extrapolator=extrapolator, window=window) + self._extrapolator = WindowExtrapolator( + extrapolator=extrapolator, window=window + ) self._kernel = kernel if self._kernel is None: self._pca_model = PCA() - elif self._kernel in ['linear', 'poly', 'rbf', 'sigmoid', 'cosine']: + elif self._kernel in ["linear", "poly", "rbf", "sigmoid", "cosine"]: self._pca_model = KernelPCA(kernel=self._kernel, fit_inverse_transform=True) else: - raise QiskitNatureError('PCA kernel type {} not found'.format(self._kernel)) + raise QiskitNatureError("PCA kernel type {} not found".format(self._kernel)) - def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List[float]]]) \ - -> Dict[float, List[float]]: + def extrapolate( + self, points: List[float], param_dict: Optional[Dict[float, List[float]]] + ) -> Dict[float, List[float]]: """ Extrapolate at specified point of interest given a set of variational parameters. This method transforms the parameters in PCA space before performing the internal @@ -366,12 +390,18 @@ def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List """ # run pca fitting and extrapolate in pca space self._pca_model.fit(list(param_dict.values())) - updated_params = {pt: self._pca_model.transform([param_dict[pt]])[0] - for pt in list(param_dict.keys())} - output_params = self._extrapolator.extrapolate(points, param_dict=updated_params) - - ret_params = {point: self._pca_model.inverse_transform(param) if not param else [] - for (point, param) in output_params.items()} + updated_params = { + pt: self._pca_model.transform([param_dict[pt]])[0] + for pt in list(param_dict.keys()) + } + output_params = self._extrapolator.extrapolate( + points, param_dict=updated_params + ) + + ret_params = { + point: self._pca_model.inverse_transform(param) if not param else [] + for (point, param) in output_params.items() + } return ret_params @@ -382,12 +412,15 @@ class SieveExtrapolator(Extrapolator): small clusters' parameters to zero. """ - def __init__(self, - extrapolator: Optional[Union[PolynomialExtrapolator, - DifferentialExtrapolator]] = None, - window: int = 2, - filter_before: bool = True, - filter_after: bool = True) -> None: + def __init__( + self, + extrapolator: Optional[ + Union[PolynomialExtrapolator, DifferentialExtrapolator] + ] = None, + window: int = 2, + filter_before: bool = True, + filter_after: bool = True, + ) -> None: """ Constructor. @@ -399,12 +432,15 @@ def __init__(self, filter_after: Keyword to perform clustering after extrapolation. """ - self._extrapolator = WindowExtrapolator(extrapolator=extrapolator, window=window) + self._extrapolator = WindowExtrapolator( + extrapolator=extrapolator, window=window + ) self._filter_before = filter_before self._filter_after = filter_after - def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List[float]]]) \ - -> Dict[float, List[float]]: + def extrapolate( + self, points: List[float], param_dict: Optional[Dict[float, List[float]]] + ) -> Dict[float, List[float]]: """ Extrapolate at specified point of interest given a set of variational parameters. Based on the specified window, a subset of the data points will be used for @@ -425,24 +461,38 @@ def extrapolate(self, points: List[float], param_dict: Optional[Dict[float, List """ # determine clustering cutoff param_arr = np.transpose(list(param_dict.values())) - param_averages = np.array(sorted(np.average(np.log10(np.abs(param_arr)), axis=0))) + param_averages = np.array( + sorted(np.average(np.log10(np.abs(param_arr)), axis=0)) + ) gaps = param_averages[1:] - param_averages[:-1] max_gap = int(np.argmax(gaps)) - sieve_cutoff = 10 ** np.average([param_averages[max_gap], param_averages[max_gap + 1]]) + sieve_cutoff = 10 ** np.average( + [param_averages[max_gap], param_averages[max_gap + 1]] + ) if self._filter_before: - filtered_dict = {point: list(map(lambda x: x if np.abs(x) > sieve_cutoff else 0, param)) - for (point, param) in param_dict.items()} - output_params = self._extrapolator.extrapolate(points, param_dict=filtered_dict) + filtered_dict = { + point: list(map(lambda x: x if np.abs(x) > sieve_cutoff else 0, param)) + for (point, param) in param_dict.items() + } + output_params = self._extrapolator.extrapolate( + points, param_dict=filtered_dict + ) else: - output_params = self._extrapolator.extrapolate(points, param_dict=param_dict) + output_params = self._extrapolator.extrapolate( + points, param_dict=param_dict + ) if self._filter_after: - ret_params = \ - cast(Dict[float, List[float]], - {point: np.asarray(list(map(lambda x: x - if np.abs(x) > sieve_cutoff else 0, param))) - for (point, param) in output_params.items()}) + ret_params = cast( + Dict[float, List[float]], + { + point: np.asarray( + list(map(lambda x: x if np.abs(x) > sieve_cutoff else 0, param)) + ) + for (point, param) in output_params.items() + }, + ) else: ret_params = cast(Dict[float, List[float]], np.asarray(output_params)) return ret_params diff --git a/qiskit_nature/algorithms/pes_samplers/potentials/__init__.py b/qiskit_nature/algorithms/pes_samplers/potentials/__init__.py index ae94590de6..e62d46d662 100644 --- a/qiskit_nature/algorithms/pes_samplers/potentials/__init__.py +++ b/qiskit_nature/algorithms/pes_samplers/potentials/__init__.py @@ -18,10 +18,10 @@ from .potential_base import EnergySurfaceBase, PotentialBase, VibrationalStructureBase __all__ = [ - 'EnergySurface1DSpline', - 'HarmonicPotential', - 'MorsePotential', - 'EnergySurfaceBase', - 'PotentialBase', - 'VibrationalStructureBase', + "EnergySurface1DSpline", + "HarmonicPotential", + "MorsePotential", + "EnergySurfaceBase", + "PotentialBase", + "VibrationalStructureBase", ] diff --git a/qiskit_nature/algorithms/pes_samplers/potentials/energy_surface_spline.py b/qiskit_nature/algorithms/pes_samplers/potentials/energy_surface_spline.py index 6edf740a66..da3e72352c 100644 --- a/qiskit_nature/algorithms/pes_samplers/potentials/energy_surface_spline.py +++ b/qiskit_nature/algorithms/pes_samplers/potentials/energy_surface_spline.py @@ -51,10 +51,13 @@ def eval(self, x: float) -> float: return result - def fit(self, xdata: List[float], ydata: List[float], - initial_vals: Optional[List[float]] = None, - bounds_list: Optional[Tuple[List[float], List[float]]] = None - ) -> None: + def fit( + self, + xdata: List[float], + ydata: List[float], + initial_vals: Optional[List[float]] = None, + bounds_list: Optional[Tuple[List[float], List[float]]] = None, + ) -> None: r"""Fits surface to data. Args: diff --git a/qiskit_nature/algorithms/pes_samplers/potentials/harmonic_potential.py b/qiskit_nature/algorithms/pes_samplers/potentials/harmonic_potential.py index 49e811ea36..cd811696c7 100644 --- a/qiskit_nature/algorithms/pes_samplers/potentials/harmonic_potential.py +++ b/qiskit_nature/algorithms/pes_samplers/potentials/harmonic_potential.py @@ -17,7 +17,9 @@ from scipy.optimize import curve_fit import qiskit_nature.constants as const -from qiskit_nature.algorithms.pes_samplers.potentials.potential_base import PotentialBase +from qiskit_nature.algorithms.pes_samplers.potentials.potential_base import ( + PotentialBase, +) from qiskit_nature.drivers import Molecule @@ -27,6 +29,7 @@ class HarmonicPotential(PotentialBase): Input units are Angstroms (distance between the two atoms), and output units are Hartrees (molecular energy). """ + # Works in Angstroms (input) and Hartrees (output) def __init__(self, molecule: Molecule) -> None: @@ -47,8 +50,7 @@ def __init__(self, molecule: Molecule) -> None: self._m_a = molecule.masses[0] self._m_b = molecule.masses[1] else: - raise ValueError( - 'Molecule masses need to be provided') + raise ValueError("Molecule masses need to be provided") @staticmethod def fit_function(x: float, k: float, r_0: float, m_shift: float) -> float: @@ -78,7 +80,7 @@ def eval(self, x: float) -> float: """ return self.fit_function(x, self.k, self.r_0, self.m_shift) - def update_molecule(self, molecule: Molecule) -> Molecule: # type: ignore + def update_molecule(self, molecule: Molecule) -> Molecule: # type: ignore """Updates the underlying molecule. Args: @@ -90,13 +92,17 @@ def update_molecule(self, molecule: Molecule) -> Molecule: # type: ignore # Check the provided molecule super().update_molecule(molecule) if len(molecule.masses) != 2: - raise ValueError('Harmonic potential only works for diatomic molecules!') + raise ValueError("Harmonic potential only works for diatomic molecules!") self._m_a = molecule.masses[0] self._m_b = molecule.masses[1] - def fit(self, xdata: List[float], ydata: List[float], - initial_vals: Optional[List[float]] = None, - bounds_list: Optional[Tuple[List[float], List[float]]] = None) -> None: + def fit( + self, + xdata: List[float], + ydata: List[float], + initial_vals: Optional[List[float]] = None, + bounds_list: Optional[Tuple[List[float], List[float]]] = None, + ) -> None: """Fits a potential to computed molecular energies. Args: @@ -115,16 +121,22 @@ def fit(self, xdata: List[float], ydata: List[float], # do the Harmonic potential fit here, the order of parameters is # [k (Hartrees/(Ang**2)), r_0 (Ang), energy_shift (Hartrees)] - h_p0 = (initial_vals if initial_vals is not None - else np.array([0.2, 0.735, 1.5])) - h_bounds = (bounds_list if bounds_list is not None - else ([0, -1, -2], [2, 3.0, 2])) + h_p0 = initial_vals if initial_vals is not None else np.array([0.2, 0.735, 1.5]) + h_bounds = ( + bounds_list if bounds_list is not None else ([0, -1, -2], [2, 3.0, 2]) + ) xdata_fit = xdata ydata_fit = ydata - fit, _ = curve_fit(self.fit_function, xdata_fit, ydata_fit, - p0=h_p0, maxfev=100000, bounds=h_bounds) + fit, _ = curve_fit( + self.fit_function, + xdata_fit, + ydata_fit, + p0=h_p0, + maxfev=100000, + bounds=h_bounds, + ) self.k = fit[0] self.r_0 = fit[1] @@ -175,7 +187,7 @@ def dissociation_energy(self, scaling: float = 1.0) -> float: estimated dissociation energy """ # Hartree/(Ang**2) to Hartree!! 1/Ang**2 -> 1/m**2 - k = self.k * 1E20 + k = self.k * 1e20 if self.d_e is not None: k = self.d_e @@ -191,7 +203,7 @@ def fundamental_frequency(self) -> float: fundamental frequency for the current fit """ # Hartree(J)/(Ang**2), need Joules per molecule!! 1/Ang**2 -> 1/m**2 - k = self.k * const.HARTREE_TO_J * 1E20 + k = self.k * const.HARTREE_TO_J * 1e20 # r0 = self.r_0*1E-10 # angstrom, need meter m_r = (self._m_a * self._m_b) / (self._m_a + self._m_b) @@ -207,7 +219,7 @@ def wave_number(self) -> int: Returns: wave number for the current fit """ - return self.fundamental_frequency() / const.C_CM_PER_S # type: ignore + return self.fundamental_frequency() / const.C_CM_PER_S # type: ignore def vibrational_energy_level(self, n: int) -> float: """ @@ -226,7 +238,9 @@ def vibrational_energy_level(self, n: int) -> float: return e_n * const.J_TO_HARTREE @classmethod - def process_fit_data(cls, xdata: List[float], ydata: List[float]) -> Tuple[list, list]: + def process_fit_data( + cls, xdata: List[float], ydata: List[float] + ) -> Tuple[list, list]: """ Mostly for internal use. Preprocesses the data passed to fit_to_data() so that only the points around the minimum are fit (which gives @@ -252,17 +266,16 @@ def process_fit_data(cls, xdata: List[float], ydata: List[float]) -> Tuple[list, all_of_min = np.array([], dtype=int) for i in x_min: all_of_min = np.concatenate( - (all_of_min, np.where(xdata_s == xdata_s[i])[0])) + (all_of_min, np.where(xdata_s == xdata_s[i])[0]) + ) # array of indices where X is equal to the next smaller value left_of_min = [] if min(all_of_min) > 0: - left_of_min = np.where( - xdata_s == xdata_s[min(all_of_min) - 1])[0] + left_of_min = np.where(xdata_s == xdata_s[min(all_of_min) - 1])[0] # array of indices where X is equal to the next bigger value right_of_min = [] if max(all_of_min) < (xdata_s.size - 1): - right_of_min = np.where( - xdata_s == xdata_s[max(all_of_min) + 1])[0] + right_of_min = np.where(xdata_s == xdata_s[max(all_of_min) + 1])[0] # all those indices together are used for fitting a harmonic # potential (around the min) inds = np.concatenate((left_of_min, all_of_min, right_of_min)) diff --git a/qiskit_nature/algorithms/pes_samplers/potentials/morse_potential.py b/qiskit_nature/algorithms/pes_samplers/potentials/morse_potential.py index bfe65afae8..9e10bf882f 100644 --- a/qiskit_nature/algorithms/pes_samplers/potentials/morse_potential.py +++ b/qiskit_nature/algorithms/pes_samplers/potentials/morse_potential.py @@ -18,7 +18,9 @@ import numpy as np from scipy.optimize import curve_fit -from qiskit_nature.algorithms.pes_samplers.potentials.potential_base import PotentialBase +from qiskit_nature.algorithms.pes_samplers.potentials.potential_base import ( + PotentialBase, +) from qiskit_nature.drivers import Molecule import qiskit_nature.constants as const @@ -29,6 +31,7 @@ class MorsePotential(PotentialBase): Input units are Angstroms (distance between the two atoms), and output units are Hartrees (molecular energy). """ + # Works in Angstroms and Hartrees def __init__(self, molecule: Molecule): @@ -52,15 +55,12 @@ def __init__(self, molecule: Molecule): self._m_a = molecule.masses[0] self._m_b = molecule.masses[1] else: - raise ValueError( - 'Molecule masses need to be provided') + raise ValueError("Molecule masses need to be provided") @staticmethod - def fit_function(x: float, - d_e: float, - alpha: float, - r_0: float, - m_shift: float) -> float: + def fit_function( + x: float, d_e: float, alpha: float, r_0: float, m_shift: float + ) -> float: """Functional form of the potential. Args: @@ -86,8 +86,7 @@ def eval(self, x: float) -> float: value of surface in point x """ # Expects Angstroms returns Hartrees - return self.fit_function(x, self.d_e, - self.alpha, self.r_0, self.m_shift) + return self.fit_function(x, self.d_e, self.alpha, self.r_0, self.m_shift) def update_molecule(self, molecule: Molecule) -> None: """Updates the underlying molecule. @@ -102,18 +101,19 @@ def update_molecule(self, molecule: Molecule) -> None: # Check the provided molecule super().update_molecule(molecule) if molecule.masses is None: - raise ValueError( - 'Molecule massses need to be provided') + raise ValueError("Molecule massses need to be provided") if len(molecule.masses) != 2: - raise ValueError( - 'Morse potential only works for diatomic molecules!') + raise ValueError("Morse potential only works for diatomic molecules!") self._m_a = molecule.masses[0] self._m_b = molecule.masses[1] - def fit(self, xdata: List[float], ydata: List[float], - initial_vals: Optional[List[float]] = None, - bounds_list: Optional[Tuple[List[float], List[float]]] = None - ) -> None: + def fit( + self, + xdata: List[float], + ydata: List[float], + initial_vals: Optional[List[float]] = None, + bounds_list: Optional[Tuple[List[float], List[float]]] = None, + ) -> None: """Fits a potential to computed molecular energies. Args: @@ -130,14 +130,20 @@ def fit(self, xdata: List[float], ydata: List[float], # do the Morse potential fit # here, the order of parameters is # [d_e (Hartree), alpha (1/ang), r_0 (ang), energy_shift (Hartree)] - m_p0 = (initial_vals if initial_vals is not None - else np.array([0.25, 2, 0.735, 1.5])) - m_bounds = (bounds_list if bounds_list is not None - else ([0, 0, 0.3, -5], - [2.5, np.inf, 1.0, 5])) + m_p0 = ( + initial_vals + if initial_vals is not None + else np.array([0.25, 2, 0.735, 1.5]) + ) + m_bounds = ( + bounds_list + if bounds_list is not None + else ([0, 0, 0.3, -5], [2.5, np.inf, 1.0, 5]) + ) - fit, _ = curve_fit(self.fit_function, xdata, ydata, - p0=m_p0, maxfev=100000, bounds=m_bounds) + fit, _ = curve_fit( + self.fit_function, xdata, ydata, p0=m_p0, maxfev=100000, bounds=m_bounds + ) self.d_e = fit[0] self.alpha = fit[1] @@ -197,7 +203,7 @@ def fundamental_frequency(self) -> float: fundamental frequency for the current fit """ d_e = self.d_e * const.HARTREE_TO_J # Hartree, need J/molecule - alp = self.alpha * 1E10 # 1/angstrom, need 1/meter + alp = self.alpha * 1e10 # 1/angstrom, need 1/meter # r0 = self.r_0*1E-10 # angstrom, need meter m_r = (self._m_a * self._m_b) / (self._m_a + self._m_b) @@ -227,8 +233,9 @@ def vibrational_energy_level(self, n: int) -> float: d_e = self.d_e * const.HARTREE_TO_J # Hartree, need J/molecule omega_0 = self.fundamental_frequency() - e_n = const.H_J_S * omega_0 * (n + 0.5) - \ - ((const.H_J_S * omega_0 * (n + 0.5)) ** 2) / (4 * d_e) + e_n = const.H_J_S * omega_0 * (n + 0.5) - ( + (const.H_J_S * omega_0 * (n + 0.5)) ** 2 + ) / (4 * d_e) # energy level return e_n * const.J_TO_HARTREE @@ -249,6 +256,7 @@ def get_maximum_trusted_level(self, n: int = 0) -> float: # Astronomy & Astrophysics, Vol. 595, November 2016 # https://doi.org/10.1051/0004-6361/201527209 return np.floor( - 2 * self.dissociation_energy(const.HARTREE_TO_J) / - (const.H_J_S * self.fundamental_frequency()) + 2 + * self.dissociation_energy(const.HARTREE_TO_J) + / (const.H_J_S * self.fundamental_frequency()) ) diff --git a/qiskit_nature/algorithms/pes_samplers/potentials/potential_base.py b/qiskit_nature/algorithms/pes_samplers/potentials/potential_base.py index dd065570a1..f37975d5ce 100644 --- a/qiskit_nature/algorithms/pes_samplers/potentials/potential_base.py +++ b/qiskit_nature/algorithms/pes_samplers/potentials/potential_base.py @@ -21,7 +21,7 @@ class EnergySurfaceBase(ABC): - """ Class to hold a potential energy surface """ + """Class to hold a potential energy surface""" @abstractmethod def eval(self, x: float) -> float: @@ -37,10 +37,13 @@ def eval(self, x: float) -> float: raise NotImplementedError @abstractmethod - def fit(self, xdata: List[float], ydata: List[float], - initial_vals: Optional[List[float]] = None, - bounds_list: Optional[Tuple[List[float], List[float]]] = None - ) -> None: + def fit( + self, + xdata: List[float], + ydata: List[float], + initial_vals: Optional[List[float]] = None, + bounds_list: Optional[Tuple[List[float], List[float]]] = None, + ) -> None: """Fits surface to data Args: @@ -147,7 +150,8 @@ def vibrational_energy_level(self, n: int) -> float: """ raise NotImplementedError - def get_maximum_trusted_level(self, n: int = 0) -> float: # pylint: disable=unused-argument + # pylint: disable=unused-argument + def get_maximum_trusted_level(self, n: int = 0) -> float: """ Returns the maximum energy level for which the particular implementation still provides a good approximation of reality. @@ -166,7 +170,7 @@ class PotentialBase(EnergySurfaceBase, VibrationalStructureBase): """Class to hold prescribed 1D potentials (e.g. Morse/Harmonic) over a degree of freedom.""" def get_num_modes(self) -> int: - """ This (1D) potential represents a single vibrational mode """ + """This (1D) potential represents a single vibrational mode""" return 1 def get_trust_region(self) -> Tuple[float, float]: diff --git a/qiskit_nature/circuit/library/__init__.py b/qiskit_nature/circuit/library/__init__.py index 1aab82fce0..380d6f3119 100644 --- a/qiskit_nature/circuit/library/__init__.py +++ b/qiskit_nature/circuit/library/__init__.py @@ -56,20 +56,17 @@ UVCCSD, ) -from .initial_states import ( - HartreeFock, - VSCF -) +from .initial_states import HartreeFock, VSCF __all__ = [ - 'EvolvedOperatorAnsatz', - 'UCC', - 'UCCSD', - 'PUCCD', - 'SUCCD', - 'HartreeFock', - 'CHC', - 'UVCC', - 'UVCCSD', - 'VSCF', + "EvolvedOperatorAnsatz", + "UCC", + "UCCSD", + "PUCCD", + "SUCCD", + "HartreeFock", + "CHC", + "UVCC", + "UVCCSD", + "VSCF", ] diff --git a/qiskit_nature/circuit/library/ansatzes/__init__.py b/qiskit_nature/circuit/library/ansatzes/__init__.py index 0ff473450a..e2510815a2 100644 --- a/qiskit_nature/circuit/library/ansatzes/__init__.py +++ b/qiskit_nature/circuit/library/ansatzes/__init__.py @@ -53,12 +53,12 @@ from .uvccsd import UVCCSD __all__ = [ - 'CHC', - 'EvolvedOperatorAnsatz', - 'PUCCD', - 'SUCCD', - 'UCC', - 'UCCSD', - 'UVCC', - 'UVCCSD', + "CHC", + "EvolvedOperatorAnsatz", + "PUCCD", + "SUCCD", + "UCC", + "UCCSD", + "UVCC", + "UVCCSD", ] diff --git a/qiskit_nature/circuit/library/ansatzes/chc.py b/qiskit_nature/circuit/library/ansatzes/chc.py index 7d7af7e43c..964fbe47b4 100644 --- a/qiskit_nature/circuit/library/ansatzes/chc.py +++ b/qiskit_nature/circuit/library/ansatzes/chc.py @@ -23,7 +23,7 @@ class CHC(BlueprintCircuit): - """ This trial wavefunction is the Compact Heuristic for vibrational Chemistry. + """This trial wavefunction is the Compact Heuristic for vibrational Chemistry. The trial wavefunction is as defined in Ollitrault Pauline J., Chemical science 11 (2020): 6842-6855. It aims at approximating @@ -34,12 +34,14 @@ class CHC(BlueprintCircuit): with the number of excitations. """ - def __init__(self, - num_qubits: Optional[int] = None, - excitations: Optional[List[Tuple[Tuple[Any, ...], ...]]] = None, - reps: int = 1, - ladder: bool = False, - initial_state: Optional[QuantumCircuit] = None) -> None: + def __init__( + self, + num_qubits: Optional[int] = None, + excitations: Optional[List[Tuple[Tuple[Any, ...], ...]]] = None, + reps: int = 1, + ladder: bool = False, + initial_state: Optional[QuantumCircuit] = None, + ) -> None: """ Args: @@ -92,7 +94,7 @@ def num_qubits(self, num_qubits: int) -> None: # invalidate the circuit self._invalidate() self._num_qubits = num_qubits - self.qregs = [QuantumRegister(num_qubits, name='q')] + self.qregs = [QuantumRegister(num_qubits, name="q")] @property def excitations(self) -> Optional[List[Tuple[Tuple[Any, ...], ...]]]: @@ -133,20 +135,20 @@ def _check_configuration(self, raise_on_failure: bool = True) -> bool: ValueError: If the number of parameters is not specified. ValueError: If the excitation list is not specified. """ - error_msg = 'The %s is None but must be set before the circuit can be built.' + error_msg = "The %s is None but must be set before the circuit can be built." if self._num_qubits is None: if raise_on_failure: - raise ValueError(error_msg, 'number of qubits') + raise ValueError(error_msg, "number of qubits") return False if self._num_parameters is None: if raise_on_failure: - raise ValueError(error_msg, 'number of parameters') + raise ValueError(error_msg, "number of parameters") return False if self._excitations is None: if raise_on_failure: - raise ValueError(error_msg, 'excitation list') + raise ValueError(error_msg, "excitation list") return False return True @@ -167,11 +169,13 @@ def _build(self) -> None: self._check_configuration() self._data = [] # type: ignore - parameters = ParameterVector('θ', self._num_parameters) + parameters = ParameterVector("θ", self._num_parameters) q = self.qubits if isinstance(self._initial_state, QuantumCircuit): - self.append(self._initial_state.to_gate(), range(self._initial_state.num_qubits)) + self.append( + self._initial_state.to_gate(), range(self._initial_state.num_qubits) + ) count = 0 for _ in range(self._reps): @@ -224,14 +228,14 @@ def _build(self) -> None: if self._ladder: for qubit in range(i, r): - self.cx(q[qubit], q[qubit+1]) - self.barrier(q[qubit], q[qubit+1]) + self.cx(q[qubit], q[qubit + 1]) + self.barrier(q[qubit], q[qubit + 1]) else: self.cx(q[i], q[r]) self.cx(q[r], q[j]) if self._ladder: for qubit in range(j, s): - self.cx(q[qubit], q[qubit+1]) + self.cx(q[qubit], q[qubit + 1]) self.barrier(q[qubit], q[qubit + 1]) else: self.cx(q[j], q[s]) @@ -240,14 +244,14 @@ def _build(self) -> None: if self._ladder: for qubit in range(s, j, -1): - self.cx(q[qubit-1], q[qubit]) - self.barrier(q[qubit-1], q[qubit]) + self.cx(q[qubit - 1], q[qubit]) + self.barrier(q[qubit - 1], q[qubit]) else: self.cx(q[j], q[s]) self.cx(q[r], q[j]) if self._ladder: for qubit in range(r, i, -1): - self.cx(q[qubit-1], q[qubit]) + self.cx(q[qubit - 1], q[qubit]) self.barrier(q[qubit - 1], q[qubit]) else: self.cx(q[i], q[r]) @@ -261,7 +265,9 @@ def _build(self) -> None: self.p(-parameters[count] / 2 + np.pi, q[r]) else: - raise ValueError('Limited to single and double excitations, ' - 'higher order is not implemented') + raise ValueError( + "Limited to single and double excitations, " + "higher order is not implemented" + ) count += 1 diff --git a/qiskit_nature/circuit/library/ansatzes/evolved_operator_ansatz.py b/qiskit_nature/circuit/library/ansatzes/evolved_operator_ansatz.py index ad7b65b8bb..245a1a914f 100644 --- a/qiskit_nature/circuit/library/ansatzes/evolved_operator_ansatz.py +++ b/qiskit_nature/circuit/library/ansatzes/evolved_operator_ansatz.py @@ -25,13 +25,15 @@ class EvolvedOperatorAnsatz(BlueprintCircuit): """The evolved operator ansatz.""" - def __init__(self, - operators: Optional[Union[OperatorBase, List[OperatorBase]]] = None, - reps: int = 1, - evolution: Optional[EvolutionBase] = None, - insert_barriers: bool = False, - name: str = 'EvolvedOps', - initial_state: Optional[QuantumCircuit] = None): + def __init__( + self, + operators: Optional[Union[OperatorBase, List[OperatorBase]]] = None, + reps: int = 1, + evolution: Optional[EvolutionBase] = None, + insert_barriers: bool = False, + name: str = "EvolvedOps", + initial_state: Optional[QuantumCircuit] = None, + ): """ Args: operators: The operators to evolve. @@ -58,12 +60,12 @@ def __init__(self, def _check_configuration(self, raise_on_failure: bool = True) -> bool: if self.operators is None: if raise_on_failure: - raise ValueError('The operators are not set.') + raise ValueError("The operators are not set.") return False if self.reps < 1: if raise_on_failure: - raise ValueError('The reps cannot be smaller than 1.') + raise ValueError("The reps cannot be smaller than 1.") return False return True @@ -114,8 +116,10 @@ def operators(self, operators: Union[OperatorBase, List[OperatorBase]]) -> None: if len(operators) > 1: num_qubits = operators[0].num_qubits - if any(operators[i].num_qubits != num_qubits for i in range(1, len(operators))): - raise ValueError('All operators must act on the same number of qubits.') + if any( + operators[i].num_qubits != num_qubits for i in range(1, len(operators)) + ): + raise ValueError("All operators must act on the same number of qubits.") self._invalidate() self._operators = operators @@ -158,21 +162,23 @@ def _build(self): self._data = [] # get the evolved operators as circuits - coeff = Parameter('c') - evolved_ops = [self.evolution.convert((coeff * op).exp_i()) for op in self.operators] + coeff = Parameter("c") + evolved_ops = [ + self.evolution.convert((coeff * op).exp_i()) for op in self.operators + ] circuits = [evolved_op.reduce().to_circuit() for evolved_op in evolved_ops] # set the registers num_qubits = circuits[0].num_qubits try: - qr = QuantumRegister(num_qubits, 'q') + qr = QuantumRegister(num_qubits, "q") self.add_register(qr) except CircuitError: # the register already exists, probably because of a previous composition pass # build the circuit - times = ParameterVector('t', self.reps * len(self.operators)) + times = ParameterVector("t", self.reps * len(self.operators)) times_it = iter(times) first = True @@ -183,7 +189,9 @@ def _build(self): else: if self._insert_barriers: self.barrier() - self.compose(circuit.assign_parameters({coeff: next(times_it)}), inplace=True) + self.compose( + circuit.assign_parameters({coeff: next(times_it)}), inplace=True + ) if self._initial_state: self.compose(self._initial_state, front=True, inplace=True) diff --git a/qiskit_nature/circuit/library/ansatzes/puccd.py b/qiskit_nature/circuit/library/ansatzes/puccd.py index aaf84aa951..694be7f2d5 100644 --- a/qiskit_nature/circuit/library/ansatzes/puccd.py +++ b/qiskit_nature/circuit/library/ansatzes/puccd.py @@ -45,13 +45,15 @@ class PUCCD(UCC): [1] https://arxiv.org/abs/1911.10864 """ - def __init__(self, qubit_converter: Optional[QubitConverter] = None, - num_particles: Optional[Tuple[int, int]] = None, - num_spin_orbitals: Optional[int] = None, - reps: int = 1, - initial_state: Optional[QuantumCircuit] = None, - include_singles: Tuple[bool, bool] = (False, False), - ): + def __init__( + self, + qubit_converter: Optional[QubitConverter] = None, + num_particles: Optional[Tuple[int, int]] = None, + num_spin_orbitals: Optional[int] = None, + reps: int = 1, + initial_state: Optional[QuantumCircuit] = None, + include_singles: Tuple[bool, bool] = (False, False), + ): """ Args: @@ -69,15 +71,17 @@ def __init__(self, qubit_converter: Optional[QubitConverter] = None, """ self._validate_num_particles(num_particles) self._include_singles = include_singles - super().__init__(qubit_converter=qubit_converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - excitations=self.generate_excitations, - alpha_spin=True, - beta_spin=True, - max_spin_excitation=None, - reps=reps, - initial_state=initial_state) + super().__init__( + qubit_converter=qubit_converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + excitations=self.generate_excitations, + alpha_spin=True, + beta_spin=True, + max_spin_excitation=None, + reps=reps, + initial_state=initial_state, + ) @property def include_singles(self) -> Tuple[bool, bool]: @@ -89,9 +93,9 @@ def include_singles(self, include_singles: Tuple[bool, bool]) -> None: """Sets whether to include single excitations.""" self._include_singles = include_singles - def generate_excitations(self, num_spin_orbitals: int, - num_particles: Tuple[int, int] - ) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: + def generate_excitations( + self, num_spin_orbitals: int, num_particles: Tuple[int, int] + ) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: """Generates the excitations for the PUCCD Ansatz. Args: @@ -110,9 +114,15 @@ def generate_excitations(self, num_spin_orbitals: int, self._validate_num_particles(num_particles) excitations = list() - excitations.extend(generate_fermionic_excitations(1, num_spin_orbitals, num_particles, - alpha_spin=self.include_singles[0], - beta_spin=self.include_singles[1])) + excitations.extend( + generate_fermionic_excitations( + 1, + num_spin_orbitals, + num_particles, + alpha_spin=self.include_singles[0], + beta_spin=self.include_singles[1], + ) + ) num_electrons = num_particles[0] beta_index_shift = num_spin_orbitals // 2 @@ -122,18 +132,23 @@ def generate_excitations(self, num_spin_orbitals: int, alpha_unocc = list(range(num_electrons, beta_index_shift)) # the Cartesian product of these lists gives all possible single alpha-spin excitations alpha_excitations = list(itertools.product(alpha_occ, alpha_unocc)) - logger.debug('Generated list of single alpha excitations: %s', alpha_excitations) + logger.debug( + "Generated list of single alpha excitations: %s", alpha_excitations + ) for alpha_exc in alpha_excitations: # create the beta-spin excitation by shifting into the upper block-spin orbital indices - beta_exc = (alpha_exc[0] + beta_index_shift, alpha_exc[1] + beta_index_shift) + beta_exc = ( + alpha_exc[0] + beta_index_shift, + alpha_exc[1] + beta_index_shift, + ) # add the excitation tuple occ: Tuple[int, ...] unocc: Tuple[int, ...] occ, unocc = zip(alpha_exc, beta_exc) exc_tuple = (occ, unocc) excitations.append(exc_tuple) - logger.debug('Added the excitation: %s', exc_tuple) + logger.debug("Added the excitation: %s", exc_tuple) return excitations @@ -144,6 +159,7 @@ def _validate_num_particles(self, num_particles): assert num_particles[0] == num_particles[1] except AssertionError as exc: raise QiskitNatureError( - 'The PUCCD Ansatz only works for singlet-spin systems. However, you specified ' - 'differing numbers of alpha and beta electrons:', str(num_particles) + "The PUCCD Ansatz only works for singlet-spin systems. However, you specified " + "differing numbers of alpha and beta electrons:", + str(num_particles), ) from exc diff --git a/qiskit_nature/circuit/library/ansatzes/succd.py b/qiskit_nature/circuit/library/ansatzes/succd.py index 3a2daa4e75..09f694b01b 100644 --- a/qiskit_nature/circuit/library/ansatzes/succd.py +++ b/qiskit_nature/circuit/library/ansatzes/succd.py @@ -31,6 +31,7 @@ # TODO: figure out how to implement `succ_full`: a variant of this class, which does include also # the symmetrically mirrored double excitations, but assigns the same circuit parameter to them. + class SUCCD(UCC): """The SUCCD Ansatz. @@ -48,13 +49,15 @@ class SUCCD(UCC): [1] https://arxiv.org/abs/1911.10864 """ - def __init__(self, qubit_converter: Optional[QubitConverter] = None, - num_particles: Optional[Tuple[int, int]] = None, - num_spin_orbitals: Optional[int] = None, - reps: int = 1, - initial_state: Optional[QuantumCircuit] = None, - include_singles: Tuple[bool, bool] = (False, False), - ): + def __init__( + self, + qubit_converter: Optional[QubitConverter] = None, + num_particles: Optional[Tuple[int, int]] = None, + num_spin_orbitals: Optional[int] = None, + reps: int = 1, + initial_state: Optional[QuantumCircuit] = None, + include_singles: Tuple[bool, bool] = (False, False), + ): """ Args: @@ -72,15 +75,17 @@ def __init__(self, qubit_converter: Optional[QubitConverter] = None, """ self._validate_num_particles(num_particles) self._include_singles = include_singles - super().__init__(qubit_converter=qubit_converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - excitations=self.generate_excitations, - alpha_spin=True, - beta_spin=True, - max_spin_excitation=None, - reps=reps, - initial_state=initial_state) + super().__init__( + qubit_converter=qubit_converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + excitations=self.generate_excitations, + alpha_spin=True, + beta_spin=True, + max_spin_excitation=None, + reps=reps, + initial_state=initial_state, + ) @property def include_singles(self) -> Tuple[bool, bool]: @@ -92,9 +97,9 @@ def include_singles(self, include_singles: Tuple[bool, bool]) -> None: """Sets whether to include single excitations.""" self._include_singles = include_singles - def generate_excitations(self, num_spin_orbitals: int, - num_particles: Tuple[int, int] - ) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: + def generate_excitations( + self, num_spin_orbitals: int, num_particles: Tuple[int, int] + ) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: """Generates the excitations for the SUCCD Ansatz. Args: @@ -113,9 +118,15 @@ def generate_excitations(self, num_spin_orbitals: int, self._validate_num_particles(num_particles) excitations: List[Tuple[Tuple[int, ...], Tuple[int, ...]]] = list() - excitations.extend(generate_fermionic_excitations(1, num_spin_orbitals, num_particles, - alpha_spin=self.include_singles[0], - beta_spin=self.include_singles[1])) + excitations.extend( + generate_fermionic_excitations( + 1, + num_spin_orbitals, + num_particles, + alpha_spin=self.include_singles[0], + beta_spin=self.include_singles[1], + ) + ) num_electrons = num_particles[0] beta_index_shift = num_spin_orbitals // 2 @@ -125,7 +136,9 @@ def generate_excitations(self, num_spin_orbitals: int, alpha_unocc = list(range(num_electrons, beta_index_shift)) # the Cartesian product of these lists gives all possible single alpha-spin excitations alpha_excitations = list(itertools.product(alpha_occ, alpha_unocc)) - logger.debug('Generated list of single alpha excitations: %s', alpha_excitations) + logger.debug( + "Generated list of single alpha excitations: %s", alpha_excitations + ) # Find all possible double excitations constructed from the list of single excitations. # Note, that we use `combinations_with_replacement` here, in order to also get those double @@ -137,14 +150,17 @@ def generate_excitations(self, num_spin_orbitals: int, # find the two excitations (Note: SUCCD only works for double excitations!) alpha_exc, second_exc = exc[0], exc[1] # shift the second excitation into the beta-spin orbital index range - beta_exc = (second_exc[0] + beta_index_shift, second_exc[1] + beta_index_shift) + beta_exc = ( + second_exc[0] + beta_index_shift, + second_exc[1] + beta_index_shift, + ) # add the excitation tuple occ: Tuple[int, ...] unocc: Tuple[int, ...] occ, unocc = zip(alpha_exc, beta_exc) exc_tuple = (occ, unocc) excitations.append(exc_tuple) - logger.debug('Added the excitation: %s', exc_tuple) + logger.debug("Added the excitation: %s", exc_tuple) return excitations @@ -153,6 +169,7 @@ def _validate_num_particles(self, num_particles): assert num_particles[0] == num_particles[1] except AssertionError as exc: raise QiskitNatureError( - 'The SUCCD Ansatz only works for singlet-spin systems. However, you specified ' - 'differing numbers of alpha and beta electrons:', str(num_particles) + "The SUCCD Ansatz only works for singlet-spin systems. However, you specified " + "differing numbers of alpha and beta electrons:", + str(num_particles), ) from exc diff --git a/qiskit_nature/circuit/library/ansatzes/ucc.py b/qiskit_nature/circuit/library/ansatzes/ucc.py index 3264699855..700e8a62a1 100644 --- a/qiskit_nature/circuit/library/ansatzes/ucc.py +++ b/qiskit_nature/circuit/library/ansatzes/ucc.py @@ -96,24 +96,34 @@ def custom_excitation_list(num_spin_orbitals: int, """ EXCITATION_TYPE = { - 's': 1, - 'd': 2, - 't': 3, - 'q': 4, + "s": 1, + "d": 2, + "t": 3, + "q": 4, } - def __init__(self, qubit_converter: Optional[QubitConverter] = None, - num_particles: Optional[Tuple[int, int]] = None, - num_spin_orbitals: Optional[int] = None, - excitations: Optional[Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[Tuple[int, ...], Tuple[int, ...]]]] - ]] = None, - alpha_spin: bool = True, - beta_spin: bool = True, - max_spin_excitation: Optional[int] = None, - reps: int = 1, - initial_state: Optional[QuantumCircuit] = None): + def __init__( + self, + qubit_converter: Optional[QubitConverter] = None, + num_particles: Optional[Tuple[int, int]] = None, + num_spin_orbitals: Optional[int] = None, + excitations: Optional[ + Union[ + str, + int, + List[int], + Callable[ + [int, Tuple[int, int]], + List[Tuple[Tuple[int, ...], Tuple[int, ...]]], + ], + ] + ] = None, + alpha_spin: bool = True, + beta_spin: bool = True, + max_spin_excitation: Optional[int] = None, + reps: int = 1, + initial_state: Optional[QuantumCircuit] = None, + ): """ Args: @@ -155,7 +165,9 @@ def __init__(self, qubit_converter: Optional[QubitConverter] = None, self._beta_spin = beta_spin self._max_spin_excitation = max_spin_excitation - super().__init__(reps=reps, evolution=PauliTrotterEvolution(), initial_state=initial_state) + super().__init__( + reps=reps, evolution=PauliTrotterEvolution(), initial_state=initial_state + ) # We cache these, because the generation may be quite expensive (depending on the generator) # and the user may want quick access to inspect these. Also, it speeds up testing for the @@ -213,22 +225,24 @@ def _invalidate(self): def _check_configuration(self, raise_on_failure: bool = True) -> bool: if self.num_spin_orbitals < 0: if raise_on_failure: - raise ValueError('The number of spin orbitals cannot be smaller than 0.') + raise ValueError( + "The number of spin orbitals cannot be smaller than 0." + ) return False if any(n < 0 for n in self.num_particles): if raise_on_failure: - raise ValueError('The number of particles cannot be smaller than 0.') + raise ValueError("The number of particles cannot be smaller than 0.") return False if self.excitations is None: if raise_on_failure: - raise ValueError('The excitations cannot be `None`.') + raise ValueError("The excitations cannot be `None`.") return False if self.qubit_converter is None: if raise_on_failure: - raise ValueError('The qubit_converter cannot be `None`.') + raise ValueError("The qubit_converter cannot be `None`.") return False return True @@ -244,7 +258,7 @@ def _build(self) -> None: # algorithms such as `AdaptVQE`. excitation_ops = self.excitation_ops() - logger.debug('Converting SecondQuantizedOps into PauliSumOps...') + logger.debug("Converting SecondQuantizedOps into PauliSumOps...") # Convert operators according to saved state in converter from the conversion of the # main operator since these need to be compatible. If Z2 Symmetry tapering was done # it may be that one or more excitation operators do not commute with the @@ -252,9 +266,11 @@ def _build(self) -> None: # the converter inserting None as the result if an operator did not commute. Here # we are not interested in that just getting the valid set of operators so that # behavior is suppressed. - self.operators = self.qubit_converter.convert_match(excitation_ops, suppress_none=True) + self.operators = self.qubit_converter.convert_match( + excitation_ops, suppress_none=True + ) - logger.debug('Building QuantumCircuit...') + logger.debug("Building QuantumCircuit...") super()._build() def excitation_ops(self) -> List[SecondQuantizedOp]: @@ -271,7 +287,7 @@ def excitation_ops(self) -> List[SecondQuantizedOp]: excitations = self._get_excitation_list() - logger.debug('Converting excitations into SecondQuantizedOps...') + logger.debug("Converting excitations into SecondQuantizedOps...") excitation_ops = self._build_fermionic_excitation_ops(excitations) self._excitation_ops = excitation_ops @@ -280,52 +296,66 @@ def excitation_ops(self) -> List[SecondQuantizedOp]: def _get_excitation_list(self) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: generators = self._get_excitation_generators() - logger.debug('Generating excitation list...') + logger.debug("Generating excitation list...") excitations = [] for gen in generators: - excitations.extend(gen( - num_spin_orbitals=self.num_spin_orbitals, - num_particles=self.num_particles - )) + excitations.extend( + gen( + num_spin_orbitals=self.num_spin_orbitals, + num_particles=self.num_particles, + ) + ) return excitations def _get_excitation_generators(self) -> List[Callable]: - logger.debug('Gathering excitation generators...') + logger.debug("Gathering excitation generators...") generators: List[Callable] = [] - extra_kwargs = {'alpha_spin': self._alpha_spin, - 'beta_spin': self._beta_spin, - 'max_spin_excitation': self._max_spin_excitation} + extra_kwargs = { + "alpha_spin": self._alpha_spin, + "beta_spin": self._beta_spin, + "max_spin_excitation": self._max_spin_excitation, + } if isinstance(self.excitations, str): for exc in self.excitations: - generators.append(partial( + generators.append( + partial( + generate_fermionic_excitations, + num_excitations=self.EXCITATION_TYPE[exc], + **extra_kwargs + ) + ) + elif isinstance(self.excitations, int): + generators.append( + partial( generate_fermionic_excitations, - num_excitations=self.EXCITATION_TYPE[exc], + num_excitations=self.excitations, **extra_kwargs - )) - elif isinstance(self.excitations, int): - generators.append(partial( - generate_fermionic_excitations, - num_excitations=self.excitations, - **extra_kwargs - )) + ) + ) elif isinstance(self.excitations, list): for exc in self.excitations: # type: ignore - generators.append(partial( - generate_fermionic_excitations, - num_excitations=exc, - **extra_kwargs - )) + generators.append( + partial( + generate_fermionic_excitations, + num_excitations=exc, + **extra_kwargs + ) + ) elif callable(self.excitations): generators = [self.excitations] else: - raise QiskitNatureError("Invalid excitation configuration: {}".format(self.excitations)) + raise QiskitNatureError( + "Invalid excitation configuration: {}".format(self.excitations) + ) return generators - def _build_fermionic_excitation_ops(self, excitations: Sequence) -> List[FermionicOp]: + def _build_fermionic_excitation_ops( + self, excitations: Sequence + ) -> List[FermionicOp]: """Builds all possible excitation operators with the given number of excitations for the specified number of particles distributed in the number of orbitals. @@ -338,12 +368,12 @@ def _build_fermionic_excitation_ops(self, excitations: Sequence) -> List[Fermion operators = [] for exc in excitations: - label = ['I'] * self.num_spin_orbitals + label = ["I"] * self.num_spin_orbitals for occ in exc[0]: - label[occ] = '+' + label[occ] = "+" for unocc in exc[1]: - label[unocc] = '-' - op = FermionicOp(''.join(label)) + label[unocc] = "-" + op = FermionicOp("".join(label)) op -= op.adjoint() # we need to account for an additional imaginary phase in the exponent (see also # `PauliTrotterEvolution.convert`) diff --git a/qiskit_nature/circuit/library/ansatzes/uccsd.py b/qiskit_nature/circuit/library/ansatzes/uccsd.py index 31b8cf4af1..40b04a724b 100644 --- a/qiskit_nature/circuit/library/ansatzes/uccsd.py +++ b/qiskit_nature/circuit/library/ansatzes/uccsd.py @@ -30,11 +30,14 @@ class UCCSD(UCC): This is a convenience subclass of the UCC Ansatz. For more information refer to :class:`UCC`. """ - def __init__(self, qubit_converter: Optional[QubitConverter] = None, - num_particles: Optional[Tuple[int, int]] = None, - num_spin_orbitals: Optional[int] = None, - reps: int = 1, - initial_state: Optional[QuantumCircuit] = None): + def __init__( + self, + qubit_converter: Optional[QubitConverter] = None, + num_particles: Optional[Tuple[int, int]] = None, + num_spin_orbitals: Optional[int] = None, + reps: int = 1, + initial_state: Optional[QuantumCircuit] = None, + ): """ Args: qubit_converter: the QubitConverter instance which takes care of mapping a @@ -45,12 +48,14 @@ def __init__(self, qubit_converter: Optional[QubitConverter] = None, reps: The number of times to repeat the evolved operators. initial_state: A `QuantumCircuit` object to prepend to the circuit. """ - super().__init__(qubit_converter=qubit_converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - excitations='sd', - alpha_spin=True, - beta_spin=True, - max_spin_excitation=None, - reps=reps, - initial_state=initial_state) + super().__init__( + qubit_converter=qubit_converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + excitations="sd", + alpha_spin=True, + beta_spin=True, + max_spin_excitation=None, + reps=reps, + initial_state=initial_state, + ) diff --git a/qiskit_nature/circuit/library/ansatzes/utils/__init__.py b/qiskit_nature/circuit/library/ansatzes/utils/__init__.py index 6c6c1a8232..6e7252fdfc 100644 --- a/qiskit_nature/circuit/library/ansatzes/utils/__init__.py +++ b/qiskit_nature/circuit/library/ansatzes/utils/__init__.py @@ -26,6 +26,6 @@ from .vibration_excitation_generator import generate_vibration_excitations __all__ = [ - 'generate_fermionic_excitations', - 'generate_vibration_excitations', + "generate_fermionic_excitations", + "generate_vibration_excitations", ] diff --git a/qiskit_nature/circuit/library/ansatzes/utils/fermionic_excitation_generator.py b/qiskit_nature/circuit/library/ansatzes/utils/fermionic_excitation_generator.py index 5bc61517e6..dfce13be32 100644 --- a/qiskit_nature/circuit/library/ansatzes/utils/fermionic_excitation_generator.py +++ b/qiskit_nature/circuit/library/ansatzes/utils/fermionic_excitation_generator.py @@ -29,13 +29,14 @@ logger = logging.getLogger(__name__) -def generate_fermionic_excitations(num_excitations: int, - num_spin_orbitals: int, - num_particles: Tuple[int, int], - alpha_spin: bool = True, - beta_spin: bool = True, - max_spin_excitation: Optional[int] = None, - ) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: +def generate_fermionic_excitations( + num_excitations: int, + num_spin_orbitals: int, + num_particles: Tuple[int, int], + alpha_spin: bool = True, + beta_spin: bool = True, + max_spin_excitation: Optional[int] = None, +) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: """Generates all possible excitations with the given number of excitations for the specified number of particles distributed among the given number of spin orbitals. @@ -64,17 +65,22 @@ def generate_fermionic_excitations(num_excitations: int, alpha_unocc = list(range(num_particles[0], num_spin_orbitals // 2)) # the Cartesian product of these lists gives all possible single alpha-spin excitations alpha_excitations = list(itertools.product(alpha_occ, alpha_unocc)) - logger.debug('Generated list of single alpha excitations: %s', alpha_excitations) + logger.debug( + "Generated list of single alpha excitations: %s", alpha_excitations + ) beta_excitations: List[Tuple[int, int]] = [] if beta_spin: # generate beta-spin orbital indices for occupied and unoccupied ones - beta_occ = list(range(num_spin_orbitals // 2, - num_spin_orbitals // 2 + num_particles[1])) - beta_unocc = list(range(num_spin_orbitals // 2 + num_particles[1], num_spin_orbitals)) + beta_occ = list( + range(num_spin_orbitals // 2, num_spin_orbitals // 2 + num_particles[1]) + ) + beta_unocc = list( + range(num_spin_orbitals // 2 + num_particles[1], num_spin_orbitals) + ) # the Cartesian product of these lists gives all possible single beta-spin excitations beta_excitations = list(itertools.product(beta_occ, beta_unocc)) - logger.debug('Generated list of single beta excitations: %s', beta_excitations) + logger.debug("Generated list of single beta excitations: %s", beta_excitations) if not alpha_excitations and not beta_excitations: # nothing to do, let's return early @@ -89,22 +95,22 @@ def generate_fermionic_excitations(num_excitations: int, # if max_spin_excitation is set, we need to filter the pool of excitations if max_spin_excitation is not None: - logger.info('The maximum number of excitations within each spin species was set to %s', - max_spin_excitation) + logger.info( + "The maximum number of excitations within each spin species was set to %s", + max_spin_excitation, + ) # first, remove all those excitations, in which more than max_spin_excitation alpha # excitations are performed at ones if alpha_excitations: # False if empty list alpha_exc_set = set(alpha_excitations) pool = itertools.filterfalse( - lambda exc: len(set(exc) & alpha_exc_set) > max_spin_excitation, - pool + lambda exc: len(set(exc) & alpha_exc_set) > max_spin_excitation, pool ) # then, do the same for beta if beta_excitations: # False if empty list beta_exc_set = set(beta_excitations) pool = itertools.filterfalse( - lambda exc: len(set(exc) & beta_exc_set) > max_spin_excitation, - pool + lambda exc: len(set(exc) & beta_exc_set) > max_spin_excitation, pool ) excitations: List[Tuple[Tuple[int, ...], Tuple[int, ...]]] = list() @@ -123,6 +129,6 @@ def generate_fermionic_excitations(num_excitations: int, occ, unocc = zip(*exc) exc_tuple = (occ, unocc) excitations.append(exc_tuple) - logger.debug('Added the excitation: %s', exc_tuple) + logger.debug("Added the excitation: %s", exc_tuple) return excitations diff --git a/qiskit_nature/circuit/library/ansatzes/utils/vibration_excitation_generator.py b/qiskit_nature/circuit/library/ansatzes/utils/vibration_excitation_generator.py index 20bd882cce..8c54548507 100644 --- a/qiskit_nature/circuit/library/ansatzes/utils/vibration_excitation_generator.py +++ b/qiskit_nature/circuit/library/ansatzes/utils/vibration_excitation_generator.py @@ -24,9 +24,10 @@ logger = logging.getLogger(__name__) -def generate_vibration_excitations(num_excitations: int, - num_modals: List[int], - ) -> List[Tuple[Tuple[Any, ...], ...]]: +def generate_vibration_excitations( + num_excitations: int, + num_modals: List[int], +) -> List[Tuple[Tuple[Any, ...], ...]]: """Generates all possible excitations with the given number of excitations for the specified number of particles distributed among the given number of spin orbitals. @@ -49,14 +50,14 @@ def generate_vibration_excitations(num_excitations: int, for accumulated_sum in partial_sum_modals: # the unoccupied modals in each mode are all modals but the lowest one: - unoccupied = list(range(idx_sum+1, accumulated_sum)) + unoccupied = list(range(idx_sum + 1, accumulated_sum)) # the single excitations for this mode are therefore simply each entry in this list, when # excited into it from the lowest modal of this list: single_excitations.extend([(idx_sum, m) for m in unoccupied]) # and now we update the running index of the lowest modal for the next mode idx_sum = accumulated_sum - logger.debug('Generated list of single excitations: %s', single_excitations) + logger.debug("Generated list of single excitations: %s", single_excitations) # we can find the actual list of excitations by doing the following: # 1. combine the single alpha- and beta-spin excitations @@ -76,6 +77,6 @@ def generate_vibration_excitations(num_excitations: int, visited_excitations.add(exc_set) exc_tuple = tuple(zip(*exc)) excitations.append(exc_tuple) - logger.debug('Added the excitation: %s', exc_tuple) + logger.debug("Added the excitation: %s", exc_tuple) return excitations diff --git a/qiskit_nature/circuit/library/ansatzes/uvcc.py b/qiskit_nature/circuit/library/ansatzes/uvcc.py index 542093302b..5e0afe4245 100644 --- a/qiskit_nature/circuit/library/ansatzes/uvcc.py +++ b/qiskit_nature/circuit/library/ansatzes/uvcc.py @@ -36,21 +36,30 @@ class UVCC(EvolvedOperatorAnsatz): """ EXCITATION_TYPE = { - 's': 1, - 'd': 2, - 't': 3, - 'q': 4, + "s": 1, + "d": 2, + "t": 3, + "q": 4, } - def __init__(self, - qubit_converter: Optional[QubitConverter] = None, - num_modals: Optional[List[int]] = None, - excitations: Optional[Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[Tuple[int, ...], Tuple[int, ...]]]] - ]] = None, - reps: int = 1, - initial_state: Optional[QuantumCircuit] = None): + def __init__( + self, + qubit_converter: Optional[QubitConverter] = None, + num_modals: Optional[List[int]] = None, + excitations: Optional[ + Union[ + str, + int, + List[int], + Callable[ + [int, Tuple[int, int]], + List[Tuple[Tuple[int, ...], Tuple[int, ...]]], + ], + ] + ] = None, + reps: int = 1, + initial_state: Optional[QuantumCircuit] = None, + ): """ Args: @@ -82,7 +91,9 @@ def __init__(self, self._num_modals = num_modals self._excitations = excitations - super().__init__(reps=reps, evolution=PauliTrotterEvolution(), initial_state=initial_state) + super().__init__( + reps=reps, evolution=PauliTrotterEvolution(), initial_state=initial_state + ) # We cache these, because the generation may be quite expensive (depending on the generator) # and the user may want quick access to inspect these. Also, it speeds up testing for the @@ -129,18 +140,20 @@ def _invalidate(self): def _check_configuration(self, raise_on_failure: bool = True) -> bool: if self.num_modals is None or any(b < 0 for b in self.num_modals): if raise_on_failure: - raise ValueError('The number of modals cannot contain negative values but is ', - self.num_modals) + raise ValueError( + "The number of modals cannot contain negative values but is ", + self.num_modals, + ) return False if self.excitations is None: if raise_on_failure: - raise ValueError('The excitations cannot be `None`.') + raise ValueError("The excitations cannot be `None`.") return False if self.qubit_converter is None: if raise_on_failure: - raise ValueError('The qubit_converter cannot be `None`.') + raise ValueError("The qubit_converter cannot be `None`.") return False return True @@ -152,10 +165,12 @@ def _build(self) -> None: if self.operators is None or self.operators == [None]: excitation_ops = self.excitation_ops() - logger.debug('Converting SecondQuantizedOps into PauliSumOps...') - self.operators = self.qubit_converter.convert_match(excitation_ops, suppress_none=True) + logger.debug("Converting SecondQuantizedOps into PauliSumOps...") + self.operators = self.qubit_converter.convert_match( + excitation_ops, suppress_none=True + ) - logger.debug('Building QuantumCircuit...') + logger.debug("Building QuantumCircuit...") super()._build() def excitation_ops(self) -> List[SecondQuantizedOp]: @@ -172,7 +187,7 @@ def excitation_ops(self) -> List[SecondQuantizedOp]: excitations = self._get_excitation_list() - logger.debug('Converting excitations into SecondQuantizedOps...') + logger.debug("Converting excitations into SecondQuantizedOps...") excitation_ops = self._build_vibration_excitation_ops(excitations) self._excitation_ops = excitation_ops @@ -181,44 +196,56 @@ def excitation_ops(self) -> List[SecondQuantizedOp]: def _get_excitation_list(self) -> List[Tuple[Tuple[int, ...], Tuple[int, ...]]]: generators = self._get_excitation_generators() - logger.debug('Generating excitation list...') + logger.debug("Generating excitation list...") excitations = [] for gen in generators: - excitations.extend(gen( - num_modals=self.num_modals, - )) + excitations.extend( + gen( + num_modals=self.num_modals, + ) + ) return excitations def _get_excitation_generators(self) -> List[Callable]: - logger.debug('Gathering excitation generators...') + logger.debug("Gathering excitation generators...") generators: List[Callable] = [] if isinstance(self.excitations, str): for exc in self.excitations: - generators.append(partial( - generate_vibration_excitations, - num_excitations=self.EXCITATION_TYPE[exc], - )) + generators.append( + partial( + generate_vibration_excitations, + num_excitations=self.EXCITATION_TYPE[exc], + ) + ) elif isinstance(self.excitations, int): - generators.append(partial( - generate_vibration_excitations, - num_excitations=self.excitations, - )) + generators.append( + partial( + generate_vibration_excitations, + num_excitations=self.excitations, + ) + ) elif isinstance(self.excitations, list): for exc in self.excitations: # type: ignore - generators.append(partial( - generate_vibration_excitations, - num_excitations=exc, - )) + generators.append( + partial( + generate_vibration_excitations, + num_excitations=exc, + ) + ) elif callable(self.excitations): generators = [self.excitations] else: - raise QiskitNatureError("Invalid excitation configuration: {}".format(self.excitations)) + raise QiskitNatureError( + "Invalid excitation configuration: {}".format(self.excitations) + ) return generators - def _build_vibration_excitation_ops(self, excitations: Sequence) -> List[VibrationalOp]: + def _build_vibration_excitation_ops( + self, excitations: Sequence + ) -> List[VibrationalOp]: """Builds all possible excitation operators with the given number of excitations for the specified number of particles distributed in the number of orbitals. @@ -233,12 +260,12 @@ def _build_vibration_excitation_ops(self, excitations: Sequence) -> List[Vibrati sum_modes = sum(self.num_modals) for exc in excitations: - label = ['I'] * sum_modes + label = ["I"] * sum_modes for occ in exc[0]: - label[occ] = '+' + label[occ] = "+" for unocc in exc[1]: - label[unocc] = '-' - op = VibrationalOp(''.join(label), len(self.num_modals), self.num_modals) + label[unocc] = "-" + op = VibrationalOp("".join(label), len(self.num_modals), self.num_modals) op -= op.adjoint() # we need to account for an additional imaginary phase in the exponent (see also # `PauliTrotterEvolution.convert`) diff --git a/qiskit_nature/circuit/library/ansatzes/uvccsd.py b/qiskit_nature/circuit/library/ansatzes/uvccsd.py index 08bb2fbfa2..710b69d992 100644 --- a/qiskit_nature/circuit/library/ansatzes/uvccsd.py +++ b/qiskit_nature/circuit/library/ansatzes/uvccsd.py @@ -30,10 +30,13 @@ class UVCCSD(UVCC): This is a convenience subclass of the UVCC Ansatz. For more information refer to :class:`UVCC`. """ - def __init__(self, qubit_converter: Optional[QubitConverter] = None, - num_modals: Optional[List[int]] = None, - reps: int = 1, - initial_state: Optional[QuantumCircuit] = None): + def __init__( + self, + qubit_converter: Optional[QubitConverter] = None, + num_modals: Optional[List[int]] = None, + reps: int = 1, + initial_state: Optional[QuantumCircuit] = None, + ): """ Args: qubit_converter: the QubitConverter instance which takes care of mapping a @@ -44,8 +47,10 @@ def __init__(self, qubit_converter: Optional[QubitConverter] = None, reps: The number of times to repeat the evolved operators. initial_state: A `QuantumCircuit` object to prepend to the circuit. """ - super().__init__(qubit_converter=qubit_converter, - num_modals=num_modals, - excitations='sd', - reps=reps, - initial_state=initial_state) + super().__init__( + qubit_converter=qubit_converter, + num_modals=num_modals, + excitations="sd", + reps=reps, + initial_state=initial_state, + ) diff --git a/qiskit_nature/circuit/library/initial_states/__init__.py b/qiskit_nature/circuit/library/initial_states/__init__.py index 3dfdf547de..d3ddd95da0 100644 --- a/qiskit_nature/circuit/library/initial_states/__init__.py +++ b/qiskit_nature/circuit/library/initial_states/__init__.py @@ -29,4 +29,4 @@ from .hartree_fock import HartreeFock from .vscf import VSCF -__all__ = ['HartreeFock', 'VSCF'] +__all__ = ["HartreeFock", "VSCF"] diff --git a/qiskit_nature/circuit/library/initial_states/hartree_fock.py b/qiskit_nature/circuit/library/initial_states/hartree_fock.py index 5630d0f14a..60d5b9ba48 100644 --- a/qiskit_nature/circuit/library/initial_states/hartree_fock.py +++ b/qiskit_nature/circuit/library/initial_states/hartree_fock.py @@ -27,10 +27,12 @@ class HartreeFock(QuantumCircuit): """A Hartree-Fock initial state.""" - def __init__(self, - num_spin_orbitals: int, - num_particles: Tuple[int, int], - qubit_converter: QubitConverter) -> None: + def __init__( + self, + num_spin_orbitals: int, + num_particles: Tuple[int, int], + qubit_converter: QubitConverter, + ) -> None: """ Args: num_spin_orbitals: The number of spin orbitals, has a min. value of 1. @@ -43,15 +45,15 @@ def __init__(self, bitstr = hartree_fock_bitstring(num_spin_orbitals, num_particles) # encode the bitstring as a `FermionicOp` - label = ['+' if bit else 'I' for bit in bitstr] - bitstr_op = FermionicOp(''.join(label)) + label = ["+" if bit else "I" for bit in bitstr] + bitstr_op = FermionicOp("".join(label)) # map the `FermionicOp` to a qubit operator qubit_op: PauliSumOp = qubit_converter.convert_match(bitstr_op) # construct the circuit - qr = QuantumRegister(qubit_op.num_qubits, 'q') - super().__init__(qr, name='HF') + qr = QuantumRegister(qubit_op.num_qubits, "q") + super().__init__(qr, name="HF") # Add gates in the right positions: we are only interested in the `X` gates because we want # to create particles (0 -> 1) where the initial state introduced a creation (`+`) operator. @@ -60,8 +62,9 @@ def __init__(self, self.x(i) -def hartree_fock_bitstring(num_spin_orbitals: int, - num_particles: Tuple[int, int]) -> List[bool]: +def hartree_fock_bitstring( + num_spin_orbitals: int, num_particles: Tuple[int, int] +) -> List[bool]: """Compute the bitstring representing the Hartree-Fock state for the specified system. Args: @@ -76,15 +79,15 @@ def hartree_fock_bitstring(num_spin_orbitals: int, ValueError: If the total number of particles is larger than the number of orbitals. """ # validate the input - validate_min('num_spin_orbitals', num_spin_orbitals, 1) + validate_min("num_spin_orbitals", num_spin_orbitals, 1) num_alpha, num_beta = num_particles if sum(num_particles) > num_spin_orbitals: - raise ValueError('# of particles must be less than or equal to # of orbitals.') + raise ValueError("# of particles must be less than or equal to # of orbitals.") half_orbitals = num_spin_orbitals // 2 bitstr = np.zeros(num_spin_orbitals, bool) bitstr[:num_alpha] = True - bitstr[half_orbitals:(half_orbitals + num_beta)] = True + bitstr[half_orbitals : (half_orbitals + num_beta)] = True return bitstr.tolist() diff --git a/qiskit_nature/circuit/library/initial_states/vscf.py b/qiskit_nature/circuit/library/initial_states/vscf.py index c40a6e6dfb..3d401ad2c9 100644 --- a/qiskit_nature/circuit/library/initial_states/vscf.py +++ b/qiskit_nature/circuit/library/initial_states/vscf.py @@ -38,10 +38,11 @@ class VSCF(QuantumCircuit): [1] Ollitrault Pauline J., Chemical science 11 (2020): 6842-6855. """ - def __init__(self, - num_modals: List[int], - qubit_converter: Optional[QubitConverter] = None, - ) -> None: + def __init__( + self, + num_modals: List[int], + qubit_converter: Optional[QubitConverter] = None, + ) -> None: """ Args: num_modals: Is a list defining the number of modals per mode. E.g. for a 3 modes system @@ -55,22 +56,25 @@ def __init__(self, bitstr = vscf_bitstring(num_modals) # encode the bitstring in a `VibrationalOp` - label = ['+' if bit else 'I' for bit in bitstr] - bitstr_op = VibrationalOp(''.join(label), num_modes=len(num_modals), num_modals=num_modals) + label = ["+" if bit else "I" for bit in bitstr] + bitstr_op = VibrationalOp( + "".join(label), num_modes=len(num_modals), num_modals=num_modals + ) # map the `VibrationalOp` to a qubit operator if qubit_converter is not None: logger.warning( - 'The only supported `QubitConverter` is one with a `DirectMapper` as the mapper ' - 'instance. However you specified %s as an input, which will be ignored until more ' - 'variants will be supported.', str(qubit_converter) + "The only supported `QubitConverter` is one with a `DirectMapper` as the mapper " + "instance. However you specified %s as an input, which will be ignored until more " + "variants will be supported.", + str(qubit_converter), ) qubit_converter = QubitConverter(DirectMapper()) qubit_op: PauliSumOp = qubit_converter.convert_match(bitstr_op) # construct the circuit - qr = QuantumRegister(qubit_op.num_qubits, 'q') - super().__init__(qr, name='VSCF') + qr = QuantumRegister(qubit_op.num_qubits, "q") + super().__init__(qr, name="VSCF") # add gates in the right positions for i, bit in enumerate(qubit_op.primitive.table.X[0]): diff --git a/qiskit_nature/constants.py b/qiskit_nature/constants.py index 5064f62519..2b3be511a7 100644 --- a/qiskit_nature/constants.py +++ b/qiskit_nature/constants.py @@ -15,9 +15,9 @@ """ # multiplicative conversions -N_A = 6.02214129E23 # particles per mol +N_A = 6.02214129e23 # particles per mol -KCAL_PER_MOL_TO_J_PER_MOLECULE = 6.947695E-21 +KCAL_PER_MOL_TO_J_PER_MOLECULE = 6.947695e-21 HARTREE_TO_KCAL_PER_MOL = 627.509474 HARTREE_TO_J_PER_MOL = 2625499.63922 HARTREE_TO_KJ_PER_MOL = 2625.49963922 @@ -25,14 +25,14 @@ J_PER_MOL_TO_PER_CM = 0.08359347178 CAL_TO_J = 4.184 HARTREE_TO_J = 4.3597443380807824e-18 # HARTREE_TO_J_PER_MOL / N_A -J_TO_HARTREE = 2.293712480489655e+17 # 1.0 / HARTREE_TO_J -M_TO_ANGSTROM = 1E10 -ANGSTROM_TO_M = 1E-10 +J_TO_HARTREE = 2.293712480489655e17 # 1.0 / HARTREE_TO_J +M_TO_ANGSTROM = 1e10 +ANGSTROM_TO_M = 1e-10 # physical constants -C_CM_PER_S = 2.9979245800E10 -C_M_PER_S = 2.9979245800E8 -HBAR_J_S = 1.054571800E-34 # note this is h/2Pi -H_J_S = 6.62607015E-34 -KB_J_PER_K = 1.3806488E-23 +C_CM_PER_S = 2.9979245800e10 +C_M_PER_S = 2.9979245800e8 +HBAR_J_S = 1.054571800e-34 # note this is h/2Pi +H_J_S = 6.62607015e-34 +KB_J_PER_K = 1.3806488e-23 diff --git a/qiskit_nature/converters/second_quantization/__init__.py b/qiskit_nature/converters/second_quantization/__init__.py index 7641e2d24e..a3b361eb11 100644 --- a/qiskit_nature/converters/second_quantization/__init__.py +++ b/qiskit_nature/converters/second_quantization/__init__.py @@ -31,5 +31,5 @@ from .qubit_converter import QubitConverter __all__ = [ - 'QubitConverter', + "QubitConverter", ] diff --git a/qiskit_nature/converters/second_quantization/qubit_converter.py b/qiskit_nature/converters/second_quantization/qubit_converter.py index d4d5927ceb..a98d70b059 100644 --- a/qiskit_nature/converters/second_quantization/qubit_converter.py +++ b/qiskit_nature/converters/second_quantization/qubit_converter.py @@ -49,10 +49,12 @@ class QubitConverter: be passed in on :meth:`convert` which will override this value should both be given. """ - def __init__(self, - mapper: QubitMapper, - two_qubit_reduction: bool = False, - z2symmetry_reduction: Optional[Union[str, List[int]]] = None): + def __init__( + self, + mapper: QubitMapper, + two_qubit_reduction: bool = False, + z2symmetry_reduction: Optional[Union[str, List[int]]] = None, + ): """ Args: @@ -111,17 +113,24 @@ def z2symmetry_reduction(self) -> Optional[Union[str, List[int]]]: return self._z2symmetry_reduction @z2symmetry_reduction.setter - def z2symmetry_reduction(self, z2symmetry_reduction: Optional[Union[str, List[int]]]) -> None: + def z2symmetry_reduction( + self, z2symmetry_reduction: Optional[Union[str, List[int]]] + ) -> None: """Set z2symmetry_reduction""" if z2symmetry_reduction is not None: if isinstance(z2symmetry_reduction, str): - if z2symmetry_reduction != 'auto': - raise ValueError("The only string-like option for z2symmetry_reduction is " - "'auto', not {}".format(z2symmetry_reduction)) + if z2symmetry_reduction != "auto": + raise ValueError( + "The only string-like option for z2symmetry_reduction is " + "'auto', not {}".format(z2symmetry_reduction) + ) elif not np.all(np.isin(z2symmetry_reduction, [-1, 1])): - raise ValueError('z2symmetry_reduction tapering values list must ' - 'contain -1\'s and/or 1\'s only but was {}'. - format(z2symmetry_reduction)) + raise ValueError( + "z2symmetry_reduction tapering values list must " + "contain -1's and/or 1's only but was {}".format( + z2symmetry_reduction + ) + ) self._z2symmetry_reduction = z2symmetry_reduction @@ -143,10 +152,12 @@ def z2symmetries(self) -> Z2Symmetries: """ return copy.deepcopy(self._z2symmetries) - def convert(self, second_q_op: SecondQuantizedOp, - num_particles: Optional[Tuple[int, int]] = None, - sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None - ) -> PauliSumOp: + def convert( + self, + second_q_op: SecondQuantizedOp, + num_particles: Optional[Tuple[int, int]] = None, + sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None, + ) -> PauliSumOp: """ Map the given second quantized operator to a qubit operators. Also it will carry out z2 symmetry reduction on the qubit operators if z2symmetry_reduction has @@ -174,19 +185,22 @@ def convert(self, second_q_op: SecondQuantizedOp, return tapered_op - def force_match(self, num_particles: Optional[Tuple[int, int]] = None, - z2symmetries: Optional[Z2Symmetries] = None) -> None: - """ This is for advanced use where :meth:`convert` may not have been called or the - converter should be used to taper to some external characteristics to be matched - when using :meth:`convert_match`. Parameters passed here, when not None, - will override any values stored from :meth:`convert`. + def force_match( + self, + num_particles: Optional[Tuple[int, int]] = None, + z2symmetries: Optional[Z2Symmetries] = None, + ) -> None: + """This is for advanced use where :meth:`convert` may not have been called or the + converter should be used to taper to some external characteristics to be matched + when using :meth:`convert_match`. Parameters passed here, when not None, + will override any values stored from :meth:`convert`. - Args: - num_particles: The number or particles pertaining to two qubit reduction - z2symmetries: Z2Symmetry information for tapering + Args: + num_particles: The number or particles pertaining to two qubit reduction + z2symmetries: Z2Symmetry information for tapering - Raises: - ValueError: If format of Z2Symmetry tapering values is invalid + Raises: + ValueError: If format of Z2Symmetry tapering values is invalid """ if num_particles is not None: self._num_particles = num_particles @@ -194,19 +208,25 @@ def force_match(self, num_particles: Optional[Tuple[int, int]] = None, if z2symmetries is not None: if not z2symmetries.is_empty(): if len(z2symmetries.tapering_values) != len(z2symmetries.sq_list): - raise ValueError(f'Z2Symmetries tapering value length was ' - f'{len(z2symmetries.tapering_values)} but expected ' - f'{len(z2symmetries.sq_list)}.') + raise ValueError( + f"Z2Symmetries tapering value length was " + f"{len(z2symmetries.tapering_values)} but expected " + f"{len(z2symmetries.sq_list)}." + ) if not np.all(np.isin(z2symmetries.tapering_values, [-1, 1])): - raise ValueError(f'Z2Symmetries values list must contain only ' - f'-1\'s and/or 1\'s but was {z2symmetries.tapering_values}.') + raise ValueError( + f"Z2Symmetries values list must contain only " + f"-1's and/or 1's but was {z2symmetries.tapering_values}." + ) self._z2symmetries = z2symmetries - def convert_match(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]], - suppress_none: bool = False - ) -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: - """ Convert further operators to match that done in :meth:`convert`, or as set by + def convert_match( + self, + second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]], + suppress_none: bool = False, + ) -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: + """Convert further operators to match that done in :meth:`convert`, or as set by :meth:`force_match`. Args: @@ -232,8 +252,10 @@ def convert_match(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuanti suppress_none = False # When only a single op we will return None back qubit_ops = [self._map(second_q_op) for second_q_op in second_q_ops] - reduced_ops = [self._two_qubit_reduce(qubit_op, self._num_particles) - for qubit_op in qubit_ops] + reduced_ops = [ + self._two_qubit_reduce(qubit_op, self._num_particles) + for qubit_op in qubit_ops + ] tapered_ops = self._symmetry_reduce(reduced_ops, suppress_none) if wrapped: @@ -241,9 +263,10 @@ def convert_match(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuanti return tapered_ops - def map(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]]) \ - -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: - """ A convenience method to map second quantized operators based on current mapper. + def map( + self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]] + ) -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: + """A convenience method to map second quantized operators based on current mapper. Args: second_q_ops: A second quantized operator, or list thereof @@ -262,8 +285,9 @@ def map(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]]) \ def _map(self, second_q_op: SecondQuantizedOp) -> PauliSumOp: return self._mapper.map(second_q_op) - def _two_qubit_reduce(self, qubit_op: PauliSumOp, - num_particles: Optional[Tuple[int, int]]) -> PauliSumOp: + def _two_qubit_reduce( + self, qubit_op: PauliSumOp, num_particles: Optional[Tuple[int, int]] + ) -> PauliSumOp: reduced_op = qubit_op if num_particles is not None: @@ -273,10 +297,11 @@ def _two_qubit_reduce(self, qubit_op: PauliSumOp, return reduced_op - def _find_taper_op(self, qubit_op: PauliSumOp, - sector_locator: Optional[Callable[[Z2Symmetries], - Optional[List[int]]]] = None - ) -> Tuple[PauliSumOp, Z2Symmetries]: + def _find_taper_op( + self, + qubit_op: PauliSumOp, + sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None, + ) -> Tuple[PauliSumOp, Z2Symmetries]: # Return operator unchanged and empty symmetries if we do not taper tapered_qubit_op = qubit_op z2_symmetries = self._no_symmetries @@ -285,14 +310,16 @@ def _find_taper_op(self, qubit_op: PauliSumOp, if self.z2symmetry_reduction is not None: z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) if z2_symmetries.is_empty(): - logger.debug('No Z2 symmetries found') + logger.debug("No Z2 symmetries found") else: # As we have symmetries, if we have a sector locator, if that provides one back # it will override any value defined on constructor - if sector_locator is not None and self.z2symmetry_reduction == 'auto': + if sector_locator is not None and self.z2symmetry_reduction == "auto": z2symmetry_reduction = sector_locator(z2_symmetries) if z2symmetry_reduction is not None: - self.z2symmetry_reduction = z2symmetry_reduction # Overrides any value + self.z2symmetry_reduction = ( + z2symmetry_reduction # Overrides any value + ) # We may end up that neither were we given a sector nor that the locator # returned one. Since though we may have found valid symmetries above we should @@ -301,36 +328,44 @@ def _find_taper_op(self, qubit_op: PauliSumOp, z2_symmetries = self._no_symmetries # So now if we have a sector and have symmetries we found we can attempt to taper - if self.z2symmetry_reduction is not None and self.z2symmetry_reduction != 'auto' \ - and not z2_symmetries.is_empty(): + if ( + self.z2symmetry_reduction is not None + and self.z2symmetry_reduction != "auto" + and not z2_symmetries.is_empty() + ): # check sector definition fits to symmetries found if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): - raise QiskitNatureError('z2symmetry_reduction tapering values list has ' - 'invalid length {} should be {}'. - format(len(self._z2symmetry_reduction), - len(z2_symmetries.symmetries))) + raise QiskitNatureError( + "z2symmetry_reduction tapering values list has " + "invalid length {} should be {}".format( + len(self._z2symmetry_reduction), len(z2_symmetries.symmetries) + ) + ) # Check all operators commute with main operator's symmetry - logger.debug('Sanity check that operator commutes with the symmetry') + logger.debug("Sanity check that operator commutes with the symmetry") symmetry_ops = [] for symmetry in z2_symmetries.symmetries: symmetry_ops.append(PauliSumOp.from_list([(symmetry.to_label(), 1.0)])) commutes = QubitConverter._check_commutes(symmetry_ops, qubit_op) if not commutes: - raise QiskitNatureError('Z2 symmetry failure. The operator must commute ' - 'with symmetries found from it!') + raise QiskitNatureError( + "Z2 symmetry failure. The operator must commute " + "with symmetries found from it!" + ) z2_symmetries.tapering_values = self._z2symmetry_reduction tapered_qubit_op = z2_symmetries.taper(qubit_op) if commutes else None return tapered_qubit_op, z2_symmetries - def _symmetry_reduce(self, qubit_ops: List[PauliSumOp], - suppress_none: bool) -> List[Optional[PauliSumOp]]: + def _symmetry_reduce( + self, qubit_ops: List[PauliSumOp], suppress_none: bool + ) -> List[Optional[PauliSumOp]]: if self._z2symmetries is None or self._z2symmetries.is_empty(): tapered_qubit_ops = qubit_ops else: - logger.debug('Checking operators commute with symmetry:') + logger.debug("Checking operators commute with symmetry:") symmetry_ops = [] for symmetry in self._z2symmetries.symmetries: symmetry_ops.append(PauliSumOp.from_list([(symmetry.to_label(), 1.0)])) @@ -354,9 +389,11 @@ def _symmetry_reduce(self, qubit_ops: List[PauliSumOp], def _check_commutes(cliffords: List[PauliSumOp], qubit_op: PauliSumOp) -> bool: commutes = [] for clifford in cliffords: - commuting_rows = qubit_op.primitive.table.commutes_with_all(clifford.primitive.table) + commuting_rows = qubit_op.primitive.table.commutes_with_all( + clifford.primitive.table + ) commutes.append(len(commuting_rows) == qubit_op.primitive.size) does_commute = bool(np.all(commutes)) - logger.debug(' \'%s\' commutes: %s, %s', id(qubit_op), does_commute, commutes) + logger.debug(" '%s' commutes: %s, %s", id(qubit_op), does_commute, commutes) return does_commute diff --git a/qiskit_nature/drivers/__init__.py b/qiskit_nature/drivers/__init__.py index 1bbeb6a642..e2c41aa500 100644 --- a/qiskit_nature/drivers/__init__.py +++ b/qiskit_nature/drivers/__init__.py @@ -148,28 +148,35 @@ from .fermionic_driver import FermionicDriver, HFMethodType from .units_type import UnitsType from .fcidumpd import FCIDumpDriver -from .gaussiand import GaussianDriver, GaussianLogDriver, GaussianLogResult, GaussianForcesDriver +from .gaussiand import ( + GaussianDriver, + GaussianLogDriver, + GaussianLogResult, + GaussianForcesDriver, +) from .hdf5d import HDF5Driver from .psi4d import PSI4Driver from .pyquanted import PyQuanteDriver, BasisType from .pyscfd import PySCFDriver, InitialGuess -__all__ = ['HFMethodType', - 'QMolecule', - 'Molecule', - 'WatsonHamiltonian', - 'BaseDriver', - 'BosonicDriver', - 'FermionicDriver', - 'UnitsType', - 'FCIDumpDriver', - 'GaussianDriver', - 'GaussianForcesDriver', - 'GaussianLogDriver', - 'GaussianLogResult', - 'HDF5Driver', - 'PSI4Driver', - 'BasisType', - 'PyQuanteDriver', - 'PySCFDriver', - 'InitialGuess'] +__all__ = [ + "HFMethodType", + "QMolecule", + "Molecule", + "WatsonHamiltonian", + "BaseDriver", + "BosonicDriver", + "FermionicDriver", + "UnitsType", + "FCIDumpDriver", + "GaussianDriver", + "GaussianForcesDriver", + "GaussianLogDriver", + "GaussianLogResult", + "HDF5Driver", + "PSI4Driver", + "BasisType", + "PyQuanteDriver", + "PySCFDriver", + "InitialGuess", +] diff --git a/qiskit_nature/drivers/base_driver.py b/qiskit_nature/drivers/base_driver.py index aea66f360a..60df445c84 100644 --- a/qiskit_nature/drivers/base_driver.py +++ b/qiskit_nature/drivers/base_driver.py @@ -27,11 +27,13 @@ class BaseDriver(ABC): """ @abstractmethod - def __init__(self, - molecule: Optional[Molecule] = None, - basis: str = 'sto3g', - hf_method: str = 'rhf', - supports_molecule: bool = False) -> None: + def __init__( + self, + molecule: Optional[Molecule] = None, + basis: str = "sto3g", + hf_method: str = "rhf", + supports_molecule: bool = False, + ) -> None: """ Args: molecule: molecule @@ -69,32 +71,32 @@ def supports_molecule(self) -> bool: @property def molecule(self) -> Optional[Molecule]: - """ return molecule """ + """return molecule""" return self._molecule @molecule.setter def molecule(self, value: Molecule) -> None: - """ set molecule """ + """set molecule""" if not self.supports_molecule: raise QiskitNatureError("Driver doesn't support molecule.") self._molecule = value @property def basis(self) -> str: - """ return basis """ + """return basis""" return self._basis @basis.setter def basis(self, value: str) -> None: - """ set basis """ + """set basis""" self._basis = value @property def hf_method(self) -> str: - """ return Hartree-Fock method """ + """return Hartree-Fock method""" return self._hf_method @hf_method.setter def hf_method(self, value: str) -> None: - """ set Hartree-Fock method """ + """set Hartree-Fock method""" self._hf_method = value diff --git a/qiskit_nature/drivers/bosonic_bases/__init__.py b/qiskit_nature/drivers/bosonic_bases/__init__.py index d3706eba95..b7c596692e 100644 --- a/qiskit_nature/drivers/bosonic_bases/__init__.py +++ b/qiskit_nature/drivers/bosonic_bases/__init__.py @@ -33,5 +33,4 @@ from .bosonic_basis import BosonicBasis from .harmonic_basis import HarmonicBasis -__all__ = ['BosonicBasis', - 'HarmonicBasis'] +__all__ = ["BosonicBasis", "HarmonicBasis"] diff --git a/qiskit_nature/drivers/bosonic_bases/bosonic_basis.py b/qiskit_nature/drivers/bosonic_bases/bosonic_basis.py index e52032f01e..fc45261a41 100644 --- a/qiskit_nature/drivers/bosonic_bases/bosonic_basis.py +++ b/qiskit_nature/drivers/bosonic_bases/bosonic_basis.py @@ -16,10 +16,11 @@ class BosonicBasis: - """ Basis to express a second quantization Bosonic Hamiltonian. """ + """Basis to express a second quantization Bosonic Hamiltonian.""" - def convert(self, threshold: float = 1e-6) \ - -> List[List[Tuple[List[List[int]], complex]]]: + def convert( + self, threshold: float = 1e-6 + ) -> List[List[Tuple[List[List[int]], complex]]]: """ This prepares an array object representing a bosonic hamiltonian expressed in the harmonic basis. This object can directly be given to the BosonicOperator diff --git a/qiskit_nature/drivers/bosonic_bases/harmonic_basis.py b/qiskit_nature/drivers/bosonic_bases/harmonic_basis.py index abcd07caef..29efc8e164 100644 --- a/qiskit_nature/drivers/bosonic_bases/harmonic_basis.py +++ b/qiskit_nature/drivers/bosonic_bases/harmonic_basis.py @@ -32,8 +32,12 @@ class HarmonicBasis(BosonicBasis): """ - def __init__(self, watson_hamiltonian: WatsonHamiltonian, num_modals: List[int], - truncation_order: int = 3) -> None: + def __init__( + self, + watson_hamiltonian: WatsonHamiltonian, + num_modals: List[int], + truncation_order: int = 3, + ) -> None: """ Args: watson_hamiltonian: A ``WatsonHamiltonian`` object which contains the hamiltonian @@ -50,7 +54,9 @@ def __init__(self, watson_hamiltonian: WatsonHamiltonian, num_modals: List[int], self._truncation_order = truncation_order @staticmethod - def _harmonic_integrals(m: int, n: int, power: int, kinetic_term: bool = False) -> float: + def _harmonic_integrals( + m: int, n: int, power: int, kinetic_term: bool = False + ) -> float: r"""Computes the integral of the Hamiltonian with the harmonic basis. This computation is as shown in [1]. @@ -86,7 +92,7 @@ def _harmonic_integrals(m: int, n: int, power: int, kinetic_term: bool = False) # coeff = -coeff elif power == 2 and kinetic_term is False: if m - n == 0: - coeff = (m + 1 / 2) + coeff = m + 1 / 2 elif m - n == 2: coeff = np.sqrt(m * (m - 1)) / 2 elif power == 3: @@ -102,8 +108,9 @@ def _harmonic_integrals(m: int, n: int, power: int, kinetic_term: bool = False) elif m - n == 4: coeff = np.sqrt(m * (m - 1) * (m - 2) * (m - 3)) / 4 else: - raise ValueError('The Q power is to high, only up to 4 is ' - 'currently supported.') + raise ValueError( + "The Q power is to high, only up to 4 is " "currently supported." + ) return coeff * (np.sqrt(2) ** power) def _is_in_basis(self, indices, order, i): @@ -115,8 +122,9 @@ def _is_in_basis(self, indices, order, i): return in_basis - def convert(self, threshold: float = 1e-6 - ) -> List[List[Tuple[List[List[int]], complex]]]: + def convert( + self, threshold: float = 1e-6 + ) -> List[List[Tuple[List[List[int]], complex]]]: """ This prepares an array object representing a bosonic hamiltonian expressed in the harmonic basis. This object can directly be given to the BosonicOperator @@ -135,14 +143,29 @@ class to be mapped to a qubit hamiltonian. num_modes = len(self._num_modals) num_modals = self._max_num_modals - harmonic_dict = {1: np.zeros((num_modes, num_modals, num_modals)), - 2: np.zeros((num_modes, num_modals, num_modals, - num_modes, num_modals, num_modals)), - 3: np.zeros((num_modes, num_modals, num_modals, - num_modes, num_modals, num_modals, - num_modes, num_modals, num_modals))} - - for entry in self._watson.data: # Entry is coeff (float) followed by indices (ints) + harmonic_dict = { + 1: np.zeros((num_modes, num_modals, num_modals)), + 2: np.zeros( + (num_modes, num_modals, num_modals, num_modes, num_modals, num_modals) + ), + 3: np.zeros( + ( + num_modes, + num_modals, + num_modals, + num_modes, + num_modals, + num_modals, + num_modes, + num_modals, + num_modals, + ) + ), + } + + for ( + entry + ) in self._watson.data: # Entry is coeff (float) followed by indices (ints) coeff0 = cast(float, entry[0]) indices = cast(List[int], entry[1:]) @@ -165,86 +188,171 @@ class to be mapped to a qubit hamiltonian. if order == 1: for m in range(num_modals): - for n in range(m+1): + for n in range(m + 1): coeff = coeff0 * self._harmonic_integrals( - m, n, index_dict[modes[0]], kinetic_term=kinetic_term) + m, n, index_dict[modes[0]], kinetic_term=kinetic_term + ) if abs(coeff) > threshold: - harmonic_dict[1][modes[0]-1, m, n] += coeff + harmonic_dict[1][modes[0] - 1, m, n] += coeff if m != n: harmonic_dict[1][modes[0] - 1, n, m] += coeff elif order == 2: for m in range(num_modals): - for n in range(m+1): + for n in range(m + 1): coeff1 = coeff0 * self._harmonic_integrals( - m, n, index_dict[modes[0]], kinetic_term=kinetic_term) + m, n, index_dict[modes[0]], kinetic_term=kinetic_term + ) for j in range(num_modals): - for k in range(j+1): + for k in range(j + 1): coeff = coeff1 * self._harmonic_integrals( - j, k, index_dict[modes[1]], kinetic_term=kinetic_term) + j, + k, + index_dict[modes[1]], + kinetic_term=kinetic_term, + ) if abs(coeff) > threshold: - harmonic_dict[2][modes[0] - 1, m, n, - modes[1] - 1, j, k] += coeff + harmonic_dict[2][ + modes[0] - 1, m, n, modes[1] - 1, j, k + ] += coeff if m != n: - harmonic_dict[2][modes[0] - 1, n, m, - modes[1] - 1, j, k] += coeff + harmonic_dict[2][ + modes[0] - 1, n, m, modes[1] - 1, j, k + ] += coeff if j != k: - harmonic_dict[2][modes[0] - 1, m, n, - modes[1] - 1, k, j] += coeff + harmonic_dict[2][ + modes[0] - 1, m, n, modes[1] - 1, k, j + ] += coeff if m != n and j != k: - harmonic_dict[2][modes[0] - 1, n, m, - modes[1] - 1, k, j] += coeff + harmonic_dict[2][ + modes[0] - 1, n, m, modes[1] - 1, k, j + ] += coeff elif order == 3: for m in range(num_modals): - for n in range(m+1): + for n in range(m + 1): coeff1 = coeff0 * self._harmonic_integrals( - m, n, index_dict[modes[0]], kinetic_term=kinetic_term) + m, n, index_dict[modes[0]], kinetic_term=kinetic_term + ) for j in range(num_modals): - for k in range(j+1): + for k in range(j + 1): coeff2 = coeff1 * self._harmonic_integrals( - j, k, index_dict[modes[1]], kinetic_term=kinetic_term) + j, + k, + index_dict[modes[1]], + kinetic_term=kinetic_term, + ) # pylint: disable=locally-disabled, invalid-name for p in range(num_modals): - for q in range(p+1): + for q in range(p + 1): coeff = coeff2 * self._harmonic_integrals( - p, q, index_dict[modes[2]], kinetic_term=kinetic_term) + p, + q, + index_dict[modes[2]], + kinetic_term=kinetic_term, + ) if abs(coeff) > threshold: - harmonic_dict[3][modes[0] - 1, m, n, - modes[1] - 1, j, k, - modes[2] - 1, p, q] += coeff + harmonic_dict[3][ + modes[0] - 1, + m, + n, + modes[1] - 1, + j, + k, + modes[2] - 1, + p, + q, + ] += coeff if m != n: - harmonic_dict[3][modes[0] - 1, n, m, - modes[1] - 1, j, k, - modes[2] - 1, p, q] += coeff + harmonic_dict[3][ + modes[0] - 1, + n, + m, + modes[1] - 1, + j, + k, + modes[2] - 1, + p, + q, + ] += coeff if k != j: - harmonic_dict[3][modes[0] - 1, m, n, - modes[1] - 1, k, j, - modes[2] - 1, p, q] += coeff + harmonic_dict[3][ + modes[0] - 1, + m, + n, + modes[1] - 1, + k, + j, + modes[2] - 1, + p, + q, + ] += coeff if p != q: - harmonic_dict[3][modes[0] - 1, m, n, - modes[1] - 1, j, k, - modes[2] - 1, q, p] += coeff + harmonic_dict[3][ + modes[0] - 1, + m, + n, + modes[1] - 1, + j, + k, + modes[2] - 1, + q, + p, + ] += coeff if m != n and k != j: - harmonic_dict[3][modes[0] - 1, n, m, - modes[1] - 1, k, j, - modes[2] - 1, p, q] += coeff + harmonic_dict[3][ + modes[0] - 1, + n, + m, + modes[1] - 1, + k, + j, + modes[2] - 1, + p, + q, + ] += coeff if m != n and p != q: - harmonic_dict[3][modes[0] - 1, n, m, - modes[1] - 1, j, k, - modes[2] - 1, q, p] += coeff + harmonic_dict[3][ + modes[0] - 1, + n, + m, + modes[1] - 1, + j, + k, + modes[2] - 1, + q, + p, + ] += coeff if p != q and k != j: - harmonic_dict[3][modes[0] - 1, m, n, - modes[1] - 1, k, j, - modes[2] - 1, q, p] += coeff + harmonic_dict[3][ + modes[0] - 1, + m, + n, + modes[1] - 1, + k, + j, + modes[2] - 1, + q, + p, + ] += coeff if m != n and j != k and p != q: - harmonic_dict[3][modes[0] - 1, n, m, - modes[1] - 1, k, j, - modes[2] - 1, q, p] += coeff + harmonic_dict[3][ + modes[0] - 1, + n, + m, + modes[1] - 1, + k, + j, + modes[2] - 1, + q, + p, + ] += coeff else: - raise ValueError('Expansion of the PES is too large, only ' - 'up to 3-body terms are supported') + raise ValueError( + "Expansion of the PES is too large, only " + "up to 3-body terms are supported" + ) harmonics = [] # type: List[List[Tuple[List[List[int]], complex]]] for idx in range(1, self._truncation_order + 1): @@ -254,8 +362,18 @@ class to be mapped to a qubit hamiltonian. values = harmonic_dict[idx][all_indices] for i in range(len(all_indices[0])): if self._is_in_basis(all_indices, idx, i): - harmonics[- 1].append(([[all_indices[3 * j][i], all_indices[3 * j + 1][i], - all_indices[3 * j + 2][i]] for j in range(idx)], - values[i])) + harmonics[-1].append( + ( + [ + [ + all_indices[3 * j][i], + all_indices[3 * j + 1][i], + all_indices[3 * j + 2][i], + ] + for j in range(idx) + ], + values[i], + ) + ) return harmonics diff --git a/qiskit_nature/drivers/fcidumpd/__init__.py b/qiskit_nature/drivers/fcidumpd/__init__.py index cad2a1ab31..1f6ba43b5e 100644 --- a/qiskit_nature/drivers/fcidumpd/__init__.py +++ b/qiskit_nature/drivers/fcidumpd/__init__.py @@ -17,4 +17,4 @@ from .fcidumpdriver import FCIDumpDriver -__all__ = ['FCIDumpDriver'] +__all__ = ["FCIDumpDriver"] diff --git a/qiskit_nature/drivers/fcidumpd/dumper.py b/qiskit_nature/drivers/fcidumpd/dumper.py index 698c8585fd..02c76ae7b3 100644 --- a/qiskit_nature/drivers/fcidumpd/dumper.py +++ b/qiskit_nature/drivers/fcidumpd/dumper.py @@ -17,9 +17,17 @@ import numpy as np -def dump(outpath: str, norb: int, nelec: int, hijs: np.ndarray, hijkls: np.ndarray, einact: float, - ms2: int = 0, orbsym: Optional[List[str]] = None, isym: int = 1 - ) -> None: +def dump( + outpath: str, + norb: int, + nelec: int, + hijs: np.ndarray, + hijkls: np.ndarray, + einact: float, + ms2: int = 0, + orbsym: Optional[List[str]] = None, + isym: int = 1, +) -> None: # pylint: disable=wrong-spelling-in-docstring """Generates a FCIDump output. @@ -38,19 +46,22 @@ def dump(outpath: str, norb: int, nelec: int, hijs: np.ndarray, hijkls: np.ndarr hij, hij_b = hijs hijkl, hijkl_ba, hijkl_bb = hijkls # assert that either all beta variables are None or all of them are not - assert all(h is None for h in [hij_b, hijkl_ba, hijkl_bb]) \ - or all(h is not None for h in [hij_b, hijkl_ba, hijkl_bb]) + assert all(h is None for h in [hij_b, hijkl_ba, hijkl_bb]) or all( + h is not None for h in [hij_b, hijkl_ba, hijkl_bb] + ) assert norb == hij.shape[0] == hijkl.shape[0] mos = range(norb) - with open(outpath, 'w') as outfile: + with open(outpath, "w") as outfile: # print header - outfile.write('&FCI NORB={:4d},NELEC={:4d},MS2={:4d}\n'.format(norb, nelec, ms2)) + outfile.write( + "&FCI NORB={:4d},NELEC={:4d},MS2={:4d}\n".format(norb, nelec, ms2) + ) if orbsym is None: - outfile.write(' ORBSYM=' + '1,'*norb + '\n') + outfile.write(" ORBSYM=" + "1," * norb + "\n") else: assert len(orbsym) == norb - outfile.write(' ORBSYM=' + ','.join(orbsym) + '\n') - outfile.write(' ISYM={:d},\n&END\n'.format(isym)) + outfile.write(" ORBSYM=" + ",".join(orbsym) + "\n") + outfile.write(" ISYM={:d},\n&END\n".format(isym)) # append 2e integrals _dump_2e_ints(hijkl, mos, outfile) if hijkl_ba is not None: @@ -66,40 +77,52 @@ def dump(outpath: str, norb: int, nelec: int, hijs: np.ndarray, hijkls: np.ndarr _write_to_outfile(outfile, einact, (0, 0, 0, 0)) -def _dump_1e_ints(hij: List[List[float]], - mos: Union[range, List[int]], - outfile: TextIO, - beta: bool = False) -> None: - idx_offset = 1 if not beta else 1+len(mos) +def _dump_1e_ints( + hij: List[List[float]], + mos: Union[range, List[int]], + outfile: TextIO, + beta: bool = False, +) -> None: + idx_offset = 1 if not beta else 1 + len(mos) hij_elements = set() for i, j in itertools.product(mos, repeat=2): if i == j: - _write_to_outfile(outfile, hij[i][j], (i+idx_offset, j+idx_offset, 0, 0)) + _write_to_outfile( + outfile, hij[i][j], (i + idx_offset, j + idx_offset, 0, 0) + ) continue if (j, i) in hij_elements and np.isclose(hij[i][j], hij[j][i]): continue - _write_to_outfile(outfile, hij[i][j], (i+idx_offset, j+idx_offset, 0, 0)) + _write_to_outfile(outfile, hij[i][j], (i + idx_offset, j + idx_offset, 0, 0)) hij_elements.add((i, j)) -def _dump_2e_ints(hijkl: np.ndarray, - mos: Union[range, List[int]], - outfile: TextIO, - beta: int = 0) -> None: +def _dump_2e_ints( + hijkl: np.ndarray, mos: Union[range, List[int]], outfile: TextIO, beta: int = 0 +) -> None: idx_offsets = [1, 1] for b in range(beta): - idx_offsets[1-b] += len(mos) + idx_offsets[1 - b] += len(mos) hijkl_elements = set() # pylint: disable=invalid-name for elem in itertools.product(mos, repeat=4): if np.isclose(hijkl[elem], 0.0, atol=1e-14): continue if len(set(elem)) == 1: - _write_to_outfile(outfile, hijkl[elem], (*[e+idx_offsets[0] for e in elem[:2]], - *[e+idx_offsets[1] for e in elem[2:]])) + _write_to_outfile( + outfile, + hijkl[elem], + ( + *[e + idx_offsets[0] for e in elem[:2]], + *[e + idx_offsets[1] for e in elem[2:]], + ), + ) continue - if beta != 1 and elem[::-1] in hijkl_elements and \ - np.isclose(hijkl[elem], hijkl[elem[::-1]]): + if ( + beta != 1 + and elem[::-1] in hijkl_elements + and np.isclose(hijkl[elem], hijkl[elem[::-1]]) + ): continue bra_perms = set(itertools.permutations(elem[:2])) ket_perms = set(itertools.permutations(elem[2:])) @@ -108,16 +131,22 @@ def _dump_2e_ints(hijkl: np.ndarray, else: permutations = itertools.chain( itertools.product(bra_perms, ket_perms), - itertools.product(ket_perms, bra_perms) + itertools.product(ket_perms, bra_perms), ) for perm in {e1 + e2 for e1, e2 in permutations}: if perm in hijkl_elements and np.isclose(hijkl[elem], hijkl[perm]): break else: - _write_to_outfile(outfile, hijkl[elem], (*[e+idx_offsets[0] for e in elem[:2]], - *[e+idx_offsets[1] for e in elem[2:]])) + _write_to_outfile( + outfile, + hijkl[elem], + ( + *[e + idx_offsets[0] for e in elem[:2]], + *[e + idx_offsets[1] for e in elem[2:]], + ), + ) hijkl_elements.add(elem) def _write_to_outfile(outfile: TextIO, value: float, indices: Tuple): - outfile.write('{:23.16E}{:4d}{:4d}{:4d}{:4d}\n'.format(value, *indices)) + outfile.write("{:23.16E}{:4d}{:4d}{:4d}{:4d}\n".format(value, *indices)) diff --git a/qiskit_nature/drivers/fcidumpd/fcidumpdriver.py b/qiskit_nature/drivers/fcidumpd/fcidumpdriver.py index ee09c0154d..7055a36e4c 100644 --- a/qiskit_nature/drivers/fcidumpd/fcidumpdriver.py +++ b/qiskit_nature/drivers/fcidumpd/fcidumpdriver.py @@ -50,13 +50,20 @@ def __init__(self, fcidump_input: str, atoms: Optional[List[str]] = None) -> Non if not isinstance(fcidump_input, str): raise QiskitNatureError( - "The fcidump_input must be str, not '{}'".format(fcidump_input)) + "The fcidump_input must be str, not '{}'".format(fcidump_input) + ) self._fcidump_input = fcidump_input - if atoms and not isinstance(atoms, list) \ - and not all(sym in QMolecule.symbols for sym in atoms): + if ( + atoms + and not isinstance(atoms, list) + and not all(sym in QMolecule.symbols for sym in atoms) + ): raise QiskitNatureError( - "The atoms must be a list of valid atomic symbols, not '{}'".format(atoms)) + "The atoms must be a list of valid atomic symbols, not '{}'".format( + atoms + ) + ) self.atoms = atoms def run(self) -> QMolecule: @@ -69,28 +76,34 @@ def run(self) -> QMolecule: q_mol = QMolecule() - q_mol.nuclear_repulsion_energy = fcidump_data.get('ecore', None) - q_mol.num_molecular_orbitals = fcidump_data.get('NORB') - q_mol.multiplicity = fcidump_data.get('MS2', 0) + 1 + q_mol.nuclear_repulsion_energy = fcidump_data.get("ecore", None) + q_mol.num_molecular_orbitals = fcidump_data.get("NORB") + q_mol.multiplicity = fcidump_data.get("MS2", 0) + 1 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 + 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: q_mol.num_atoms = len(self.atoms) q_mol.atom_symbol = self.atoms - q_mol.atom_xyz = [[float('NaN')] * 3] * len(self.atoms) # ensures QMolecule.log() works + q_mol.atom_xyz = [[float("NaN")] * 3] * len( + self.atoms + ) # ensures QMolecule.log() works - q_mol.mo_onee_ints = fcidump_data.get('hij', None) - q_mol.mo_onee_ints_b = fcidump_data.get('hij_b', None) - q_mol.mo_eri_ints = fcidump_data.get('hijkl', None) - q_mol.mo_eri_ints_bb = fcidump_data.get('hijkl_bb', None) - q_mol.mo_eri_ints_ba = fcidump_data.get('hijkl_ba', None) + q_mol.mo_onee_ints = fcidump_data.get("hij", None) + q_mol.mo_onee_ints_b = fcidump_data.get("hij_b", None) + q_mol.mo_eri_ints = fcidump_data.get("hijkl", None) + q_mol.mo_eri_ints_bb = fcidump_data.get("hijkl_bb", None) + q_mol.mo_eri_ints_ba = fcidump_data.get("hijkl_ba", None) return q_mol @staticmethod - def dump(q_mol: QMolecule, outpath: str, orbsym: Optional[List[str]] = None, - isym: int = 1) -> None: + def dump( + q_mol: QMolecule, + outpath: str, + orbsym: Optional[List[str]] = None, + isym: int = 1, + ) -> None: """Convenience method to produce an FCIDump output file. Args: @@ -100,8 +113,14 @@ def dump(q_mol: QMolecule, outpath: str, orbsym: Optional[List[str]] = None, orbsym: A list of spatial symmetries of the orbitals. isym: The spatial symmetry of the wave function. """ - dump(outpath, - q_mol.num_molecular_orbitals, q_mol.num_alpha + q_mol.num_beta, - (q_mol.mo_onee_ints, q_mol.mo_onee_ints_b), # type: ignore - (q_mol.mo_eri_ints, q_mol.mo_eri_ints_ba, q_mol.mo_eri_ints_bb), # type: ignore - q_mol.nuclear_repulsion_energy, ms2=q_mol.multiplicity - 1, orbsym=orbsym, isym=isym) + dump( + outpath, + q_mol.num_molecular_orbitals, + q_mol.num_alpha + q_mol.num_beta, + (q_mol.mo_onee_ints, q_mol.mo_onee_ints_b), # type: ignore + (q_mol.mo_eri_ints, q_mol.mo_eri_ints_ba, q_mol.mo_eri_ints_bb), # type: ignore + q_mol.nuclear_repulsion_energy, + ms2=q_mol.multiplicity - 1, + orbsym=orbsym, + isym=isym, + ) diff --git a/qiskit_nature/drivers/fcidumpd/parser.py b/qiskit_nature/drivers/fcidumpd/parser.py index a83673ddd6..809aeff47b 100644 --- a/qiskit_nature/drivers/fcidumpd/parser.py +++ b/qiskit_nature/drivers/fcidumpd/parser.py @@ -34,65 +34,75 @@ def parse(fcidump: str) -> Dict[str, Any]: A dictionary storing the parsed data. """ try: - with open(fcidump, 'r') as file: + with open(fcidump, "r") as file: fcidump_str = file.read() except OSError as ex: - raise QiskitNatureError("Input file '{}' cannot be read!".format(fcidump)) from ex + raise QiskitNatureError( + "Input file '{}' cannot be read!".format(fcidump) + ) from ex output = {} # type: Dict[str, Any] # FCIDump starts with a Fortran namelist of meta data - namelist_end = re.search('(/|&END)', fcidump_str) - metadata = fcidump_str[:namelist_end.start(0)] - metadata = ' '.join(metadata.split()) # replace duplicate whitespace and newlines + namelist_end = re.search("(/|&END)", fcidump_str) + metadata = fcidump_str[: namelist_end.start(0)] + metadata = " ".join(metadata.split()) # replace duplicate whitespace and newlines # we know what elements to look for so we don't get too fancy with the parsing # pattern explanation: # .*? any text # (*|*), match either part of this group followed by a comma # [-+]? match up to a single - or + # \d*.\d+ number format - pattern = r'.*?([-+]?\d*\.\d+|[-+]?\d+),' + pattern = r".*?([-+]?\d*\.\d+|[-+]?\d+)," # we parse the values in the order in which they are listed in Knowles1989 - _norb = re.search('NORB'+pattern, metadata) + _norb = re.search("NORB" + pattern, metadata) if _norb is None: - raise QiskitNatureError("The required NORB entry of the FCIDump format is missing!") + raise QiskitNatureError( + "The required NORB entry of the FCIDump format is missing!" + ) norb = int(_norb.groups()[0]) - output['NORB'] = norb - _nelec = re.search('NELEC'+pattern, metadata) + output["NORB"] = norb + _nelec = re.search("NELEC" + pattern, metadata) if _nelec is None: - raise QiskitNatureError("The required NELEC entry of the FCIDump format is missing!") - output['NELEC'] = int(_nelec.groups()[0]) + raise QiskitNatureError( + "The required NELEC entry of the FCIDump format is missing!" + ) + output["NELEC"] = int(_nelec.groups()[0]) # the rest of these values may occur and are set to their defaults otherwise - _ms2 = re.search('MS2'+pattern, metadata) - output['MS2'] = int(_ms2.groups()[0]) if _ms2 else 0 - _isym = re.search('ISYM'+pattern, metadata) - output['ISYM'] = int(_isym.groups()[0]) if _isym else 1 + _ms2 = re.search("MS2" + pattern, metadata) + output["MS2"] = int(_ms2.groups()[0]) if _ms2 else 0 + _isym = re.search("ISYM" + pattern, metadata) + output["ISYM"] = int(_isym.groups()[0]) if _isym else 1 # ORBSYM holds a list, thus it requires a little different treatment - _orbsym = re.search(r'ORBSYM.*?'+r'(\d+),'*norb, metadata) - output['ORBSYM'] = [int(s) for s in _orbsym.groups()] if _orbsym else [1] * norb - _iprtim = re.search('IPRTIM'+pattern, metadata) - output['IPRTIM'] = int(_iprtim.groups()[0]) if _iprtim else -1 - _int = re.search('INT'+pattern, metadata) - output['INT'] = int(_int.groups()[0]) if _int else 5 - _memory = re.search('MEMORY'+pattern, metadata) - output['MEMORY'] = int(_memory.groups()[0]) if _memory else 10000 - _core = re.search('CORE'+pattern, metadata) - output['CORE'] = float(_core.groups()[0]) if _core else 0.0 - _maxit = re.search('MAXIT'+pattern, metadata) - output['MAXIT'] = int(_maxit.groups()[0]) if _maxit else 25 - _thr = re.search('THR'+pattern, metadata) - output['THR'] = float(_thr.groups()[0]) if _thr else 1e-5 - _thrres = re.search('THRRES'+pattern, metadata) - output['THRRES'] = float(_thrres.groups()[0]) if _thrres else 0.1 - _nroot = re.search('NROOT'+pattern, metadata) - output['NROOT'] = int(_nroot.groups()[0]) if _nroot else 1 + _orbsym = re.search(r"ORBSYM.*?" + r"(\d+)," * norb, metadata) + output["ORBSYM"] = [int(s) for s in _orbsym.groups()] if _orbsym else [1] * norb + _iprtim = re.search("IPRTIM" + pattern, metadata) + output["IPRTIM"] = int(_iprtim.groups()[0]) if _iprtim else -1 + _int = re.search("INT" + pattern, metadata) + output["INT"] = int(_int.groups()[0]) if _int else 5 + _memory = re.search("MEMORY" + pattern, metadata) + output["MEMORY"] = int(_memory.groups()[0]) if _memory else 10000 + _core = re.search("CORE" + pattern, metadata) + output["CORE"] = float(_core.groups()[0]) if _core else 0.0 + _maxit = re.search("MAXIT" + pattern, metadata) + output["MAXIT"] = int(_maxit.groups()[0]) if _maxit else 25 + _thr = re.search("THR" + pattern, metadata) + output["THR"] = float(_thr.groups()[0]) if _thr else 1e-5 + _thrres = re.search("THRRES" + pattern, metadata) + output["THRRES"] = float(_thrres.groups()[0]) if _thrres else 0.1 + _nroot = re.search("NROOT" + pattern, metadata) + output["NROOT"] = int(_nroot.groups()[0]) if _nroot else 1 # If the FCIDump file resulted from an unrestricted spin calculation the indices will label spin # rather than molecular orbitals. This means, that a line must exist which encodes the # coefficient for the spin orbital with index (norb*2, norb*2). By checking for such a line we # can distinguish between unrestricted and restricted FCIDump files. - _uhf = bool(re.search(r'.*(\s+{}\s+{}\s+0\s+0)'.format(norb*2, norb*2), - fcidump_str[namelist_end.start(0):])) + _uhf = bool( + re.search( + r".*(\s+{}\s+{}\s+0\s+0)".format(norb * 2, norb * 2), + fcidump_str[namelist_end.start(0) :], + ) + ) # the rest of the FCIDump will hold lines of the form x i a j b # a few cases have to be treated differently: @@ -107,62 +117,74 @@ def parse(fcidump: str) -> Dict[str, Any]: hij_b = hijkl_ab = hijkl_ba = hijkl_bb = None hij_b_elements = hijkl_ab_elements = hijkl_ba_elements = hijkl_bb_elements = set() if _uhf: - beta_range = [n+norb for n in range(norb)] + beta_range = [n + norb for n in range(norb)] hij_b = np.zeros((norb, norb)) hij_b_elements = set(itertools.product(beta_range, repeat=2)) hijkl_ab = np.zeros((norb, norb, norb, norb)) hijkl_ba = np.zeros((norb, norb, norb, norb)) hijkl_bb = np.zeros((norb, norb, norb, norb)) - hijkl_ab_elements = set(itertools.product( - range(norb), range(norb), beta_range, beta_range - )) - hijkl_ba_elements = set(itertools.product( - beta_range, beta_range, range(norb), range(norb) - )) + hijkl_ab_elements = set( + itertools.product(range(norb), range(norb), beta_range, beta_range) + ) + hijkl_ba_elements = set( + itertools.product(beta_range, beta_range, range(norb), range(norb)) + ) hijkl_bb_elements = set(itertools.product(beta_range, repeat=4)) - orbital_data = fcidump_str[namelist_end.end(0):].split('\n') + orbital_data = fcidump_str[namelist_end.end(0) :].split("\n") for orbital in orbital_data: if not orbital: continue x = float(orbital.split()[0]) # Note: differing naming than ijkl due to E741 and this iajb is inline with this: # https://hande.readthedocs.io/en/latest/manual/integrals.html#fcidump-format - i, a, j, b = [int(i) for i in orbital.split()[1:]] # pylint: disable=invalid-name + i, a, j, b = [ + int(i) for i in orbital.split()[1:] + ] # pylint: disable=invalid-name if i == a == j == b == 0: - output['ecore'] = x + output["ecore"] = x elif a == j == b == 0: # TODO: x is the energy of the i-th MO continue elif j == b == 0: try: - hij_elements.remove((i-1, a-1)) - hij[i-1][a-1] = x + hij_elements.remove((i - 1, a - 1)) + hij[i - 1][a - 1] = x except KeyError as ex: if _uhf: - hij_b_elements.remove((i-1, a-1)) - hij_b[i-1-norb][a-1-norb] = x + hij_b_elements.remove((i - 1, a - 1)) + hij_b[i - 1 - norb][a - 1 - norb] = x else: - raise QiskitNatureError("Unkown 1-electron integral indices encountered in \ - '{}'".format((i, a))) from ex + raise QiskitNatureError( + "Unkown 1-electron integral indices encountered in \ + '{}'".format( + (i, a) + ) + ) from ex else: try: - hijkl_elements.remove((i-1, a-1, j-1, b-1)) - hijkl[i-1][a-1][j-1][b-1] = x + hijkl_elements.remove((i - 1, a - 1, j - 1, b - 1)) + hijkl[i - 1][a - 1][j - 1][b - 1] = x except KeyError as ex: if _uhf: try: - hijkl_ab_elements.remove((i-1, a-1, j-1, b-1)) - hijkl_ab[i-1][a-1][j-1-norb][b-1-norb] = x + hijkl_ab_elements.remove((i - 1, a - 1, j - 1, b - 1)) + hijkl_ab[i - 1][a - 1][j - 1 - norb][b - 1 - norb] = x except KeyError: try: - hijkl_ba_elements.remove((i-1, a-1, j-1, b-1)) - hijkl_ba[i-1-norb][a-1-norb][j-1][b-1] = x + hijkl_ba_elements.remove((i - 1, a - 1, j - 1, b - 1)) + hijkl_ba[i - 1 - norb][a - 1 - norb][j - 1][b - 1] = x except KeyError: - hijkl_bb_elements.remove((i-1, a-1, j-1, b-1)) - hijkl_bb[i-1-norb][a-1-norb][j-1-norb][b-1-norb] = x + hijkl_bb_elements.remove((i - 1, a - 1, j - 1, b - 1)) + hijkl_bb[i - 1 - norb][a - 1 - norb][j - 1 - norb][ + b - 1 - norb + ] = x else: - raise QiskitNatureError("Unkown 2-electron integral indices encountered in \ - '{}'".format((i, a, j, b))) from ex + raise QiskitNatureError( + "Unkown 2-electron integral indices encountered in \ + '{}'".format( + (i, a, j, b) + ) + ) from ex # iterate over still empty elements in 1-electron matrix and populate with symmetric ones # if any elements are not populated these will be zero @@ -183,38 +205,38 @@ def parse(fcidump: str) -> Dict[str, Any]: # assert that EITHER hijkl_ab OR hijkl_ba were given if np.allclose(hijkl_ab, 0.0) == np.allclose(hijkl_ba, 0.0): - raise QiskitNatureError("Encountered mixed sets of indices for the 2-electron \ - integrals. Either alpha/beta or beta/alpha matrix should be specified.") + raise QiskitNatureError( + "Encountered mixed sets of indices for the 2-electron \ + integrals. Either alpha/beta or beta/alpha matrix should be specified." + ) if np.allclose(hijkl_ba, 0.0): hijkl_ba = hijkl_ab.transpose() - output['hij'] = hij - output['hij_b'] = hij_b - output['hijkl'] = hijkl - output['hijkl_ba'] = hijkl_ba - output['hijkl_bb'] = hijkl_bb + output["hij"] = hij + output["hij_b"] = hij_b + output["hijkl"] = hijkl + output["hijkl_ba"] = hijkl_ba + output["hijkl_bb"] = hijkl_bb return output -def _permute_1e_ints(hij: np.ndarray, - elements: Set[Tuple[int, ...]], - norb: int, - beta: bool = False) -> None: +def _permute_1e_ints( + hij: np.ndarray, elements: Set[Tuple[int, ...]], norb: int, beta: bool = False +) -> None: for elem in elements.copy(): - shifted = tuple(e-(beta * norb) for e in elem) + shifted = tuple(e - (beta * norb) for e in elem) hij[shifted] = hij[shifted[::-1]] elements.remove(elem) -def _permute_2e_ints(hijkl: np.ndarray, - elements: Set[Tuple[int, ...]], - norb: int, - beta: int = 0) -> None: +def _permute_2e_ints( + hijkl: np.ndarray, elements: Set[Tuple[int, ...]], norb: int, beta: int = 0 +) -> None: # pylint: disable=wrong-spelling-in-comment for elem in elements.copy(): - shifted = tuple(e-((e >= norb) * norb) for e in elem) + shifted = tuple(e - ((e >= norb) * norb) for e in elem) # initially look for "transposed" element if spins are equal if beta != 1 and elem[::-1] not in elements: hijkl[shifted] = hijkl[shifted[::-1]] @@ -233,7 +255,7 @@ def _permute_2e_ints(hijkl: np.ndarray, # BUT NOT ( ik | jl ) etc. permutations = itertools.chain( itertools.product(bra_perms, ket_perms), - itertools.product(ket_perms, bra_perms) + itertools.product(ket_perms, bra_perms), ) for perm in {e1 + e2 for e1, e2 in permutations}: if perm in elements: diff --git a/qiskit_nature/drivers/fermionic_driver.py b/qiskit_nature/drivers/fermionic_driver.py index c86b76b96b..432c96389c 100644 --- a/qiskit_nature/drivers/fermionic_driver.py +++ b/qiskit_nature/drivers/fermionic_driver.py @@ -22,10 +22,11 @@ class HFMethodType(Enum): - """ HFMethodType Enum """ - RHF = 'rhf' - ROHF = 'rohf' - UHF = 'uhf' + """HFMethodType Enum""" + + RHF = "rhf" + ROHF = "rohf" + UHF = "uhf" class FermionicDriver(BaseDriver): diff --git a/qiskit_nature/drivers/gaussiand/__init__.py b/qiskit_nature/drivers/gaussiand/__init__.py index d04912c10e..e8be451164 100644 --- a/qiskit_nature/drivers/gaussiand/__init__.py +++ b/qiskit_nature/drivers/gaussiand/__init__.py @@ -176,7 +176,9 @@ from .gaussian_log_driver import GaussianLogDriver from .gaussian_log_result import GaussianLogResult -__all__ = ['GaussianDriver', - 'GaussianForcesDriver', - 'GaussianLogDriver', - 'GaussianLogResult'] +__all__ = [ + "GaussianDriver", + "GaussianForcesDriver", + "GaussianLogDriver", + "GaussianLogResult", +] diff --git a/qiskit_nature/drivers/gaussiand/gaussian_forces_driver.py b/qiskit_nature/drivers/gaussiand/gaussian_forces_driver.py index c66c938c20..13e5b6898e 100644 --- a/qiskit_nature/drivers/gaussiand/gaussian_forces_driver.py +++ b/qiskit_nature/drivers/gaussiand/gaussian_forces_driver.py @@ -40,14 +40,16 @@ class GaussianForcesDriver(BosonicDriver): - """ Gaussian™ 16 forces driver. """ - - def __init__(self, - jcf: Union[str, List[str]] = B3YLP_JCF_DEFAULT, - logfile: Optional[str] = None, - molecule: Optional[Molecule] = None, - basis: str = 'sto-3g', - normalize: bool = True) -> None: + """Gaussian™ 16 forces driver.""" + + def __init__( + self, + jcf: Union[str, List[str]] = B3YLP_JCF_DEFAULT, + logfile: Optional[str] = None, + molecule: Optional[Molecule] = None, + basis: str = "sto-3g", + normalize: bool = True, + ) -> None: r""" Args: jcf: A job control file conforming to Gaussian™ 16 format. This can @@ -67,10 +69,9 @@ def __init__(self, QiskitNatureError: If `jcf` or `molecule` given and Gaussian™ 16 executable cannot be located. """ - super().__init__(molecule=molecule, - basis=basis, - hf_method='', - supports_molecule=True) + super().__init__( + molecule=molecule, basis=basis, hf_method="", supports_molecule=True + ) self._jcf = jcf self._logfile = None self._normalize = normalize @@ -99,15 +100,21 @@ def run(self) -> WatsonHamiltonian: def _from_molecule_to_str(self) -> str: if self.molecule.units == UnitsType.ANGSTROM: - units = 'Angstrom' + units = "Angstrom" elif self.molecule.units == UnitsType.BOHR: - units = 'Bohr' + units = "Bohr" else: - raise QiskitNatureError("Unknown unit '{}'".format(self.molecule.units.value)) - cfg1 = f'#p B3LYP/{self.basis} UNITS={units} Freq=(Anharm) Int=Ultrafine SCF=VeryTight\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} geometry optimization\n\n' - cfg3 = f'{self.molecule.charge} {self.molecule.multiplicity}\n{geom}\n\n' + raise QiskitNatureError( + "Unknown unit '{}'".format(self.molecule.units.value) + ) + cfg1 = f"#p B3LYP/{self.basis} UNITS={units} Freq=(Anharm) Int=Ultrafine SCF=VeryTight\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} geometry optimization\n\n" + cfg3 = f"{self.molecule.charge} {self.molecule.multiplicity}\n{geom}\n\n" return cfg1 + cfg2 + cfg3 diff --git a/qiskit_nature/drivers/gaussiand/gaussian_log_driver.py b/qiskit_nature/drivers/gaussiand/gaussian_log_driver.py index 16e5e703de..8b4ab4ec8a 100644 --- a/qiskit_nature/drivers/gaussiand/gaussian_log_driver.py +++ b/qiskit_nature/drivers/gaussiand/gaussian_log_driver.py @@ -24,7 +24,7 @@ class GaussianLogDriver(BaseDriver): - """ Gaussian™ 16 log driver. + """Gaussian™ 16 log driver. Qiskit chemistry driver using the Gaussian™ 16 program that provides the log back, via :class:`GaussianLogResult`, for access to the log and data recorded there. @@ -49,11 +49,12 @@ def __init__(self, jcf: Union[str, List[str]]) -> None: GaussianLogDriver._check_valid() if not isinstance(jcf, list) and not isinstance(jcf, str): - raise QiskitNatureError("Invalid input for Gaussian Log Driver '{}'" - .format(jcf)) + raise QiskitNatureError( + "Invalid input for Gaussian Log Driver '{}'".format(jcf) + ) if isinstance(jcf, list): - jcf = '\n'.join(jcf) + jcf = "\n".join(jcf) self._jcf = jcf super().__init__() @@ -63,7 +64,7 @@ def _check_valid(): check_valid() def run(self) -> GaussianLogResult: - """ Runs the driver to produce a result given the supplied job control file. + """Runs the driver to produce a result given the supplied job control file. Returns: A log file result. @@ -74,12 +75,14 @@ def run(self) -> GaussianLogResult: # The job control file, needs to end with a blank line to be valid for # Gaussian to process it. We simply add the blank line here if not. cfg = self._jcf - while not cfg.endswith('\n\n'): - cfg += '\n' - - logger.debug("User supplied job control file raw: '%s'", - cfg.replace('\r', '\\r').replace('\n', '\\n')) - logger.debug('User supplied job control file\n%s', cfg) + while not cfg.endswith("\n\n"): + cfg += "\n" + + logger.debug( + "User supplied job control file raw: '%s'", + cfg.replace("\r", "\\r").replace("\n", "\\n"), + ) + logger.debug("User supplied job control file\n%s", cfg) all_text = run_g16(cfg) if not all_text: diff --git a/qiskit_nature/drivers/gaussiand/gaussian_log_result.py b/qiskit_nature/drivers/gaussiand/gaussian_log_result.py index e8d64e594c..cda6cab0c3 100644 --- a/qiskit_nature/drivers/gaussiand/gaussian_log_result.py +++ b/qiskit_nature/drivers/gaussiand/gaussian_log_result.py @@ -23,12 +23,13 @@ class GaussianLogResult: - """ Result for Gaussian™ 16 log driver. + """Result for Gaussian™ 16 log driver. This result allows access to selected data from the log file that is not available via the use Gaussian 16 interfacing code when using the MatrixElement file. Since this parses the text output it is subject to the format of the log file. """ + def __init__(self, log: Union[str, List[str]]) -> None: """ Args: @@ -43,11 +44,11 @@ def __init__(self, log: Union[str, List[str]]) -> None: self._log = None if isinstance(log, str): - lines = log.split('\n') + lines = log.split("\n") if len(lines) == 1: with open(lines[0]) as file: - self._log = file.read().split('\n') + self._log = file.read().split("\n") else: self._log = lines @@ -59,20 +60,20 @@ def __init__(self, log: Union[str, List[str]]) -> None: @property def log(self) -> List[str]: - """ The complete Gaussian log in the form of a list of strings. """ + """The complete Gaussian log in the form of a list of strings.""" return copy.copy(self._log) def __str__(self): - return '\n'.join(self._log) + return "\n".join(self._log) # Sections of interest in the log file - _SECTION_QUADRATIC = r':\s+QUADRATIC\sFORCE\sCONSTANTS\sIN\sNORMAL\sMODES' - _SECTION_CUBIC = r':\s+CUBIC\sFORCE\sCONSTANTS\sIN\sNORMAL\sMODES' - _SECTION_QUARTIC = r':\s+QUARTIC\sFORCE\sCONSTANTS\sIN\sNORMAL\sMODES' + _SECTION_QUADRATIC = r":\s+QUADRATIC\sFORCE\sCONSTANTS\sIN\sNORMAL\sMODES" + _SECTION_CUBIC = r":\s+CUBIC\sFORCE\sCONSTANTS\sIN\sNORMAL\sMODES" + _SECTION_QUARTIC = r":\s+QUARTIC\sFORCE\sCONSTANTS\sIN\sNORMAL\sMODES" @property def quadratic_force_constants(self) -> List[Tuple[str, str, float, float, float]]: - """ Quadratic force constants. (2 indices, 3 values) + """Quadratic force constants. (2 indices, 3 values) Returns: A list of tuples each with 2 index values and 3 constant values. @@ -83,7 +84,7 @@ def quadratic_force_constants(self) -> List[Tuple[str, str, float, float, float] @property def cubic_force_constants(self) -> List[Tuple[str, str, str, float, float, float]]: - """ Cubic force constants. (3 indices, 3 values) + """Cubic force constants. (3 indices, 3 values) Returns: A list of tuples each with 3 index values and 3 constant values. @@ -93,8 +94,10 @@ def cubic_force_constants(self) -> List[Tuple[str, str, str, float, float, float return cast(List[Tuple[str, str, str, float, float, float]], cfc) @property - def quartic_force_constants(self) -> List[Tuple[str, str, str, str, float, float, float]]: - """ Quartic force constants. (4 indices, 3 values) + def quartic_force_constants( + self, + ) -> List[Tuple[str, str, str, str, float, float, float]]: + """Quartic force constants. (4 indices, 3 values) Returns: A list of tuples each with 4 index values and 3 constant values. @@ -105,11 +108,11 @@ def quartic_force_constants(self) -> List[Tuple[str, str, str, str, float, float def _force_constants(self, section_name: str, indices: int) -> List[Tuple]: constants = [] - pattern_constants = '' + pattern_constants = "" for i in range(indices): - pattern_constants += r'\s+(?P\w+)'.format(i+1) + pattern_constants += r"\s+(?P\w+)".format(i + 1) for i in range(3): - pattern_constants += r'\s+(?P[+-]?\d+\.\d+)'.format(i+1) + pattern_constants += r"\s+(?P[+-]?\d+\.\d+)".format(i + 1) # Find the section of interest i = 0 @@ -139,18 +142,18 @@ def _force_constants(self, section_name: str, indices: int) -> List[Tuple]: if const is not None: clist = [] # type: List[Union[str, float]] for i in range(indices): - clist.append(const.group('index{}'.format(i + 1))) + clist.append(const.group("index{}".format(i + 1))) for i in range(3): - clist.append(float(const.group('const{}'.format(i + 1)))) + clist.append(float(const.group("const{}".format(i + 1)))) constants.append(tuple(clist)) else: - break # End of matching lines + break # End of matching lines return constants @property def a_to_h_numbering(self) -> Dict[str, int]: - """ A to H numbering mapping. + """A to H numbering mapping. Returns: Dictionary mapping string A numbering such as '1', '3a' etc from forces modes @@ -163,18 +166,22 @@ def a_to_h_numbering(self) -> Dict[str, int]: found_a = False for line in self._log: if not found_section: - if re.search(r'Input/Output\sinformation', line) is not None: + if re.search(r"Input/Output\sinformation", line) is not None: logger.debug(line) found_section = True else: - if re.search(r'\s+\(H\)\s+\|', line) is not None: + if re.search(r"\s+\(H\)\s+\|", line) is not None: logger.debug(line) found_h = True - h_nums = [x.strip() for x in line.split('|') if x and '(H)' not in x] - elif re.search(r'\s+\(A\)\s+\|', line) is not None: + h_nums = [ + x.strip() for x in line.split("|") if x and "(H)" not in x + ] + elif re.search(r"\s+\(A\)\s+\|", line) is not None: logger.debug(line) found_a = True - a_nums = [x.strip() for x in line.split('|') if x and '(A)' not in x] + a_nums = [ + x.strip() for x in line.split("|") if x and "(A)" not in x + ] if found_h and found_a: for i, a_num in enumerate(a_nums): diff --git a/qiskit_nature/drivers/gaussiand/gaussian_utils.py b/qiskit_nature/drivers/gaussiand/gaussian_utils.py index b9d81c9b5c..0066430930 100644 --- a/qiskit_nature/drivers/gaussiand/gaussian_utils.py +++ b/qiskit_nature/drivers/gaussiand/gaussian_utils.py @@ -19,18 +19,20 @@ logger = logging.getLogger(__name__) -_GAUSSIAN_16 = 'g16' -_GAUSSIAN_16_DESC = 'Gaussian 16' +_GAUSSIAN_16 = "g16" +_GAUSSIAN_16_DESC = "Gaussian 16" _G16PROG = which(_GAUSSIAN_16) def check_valid() -> None: - """ Checks if Gaussian is installed and available""" + """Checks if Gaussian is installed and available""" if _G16PROG is None: raise QiskitNatureError( - "Could not locate {} executable '{}'. Please check that it is installed correctly." - .format(_GAUSSIAN_16_DESC, _GAUSSIAN_16)) + "Could not locate {} executable '{}'. Please check that it is installed correctly.".format( + _GAUSSIAN_16_DESC, _GAUSSIAN_16 + ) + ) def run_g16(cfg: str) -> str: @@ -50,14 +52,16 @@ def run_g16(cfg: str) -> str: """ process = None try: - with Popen(_GAUSSIAN_16, stdin=PIPE, stdout=PIPE, universal_newlines=True) as process: + with Popen( + _GAUSSIAN_16, stdin=PIPE, stdout=PIPE, universal_newlines=True + ) as process: stdout, _ = process.communicate(cfg) process.wait() except Exception as ex: if process is not None: process.kill() - raise QiskitNatureError('{} run has failed'.format(_GAUSSIAN_16_DESC)) from ex + raise QiskitNatureError("{} run has failed".format(_GAUSSIAN_16_DESC)) from ex if process.returncode != 0: errmsg = "" @@ -70,8 +74,10 @@ def run_g16(cfg: str) -> str: logger.error(lines[i]) errmsg += lines[i] + "\n" raise QiskitNatureError( - '{} process return code {}\n{}'.format( - _GAUSSIAN_16_DESC, process.returncode, errmsg)) + "{} process return code {}\n{}".format( + _GAUSSIAN_16_DESC, process.returncode, errmsg + ) + ) all_text = "" if stdout is not None: diff --git a/qiskit_nature/drivers/gaussiand/gaussiandriver.py b/qiskit_nature/drivers/gaussiand/gaussiandriver.py index 7ccc930f24..d8cec99868 100644 --- a/qiskit_nature/drivers/gaussiand/gaussiandriver.py +++ b/qiskit_nature/drivers/gaussiand/gaussiandriver.py @@ -44,13 +44,14 @@ class GaussianDriver(FermionicDriver): as to have it output a MatrixElement file. """ - 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', - molecule: Optional[Molecule] = None, - basis: str = 'sto-3g', - hf_method: HFMethodType = HFMethodType.RHF) -> None: + 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", + molecule: Optional[Molecule] = None, + basis: str = "sto-3g", + hf_method: HFMethodType = HFMethodType.RHF, + ) -> None: """ Args: config: A molecular configuration conforming to Gaussian™ 16 format. @@ -70,15 +71,19 @@ def __init__(self, """ GaussianDriver._check_valid() if not isinstance(config, str) and not isinstance(config, list): - raise QiskitNatureError("Invalid config for Gaussian Driver '{}'".format(config)) + raise QiskitNatureError( + "Invalid config for Gaussian Driver '{}'".format(config) + ) if isinstance(config, list): - config = '\n'.join(config) - - super().__init__(molecule=molecule, - basis=basis, - hf_method=hf_method.value, - supports_molecule=True) + config = "\n".join(config) + + super().__init__( + molecule=molecule, + basis=basis, + hf_method=hf_method.value, + supports_molecule=True, + ) self._config = config @staticmethod @@ -88,17 +93,23 @@ def _check_valid(): def _from_molecule_to_str(self) -> str: units = None if self.molecule.units == UnitsType.ANGSTROM: - units = 'Angstrom' + units = "Angstrom" elif self.molecule.units == UnitsType.BOHR: - units = 'Bohr' + units = "Bohr" else: - raise QiskitNatureError("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' + raise QiskitNatureError( + "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: @@ -107,12 +118,14 @@ def run(self) -> QMolecule: else: cfg = self._config - while not cfg.endswith('\n\n'): - cfg += '\n' + while not cfg.endswith("\n\n"): + cfg += "\n" - logger.debug("User supplied configuration raw: '%s'", - cfg.replace('\r', '\\r').replace('\n', '\\n')) - logger.debug('User supplied configuration\n%s', cfg) + logger.debug( + "User supplied configuration raw: '%s'", + cfg.replace("\r", "\\r").replace("\n", "\\n"), + ) + logger.debug("User supplied configuration\n%s", cfg) # To the Gaussian section of the input file passed here as section string # add line '# Symm=NoInt output=(matrix,i4labels,mo2el) tran=full' @@ -120,11 +133,11 @@ def run(self) -> QMolecule: # beginning with % along with any others that start with # # append at end the name of the MatrixElement file to be written - file, fname = tempfile.mkstemp(suffix='.mat') + file, fname = tempfile.mkstemp(suffix=".mat") os.close(file) cfg = GaussianDriver._augment_config(fname, cfg) - logger.debug('Augmented control information:\n%s', cfg) + logger.debug("Augmented control information:\n%s", cfg) run_g16(cfg) @@ -134,7 +147,7 @@ def run(self) -> QMolecule: except Exception: # pylint: disable=broad-except logger.warning("Failed to remove MatrixElement file %s", fname) - q_mol.origin_driver_name = 'GAUSSIAN' + q_mol.origin_driver_name = "GAUSSIAN" q_mol.origin_driver_config = cfg return q_mol @@ -151,15 +164,19 @@ def _augment_config(fname: str, cfg: str) -> str: line = inf.readline() if not line: break - if line.startswith('#'): + if line.startswith("#"): outf.write(line) while not added: line = inf.readline() if not line: - raise QiskitNatureError('Unexpected end of Gaussian input') + raise QiskitNatureError( + "Unexpected end of Gaussian input" + ) if not line.strip(): - outf.write('# Window=Full Int=NoRaff Symm=(NoInt,None) ' - 'output=(matrix,i4labels,mo2el) tran=full\n') + outf.write( + "# Window=Full Int=NoRaff Symm=(NoInt,None) " + "output=(matrix,i4labels,mo2el) tran=full\n" + ) added = True outf.write(line) else: @@ -178,7 +195,7 @@ def _augment_config(fname: str, cfg: str) -> str: while not added: line = inf.readline() if not line: - raise QiskitNatureError('Unexpected end of Gaussian input') + raise QiskitNatureError("Unexpected end of Gaussian input") if not line.strip(): blank = True if section_count == 2: @@ -191,7 +208,7 @@ def _augment_config(fname: str, cfg: str) -> str: outf.write(line) outf.write(fname) - outf.write('\n\n') + outf.write("\n\n") # Whatever is left in the original config we just append without further inspection while True: @@ -212,42 +229,49 @@ def _parse_matrix_file(fname: str, useao2e: bool = False) -> QMolecule: """ try: # add gauopen to sys.path so that binaries can be loaded - gauopen_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'gauopen') + gauopen_directory = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "gauopen" + ) if gauopen_directory not in sys.path: sys.path.insert(0, gauopen_directory) # pylint: disable=import-outside-toplevel from .gauopen.QCMatEl import MatEl except ImportError as mnfe: - msg = ('qcmatrixio extension not found. ' - 'See Gaussian driver readme to build qcmatrixio.F using f2py') \ - if mnfe.name == 'qcmatrixio' else str(mnfe) + msg = ( + ( + "qcmatrixio extension not found. " + "See Gaussian driver readme to build qcmatrixio.F using f2py" + ) + if mnfe.name == "qcmatrixio" + else str(mnfe) + ) logger.info(msg) raise QiskitNatureError(msg) from mnfe mel = MatEl(file=fname) - logger.debug('MatrixElement file:\n%s', mel) + logger.debug("MatrixElement file:\n%s", mel) # Create driver level molecule object and populate _q_ = QMolecule() _q_.origin_driver_version = mel.gversion # Energies and orbits - _q_.hf_energy = mel.scalar('ETOTAL') - _q_.nuclear_repulsion_energy = mel.scalar('ENUCREP') + _q_.hf_energy = mel.scalar("ETOTAL") + _q_.nuclear_repulsion_energy = mel.scalar("ENUCREP") _q_.num_molecular_orbitals = 0 # updated below from orbital coeffs size _q_.num_alpha = (mel.ne + mel.multip - 1) // 2 _q_.num_beta = (mel.ne - mel.multip + 1) // 2 - moc = GaussianDriver._get_matrix(mel, 'ALPHA MO COEFFICIENTS') - moc_b = GaussianDriver._get_matrix(mel, 'BETA MO COEFFICIENTS') + moc = GaussianDriver._get_matrix(mel, "ALPHA MO COEFFICIENTS") + moc_b = GaussianDriver._get_matrix(mel, "BETA MO COEFFICIENTS") if np.array_equal(moc, moc_b): - logger.debug('ALPHA and BETA MO COEFFS identical, keeping only ALPHA') + logger.debug("ALPHA and BETA MO COEFFS identical, keeping only ALPHA") moc_b = None _q_.num_molecular_orbitals = moc.shape[0] _q_.mo_coeff = moc _q_.mo_coeff_b = moc_b - orbs_energy = GaussianDriver._get_matrix(mel, 'ALPHA ORBITAL ENERGIES') + orbs_energy = GaussianDriver._get_matrix(mel, "ALPHA ORBITAL ENERGIES") _q_.orbital_energies = orbs_energy - orbs_energy_b = GaussianDriver._get_matrix(mel, 'BETA ORBITAL ENERGIES') + orbs_energy_b = GaussianDriver._get_matrix(mel, "BETA ORBITAL ENERGIES") _q_.orbital_energies_b = orbs_energy_b if moc_b is not None else None # Molecule geometry _q_.molecular_charge = mel.icharg @@ -266,29 +290,35 @@ def _parse_matrix_file(fname: str, useao2e: bool = False) -> QMolecule: _q_.atom_xyz[n_i][idx] = coord # 1 and 2 electron integrals - hcore = GaussianDriver._get_matrix(mel, 'CORE HAMILTONIAN ALPHA') - logger.debug('CORE HAMILTONIAN ALPHA %s', hcore.shape) - hcore_b = GaussianDriver._get_matrix(mel, 'CORE HAMILTONIAN BETA') + hcore = GaussianDriver._get_matrix(mel, "CORE HAMILTONIAN ALPHA") + logger.debug("CORE HAMILTONIAN ALPHA %s", hcore.shape) + hcore_b = GaussianDriver._get_matrix(mel, "CORE HAMILTONIAN BETA") if np.array_equal(hcore, hcore_b): # From Gaussian interfacing documentation: "The two # core Hamiltonians are identical unless # a Fermi contact perturbation has been applied." - logger.debug('CORE HAMILTONIAN ALPHA and BETA identical, keeping only ALPHA') + logger.debug( + "CORE HAMILTONIAN ALPHA and BETA identical, keeping only ALPHA" + ) hcore_b = None - logger.debug('CORE HAMILTONIAN BETA %s', - '- Not present' if hcore_b is None else hcore_b.shape) - kinetic = GaussianDriver._get_matrix(mel, 'KINETIC ENERGY') - logger.debug('KINETIC ENERGY %s', kinetic.shape) - overlap = GaussianDriver._get_matrix(mel, 'OVERLAP') - logger.debug('OVERLAP %s', overlap.shape) + logger.debug( + "CORE HAMILTONIAN BETA %s", + "- Not present" if hcore_b is None else hcore_b.shape, + ) + kinetic = GaussianDriver._get_matrix(mel, "KINETIC ENERGY") + logger.debug("KINETIC ENERGY %s", kinetic.shape) + overlap = GaussianDriver._get_matrix(mel, "OVERLAP") + logger.debug("OVERLAP %s", overlap.shape) mohij = QMolecule.oneeints2mo(hcore, moc) mohij_b = None if moc_b is not None: - mohij_b = QMolecule.oneeints2mo(hcore if hcore_b is None else hcore_b, moc_b) + mohij_b = QMolecule.oneeints2mo( + hcore if hcore_b is None else hcore_b, moc_b + ) - eri = GaussianDriver._get_matrix(mel, 'REGULAR 2E INTEGRALS') - logger.debug('REGULAR 2E INTEGRALS %s', eri.shape) - if moc_b is None and mel.matlist.get('BB MO 2E INTEGRALS') is not None: + eri = GaussianDriver._get_matrix(mel, "REGULAR 2E INTEGRALS") + logger.debug("REGULAR 2E INTEGRALS %s", eri.shape) + if moc_b is None and mel.matlist.get("BB MO 2E INTEGRALS") is not None: # It seems that when using ROHF, where alpha and beta coeffs are # the same, that integrals # for BB and BA are included in the output, as well as just AA @@ -299,7 +329,8 @@ def _parse_matrix_file(fname: str, useao2e: bool = False) -> QMolecule: # converting them ourselves. useao2e = True logger.info( - 'Identical A and B coeffs but BB ints are present - using regular 2E ints instead') + "Identical A and B coeffs but BB ints are present - using regular 2E ints instead" + ) if useao2e: # eri are 2-body in AO. We can convert to MO via the QMolecule @@ -314,14 +345,18 @@ def _parse_matrix_file(fname: str, useao2e: bool = False) -> QMolecule: # These are in MO basis but by default will be reduced in size by # frozen core default so to use them we need to add Window=Full # above when we augment the config - mohijkl = GaussianDriver._get_matrix(mel, 'AA MO 2E INTEGRALS') - logger.debug('AA MO 2E INTEGRALS %s', mohijkl.shape) - mohijkl_bb = GaussianDriver._get_matrix(mel, 'BB MO 2E INTEGRALS') - logger.debug('BB MO 2E INTEGRALS %s', - '- Not present' if mohijkl_bb is None else mohijkl_bb.shape) - mohijkl_ba = GaussianDriver._get_matrix(mel, 'BA MO 2E INTEGRALS') - logger.debug('BA MO 2E INTEGRALS %s', - '- Not present' if mohijkl_ba is None else mohijkl_ba.shape) + mohijkl = GaussianDriver._get_matrix(mel, "AA MO 2E INTEGRALS") + logger.debug("AA MO 2E INTEGRALS %s", mohijkl.shape) + mohijkl_bb = GaussianDriver._get_matrix(mel, "BB MO 2E INTEGRALS") + logger.debug( + "BB MO 2E INTEGRALS %s", + "- Not present" if mohijkl_bb is None else mohijkl_bb.shape, + ) + mohijkl_ba = GaussianDriver._get_matrix(mel, "BA MO 2E INTEGRALS") + logger.debug( + "BA MO 2E INTEGRALS %s", + "- Not present" if mohijkl_ba is None else mohijkl_ba.shape, + ) _q_.hcore = hcore _q_.hcore_b = hcore_b @@ -336,8 +371,8 @@ def _parse_matrix_file(fname: str, useao2e: bool = False) -> QMolecule: _q_.mo_eri_ints_ba = mohijkl_ba # dipole moment - dipints = GaussianDriver._get_matrix(mel, 'DIPOLE INTEGRALS') - dipints = np.einsum('ijk->kji', dipints) + dipints = GaussianDriver._get_matrix(mel, "DIPOLE INTEGRALS") + dipints = np.einsum("ijk->kji", dipints) _q_.x_dip_ints = dipints[0] _q_.y_dip_ints = dipints[1] _q_.z_dip_ints = dipints[2] @@ -352,7 +387,7 @@ def _parse_matrix_file(fname: str, useao2e: bool = False) -> QMolecule: _q_.y_dip_mo_ints_b = QMolecule.oneeints2mo(dipints[1], moc_b) _q_.z_dip_mo_ints_b = QMolecule.oneeints2mo(dipints[2], moc_b) - nucl_dip = np.einsum('i,ix->x', syms, xyz) + nucl_dip = np.einsum("i,ix->x", syms, xyz) nucl_dip = np.round(nucl_dip, decimals=8) _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True @@ -369,5 +404,5 @@ def _get_matrix(mel, name) -> np.ndarray: if m_x is None: return None dims = tuple(abs(i) for i in m_x.dimens) - mat = np.reshape(m_x.expand(), dims, order='F') + mat = np.reshape(m_x.expand(), dims, order="F") return mat diff --git a/qiskit_nature/drivers/hdf5d/__init__.py b/qiskit_nature/drivers/hdf5d/__init__.py index acc1c2463d..56afd39f02 100644 --- a/qiskit_nature/drivers/hdf5d/__init__.py +++ b/qiskit_nature/drivers/hdf5d/__init__.py @@ -14,4 +14,4 @@ from .hdf5driver import HDF5Driver -__all__ = ['HDF5Driver'] +__all__ = ["HDF5Driver"] diff --git a/qiskit_nature/drivers/hdf5d/hdf5driver.py b/qiskit_nature/drivers/hdf5d/hdf5driver.py index 6845ebc892..6b03e538ea 100644 --- a/qiskit_nature/drivers/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/hdf5d/hdf5driver.py @@ -29,8 +29,7 @@ class HDF5Driver(FermionicDriver): a :class:`~qiskit_nature.drivers.QMolecule` instance. """ - def __init__(self, - hdf5_input: str = 'molecule.hdf5') -> None: + def __init__(self, hdf5_input: str = "molecule.hdf5") -> None: """ Args: hdf5_input: Path to HDF5 file @@ -41,12 +40,12 @@ def __init__(self, @property def work_path(self): - """ Returns work path. """ + """Returns work path.""" return self._work_path @work_path.setter def work_path(self, new_work_path): - """ Sets work path. """ + """Sets work path.""" self._work_path = new_work_path def run(self) -> QMolecule: @@ -64,7 +63,7 @@ def run(self) -> QMolecule: hdf5_file = os.path.abspath(os.path.join(self.work_path, hdf5_file)) if not os.path.isfile(hdf5_file): - raise LookupError('HDF5 file not found: {}'.format(hdf5_file)) + raise LookupError("HDF5 file not found: {}".format(hdf5_file)) molecule = QMolecule(hdf5_file) molecule.load() diff --git a/qiskit_nature/drivers/molecule.py b/qiskit_nature/drivers/molecule.py index a5238f3257..1c090031ba 100644 --- a/qiskit_nature/drivers/molecule.py +++ b/qiskit_nature/drivers/molecule.py @@ -34,13 +34,14 @@ class Molecule: directly if its needed. """ - def __init__(self, - geometry: List[Tuple[str, List[float]]], - multiplicity: int = 1, - charge: int = 0, - degrees_of_freedom: Optional[List[Callable]] = None, - masses: Optional[List[float]] = None - ) -> None: + def __init__( + self, + geometry: List[Tuple[str, List[float]]], + multiplicity: int = 1, + charge: int = 0, + degrees_of_freedom: Optional[List[Callable]] = None, + masses: Optional[List[float]] = None, + ) -> None: """ Args: geometry: A list of atoms defining a given molecule where each item in the list @@ -70,18 +71,24 @@ def __init__(self, self._perturbations = None # type: Optional[List[float]] @staticmethod - def _check_consistency(geometry: List[Tuple[str, List[float]]], - masses: Optional[List[float]]): + def _check_consistency( + geometry: List[Tuple[str, List[float]]], masses: Optional[List[float]] + ): if masses is not None and len(masses) != len(geometry): - raise ValueError('Length of masses {} must match length of geometries {}'.format( - len(masses), len(geometry))) + raise ValueError( + "Length of masses {} must match length of geometries {}".format( + len(masses), len(geometry) + ) + ) @classmethod - def _distance_modifier(cls, - function: Callable[[float, float], float], - parameter: float, - geometry: List[Tuple[str, List[float]]], - atom_pair: Tuple[int, int]) -> List[Tuple[str, List[float]]]: + def _distance_modifier( + cls, + function: Callable[[float, float], float], + parameter: float, + geometry: List[Tuple[str, List[float]]], + atom_pair: Tuple[int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: function: a function of two parameters (current distance, @@ -113,10 +120,12 @@ def _distance_modifier(cls, return ending_geometry @classmethod - def absolute_distance(cls, - distance: float, - geometry: List[Tuple[str, List[float]]], - atom_pair: Tuple[int, int]) -> List[Tuple[str, List[float]]]: + def absolute_distance( + cls, + distance: float, + geometry: List[Tuple[str, List[float]]], + atom_pair: Tuple[int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: distance: The (new) distance between the two atoms. @@ -136,10 +145,12 @@ def func(curr_dist, extra): # pylint: disable=unused-argument return cls._distance_modifier(func, distance, geometry, atom_pair) @classmethod - def absolute_stretching(cls, - perturbation: float, - geometry: List[Tuple[str, List[float]]], - atom_pair: Tuple[int, int]) -> List[Tuple[str, List[float]]]: + def absolute_stretching( + cls, + perturbation: float, + geometry: List[Tuple[str, List[float]]], + atom_pair: Tuple[int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: perturbation: The magnitude of the stretch. @@ -157,14 +168,15 @@ def absolute_stretching(cls, def func(curr_dist, extra): return curr_dist + extra - return cls._distance_modifier(func, perturbation, geometry, - atom_pair) + return cls._distance_modifier(func, perturbation, geometry, atom_pair) @classmethod - def relative_stretching(cls, - perturbation: float, - geometry: List[Tuple[str, List[float]]], - atom_pair: Tuple[int, int]) -> List[Tuple[str, List[float]]]: + def relative_stretching( + cls, + perturbation: float, + geometry: List[Tuple[str, List[float]]], + atom_pair: Tuple[int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: perturbation: The magnitude of the stretch. @@ -182,15 +194,16 @@ def relative_stretching(cls, def func(curr_dist, extra): return curr_dist * extra - return cls._distance_modifier(func, perturbation, geometry, - atom_pair) + return cls._distance_modifier(func, perturbation, geometry, atom_pair) @classmethod - def _bend_modifier(cls, - function: Callable[[float, float], float], - parameter: float, - geometry: List[Tuple[str, List[float]]], - atom_trio: Tuple[int, int, int]) -> List[Tuple[str, List[float]]]: + def _bend_modifier( + cls, + function: Callable[[float, float], float], + parameter: float, + geometry: List[Tuple[str, List[float]]], + atom_trio: Tuple[int, int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: function: a function of two parameters (current angle, @@ -220,22 +233,18 @@ def _bend_modifier(cls, # It'd be good to fix this later to remember the axis in some way. if np.linalg.norm(rot_axis) == 0: nudged_vec = copy.deepcopy(distance_vec1to2) - nudged_vec[0] += .01 + nudged_vec[0] += 0.01 rot_axis = np.cross(nudged_vec, distance_vec3to2) rot_unit_axis = rot_axis / np.linalg.norm(rot_axis) starting_angle = np.arcsin( - np.linalg.norm(rot_axis) / ( - np.linalg.norm(distance_vec1to2) - * np.linalg.norm(distance_vec3to2) - ) + np.linalg.norm(rot_axis) + / (np.linalg.norm(distance_vec1to2) * np.linalg.norm(distance_vec3to2)) ) new_angle = function(starting_angle, parameter) perturbation = new_angle - starting_angle rot_matrix = scipy.linalg.expm( - np.cross( - np.eye(3), - rot_unit_axis * - perturbation)) + np.cross(np.eye(3), rot_unit_axis * perturbation) + ) new_coord1 = rot_matrix @ starting_coord1 ending_geometry = copy.deepcopy(geometry) @@ -243,10 +252,12 @@ def _bend_modifier(cls, return ending_geometry @classmethod - def absolute_angle(cls, - angle: float, - geometry: List[Tuple[str, List[float]]], - atom_trio: Tuple[int, int, int]) -> List[Tuple[str, List[float]]]: + def absolute_angle( + cls, + angle: float, + geometry: List[Tuple[str, List[float]]], + atom_trio: Tuple[int, int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: angle: The magnitude of the perturbation in **radians**. @@ -269,10 +280,12 @@ def func(curr_angle, extra): # pylint: disable=unused-argument return cls._bend_modifier(func, angle, geometry, atom_trio) @classmethod - def absolute_bending(cls, - bend: float, - geometry: List[Tuple[str, List[float]]], - atom_trio: Tuple[int, int, int]) -> List[Tuple[str, List[float]]]: + def absolute_bending( + cls, + bend: float, + geometry: List[Tuple[str, List[float]]], + atom_trio: Tuple[int, int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: bend: The magnitude of the perturbation in **radians**. @@ -295,10 +308,12 @@ def func(curr_angle, extra): return cls._bend_modifier(func, bend, geometry, atom_trio) @classmethod - def relative_bending(cls, - bend: float, - geometry: List[Tuple[str, List[float]]], - atom_trio: Tuple[int, int, int]) -> List[Tuple[str, List[float]]]: + def relative_bending( + cls, + bend: float, + geometry: List[Tuple[str, List[float]]], + atom_trio: Tuple[int, int, int], + ) -> List[Tuple[str, List[float]]]: """ Args: bend: The magnitude of the perturbation in **radians**. @@ -322,7 +337,7 @@ def func(curr_angle, extra): return cls._bend_modifier(func, bend, geometry, atom_trio) def _get_perturbed_geom(self) -> List[Tuple[str, List[float]]]: - """ get perturbed geometry """ + """get perturbed geometry""" if self.perturbations is None or self._degrees_of_freedom is None: return self._geometry @@ -333,22 +348,22 @@ def _get_perturbed_geom(self) -> List[Tuple[str, List[float]]]: @property def units(self): - """ The geometry coordinate units """ + """The geometry coordinate units""" return UnitsType.ANGSTROM @property def geometry(self) -> List[Tuple[str, List[float]]]: - """ Get geometry accounting for any perturbations """ + """Get geometry accounting for any perturbations""" return self._get_perturbed_geom() @property def masses(self) -> Optional[List[float]]: - """ Get masses """ + """Get masses""" return self._masses @masses.setter def masses(self, value: Optional[List[float]]) -> None: - """ Set masses + """Set masses Args: value: masses @@ -360,30 +375,30 @@ def masses(self, value: Optional[List[float]]) -> None: @property def multiplicity(self) -> int: - """ Get multiplicity """ + """Get multiplicity""" return self._multiplicity @multiplicity.setter def multiplicity(self, value: int) -> None: - """ Set multiplicity """ + """Set multiplicity""" self._multiplicity = value @property def charge(self) -> int: - """ Get charge """ + """Get charge""" return self._charge @charge.setter def charge(self, value: int) -> None: - """ Set charge """ + """Set charge""" self._charge = value @property def perturbations(self) -> Optional[List[float]]: - """ Get perturbations """ + """Get perturbations""" return self._perturbations @perturbations.setter def perturbations(self, value: Optional[List[float]]) -> None: - """ Set perturbations """ + """Set perturbations""" self._perturbations = value diff --git a/qiskit_nature/drivers/psi4d/__init__.py b/qiskit_nature/drivers/psi4d/__init__.py index fd09e3f6b8..0211f37678 100644 --- a/qiskit_nature/drivers/psi4d/__init__.py +++ b/qiskit_nature/drivers/psi4d/__init__.py @@ -36,4 +36,4 @@ from .psi4driver import PSI4Driver -__all__ = ['PSI4Driver'] +__all__ = ["PSI4Driver"] diff --git a/qiskit_nature/drivers/psi4d/psi4driver.py b/qiskit_nature/drivers/psi4d/psi4driver.py index f98c799d10..643e1588c1 100644 --- a/qiskit_nature/drivers/psi4d/psi4driver.py +++ b/qiskit_nature/drivers/psi4d/psi4driver.py @@ -28,7 +28,7 @@ logger = logging.getLogger(__name__) -PSI4 = 'psi4' +PSI4 = "psi4" PSI4_APP = which(PSI4) @@ -40,13 +40,16 @@ class PSI4Driver(FermionicDriver): See http://www.psicode.org/ """ - def __init__(self, - config: Union[str, List[str]] = - 'molecule h2 {\n 0 1\n H 0.0 0.0 0.0\n H 0.0 0.0 0.735\n}\n\n' - 'set {\n basis sto-3g\n scf_type pk\n reference rhf\n', - molecule: Optional[Molecule] = None, - basis: str = 'sto-3g', - hf_method: HFMethodType = HFMethodType.RHF) -> None: + def __init__( + self, + config: Union[ + str, List[str] + ] = "molecule h2 {\n 0 1\n H 0.0 0.0 0.0\n H 0.0 0.0 0.735\n}\n\n" + "set {\n basis sto-3g\n scf_type pk\n reference rhf\n", + molecule: Optional[Molecule] = None, + basis: str = "sto-3g", + hf_method: HFMethodType = HFMethodType.RHF, + ) -> None: """ Args: config: A molecular configuration conforming to PSI4 format. @@ -66,15 +69,19 @@ def __init__(self, """ self._check_valid() if not isinstance(config, str) and not isinstance(config, list): - raise QiskitNatureError("Invalid config for PSI4 Driver '{}'".format(config)) + raise QiskitNatureError( + "Invalid config for PSI4 Driver '{}'".format(config) + ) if isinstance(config, list): - config = '\n'.join(config) - - super().__init__(molecule=molecule, - basis=basis, - hf_method=hf_method.value, - supports_molecule=True) + config = "\n".join(config) + + super().__init__( + molecule=molecule, + basis=basis, + hf_method=hf_method.value, + supports_molecule=True, + ) self._config = config @staticmethod @@ -85,18 +92,24 @@ def _check_valid(): def _from_molecule_to_str(self) -> str: units = None if self.molecule.units == UnitsType.ANGSTROM: - units = 'ang' + units = "ang" elif self.molecule.units == UnitsType.BOHR: - units = 'bohr' + units = "bohr" else: - raise QiskitNatureError("Unknown unit '{}'".format(self.molecule.units.value)) - name = ''.join([name for (name, _) in self.molecule.geometry]) - geom = '\n'.join([name + ' ' + ' '.join(map(str, coord)) - for (name, coord) in self.molecule.geometry]) - cfg1 = f'molecule {name} {{\nunits {units}\n' - cfg2 = f'{self.molecule.charge} {self.molecule.multiplicity}\n' - cfg3 = f'{geom}\nno_com\nno_reorient\n}}\n\n' - cfg4 = f'set {{\n basis {self.basis}\n scf_type pk\n reference {self.hf_method}\n}}' + raise QiskitNatureError( + "Unknown unit '{}'".format(self.molecule.units.value) + ) + name = "".join([name for (name, _) in self.molecule.geometry]) + geom = "\n".join( + [ + name + " " + " ".join(map(str, coord)) + for (name, coord) in self.molecule.geometry + ] + ) + cfg1 = f"molecule {name} {{\nunits {units}\n" + cfg2 = f"{self.molecule.charge} {self.molecule.multiplicity}\n" + cfg3 = f"{geom}\nno_com\nno_reorient\n}}\n\n" + cfg4 = f"set {{\n basis {self.basis}\n scf_type pk\n reference {self.hf_method}\n}}" return cfg1 + cfg2 + cfg3 + cfg4 def run(self) -> QMolecule: @@ -106,41 +119,45 @@ def run(self) -> QMolecule: cfg = self._config psi4d_directory = os.path.dirname(os.path.realpath(__file__)) - template_file = psi4d_directory + '/_template.txt' - qiskit_chemistry_directory = os.path.abspath(os.path.join(psi4d_directory, '../..')) + template_file = psi4d_directory + "/_template.txt" + qiskit_chemistry_directory = os.path.abspath( + os.path.join(psi4d_directory, "../..") + ) molecule = QMolecule() - input_text = cfg + '\n' - input_text += 'import sys\n' - syspath = '[\'' + qiskit_chemistry_directory + '\',\'' + '\',\''.join(sys.path) + '\']' + input_text = cfg + "\n" + input_text += "import sys\n" + syspath = ( + "['" + qiskit_chemistry_directory + "','" + "','".join(sys.path) + "']" + ) - input_text += 'sys.path = ' + syspath + ' + sys.path\n' - input_text += 'from qiskit_nature.drivers.qmolecule import QMolecule\n' + input_text += "sys.path = " + syspath + " + sys.path\n" + input_text += "from qiskit_nature.drivers.qmolecule import QMolecule\n" input_text += '_q_molecule = QMolecule("{0}")\n'.format(molecule.filename) - with open(template_file, 'r') as file: + with open(template_file, "r") as file: input_text += file.read() - file_fd, input_file = tempfile.mkstemp(suffix='.inp') + file_fd, input_file = tempfile.mkstemp(suffix=".inp") os.close(file_fd) - with open(input_file, 'w') as stream: + with open(input_file, "w") as stream: stream.write(input_text) - file_fd, output_file = tempfile.mkstemp(suffix='.out') + file_fd, output_file = tempfile.mkstemp(suffix=".out") os.close(file_fd) try: PSI4Driver._run_psi4(input_file, output_file) if logger.isEnabledFor(logging.DEBUG): - with open(output_file, 'r') as file: - logger.debug('PSI4 output file:\n%s', file.read()) + with open(output_file, "r") as file: + logger.debug("PSI4 output file:\n%s", file.read()) finally: run_directory = os.getcwd() for local_file in os.listdir(run_directory): - if local_file.endswith('.clean'): - os.remove(run_directory + '/' + local_file) + if local_file.endswith(".clean"): + os.remove(run_directory + "/" + local_file) try: - os.remove('timer.dat') + os.remove("timer.dat") except Exception: # pylint: disable=broad-except pass @@ -158,7 +175,7 @@ def run(self) -> QMolecule: _q_molecule.load() # remove internal file _q_molecule.remove_file() - _q_molecule.origin_driver_name = 'PSI4' + _q_molecule.origin_driver_name = "PSI4" _q_molecule.origin_driver_config = cfg return _q_molecule @@ -168,15 +185,18 @@ def _run_psi4(input_file, output_file): # Run psi4. process = None try: - with subprocess.Popen([PSI4, input_file, output_file], - stdout=subprocess.PIPE, universal_newlines=True) as process: + with subprocess.Popen( + [PSI4, input_file, output_file], + stdout=subprocess.PIPE, + universal_newlines=True, + ) as process: stdout, _ = process.communicate() process.wait() except Exception as ex: if process is not None: process.kill() - raise QiskitNatureError('{} run has failed'.format(PSI4)) from ex + raise QiskitNatureError("{} run has failed".format(PSI4)) from ex if process.returncode != 0: errmsg = "" @@ -185,5 +205,6 @@ def _run_psi4(input_file, output_file): for i, _ in enumerate(lines): logger.error(lines[i]) errmsg += lines[i] + "\n" - raise QiskitNatureError('{} process return code {}\n{}'.format( - PSI4, process.returncode, errmsg)) + raise QiskitNatureError( + "{} process return code {}\n{}".format(PSI4, process.returncode, errmsg) + ) diff --git a/qiskit_nature/drivers/pyquanted/__init__.py b/qiskit_nature/drivers/pyquanted/__init__.py index 666fdd5e85..2c7757adc6 100644 --- a/qiskit_nature/drivers/pyquanted/__init__.py +++ b/qiskit_nature/drivers/pyquanted/__init__.py @@ -38,5 +38,4 @@ from .pyquantedriver import PyQuanteDriver, BasisType -__all__ = ['PyQuanteDriver', - 'BasisType'] +__all__ = ["PyQuanteDriver", "BasisType"] diff --git a/qiskit_nature/drivers/pyquanted/integrals.py b/qiskit_nature/drivers/pyquanted/integrals.py index 23eb0a9de7..f486979573 100644 --- a/qiskit_nature/drivers/pyquanted/integrals.py +++ b/qiskit_nature/drivers/pyquanted/integrals.py @@ -28,18 +28,13 @@ from pyquante2.ints.integrals import twoe_integrals from pyquante2.utils import simx except ImportError: - logger.info('PyQuante2 is not installed. See https://github.com/rpmuller/pyquante2') - - -def compute_integrals(atoms, - units, - charge, - multiplicity, - basis, - hf_method='rhf', - tol=1e-8, - maxiters=100): - """ Compute integrals """ + logger.info("PyQuante2 is not installed. See https://github.com/rpmuller/pyquante2") + + +def compute_integrals( + atoms, units, charge, multiplicity, basis, hf_method="rhf", tol=1e-8, maxiters=100 +): + """Compute integrals""" # Get config from input parameters # Molecule is in this format xyz as below or in Z-matrix e.g "H; O 1 1.08; H 2 1.08 1 107.5": # atoms=H .0 .0 .0; H .0 .0 0.2 @@ -55,12 +50,14 @@ def compute_integrals(atoms, try: q_mol = _calculate_integrals(mol, basis, hf_method, tol, maxiters) except Exception as exc: - raise QiskitNatureError('Failed electronic structure computation') from exc + raise QiskitNatureError("Failed electronic structure computation") from exc return q_mol -def _calculate_integrals(molecule, basis='sto3g', hf_method='rhf', tol=1e-8, maxiters=100): +def _calculate_integrals( + molecule, basis="sto3g", hf_method="rhf", tol=1e-8, maxiters=100 +): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: @@ -82,24 +79,24 @@ def _calculate_integrals(molecule, basis='sto3g', hf_method='rhf', tol=1e-8, max # convert overlap integrals to molecular basis # calculate the Hartree-Fock solution of the molecule - if hf_method == 'rhf': + if hf_method == "rhf": solver = rhf(molecule, bfs) - elif hf_method == 'rohf': + elif hf_method == "rohf": solver = rohf(molecule, bfs) - elif hf_method == 'uhf': + elif hf_method == "uhf": solver = uhf(molecule, bfs) else: - raise QiskitNatureError('Invalid hf_method type: {}'.format(hf_method)) + raise QiskitNatureError("Invalid hf_method type: {}".format(hf_method)) ehf = solver.converge(tol=tol, maxiters=maxiters) - logger.debug('PyQuante2 processing information:\n%s', solver) - if hasattr(solver, 'orbs'): + logger.debug("PyQuante2 processing information:\n%s", solver) + if hasattr(solver, "orbs"): orbs = solver.orbs orbs_b = None else: orbs = solver.orbsa orbs_b = solver.orbsb norbs = len(orbs) - if hasattr(solver, 'orbe'): + if hasattr(solver, "orbe"): orbs_energy = solver.orbe orbs_energy_b = None else: @@ -118,11 +115,13 @@ def _calculate_integrals(molecule, basis='sto3g', hf_method='rhf', tol=1e-8, max mohijkl_ba = None if orbs_b is not None: mohijkl_bb = hijkl.transform(orbs_b) - mohijkl_ba = np.einsum('aI,bJ,cK,dL,abcd->IJKL', orbs_b, orbs_b, orbs, orbs, hijkl[...]) + mohijkl_ba = np.einsum( + "aI,bJ,cK,dL,abcd->IJKL", orbs_b, orbs_b, orbs, orbs, hijkl[...] + ) # Create driver level molecule object and populate _q_ = QMolecule() - _q_.origin_driver_version = '?' # No version info seems available to access + _q_.origin_driver_version = "?" # No version info seems available to access # Energies and orbits _q_.hf_energy = ehf[0] _q_.nuclear_repulsion_energy = enuke @@ -164,38 +163,42 @@ def _calculate_integrals(molecule, basis='sto3g', hf_method='rhf', tol=1e-8, max def _parse_molecule(val, units, charge, multiplicity): val = _check_molecule_format(val) - parts = [x.strip() for x in val.split(';')] + parts = [x.strip() for x in val.split(";")] if parts is None or len(parts) < 1: # pylint: disable=len-as-condition - raise QiskitNatureError('Molecule format error: ' + val) + raise QiskitNatureError("Molecule format error: " + val) geom = [] for n, _ in enumerate(parts): part = parts[n] geom.append(_parse_atom(part)) if len(geom) < 1: # pylint: disable=len-as-condition - raise QiskitNatureError('Molecule format error: ' + val) + raise QiskitNatureError("Molecule format error: " + val) try: - from pyquante2 import molecule # pylint: disable=import-error,import-outside-toplevel + # pylint: disable=import-error,import-outside-toplevel + from pyquante2 import ( + molecule, + ) + return molecule(geom, units=units, charge=charge, multiplicity=multiplicity) except Exception as exc: - raise QiskitNatureError('Failed to create molecule') from exc + raise QiskitNatureError("Failed to create molecule") from exc def _check_molecule_format(val): """If it seems to be zmatrix rather than xyz format we convert before returning""" - atoms = [x.strip() for x in val.split(';')] + atoms = [x.strip() for x in val.split(";")] if atoms is None or len(atoms) < 1: # pylint: disable=len-as-condition - raise QiskitNatureError('Molecule format error: ' + val) + raise QiskitNatureError("Molecule format error: " + val) # An xyz format has 4 parts in each atom, if not then do zmatrix convert # Allows dummy atoms, using symbol 'X' in zmatrix format for coord computation to xyz - parts = [x.strip() for x in atoms[0].split(' ')] + parts = [x.strip() for x in atoms[0].split(" ")] if len(parts) != 4: try: zmat = [] for atom in atoms: - parts = [x.strip() for x in atom.split(' ')] + parts = [x.strip() for x in atom.split(" ")] z = [parts[0]] for i in range(1, len(parts), 2): z.append(int(parts[i])) @@ -204,41 +207,41 @@ def _check_molecule_format(val): xyz = z2xyz(zmat) new_val = "" for atm in xyz: - if atm[0].upper() == 'X': + if atm[0].upper() == "X": continue if new_val: new_val += "; " new_val += "{} {} {} {}".format(atm[0], atm[1], atm[2], atm[3]) return new_val except Exception as exc: - raise QiskitNatureError('Failed to convert atom string: ' + val) from exc + raise QiskitNatureError("Failed to convert atom string: " + val) from exc return val def _parse_atom(val): if val is None or len(val) < 1: # pylint: disable=len-as-condition - raise QiskitNatureError('Molecule atom format error: empty') + raise QiskitNatureError("Molecule atom format error: empty") - parts = re.split(r'\s+', val) + parts = re.split(r"\s+", val) if len(parts) != 4: - raise QiskitNatureError('Molecule atom format error: ' + val) + raise QiskitNatureError("Molecule atom format error: " + val) parts[0] = parts[0].lower().capitalize() if not parts[0].isdigit(): if parts[0] in QMolecule.symbols: parts[0] = QMolecule.symbols.index(parts[0]) else: - raise QiskitNatureError('Molecule atom symbol error: ' + parts[0]) + raise QiskitNatureError("Molecule atom symbol error: " + parts[0]) return int(float(parts[0])), float(parts[1]), float(parts[2]), float(parts[3]) def _check_units(units): if units.lower() in ["angstrom", "ang", "a"]: - units = 'Angstrom' + units = "Angstrom" elif units.lower() in ["bohr", "b"]: - units = 'Bohr' + units = "Bohr" else: - raise QiskitNatureError('Molecule units format error: ' + units) + raise QiskitNatureError("Molecule units format error: " + units) return units diff --git a/qiskit_nature/drivers/pyquanted/pyquantedriver.py b/qiskit_nature/drivers/pyquanted/pyquantedriver.py index 0c26a97ef6..e5671534a9 100644 --- a/qiskit_nature/drivers/pyquanted/pyquantedriver.py +++ b/qiskit_nature/drivers/pyquanted/pyquantedriver.py @@ -30,10 +30,11 @@ class BasisType(Enum): - """ Basis Type """ - BSTO3G = 'sto3g' - B631G = '6-31g' - B631GSS = '6-31g**' + """Basis Type""" + + BSTO3G = "sto3g" + B631G = "6-31g" + B631GSS = "6-31g**" class PyQuanteDriver(FermionicDriver): @@ -43,17 +44,18 @@ class PyQuanteDriver(FermionicDriver): See https://github.com/rpmuller/pyquante2 """ - def __init__(self, - atoms: Union[str, List[str]] = - 'H 0.0 0.0 0.0; H 0.0 0.0 0.735', - units: UnitsType = UnitsType.ANGSTROM, - charge: int = 0, - multiplicity: int = 1, - basis: BasisType = BasisType.BSTO3G, - hf_method: HFMethodType = HFMethodType.RHF, - tol: float = 1e-8, - maxiters: int = 100, - molecule: Optional[Molecule] = None) -> None: + def __init__( + self, + atoms: Union[str, List[str]] = "H 0.0 0.0 0.0; H 0.0 0.0 0.735", + units: UnitsType = UnitsType.ANGSTROM, + charge: int = 0, + multiplicity: int = 1, + basis: BasisType = BasisType.BSTO3G, + hf_method: HFMethodType = HFMethodType.RHF, + tol: float = 1e-8, + maxiters: int = 100, + molecule: Optional[Molecule] = None, + ) -> None: """ Args: atoms: Atoms list or string separated by semicolons or line breaks. Each element in the @@ -77,20 +79,24 @@ def __init__(self, Raises: QiskitNatureError: Invalid Input """ - validate_min('maxiters', maxiters, 1) + validate_min("maxiters", maxiters, 1) self._check_valid() if not isinstance(atoms, str) and not isinstance(atoms, list): - raise QiskitNatureError("Invalid atom input for PYQUANTE Driver '{}'".format(atoms)) + raise QiskitNatureError( + "Invalid atom input for PYQUANTE Driver '{}'".format(atoms) + ) if isinstance(atoms, list): - atoms = ';'.join(atoms) + atoms = ";".join(atoms) elif isinstance(atoms, str): - atoms = atoms.replace('\n', ';') - - super().__init__(molecule=molecule, - basis=basis.value, - hf_method=hf_method.value, - supports_molecule=True) + atoms = atoms.replace("\n", ";") + + super().__init__( + molecule=molecule, + basis=basis.value, + hf_method=hf_method.value, + supports_molecule=True, + ) self._atoms = atoms self._units = units.value self._charge = charge @@ -100,21 +106,27 @@ def __init__(self, @staticmethod def _check_valid(): - err_msg = 'PyQuante2 is not installed. See https://github.com/rpmuller/pyquante2' + err_msg = ( + "PyQuante2 is not installed. See https://github.com/rpmuller/pyquante2" + ) try: - spec = importlib.util.find_spec('pyquante2') + spec = importlib.util.find_spec("pyquante2") if spec is not None: return except Exception as ex: # pylint: disable=broad-except - logger.debug('PyQuante2 check error %s', str(ex)) + logger.debug("PyQuante2 check error %s", str(ex)) raise QiskitNatureError(err_msg) from ex raise QiskitNatureError(err_msg) def run(self) -> QMolecule: if self.molecule is not None: - atoms = ';'.join([name + ' ' + ' '.join(map(str, coord)) - for (name, coord) in self.molecule.geometry]) + atoms = ";".join( + [ + name + " " + " ".join(map(str, coord)) + for (name, coord) in self.molecule.geometry + ] + ) charge = self.molecule.charge multiplicity = self.molecule.multiplicity units = self.molecule.units.value @@ -127,25 +139,29 @@ def run(self) -> QMolecule: basis = self.basis hf_method = self.hf_method - q_mol = compute_integrals(atoms=atoms, - units=units, - charge=charge, - multiplicity=multiplicity, - basis=basis, - hf_method=hf_method, - tol=self._tol, - maxiters=self._maxiters) - - q_mol.origin_driver_name = 'PYQUANTE' - cfg = ['atoms={}'.format(atoms), - 'units={}'.format(units), - 'charge={}'.format(charge), - 'multiplicity={}'.format(multiplicity), - 'basis={}'.format(basis), - 'hf_method={}'.format(hf_method), - 'tol={}'.format(self._tol), - 'maxiters={}'.format(self._maxiters), - ''] - q_mol.origin_driver_config = '\n'.join(cfg) + q_mol = compute_integrals( + atoms=atoms, + units=units, + charge=charge, + multiplicity=multiplicity, + basis=basis, + hf_method=hf_method, + tol=self._tol, + maxiters=self._maxiters, + ) + + q_mol.origin_driver_name = "PYQUANTE" + cfg = [ + "atoms={}".format(atoms), + "units={}".format(units), + "charge={}".format(charge), + "multiplicity={}".format(multiplicity), + "basis={}".format(basis), + "hf_method={}".format(hf_method), + "tol={}".format(self._tol), + "maxiters={}".format(self._maxiters), + "", + ] + q_mol.origin_driver_config = "\n".join(cfg) return q_mol diff --git a/qiskit_nature/drivers/pyscfd/__init__.py b/qiskit_nature/drivers/pyscfd/__init__.py index 031ac8d6c4..ef1d8d79e8 100644 --- a/qiskit_nature/drivers/pyscfd/__init__.py +++ b/qiskit_nature/drivers/pyscfd/__init__.py @@ -25,5 +25,4 @@ from .pyscfdriver import PySCFDriver, InitialGuess -__all__ = ['PySCFDriver', - 'InitialGuess'] +__all__ = ["PySCFDriver", "InitialGuess"] diff --git a/qiskit_nature/drivers/pyscfd/integrals.py b/qiskit_nature/drivers/pyscfd/integrals.py index 38ef45d4b8..f0ec415efc 100644 --- a/qiskit_nature/drivers/pyscfd/integrals.py +++ b/qiskit_nature/drivers/pyscfd/integrals.py @@ -29,22 +29,27 @@ from pyscf.lib import param from pyscf.lib import logger as pylogger from pyscf.tools import dump_mat - warnings.filterwarnings('ignore', category=DeprecationWarning, module='pyscf') + + warnings.filterwarnings("ignore", category=DeprecationWarning, module="pyscf") except ImportError: - logger.info("PySCF is not installed. See https://sunqm.github.io/pyscf/install.html") - - -def compute_integrals(atom, - unit, - charge, - spin, - basis, - hf_method='rhf', - conv_tol=1e-9, - max_cycle=50, - init_guess='minao', - max_memory=None): - """ compute integrals """ + logger.info( + "PySCF is not installed. See https://sunqm.github.io/pyscf/install.html" + ) + + +def compute_integrals( + atom, + unit, + charge, + spin, + basis, + hf_method="rhf", + conv_tol=1e-9, + max_cycle=50, + init_guess="minao", + max_memory=None, +): + """compute integrals""" # Get config from input parameters # molecule is in PySCF atom string format e.g. "H .0 .0 .0; H .0 .0 0.2" # or in Z-Matrix format e.g. "H; O 1 1.08; H 2 1.08 1 107.5" @@ -60,11 +65,17 @@ def compute_integrals(atom, output = None if logger.isEnabledFor(logging.DEBUG): verbose = pylogger.INFO - file, output = tempfile.mkstemp(suffix='.log') + file, output = tempfile.mkstemp(suffix=".log") os.close(file) - mol = gto.Mole(atom=atom, unit=unit, basis=basis, - max_memory=max_memory, verbose=verbose, output=output) + mol = gto.Mole( + atom=atom, + unit=unit, + basis=basis, + max_memory=max_memory, + verbose=verbose, + output=output, + ) mol.symmetry = False mol.charge = charge mol.spin = spin @@ -78,34 +89,36 @@ def compute_integrals(atom, pass except Exception as exc: - raise QiskitNatureError('Failed electronic structure computation') from exc + raise QiskitNatureError("Failed electronic structure computation") from exc return q_mol def _check_molecule_format(val): """If it seems to be zmatrix rather than xyz format we convert before returning""" - atoms = [x.strip() for x in val.split(';')] + atoms = [x.strip() for x in val.split(";")] if atoms is None or len(atoms) < 1: # pylint: disable=len-as-condition - raise QiskitNatureError('Molecule format error: ' + val) + raise QiskitNatureError("Molecule format error: " + val) # An xyz format has 4 parts in each atom, if not then do zmatrix convert # Allows dummy atoms, using symbol 'X' in zmatrix format for coord computation to xyz - parts = [x.strip() for x in atoms[0].split(' ')] + parts = [x.strip() for x in atoms[0].split(" ")] if len(parts) != 4: try: newval = [] for entry in gto.mole.from_zmatrix(val): - if entry[0].upper() != 'X': + if entry[0].upper() != "X": newval.append(entry) return newval except Exception as exc: - raise QiskitNatureError('Failed to convert atom string: ' + val) from exc + raise QiskitNatureError("Failed to convert atom string: " + val) from exc return val -def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init_guess='minao'): +def _calculate_integrals( + mol, hf_method="rhf", conv_tol=1e-9, max_cycle=50, init_guess="minao" +): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: @@ -121,20 +134,20 @@ def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init """ enuke = gto.mole.energy_nuc(mol) - if hf_method == 'rhf': + if hf_method == "rhf": m_f = scf.RHF(mol) - elif hf_method == 'rohf': + elif hf_method == "rohf": m_f = scf.ROHF(mol) - elif hf_method == 'uhf': + elif hf_method == "uhf": m_f = scf.UHF(mol) else: - raise QiskitNatureError('Invalid hf_method type: {}'.format(hf_method)) + raise QiskitNatureError("Invalid hf_method type: {}".format(hf_method)) m_f.conv_tol = conv_tol m_f.max_cycle = max_cycle m_f.init_guess = init_guess ehf = m_f.kernel() - logger.info('PySCF kernel() converged: %s, e(hf): %s', m_f.converged, m_f.e_tot) + logger.info("PySCF kernel() converged: %s, e(hf): %s", m_f.converged, m_f.e_tot) if isinstance(m_f.mo_coeff, tuple): mo_coeff = m_f.mo_coeff[0] mo_coeff_b = m_f.mo_coeff[1] @@ -170,13 +183,13 @@ def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init if logger.isEnabledFor(logging.DEBUG): # Add some more to PySCF output... # First analyze() which prints extra information about MO energy and occupation - mol.stdout.write('\n') + mol.stdout.write("\n") m_f.analyze() # Now labelled orbitals for contributions to the MOs for s,p,d etc of each atom - mol.stdout.write('\n\n--- Alpha Molecular Orbitals ---\n\n') + mol.stdout.write("\n\n--- Alpha Molecular Orbitals ---\n\n") dump_mat.dump_mo(mol, mo_coeff, digits=7, start=1) if mo_coeff_b is not None: - mol.stdout.write('\n--- Beta Molecular Orbitals ---\n\n') + mol.stdout.write("\n--- Beta Molecular Orbitals ---\n\n") dump_mat.dump_mo(mol, mo_coeff_b, digits=7, start=1) mol.stdout.flush() @@ -186,7 +199,7 @@ def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init if mo_coeff_b is not None: mohij_b = np.dot(np.dot(mo_coeff_b.T, hij), mo_coeff_b) - eri = mol.intor('int2e', aosym=1) + eri = mol.intor("int2e", aosym=1) mo_eri = ao2mo.incore.full(m_f._eri, mo_coeff, compact=False) mohijkl = mo_eri.reshape(norbs, norbs, norbs, norbs) mohijkl_bb = None @@ -194,14 +207,14 @@ def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init if mo_coeff_b is not None: mo_eri_b = ao2mo.incore.full(m_f._eri, mo_coeff_b, compact=False) mohijkl_bb = mo_eri_b.reshape(norbs, norbs, norbs, norbs) - mo_eri_ba = ao2mo.incore.general(m_f._eri, - (mo_coeff_b, mo_coeff_b, mo_coeff, mo_coeff), - compact=False) + mo_eri_ba = ao2mo.incore.general( + m_f._eri, (mo_coeff_b, mo_coeff_b, mo_coeff, mo_coeff), compact=False + ) mohijkl_ba = mo_eri_ba.reshape(norbs, norbs, norbs, norbs) # dipole integrals mol.set_common_orig((0, 0, 0)) - ao_dip = mol.intor_symmetric('int1e_r', comp=3) + ao_dip = mol.intor_symmetric("int1e_r", comp=3) x_dip_ints = ao_dip[0] y_dip_ints = ao_dip[1] z_dip_ints = ao_dip[2] @@ -209,9 +222,9 @@ def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init d_m = m_f.make_rdm1(m_f.mo_coeff, m_f.mo_occ) if not (isinstance(d_m, np.ndarray) and d_m.ndim == 2): d_m = d_m[0] + d_m[1] - elec_dip = np.negative(np.einsum('xij,ji->x', ao_dip, d_m).real) + elec_dip = np.negative(np.einsum("xij,ji->x", ao_dip, d_m).real) elec_dip = np.round(elec_dip, decimals=8) - nucl_dip = np.einsum('i,ix->x', mol.atom_charges(), mol.atom_coords()) + nucl_dip = np.einsum("i,ix->x", mol.atom_charges(), mol.atom_coords()) nucl_dip = np.round(nucl_dip, decimals=8) logger.info("HF Electronic dipole moment: %s", elec_dip) logger.info("Nuclear dipole moment: %s", nucl_dip) @@ -248,7 +261,7 @@ def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init # 1 and 2 electron integrals AO and MO _q_.hcore = hij _q_.hcore_b = None - _q_.kinetic = mol.intor_symmetric('int1e_kin') + _q_.kinetic = mol.intor_symmetric("int1e_kin") _q_.overlap = m_f.get_ovlp() _q_.eri = eri _q_.mo_onee_ints = mohij @@ -282,8 +295,8 @@ def _process_pyscf_log(logfile): content = file.readlines() for i, _ in enumerate(content): - if content[i].startswith('System:'): + if content[i].startswith("System:"): content = content[i:] break - logger.debug('PySCF processing messages log:\n%s', ''.join(content)) + logger.debug("PySCF processing messages log:\n%s", "".join(content)) diff --git a/qiskit_nature/drivers/pyscfd/pyscfdriver.py b/qiskit_nature/drivers/pyscfd/pyscfdriver.py index 988ff54c76..aa13105f3c 100644 --- a/qiskit_nature/drivers/pyscfd/pyscfdriver.py +++ b/qiskit_nature/drivers/pyscfd/pyscfdriver.py @@ -30,11 +30,12 @@ class InitialGuess(Enum): - """ Initial Guess Enum """ - MINAO = 'minao' - HCORE = '1e' - ONE_E = '1e' - ATOM = 'atom' + """Initial Guess Enum""" + + MINAO = "minao" + HCORE = "1e" + ONE_E = "1e" + ATOM = "atom" class PySCFDriver(FermionicDriver): @@ -44,19 +45,20 @@ class PySCFDriver(FermionicDriver): See https://sunqm.github.io/pyscf/ """ - def __init__(self, - atom: Union[str, List[str]] = - 'H 0.0 0.0 0.0; H 0.0 0.0 0.735', - unit: UnitsType = UnitsType.ANGSTROM, - charge: int = 0, - spin: int = 0, - basis: str = 'sto3g', - hf_method: HFMethodType = HFMethodType.RHF, - conv_tol: float = 1e-9, - max_cycle: int = 50, - init_guess: InitialGuess = InitialGuess.MINAO, - max_memory: Optional[int] = None, - molecule: Optional[Molecule] = None) -> None: + def __init__( + self, + atom: Union[str, List[str]] = "H 0.0 0.0 0.0; H 0.0 0.0 0.735", + unit: UnitsType = UnitsType.ANGSTROM, + charge: int = 0, + spin: int = 0, + basis: str = "sto3g", + hf_method: HFMethodType = HFMethodType.RHF, + conv_tol: float = 1e-9, + max_cycle: int = 50, + init_guess: InitialGuess = InitialGuess.MINAO, + max_memory: Optional[int] = None, + molecule: Optional[Molecule] = None, + ) -> None: """ Args: atom: Atom list or string separated by semicolons or line breaks. Each element in the @@ -86,18 +88,22 @@ def __init__(self, """ self._check_valid() if not isinstance(atom, str) and not isinstance(atom, list): - raise QiskitNatureError("Invalid atom input for PYSCF Driver '{}'".format(atom)) + raise QiskitNatureError( + "Invalid atom input for PYSCF Driver '{}'".format(atom) + ) if isinstance(atom, list): - atom = ';'.join(atom) + atom = ";".join(atom) elif isinstance(atom, str): - atom = atom.replace('\n', ';') - - validate_min('max_cycle', max_cycle, 1) - super().__init__(molecule=molecule, - basis=basis, - hf_method=hf_method.value, - supports_molecule=True) + atom = atom.replace("\n", ";") + + validate_min("max_cycle", max_cycle, 1) + super().__init__( + molecule=molecule, + basis=basis, + hf_method=hf_method.value, + supports_molecule=True, + ) self._atom = atom self._units = unit.value self._charge = charge @@ -109,21 +115,27 @@ def __init__(self, @staticmethod def _check_valid(): - err_msg = "PySCF is not installed. See https://sunqm.github.io/pyscf/install.html" + err_msg = ( + "PySCF is not installed. See https://sunqm.github.io/pyscf/install.html" + ) try: - spec = importlib.util.find_spec('pyscf') + spec = importlib.util.find_spec("pyscf") if spec is not None: return except Exception as ex: # pylint: disable=broad-except - logger.debug('PySCF check error %s', str(ex)) + logger.debug("PySCF check error %s", str(ex)) raise QiskitNatureError(err_msg) from ex raise QiskitNatureError(err_msg) def run(self) -> QMolecule: if self.molecule is not None: - atom = ';'.join([name + ' ' + ' '.join(map(str, coord)) - for (name, coord) in self.molecule.geometry]) + atom = ";".join( + [ + name + " " + " ".join(map(str, coord)) + for (name, coord) in self.molecule.geometry + ] + ) charge = self.molecule.charge spin = self.molecule.multiplicity - 1 units = self.molecule.units.value @@ -136,29 +148,33 @@ def run(self) -> QMolecule: basis = self.basis hf_method = self.hf_method - q_mol = compute_integrals(atom=atom, - unit=units, - charge=charge, - spin=spin, - basis=basis, - hf_method=hf_method, - conv_tol=self._conv_tol, - max_cycle=self._max_cycle, - init_guess=self._init_guess, - max_memory=self._max_memory) - - q_mol.origin_driver_name = 'PYSCF' - cfg = ['atom={}'.format(atom), - 'unit={}'.format(units), - 'charge={}'.format(charge), - 'spin={}'.format(spin), - 'basis={}'.format(basis), - 'hf_method={}'.format(hf_method), - 'conv_tol={}'.format(self._conv_tol), - 'max_cycle={}'.format(self._max_cycle), - 'init_guess={}'.format(self._init_guess), - 'max_memory={}'.format(self._max_memory), - ''] - q_mol.origin_driver_config = '\n'.join(cfg) + q_mol = compute_integrals( + atom=atom, + unit=units, + charge=charge, + spin=spin, + basis=basis, + hf_method=hf_method, + conv_tol=self._conv_tol, + max_cycle=self._max_cycle, + init_guess=self._init_guess, + max_memory=self._max_memory, + ) + + q_mol.origin_driver_name = "PYSCF" + cfg = [ + "atom={}".format(atom), + "unit={}".format(units), + "charge={}".format(charge), + "spin={}".format(spin), + "basis={}".format(basis), + "hf_method={}".format(hf_method), + "conv_tol={}".format(self._conv_tol), + "max_cycle={}".format(self._max_cycle), + "init_guess={}".format(self._init_guess), + "max_memory={}".format(self._max_memory), + "", + ] + q_mol.origin_driver_config = "\n".join(cfg) return q_mol diff --git a/qiskit_nature/drivers/qmolecule.py b/qiskit_nature/drivers/qmolecule.py index bf7a6fe4b0..7bb793e828 100644 --- a/qiskit_nature/drivers/qmolecule.py +++ b/qiskit_nature/drivers/qmolecule.py @@ -20,7 +20,7 @@ import numpy -TWOE_TO_SPIN_SUBSCRIPT = 'ijkl->ljik' +TWOE_TO_SPIN_SUBSCRIPT = "ijkl->ljik" with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=FutureWarning) @@ -123,37 +123,41 @@ def __init__(self, filename=None): @property def one_body_integrals(self): - """ Returns one body electron integrals. """ + """Returns one body electron integrals.""" return QMolecule.onee_to_spin(self.mo_onee_ints, self.mo_onee_ints_b) @property def two_body_integrals(self): - """ Returns two body electron integrals. """ - return QMolecule.twoe_to_spin(self.mo_eri_ints, self.mo_eri_ints_bb, self.mo_eri_ints_ba) + """Returns two body electron integrals.""" + return QMolecule.twoe_to_spin( + self.mo_eri_ints, self.mo_eri_ints_bb, self.mo_eri_ints_ba + ) def has_dipole_integrals(self): - """ Check if dipole integrals are present. """ - return self.x_dip_mo_ints is not None and \ - self.y_dip_mo_ints is not None and \ - self.z_dip_mo_ints is not None + """Check if dipole integrals are present.""" + return ( + self.x_dip_mo_ints is not None + and self.y_dip_mo_ints is not None + and self.z_dip_mo_ints is not None + ) @property def x_dipole_integrals(self): - """ returns x_dipole_integrals """ + """returns x_dipole_integrals""" return QMolecule.onee_to_spin(self.x_dip_mo_ints, self.x_dip_mo_ints_b) @property def y_dipole_integrals(self): - """ returns y_dipole_integrals """ + """returns y_dipole_integrals""" return QMolecule.onee_to_spin(self.y_dip_mo_ints, self.y_dip_mo_ints_b) @property def z_dipole_integrals(self): - """ returns z_dipole_integrals """ + """returns z_dipole_integrals""" return QMolecule.onee_to_spin(self.z_dip_mo_ints, self.z_dip_mo_ints_b) def Z(self, natom): # pylint: disable=invalid-name - """ Z """ + """Z""" if natom < 0 or natom >= self.num_atoms: raise ValueError("Atom index out of range") return QMolecule.symbols.index(self.atom_symbol[natom].lower().capitalize()) @@ -165,7 +169,9 @@ def core_orbitals(self) -> List[int]: A list of core orbital indices. """ if self.num_atoms is None: - logger.warning("Missing molecule information! Returning empty core orbital list.") + logger.warning( + "Missing molecule information! Returning empty core orbital list." + ) return [] count = 0 for i in range(self.num_atoms): @@ -186,9 +192,9 @@ def core_orbitals(self) -> List[int]: @property def filename(self): - """ returns temp file path """ + """returns temp file path""" if self._filename is None: - file, self._filename = tempfile.mkstemp(suffix='.hdf5') + file, self._filename = tempfile.mkstemp(suffix=".hdf5") os.close(file) return self._filename @@ -200,6 +206,7 @@ def load(self): return with h5py.File(self._filename, "r") as file: + def read_array(name): _data = file[name][...] if _data.dtype == numpy.bool_ and _data.size == 1 and not _data: @@ -216,25 +223,27 @@ def read_dict(name): # A version field was added to save format from version 2 so if # there is no version then we have original (version 1) format version = 1 - if 'version' in file.keys(): + if "version" in file.keys(): data = file["version"][...] version = int(data) if data.dtype.num != 0 else version # Origin driver info data = file["origin_driver/name"][...] - self.origin_driver_name = data[...].tobytes().decode('utf-8') - self.origin_driver_version = '?' + self.origin_driver_name = data[...].tobytes().decode("utf-8") + self.origin_driver_version = "?" if version > 1: data = file["origin_driver/version"][...] - self.origin_driver_version = data[...].tobytes().decode('utf-8') + self.origin_driver_version = data[...].tobytes().decode("utf-8") data = file["origin_driver/config"][...] - self.origin_driver_config = data[...].tobytes().decode('utf-8') + self.origin_driver_config = data[...].tobytes().decode("utf-8") # Energies data = file["energy/hf_energy"][...] self.hf_energy = float(data) if data.dtype.num != 0 else None data = file["energy/nuclear_repulsion_energy"][...] - self.nuclear_repulsion_energy = float(data) if data.dtype.num != 0 else None + self.nuclear_repulsion_energy = ( + float(data) if data.dtype.num != 0 else None + ) if version > 2: self.energy_shift = read_dict("energy/energy_shift") self.x_dip_energy_shift = read_dict("energy/x_dip_energy_shift") @@ -249,20 +258,27 @@ def read_dict(name): # Orbitals try: data = file["orbitals/num_molecular_orbitals"][...] - self.num_molecular_orbitals = int(data) if data.dtype.num != 0 else None + self.num_molecular_orbitals = ( + int(data) if data.dtype.num != 0 else None + ) except KeyError: # try the legacy attribute name data = file["orbitals/num_orbitals"][...] - self.num_molecular_orbitals = int(data) if data.dtype.num != 0 else None + self.num_molecular_orbitals = ( + int(data) if data.dtype.num != 0 else None + ) data = file["orbitals/num_alpha"][...] self.num_alpha = int(data) if data.dtype.num != 0 else None data = file["orbitals/num_beta"][...] self.num_beta = int(data) if data.dtype.num != 0 else None self.mo_coeff = read_array("orbitals/mo_coeff") - self.mo_coeff_b = read_array("orbitals/mo_coeff_B") if version > 1 else None + self.mo_coeff_b = ( + read_array("orbitals/mo_coeff_B") if version > 1 else None + ) self.orbital_energies = read_array("orbitals/orbital_energies") - self.orbital_energies_b = \ + self.orbital_energies_b = ( read_array("orbitals/orbital_energies_B") if version > 1 else None + ) self.mo_occ = read_array("orbitals/mo_occ") if version > 2 else None self.mo_occ_b = read_array("orbitals/mo_occ_B") if version > 2 else None @@ -274,7 +290,7 @@ def read_dict(name): data = file["geometry/num_atoms"][...] self.num_atoms = int(data) if data.dtype.num != 0 else None data = file["geometry/atom_symbol"][...] - self.atom_symbol = [a.decode('utf8') for a in data] + self.atom_symbol = [a.decode("utf8") for a in data] self.atom_xyz = file["geometry/atom_xyz"][...] # 1 and 2 electron integrals in AO basis @@ -286,26 +302,41 @@ def read_dict(name): # 1 and 2 electron integrals in MO basis self.mo_onee_ints = read_array("integrals/mo_onee_ints") - self.mo_onee_ints_b = \ + self.mo_onee_ints_b = ( read_array("integrals/mo_onee_ints_B") if version > 1 else None + ) self.mo_eri_ints = read_array("integrals/mo_eri_ints") - self.mo_eri_ints_bb = \ + self.mo_eri_ints_bb = ( read_array("integrals/mo_eri_ints_BB") if version > 1 else None - self.mo_eri_ints_ba = \ + ) + self.mo_eri_ints_ba = ( read_array("integrals/mo_eri_ints_BA") if version > 1 else None + ) # dipole integrals in AO basis - self.x_dip_ints = read_array("dipole/x_dip_ints") if version > 1 else None - self.y_dip_ints = read_array("dipole/y_dip_ints") if version > 1 else None - self.z_dip_ints = read_array("dipole/z_dip_ints") if version > 1 else None + self.x_dip_ints = ( + read_array("dipole/x_dip_ints") if version > 1 else None + ) + self.y_dip_ints = ( + read_array("dipole/y_dip_ints") if version > 1 else None + ) + self.z_dip_ints = ( + read_array("dipole/z_dip_ints") if version > 1 else None + ) # dipole integrals in MO basis self.x_dip_mo_ints = read_array("dipole/x_dip_mo_ints") - self.x_dip_mo_ints_b = read_array("dipole/x_dip_mo_ints_B") if version > 1 else None + self.x_dip_mo_ints_b = ( + read_array("dipole/x_dip_mo_ints_B") if version > 1 else None + ) self.y_dip_mo_ints = read_array("dipole/y_dip_mo_ints") - self.y_dip_mo_ints_b = read_array("dipole/y_dip_mo_ints_B") if version > 1 else None + self.y_dip_mo_ints_b = ( + read_array("dipole/y_dip_mo_ints_B") if version > 1 else None + ) self.z_dip_mo_ints = read_array("dipole/z_dip_mo_ints") - self.z_dip_mo_ints_b = read_array("dipole/z_dip_mo_ints_B") if version > 1 else None + self.z_dip_mo_ints_b = ( + read_array("dipole/z_dip_mo_ints_B") if version > 1 else None + ) self.nuclear_dipole_moment = file["dipole/nuclear_dipole_moment"][...] self.reverse_dipole_sign = file["dipole/reverse_dipole_sign"][...] @@ -323,6 +354,7 @@ def save(self, file_name=None): self.remove_file() with h5py.File(file, "w") as file: + def create_dataset(group, name, value): def is_float(v): if v is None: @@ -344,26 +376,45 @@ def is_float(v): for k, v in value.items(): sub_group.create_dataset(k, data=v) else: - group.create_dataset(name, data=(value if value is not None else False)) + group.create_dataset( + name, data=(value if value is not None else False) + ) file.create_dataset("version", data=(self.QMOLECULE_VERSION,)) # Driver origin of molecule data g_driver = file.create_group("origin_driver") g_driver.create_dataset( - "name", data=(numpy.string_(self.origin_driver_name) - if self.origin_driver_name is not None else numpy.string_("?"))) + "name", + data=( + numpy.string_(self.origin_driver_name) + if self.origin_driver_name is not None + else numpy.string_("?") + ), + ) g_driver.create_dataset( - "version", data=(numpy.string_(self.origin_driver_version) - if self.origin_driver_version is not None else numpy.string_("?"))) + "version", + data=( + numpy.string_(self.origin_driver_version) + if self.origin_driver_version is not None + else numpy.string_("?") + ), + ) g_driver.create_dataset( - "config", data=(numpy.string_(self.origin_driver_config) - if self.origin_driver_config is not None else numpy.string_("?"))) + "config", + data=( + numpy.string_(self.origin_driver_config) + if self.origin_driver_config is not None + else numpy.string_("?") + ), + ) # Energies g_energy = file.create_group("energy") create_dataset(g_energy, "hf_energy", self.hf_energy) - create_dataset(g_energy, "nuclear_repulsion_energy", self.nuclear_repulsion_energy) + create_dataset( + g_energy, "nuclear_repulsion_energy", self.nuclear_repulsion_energy + ) create_dataset(g_energy, "energy_shift", self.energy_shift) create_dataset(g_energy, "x_dip_energy_shift", self.x_dip_energy_shift) create_dataset(g_energy, "y_dip_energy_shift", self.y_dip_energy_shift) @@ -371,7 +422,9 @@ def is_float(v): # Orbitals g_orbitals = file.create_group("orbitals") - create_dataset(g_orbitals, "num_molecular_orbitals", self.num_molecular_orbitals) + create_dataset( + g_orbitals, "num_molecular_orbitals", self.num_molecular_orbitals + ) create_dataset(g_orbitals, "num_alpha", self.num_alpha) create_dataset(g_orbitals, "num_beta", self.num_beta) create_dataset(g_orbitals, "mo_coeff", self.mo_coeff) @@ -387,8 +440,13 @@ def is_float(v): create_dataset(g_geometry, "multiplicity", self.multiplicity) create_dataset(g_geometry, "num_atoms", self.num_atoms) g_geometry.create_dataset( - "atom_symbol", data=([a.encode('utf8') for a in self.atom_symbol] - if self.atom_symbol is not None else False)) + "atom_symbol", + data=( + [a.encode("utf8") for a in self.atom_symbol] + if self.atom_symbol is not None + else False + ), + ) create_dataset(g_geometry, "atom_xyz", self.atom_xyz) # 1 and 2 electron integrals @@ -415,11 +473,13 @@ def is_float(v): create_dataset(g_dipole, "y_dip_mo_ints_B", self.y_dip_mo_ints_b) create_dataset(g_dipole, "z_dip_mo_ints", self.z_dip_mo_ints) create_dataset(g_dipole, "z_dip_mo_ints_B", self.z_dip_mo_ints_b) - create_dataset(g_dipole, "nuclear_dipole_moment", self.nuclear_dipole_moment) + create_dataset( + g_dipole, "nuclear_dipole_moment", self.nuclear_dipole_moment + ) create_dataset(g_dipole, "reverse_dipole_sign", self.reverse_dipole_sign) def remove_file(self, file_name=None): - """ remove file """ + """remove file""" try: file = self._filename if file_name is None else file_name os.remove(file) @@ -459,21 +519,21 @@ def twoeints2mo(ints, moc): eri_mo = numpy.zeros((dim, dim, dim, dim)) for a_i in range(dim): - temp1 = numpy.einsum('i,i...->...', moc[:, a_i], ints) + temp1 = numpy.einsum("i,i...->...", moc[:, a_i], ints) for b_i in range(dim): - temp2 = numpy.einsum('j,j...->...', moc[:, b_i], temp1) - temp3 = numpy.einsum('kc,k...->...c', moc, temp2) - eri_mo[a_i, b_i, :, :] = numpy.einsum('ld,l...c->...cd', moc, temp3) + temp2 = numpy.einsum("j,j...->...", moc[:, b_i], temp1) + temp3 = numpy.einsum("kc,k...->...c", moc, temp2) + eri_mo[a_i, b_i, :, :] = numpy.einsum("ld,l...c->...cd", moc, temp3) return eri_mo @staticmethod def twoeints2mo_general(ints, moc1, moc2, moc3, moc4): - """ twoeints2mo_general """ - return numpy.einsum('pqrs,pi,qj,rk,sl->ijkl', ints, moc1, moc2, moc3, moc4) + """twoeints2mo_general""" + return numpy.einsum("pqrs,pi,qj,rk,sl->ijkl", ints, moc1, moc2, moc3, moc4) @staticmethod - def onee_to_spin(mohij, mohij_b=None, threshold=1E-12): + def onee_to_spin(mohij, mohij_b=None, threshold=1e-12): """Convert one-body MO integrals to spin orbital basis Takes one body integrals in molecular orbital basis and returns @@ -492,14 +552,14 @@ def onee_to_spin(mohij, mohij_b=None, threshold=1E-12): # The number of spin orbitals is twice the number of orbitals norbs = mohij.shape[0] - nspin_orbs = 2*norbs + nspin_orbs = 2 * norbs # One electron terms moh1_qubit = numpy.zeros([nspin_orbs, nspin_orbs]) for p in range(nspin_orbs): # pylint: disable=invalid-name for q in range(nspin_orbs): - spinp = int(p/norbs) - spinq = int(q/norbs) + spinp = int(p / norbs) + spinq = int(q / norbs) if spinp % 2 != spinq % 2: continue ints = mohij if spinp == 0 else mohij_b @@ -511,7 +571,7 @@ def onee_to_spin(mohij, mohij_b=None, threshold=1E-12): return moh1_qubit @staticmethod - def twoe_to_spin(mohijkl, mohijkl_bb=None, mohijkl_ba=None, threshold=1E-12): + def twoe_to_spin(mohijkl, mohijkl_bb=None, mohijkl_ba=None, threshold=1e-12): """Convert two-body MO integrals to spin orbital basis Takes two body integrals in molecular orbital basis and returns @@ -537,7 +597,7 @@ def twoe_to_spin(mohijkl, mohijkl_bb=None, mohijkl_ba=None, threshold=1E-12): # The number of spin orbitals is twice the number of orbitals norbs = mohijkl.shape[0] - nspin_orbs = 2*norbs + nspin_orbs = 2 * norbs # The spin orbitals are mapped in the following way: # Orbital zero, spin up mapped to qubit 0 @@ -557,10 +617,10 @@ def twoe_to_spin(mohijkl, mohijkl_bb=None, mohijkl_ba=None, threshold=1E-12): for q in range(nspin_orbs): for r in range(nspin_orbs): for s in range(nspin_orbs): # pylint: disable=invalid-name - spinp = int(p/norbs) - spinq = int(q/norbs) - spinr = int(r/norbs) - spins = int(s/norbs) + spinp = int(p / norbs) + spinq = int(q / norbs) + spinr = int(r / norbs) + spins = int(s / norbs) if spinp != spins: continue if spinq != spinr: @@ -574,32 +634,138 @@ def twoe_to_spin(mohijkl, mohijkl_bb=None, mohijkl_ba=None, threshold=1E-12): orbr = int(r % norbs) orbs = int(s % norbs) if abs(ints[orbp, orbq, orbr, orbs]) > threshold: - moh2_qubit[p, q, r, s] = -0.5*ints[orbp, orbq, orbr, orbs] + moh2_qubit[p, q, r, s] = -0.5 * ints[orbp, orbq, orbr, orbs] return moh2_qubit symbols = [ # pylint: disable=bad-option-value,bad-whitespace - '_', - 'H', 'He', - 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', - 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', - 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', - 'Ge', 'As', 'Se', 'Br', 'Kr', - 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', - 'Sn', 'Sb', 'Te', 'I', 'Xe', - 'Cs', 'Ba', - 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', - 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', - 'Fr', 'Ra', - 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', - 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og'] + "_", + "H", + "He", + "Li", + "Be", + "B", + "C", + "N", + "O", + "F", + "Ne", + "Na", + "Mg", + "Al", + "Si", + "P", + "S", + "Cl", + "Ar", + "K", + "Ca", + "Sc", + "Ti", + "V", + "Cr", + "Mn", + "Fe", + "Co", + "Ni", + "Cu", + "Zn", + "Ga", + "Ge", + "As", + "Se", + "Br", + "Kr", + "Rb", + "Sr", + "Y", + "Zr", + "Nb", + "Mo", + "Tc", + "Ru", + "Rh", + "Pd", + "Ag", + "Cd", + "In", + "Sn", + "Sb", + "Te", + "I", + "Xe", + "Cs", + "Ba", + "La", + "Ce", + "Pr", + "Nd", + "Pm", + "Sm", + "Eu", + "Gd", + "Tb", + "Dy", + "Ho", + "Er", + "Tm", + "Yb", + "Lu", + "Hf", + "Ta", + "W", + "Re", + "Os", + "Ir", + "Pt", + "Au", + "Hg", + "Tl", + "Pb", + "Bi", + "Po", + "At", + "Rn", + "Fr", + "Ra", + "Ac", + "Th", + "Pa", + "U", + "Np", + "Pu", + "Am", + "Cm", + "Bk", + "Cf", + "Es", + "Fm", + "Md", + "No", + "Lr", + "Rf", + "Db", + "Sg", + "Bh", + "Hs", + "Mt", + "Ds", + "Rg", + "Cn", + "Nh", + "Fl", + "Mc", + "Lv", + "Ts", + "Og", + ] BOHR = 0.52917721092 # No of Angstroms in Bohr (from 2010 CODATA) - DEBYE = 0.393430307 # No ea0 in Debye. Use to convert our dipole moment numbers to Debye + DEBYE = 0.393430307 # No ea0 in Debye. Use to convert our dipole moment numbers to Debye def log(self): - """ log properties """ + """log properties""" if not logger.isEnabledFor(logging.INFO): return opts = numpy.get_printoptions() @@ -609,25 +775,36 @@ def log(self): # Originating driver name & config if set if self.origin_driver_name and self.origin_driver_name != "?": logger.info("Originating driver name: %s", self.origin_driver_name) - logger.info("Originating driver version: %s", self.origin_driver_version) - logger.info("Originating driver config:\n%s", self.origin_driver_config[:-1]) + logger.info( + "Originating driver version: %s", self.origin_driver_version + ) + logger.info( + "Originating driver config:\n%s", self.origin_driver_config[:-1] + ) logger.info("Computed Hartree-Fock energy: %s", self.hf_energy) logger.info("Nuclear repulsion energy: %s", self.nuclear_repulsion_energy) logger.info("Energy shift due to transformations: %s", self.energy_shift) if None not in (self.hf_energy, self.nuclear_repulsion_energy): - logger.info("One and two electron Hartree-Fock energy: %s", - self.hf_energy - self.nuclear_repulsion_energy) + logger.info( + "One and two electron Hartree-Fock energy: %s", + self.hf_energy - self.nuclear_repulsion_energy, + ) logger.info("Number of orbitals is %s", self.num_molecular_orbitals) logger.info("%s alpha and %s beta electrons", self.num_alpha, self.num_beta) - logger.info("Molecule comprises %s atoms and in xyz format is ::", self.num_atoms) + logger.info( + "Molecule comprises %s atoms and in xyz format is ::", self.num_atoms + ) logger.info(" %s, %s", self.molecular_charge, self.multiplicity) if self.num_atoms is not None: for n in range(0, self.num_atoms): - logger.info(" %2s %s, %s, %s", self.atom_symbol[n], - self.atom_xyz[n][0] * QMolecule.BOHR, - self.atom_xyz[n][1] * QMolecule.BOHR, - self.atom_xyz[n][2] * QMolecule.BOHR) + logger.info( + " %2s %s, %s, %s", + self.atom_symbol[n], + self.atom_xyz[n][0] * QMolecule.BOHR, + self.atom_xyz[n][1] * QMolecule.BOHR, + self.atom_xyz[n][2] * QMolecule.BOHR, + ) if self.mo_coeff is not None: logger.info("MO coefficients A: %s", self.mo_coeff.shape) logger.debug("\n%s", self.mo_coeff) @@ -672,10 +849,14 @@ def log(self): logger.info("Two body ERI MO AA integrals: %s", self.mo_eri_ints.shape) logger.debug("\n%s", self.mo_eri_ints) if self.mo_eri_ints_bb is not None: - logger.info("Two body ERI MO BB integrals: %s", self.mo_eri_ints_bb.shape) + logger.info( + "Two body ERI MO BB integrals: %s", self.mo_eri_ints_bb.shape + ) logger.debug("\n%s", self.mo_eri_ints_bb) if self.mo_eri_ints_ba is not None: - logger.info("Two body ERI MO BA integrals: %s", self.mo_eri_ints_ba.shape) + logger.info( + "Two body ERI MO BA integrals: %s", self.mo_eri_ints_ba.shape + ) logger.debug("\n%s", self.mo_eri_ints_ba) if self.x_dip_ints is not None: @@ -710,8 +891,10 @@ def log(self): if self.nuclear_dipole_moment is not None: logger.info("Nuclear dipole moment: %s", self.nuclear_dipole_moment) if self.reverse_dipole_sign is not None: - logger.info("Reversal of electronic dipole moment sign needed: %s", - self.reverse_dipole_sign) + logger.info( + "Reversal of electronic dipole moment sign needed: %s", + self.reverse_dipole_sign, + ) logger.info("Core orbitals list %s", self.core_orbitals) finally: diff --git a/qiskit_nature/drivers/units_type.py b/qiskit_nature/drivers/units_type.py index 6884d83fa5..aea01c8759 100644 --- a/qiskit_nature/drivers/units_type.py +++ b/qiskit_nature/drivers/units_type.py @@ -18,6 +18,7 @@ class UnitsType(Enum): - """ Units Type Enum """ - ANGSTROM = 'Angstrom' - BOHR = 'Bohr' + """Units Type Enum""" + + ANGSTROM = "Angstrom" + BOHR = "Bohr" diff --git a/qiskit_nature/exceptions.py b/qiskit_nature/exceptions.py index 0bfe3cdd19..9611541233 100644 --- a/qiskit_nature/exceptions.py +++ b/qiskit_nature/exceptions.py @@ -17,4 +17,5 @@ class QiskitNatureError(QiskitError): """Class for errors returned by Qiskit's Nature module.""" + pass diff --git a/qiskit_nature/mappers/second_quantization/__init__.py b/qiskit_nature/mappers/second_quantization/__init__.py index 69077750d6..1e9f0e2ddc 100644 --- a/qiskit_nature/mappers/second_quantization/__init__.py +++ b/qiskit_nature/mappers/second_quantization/__init__.py @@ -71,13 +71,13 @@ from .vibrational_mapper import VibrationalMapper __all__ = [ - 'BravyiKitaevMapper', - 'DirectMapper', - 'FermionicMapper', - 'JordanWignerMapper', - 'LinearMapper', - 'ParityMapper', - 'QubitMapper', - 'SpinMapper', - 'VibrationalMapper', + "BravyiKitaevMapper", + "DirectMapper", + "FermionicMapper", + "JordanWignerMapper", + "LinearMapper", + "ParityMapper", + "QubitMapper", + "SpinMapper", + "VibrationalMapper", ] diff --git a/qiskit_nature/mappers/second_quantization/bravyi_kitaev_mapper.py b/qiskit_nature/mappers/second_quantization/bravyi_kitaev_mapper.py index 9a18eb3b77..245bb9efb1 100644 --- a/qiskit_nature/mappers/second_quantization/bravyi_kitaev_mapper.py +++ b/qiskit_nature/mappers/second_quantization/bravyi_kitaev_mapper.py @@ -24,7 +24,7 @@ class BravyiKitaevMapper(FermionicMapper): - """The Bravyi-Kitaev fermion-to-qubit mapping. """ + """The Bravyi-Kitaev fermion-to-qubit mapping.""" def map(self, second_q_op: FermionicOp) -> PauliSumOp: @@ -49,8 +49,9 @@ def parity_set(j, n): if j < n / 2: indices = np.append(indices, parity_set(j, n / 2)) else: - indices = np.append(indices, np.append( - parity_set(j - n / 2, n / 2) + n / 2, n / 2 - 1)) + indices = np.append( + indices, np.append(parity_set(j - n / 2, n / 2) + n / 2, n / 2 - 1) + ) return indices def update_set(j, n): @@ -68,8 +69,7 @@ def update_set(j, n): if n % 2 != 0: return indices if j < n / 2: - indices = np.append(indices, np.append( - n - 1, update_set(j, n / 2))) + indices = np.append(indices, np.append(n - 1, update_set(j, n / 2))) else: indices = np.append(indices, update_set(j - n / 2, n / 2) + n / 2) return indices @@ -93,8 +93,9 @@ def flip_set(j, n): elif n / 2 <= j < n - 1: indices = np.append(indices, flip_set(j - n / 2, n / 2) + n / 2) else: - indices = np.append(np.append(indices, flip_set( - j - n / 2, n / 2) + n / 2), n / 2 - 1) + indices = np.append( + np.append(indices, flip_set(j - n / 2, n / 2) + n / 2), n / 2 - 1 + ) return indices pauli_table = [] @@ -127,12 +128,15 @@ def flip_set(j, n): remainder_sets.append(np.setdiff1d(parity_sets[j], flip_sets[j])) - update_pauli.append(Pauli((np.zeros(nmodes, dtype=bool), - np.zeros(nmodes, dtype=bool)))) - parity_pauli.append(Pauli((np.zeros(nmodes, dtype=bool), - np.zeros(nmodes, dtype=bool)))) - remainder_pauli.append(Pauli((np.zeros(nmodes, dtype=bool), - np.zeros(nmodes, dtype=bool)))) + update_pauli.append( + Pauli((np.zeros(nmodes, dtype=bool), np.zeros(nmodes, dtype=bool))) + ) + parity_pauli.append( + Pauli((np.zeros(nmodes, dtype=bool), np.zeros(nmodes, dtype=bool))) + ) + remainder_pauli.append( + Pauli((np.zeros(nmodes, dtype=bool), np.zeros(nmodes, dtype=bool))) + ) for k in range(nmodes): if np.in1d(k, update_sets[j]): update_pauli[j].x[k] = True @@ -146,7 +150,11 @@ def flip_set(j, n): y_j = Pauli((np.zeros(nmodes, dtype=bool), np.zeros(nmodes, dtype=bool))) y_j.z[j] = True y_j.x[j] = True - pauli_table.append((parity_pauli[j] & x_j & update_pauli[j], - remainder_pauli[j] & y_j & update_pauli[j])) + pauli_table.append( + ( + parity_pauli[j] & x_j & update_pauli[j], + remainder_pauli[j] & y_j & update_pauli[j], + ) + ) return QubitMapper.mode_based_mapping(second_q_op, pauli_table) diff --git a/qiskit_nature/mappers/second_quantization/fermionic_mapper.py b/qiskit_nature/mappers/second_quantization/fermionic_mapper.py index 62b40f59f9..f626cb557f 100644 --- a/qiskit_nature/mappers/second_quantization/fermionic_mapper.py +++ b/qiskit_nature/mappers/second_quantization/fermionic_mapper.py @@ -21,7 +21,7 @@ class FermionicMapper(QubitMapper): - """ Mapper of Fermionic Operator to Qubit Operator """ + """Mapper of Fermionic Operator to Qubit Operator""" @abstractmethod def map(self, second_q_op: FermionicOp) -> PauliSumOp: diff --git a/qiskit_nature/mappers/second_quantization/jordan_wigner_mapper.py b/qiskit_nature/mappers/second_quantization/jordan_wigner_mapper.py index b9deaea422..b4bfb920a1 100644 --- a/qiskit_nature/mappers/second_quantization/jordan_wigner_mapper.py +++ b/qiskit_nature/mappers/second_quantization/jordan_wigner_mapper.py @@ -24,7 +24,7 @@ class JordanWignerMapper(FermionicMapper): - """The Jordan-Wigner fermion-to-qubit mapping. """ + """The Jordan-Wigner fermion-to-qubit mapping.""" def map(self, second_q_op: FermionicOp) -> PauliSumOp: diff --git a/qiskit_nature/mappers/second_quantization/linear_mapper.py b/qiskit_nature/mappers/second_quantization/linear_mapper.py index 6879c45f2b..4200432f48 100644 --- a/qiskit_nature/mappers/second_quantization/linear_mapper.py +++ b/qiskit_nature/mappers/second_quantization/linear_mapper.py @@ -27,7 +27,7 @@ class LinearMapper(SpinMapper): - """The Linear spin-to-qubit mapping. """ + """The Linear spin-to-qubit mapping.""" def map(self, second_q_op: SpinOp) -> PauliSumOp: @@ -40,7 +40,9 @@ def map(self, second_q_op: SpinOp) -> PauliSumOp: operatorlist: List[PauliSumOp] = [] - for n_x, n_y, n_z in zip(second_q_op.x[idx], second_q_op.y[idx], second_q_op.z[idx]): + for n_x, n_y, n_z in zip( + second_q_op.x[idx], second_q_op.y[idx], second_q_op.z[idx] + ): operator_on_spin_i: List[PauliSumOp] = [] @@ -60,7 +62,9 @@ def map(self, second_q_op: SpinOp) -> PauliSumOp: ) if np.any([n_x, n_y, n_z]) > 0: - single_operator_on_spin_i = reduce(operator.matmul, operator_on_spin_i) + single_operator_on_spin_i = reduce( + operator.matmul, operator_on_spin_i + ) operatorlist.append(single_operator_on_spin_i.reduce()) else: @@ -94,47 +98,55 @@ def _linear_encoding(self, spin: Union[Fraction, float]) -> List[PauliSumOp]: nqubits = dspin # quick functions to generate a pauli with X / Y / Z at location `i` - pauli_id = Pauli('I' * nqubits) + pauli_id = Pauli("I" * nqubits) def pauli_x(i): - return Pauli('I' * i + 'X' + 'I' * (nqubits - i - 1)) + return Pauli("I" * i + "X" + "I" * (nqubits - i - 1)) def pauli_y(i): - return Pauli('I' * i + 'Y' + 'I' * (nqubits - i - 1)) + return Pauli("I" * i + "Y" + "I" * (nqubits - i - 1)) def pauli_z(i): - return Pauli('I' * i + 'Z' + 'I' * (nqubits - i - 1)) + return Pauli("I" * i + "Z" + "I" * (nqubits - i - 1)) # 1. build the non-diagonal X operator x_summands = [] for i, coeff in enumerate(np.diag(SpinOp("X", spin=spin).to_matrix(), 1)): - x_summands.append(PauliSumOp( - coeff / 2. * SparsePauliOp(pauli_x(i).dot(pauli_x(i + 1))) + - coeff / 2. * SparsePauliOp(pauli_y(i).dot(pauli_y(i + 1))) - )) + x_summands.append( + PauliSumOp( + coeff / 2.0 * SparsePauliOp(pauli_x(i).dot(pauli_x(i + 1))) + + coeff / 2.0 * SparsePauliOp(pauli_y(i).dot(pauli_y(i + 1))) + ) + ) spin_op_encoding.append(reduce(operator.add, x_summands)) # 2. build the non-diagonal Y operator y_summands = [] for i, coeff in enumerate(np.diag(SpinOp("Y", spin=spin).to_matrix(), 1)): - y_summands.append(PauliSumOp( - -1j * coeff / 2. * SparsePauliOp(pauli_x(i).dot(pauli_y(i + 1))) + - 1j * coeff / 2. * SparsePauliOp(pauli_y(i).dot(pauli_x(i + 1))) - )) + y_summands.append( + PauliSumOp( + -1j * coeff / 2.0 * SparsePauliOp(pauli_x(i).dot(pauli_y(i + 1))) + + 1j * coeff / 2.0 * SparsePauliOp(pauli_y(i).dot(pauli_x(i + 1))) + ) + ) spin_op_encoding.append(reduce(operator.add, y_summands)) # 3. build the diagonal Z z_summands = [] for i, coeff in enumerate(np.diag(SpinOp("Z", spin=spin).to_matrix())): # get the first upper diagonal of coeff. - z_summands.append(PauliSumOp(coeff / 2. * SparsePauliOp(pauli_z(i)) + - coeff / 2. * SparsePauliOp(pauli_id))) + z_summands.append( + PauliSumOp( + coeff / 2.0 * SparsePauliOp(pauli_z(i)) + + coeff / 2.0 * SparsePauliOp(pauli_id) + ) + ) z_operator = reduce(operator.add, z_summands) spin_op_encoding.append(z_operator) # 4. add the identity operator - spin_op_encoding.append(PauliSumOp(1. * SparsePauliOp(pauli_id))) + spin_op_encoding.append(PauliSumOp(1.0 * SparsePauliOp(pauli_id))) # return the lookup table for the transformed XYZI operators return spin_op_encoding diff --git a/qiskit_nature/mappers/second_quantization/parity_mapper.py b/qiskit_nature/mappers/second_quantization/parity_mapper.py index fde4723d19..6668040192 100644 --- a/qiskit_nature/mappers/second_quantization/parity_mapper.py +++ b/qiskit_nature/mappers/second_quantization/parity_mapper.py @@ -25,7 +25,7 @@ class ParityMapper(FermionicMapper): - """The Parity fermion-to-qubit mapping. """ + """The Parity fermion-to-qubit mapping.""" def __init__(self): super().__init__(allows_two_qubit_reduction=True) diff --git a/qiskit_nature/mappers/second_quantization/qubit_mapper.py b/qiskit_nature/mappers/second_quantization/qubit_mapper.py index 671c94e297..0ddb9afed2 100644 --- a/qiskit_nature/mappers/second_quantization/qubit_mapper.py +++ b/qiskit_nature/mappers/second_quantization/qubit_mapper.py @@ -60,8 +60,9 @@ def map(self, second_q_op: SecondQuantizedOp) -> PauliSumOp: raise NotImplementedError() @staticmethod - def mode_based_mapping(second_q_op: SecondQuantizedOp, - pauli_table: List[Tuple[Pauli, Pauli]]) -> PauliSumOp: + def mode_based_mapping( + second_q_op: SecondQuantizedOp, pauli_table: List[Tuple[Pauli, Pauli]] + ) -> PauliSumOp: """Utility method to map a `SecondQuantizedOp` to a `PauliSumOp` using a pauli table. Args: @@ -77,10 +78,13 @@ def mode_based_mapping(second_q_op: SecondQuantizedOp, """ nmodes = len(pauli_table) if nmodes != second_q_op.register_length: - raise QiskitNatureError(f"Pauli table len {nmodes} does not match" - f"operator register length {second_q_op.register_length}") + raise QiskitNatureError( + f"Pauli table len {nmodes} does not match" + f"operator register length {second_q_op.register_length}" + ) # 0. Some utilities + def times_creation_op(position, pauli_table): # The creation operator is given by 0.5*(X + 1j*Y) real_part = SparsePauliOp(pauli_table[position][0], coeffs=[0.5]) diff --git a/qiskit_nature/mappers/second_quantization/spin_mapper.py b/qiskit_nature/mappers/second_quantization/spin_mapper.py index 337235953b..5700728d37 100644 --- a/qiskit_nature/mappers/second_quantization/spin_mapper.py +++ b/qiskit_nature/mappers/second_quantization/spin_mapper.py @@ -21,7 +21,7 @@ class SpinMapper(QubitMapper): - """ Mapper of Spin Operator to Qubit Operator """ + """Mapper of Spin Operator to Qubit Operator""" @abstractmethod def map(self, second_q_op: SpinOp) -> PauliSumOp: diff --git a/qiskit_nature/mappers/second_quantization/vibrational_mapper.py b/qiskit_nature/mappers/second_quantization/vibrational_mapper.py index b03dc795e7..17a74b8e3c 100644 --- a/qiskit_nature/mappers/second_quantization/vibrational_mapper.py +++ b/qiskit_nature/mappers/second_quantization/vibrational_mapper.py @@ -21,7 +21,7 @@ class VibrationalMapper(QubitMapper): - """ Mapper of Vibrational Operator to Qubit Operator """ + """Mapper of Vibrational Operator to Qubit Operator""" @abstractmethod def map(self, second_q_op: VibrationalOp) -> PauliSumOp: diff --git a/qiskit_nature/operators/second_quantization/__init__.py b/qiskit_nature/operators/second_quantization/__init__.py index f07878f56e..60c50a7161 100644 --- a/qiskit_nature/operators/second_quantization/__init__.py +++ b/qiskit_nature/operators/second_quantization/__init__.py @@ -34,8 +34,8 @@ from .vibrational_op import VibrationalOp __all__ = [ - 'FermionicOp', - 'SecondQuantizedOp', - 'SpinOp', - 'VibrationalOp', + "FermionicOp", + "SecondQuantizedOp", + "SpinOp", + "VibrationalOp", ] diff --git a/qiskit_nature/operators/second_quantization/fermionic_op.py b/qiskit_nature/operators/second_quantization/fermionic_op.py index 63e45d8279..7131f721b5 100644 --- a/qiskit_nature/operators/second_quantization/fermionic_op.py +++ b/qiskit_nature/operators/second_quantization/fermionic_op.py @@ -165,10 +165,14 @@ def __init__( self._labels: List[str] if not isinstance(data, (tuple, list, str)): - raise TypeError(f"Type of data must be str, tuple, or list, not {type(data)}.") + raise TypeError( + f"Type of data must be str, tuple, or list, not {type(data)}." + ) if isinstance(data, tuple): - if not isinstance(data[0], str) or not isinstance(data[1], (int, float, complex)): + if not isinstance(data[0], str) or not isinstance( + data[1], (int, float, complex) + ): raise TypeError( f"Data tuple must be (str, number), not ({type(data[0])}, {type(data[1])})." ) @@ -191,34 +195,46 @@ def __init__( if not all(len(label) == self._register_length for label in labels): raise ValueError("Lengths of strings of label are different.") label_pattern = re.compile(r"^[I\+\-NE]+$") - invalid_labels = [label for label in labels if not label_pattern.match(label)] + invalid_labels = [ + label for label in labels if not label_pattern.match(label) + ] if invalid_labels: - raise ValueError(f"Invalid labels for dense labels are given: {invalid_labels}") + raise ValueError( + f"Invalid labels for dense labels are given: {invalid_labels}" + ) self._labels = list(labels) else: # Sparse label validate_min("register_length", register_length, 1) self._register_length = register_length label_pattern = re.compile(r"^[I\+\-NE]_\d+$") invalid_labels = [ - label for label in labels if not all(label_pattern.match(l) for l in label.split()) + label + for label in labels + if not all(label_pattern.match(lb) for lb in label.split()) ] if invalid_labels: - raise ValueError(f"Invalid labels for sparse labels are given: {invalid_labels}") + raise ValueError( + f"Invalid labels for sparse labels are given: {invalid_labels}" + ) list_label = [["I"] * self._register_length for _ in labels] for term, label in enumerate(labels): prev_index: Optional[int] = None for split_label in label.split(): op_label, index_str = split_label.split("_", 1) index = int(index_str) - validate_range_exclusive_max("index", index, 0, self._register_length) + validate_range_exclusive_max( + "index", index, 0, self._register_length + ) if prev_index is not None and prev_index > index: - raise ValueError("Indices of labels must be in ascending order.") + raise ValueError( + "Indices of labels must be in ascending order." + ) if list_label[term][index] != "I": raise ValueError(f"Duplicate index {index} is given.") list_label[term][index] = op_label prev_index = index - self._labels = ["".join(l) for l in list_label] + self._labels = ["".join(lb) for lb in list_label] def __repr__(self) -> str: if len(self) == 1: @@ -232,7 +248,9 @@ def __str__(self) -> str: if len(self) == 1: label, coeff = self.to_list()[0] return f"{label} * {coeff}" - return " " + "\n+ ".join([f"{label} * {coeff}" for label, coeff in self.to_list()]) + return " " + "\n+ ".join( + [f"{label} * {coeff}" for label, coeff in self.to_list()] + ) def __len__(self): return len(self._labels) @@ -307,7 +325,9 @@ def compose(self, other: "FermionicOp") -> "FermionicOp": @classmethod def _single_mul(cls, label1: str, label2: str) -> Tuple[str, complex]: if len(label1) != len(label2): - raise QiskitNatureError("Operators act on Fermion Registers of different length") + raise QiskitNatureError( + "Operators act on Fermion Registers of different length" + ) new_label = [] sign = 1 @@ -349,7 +369,10 @@ def add(self, other: "FermionicOp") -> "FermionicOp": return FermionicOp( list( - zip(self._labels + other._labels, np.hstack((self._coeffs, other._coeffs)).tolist()) + zip( + self._labels + other._labels, + np.hstack((self._coeffs, other._coeffs)).tolist(), + ) ) ) @@ -380,9 +403,13 @@ def adjoint(self) -> "FermionicOp": label_list.append("".join(daggered_label)) coeff_list.append(conjugated_coeff) - return FermionicOp(list(zip(label_list, np.array(coeff_list, dtype=np.complex128)))) + return FermionicOp( + list(zip(label_list, np.array(coeff_list, dtype=np.complex128))) + ) - def reduce(self, atol: Optional[float] = None, rtol: Optional[float] = None) -> "FermionicOp": + def reduce( + self, atol: Optional[float] = None, rtol: Optional[float] = None + ) -> "FermionicOp": if atol is None: atol = self.atol if rtol is None: @@ -393,8 +420,12 @@ def reduce(self, atol: Optional[float] = None, rtol: Optional[float] = None) -> for i, val in zip(indices, self._coeffs): coeff_list[i] += val non_zero = [ - i for i, v in enumerate(coeff_list) if not np.isclose(v, 0, atol=atol, rtol=rtol) + i + for i, v in enumerate(coeff_list) + if not np.isclose(v, 0, atol=atol, rtol=rtol) ] if not non_zero: return FermionicOp(("I" * self.register_length, 0)) - return FermionicOp(list(zip(label_list[non_zero].tolist(), coeff_list[non_zero]))) + return FermionicOp( + list(zip(label_list[non_zero].tolist(), coeff_list[non_zero])) + ) diff --git a/qiskit_nature/operators/second_quantization/qubit_converter.py b/qiskit_nature/operators/second_quantization/qubit_converter.py index 31083054b8..86776c082b 100644 --- a/qiskit_nature/operators/second_quantization/qubit_converter.py +++ b/qiskit_nature/operators/second_quantization/qubit_converter.py @@ -32,7 +32,7 @@ class QubitConverter: - """ **DEPRECATED** A converter from Second-Quantized to Qubit Operators. + """**DEPRECATED** A converter from Second-Quantized to Qubit Operators. The QubitConverter was moved to `converters.second_quantization` package. @@ -53,10 +53,12 @@ class QubitConverter: be passed in on :meth:`convert` which will override this value should both be given. """ - def __init__(self, - mapper: QubitMapper, - two_qubit_reduction: bool = False, - z2symmetry_reduction: Optional[Union[str, List[int]]] = None): + def __init__( + self, + mapper: QubitMapper, + two_qubit_reduction: bool = False, + z2symmetry_reduction: Optional[Union[str, List[int]]] = None, + ): """ Args: @@ -73,11 +75,14 @@ def __init__(self, sector can be provided (a list of int of values -1, and 1). The default is None meaning no symmetry reduction is done. """ - warnings.warn('This QubitConverter is deprecated as of 0.1.0, ' - 'and will be removed no earlier than 3 months after the release. ' - 'You should use the qiskit_nature.converters.second_quantization ' - 'QubitConverter as a direct replacement instead.', - DeprecationWarning, stacklevel=2) + warnings.warn( + "This QubitConverter is deprecated as of 0.1.0, " + "and will be removed no earlier than 3 months after the release. " + "You should use the qiskit_nature.converters.second_quantization " + "QubitConverter as a direct replacement instead.", + DeprecationWarning, + stacklevel=2, + ) self._mapper: QubitMapper = mapper self._two_qubit_reduction: bool = two_qubit_reduction @@ -120,17 +125,24 @@ def z2symmetry_reduction(self) -> Optional[Union[str, List[int]]]: return self._z2symmetry_reduction @z2symmetry_reduction.setter - def z2symmetry_reduction(self, z2symmetry_reduction: Optional[Union[str, List[int]]]) -> None: + def z2symmetry_reduction( + self, z2symmetry_reduction: Optional[Union[str, List[int]]] + ) -> None: """Set z2symmetry_reduction""" if z2symmetry_reduction is not None: if isinstance(z2symmetry_reduction, str): - if z2symmetry_reduction != 'auto': - raise ValueError("The only string-like option for z2symmetry_reduction is " - "'auto', not {}".format(z2symmetry_reduction)) + if z2symmetry_reduction != "auto": + raise ValueError( + "The only string-like option for z2symmetry_reduction is " + "'auto', not {}".format(z2symmetry_reduction) + ) elif not np.all(np.isin(z2symmetry_reduction, [-1, 1])): - raise ValueError('z2symmetry_reduction tapering values list must ' - 'contain -1\'s and/or 1\'s only but was {}'. - format(z2symmetry_reduction)) + raise ValueError( + "z2symmetry_reduction tapering values list must " + "contain -1's and/or 1's only but was {}".format( + z2symmetry_reduction + ) + ) self._z2symmetry_reduction = z2symmetry_reduction @@ -152,10 +164,12 @@ def z2symmetries(self) -> Z2Symmetries: """ return copy.deepcopy(self._z2symmetries) - def convert(self, second_q_op: SecondQuantizedOp, - num_particles: Optional[Tuple[int, int]] = None, - sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None - ) -> PauliSumOp: + def convert( + self, + second_q_op: SecondQuantizedOp, + num_particles: Optional[Tuple[int, int]] = None, + sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None, + ) -> PauliSumOp: """ Map the given second quantized operator to a qubit operators. Also it will carry out z2 symmetry reduction on the qubit operators if z2symmetry_reduction has @@ -183,19 +197,22 @@ def convert(self, second_q_op: SecondQuantizedOp, return tapered_op - def force_match(self, num_particles: Optional[Tuple[int, int]] = None, - z2symmetries: Optional[Z2Symmetries] = None) -> None: - """ This is for advanced use where :meth:`convert` may not have been called or the - converter should be used to taper to some external characteristics to be matched - when using :meth:`convert_match`. Parameters passed here, when not None, - will override any values stored from :meth:`convert`. + def force_match( + self, + num_particles: Optional[Tuple[int, int]] = None, + z2symmetries: Optional[Z2Symmetries] = None, + ) -> None: + """This is for advanced use where :meth:`convert` may not have been called or the + converter should be used to taper to some external characteristics to be matched + when using :meth:`convert_match`. Parameters passed here, when not None, + will override any values stored from :meth:`convert`. - Args: - num_particles: The number or particles pertaining to two qubit reduction - z2symmetries: Z2Symmetry information for tapering + Args: + num_particles: The number or particles pertaining to two qubit reduction + z2symmetries: Z2Symmetry information for tapering - Raises: - ValueError: If format of Z2Symmetry tapering values is invalid + Raises: + ValueError: If format of Z2Symmetry tapering values is invalid """ if num_particles is not None: self._num_particles = num_particles @@ -203,19 +220,25 @@ def force_match(self, num_particles: Optional[Tuple[int, int]] = None, if z2symmetries is not None: if not z2symmetries.is_empty(): if len(z2symmetries.tapering_values) != len(z2symmetries.sq_list): - raise ValueError(f'Z2Symmetries tapering value length was ' - f'{len(z2symmetries.tapering_values)} but expected ' - f'{len(z2symmetries.sq_list)}.') + raise ValueError( + f"Z2Symmetries tapering value length was " + f"{len(z2symmetries.tapering_values)} but expected " + f"{len(z2symmetries.sq_list)}." + ) if not np.all(np.isin(z2symmetries.tapering_values, [-1, 1])): - raise ValueError(f'Z2Symmetries values list must contain only ' - f'-1\'s and/or 1\'s but was {z2symmetries.tapering_values}.') + raise ValueError( + f"Z2Symmetries values list must contain only " + f"-1's and/or 1's but was {z2symmetries.tapering_values}." + ) self._z2symmetries = z2symmetries - def convert_match(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]], - suppress_none: bool = False - ) -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: - """ Convert further operators to match that done in :meth:`convert`, or as set by + def convert_match( + self, + second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]], + suppress_none: bool = False, + ) -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: + """Convert further operators to match that done in :meth:`convert`, or as set by :meth:`force_match`. Args: @@ -241,8 +264,10 @@ def convert_match(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuanti suppress_none = False # When only a single op we will return None back qubit_ops = [self._map(second_q_op) for second_q_op in second_q_ops] - reduced_ops = [self._two_qubit_reduce(qubit_op, self._num_particles) - for qubit_op in qubit_ops] + reduced_ops = [ + self._two_qubit_reduce(qubit_op, self._num_particles) + for qubit_op in qubit_ops + ] tapered_ops = self._symmetry_reduce(reduced_ops, suppress_none) if wrapped: @@ -250,9 +275,10 @@ def convert_match(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuanti return tapered_ops - def map(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]]) \ - -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: - """ A convenience method to map second quantized operators based on current mapper. + def map( + self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]] + ) -> Union[PauliSumOp, List[Optional[PauliSumOp]]]: + """A convenience method to map second quantized operators based on current mapper. Args: second_q_ops: A second quantized operator, or list thereof @@ -271,21 +297,26 @@ def map(self, second_q_ops: Union[SecondQuantizedOp, List[SecondQuantizedOp]]) \ def _map(self, second_q_op: SecondQuantizedOp) -> PauliSumOp: return self._mapper.map(second_q_op) - def _two_qubit_reduce(self, qubit_op: PauliSumOp, - num_particles: Optional[Tuple[int, int]]) -> PauliSumOp: + def _two_qubit_reduce( + self, qubit_op: PauliSumOp, num_particles: Optional[Tuple[int, int]] + ) -> PauliSumOp: reduced_op = qubit_op - if num_particles is not None and self._two_qubit_reduction and \ - self._mapper.allows_two_qubit_reduction: + if ( + num_particles is not None + and self._two_qubit_reduction + and self._mapper.allows_two_qubit_reduction + ): two_q_reducer = TwoQubitReduction(num_particles) reduced_op = cast(PauliSumOp, two_q_reducer.convert(qubit_op)) return reduced_op - def _find_taper_op(self, qubit_op: PauliSumOp, - sector_locator: Optional[Callable[[Z2Symmetries], - Optional[List[int]]]] = None - ) -> Tuple[PauliSumOp, Z2Symmetries]: + def _find_taper_op( + self, + qubit_op: PauliSumOp, + sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None, + ) -> Tuple[PauliSumOp, Z2Symmetries]: # Return operator unchanged and empty symmetries if we do not taper tapered_qubit_op = qubit_op z2_symmetries = self._no_symmetries @@ -294,14 +325,16 @@ def _find_taper_op(self, qubit_op: PauliSumOp, if self.z2symmetry_reduction is not None: z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) if z2_symmetries.is_empty(): - logger.debug('No Z2 symmetries found') + logger.debug("No Z2 symmetries found") else: # As we have symmetries, if we have a sector locator, if that provides one back # it will override any value defined on constructor - if sector_locator is not None and self.z2symmetry_reduction == 'auto': + if sector_locator is not None and self.z2symmetry_reduction == "auto": z2symmetry_reduction = sector_locator(z2_symmetries) if z2symmetry_reduction is not None: - self.z2symmetry_reduction = z2symmetry_reduction # Overrides any value + self.z2symmetry_reduction = ( + z2symmetry_reduction # Overrides any value + ) # We may end up that neither were we given a sector nor that the locator # returned one. Since though we may have found valid symmetries above we should @@ -310,36 +343,44 @@ def _find_taper_op(self, qubit_op: PauliSumOp, z2_symmetries = self._no_symmetries # So now if we have a sector and have symmetries we found we can attempt to taper - if self.z2symmetry_reduction is not None and self.z2symmetry_reduction != 'auto' \ - and not z2_symmetries.is_empty(): + if ( + self.z2symmetry_reduction is not None + and self.z2symmetry_reduction != "auto" + and not z2_symmetries.is_empty() + ): # check sector definition fits to symmetries found if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): - raise QiskitNatureError('z2symmetry_reduction tapering values list has ' - 'invalid length {} should be {}'. - format(len(self._z2symmetry_reduction), - len(z2_symmetries.symmetries))) + raise QiskitNatureError( + "z2symmetry_reduction tapering values list has " + "invalid length {} should be {}".format( + len(self._z2symmetry_reduction), len(z2_symmetries.symmetries) + ) + ) # Check all operators commute with main operator's symmetry - logger.debug('Sanity check that operator commutes with the symmetry') + logger.debug("Sanity check that operator commutes with the symmetry") symmetry_ops = [] for symmetry in z2_symmetries.symmetries: symmetry_ops.append(PauliSumOp.from_list([(symmetry.to_label(), 1.0)])) commutes = QubitConverter._check_commutes(symmetry_ops, qubit_op) if not commutes: - raise QiskitNatureError('Z2 symmetry failure. The operator must commute ' - 'with symmetries found from it!') + raise QiskitNatureError( + "Z2 symmetry failure. The operator must commute " + "with symmetries found from it!" + ) z2_symmetries.tapering_values = self._z2symmetry_reduction tapered_qubit_op = z2_symmetries.taper(qubit_op) if commutes else None return tapered_qubit_op, z2_symmetries - def _symmetry_reduce(self, qubit_ops: List[PauliSumOp], - suppress_none: bool) -> List[Optional[PauliSumOp]]: + def _symmetry_reduce( + self, qubit_ops: List[PauliSumOp], suppress_none: bool + ) -> List[Optional[PauliSumOp]]: if self._z2symmetries is None or self._z2symmetries.is_empty(): tapered_qubit_ops = qubit_ops else: - logger.debug('Checking operators commute with symmetry:') + logger.debug("Checking operators commute with symmetry:") symmetry_ops = [] for symmetry in self._z2symmetries.symmetries: symmetry_ops.append(PauliSumOp.from_list([(symmetry.to_label(), 1.0)])) @@ -363,9 +404,11 @@ def _symmetry_reduce(self, qubit_ops: List[PauliSumOp], def _check_commutes(cliffords: List[PauliSumOp], qubit_op: PauliSumOp) -> bool: commutes = [] for clifford in cliffords: - commuting_rows = qubit_op.primitive.table.commutes_with_all(clifford.primitive.table) + commuting_rows = qubit_op.primitive.table.commutes_with_all( + clifford.primitive.table + ) commutes.append(len(commuting_rows) == qubit_op.primitive.size) does_commute = bool(np.all(commutes)) - logger.debug(' \'%s\' commutes: %s, %s', id(qubit_op), does_commute, commutes) + logger.debug(" '%s' commutes: %s, %s", id(qubit_op), does_commute, commutes) return does_commute diff --git a/qiskit_nature/operators/second_quantization/spin_op.py b/qiskit_nature/operators/second_quantization/spin_op.py index 36c5d5b377..2b9080b48c 100644 --- a/qiskit_nature/operators/second_quantization/spin_op.py +++ b/qiskit_nature/operators/second_quantization/spin_op.py @@ -199,7 +199,9 @@ def __init__( ) self._dim = int(2 * spin + 1) - if isinstance(data, tuple) and all(isinstance(datum, np.ndarray) for datum in data): + if isinstance(data, tuple) and all( + isinstance(datum, np.ndarray) for datum in data + ): self._spin_array = np.array(data[0], dtype=np.uint8) self._register_length = self._spin_array.shape[2] self._coeffs = np.array(data[1], dtype=dtype) @@ -220,13 +222,19 @@ def __init__( sparse = r"([IXYZ]_\d+(\^\d+)?|[\+\-]_\d+?)" # space (\s) separated sparse label or empty string label_pattern = re.compile(rf"^({sparse}\s)*{sparse}(?!\s)$|^$") - invalid_labels = [label for label, _ in data if not label_pattern.match(label)] + invalid_labels = [ + label for label, _ in data if not label_pattern.match(label) + ] if invalid_labels: - raise ValueError(f"Invalid labels for sparse labels: {invalid_labels}.") + raise ValueError( + f"Invalid labels for sparse labels: {invalid_labels}." + ) else: # dense_label # dense label (repeat of [IXYZ+-]) label_pattern = re.compile(r"^[IXYZ\+\-]+$") - invalid_labels = [label for label, _ in data if not label_pattern.match(label)] + invalid_labels = [ + label for label, _ in data if not label_pattern.match(label) + ] if invalid_labels: raise ValueError( f"Invalid labels for dense labels: {invalid_labels} (if you want to use " @@ -246,9 +254,13 @@ def __init__( if register_length is None: # Dense label self._register_length = len(labels[0]) label_pattern = re.compile(r"^[IXYZ]+$") - invalid_labels = [label for label in labels if not label_pattern.match(label)] + invalid_labels = [ + label for label in labels if not label_pattern.match(label) + ] if invalid_labels: - raise ValueError(f"Invalid labels for dense labels are given: {invalid_labels}") + raise ValueError( + f"Invalid labels for dense labels are given: {invalid_labels}" + ) self._spin_array = np.array( [ [[char == "X", char == "Y", char == "Z"] for char in label] @@ -262,7 +274,7 @@ def __init__( invalid_labels = [ label for label in labels - if not all(label_pattern.match(l) for l in label.split()) + if not all(label_pattern.match(lb) for lb in label.split()) ] if invalid_labels: raise ValueError( @@ -291,7 +303,9 @@ def __str__(self) -> str: if len(self) == 1: label, coeff = self.to_list()[0] return f"{label} * {coeff}" - return " " + "\n+ ".join([f"{label} * {coeff}" for label, coeff in self.to_list()]) + return " " + "\n+ ".join( + [f"{label} * {coeff}" for label, coeff in self.to_list()] + ) def __len__(self) -> int: return len(self._coeffs) @@ -336,14 +350,17 @@ def z(self) -> np.ndarray: def add(self, other: "SpinOp") -> "SpinOp": if not isinstance(other, SpinOp): raise TypeError( - "Unsupported operand type(s) for +: 'SpinOp' and " f"'{type(other).__name__}'" + "Unsupported operand type(s) for +: 'SpinOp' and " + f"'{type(other).__name__}'" ) if self.register_length != other.register_length: raise TypeError("Incompatible register lengths for '+'.") if self.spin != other.spin: - raise TypeError(f"Addition between spin {self.spin} and spin {other.spin} is invalid.") + raise TypeError( + f"Addition between spin {self.spin} and spin {other.spin} is invalid." + ) return SpinOp( ( @@ -375,7 +392,9 @@ def adjoint(self) -> "SpinOp": # to simply complex conjugating the coefficient. return SpinOp((self._spin_array, self._coeffs.conjugate()), spin=self.spin) - def reduce(self, atol: Optional[float] = None, rtol: Optional[float] = None) -> "SpinOp": + def reduce( + self, atol: Optional[float] = None, rtol: Optional[float] = None + ) -> "SpinOp": if atol is None: atol = self.atol if rtol is None: @@ -388,7 +407,9 @@ def reduce(self, atol: Optional[float] = None, rtol: Optional[float] = None) -> for i, val in zip(indices, self._coeffs): coeff_list[i] += val non_zero = [ - i for i, v in enumerate(coeff_list) if not np.isclose(v, 0, atol=atol, rtol=rtol) + i + for i, v in enumerate(coeff_list) + if not np.isclose(v, 0, atol=atol, rtol=rtol) ] if not non_zero: return SpinOp( @@ -449,7 +470,10 @@ def to_matrix(self) -> np.ndarray: y_mat = np.fromfunction( lambda i, j: np.where( np.abs(i - j) == 1, - 1j * (i - j) * np.sqrt((self._dim + 1) * (i + j + 1) / 2 - (i + 1) * (j + 1)) / 2, + 1j + * (i - j) + * np.sqrt((self._dim + 1) * (i + j + 1) / 2 - (i + 1) * (j + 1)) + / 2, 0, ), (self._dim, self._dim), @@ -481,7 +505,9 @@ def _from_sparse_label(self, labels): xyz_dict = {"X": 0, "Y": 1, "Z": 2} # 3-dimensional ndarray (XYZ, terms, register) - self._spin_array = np.zeros((3, len(labels), self.register_length), dtype=np.uint8) + self._spin_array = np.zeros( + (3, len(labels), self.register_length), dtype=np.uint8 + ) for term, label in enumerate(labels): for split_label in label.split(): xyz, nums = split_label.split("_", 1) @@ -490,7 +516,9 @@ def _from_sparse_label(self, labels): continue xyz_num = xyz_dict[xyz] - index, power = map(int, nums.split("^", 1)) if "^" in nums else (int(nums), 1) + index, power = ( + map(int, nums.split("^", 1)) if "^" in nums else (int(nums), 1) + ) if index >= self.register_length: raise ValueError( f"Index {index} must be smaller than register_length {self.register_length}" diff --git a/qiskit_nature/operators/second_quantization/star_algebra.py b/qiskit_nature/operators/second_quantization/star_algebra.py index 47ee475d0d..bf594e520a 100644 --- a/qiskit_nature/operators/second_quantization/star_algebra.py +++ b/qiskit_nature/operators/second_quantization/star_algebra.py @@ -39,7 +39,7 @@ class StarAlgebraMixin(MultiplyMixin, ABC): @abstractmethod def mul(self, other: complex): - """ Return scalar multiplication of self and other, overloaded by `*`.""" + """Return scalar multiplication of self and other, overloaded by `*`.""" return NotImplementedError def __mul__(self, other: complex): @@ -52,7 +52,7 @@ def _multiply(self, other: complex): @abstractmethod def add(self, other): - """ Return Operator addition of self and other, overloaded by `+`.""" + """Return Operator addition of self and other, overloaded by `+`.""" return NotImplementedError def __add__(self, other): @@ -111,5 +111,5 @@ def dagger(self): return self.adjoint() def __invert__(self): - """ Overload unary `~` to return Operator adjoint.""" + """Overload unary `~` to return Operator adjoint.""" return self.adjoint() diff --git a/qiskit_nature/operators/second_quantization/vibrational_op.py b/qiskit_nature/operators/second_quantization/vibrational_op.py index a01a616aa9..5b6f612f18 100644 --- a/qiskit_nature/operators/second_quantization/vibrational_op.py +++ b/qiskit_nature/operators/second_quantization/vibrational_op.py @@ -85,11 +85,16 @@ class VibrationalOp(SecondQuantizedOp): # a valid pattern consists of a single "+" or "-" operator followed by "_" and a mode index # followed by "*" and a modal index, possibly appearing multiple times and separated by a space - _VALID_VIBR_LABEL_PATTERN = re.compile(r"^([\+\-]_\d+\*\d+\s)*[\+\-]_\d+\*\d+(?!\s)$|^[\+\-]+$") - - def __init__(self, data: Union[str, Tuple[str, complex], List[Tuple[str, complex]]], - num_modes: int, - num_modals: Union[int, List[int]]): + _VALID_VIBR_LABEL_PATTERN = re.compile( + r"^([\+\-]_\d+\*\d+\s)*[\+\-]_\d+\*\d+(?!\s)$|^[\+\-]+$" + ) + + def __init__( + self, + data: Union[str, Tuple[str, complex], List[Tuple[str, complex]]], + num_modes: int, + num_modals: Union[int, List[int]], + ): r""" Args: data: list of labels and coefficients. @@ -104,10 +109,14 @@ def __init__(self, data: Union[str, Tuple[str, complex], List[Tuple[str, complex ValueError: invalid labels. """ if not isinstance(data, (tuple, list, str)): - raise TypeError(f"Type of data must be str, tuple, or list, not {type(data)}.") + raise TypeError( + f"Type of data must be str, tuple, or list, not {type(data)}." + ) if isinstance(data, tuple): - if not isinstance(data[0], str) or not isinstance(data[1], (int, float, complex)): + if not isinstance(data[0], str) or not isinstance( + data[1], (int, float, complex) + ): raise TypeError( f"Data tuple must be (str, number), not ({type(data[0])}, {type(data[1])})." ) @@ -135,14 +144,18 @@ def __init__(self, data: Union[str, Tuple[str, complex], List[Tuple[str, complex labels, coeffs = zip(*data) self._coeffs = np.array(coeffs, np.complex128) - if not any('_' in label for label in labels): + if not any("_" in label for label in labels): # Dense label if not all(len(label) == self._register_length for label in labels): raise ValueError("Lengths of strings of label are different.") label_pattern = re.compile(r"^[I\+\-NE]+$") - invalid_labels = [label for label in labels if not label_pattern.match(label)] + invalid_labels = [ + label for label in labels if not label_pattern.match(label) + ] if invalid_labels: - raise ValueError(f"Invalid labels for dense labels are given: {invalid_labels}") + raise ValueError( + f"Invalid labels for dense labels are given: {invalid_labels}" + ) self._labels = list(labels) else: # Sparse label @@ -150,9 +163,13 @@ def __init__(self, data: Union[str, Tuple[str, complex], List[Tuple[str, complex ops: List[VibrationalOp] = [] for dense_label, coeff in dense_labels: - new_op = reduce(lambda a, b: a @ b, ( - VibrationalOp((label, 1), num_modes, num_modals) for label in dense_label - )) + new_op = reduce( + lambda a, b: a @ b, + ( + VibrationalOp((label, 1), num_modes, num_modals) + for label in dense_label + ), + ) # We ignore the type here because mypy only sees the complex coefficient ops.append(coeff * new_op) # type: ignore @@ -172,7 +189,9 @@ def __str__(self) -> str: if len(self) == 1: label, coeff = self.to_list()[0] return f"{label} * {coeff}" - return " " + "\n+ ".join([f"{label} * {coeff}" for label, coeff in self.to_list()]) + return " " + "\n+ ".join( + [f"{label} * {coeff}" for label, coeff in self.to_list()] + ) def __len__(self): return len(self._labels) @@ -203,8 +222,11 @@ def mul(self, other: complex) -> "VibrationalOp": raise TypeError( f"Unsupported operand type(s) for *: 'VibrationalOp' and '{type(other).__name__}'" ) - return VibrationalOp(list(zip(self._labels, (other * self._coeffs).tolist())), - self._num_modes, self._num_modals) + return VibrationalOp( + list(zip(self._labels, (other * self._coeffs).tolist())), + self._num_modes, + self._num_modals, + ) def add(self, other: "VibrationalOp") -> "VibrationalOp": if not isinstance(other, VibrationalOp): @@ -218,7 +240,10 @@ def add(self, other: "VibrationalOp") -> "VibrationalOp": return VibrationalOp( list( - zip(self._labels + other._labels, np.hstack((self._coeffs, other._coeffs)).tolist()) + zip( + self._labels + other._labels, + np.hstack((self._coeffs, other._coeffs)).tolist(), + ) ), self._num_modes, self._num_modals, @@ -248,10 +273,15 @@ def adjoint(self) -> "VibrationalOp": label_list.append("".join(daggered_label)) coeff_list.append(conjugated_coeff) - return VibrationalOp(list(zip(label_list, np.array(coeff_list, dtype=np.complex128))), - self._num_modes, self._num_modals) + return VibrationalOp( + list(zip(label_list, np.array(coeff_list, dtype=np.complex128))), + self._num_modes, + self._num_modals, + ) - def reduce(self, atol: Optional[float] = None, rtol: Optional[float] = None) -> "VibrationalOp": + def reduce( + self, atol: Optional[float] = None, rtol: Optional[float] = None + ) -> "VibrationalOp": if atol is None: atol = self.atol if rtol is None: @@ -262,12 +292,17 @@ def reduce(self, atol: Optional[float] = None, rtol: Optional[float] = None) -> for i, val in zip(indices, self._coeffs): coeff_list[i] += val non_zero = [ - i for i, v in enumerate(coeff_list) if not np.isclose(v, 0, atol=atol, rtol=rtol) + i + for i, v in enumerate(coeff_list) + if not np.isclose(v, 0, atol=atol, rtol=rtol) ] if not non_zero: return VibrationalOp(("I_0*0", 0), self._num_modes, self._num_modals) - return VibrationalOp(list(zip(label_list[non_zero].tolist(), coeff_list[non_zero])), - self._num_modes, self._num_modals) + return VibrationalOp( + list(zip(label_list[non_zero].tolist(), coeff_list[non_zero])), + self._num_modes, + self._num_modals, + ) def compose(self, other: "VibrationalOp") -> "VibrationalOp": if isinstance(other, VibrationalOp): @@ -327,7 +362,9 @@ def compose(self, other: "VibrationalOp") -> "VibrationalOp": @classmethod def _single_mul(cls, label1: str, label2: str) -> Tuple[str, bool]: if len(label1) != len(label2): - raise QiskitNatureError("Operators act on Fermion Registers of different length") + raise QiskitNatureError( + "Operators act on Fermion Registers of different length" + ) new_label = [] @@ -342,61 +379,84 @@ def _single_mul(cls, label1: str, label2: str) -> Tuple[str, bool]: return "".join(new_label), True - def _validate_vibrational_labels(self, - vibrational_labels: List[Tuple[str, complex]], - num_modals: List[int]): + def _validate_vibrational_labels( + self, vibrational_labels: List[Tuple[str, complex]], num_modals: List[int] + ): """Validates vibrational labels in the following aspects: - - vibrational labels stored in a correct data structure, - - labels for each coefficient conform with a regular expression, - - indices of operators in each label are correct and ordered correctly: - * indices for modes and modals do not exceed declared ranges, - * there are no duplicated operators for each coefficient, - * operators in each label are sorted in the decreasing order of modes and modals, - if both are equal then '+' comes before '-' (i.e. they are normal ordered), - * Finally, a warning will be logged if the number of particles is not preserved - within each mode. This corresponds to a mismatching number of `+` and `-` operators. - This case only leads to a warning because it allows re-use of the - :class:`VibrationalOp` for state initialization, where only `+` operators are - present. - - Args: - vibrational_labels: list of vibrational labels with coefficients. - num_modals: the number of modals. - - Raises: - ValueError: if invalid vibrational labels provided. - """ + - vibrational labels stored in a correct data structure, + - labels for each coefficient conform with a regular expression, + - indices of operators in each label are correct and ordered correctly: + * indices for modes and modals do not exceed declared ranges, + * there are no duplicated operators for each coefficient, + * operators in each label are sorted in the decreasing order of modes and modals, + if both are equal then '+' comes before '-' (i.e. they are normal ordered), + * Finally, a warning will be logged if the number of particles is not preserved + within each mode. This corresponds to a mismatching number of `+` and `-` operators. + This case only leads to a warning because it allows re-use of the + :class:`VibrationalOp` for state initialization, where only `+` operators are + present. + + Args: + vibrational_labels: list of vibrational labels with coefficients. + num_modals: the number of modals. + + Raises: + ValueError: if invalid vibrational labels provided. + """ if not isinstance(vibrational_labels, list): raise ValueError("Invalid data type.") - invalid_labels = [label for label, _ in vibrational_labels if - not self._VALID_VIBR_LABEL_PATTERN.match(label)] + invalid_labels = [ + label + for label, _ in vibrational_labels + if not self._VALID_VIBR_LABEL_PATTERN.match(label) + ] if invalid_labels: raise ValueError(f"Invalid labels: {invalid_labels}") self._validate_indices(vibrational_labels, num_modals) - def _validate_indices(self, vibrational_labels: List[Tuple[str, complex]], - num_modals: List[int]): + def _validate_indices( + self, vibrational_labels: List[Tuple[str, complex]], num_modals: List[int] + ): for labels, _ in vibrational_labels: coeff_labels_split = labels.split() num_modes = len(num_modals) par_num_mode_conserved_check = [0] * num_modes prev_op, prev_mode_index, prev_modal_index = "+", -1, -1 for label in coeff_labels_split: - op, mode_index_str, modal_index_str = re.split('[*_]', label) + op, mode_index_str, modal_index_str = re.split("[*_]", label) mode_index = int(mode_index_str) modal_index = int(modal_index_str) - if self._is_index_out_of_range(mode_index, num_modes, modal_index, num_modals): - raise ValueError(f"Indices out of the declared range for label {label}.") - if self._is_label_duplicated(mode_index, prev_mode_index, modal_index, - prev_modal_index, op, prev_op): - raise ValueError(f"Operators in a label duplicated for label {label}.") - if self._is_order_incorrect(mode_index, prev_mode_index, modal_index, - prev_modal_index, op, prev_op): + if self._is_index_out_of_range( + mode_index, num_modes, modal_index, num_modals + ): + raise ValueError( + f"Indices out of the declared range for label {label}." + ) + if self._is_label_duplicated( + mode_index, + prev_mode_index, + modal_index, + prev_modal_index, + op, + prev_op, + ): + raise ValueError( + f"Operators in a label duplicated for label {label}." + ) + if self._is_order_incorrect( + mode_index, + prev_mode_index, + modal_index, + prev_modal_index, + op, + prev_op, + ): raise ValueError( f"Incorrect order of operators for label {label} and previous label " - f"{str(prev_op)}_{str(prev_mode_index)}*{str(prev_modal_index)}.") + f"{str(prev_op)}_{str(prev_mode_index)}*{str(prev_modal_index)}." + ) prev_op, prev_mode_index, prev_modal_index = op, mode_index, modal_index @@ -405,39 +465,81 @@ def _validate_indices(self, vibrational_labels: List[Tuple[str, complex]], if item != 0: logger.warning( "Number of raising and lowering operators do not agree for mode %s in " - "label %s.", index, labels) - - def _is_index_out_of_range(self, mode_index: int, num_modes: int, modal_index: int, - num_modals: List[int]) -> bool: + "label %s.", + index, + labels, + ) + + def _is_index_out_of_range( + self, mode_index: int, num_modes: int, modal_index: int, num_modals: List[int] + ) -> bool: return mode_index >= num_modes or modal_index >= num_modals[int(mode_index)] - def _is_label_duplicated(self, mode_index: int, prev_mode_index: int, modal_index: int, - prev_modal_index: int, op: str, prev_op: str) -> bool: - return modal_index == prev_modal_index and mode_index == prev_mode_index and op == prev_op + def _is_label_duplicated( + self, + mode_index: int, + prev_mode_index: int, + modal_index: int, + prev_modal_index: int, + op: str, + prev_op: str, + ) -> bool: + return ( + modal_index == prev_modal_index + and mode_index == prev_mode_index + and op == prev_op + ) - def _is_order_incorrect(self, mode_index: int, prev_mode_index: int, modal_index: int, - prev_modal_index: int, op: str, prev_op: str) -> bool: - return self._is_mode_order_incorrect(mode_index, prev_mode_index) \ - or self._is_modal_order_incorrect(prev_mode_index, mode_index, - prev_modal_index, modal_index) \ - or self._is_operator_order_incorrect(mode_index, prev_mode_index, modal_index, - prev_modal_index, op, prev_op) + def _is_order_incorrect( + self, + mode_index: int, + prev_mode_index: int, + modal_index: int, + prev_modal_index: int, + op: str, + prev_op: str, + ) -> bool: + return ( + self._is_mode_order_incorrect(mode_index, prev_mode_index) + or self._is_modal_order_incorrect( + prev_mode_index, mode_index, prev_modal_index, modal_index + ) + or self._is_operator_order_incorrect( + mode_index, prev_mode_index, modal_index, prev_modal_index, op, prev_op + ) + ) def _is_mode_order_incorrect(self, mode_index: int, prev_mode_index: int) -> bool: return mode_index < prev_mode_index - def _is_modal_order_incorrect(self, prev_mode_index: int, mode_index: int, - prev_modal_index: int, modal_index: int) -> bool: + def _is_modal_order_incorrect( + self, + prev_mode_index: int, + mode_index: int, + prev_modal_index: int, + modal_index: int, + ) -> bool: return mode_index == prev_mode_index and modal_index < prev_modal_index - def _is_operator_order_incorrect(self, mode_index: int, prev_mode_index: int, modal_index: int, - prev_modal_index: int, op: str, prev_op: str) -> bool: - return mode_index == prev_mode_index and modal_index == prev_modal_index \ - and prev_op == "-" and op == "+" + def _is_operator_order_incorrect( + self, + mode_index: int, + prev_mode_index: int, + modal_index: int, + prev_modal_index: int, + op: str, + prev_op: str, + ) -> bool: + return ( + mode_index == prev_mode_index + and modal_index == prev_modal_index + and prev_op == "-" + and op == "+" + ) - def _convert_to_dense_labels(self, vibrational_labels: List[Tuple[str, complex]], - num_modals: List[int] - ) -> List[Tuple[List[str], complex]]: + def _convert_to_dense_labels( + self, vibrational_labels: List[Tuple[str, complex]], num_modals: List[int] + ) -> List[Tuple[List[str], complex]]: """Converts sparse :class:`VibrationalOp` labels to dense ones. The dense labels match the notation of :class:`FermionicOp`. @@ -457,21 +559,27 @@ def _convert_to_dense_labels(self, vibrational_labels: List[Tuple[str, complex]] dense_labels = [] for labels, coeff in vibrational_labels: - coeff_new_labels = self._build_coeff_dense_labels(labels, partial_sum_modals) + coeff_new_labels = self._build_coeff_dense_labels( + labels, partial_sum_modals + ) dense_labels.append((coeff_new_labels, coeff)) return dense_labels - def _build_coeff_dense_labels(self, labels: str, partial_sum_modals: List[int]) -> List[str]: + def _build_coeff_dense_labels( + self, labels: str, partial_sum_modals: List[int] + ) -> List[str]: coeff_labels_split = labels.split() coeff_new_labels = [] for label in coeff_labels_split: op, index = self._build_dense_label(label, partial_sum_modals) - new_label = ['I'] * partial_sum_modals[-1] + new_label = ["I"] * partial_sum_modals[-1] new_label[index] = op - coeff_new_labels.append(''.join(new_label)) + coeff_new_labels.append("".join(new_label)) return coeff_new_labels - def _build_dense_label(self, label: str, partial_sum_modals: List[int]) -> Tuple[str, int]: - op, mode_index, modal_index = re.split('[*_]', label) + def _build_dense_label( + self, label: str, partial_sum_modals: List[int] + ) -> Tuple[str, int]: + op, mode_index, modal_index = re.split("[*_]", label) index = partial_sum_modals[int(mode_index)] + int(modal_index) return (op, index) diff --git a/qiskit_nature/problems/second_quantization/__init__.py b/qiskit_nature/problems/second_quantization/__init__.py index c77d71343e..ac0130cbc9 100644 --- a/qiskit_nature/problems/second_quantization/__init__.py +++ b/qiskit_nature/problems/second_quantization/__init__.py @@ -31,7 +31,7 @@ from .vibrational.vibrational_structure_problem import VibrationalStructureProblem __all__ = [ - 'BaseProblem', - 'ElectronicStructureProblem', - 'VibrationalStructureProblem', + "BaseProblem", + "ElectronicStructureProblem", + "VibrationalStructureProblem", ] diff --git a/qiskit_nature/problems/second_quantization/base_problem.py b/qiskit_nature/problems/second_quantization/base_problem.py index 320814a377..a449c722c3 100644 --- a/qiskit_nature/problems/second_quantization/base_problem.py +++ b/qiskit_nature/problems/second_quantization/base_problem.py @@ -28,8 +28,9 @@ class BaseProblem(ABC): """Base Problem""" - def __init__(self, driver: BaseDriver, - transformers: Optional[List[BaseTransformer]] = None): + def __init__( + self, driver: BaseDriver, transformers: Optional[List[BaseTransformer]] = None + ): """ Args: @@ -73,7 +74,9 @@ def _transform(self, data): data = transformer.transform(data) return data - def symmetry_sector_locator(self, z2_symmetries: Z2Symmetries) -> Optional[List[int]]: + def symmetry_sector_locator( + self, z2_symmetries: Z2Symmetries + ) -> Optional[List[int]]: # pylint: disable=unused-argument """Given the detected Z2Symmetries, it can determine the correct sector of the tapered operators so the correct one can be returned @@ -100,8 +103,11 @@ def interpret(self, raw_result: EigenstateResult) -> EigenstateResult: raise NotImplementedError() @abstractmethod - def get_default_filter_criterion(self) -> Optional[Callable[[Union[List, np.ndarray], float, - Optional[List[float]]], bool]]: + def get_default_filter_criterion( + self, + ) -> Optional[ + Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool] + ]: """Returns a default filter criterion method to filter the eigenvalues computed by the eigen solver. For more information see also qiskit.algorithms.eigen_solvers.NumPyEigensolver.filter_criterion. @@ -113,13 +119,22 @@ def get_default_filter_criterion(self) -> Optional[Callable[[Union[List, np.ndar raise NotImplementedError() @abstractmethod - def hopping_qeom_ops(self, qubit_converter: QubitConverter, - excitations: Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[Tuple[int, ...], Tuple[ - int, ...]]]]] = 'sd', - ) -> Tuple[Dict[str, PauliSumOp], Dict[str, List[bool]], - Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]]]: + def hopping_qeom_ops( + self, + qubit_converter: QubitConverter, + excitations: Union[ + str, + int, + List[int], + Callable[ + [int, Tuple[int, int]], List[Tuple[Tuple[int, ...], Tuple[int, ...]]] + ], + ] = "sd", + ) -> Tuple[ + Dict[str, PauliSumOp], + Dict[str, List[bool]], + Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]], + ]: """Generates the hopping operators and their commutativity information for the specified set of excitations. diff --git a/qiskit_nature/problems/second_quantization/electronic/__init__.py b/qiskit_nature/problems/second_quantization/electronic/__init__.py index fea645a89b..32df4492cd 100644 --- a/qiskit_nature/problems/second_quantization/electronic/__init__.py +++ b/qiskit_nature/problems/second_quantization/electronic/__init__.py @@ -20,5 +20,5 @@ from .electronic_structure_problem import ElectronicStructureProblem __all__ = [ - 'ElectronicStructureProblem', + "ElectronicStructureProblem", ] diff --git a/qiskit_nature/problems/second_quantization/electronic/builders/aux_fermionic_ops_builder.py b/qiskit_nature/problems/second_quantization/electronic/builders/aux_fermionic_ops_builder.py index b3c6879cd1..2b5e6417f0 100644 --- a/qiskit_nature/problems/second_quantization/electronic/builders/aux_fermionic_ops_builder.py +++ b/qiskit_nature/problems/second_quantization/electronic/builders/aux_fermionic_ops_builder.py @@ -16,10 +16,14 @@ from qiskit_nature.drivers import QMolecule from qiskit_nature.operators.second_quantization import FermionicOp -from qiskit_nature.problems.second_quantization.electronic.builders.fermionic_op_builder import \ - build_ferm_op_from_ints -from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import \ - calc_total_magnetization_ints, calc_total_ang_momentum_ints, calc_total_particle_num_ints +from qiskit_nature.problems.second_quantization.electronic.builders.fermionic_op_builder import ( + build_ferm_op_from_ints, +) +from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import ( + calc_total_magnetization_ints, + calc_total_ang_momentum_ints, + calc_total_particle_num_ints, +) def _create_all_aux_operators(q_molecule: QMolecule) -> List[FermionicOp]: @@ -33,21 +37,27 @@ def _create_all_aux_operators(q_molecule: QMolecule) -> List[FermionicOp]: particle number, angular momentum and total magnetization operators. If the QMolecule object contained dipole integrals, the list will also contain the X, Y and Z dipole operators. """ - aux_second_quantized_ops_list = [_create_total_particle_num_op(q_molecule), - _create_total_ang_momentum_op(q_molecule), - _create_total_magnetization_op(q_molecule), - ] + aux_second_quantized_ops_list = [ + _create_total_particle_num_op(q_molecule), + _create_total_ang_momentum_op(q_molecule), + _create_total_magnetization_op(q_molecule), + ] if q_molecule.has_dipole_integrals(): x_dipole_operator, y_dipole_operator, z_dipole_operator = _create_dipole_ops( - q_molecule) - aux_second_quantized_ops_list += [x_dipole_operator, - y_dipole_operator, - z_dipole_operator] + q_molecule + ) + aux_second_quantized_ops_list += [ + x_dipole_operator, + y_dipole_operator, + z_dipole_operator, + ] return aux_second_quantized_ops_list -def _create_dipole_ops(q_molecule: QMolecule) -> Tuple[FermionicOp, FermionicOp, FermionicOp]: +def _create_dipole_ops( + q_molecule: QMolecule, +) -> Tuple[FermionicOp, FermionicOp, FermionicOp]: x_dipole_operator = build_ferm_op_from_ints(q_molecule.x_dipole_integrals) y_dipole_operator = build_ferm_op_from_ints(q_molecule.y_dipole_integrals) z_dipole_operator = build_ferm_op_from_ints(q_molecule.z_dipole_integrals) diff --git a/qiskit_nature/problems/second_quantization/electronic/builders/fermionic_op_builder.py b/qiskit_nature/problems/second_quantization/electronic/builders/fermionic_op_builder.py index 831ca466aa..5fdb8384d0 100644 --- a/qiskit_nature/problems/second_quantization/electronic/builders/fermionic_op_builder.py +++ b/qiskit_nature/problems/second_quantization/electronic/builders/fermionic_op_builder.py @@ -38,8 +38,9 @@ def _build_fermionic_op(q_molecule: QMolecule) -> FermionicOp: return build_ferm_op_from_ints(one_body_ints, two_body_ints) -def build_ferm_op_from_ints(one_body_integrals: np.ndarray, - two_body_integrals: np.ndarray = None) -> FermionicOp: +def build_ferm_op_from_ints( + one_body_integrals: np.ndarray, two_body_integrals: np.ndarray = None +) -> FermionicOp: """ Builds a fermionic operator based on 1- and/or 2-body integrals. Integral values are used for the coefficients of the second-quantized Hamiltonian that is built. If integrals are stored @@ -70,13 +71,17 @@ def build_ferm_op_from_ints(one_body_integrals: np.ndarray, return fermionic_op -def _build_ferm_op_helper(one_body_integrals: np.ndarray, - two_body_integrals: np.ndarray) -> FermionicOp: +def _build_ferm_op_helper( + one_body_integrals: np.ndarray, two_body_integrals: np.ndarray +) -> FermionicOp: one_body_base_ops_labels = _create_one_body_base_ops(one_body_integrals) - two_body_base_ops_labels = _create_two_body_base_ops( - two_body_integrals) if two_body_integrals is not None else [] + two_body_base_ops_labels = ( + _create_two_body_base_ops(two_body_integrals) + if two_body_integrals is not None + else [] + ) base_ops_labels = one_body_base_ops_labels + two_body_base_ops_labels - initial_label_with_ceoff = ('I' * len(one_body_integrals), 0) + initial_label_with_ceoff = ("I" * len(one_body_integrals), 0) # TODO the initial label should be eliminated once QMolecule is refactored (currently # has_dipole_integrals() checks for None only but zero-matrices happen instead of None and # initial labels prevents from an empty labels list when building a FermionicOp) @@ -86,18 +91,27 @@ def _build_ferm_op_helper(one_body_integrals: np.ndarray, return fermionic_op -def _create_one_body_base_ops(one_body_integrals: np.ndarray) -> List[Tuple[str, complex]]: +def _create_one_body_base_ops( + one_body_integrals: np.ndarray, +) -> List[Tuple[str, complex]]: repeat_num = 2 - return _create_base_ops_labels(one_body_integrals, repeat_num, _calc_coeffs_with_ops_one_body) + return _create_base_ops_labels( + one_body_integrals, repeat_num, _calc_coeffs_with_ops_one_body + ) -def _create_two_body_base_ops(two_body_integrals: np.ndarray) -> List[Tuple[str, complex]]: +def _create_two_body_base_ops( + two_body_integrals: np.ndarray, +) -> List[Tuple[str, complex]]: repeat_num = 4 - return _create_base_ops_labels(two_body_integrals, repeat_num, _calc_coeffs_with_ops_two_body) + return _create_base_ops_labels( + two_body_integrals, repeat_num, _calc_coeffs_with_ops_two_body + ) -def _create_base_ops_labels(integrals: np.ndarray, repeat_num: int, calc_coeffs_with_ops) -> \ - List[Tuple[str, complex]]: +def _create_base_ops_labels( + integrals: np.ndarray, repeat_num: int, calc_coeffs_with_ops +) -> List[Tuple[str, complex]]: all_base_ops_labels = [] integrals_length = len(integrals) for idx in itertools.product(range(integrals_length), repeat=repeat_num): @@ -111,18 +125,18 @@ def _create_base_ops_labels(integrals: np.ndarray, repeat_num: int, calc_coeffs_ def _calc_coeffs_with_ops_one_body(idx) -> List[Tuple[complex, str]]: - return [(idx[0], '+'), (idx[1], '-')] + return [(idx[0], "+"), (idx[1], "-")] def _calc_coeffs_with_ops_two_body(idx) -> List[Tuple[complex, str]]: - return [(idx[0], '+'), (idx[2], '+'), (idx[3], '-'), (idx[1], '-')] + return [(idx[0], "+"), (idx[2], "+"), (idx[3], "-"), (idx[1], "-")] def _create_base_op_from_labels(coeff, length: int, coeffs_with_ops) -> FermionicOp: - label = ['I'] * length - base_op = coeff * FermionicOp(''.join(label)) + label = ["I"] * length + base_op = coeff * FermionicOp("".join(label)) for i, op in coeffs_with_ops: label_i = label.copy() label_i[i] = op - base_op @= FermionicOp(''.join(label_i)) + base_op @= FermionicOp("".join(label_i)) return base_op diff --git a/qiskit_nature/problems/second_quantization/electronic/builders/hopping_ops_builder.py b/qiskit_nature/problems/second_quantization/electronic/builders/hopping_ops_builder.py index 9217dc0119..fda6de7e8b 100644 --- a/qiskit_nature/problems/second_quantization/electronic/builders/hopping_ops_builder.py +++ b/qiskit_nature/problems/second_quantization/electronic/builders/hopping_ops_builder.py @@ -25,14 +25,20 @@ from qiskit_nature.converters.second_quantization import QubitConverter -def _build_qeom_hopping_ops(q_molecule: QMolecule, qubit_converter: QubitConverter, - excitations: Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[Tuple[int, ...], - Tuple[int, ...]]]]] = 'sd', - ) -> Tuple[Dict[str, PauliSumOp], - Dict[str, List[bool]], - Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]]]: +def _build_qeom_hopping_ops( + q_molecule: QMolecule, + qubit_converter: QubitConverter, + excitations: Union[ + str, + int, + List[int], + Callable[[int, Tuple[int, int]], List[Tuple[Tuple[int, ...], Tuple[int, ...]]]], + ] = "sd", +) -> Tuple[ + Dict[str, PauliSumOp], + Dict[str, List[bool]], + Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]], +]: """Builds the product of raising and lowering operators (basic excitation operators) Args: @@ -58,13 +64,19 @@ def _build_qeom_hopping_ops(q_molecule: QMolecule, qubit_converter: QubitConvert num_spin_orbitals = 2 * num_molecular_orbitals excitations_list: List[Tuple[Tuple[int, ...], Tuple[int, ...]]] - if isinstance(excitations, (str, int)) or \ - (isinstance(excitations, list) and all(isinstance(exc, int) for exc in excitations)): + if isinstance(excitations, (str, int)) or ( + isinstance(excitations, list) + and all(isinstance(exc, int) for exc in excitations) + ): excitations = cast(Union[str, int, List[int]], excitations) - ansatz = UCC(qubit_converter, (num_alpha, num_beta), num_spin_orbitals, excitations) + ansatz = UCC( + qubit_converter, (num_alpha, num_beta), num_spin_orbitals, excitations + ) excitations_list = ansatz._get_excitation_list() else: - excitations_list = cast(List[Tuple[Tuple[int, ...], Tuple[int, ...]]], excitations) + excitations_list = cast( + List[Tuple[Tuple[int, ...], Tuple[int, ...]]], excitations + ) size = len(excitations_list) @@ -75,18 +87,19 @@ def _build_qeom_hopping_ops(q_molecule: QMolecule, qubit_converter: QubitConvert to_be_executed_list = [] for idx in range(size): to_be_executed_list += [excitations_list[idx], excitations_list[idx][::-1]] - hopping_operators['E_{}'.format(idx)] = None - hopping_operators['Edag_{}'.format(idx)] = None - type_of_commutativities['E_{}'.format(idx)] = None - type_of_commutativities['Edag_{}'.format(idx)] = None - excitation_indices['E_{}'.format(idx)] = excitations_list[idx] - excitation_indices['Edag_{}'.format(idx)] = excitations_list[idx][::-1] - - result = parallel_map(_build_single_hopping_operator, - to_be_executed_list, - task_args=(num_spin_orbitals, - qubit_converter), - num_processes=algorithm_globals.num_processes) + hopping_operators["E_{}".format(idx)] = None + hopping_operators["Edag_{}".format(idx)] = None + type_of_commutativities["E_{}".format(idx)] = None + type_of_commutativities["Edag_{}".format(idx)] = None + excitation_indices["E_{}".format(idx)] = excitations_list[idx] + excitation_indices["Edag_{}".format(idx)] = excitations_list[idx][::-1] + + result = parallel_map( + _build_single_hopping_operator, + to_be_executed_list, + task_args=(num_spin_orbitals, qubit_converter), + num_processes=algorithm_globals.num_processes, + ) for key, res in zip(hopping_operators.keys(), result): hopping_operators[key] = res[0] @@ -95,16 +108,17 @@ def _build_qeom_hopping_ops(q_molecule: QMolecule, qubit_converter: QubitConvert return hopping_operators, type_of_commutativities, excitation_indices -def _build_single_hopping_operator(excitation: Tuple[Tuple[int, ...], Tuple[int, ...]], - num_spin_orbitals: int, - qubit_converter: QubitConverter - ) -> Tuple[PauliSumOp, List[bool]]: - label = ['I'] * num_spin_orbitals +def _build_single_hopping_operator( + excitation: Tuple[Tuple[int, ...], Tuple[int, ...]], + num_spin_orbitals: int, + qubit_converter: QubitConverter, +) -> Tuple[PauliSumOp, List[bool]]: + label = ["I"] * num_spin_orbitals for occ in excitation[0]: - label[occ] = '+' + label[occ] = "+" for unocc in excitation[1]: - label[unocc] = '-' - fer_op = FermionicOp((''.join(label), 4.0 ** len(excitation[0]))) + label[unocc] = "-" + fer_op = FermionicOp(("".join(label), 4.0 ** len(excitation[0]))) qubit_op: PauliSumOp = qubit_converter.convert_match(fer_op) z2_symmetries = qubit_converter.z2symmetries @@ -114,9 +128,11 @@ def _build_single_hopping_operator(excitation: Tuple[Tuple[int, ...], Tuple[int, for symmetry in z2_symmetries.symmetries: symmetry_op = PauliSumOp.from_list([(symmetry.to_label(), 1.0)]) commuting = qubit_op.primitive.table.commutes_with_all( - symmetry_op.primitive.table) + symmetry_op.primitive.table + ) anticommuting = qubit_op.primitive.table.anticommutes_with_all( - symmetry_op.primitive.table) + symmetry_op.primitive.table + ) if commuting != anticommuting: # only one of them is True if commuting: @@ -126,6 +142,7 @@ def _build_single_hopping_operator(excitation: Tuple[Tuple[int, ...], Tuple[int, else: raise QiskitNatureError( "Symmetry {} is nor commute neither anti-commute " - "to exciting operator.".format(symmetry.to_label())) + "to exciting operator.".format(symmetry.to_label()) + ) return qubit_op, commutativities diff --git a/qiskit_nature/problems/second_quantization/electronic/electronic_structure_problem.py b/qiskit_nature/problems/second_quantization/electronic/electronic_structure_problem.py index fee94c7253..4073d3a1f1 100644 --- a/qiskit_nature/problems/second_quantization/electronic/electronic_structure_problem.py +++ b/qiskit_nature/problems/second_quantization/electronic/electronic_structure_problem.py @@ -20,7 +20,9 @@ from qiskit.opflow import PauliSumOp from qiskit.opflow.primitive_ops import Z2Symmetries -from qiskit_nature.circuit.library.initial_states.hartree_fock import hartree_fock_bitstring +from qiskit_nature.circuit.library.initial_states.hartree_fock import ( + hartree_fock_bitstring, +) from qiskit_nature.drivers import FermionicDriver, QMolecule from qiskit_nature.operators.second_quantization import SecondQuantizedOp from qiskit_nature.converters.second_quantization import QubitConverter @@ -37,8 +39,11 @@ class ElectronicStructureProblem(BaseProblem): """Electronic Structure Problem""" - def __init__(self, driver: FermionicDriver, - q_molecule_transformers: Optional[List[BaseTransformer]] = None): + def __init__( + self, + driver: FermionicDriver, + q_molecule_transformers: Optional[List[BaseTransformer]] = None, + ): """ Args: @@ -62,22 +67,33 @@ def second_q_ops(self) -> List[SecondQuantizedOp]: operator, and (if available) x, y, z dipole operators. """ self._molecule_data = cast(QMolecule, self.driver.run()) - self._molecule_data_transformed = cast(QMolecule, self._transform(self._molecule_data)) + self._molecule_data_transformed = cast( + QMolecule, self._transform(self._molecule_data) + ) electronic_fermionic_op = _build_fermionic_op(self._molecule_data_transformed) - second_quantized_ops_list = [electronic_fermionic_op] + _create_all_aux_operators( - self._molecule_data_transformed) + second_quantized_ops_list = [ + electronic_fermionic_op + ] + _create_all_aux_operators(self._molecule_data_transformed) return second_quantized_ops_list - def hopping_qeom_ops(self, qubit_converter: QubitConverter, - excitations: Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[ - Tuple[int, ...], Tuple[ - int, ...]]]]] = 'sd', - ) -> Tuple[Dict[str, PauliSumOp], Dict[str, List[bool]], - Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]]]: + def hopping_qeom_ops( + self, + qubit_converter: QubitConverter, + excitations: Union[ + str, + int, + List[int], + Callable[ + [int, Tuple[int, int]], List[Tuple[Tuple[int, ...], Tuple[int, ...]]] + ], + ] = "sd", + ) -> Tuple[ + Dict[str, PauliSumOp], + Dict[str, List[bool]], + Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]], + ]: """Generates the hopping operators and their commutativity information for the specified set of excitations. @@ -101,8 +117,12 @@ def hopping_qeom_ops(self, qubit_converter: QubitConverter, q_molecule = cast(QMolecule, self.molecule_data) return _build_qeom_hopping_ops(q_molecule, qubit_converter, excitations) - def interpret(self, raw_result: Union[EigenstateResult, EigensolverResult, - MinimumEigensolverResult]) -> ElectronicStructureResult: + def interpret( + self, + raw_result: Union[ + EigenstateResult, EigensolverResult, MinimumEigensolverResult + ], + ) -> ElectronicStructureResult: """Interprets an EigenstateResult in the context of this transformation. Args: @@ -115,8 +135,11 @@ def interpret(self, raw_result: Union[EigenstateResult, EigensolverResult, q_molecule_transformed = cast(QMolecule, self.molecule_data_transformed) return _interpret(q_molecule, q_molecule_transformed, raw_result) - def get_default_filter_criterion(self) -> Optional[Callable[[Union[List, np.ndarray], float, - Optional[List[float]]], bool]]: + def get_default_filter_criterion( + self, + ) -> Optional[ + Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool] + ]: """Returns a default filter criterion method to filter the eigenvalues computed by the eigen solver. For more information see also qiskit.algorithms.eigen_solvers.NumPyEigensolver.filter_criterion. @@ -132,13 +155,19 @@ def filter_criterion(self, eigenstate, eigenvalue, aux_values): # the second aux_value is the total angular momentum which (for singlets) should be zero total_angular_momentum_aux = aux_values[1][0] q_molecule_transformed = cast(QMolecule, self._molecule_data_transformed) - return np.isclose( - q_molecule_transformed.num_alpha + q_molecule_transformed.num_beta, - num_particles_aux) and np.isclose(0., total_angular_momentum_aux) + return ( + np.isclose( + q_molecule_transformed.num_alpha + q_molecule_transformed.num_beta, + num_particles_aux, + ) + and np.isclose(0.0, total_angular_momentum_aux) + ) return partial(filter_criterion, self) - def symmetry_sector_locator(self, z2_symmetries: Z2Symmetries) -> Optional[List[int]]: + def symmetry_sector_locator( + self, z2_symmetries: Z2Symmetries + ) -> Optional[List[int]]: """Given the detected Z2Symmetries can determine the correct sector of the tapered operators so the correct one can be returned @@ -152,8 +181,11 @@ def symmetry_sector_locator(self, z2_symmetries: Z2Symmetries) -> Optional[List[ hf_bitstr = hartree_fock_bitstring( num_spin_orbitals=2 * q_molecule.num_molecular_orbitals, - num_particles=self.num_particles) - sector_locator = ElectronicStructureProblem._pick_sector(z2_symmetries, hf_bitstr) + num_particles=self.num_particles, + ) + sector_locator = ElectronicStructureProblem._pick_sector( + z2_symmetries, hf_bitstr + ) return sector_locator @@ -162,7 +194,9 @@ def _pick_sector(z2_symmetries: Z2Symmetries, hf_str: List[bool]) -> List[int]: # Finding all the symmetries using the find_Z2_symmetries: taper_coeff: List[int] = [] for sym in z2_symmetries.symmetries: - coeff = -1 if np.logical_xor.reduce(np.logical_and(sym.z[::-1], hf_str)) else 1 + coeff = ( + -1 if np.logical_xor.reduce(np.logical_and(sym.z[::-1], hf_str)) else 1 + ) taper_coeff.append(coeff) return taper_coeff diff --git a/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/__init__.py b/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/__init__.py index 6d8c4be121..c488da06ff 100644 --- a/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/__init__.py +++ b/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/__init__.py @@ -17,7 +17,7 @@ from .particle_number_integrals_calculator import calc_total_particle_num_ints __all__ = [ - 'calc_total_ang_momentum_ints', - 'calc_total_magnetization_ints', - 'calc_total_particle_num_ints', + "calc_total_ang_momentum_ints", + "calc_total_magnetization_ints", + "calc_total_particle_num_ints", ] diff --git a/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/angular_momentum_integrals_calculator.py b/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/angular_momentum_integrals_calculator.py index 6855b46997..52349c3eb5 100644 --- a/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/angular_momentum_integrals_calculator.py +++ b/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/angular_momentum_integrals_calculator.py @@ -39,25 +39,34 @@ def calc_total_ang_momentum_ints(num_modes: int) -> Tuple[np.ndarray, np.ndarray def _calc_s_x_squared_ints(num_modes: int) -> Tuple[np.ndarray, np.ndarray]: - return _calc_squared_ints(num_modes, _modify_s_x_squared_ints_neq, _modify_s_x_squared_ints_eq) + return _calc_squared_ints( + num_modes, _modify_s_x_squared_ints_neq, _modify_s_x_squared_ints_eq + ) def _calc_s_y_squared_ints(num_modes: int) -> Tuple[np.ndarray, np.ndarray]: - return _calc_squared_ints(num_modes, _modify_s_y_squared_ints_neq, _modify_s_y_squared_ints_eq) + return _calc_squared_ints( + num_modes, _modify_s_y_squared_ints_neq, _modify_s_y_squared_ints_eq + ) def _calc_s_z_squared_ints(num_modes: int) -> Tuple[np.ndarray, np.ndarray]: - return _calc_squared_ints(num_modes, _modify_s_z_squared_ints_neq, _modify_s_z_squared_ints_eq) + return _calc_squared_ints( + num_modes, _modify_s_z_squared_ints_neq, _modify_s_z_squared_ints_eq + ) -def _calc_squared_ints(num_modes: int, func_neq, func_eq) -> Tuple[np.ndarray, np.ndarray]: +def _calc_squared_ints( + num_modes: int, func_neq, func_eq +) -> Tuple[np.ndarray, np.ndarray]: # calculates 1- and 2-body integrals for a given angular momentum axis (x or y or z, # specified by func_neq and func_eq) num_modes_2 = num_modes // 2 h_1 = np.zeros((num_modes, num_modes)) h_2 = np.zeros((num_modes, num_modes, num_modes, num_modes)) - for p, q in itertools.product(range(num_modes_2), repeat=2): # pylint: disable=invalid-name + # pylint: disable=invalid-name + for p, q in itertools.product(range(num_modes_2), repeat=2): if p != q: h_2 = func_neq(h_2, p, q, num_modes_2) else: @@ -69,75 +78,102 @@ def _calc_squared_ints(num_modes: int, func_neq, func_eq) -> Tuple[np.ndarray, n return h_1, h_2 -def _modify_s_x_squared_ints_neq(h_2: np.ndarray, p_ind: int, q_ind: int, - num_modes_2: int) -> np.ndarray: - indices = [(p_ind, p_ind + num_modes_2, q_ind, q_ind + num_modes_2), - (p_ind + num_modes_2, p_ind, q_ind, q_ind + num_modes_2), - (p_ind, p_ind + num_modes_2, q_ind + num_modes_2, q_ind), - (p_ind + num_modes_2, p_ind, q_ind + num_modes_2, q_ind)] +def _modify_s_x_squared_ints_neq( + h_2: np.ndarray, p_ind: int, q_ind: int, num_modes_2: int +) -> np.ndarray: + indices = [ + (p_ind, p_ind + num_modes_2, q_ind, q_ind + num_modes_2), + (p_ind + num_modes_2, p_ind, q_ind, q_ind + num_modes_2), + (p_ind, p_ind + num_modes_2, q_ind + num_modes_2, q_ind), + (p_ind + num_modes_2, p_ind, q_ind + num_modes_2, q_ind), + ] values = [1, 1, 1, 1] # adds provided values to values of 2-body integrals (x axis of angular momentum) at given # indices in case p not equal to q return _add_values_to_s_squared_ints(h_2, indices, values) -def _modify_s_x_squared_ints_eq(h_2: np.ndarray, p_ind: int, num_modes_2: int) -> np.ndarray: - indices = [(p_ind, p_ind + num_modes_2, p_ind, p_ind + num_modes_2), - (p_ind + num_modes_2, p_ind, p_ind + num_modes_2, p_ind), - (p_ind, p_ind, p_ind + num_modes_2, p_ind + num_modes_2), - (p_ind + num_modes_2, p_ind + num_modes_2, p_ind, p_ind)] +def _modify_s_x_squared_ints_eq( + h_2: np.ndarray, p_ind: int, num_modes_2: int +) -> np.ndarray: + indices = [ + (p_ind, p_ind + num_modes_2, p_ind, p_ind + num_modes_2), + (p_ind + num_modes_2, p_ind, p_ind + num_modes_2, p_ind), + (p_ind, p_ind, p_ind + num_modes_2, p_ind + num_modes_2), + (p_ind + num_modes_2, p_ind + num_modes_2, p_ind, p_ind), + ] values = [-1, -1, -1, -1] # adds provided values to values of 2-body integrals (x axis of angular momentum) at given # indices in case p equal to q return _add_values_to_s_squared_ints(h_2, indices, values) -def _modify_s_y_squared_ints_neq(h_2: np.ndarray, p_ind: int, q_ind: int, - num_modes_2: int) -> np.ndarray: - indices = [(p_ind, p_ind + num_modes_2, q_ind, q_ind + num_modes_2), - (p_ind + num_modes_2, p_ind, q_ind, q_ind + num_modes_2), - (p_ind, p_ind + num_modes_2, q_ind + num_modes_2, q_ind), - (p_ind + num_modes_2, p_ind, q_ind + num_modes_2, q_ind)] +def _modify_s_y_squared_ints_neq( + h_2: np.ndarray, p_ind: int, q_ind: int, num_modes_2: int +) -> np.ndarray: + indices = [ + (p_ind, p_ind + num_modes_2, q_ind, q_ind + num_modes_2), + (p_ind + num_modes_2, p_ind, q_ind, q_ind + num_modes_2), + (p_ind, p_ind + num_modes_2, q_ind + num_modes_2, q_ind), + (p_ind + num_modes_2, p_ind, q_ind + num_modes_2, q_ind), + ] values = [-1, 1, 1, -1] # adds provided values to values of 2-body integrals (y axis of angular momentum) at given # indices in case p not equal to q return _add_values_to_s_squared_ints(h_2, indices, values) -def _modify_s_y_squared_ints_eq(h_2: np.ndarray, p_ind: int, num_modes_2: int) -> np.ndarray: - indices = [(p_ind, p_ind + num_modes_2, p_ind, p_ind + num_modes_2), - (p_ind + num_modes_2, p_ind, p_ind + num_modes_2, p_ind), - (p_ind, p_ind, p_ind + num_modes_2, p_ind + num_modes_2), - (p_ind + num_modes_2, p_ind + num_modes_2, p_ind, p_ind)] +def _modify_s_y_squared_ints_eq( + h_2: np.ndarray, p_ind: int, num_modes_2: int +) -> np.ndarray: + indices = [ + (p_ind, p_ind + num_modes_2, p_ind, p_ind + num_modes_2), + (p_ind + num_modes_2, p_ind, p_ind + num_modes_2, p_ind), + (p_ind, p_ind, p_ind + num_modes_2, p_ind + num_modes_2), + (p_ind + num_modes_2, p_ind + num_modes_2, p_ind, p_ind), + ] values = [1, 1, -1, -1] # adds provided values to values of 2-body integrals (y axis of angular momentum) at given # indices in case p equal to q return _add_values_to_s_squared_ints(h_2, indices, values) -def _modify_s_z_squared_ints_neq(h_2: np.ndarray, p_ind: int, q_ind: int, - num_modes_2: int) -> np.ndarray: - indices = [(p_ind, p_ind, q_ind, q_ind), - (p_ind + num_modes_2, p_ind + num_modes_2, q_ind, q_ind), - (p_ind, p_ind, q_ind + num_modes_2, q_ind + num_modes_2), - (p_ind + num_modes_2, p_ind + num_modes_2, q_ind + num_modes_2, q_ind + num_modes_2)] +def _modify_s_z_squared_ints_neq( + h_2: np.ndarray, p_ind: int, q_ind: int, num_modes_2: int +) -> np.ndarray: + indices = [ + (p_ind, p_ind, q_ind, q_ind), + (p_ind + num_modes_2, p_ind + num_modes_2, q_ind, q_ind), + (p_ind, p_ind, q_ind + num_modes_2, q_ind + num_modes_2), + ( + p_ind + num_modes_2, + p_ind + num_modes_2, + q_ind + num_modes_2, + q_ind + num_modes_2, + ), + ] values = [1, -1, -1, 1] # adds provided values to values of 2-body integrals (z axis of angular momentum) at given # indices in case p not equal to q return _add_values_to_s_squared_ints(h_2, indices, values) -def _modify_s_z_squared_ints_eq(h_2: np.ndarray, p_ind: int, num_modes_2: int) -> np.ndarray: - indices = [(p_ind, p_ind + num_modes_2, p_ind + num_modes_2, p_ind), - (p_ind + num_modes_2, p_ind, p_ind, p_ind + num_modes_2)] +def _modify_s_z_squared_ints_eq( + h_2: np.ndarray, p_ind: int, num_modes_2: int +) -> np.ndarray: + indices = [ + (p_ind, p_ind + num_modes_2, p_ind + num_modes_2, p_ind), + (p_ind + num_modes_2, p_ind, p_ind, p_ind + num_modes_2), + ] values = [1, 1] # adds provided values to values of 2-body integrals (z axis of angular momentum) at given # indices in case p equal to q return _add_values_to_s_squared_ints(h_2, indices, values) -def _add_values_to_s_squared_ints(h_2: np.ndarray, indices: List[Tuple[int, int, int, int]], - values: List[int]) -> np.ndarray: +def _add_values_to_s_squared_ints( + h_2: np.ndarray, indices: List[Tuple[int, int, int, int]], values: List[int] +) -> np.ndarray: for index, value in zip(indices, values): h_2[index] += value return h_2 diff --git a/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/magnetization_integrals_calculator.py b/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/magnetization_integrals_calculator.py index 0837084477..9ea65cbb34 100644 --- a/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/magnetization_integrals_calculator.py +++ b/qiskit_nature/problems/second_quantization/electronic/integrals_calculators/magnetization_integrals_calculator.py @@ -29,6 +29,6 @@ def calc_total_magnetization_ints(num_modes: int) -> Tuple[np.ndarray, None]: """ modes = num_modes h_1 = np.eye(modes, dtype=complex) * 0.5 - h_1[modes // 2:, modes // 2:] *= -1.0 + h_1[modes // 2 :, modes // 2 :] *= -1.0 return h_1, None diff --git a/qiskit_nature/problems/second_quantization/electronic/result_interpreter.py b/qiskit_nature/problems/second_quantization/electronic/result_interpreter.py index e69a6e52f1..a7dd7b2f7c 100644 --- a/qiskit_nature/problems/second_quantization/electronic/result_interpreter.py +++ b/qiskit_nature/problems/second_quantization/electronic/result_interpreter.py @@ -16,13 +16,18 @@ from qiskit.algorithms import EigensolverResult, MinimumEigensolverResult from qiskit_nature.drivers import QMolecule -from qiskit_nature.results import EigenstateResult, ElectronicStructureResult, DipoleTuple - - -def _interpret(molecule_data: QMolecule, molecule_data_transformed: QMolecule, - raw_result: Union[EigenstateResult, EigensolverResult, - MinimumEigensolverResult]) -> \ - ElectronicStructureResult: +from qiskit_nature.results import ( + EigenstateResult, + ElectronicStructureResult, + DipoleTuple, +) + + +def _interpret( + molecule_data: QMolecule, + molecule_data_transformed: QMolecule, + raw_result: Union[EigenstateResult, EigensolverResult, MinimumEigensolverResult], +) -> ElectronicStructureResult: """Interprets an EigenstateResult in the context of this transformation. Args: @@ -35,8 +40,9 @@ def _interpret(molecule_data: QMolecule, molecule_data_transformed: QMolecule, """ eigenstate_result = _interpret_raw_result(raw_result) - result = _interpret_electr_struct_result(eigenstate_result, molecule_data, - molecule_data_transformed) + result = _interpret_electr_struct_result( + eigenstate_result, molecule_data, molecule_data_transformed + ) return result @@ -56,12 +62,15 @@ def _interpret_raw_result(raw_result): eigenstate_result.raw_result = raw_result eigenstate_result.eigenenergies = np.asarray([raw_result.eigenvalue]) eigenstate_result.eigenstates = [raw_result.eigenstate] - eigenstate_result.aux_operator_eigenvalues = [raw_result.aux_operator_eigenvalues] + eigenstate_result.aux_operator_eigenvalues = [ + raw_result.aux_operator_eigenvalues + ] return eigenstate_result -def _interpret_electr_struct_result(eigenstate_result, molecule_data, - molecule_data_transformed): +def _interpret_electr_struct_result( + eigenstate_result, molecule_data, molecule_data_transformed +): q_molecule = cast(QMolecule, molecule_data) q_molecule_transformed = cast(QMolecule, molecule_data_transformed) result = ElectronicStructureResult() @@ -75,7 +84,9 @@ def _interpret_electr_struct_result(eigenstate_result, molecule_data, def _interpret_eigenstate_results(eigenstate_result, result): result.combine(eigenstate_result) - result.computed_energies = np.asarray([e.real for e in eigenstate_result.eigenenergies]) + result.computed_energies = np.asarray( + [e.real for e in eigenstate_result.eigenenergies] + ) def _interpret_q_molecule_results(q_molecule, result): @@ -116,7 +127,9 @@ def _interpret_aux_ops_results(q_molecule_transformed, result): result.magnetization.append(aux_op_eigenvalues[2][0].real) # type: ignore if len(aux_op_eigenvalues) >= 6 and q_molecule_transformed.has_dipole_integrals: - _interpret_dipole_results(aux_op_eigenvalues, q_molecule_transformed, result) + _interpret_dipole_results( + aux_op_eigenvalues, q_molecule_transformed, result + ) def _interpret_dipole_results(aux_op_eigenvalues, q_molecule_transformed, result): @@ -131,9 +144,16 @@ def _interpret_dipole_results(aux_op_eigenvalues, q_molecule_transformed, result result.reverse_dipole_sign = q_molecule_transformed.reverse_dipole_sign result.computed_dipole_moment.append(cast(DipoleTuple, tuple(dipole_moment))) - result.extracted_transformer_dipoles.append({ - name: cast(DipoleTuple, (q_molecule_transformed.x_dip_energy_shift[name], - q_molecule_transformed.y_dip_energy_shift[name], - q_molecule_transformed.z_dip_energy_shift[name])) - for name in q_molecule_transformed.x_dip_energy_shift.keys() - }) + result.extracted_transformer_dipoles.append( + { + name: cast( + DipoleTuple, + ( + q_molecule_transformed.x_dip_energy_shift[name], + q_molecule_transformed.y_dip_energy_shift[name], + q_molecule_transformed.z_dip_energy_shift[name], + ), + ) + for name in q_molecule_transformed.x_dip_energy_shift.keys() + } + ) diff --git a/qiskit_nature/problems/second_quantization/vibrational/builders/aux_vibrational_ops_builder.py b/qiskit_nature/problems/second_quantization/vibrational/builders/aux_vibrational_ops_builder.py index d197656f3c..5a02c55588 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/builders/aux_vibrational_ops_builder.py +++ b/qiskit_nature/problems/second_quantization/vibrational/builders/aux_vibrational_ops_builder.py @@ -15,8 +15,9 @@ from typing import List from qiskit_nature.operators.second_quantization import VibrationalOp -from qiskit_nature.problems.second_quantization.vibrational.integrals_calculators import \ - calc_occ_modals_per_mode_ints +from qiskit_nature.problems.second_quantization.vibrational.integrals_calculators import ( + calc_occ_modals_per_mode_ints, +) from .vibrational_op_builder import build_vibrational_op_from_ints @@ -32,14 +33,18 @@ def _create_all_aux_operators(num_modals: List[int]) -> List[VibrationalOp]: aux_second_quantized_ops_list = [] for mode in range(len(num_modals)): - aux_second_quantized_ops_list.append(_create_occ_modals_per_mode(num_modals, mode)) + aux_second_quantized_ops_list.append( + _create_occ_modals_per_mode(num_modals, mode) + ) return aux_second_quantized_ops_list -def _create_occ_modals_per_mode(num_modals: List[int], mode_index: int) -> VibrationalOp: +def _create_occ_modals_per_mode( + num_modals: List[int], mode_index: int +) -> VibrationalOp: return build_vibrational_op_from_ints( calc_occ_modals_per_mode_ints(num_modals, mode_index), len(num_modals), - num_modals + num_modals, ) diff --git a/qiskit_nature/problems/second_quantization/vibrational/builders/hopping_ops_builder.py b/qiskit_nature/problems/second_quantization/vibrational/builders/hopping_ops_builder.py index 9321a9120f..ff83c139ea 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/builders/hopping_ops_builder.py +++ b/qiskit_nature/problems/second_quantization/vibrational/builders/hopping_ops_builder.py @@ -23,15 +23,20 @@ from qiskit_nature.converters.second_quantization import QubitConverter -def _build_qeom_hopping_ops(num_modals: List[int], - qubit_converter: QubitConverter, - excitations: Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[Tuple[int, ...], - Tuple[int, ...]]]]] = 'sd', - ) -> Tuple[Dict[str, PauliSumOp], - Dict[str, List[bool]], - Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]]]: +def _build_qeom_hopping_ops( + num_modals: List[int], + qubit_converter: QubitConverter, + excitations: Union[ + str, + int, + List[int], + Callable[[int, Tuple[int, int]], List[Tuple[Tuple[int, ...], Tuple[int, ...]]]], + ] = "sd", +) -> Tuple[ + Dict[str, PauliSumOp], + Dict[str, List[bool]], + Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]], +]: """ Args: num_modals: the number of modals per mode. @@ -50,13 +55,17 @@ def _build_qeom_hopping_ops(num_modals: List[int], """ excitations_list: List[Tuple[Tuple[int, ...], Tuple[int, ...]]] - if isinstance(excitations, (str, int)) or \ - (isinstance(excitations, list) and all(isinstance(exc, int) for exc in excitations)): + if isinstance(excitations, (str, int)) or ( + isinstance(excitations, list) + and all(isinstance(exc, int) for exc in excitations) + ): excitations = cast(Union[str, int, List[int]], excitations) ansatz = UVCC(qubit_converter, num_modals, excitations) excitations_list = ansatz._get_excitation_list() else: - excitations_list = cast(List[Tuple[Tuple[int, ...], Tuple[int, ...]]], excitations) + excitations_list = cast( + List[Tuple[Tuple[int, ...], Tuple[int, ...]]], excitations + ) size = len(excitations_list) @@ -65,15 +74,17 @@ def _build_qeom_hopping_ops(num_modals: List[int], to_be_executed_list = [] for idx in range(size): to_be_executed_list += [excitations_list[idx], excitations_list[idx][::-1]] - hopping_operators['E_{}'.format(idx)] = None - hopping_operators['Edag_{}'.format(idx)] = None - excitation_indices['E_{}'.format(idx)] = excitations_list[idx] - excitation_indices['Edag_{}'.format(idx)] = excitations_list[idx][::-1] - - result = parallel_map(_build_single_hopping_operator, - to_be_executed_list, - task_args=(num_modals, qubit_converter), - num_processes=algorithm_globals.num_processes) + hopping_operators["E_{}".format(idx)] = None + hopping_operators["Edag_{}".format(idx)] = None + excitation_indices["E_{}".format(idx)] = excitations_list[idx] + excitation_indices["Edag_{}".format(idx)] = excitations_list[idx][::-1] + + result = parallel_map( + _build_single_hopping_operator, + to_be_executed_list, + task_args=(num_modals, qubit_converter), + num_processes=algorithm_globals.num_processes, + ) for key, res in zip(hopping_operators.keys(), result): hopping_operators[key] = res @@ -85,17 +96,19 @@ def _build_qeom_hopping_ops(num_modals: List[int], return hopping_operators, type_of_commutativities, excitation_indices # type: ignore -def _build_single_hopping_operator(excitation: Tuple[Tuple[int, ...], Tuple[int, ...]], - num_modals: List[int], - qubit_converter: QubitConverter) -> PauliSumOp: +def _build_single_hopping_operator( + excitation: Tuple[Tuple[int, ...], Tuple[int, ...]], + num_modals: List[int], + qubit_converter: QubitConverter, +) -> PauliSumOp: sum_modes = sum(num_modals) - label = ['I'] * sum_modes + label = ["I"] * sum_modes for occ in excitation[0]: - label[occ] = '+' + label[occ] = "+" for unocc in excitation[1]: - label[unocc] = '-' - vibrational_op = VibrationalOp(''.join(label), len(num_modals), num_modals) + label[unocc] = "-" + vibrational_op = VibrationalOp("".join(label), len(num_modals), num_modals) qubit_op: PauliSumOp = qubit_converter.convert_match(vibrational_op) return qubit_op diff --git a/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_label_builder.py b/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_label_builder.py index 7b7f5b23c3..90bdb65ae2 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_label_builder.py +++ b/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_label_builder.py @@ -15,8 +15,9 @@ from typing import Tuple, List -def _create_labels(boson_hamilt_harm_basis: List[List[Tuple[List[List[int]], complex]]]) -> \ - List[Tuple[str, complex]]: +def _create_labels( + boson_hamilt_harm_basis: List[List[Tuple[List[List[int]], complex]]] +) -> List[Tuple[str, complex]]: """Creates `VibrationalOp` labels from a data structure returned by the convert() method in `HarmonicBasis`. @@ -32,8 +33,9 @@ def _create_labels(boson_hamilt_harm_basis: List[List[Tuple[List[List[int]], com return all_labels -def _create_num_body_labels(num_body_data: List[Tuple[List[List[int]], complex]]) -> \ - List[Tuple[str, complex]]: +def _create_num_body_labels( + num_body_data: List[Tuple[List[List[int]], complex]] +) -> List[Tuple[str, complex]]: num_body_labels = [] for indices, coeff in num_body_data: indices.sort() diff --git a/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_op_builder.py b/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_op_builder.py index 378a1a037d..312d009be8 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_op_builder.py +++ b/qiskit_nature/problems/second_quantization/vibrational/builders/vibrational_op_builder.py @@ -18,17 +18,19 @@ from qiskit_nature.drivers.bosonic_bases import BosonicBasis, HarmonicBasis from qiskit_nature.operators.second_quantization import VibrationalOp -from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder \ - import _create_labels +from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder import ( + _create_labels, +) logger = logging.getLogger(__name__) -def _build_vibrational_op(watson_hamiltonian: WatsonHamiltonian, - num_modals: Union[int, List[int]], - truncation_order: int, - basis: Optional[BosonicBasis] = None, - ) -> VibrationalOp: +def _build_vibrational_op( + watson_hamiltonian: WatsonHamiltonian, + num_modals: Union[int, List[int]], + truncation_order: int, + basis: Optional[BosonicBasis] = None, +) -> VibrationalOp: """ Builds a :class:`VibrationalOp` based on a :class:`WatsonHamiltonian` object. @@ -45,24 +47,30 @@ def _build_vibrational_op(watson_hamiltonian: WatsonHamiltonian, """ if basis is not None: logger.warning( - 'The only supported `BosonicBasis` is the `HarmonicBasis`. However you specified ' - '%s as an input, which will be ignored.', str(basis)) + "The only supported `BosonicBasis` is the `HarmonicBasis`. However you specified " + "%s as an input, which will be ignored.", + str(basis), + ) num_modes = watson_hamiltonian.num_modes if isinstance(num_modals, int): num_modals = [num_modals] * num_modes - boson_hamilt_harm_basis = HarmonicBasis(watson_hamiltonian, - num_modals, truncation_order).convert() + boson_hamilt_harm_basis = HarmonicBasis( + watson_hamiltonian, num_modals, truncation_order + ).convert() - return build_vibrational_op_from_ints(boson_hamilt_harm_basis, num_modes, num_modals) + return build_vibrational_op_from_ints( + boson_hamilt_harm_basis, num_modes, num_modals + ) -def build_vibrational_op_from_ints(h_mat: List[List[Tuple[List[List[int]], complex]]], - num_modes: int, - num_modals: List[int], - ) -> VibrationalOp: +def build_vibrational_op_from_ints( + h_mat: List[List[Tuple[List[List[int]], complex]]], + num_modes: int, + num_modals: List[int], +) -> VibrationalOp: """ Builds a :class:`VibrationalOp` based on an integral list as produced by :meth:`HarmonicBasis.convert()`. diff --git a/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/__init__.py b/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/__init__.py index d3e2b2914b..f2d0b8ceec 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/__init__.py +++ b/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/__init__.py @@ -15,5 +15,5 @@ from .occupied_modal_per_mode_integrals_calculator import calc_occ_modals_per_mode_ints __all__ = [ - 'calc_occ_modals_per_mode_ints', + "calc_occ_modals_per_mode_ints", ] diff --git a/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/occupied_modal_per_mode_integrals_calculator.py b/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/occupied_modal_per_mode_integrals_calculator.py index d9c24ecb67..5d88a9b6db 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/occupied_modal_per_mode_integrals_calculator.py +++ b/qiskit_nature/problems/second_quantization/vibrational/integrals_calculators/occupied_modal_per_mode_integrals_calculator.py @@ -15,9 +15,9 @@ from typing import List, Tuple -def calc_occ_modals_per_mode_ints(num_modals: List[int], - mode_index: int - ) -> List[List[Tuple[List[List[int]], complex]]]: +def calc_occ_modals_per_mode_ints( + num_modals: List[int], mode_index: int +) -> List[List[Tuple[List[List[int]], complex]]]: """ Calculates WatsonHamiltonian-like integrals to evaluate the number of occupied modals in a given mode. @@ -32,6 +32,6 @@ def calc_occ_modals_per_mode_ints(num_modals: List[int], """ h_mat: List[List[Tuple[List[List[int]], complex]]] = [[]] for modal in range(num_modals[mode_index]): - h_mat[0].append(([[mode_index, modal, modal]], 1.)) + h_mat[0].append(([[mode_index, modal, modal]], 1.0)) return h_mat diff --git a/qiskit_nature/problems/second_quantization/vibrational/result_interpreter.py b/qiskit_nature/problems/second_quantization/vibrational/result_interpreter.py index 20128482f4..89d54737a7 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/result_interpreter.py +++ b/qiskit_nature/problems/second_quantization/vibrational/result_interpreter.py @@ -18,16 +18,17 @@ from qiskit_nature.results import EigenstateResult, VibrationalStructureResult -def _interpret(num_modes: int, raw_result: Union[EigenstateResult, EigensolverResult, - MinimumEigensolverResult]) -> \ - VibrationalStructureResult: +def _interpret( + num_modes: int, + raw_result: Union[EigenstateResult, EigensolverResult, MinimumEigensolverResult], +) -> VibrationalStructureResult: """Interprets an EigenstateResult in the context of this transformation. - Args: - num_modes: number of modes. - raw_result: an eigenstate result object. - Returns: - An vibrational structure result. - """ + Args: + num_modes: number of modes. + raw_result: an eigenstate result object. + Returns: + An vibrational structure result. + """ eigenstate_result = _interpret_raw_result(raw_result) result = _interpret_vibr_struct_result(eigenstate_result) diff --git a/qiskit_nature/problems/second_quantization/vibrational/vibrational_structure_problem.py b/qiskit_nature/problems/second_quantization/vibrational/vibrational_structure_problem.py index 1d6ad786b8..d5d8b7530b 100644 --- a/qiskit_nature/problems/second_quantization/vibrational/vibrational_structure_problem.py +++ b/qiskit_nature/problems/second_quantization/vibrational/vibrational_structure_problem.py @@ -35,8 +35,13 @@ class VibrationalStructureProblem(BaseProblem): """Vibrational Structure Problem""" - def __init__(self, bosonic_driver: BosonicDriver, num_modals: Union[int, List[int]], - truncation_order: int, transformers: Optional[List[BaseTransformer]] = None): + def __init__( + self, + bosonic_driver: BosonicDriver, + num_modals: Union[int, List[int]], + truncation_order: int, + transformers: Optional[List[BaseTransformer]] = None, + ): """ Args: bosonic_driver: A bosonic driver encoding the molecule information. @@ -55,13 +60,16 @@ def second_q_ops(self) -> List[SecondQuantizedOp]: Returns: A list of `SecondQuantizedOp` in the following order: ... . """ - self._molecule_data: WatsonHamiltonian = cast(WatsonHamiltonian, self.driver.run()) - self._molecule_data_transformed: WatsonHamiltonian = \ - cast(WatsonHamiltonian, self._transform(self._molecule_data)) + self._molecule_data: WatsonHamiltonian = cast( + WatsonHamiltonian, self.driver.run() + ) + self._molecule_data_transformed: WatsonHamiltonian = cast( + WatsonHamiltonian, self._transform(self._molecule_data) + ) - vibrational_spin_op = _build_vibrational_op(self._molecule_data_transformed, - self.num_modals, - self.truncation_order) + vibrational_spin_op = _build_vibrational_op( + self._molecule_data_transformed, self.num_modals, self.truncation_order + ) num_modes = self._molecule_data_transformed.num_modes if isinstance(self.num_modals, int): @@ -69,18 +77,28 @@ def second_q_ops(self) -> List[SecondQuantizedOp]: else: num_modals = self.num_modals - second_quantized_ops_list = [vibrational_spin_op] + _create_all_aux_operators(num_modals) + second_quantized_ops_list = [vibrational_spin_op] + _create_all_aux_operators( + num_modals + ) return second_quantized_ops_list - def hopping_qeom_ops(self, qubit_converter: QubitConverter, - excitations: Union[str, int, List[int], - Callable[[int, Tuple[int, int]], - List[Tuple[ - Tuple[int, ...], Tuple[ - int, ...]]]]] = 'sd', - ) -> Tuple[Dict[str, PauliSumOp], Dict[str, List[bool]], - Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]]]: + def hopping_qeom_ops( + self, + qubit_converter: QubitConverter, + excitations: Union[ + str, + int, + List[int], + Callable[ + [int, Tuple[int, int]], List[Tuple[Tuple[int, ...], Tuple[int, ...]]] + ], + ] = "sd", + ) -> Tuple[ + Dict[str, PauliSumOp], + Dict[str, List[bool]], + Dict[str, Tuple[Tuple[int, ...], Tuple[int, ...]]], + ]: """Generates the hopping operators and their commutativity information for the specified set of excitations. @@ -109,19 +127,26 @@ def hopping_qeom_ops(self, qubit_converter: QubitConverter, return _build_qeom_hopping_ops(num_modals, qubit_converter, excitations) - def interpret(self, raw_result: Union[EigenstateResult, EigensolverResult, - MinimumEigensolverResult]) -> VibrationalStructureResult: + def interpret( + self, + raw_result: Union[ + EigenstateResult, EigensolverResult, MinimumEigensolverResult + ], + ) -> VibrationalStructureResult: """Interprets an EigenstateResult in the context of this transformation. - Args: - raw_result: an eigenstate result object. - Returns: - An vibrational structure result. - """ + Args: + raw_result: an eigenstate result object. + Returns: + An vibrational structure result. + """ return _interpret(self._molecule_data.num_modes, raw_result) - def get_default_filter_criterion(self) -> Optional[Callable[[Union[List, np.ndarray], float, - Optional[List[float]]], bool]]: + def get_default_filter_criterion( + self, + ) -> Optional[ + Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool] + ]: """Returns a default filter criterion method to filter the eigenvalues computed by the eigen solver. For more information see also aqua.algorithms.eigen_solvers.NumPyEigensolver.filter_criterion. diff --git a/qiskit_nature/results/__init__.py b/qiskit_nature/results/__init__.py index ec2cacecf3..662518e662 100644 --- a/qiskit_nature/results/__init__.py +++ b/qiskit_nature/results/__init__.py @@ -39,9 +39,9 @@ from .vibrational_structure_result import VibrationalStructureResult __all__ = [ - 'BOPESSamplerResult', - 'DipoleTuple', - 'EigenstateResult', - 'ElectronicStructureResult', - 'VibrationalStructureResult', + "BOPESSamplerResult", + "DipoleTuple", + "EigenstateResult", + "ElectronicStructureResult", + "VibrationalStructureResult", ] diff --git a/qiskit_nature/results/bopes_sampler_result.py b/qiskit_nature/results/bopes_sampler_result.py index 6d95a34735..93c32f4d35 100644 --- a/qiskit_nature/results/bopes_sampler_result.py +++ b/qiskit_nature/results/bopes_sampler_result.py @@ -23,9 +23,12 @@ class BOPESSamplerResult: """The BOPES Sampler result""" - def __init__(self, points: List[float], - energies: List[float], - raw_results: Dict[float, EigenstateResult]) -> None: + def __init__( + self, + points: List[float], + energies: List[float], + raw_results: Dict[float, EigenstateResult], + ) -> None: """ Creates an new instance of the result. Args: @@ -40,19 +43,19 @@ def __init__(self, points: List[float], @property def points(self) -> List[float]: - """ returns list of points.""" + """returns list of points.""" return self._points @property def energies(self) -> List[float]: - """ returns list of energies.""" + """returns list of energies.""" return self._energies @property def raw_results(self) -> Dict[float, EigenstateResult]: - """ returns all results for all points.""" + """returns all results for all points.""" return self._raw_results def point_results(self, point: float) -> EigenstateResult: - """ returns all results for a specific point.""" + """returns all results for a specific point.""" return self.raw_results[point] diff --git a/qiskit_nature/results/eigenstate_result.py b/qiskit_nature/results/eigenstate_result.py index 496b53317b..de9dfdab22 100644 --- a/qiskit_nature/results/eigenstate_result.py +++ b/qiskit_nature/results/eigenstate_result.py @@ -29,47 +29,100 @@ class EigenstateResult(AlgorithmResult): def __init__(self) -> None: super().__init__() self._eigenenergies: Optional[np.ndarray] = None - self._eigenstates: Optional[List[Union[str, - dict, Result, list, np.ndarray, Statevector, - QuantumCircuit, - Instruction, OperatorBase]]] = None + self._eigenstates: Optional[ + List[ + Union[ + str, + dict, + Result, + list, + np.ndarray, + Statevector, + QuantumCircuit, + Instruction, + OperatorBase, + ] + ] + ] = None self._aux_operator_eigenvalues: Optional[List[float]] = None self._raw_result: Optional[AlgorithmResult] = None @property def eigenenergies(self) -> Optional[np.ndarray]: - """ returns eigen energies """ + """returns eigen energies""" return self._eigenenergies @eigenenergies.setter def eigenenergies(self, value: np.ndarray) -> None: - """ set eigen energies """ + """set eigen energies""" self._eigenenergies = value @property - def eigenstates(self) -> Optional[List[Union[str, dict, Result, list, np.ndarray, Statevector, - QuantumCircuit, Instruction, OperatorBase]]]: - """ returns eigen states """ + def eigenstates( + self, + ) -> Optional[ + List[ + Union[ + str, + dict, + Result, + list, + np.ndarray, + Statevector, + QuantumCircuit, + Instruction, + OperatorBase, + ] + ] + ]: + """returns eigen states""" return self._eigenstates @eigenstates.setter - def eigenstates(self, value: List[Union[str, dict, Result, list, np.ndarray, Statevector, - QuantumCircuit, Instruction, OperatorBase]]) -> None: - """ set eigen states """ + def eigenstates( + self, + value: List[ + Union[ + str, + dict, + Result, + list, + np.ndarray, + Statevector, + QuantumCircuit, + Instruction, + OperatorBase, + ] + ], + ) -> None: + """set eigen states""" self._eigenstates = value @property def groundenergy(self) -> Optional[float]: - """ returns ground energy """ + """returns ground energy""" energies = self.eigenenergies if isinstance(energies, np.ndarray) and not energies.size: return energies[0].real return None @property - def groundstate(self) -> Optional[Union[str, dict, Result, list, np.ndarray, Statevector, - QuantumCircuit, Instruction, OperatorBase]]: - """ returns ground state """ + def groundstate( + self, + ) -> Optional[ + Union[ + str, + dict, + Result, + list, + np.ndarray, + Statevector, + QuantumCircuit, + Instruction, + OperatorBase, + ] + ]: + """returns ground state""" states = self.eigenstates if states: return states[0] @@ -77,12 +130,12 @@ def groundstate(self) -> Optional[Union[str, dict, Result, list, np.ndarray, Sta @property def aux_operator_eigenvalues(self) -> Optional[List[float]]: - """ return aux operator eigen values """ + """return aux operator eigen values""" return self._aux_operator_eigenvalues @aux_operator_eigenvalues.setter def aux_operator_eigenvalues(self, value: List[float]) -> None: - """ set aux operator eigen values """ + """set aux operator eigen values""" self._aux_operator_eigenvalues = value @property @@ -104,15 +157,18 @@ def combine(self, result: AlgorithmResult) -> None: TypeError: Argument is None """ if result is None: - raise TypeError('Argument result expected.') + raise TypeError("Argument result expected.") if result == self: return # find any result public property that exists in the receiver for name, value in inspect.getmembers(result): - if not name.startswith('_') and \ - not inspect.ismethod(value) and not inspect.isfunction(value) and \ - hasattr(self, name): + if ( + not name.startswith("_") + and not inspect.ismethod(value) + and not inspect.isfunction(value) + and hasattr(self, name) + ): try: setattr(self, name, value) except AttributeError: diff --git a/qiskit_nature/results/electronic_structure_result.py b/qiskit_nature/results/electronic_structure_result.py index 81ddbbc93b..34ecfdf62b 100644 --- a/qiskit_nature/results/electronic_structure_result.py +++ b/qiskit_nature/results/electronic_structure_result.py @@ -35,42 +35,44 @@ class ElectronicStructureResult(EigenstateResult): def __init__(self) -> None: super().__init__() - self._hartree_fock_energy: float = 0. + self._hartree_fock_energy: float = 0.0 self._nuclear_repulsion_energy: Optional[float] = None self._nuclear_dipole_moment: Optional[DipoleTuple] = None self._computed_energies: Optional[np.ndarray] = None self._extracted_transformer_energies: Dict[str, float] = {} - self._extracted_transformer_dipoles: Optional[List[Dict[str, DipoleTuple]]] = None + self._extracted_transformer_dipoles: Optional[ + List[Dict[str, DipoleTuple]] + ] = None self._reverse_dipole_sign: bool = False @property def hartree_fock_energy(self) -> float: - """ Returns Hartree-Fock energy """ + """Returns Hartree-Fock energy""" return self._hartree_fock_energy @hartree_fock_energy.setter def hartree_fock_energy(self, value: float) -> None: - """ Sets Hartree-Fock energy """ + """Sets Hartree-Fock energy""" self._hartree_fock_energy = value @property def nuclear_repulsion_energy(self) -> Optional[float]: - """ Returns nuclear repulsion energy when available from driver """ + """Returns nuclear repulsion energy when available from driver""" return self._nuclear_repulsion_energy @nuclear_repulsion_energy.setter def nuclear_repulsion_energy(self, value: float) -> None: - """ Sets nuclear repulsion energy """ + """Sets nuclear repulsion energy""" self._nuclear_repulsion_energy = value @property def nuclear_dipole_moment(self) -> Optional[DipoleTuple]: - """ Returns nuclear dipole moment X,Y,Z components in A.U when available from driver """ + """Returns nuclear dipole moment X,Y,Z components in A.U when available from driver""" return self._nuclear_dipole_moment @nuclear_dipole_moment.setter def nuclear_dipole_moment(self, value: DipoleTuple) -> None: - """ Sets nuclear dipole moment in A.U """ + """Sets nuclear dipole moment in A.U""" self._nuclear_dipole_moment = value # TODO we need to be able to extract the statevector or the optimal parameters that can @@ -78,14 +80,18 @@ def nuclear_dipole_moment(self, value: DipoleTuple) -> None: @property def total_energies(self) -> np.ndarray: - """ Returns ground state energy if nuclear_repulsion_energy is available from driver """ - nre = self.nuclear_repulsion_energy if self.nuclear_repulsion_energy is not None else 0 + """Returns ground state energy if nuclear_repulsion_energy is available from driver""" + nre = ( + self.nuclear_repulsion_energy + if self.nuclear_repulsion_energy is not None + else 0 + ) # Adding float to np.ndarray adds it to each entry return self.electronic_energies + nre @property def electronic_energies(self) -> np.ndarray: - """ Returns electronic part of ground state energy """ + """Returns electronic part of ground state energy""" # TODO the fact that this property is computed on the fly breaks the `.combine()` # functionality # Adding float to np.ndarray adds it to each entry @@ -93,12 +99,12 @@ def electronic_energies(self) -> np.ndarray: @property def computed_energies(self) -> Optional[np.ndarray]: - """ Returns computed electronic part of ground state energy """ + """Returns computed electronic part of ground state energy""" return self._computed_energies @computed_energies.setter def computed_energies(self, value: np.ndarray) -> None: - """ Sets computed electronic part of ground state energy """ + """Sets computed electronic part of ground state energy""" self._computed_energies = value @property @@ -120,22 +126,25 @@ def extracted_transformer_energy(self) -> float: # drivers either support dipole integrals or not. Note that when using Z2 symmetries of def has_dipole(self) -> bool: - """ Returns whether dipole moment is present in result or not """ - return self.nuclear_dipole_moment is not None and self.electronic_dipole_moment is not None + """Returns whether dipole moment is present in result or not""" + return ( + self.nuclear_dipole_moment is not None + and self.electronic_dipole_moment is not None + ) @property def reverse_dipole_sign(self) -> bool: - """ Returns if electronic dipole moment sign should be reversed when adding to nuclear """ + """Returns if electronic dipole moment sign should be reversed when adding to nuclear""" return self._reverse_dipole_sign @reverse_dipole_sign.setter def reverse_dipole_sign(self, value: bool) -> None: - """ Sets if electronic dipole moment sign should be reversed when adding to nuclear """ + """Sets if electronic dipole moment sign should be reversed when adding to nuclear""" self._reverse_dipole_sign = value @property def total_dipole_moment(self) -> Optional[List[float]]: - """ Returns total dipole of moment """ + """Returns total dipole of moment""" if self.dipole_moment is None: return None # No dipole at all tdm: List[float] = [] @@ -148,7 +157,7 @@ def total_dipole_moment(self) -> Optional[List[float]]: @property def total_dipole_moment_in_debye(self) -> Optional[List[float]]: - """ Returns total dipole of moment in Debye """ + """Returns total dipole of moment in Debye""" tdm = self.total_dipole_moment if tdm is None: return None @@ -156,41 +165,47 @@ def total_dipole_moment_in_debye(self) -> Optional[List[float]]: @property def dipole_moment(self) -> Optional[List[DipoleTuple]]: - """ Returns dipole moment """ + """Returns dipole moment""" edm = self.electronic_dipole_moment if self.reverse_dipole_sign: - edm = [cast(DipoleTuple, tuple(-1 * x if x is not None else None for x in dip)) - for dip in edm] + edm = [ + cast(DipoleTuple, tuple(-1 * x if x is not None else None for x in dip)) + for dip in edm + ] return [_dipole_tuple_add(dip, self.nuclear_dipole_moment) for dip in edm] @property def dipole_moment_in_debye(self) -> Optional[List[DipoleTuple]]: - """ Returns dipole moment in Debye """ + """Returns dipole moment in Debye""" dipm = self.dipole_moment if dipm is None: return None dipmd = [] for dip in dipm: - dipmd0 = dip[0]/QMolecule.DEBYE if dip[0] is not None else None - dipmd1 = dip[1]/QMolecule.DEBYE if dip[1] is not None else None - dipmd2 = dip[2]/QMolecule.DEBYE if dip[2] is not None else None + dipmd0 = dip[0] / QMolecule.DEBYE if dip[0] is not None else None + dipmd1 = dip[1] / QMolecule.DEBYE if dip[1] is not None else None + dipmd2 = dip[2] / QMolecule.DEBYE if dip[2] is not None else None dipmd += [(dipmd0, dipmd1, dipmd2)] return dipmd @property def electronic_dipole_moment(self) -> Optional[List[DipoleTuple]]: - """ Returns electronic dipole moment """ - return [_dipole_tuple_add(comp_dip, extr_dip) for comp_dip, extr_dip in - zip(self.computed_dipole_moment, self.extracted_transformer_dipole)] + """Returns electronic dipole moment""" + return [ + _dipole_tuple_add(comp_dip, extr_dip) + for comp_dip, extr_dip in zip( + self.computed_dipole_moment, self.extracted_transformer_dipole + ) + ] @property def computed_dipole_moment(self) -> Optional[List[DipoleTuple]]: - """ Returns computed electronic part of dipole moment """ + """Returns computed electronic part of dipole moment""" return self._computed_dipole_moment @computed_dipole_moment.setter def computed_dipole_moment(self, value: List[DipoleTuple]) -> None: - """ Sets computed electronic part of dipole moment """ + """Sets computed electronic part of dipole moment""" self._computed_dipole_moment = value @property @@ -199,7 +214,9 @@ def extracted_transformer_dipoles(self) -> Optional[List[Dict[str, DipoleTuple]] return self._extracted_transformer_dipoles @extracted_transformer_dipoles.setter - def extracted_transformer_dipoles(self, value: List[Dict[str, DipoleTuple]]) -> None: + def extracted_transformer_dipoles( + self, value: List[Dict[str, DipoleTuple]] + ) -> None: """Sets the dipole moments extracted by any applied transformers.""" self._extracted_transformer_dipoles = value @@ -221,24 +238,26 @@ def extracted_transformer_dipole(self) -> List[DipoleTuple]: # instead of any measured value. def has_observables(self): - """ Returns whether result has aux op observables such as spin, num particles """ - return self.total_angular_momentum is not None \ - or self.num_particles is not None \ + """Returns whether result has aux op observables such as spin, num particles""" + return ( + self.total_angular_momentum is not None + or self.num_particles is not None or self.magnetization is not None + ) @property def total_angular_momentum(self) -> Optional[List[float]]: - """ Returns total angular momentum (S^2) """ + """Returns total angular momentum (S^2)""" return self._total_angular_momentum @total_angular_momentum.setter def total_angular_momentum(self, value: List[float]) -> None: - """ Sets total angular momentum """ + """Sets total angular momentum""" self._total_angular_momentum = value @property def spin(self) -> Optional[List[float]]: - """ Returns computed spin """ + """Returns computed spin""" if self.total_angular_momentum is None: return None spin = [] @@ -248,131 +267,194 @@ def spin(self) -> Optional[List[float]]: @property def num_particles(self) -> Optional[List[float]]: - """ Returns measured number of particles """ + """Returns measured number of particles""" return self._num_particles @num_particles.setter def num_particles(self, value: List[float]) -> None: - """ Sets measured number of particles """ + """Sets measured number of particles""" self._num_particles = value @property def magnetization(self) -> Optional[List[float]]: - """ Returns measured magnetization """ + """Returns measured magnetization""" return self._magnetization @magnetization.setter def magnetization(self, value: List[float]) -> None: - """ Sets measured magnetization """ + """Sets measured magnetization""" self._magnetization = value def __str__(self) -> str: - """ Printable formatted result """ - return '\n'.join(self.formatted()) + """Printable formatted result""" + return "\n".join(self.formatted()) def formatted(self) -> List[str]: - """ Formatted result as a list of strings """ + """Formatted result as a list of strings""" lines = [] - lines.append('=== GROUND STATE ENERGY ===') - lines.append(' ') - lines.append('* Electronic ground state energy (Hartree): {}'. - format(round(self.electronic_energies[0], 12))) - lines.append(' - computed part: {}'. - format(round(self.computed_energies[0], 12))) + lines.append("=== GROUND STATE ENERGY ===") + lines.append(" ") + lines.append( + "* Electronic ground state energy (Hartree): {}".format( + round(self.electronic_energies[0], 12) + ) + ) + lines.append( + " - computed part: {}".format(round(self.computed_energies[0], 12)) + ) for name, value in self.extracted_transformer_energies.items(): - lines.append(' - {} extracted energy part: {}'.format(name, round(value, 12))) + lines.append( + " - {} extracted energy part: {}".format(name, round(value, 12)) + ) if self.nuclear_repulsion_energy is not None: - lines.append('~ Nuclear repulsion energy (Hartree): {}'. - format(round(self.nuclear_repulsion_energy, 12))) - lines.append('> Total ground state energy (Hartree): {}'. - format(round(self.total_energies[0], 12))) + lines.append( + "~ Nuclear repulsion energy (Hartree): {}".format( + round(self.nuclear_repulsion_energy, 12) + ) + ) + lines.append( + "> Total ground state energy (Hartree): {}".format( + round(self.total_energies[0], 12) + ) + ) if len(self.computed_energies) > 1: - lines.append(' ') - lines.append('=== EXCITED STATE ENERGIES ===') - lines.append(' ') - for idx, (elec_energy, total_energy) in enumerate(zip(self.electronic_energies[1:], - self.total_energies[1:])): - lines.append('{: 3d}: '.format(idx+1)) - lines.append('* Electronic excited state energy (Hartree): {}'. - format(round(elec_energy, 12))) - lines.append('> Total excited state energy (Hartree): {}'. - format(round(total_energy, 12))) + lines.append(" ") + lines.append("=== EXCITED STATE ENERGIES ===") + lines.append(" ") + for idx, (elec_energy, total_energy) in enumerate( + zip(self.electronic_energies[1:], self.total_energies[1:]) + ): + lines.append("{: 3d}: ".format(idx + 1)) + lines.append( + "* Electronic excited state energy (Hartree): {}".format( + round(elec_energy, 12) + ) + ) + lines.append( + "> Total excited state energy (Hartree): {}".format( + round(total_energy, 12) + ) + ) if self.has_observables(): - lines.append(' ') - lines.append('=== MEASURED OBSERVABLES ===') - lines.append(' ') - for idx, (num_particles, spin, total_angular_momentum, magnetization) in enumerate(zip( - self.num_particles, self.spin, self.total_angular_momentum, - self.magnetization)): - line = '{: 3d}: '.format(idx) + lines.append(" ") + lines.append("=== MEASURED OBSERVABLES ===") + lines.append(" ") + for idx, ( + num_particles, + spin, + total_angular_momentum, + magnetization, + ) in enumerate( + zip( + self.num_particles, + self.spin, + self.total_angular_momentum, + self.magnetization, + ) + ): + line = "{: 3d}: ".format(idx) if num_particles is not None: - line += ' # Particles: {:.3f}'.format(num_particles) + line += " # Particles: {:.3f}".format(num_particles) if spin is not None: - line += ' S: {:.3f}'.format(spin) + line += " S: {:.3f}".format(spin) if total_angular_momentum is not None: - line += ' S^2: {:.3f}'.format(total_angular_momentum) + line += " S^2: {:.3f}".format(total_angular_momentum) if magnetization is not None: - line += ' M: {:.3f}'.format(magnetization) + line += " M: {:.3f}".format(magnetization) lines.append(line) if self.has_dipole(): - lines.append(' ') - lines.append('=== DIPOLE MOMENTS ===') - lines.append(' ') + lines.append(" ") + lines.append("=== DIPOLE MOMENTS ===") + lines.append(" ") if self.nuclear_dipole_moment is not None: - lines.append('~ Nuclear dipole moment (a.u.): {}' - .format(_dipole_to_string(self.nuclear_dipole_moment))) - lines.append(' ') - for idx, (elec_dip, comp_dip, extr_dip, dip, tot_dip, dip_db, tot_dip_db) in \ - enumerate(zip( - self.electronic_dipole_moment, self.computed_dipole_moment, - self.extracted_transformer_dipoles, - self.dipole_moment, self.total_dipole_moment, - self.dipole_moment_in_debye, self.total_dipole_moment_in_debye)): - lines.append('{: 3d}: '.format(idx)) - lines.append(' * Electronic dipole moment (a.u.): {}' - .format(_dipole_to_string(elec_dip))) - lines.append(' - computed part: {}' - .format(_dipole_to_string(comp_dip))) + lines.append( + "~ Nuclear dipole moment (a.u.): {}".format( + _dipole_to_string(self.nuclear_dipole_moment) + ) + ) + lines.append(" ") + for idx, ( + elec_dip, + comp_dip, + extr_dip, + dip, + tot_dip, + dip_db, + tot_dip_db, + ) in enumerate( + zip( + self.electronic_dipole_moment, + self.computed_dipole_moment, + self.extracted_transformer_dipoles, + self.dipole_moment, + self.total_dipole_moment, + self.dipole_moment_in_debye, + self.total_dipole_moment_in_debye, + ) + ): + lines.append("{: 3d}: ".format(idx)) + lines.append( + " * Electronic dipole moment (a.u.): {}".format( + _dipole_to_string(elec_dip) + ) + ) + lines.append( + " - computed part: {}".format(_dipole_to_string(comp_dip)) + ) for name, ex_dip in extr_dip.items(): - lines.append(' - {} extracted energy part: {}' - .format(name, _dipole_to_string(ex_dip))) + lines.append( + " - {} extracted energy part: {}".format( + name, _dipole_to_string(ex_dip) + ) + ) if self.nuclear_dipole_moment is not None: - lines.append(' > Dipole moment (a.u.): {} Total: {}' - .format(_dipole_to_string(dip), _float_to_string(tot_dip))) - lines.append(' (debye): {} Total: {}' - .format(_dipole_to_string(dip_db), _float_to_string(tot_dip_db))) - lines.append(' ') + lines.append( + " > Dipole moment (a.u.): {} Total: {}".format( + _dipole_to_string(dip), _float_to_string(tot_dip) + ) + ) + lines.append( + " (debye): {} Total: {}".format( + _dipole_to_string(dip_db), _float_to_string(tot_dip_db) + ) + ) + lines.append(" ") return lines -def _dipole_tuple_add(x: Optional[DipoleTuple], - y: Optional[DipoleTuple]) -> Optional[DipoleTuple]: - """ Utility to add two dipole tuples element-wise for dipole additions """ +def _dipole_tuple_add( + x: Optional[DipoleTuple], y: Optional[DipoleTuple] +) -> Optional[DipoleTuple]: + """Utility to add two dipole tuples element-wise for dipole additions""" if x is None or y is None: return None return _element_add(x[0], y[0]), _element_add(x[1], y[1]), _element_add(x[2], y[2]) def _element_add(x: Optional[float], y: Optional[float]): - """ Add dipole elements where a value may be None then None is returned """ + """Add dipole elements where a value may be None then None is returned""" return x + y if x is not None and y is not None else None def _dipole_to_string(dipole: DipoleTuple): dips = [round(x, 8) if x is not None else x for x in dipole] - value = '[' + value = "[" for i, _ in enumerate(dips): - value += _float_to_string(dips[i]) if dips[i] is not None else 'None' - value += ' ' if i < len(dips)-1 else ']' + value += _float_to_string(dips[i]) if dips[i] is not None else "None" + value += " " if i < len(dips) - 1 else "]" return value def _float_to_string(value: Optional[float], precision: int = 8) -> str: if value is None: - return 'None' + return "None" else: - return '0.0' if value == 0 else ('{:.' + str(precision) + 'f}').format(value).rstrip('0') + return ( + "0.0" + if value == 0 + else ("{:." + str(precision) + "f}").format(value).rstrip("0") + ) diff --git a/qiskit_nature/results/vibrational_structure_result.py b/qiskit_nature/results/vibrational_structure_result.py index 0feb7fdced..15f1537346 100644 --- a/qiskit_nature/results/vibrational_structure_result.py +++ b/qiskit_nature/results/vibrational_structure_result.py @@ -34,12 +34,12 @@ def __init__(self) -> None: @property def algorithm_result(self) -> Optional[AlgorithmResult]: - """ Returns raw algorithm result """ + """Returns raw algorithm result""" return self._algorithm_result @algorithm_result.setter def algorithm_result(self, value: AlgorithmResult) -> None: - """ Sets raw algorithm result """ + """Sets raw algorithm result""" self._algorithm_result = value # TODO we need to be able to extract the statevector or the optimal parameters that can @@ -47,38 +47,43 @@ def algorithm_result(self, value: AlgorithmResult) -> None: @property def computed_vibrational_energies(self) -> Optional[np.ndarray]: - """ Returns computed electronic part of ground state energy """ + """Returns computed electronic part of ground state energy""" return self._computed_vibrational_energies @computed_vibrational_energies.setter def computed_vibrational_energies(self, value: np.ndarray) -> None: - """ Sets computed electronic part of ground state energy """ + """Sets computed electronic part of ground state energy""" self._computed_vibrational_energies = value @property def num_occupied_modals_per_mode(self) -> Optional[List[float]]: - """ Returns the number of occupied modal per mode """ + """Returns the number of occupied modal per mode""" return self._num_occupied_modals_per_mode @num_occupied_modals_per_mode.setter def num_occupied_modals_per_mode(self, value: List[float]) -> None: - """ Sets measured number of modes """ + """Sets measured number of modes""" self._num_occupied_modals_per_mode = value def __str__(self) -> str: - """ Printable formatted result """ - return '\n'.join(self.formatted()) + """Printable formatted result""" + return "\n".join(self.formatted()) def formatted(self) -> List[str]: - """ Formatted result as a list of strings """ + """Formatted result as a list of strings""" lines = [] - lines.append('=== GROUND STATE ENERGY ===') - lines.append(' ') - lines.append('* Vibrational ground state energy (cm^-1): {}'. - format(np.round(self.computed_vibrational_energies[0], 12))) + lines.append("=== GROUND STATE ENERGY ===") + lines.append(" ") + lines.append( + "* Vibrational ground state energy (cm^-1): {}".format( + np.round(self.computed_vibrational_energies[0], 12) + ) + ) if len(self.num_occupied_modals_per_mode) > 0: - lines.append('The number of occupied modals is') + lines.append("The number of occupied modals is") for i in range(len(self.num_occupied_modals_per_mode)): - lines.append('- Mode {}: {}'.format(i, self.num_occupied_modals_per_mode[i])) + lines.append( + "- Mode {}: {}".format(i, self.num_occupied_modals_per_mode[i]) + ) return lines diff --git a/qiskit_nature/transformers/__init__.py b/qiskit_nature/transformers/__init__.py index 2e2b1e9617..4c8cd4c340 100644 --- a/qiskit_nature/transformers/__init__.py +++ b/qiskit_nature/transformers/__init__.py @@ -36,7 +36,7 @@ from .freeze_core_transformer import FreezeCoreTransformer __all__ = [ - 'ActiveSpaceTransformer', - 'BaseTransformer', - 'FreezeCoreTransformer', + "ActiveSpaceTransformer", + "BaseTransformer", + "FreezeCoreTransformer", ] diff --git a/qiskit_nature/transformers/active_space_transformer.py b/qiskit_nature/transformers/active_space_transformer.py index 7994b7bd35..54be58662f 100644 --- a/qiskit_nature/transformers/active_space_transformer.py +++ b/qiskit_nature/transformers/active_space_transformer.py @@ -22,9 +22,9 @@ from .base_transformer import BaseTransformer -ACTIVE_INTS_SUBSCRIPT = 'pqrs,pi,qj,rk,sl->ijkl' +ACTIVE_INTS_SUBSCRIPT = "pqrs,pi,qj,rk,sl->ijkl" -INACTIVE_ENERGY_SUBSCRIPT = 'ij,ji' +INACTIVE_ENERGY_SUBSCRIPT = "ij,ji" logger = logging.getLogger(__name__) @@ -74,11 +74,12 @@ class ActiveSpaceTransformer(BaseTransformer): (2020).* """ - def __init__(self, - num_electrons: Optional[Union[int, Tuple[int, int]]] = None, - num_molecular_orbitals: Optional[int] = None, - active_orbitals: Optional[List[int]] = None, - ): + def __init__( + self, + num_electrons: Optional[Union[int, Tuple[int, int]]] = None, + num_molecular_orbitals: Optional[int] = None, + active_orbitals: Optional[List[int]] = None, + ): """Initializes a transformer which can reduce a `QMolecule` to a configured active space. This transformer requires the AO-basis matrices `hcore` and `eri` to be available, as well @@ -138,17 +139,27 @@ def transform(self, molecule_data: QMolecule) -> QMolecule: self._beta = mo_coeff_full[1] is not None # get molecular orbital occupation numbers mo_occ_full = self._extract_mo_occupation_vector(molecule_data) - self._mo_occ_total = mo_occ_full[0] + mo_occ_full[1] if self._beta else mo_occ_full[0] + self._mo_occ_total = ( + mo_occ_full[0] + mo_occ_full[1] if self._beta else mo_occ_full[0] + ) - active_orbs_idxs, inactive_orbs_idxs = self._determine_active_space(molecule_data) + active_orbs_idxs, inactive_orbs_idxs = self._determine_active_space( + molecule_data + ) # split molecular orbitals coefficients into active and inactive parts - self._mo_coeff_inactive = (mo_coeff_full[0][:, inactive_orbs_idxs], - mo_coeff_full[1][:, inactive_orbs_idxs] if self._beta else None) - self._mo_coeff_active = (mo_coeff_full[0][:, active_orbs_idxs], - mo_coeff_full[1][:, active_orbs_idxs] if self._beta else None) - self._mo_occ_inactive = (mo_occ_full[0][inactive_orbs_idxs], - mo_occ_full[1][inactive_orbs_idxs] if self._beta else None) + self._mo_coeff_inactive = ( + mo_coeff_full[0][:, inactive_orbs_idxs], + mo_coeff_full[1][:, inactive_orbs_idxs] if self._beta else None, + ) + self._mo_coeff_active = ( + mo_coeff_full[0][:, active_orbs_idxs], + mo_coeff_full[1][:, active_orbs_idxs] if self._beta else None, + ) + self._mo_occ_inactive = ( + mo_occ_full[0][inactive_orbs_idxs], + mo_occ_full[1][inactive_orbs_idxs] if self._beta else None, + ) self._compute_inactive_density_matrix() @@ -160,39 +171,50 @@ def transform(self, molecule_data: QMolecule) -> QMolecule: molecule_data_reduced.num_beta = self._num_particles[1] molecule_data_reduced.mo_coeff = self._mo_coeff_active[0] molecule_data_reduced.mo_coeff_b = self._mo_coeff_active[1] - molecule_data_reduced.orbital_energies = molecule_data.orbital_energies[active_orbs_idxs] + molecule_data_reduced.orbital_energies = molecule_data.orbital_energies[ + active_orbs_idxs + ] if self._beta: - molecule_data_reduced.orbital_energies_b = \ - molecule_data.orbital_energies_b[active_orbs_idxs] + molecule_data_reduced.orbital_energies_b = molecule_data.orbital_energies_b[ + active_orbs_idxs + ] molecule_data_reduced.kinetic = None molecule_data_reduced.overlap = None # reduce electronic energy integrals - self._reduce_to_active_space(molecule_data, molecule_data_reduced, - 'energy_shift', - ('hcore', 'hcore_b'), - ('mo_onee_ints', 'mo_onee_ints_b'), - 'eri', - ('mo_eri_ints', 'mo_eri_ints_ba', 'mo_eri_ints_bb') - ) + self._reduce_to_active_space( + molecule_data, + molecule_data_reduced, + "energy_shift", + ("hcore", "hcore_b"), + ("mo_onee_ints", "mo_onee_ints_b"), + "eri", + ("mo_eri_ints", "mo_eri_ints_ba", "mo_eri_ints_bb"), + ) # reduce dipole moment integrals if molecule_data.has_dipole_integrals(): - self._reduce_to_active_space(molecule_data, molecule_data_reduced, - 'x_dip_energy_shift', - ('x_dip_ints', None), - ('x_dip_mo_ints', 'x_dip_mo_ints_b') - ) - self._reduce_to_active_space(molecule_data, molecule_data_reduced, - 'y_dip_energy_shift', - ('y_dip_ints', None), - ('y_dip_mo_ints', 'y_dip_mo_ints_b') - ) - self._reduce_to_active_space(molecule_data, molecule_data_reduced, - 'z_dip_energy_shift', - ('z_dip_ints', None), - ('z_dip_mo_ints', 'z_dip_mo_ints_b') - ) + self._reduce_to_active_space( + molecule_data, + molecule_data_reduced, + "x_dip_energy_shift", + ("x_dip_ints", None), + ("x_dip_mo_ints", "x_dip_mo_ints_b"), + ) + self._reduce_to_active_space( + molecule_data, + molecule_data_reduced, + "y_dip_energy_shift", + ("y_dip_ints", None), + ("y_dip_mo_ints", "y_dip_mo_ints_b"), + ) + self._reduce_to_active_space( + molecule_data, + molecule_data_reduced, + "z_dip_energy_shift", + ("z_dip_ints", None), + ("z_dip_mo_ints", "z_dip_mo_ints_b"), + ) return molecule_data_reduced @@ -201,34 +223,40 @@ def _check_configuration(self): if self._num_electrons % 2 != 0: raise QiskitNatureError( "The number of active electrons must be even! Otherwise you must specify them " - "as a tuple, not as:", self._num_electrons + "as a tuple, not as:", + self._num_electrons, ) if self._num_electrons < 0: raise QiskitNatureError( - "The number of active electrons cannot be negative:", self._num_electrons + "The number of active electrons cannot be negative:", + self._num_electrons, ) elif isinstance(self._num_electrons, tuple): - if not all(isinstance(n_elec, int) and n_elec >= 0 for n_elec in self._num_electrons): + if not all( + isinstance(n_elec, int) and n_elec >= 0 + for n_elec in self._num_electrons + ): raise QiskitNatureError( "Neither the number of alpha, nor the number of beta electrons can be " - "negative:", self._num_electrons + "negative:", + self._num_electrons, ) else: raise QiskitNatureError( "The number of active electrons must be an int, or a tuple thereof, not:", - self._num_electrons + self._num_electrons, ) if isinstance(self._num_molecular_orbitals, int): if self._num_molecular_orbitals < 0: raise QiskitNatureError( "The number of active orbitals cannot be negative:", - self._num_molecular_orbitals + self._num_molecular_orbitals, ) else: raise QiskitNatureError( "The number of active orbitals must be an int, not:", - self._num_electrons + self._num_electrons, ) def _extract_mo_occupation_vector(self, molecule_data: QMolecule): @@ -236,14 +264,17 @@ def _extract_mo_occupation_vector(self, molecule_data: QMolecule): if mo_occ_full[0] is None: # QMolecule provided by driver without `mo_occ` information available. Constructing # occupation numbers based on ground state HF case. - occ_alpha = [1.] * molecule_data.num_alpha \ - + [0.] * (molecule_data.num_molecular_orbitals - molecule_data.num_alpha) + occ_alpha = [1.0] * molecule_data.num_alpha + [0.0] * ( + molecule_data.num_molecular_orbitals - molecule_data.num_alpha + ) if self._beta: - occ_beta = [1.] * molecule_data.num_beta \ - + [0.] * (molecule_data.num_molecular_orbitals - molecule_data.num_beta) + occ_beta = [1.0] * molecule_data.num_beta + [0.0] * ( + molecule_data.num_molecular_orbitals - molecule_data.num_beta + ) else: - occ_alpha[:molecule_data.num_beta] = [o + 1 for o in - occ_alpha[:molecule_data.num_beta]] + occ_alpha[: molecule_data.num_beta] = [ + o + 1 for o in occ_alpha[: molecule_data.num_beta] + ] occ_beta = None mo_occ_full = (np.asarray(occ_alpha), np.asarray(occ_beta)) return mo_occ_full @@ -267,12 +298,16 @@ def _determine_active_space(self, molecule_data: QMolecule): if self._active_orbitals is None: norbs_inactive = nelec_inactive // 2 inactive_orbs_idxs = list(range(norbs_inactive)) - active_orbs_idxs = list(range(norbs_inactive, - norbs_inactive+self._num_molecular_orbitals)) + active_orbs_idxs = list( + range(norbs_inactive, norbs_inactive + self._num_molecular_orbitals) + ) else: active_orbs_idxs = self._active_orbitals - inactive_orbs_idxs = [o for o in range(nelec_total // 2) if o not in - self._active_orbitals and self._mo_occ_total[o] > 0] + inactive_orbs_idxs = [ + o + for o in range(nelec_total // 2) + if o not in self._active_orbitals and self._mo_occ_total[o] > 0 + ] return (active_orbs_idxs, inactive_orbs_idxs) @@ -290,9 +325,7 @@ def _validate_num_electrons(self, nelec_inactive: int): if nelec_inactive % 2 != 0: raise QiskitNatureError("The number of inactive electrons must be even.") - def _validate_num_orbitals(self, - nelec_inactive: int, - molecule_data: QMolecule): + def _validate_num_orbitals(self, nelec_inactive: int, molecule_data: QMolecule): """Validates the number of orbitals. Args: @@ -306,37 +339,49 @@ def _validate_num_orbitals(self, """ if self._active_orbitals is None: norbs_inactive = nelec_inactive // 2 - if norbs_inactive + self._num_molecular_orbitals > molecule_data.num_molecular_orbitals: + if ( + norbs_inactive + self._num_molecular_orbitals + > molecule_data.num_molecular_orbitals + ): raise QiskitNatureError("More orbitals requested than available.") else: if self._num_molecular_orbitals != len(self._active_orbitals): - raise QiskitNatureError("The number of selected active orbital indices does not " - "match the specified number of active orbitals.") + raise QiskitNatureError( + "The number of selected active orbital indices does not " + "match the specified number of active orbitals." + ) if max(self._active_orbitals) >= molecule_data.num_molecular_orbitals: raise QiskitNatureError("More orbitals requested than available.") if sum(self._mo_occ_total[self._active_orbitals]) != self._num_electrons: - raise QiskitNatureError("The number of electrons in the selected active orbitals " - "does not match the specified number of active electrons.") + raise QiskitNatureError( + "The number of electrons in the selected active orbitals " + "does not match the specified number of active electrons." + ) def _compute_inactive_density_matrix(self): """Computes the inactive density matrix.""" - density_inactive_a = np.dot(self._mo_coeff_inactive[0]*self._mo_occ_inactive[0], - np.transpose(self._mo_coeff_inactive[0])) + density_inactive_a = np.dot( + self._mo_coeff_inactive[0] * self._mo_occ_inactive[0], + np.transpose(self._mo_coeff_inactive[0]), + ) density_inactive_b = None if self._beta: - density_inactive_b = np.dot(self._mo_coeff_inactive[1]*self._mo_occ_inactive[1], - np.transpose(self._mo_coeff_inactive[1])) + density_inactive_b = np.dot( + self._mo_coeff_inactive[1] * self._mo_occ_inactive[1], + np.transpose(self._mo_coeff_inactive[1]), + ) self._density_inactive = (density_inactive_a, density_inactive_b) - def _reduce_to_active_space(self, - molecule_data: QMolecule, - molecule_data_reduced: QMolecule, - energy_shift_attribute: str, - ao_1e_attribute: Tuple[str, Optional[str]], - mo_1e_attribute: Tuple[str, str], - ao_2e_attribute: Optional[str] = None, - mo_2e_attribute: Optional[Tuple[str, str, str]] = None, - ) -> None: + def _reduce_to_active_space( + self, + molecule_data: QMolecule, + molecule_data_reduced: QMolecule, + energy_shift_attribute: str, + ao_1e_attribute: Tuple[str, Optional[str]], + mo_1e_attribute: Tuple[str, str], + ao_2e_attribute: Optional[str] = None, + mo_2e_attribute: Optional[Tuple[str, str, str]] = None, + ) -> None: """A utility method which performs the actual orbital reduction computation. Args: @@ -383,10 +428,13 @@ def _reduce_to_active_space(self, energy_shift = self._compute_inactive_energy(ao_1e_matrix, inactive_op) - mo_1e_matrix, mo_2e_matrix = self._compute_active_integrals(inactive_op, ao_2e_matrix) + mo_1e_matrix, mo_2e_matrix = self._compute_active_integrals( + inactive_op, ao_2e_matrix + ) - getattr(molecule_data_reduced, energy_shift_attribute)['ActiveSpaceTransformer'] = \ - energy_shift + getattr(molecule_data_reduced, energy_shift_attribute)[ + "ActiveSpaceTransformer" + ] = energy_shift setattr(molecule_data_reduced, ao_1e_attribute[0], inactive_op[0]) setattr(molecule_data_reduced, mo_1e_attribute[0], mo_1e_matrix[0]) if self._beta: @@ -399,10 +447,11 @@ def _reduce_to_active_space(self, setattr(molecule_data_reduced, mo_2e_attribute[1], mo_2e_matrix[1]) setattr(molecule_data_reduced, mo_2e_attribute[2], mo_2e_matrix[2]) - def _compute_inactive_fock_op(self, - hcore: Tuple[np.ndarray, Optional[np.ndarray]], - eri: np.ndarray, - ) -> Tuple[np.ndarray, Optional[np.ndarray]]: + def _compute_inactive_fock_op( + self, + hcore: Tuple[np.ndarray, Optional[np.ndarray]], + eri: np.ndarray, + ) -> Tuple[np.ndarray, Optional[np.ndarray]]: """Computes the inactive Fock operator. Args: @@ -413,23 +462,32 @@ def _compute_inactive_fock_op(self, The pair of alpha- and beta-spin inactive Fock operators. """ # compute inactive Fock matrix - coulomb_inactive = np.einsum('ijkl,ji->kl', eri, self._density_inactive[0]) - exchange_inactive = np.einsum('ijkl,jk->il', eri, self._density_inactive[0]) + coulomb_inactive = np.einsum("ijkl,ji->kl", eri, self._density_inactive[0]) + exchange_inactive = np.einsum("ijkl,jk->il", eri, self._density_inactive[0]) fock_inactive = hcore[0] + coulomb_inactive - 0.5 * exchange_inactive fock_inactive_b = coulomb_inactive_b = exchange_inactive_b = None if self._beta: - coulomb_inactive_b = np.einsum('ijkl,ji->kl', eri, self._density_inactive[1]) - exchange_inactive_b = np.einsum('ijkl,jk->il', eri, self._density_inactive[1]) - fock_inactive = hcore[0] + coulomb_inactive + coulomb_inactive_b - exchange_inactive - fock_inactive_b = hcore[1] + coulomb_inactive + coulomb_inactive_b - exchange_inactive_b + coulomb_inactive_b = np.einsum( + "ijkl,ji->kl", eri, self._density_inactive[1] + ) + exchange_inactive_b = np.einsum( + "ijkl,jk->il", eri, self._density_inactive[1] + ) + fock_inactive = ( + hcore[0] + coulomb_inactive + coulomb_inactive_b - exchange_inactive + ) + fock_inactive_b = ( + hcore[1] + coulomb_inactive + coulomb_inactive_b - exchange_inactive_b + ) return (fock_inactive, fock_inactive_b) - def _compute_inactive_energy(self, - hcore: Tuple[np.ndarray, Optional[np.ndarray]], - fock_inactive: Tuple[np.ndarray, Optional[np.ndarray]], - ) -> float: + def _compute_inactive_energy( + self, + hcore: Tuple[np.ndarray, Optional[np.ndarray]], + fock_inactive: Tuple[np.ndarray, Optional[np.ndarray]], + ) -> float: """Computes the inactive energy. Args: @@ -442,25 +500,33 @@ def _compute_inactive_energy(self, # compute inactive energy e_inactive = 0.0 if not self._beta and self._mo_coeff_inactive[0].size > 0: - e_inactive += 0.5 * np.einsum(INACTIVE_ENERGY_SUBSCRIPT, self._density_inactive[0], - hcore[0] + fock_inactive[0]) + e_inactive += 0.5 * np.einsum( + INACTIVE_ENERGY_SUBSCRIPT, + self._density_inactive[0], + hcore[0] + fock_inactive[0], + ) elif self._beta and self._mo_coeff_inactive[1].size > 0: - e_inactive += 0.5 * np.einsum(INACTIVE_ENERGY_SUBSCRIPT, self._density_inactive[0], - hcore[0] + fock_inactive[0]) - e_inactive += 0.5 * np.einsum(INACTIVE_ENERGY_SUBSCRIPT, self._density_inactive[1], - hcore[1] + fock_inactive[1]) + e_inactive += 0.5 * np.einsum( + INACTIVE_ENERGY_SUBSCRIPT, + self._density_inactive[0], + hcore[0] + fock_inactive[0], + ) + e_inactive += 0.5 * np.einsum( + INACTIVE_ENERGY_SUBSCRIPT, + self._density_inactive[1], + hcore[1] + fock_inactive[1], + ) return e_inactive - def _compute_active_integrals(self, - fock_inactive: Tuple[np.ndarray, Optional[np.ndarray]], - eri: Optional[np.ndarray] = None, - ) -> Tuple[ - Tuple[np.ndarray, Optional[np.ndarray]], - Optional[Tuple[np.ndarray, - Optional[np.ndarray], - Optional[np.ndarray]]] - ]: + def _compute_active_integrals( + self, + fock_inactive: Tuple[np.ndarray, Optional[np.ndarray]], + eri: Optional[np.ndarray] = None, + ) -> Tuple[ + Tuple[np.ndarray, Optional[np.ndarray]], + Optional[Tuple[np.ndarray, Optional[np.ndarray], Optional[np.ndarray]]], + ]: """Computes the h1 and h2 integrals for the active space. Args: @@ -473,31 +539,50 @@ def _compute_active_integrals(self, (alpha-alpha-spin h2, beta-alpha-spin h2, beta-beta-spin h2)) """ # compute new 1- and 2-electron integrals - hij = np.dot(np.dot(np.transpose(self._mo_coeff_active[0]), fock_inactive[0]), - self._mo_coeff_active[0]) + hij = np.dot( + np.dot(np.transpose(self._mo_coeff_active[0]), fock_inactive[0]), + self._mo_coeff_active[0], + ) hij_b = None if self._beta: - hij_b = np.dot(np.dot(np.transpose(self._mo_coeff_active[1]), fock_inactive[1]), - self._mo_coeff_active[1]) + hij_b = np.dot( + np.dot(np.transpose(self._mo_coeff_active[1]), fock_inactive[1]), + self._mo_coeff_active[1], + ) if eri is None: return ((hij, hij_b), None) - hijkl = np.einsum(ACTIVE_INTS_SUBSCRIPT, eri, - self._mo_coeff_active[0], self._mo_coeff_active[0], - self._mo_coeff_active[0], self._mo_coeff_active[0], - optimize=True) + hijkl = np.einsum( + ACTIVE_INTS_SUBSCRIPT, + eri, + self._mo_coeff_active[0], + self._mo_coeff_active[0], + self._mo_coeff_active[0], + self._mo_coeff_active[0], + optimize=True, + ) hijkl_bb = hijkl_ba = None if self._beta: - hijkl_bb = np.einsum(ACTIVE_INTS_SUBSCRIPT, eri, - self._mo_coeff_active[1], self._mo_coeff_active[1], - self._mo_coeff_active[1], self._mo_coeff_active[1], - optimize=True) - hijkl_ba = np.einsum(ACTIVE_INTS_SUBSCRIPT, eri, - self._mo_coeff_active[1], self._mo_coeff_active[1], - self._mo_coeff_active[0], self._mo_coeff_active[0], - optimize=True) + hijkl_bb = np.einsum( + ACTIVE_INTS_SUBSCRIPT, + eri, + self._mo_coeff_active[1], + self._mo_coeff_active[1], + self._mo_coeff_active[1], + self._mo_coeff_active[1], + optimize=True, + ) + hijkl_ba = np.einsum( + ACTIVE_INTS_SUBSCRIPT, + eri, + self._mo_coeff_active[1], + self._mo_coeff_active[1], + self._mo_coeff_active[0], + self._mo_coeff_active[0], + optimize=True, + ) return (hij, hij_b), (hijkl, hijkl_ba, hijkl_bb) diff --git a/qiskit_nature/transformers/freeze_core_transformer.py b/qiskit_nature/transformers/freeze_core_transformer.py index 0c49d830f4..ab737b1230 100644 --- a/qiskit_nature/transformers/freeze_core_transformer.py +++ b/qiskit_nature/transformers/freeze_core_transformer.py @@ -25,9 +25,11 @@ class FreezeCoreTransformer(ActiveSpaceTransformer): """The Freeze-Core reduction.""" - def __init__(self, freeze_core: bool = True, - remove_orbitals: Optional[List[int]] = None, - ): + def __init__( + self, + freeze_core: bool = True, + remove_orbitals: Optional[List[int]] = None, + ): """Initializes a transformer which reduces a `QMolecule` by removing some molecular orbitals. @@ -75,8 +77,9 @@ def transform(self, molecule_data: QMolecule) -> QMolecule: def rename_dict_key(energy_shift_dict): try: - energy_shift_dict['FreezeCoreTransformer'] = \ - energy_shift_dict.pop('ActiveSpaceTransformer') + energy_shift_dict["FreezeCoreTransformer"] = energy_shift_dict.pop( + "ActiveSpaceTransformer" + ) except KeyError: pass @@ -96,8 +99,11 @@ def _determine_active_space(self, molecule_data: QMolecule): inactive_orbs_idxs = molecule_data.core_orbitals if self._remove_orbitals is not None: inactive_orbs_idxs.extend(self._remove_orbitals) - active_orbs_idxs = [o for o in range(molecule_data.num_molecular_orbitals) - if o not in inactive_orbs_idxs] + active_orbs_idxs = [ + o + for o in range(molecule_data.num_molecular_orbitals) + if o not in inactive_orbs_idxs + ] self._active_orbitals = active_orbs_idxs self._num_molecular_orbitals = len(active_orbs_idxs) diff --git a/qiskit_nature/version.py b/qiskit_nature/version.py index f998fe2d52..d0798f14fa 100644 --- a/qiskit_nature/version.py +++ b/qiskit_nature/version.py @@ -22,21 +22,28 @@ def _minimal_ext_cmd(cmd): # construct minimal environment env = {} - for k in ['SYSTEMROOT', 'PATH']: + for k in ["SYSTEMROOT", "PATH"]: v = os.environ.get(k) if v is not None: env[k] = v # LANGUAGE is used on win32 - env['LANGUAGE'] = 'C' - env['LANG'] = 'C' - env['LC_ALL'] = 'C' - with subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, env=env, - cwd=os.path.join(os.path.dirname(QISKIT_DIR))) as proc: + env["LANGUAGE"] = "C" + env["LANG"] = "C" + env["LC_ALL"] = "C" + with subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, + cwd=os.path.join(os.path.dirname(QISKIT_DIR)), + ) as proc: stdout, stderr = proc.communicate() if proc.returncode > 0: - raise OSError('Command {} exited with code {}: {}'.format( - cmd, proc.returncode, stderr.strip().decode('ascii'))) + raise OSError( + "Command {} exited with code {}: {}".format( + cmd, proc.returncode, stderr.strip().decode("ascii") + ) + ) return stdout @@ -44,8 +51,8 @@ def git_version(): """Get the current git head sha1.""" # Determine if we're at main try: - out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD']) - git_revision = out.strip().decode('ascii') + out = _minimal_ext_cmd(["git", "rev-parse", "HEAD"]) + git_revision = out.strip().decode("ascii") except OSError: git_revision = "Unknown" @@ -63,15 +70,15 @@ def get_version_info(): # up the build under Python 3. full_version = VERSION - if not os.path.exists(os.path.join(os.path.dirname(QISKIT_DIR), '.git')): + if not os.path.exists(os.path.join(os.path.dirname(QISKIT_DIR), ".git")): return full_version try: - release = _minimal_ext_cmd(['git', 'tag', '-l', '--points-at', 'HEAD']) + release = _minimal_ext_cmd(["git", "tag", "-l", "--points-at", "HEAD"]) except Exception: # pylint: disable=broad-except return full_version git_revision = git_version() if not release: - full_version += '.dev0+' + git_revision[:7] + full_version += ".dev0+" + git_revision[:7] return full_version diff --git a/requirements-dev.txt b/requirements-dev.txt index 097dd5b6a6..1e1017601b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,6 @@ coverage>=4.4.0 matplotlib>=2.1 -pycodestyle +black==21.4b2 pylint>=2.7.1 pylintfileheader>=0.0.2 pylatexenc>=1.4 diff --git a/test/__init__.py b/test/__init__.py index 288a4bce7b..5ad2fe4b63 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -14,4 +14,4 @@ from .nature_test_case import QiskitNatureTestCase -__all__ = ['QiskitNatureTestCase'] +__all__ = ["QiskitNatureTestCase"] diff --git a/test/algorithms/excited_state_solvers/eigensolver_factories/test_numpy_eigensolver_factory.py b/test/algorithms/excited_state_solvers/eigensolver_factories/test_numpy_eigensolver_factory.py index 1dd10b8ec6..0d05dcb7be 100644 --- a/test/algorithms/excited_state_solvers/eigensolver_factories/test_numpy_eigensolver_factory.py +++ b/test/algorithms/excited_state_solvers/eigensolver_factories/test_numpy_eigensolver_factory.py @@ -22,7 +22,7 @@ class TestNumPyEigensolverFactory(QiskitNatureTestCase): - """ Test NumPyMinimumEigensovler Factory """ + """Test NumPyMinimumEigensovler Factory""" # NOTE: The actual usage of this class is mostly tested in combination with the ground-state # eigensolvers (one module above). @@ -31,36 +31,41 @@ def setUp(self): super().setUp() try: - self.driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.75', - unit=UnitsType.ANGSTROM, - charge=0, - spin=0, - basis='sto3g') + self.driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.75", + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto3g", + ) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") self.electronic_structure_problem = ElectronicStructureProblem(self.driver) # pylint: disable=unused-argument def filter_criterion(eigenstate, eigenvalue, aux_values): - return np.isclose(aux_values[0][0], 2.) + return np.isclose(aux_values[0][0], 2.0) self.k = 99 - self._numpy_eigensolver_factory = NumPyEigensolverFactory(filter_criterion=filter_criterion, - k=self.k) + self._numpy_eigensolver_factory = NumPyEigensolverFactory( + filter_criterion=filter_criterion, k=self.k + ) def test_setters_getters(self): - """ Test Getter/Setter """ + """Test Getter/Setter""" # filter_criterion self.assertIsNotNone(self._numpy_eigensolver_factory.filter_criterion) # pylint: disable=unused-argument def filter_criterion(eigenstate, eigenvalue, aux_values): - return np.isclose(aux_values[0][0], 3.) + return np.isclose(aux_values[0][0], 3.0) self._numpy_eigensolver_factory.filter_criterion = filter_criterion - self.assertEqual(self._numpy_eigensolver_factory.filter_criterion, filter_criterion) + self.assertEqual( + self._numpy_eigensolver_factory.filter_criterion, filter_criterion + ) # k self.assertEqual(self._numpy_eigensolver_factory.k, self.k) @@ -72,11 +77,13 @@ def filter_criterion(eigenstate, eigenvalue, aux_values): self._numpy_eigensolver_factory.use_default_filter_criterion = True self.assertTrue(self._numpy_eigensolver_factory.use_default_filter_criterion) # get_solver - solver = self._numpy_eigensolver_factory.get_solver(self.electronic_structure_problem) + solver = self._numpy_eigensolver_factory.get_solver( + self.electronic_structure_problem + ) self.assertIsInstance(solver, NumPyEigensolver) self.assertEqual(solver.k, 100) self.assertEqual(solver.filter_criterion, filter_criterion) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/excited_state_solvers/test_bosonic_esc_calculation.py b/test/algorithms/excited_state_solvers/test_bosonic_esc_calculation.py index a8b97b7608..743f690a97 100644 --- a/test/algorithms/excited_state_solvers/test_bosonic_esc_calculation.py +++ b/test/algorithms/excited_state_solvers/test_bosonic_esc_calculation.py @@ -23,36 +23,53 @@ from qiskit_nature.drivers import BosonicDriver, WatsonHamiltonian from qiskit_nature.mappers.second_quantization import DirectMapper from qiskit_nature.converters.second_quantization import QubitConverter -from qiskit_nature.problems.second_quantization.vibrational import VibrationalStructureProblem +from qiskit_nature.problems.second_quantization.vibrational import ( + VibrationalStructureProblem, +) from qiskit_nature.algorithms import ( - GroundStateEigensolver, NumPyMinimumEigensolverFactory, - VQEUVCCFactory, QEOM, ExcitedStatesEigensolver, NumPyEigensolverFactory + GroundStateEigensolver, + NumPyMinimumEigensolverFactory, + VQEUVCCFactory, + QEOM, + ExcitedStatesEigensolver, + NumPyEigensolverFactory, ) class _DummyBosonicDriver(BosonicDriver): - def __init__(self): super().__init__() - modes = [[605.3643675, 1, 1], [-605.3643675, -1, -1], [340.5950575, 2, 2], - [-340.5950575, -2, -2], [-89.09086530649508, 2, 1, 1], - [-15.590557244410897, 2, 2, 2], [1.6512647916666667, 1, 1, 1, 1], - [5.03965375, 2, 2, 1, 1], [0.43840625000000005, 2, 2, 2, 2]] + modes = [ + [605.3643675, 1, 1], + [-605.3643675, -1, -1], + [340.5950575, 2, 2], + [-340.5950575, -2, -2], + [-89.09086530649508, 2, 1, 1], + [-15.590557244410897, 2, 2, 2], + [1.6512647916666667, 1, 1, 1, 1], + [5.03965375, 2, 2, 1, 1], + [0.43840625000000005, 2, 2, 2, 2], + ] self._watson = WatsonHamiltonian(modes, 2) def run(self): - """ Run dummy driver to return test watson hamiltonian """ + """Run dummy driver to return test watson hamiltonian""" return self._watson class TestBosonicESCCalculation(QiskitNatureTestCase): - """ Test Numerical QEOM excited states calculation """ + """Test Numerical QEOM excited states calculation""" def setUp(self): super().setUp() algorithm_globals.random_seed = 8 - self.reference_energies = [1889.95738428, 3294.21806197, 4287.26821341, 5819.76975784] + self.reference_energies = [ + 1889.95738428, + 3294.21806197, + 4287.26821341, + 5819.76975784, + ] self.driver = _DummyBosonicDriver() self.qubit_converter = QubitConverter(DirectMapper()) @@ -64,41 +81,49 @@ def setUp(self): ) def test_numpy_mes(self): - """ Test with NumPyMinimumEigensolver """ + """Test with NumPyMinimumEigensolver""" solver = NumPyMinimumEigensolverFactory(use_default_filter_criterion=True) gsc = GroundStateEigensolver(self.qubit_converter, solver) - esc = QEOM(gsc, 'sd') + esc = QEOM(gsc, "sd") results = esc.solve(self.vibrational_problem) for idx in range(len(self.reference_energies)): - self.assertAlmostEqual(results.computed_vibrational_energies[idx], - self.reference_energies[idx], - places=4) + self.assertAlmostEqual( + results.computed_vibrational_energies[idx], + self.reference_energies[idx], + places=4, + ) def test_numpy_factory(self): - """ Test with NumPyEigensolver """ + """Test with NumPyEigensolver""" solver = NumPyEigensolverFactory(use_default_filter_criterion=True) esc = ExcitedStatesEigensolver(self.qubit_converter, solver) results = esc.solve(self.vibrational_problem) for idx in range(len(self.reference_energies)): - self.assertAlmostEqual(results.computed_vibrational_energies[idx], - self.reference_energies[idx], - places=4) + self.assertAlmostEqual( + results.computed_vibrational_energies[idx], + self.reference_energies[idx], + places=4, + ) def test_vqe_uvccsd_factory(self): - """ Test with VQE plus UVCCSD """ + """Test with VQE plus UVCCSD""" optimizer = COBYLA(maxiter=5000) - solver = VQEUVCCFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator')), - optimizer=optimizer) + solver = VQEUVCCFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")), + optimizer=optimizer, + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) - esc = QEOM(gsc, 'sd') + esc = QEOM(gsc, "sd") results = esc.solve(self.vibrational_problem) for idx in range(len(self.reference_energies)): - self.assertAlmostEqual(results.computed_vibrational_energies[idx], - self.reference_energies[idx], - places=1) + self.assertAlmostEqual( + results.computed_vibrational_energies[idx], + self.reference_energies[idx], + places=1, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/excited_state_solvers/test_excited_states_solvers.py b/test/algorithms/excited_state_solvers/test_excited_states_solvers.py index 6b7aab6117..51b8b50a6c 100644 --- a/test/algorithms/excited_state_solvers/test_excited_states_solvers.py +++ b/test/algorithms/excited_state_solvers/test_excited_states_solvers.py @@ -25,64 +25,78 @@ from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem from qiskit_nature.algorithms import ( - GroundStateEigensolver, VQEUCCFactory, - NumPyEigensolverFactory, ExcitedStatesEigensolver, QEOM + GroundStateEigensolver, + VQEUCCFactory, + NumPyEigensolverFactory, + ExcitedStatesEigensolver, + QEOM, ) class TestNumericalQEOMESCCalculation(QiskitNatureTestCase): - """ Test Numerical qEOM excited states calculation """ + """Test Numerical qEOM excited states calculation""" def setUp(self): super().setUp() algorithm_globals.random_seed = 8 try: - self.driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.75', - unit=UnitsType.ANGSTROM, - charge=0, - spin=0, - basis='sto3g') + self.driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.75", + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto3g", + ) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') - - self.reference_energies = [-1.8427016, -1.8427016 + 0.5943372, -1.8427016 + 0.95788352, - -1.8427016 + 1.5969296] + self.skipTest("PYSCF driver does not appear to be installed") + + self.reference_energies = [ + -1.8427016, + -1.8427016 + 0.5943372, + -1.8427016 + 0.95788352, + -1.8427016 + 1.5969296, + ] self.qubit_converter = QubitConverter(JordanWignerMapper()) self.electronic_structure_problem = ElectronicStructureProblem(self.driver) solver = NumPyEigensolver() self.ref = solver - self.quantum_instance = QuantumInstance(BasicAer.get_backend('statevector_simulator'), - seed_transpiler=90, seed_simulator=12) + self.quantum_instance = QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + seed_transpiler=90, + seed_simulator=12, + ) def test_numpy_mes(self): - """ Test NumPyMinimumEigenSolver with QEOM """ + """Test NumPyMinimumEigenSolver with QEOM""" solver = NumPyMinimumEigensolver() gsc = GroundStateEigensolver(self.qubit_converter, solver) - esc = QEOM(gsc, 'sd') + esc = QEOM(gsc, "sd") results = esc.solve(self.electronic_structure_problem) for idx in range(len(self.reference_energies)): - self.assertAlmostEqual(results.computed_energies[idx], self.reference_energies[idx], - places=4) + self.assertAlmostEqual( + results.computed_energies[idx], self.reference_energies[idx], places=4 + ) def test_vqe_mes(self): - """ Test VQEUCCSDFactory with QEOM """ + """Test VQEUCCSDFactory with QEOM""" solver = VQEUCCFactory(self.quantum_instance) gsc = GroundStateEigensolver(self.qubit_converter, solver) - esc = QEOM(gsc, 'sd') + esc = QEOM(gsc, "sd") results = esc.solve(self.electronic_structure_problem) for idx in range(len(self.reference_energies)): - self.assertAlmostEqual(results.computed_energies[idx], self.reference_energies[idx], - places=4) + self.assertAlmostEqual( + results.computed_energies[idx], self.reference_energies[idx], places=4 + ) def test_numpy_factory(self): - """ Test NumPyEigenSolverFactory with ExcitedStatesEigensolver """ + """Test NumPyEigenSolverFactory with ExcitedStatesEigensolver""" # pylint: disable=unused-argument def filter_criterion(eigenstate, eigenvalue, aux_values): - return np.isclose(aux_values[0][0], 2.) + return np.isclose(aux_values[0][0], 2.0) solver = NumPyEigensolverFactory(filter_criterion=filter_criterion) esc = ExcitedStatesEigensolver(self.qubit_converter, solver) @@ -95,9 +109,10 @@ def filter_criterion(eigenstate, eigenvalue, aux_values): computed_energies.append(comp_energy) for idx in range(len(self.reference_energies)): - self.assertAlmostEqual(computed_energies[idx], self.reference_energies[idx], - places=4) + self.assertAlmostEqual( + computed_energies[idx], self.reference_energies[idx], places=4 + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_ucc_factory.py b/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_ucc_factory.py index e8efca4b94..30941680be 100644 --- a/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_ucc_factory.py +++ b/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_ucc_factory.py @@ -27,7 +27,8 @@ class TestVQEUCCFactory(QiskitNatureTestCase): - """ Test VQE UCC MinimumEigensolver Factory """ + """Test VQE UCC MinimumEigensolver Factory""" + # NOTE: The actual usage of this class is mostly tested in combination with the ground-state # eigensolvers (one module above). @@ -37,18 +38,22 @@ def setUp(self): self.converter = QubitConverter(JordanWignerMapper()) self.seed = 50 - self.quantum_instance = QuantumInstance(BasicAer.get_backend('statevector_simulator'), - shots=1, - seed_simulator=self.seed, - seed_transpiler=self.seed) + self.quantum_instance = QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + shots=1, + seed_simulator=self.seed, + seed_transpiler=self.seed, + ) self._vqe_ucc_factory = VQEUCCFactory(self.quantum_instance) def test_setters_getters(self): - """ Test Getter/Setter """ + """Test Getter/Setter""" with self.subTest("Quantum Instance"): - self.assertEqual(self._vqe_ucc_factory.quantum_instance, self.quantum_instance) + self.assertEqual( + self._vqe_ucc_factory.quantum_instance, self.quantum_instance + ) self._vqe_ucc_factory.quantum_instance = None self.assertEqual(self._vqe_ucc_factory.quantum_instance, None) @@ -88,5 +93,5 @@ def test_setters_getters(self): self.assertEqual(self._vqe_ucc_factory.initial_state, initial_state) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_uvcc_factory.py b/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_uvcc_factory.py index 62dc477735..96bdff74e5 100644 --- a/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_uvcc_factory.py +++ b/test/algorithms/ground_state_solvers/minimum_eigensolver_factories/test_vqe_uvcc_factory.py @@ -25,7 +25,7 @@ class TestVQEUVCCFactory(QiskitNatureTestCase): - """ Test VQE UVCC MinimumEigensolver Factory """ + """Test VQE UVCC MinimumEigensolver Factory""" # NOTE: The actual usage of this class is mostly tested in combination with the ground-state # eigensolvers (one module above). @@ -36,18 +36,22 @@ def setUp(self): self.converter = QubitConverter(JordanWignerMapper()) self.seed = 50 - self.quantum_instance = QuantumInstance(BasicAer.get_backend('statevector_simulator'), - shots=1, - seed_simulator=self.seed, - seed_transpiler=self.seed) + self.quantum_instance = QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + shots=1, + seed_simulator=self.seed, + seed_transpiler=self.seed, + ) self._vqe_uvcc_factory = VQEUVCCFactory(self.quantum_instance) def test_setters_getters(self): - """ Test Getter/Setter """ + """Test Getter/Setter""" with self.subTest("Quantum Instance"): - self.assertEqual(self._vqe_uvcc_factory.quantum_instance, self.quantum_instance) + self.assertEqual( + self._vqe_uvcc_factory.quantum_instance, self.quantum_instance + ) self._vqe_uvcc_factory.quantum_instance = None self.assertEqual(self._vqe_uvcc_factory.quantum_instance, None) @@ -87,5 +91,5 @@ def test_setters_getters(self): self.assertEqual(self._vqe_uvcc_factory.initial_state, initial_state) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/ground_state_solvers/test_adapt_vqe.py b/test/algorithms/ground_state_solvers/test_adapt_vqe.py index 4da63256ec..9445220285 100644 --- a/test/algorithms/ground_state_solvers/test_adapt_vqe.py +++ b/test/algorithms/ground_state_solvers/test_adapt_vqe.py @@ -31,22 +31,23 @@ from qiskit_nature.mappers.second_quantization import ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem -from qiskit_nature.problems.second_quantization.electronic.builders.fermionic_op_builder import \ - build_ferm_op_from_ints +from qiskit_nature.problems.second_quantization.electronic.builders.fermionic_op_builder import ( + build_ferm_op_from_ints, +) class TestAdaptVQE(QiskitNatureTestCase): - """ Test Adaptive VQE Ground State Calculation """ + """Test Adaptive VQE Ground State Calculation""" def setUp(self): super().setUp() try: - self.driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', - unit=UnitsType.ANGSTROM, - basis='sto3g') + self.driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g" + ) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") return self.problem = ElectronicStructureProblem(self.driver) @@ -56,16 +57,20 @@ def setUp(self): self.qubit_converter = QubitConverter(ParityMapper()) def test_default(self): - """ Default execution """ - solver = VQEUCCFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator'))) + """Default execution""" + solver = VQEUCCFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")) + ) calc = AdaptVQE(self.qubit_converter, solver) res = calc.solve(self.problem) self.assertAlmostEqual(res.electronic_energies[0], self.expected, places=6) def test_aux_ops_reusability(self): - """ Test that the auxiliary operators can be reused """ + """Test that the auxiliary operators can be reused""" # Regression test against #1475 - solver = VQEUCCFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator'))) + solver = VQEUCCFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")) + ) calc = AdaptVQE(self.qubit_converter, solver) modes = 4 @@ -75,38 +80,55 @@ def test_aux_ops_reusability(self): aux_ops_copy = copy.deepcopy(aux_ops) _ = calc.solve(self.problem) - assert all(frozenset(a.to_list()) == frozenset(b.to_list()) - for a, b in zip(aux_ops, aux_ops_copy)) + assert all( + frozenset(a.to_list()) == frozenset(b.to_list()) + for a, b in zip(aux_ops, aux_ops_copy) + ) def test_custom_minimum_eigensolver(self): - """ Test custom MES """ + """Test custom MES""" + class CustomFactory(VQEUCCFactory): """A custom MESFactory""" def get_solver(self, problem, qubit_converter): - q_molecule_transformed = cast(QMolecule, problem.molecule_data_transformed) + q_molecule_transformed = cast( + QMolecule, problem.molecule_data_transformed + ) num_molecular_orbitals = q_molecule_transformed.num_molecular_orbitals - num_particles = (q_molecule_transformed.num_alpha, q_molecule_transformed.num_beta) + num_particles = ( + q_molecule_transformed.num_alpha, + q_molecule_transformed.num_beta, + ) num_spin_orbitals = 2 * num_molecular_orbitals - initial_state = HartreeFock(num_spin_orbitals, num_particles, qubit_converter) - ansatz = UCC(qubit_converter=qubit_converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - excitations='d', - initial_state=initial_state) - vqe = VQE(ansatz=ansatz, quantum_instance=self._quantum_instance, - optimizer=L_BFGS_B()) + initial_state = HartreeFock( + num_spin_orbitals, num_particles, qubit_converter + ) + ansatz = UCC( + qubit_converter=qubit_converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + excitations="d", + initial_state=initial_state, + ) + vqe = VQE( + ansatz=ansatz, + quantum_instance=self._quantum_instance, + optimizer=L_BFGS_B(), + ) return vqe - solver = CustomFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator'))) + solver = CustomFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")) + ) calc = AdaptVQE(self.qubit_converter, solver) res = calc.solve(self.problem) self.assertAlmostEqual(res.electronic_energies[0], self.expected, places=6) def test_custom_excitation_pool(self): - """ Test custom excitation pool """ + """Test custom excitation pool""" class CustomFactory(VQEUCCFactory): """A custom MES factory.""" @@ -121,13 +143,15 @@ def get_solver(self, problem, qubit_converter): solver.ansatz.operators = custom_excitation_pool return solver - solver = CustomFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator'))) + solver = CustomFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")) + ) calc = AdaptVQE(self.qubit_converter, solver) res = calc.solve(self.problem) self.assertAlmostEqual(res.electronic_energies[0], self.expected, places=6) def test_vqe_adapt_check_cyclicity(self): - """ AdaptVQE index cycle detection """ + """AdaptVQE index cycle detection""" param_list = [ ([1, 1], True), ([1, 11], False), @@ -160,5 +184,5 @@ def test_vqe_adapt_check_cyclicity(self): self.assertEqual(is_cycle, AdaptVQE._check_cyclicity(seq)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/ground_state_solvers/test_advanced_ucc_variants.py b/test/algorithms/ground_state_solvers/test_advanced_ucc_variants.py index 1260d0cef4..c7d8eb0039 100644 --- a/test/algorithms/ground_state_solvers/test_advanced_ucc_variants.py +++ b/test/algorithms/ground_state_solvers/test_advanced_ucc_variants.py @@ -39,20 +39,22 @@ class TestUCCSDHartreeFock(QiskitNatureTestCase): def setUp(self): super().setUp() - self.driver = PySCFDriver(atom='H 0 0 0.735; H 0 0 0', basis='631g') + self.driver = PySCFDriver(atom="H 0 0 0.735; H 0 0 0", basis="631g") self.qubit_converter = QubitConverter(ParityMapper(), two_qubit_reduction=True) - self.electronic_structure_problem = ElectronicStructureProblem(self.driver, - [FreezeCoreTransformer()]) + self.electronic_structure_problem = ElectronicStructureProblem( + self.driver, [FreezeCoreTransformer()] + ) self.num_spin_orbitals = 8 self.num_particles = (1, 1) # because we create the initial state and ansatzes early, we need to ensure the qubit # converter already ran such that convert_match works as expected - _ = self.qubit_converter.convert(self.electronic_structure_problem.second_q_ops()[0], - self.num_particles) + _ = self.qubit_converter.convert( + self.electronic_structure_problem.second_q_ops()[0], self.num_particles + ) self.reference_energy_pUCCD = -1.1434447924298028 self.reference_energy_UCCD0 = -1.1476045878481704 @@ -62,86 +64,123 @@ def setUp(self): # reference energy of UCCSD/VQE when no tapering on excitations is used self.reference_energy_UCCSD_no_tap_exc = -1.1516142309717594 # excitations for succ - self.reference_singlet_double_excitations = [[0, 1, 4, 5], [0, 1, 4, 6], [0, 1, 4, 7], - [0, 2, 4, 6], [0, 2, 4, 7], [0, 3, 4, 7]] + self.reference_singlet_double_excitations = [ + [0, 1, 4, 5], + [0, 1, 4, 6], + [0, 1, 4, 7], + [0, 2, 4, 6], + [0, 2, 4, 7], + [0, 3, 4, 7], + ] # groups for succ_full - self.reference_singlet_groups = [[[0, 1, 4, 5]], [[0, 1, 4, 6], [0, 2, 4, 5]], - [[0, 1, 4, 7], [0, 3, 4, 5]], [[0, 2, 4, 6]], - [[0, 2, 4, 7], [0, 3, 4, 6]], [[0, 3, 4, 7]]] + self.reference_singlet_groups = [ + [[0, 1, 4, 5]], + [[0, 1, 4, 6], [0, 2, 4, 5]], + [[0, 1, 4, 7], [0, 3, 4, 5]], + [[0, 2, 4, 6]], + [[0, 2, 4, 7], [0, 3, 4, 6]], + [[0, 3, 4, 7]], + ] @slow_test def test_uccsd_hf_qpUCCD(self): - """ paired uccd test """ + """paired uccd test""" optimizer = SLSQP(maxiter=100) - initial_state = HartreeFock(self.num_spin_orbitals, - self.num_particles, - self.qubit_converter) - - ansatz = PUCCD(self.qubit_converter, - self.num_particles, - self.num_spin_orbitals, - initial_state=initial_state) - - solver = VQE(ansatz=ansatz, optimizer=optimizer, - quantum_instance=QuantumInstance( - backend=BasicAer.get_backend('statevector_simulator'))) + initial_state = HartreeFock( + self.num_spin_orbitals, self.num_particles, self.qubit_converter + ) + + ansatz = PUCCD( + self.qubit_converter, + self.num_particles, + self.num_spin_orbitals, + initial_state=initial_state, + ) + + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + quantum_instance=QuantumInstance( + backend=BasicAer.get_backend("statevector_simulator") + ), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) result = gsc.solve(self.electronic_structure_problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy_pUCCD, places=6) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy_pUCCD, places=6 + ) @slow_test def test_uccsd_hf_qUCCD0(self): - """ singlet uccd test """ + """singlet uccd test""" optimizer = SLSQP(maxiter=100) - initial_state = HartreeFock(self.num_spin_orbitals, - self.num_particles, - self.qubit_converter) - - ansatz = SUCCD(self.qubit_converter, - self.num_particles, - self.num_spin_orbitals, - initial_state=initial_state) - - solver = VQE(ansatz=ansatz, optimizer=optimizer, - quantum_instance=QuantumInstance( - backend=BasicAer.get_backend('statevector_simulator'))) + initial_state = HartreeFock( + self.num_spin_orbitals, self.num_particles, self.qubit_converter + ) + + ansatz = SUCCD( + self.qubit_converter, + self.num_particles, + self.num_spin_orbitals, + initial_state=initial_state, + ) + + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + quantum_instance=QuantumInstance( + backend=BasicAer.get_backend("statevector_simulator") + ), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) result = gsc.solve(self.electronic_structure_problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy_UCCD0, places=6) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy_UCCD0, places=6 + ) - @unittest.skip("Skip until https://github.com/Qiskit/qiskit-nature/issues/91 is closed.") + @unittest.skip( + "Skip until https://github.com/Qiskit/qiskit-nature/issues/91 is closed." + ) def test_uccsd_hf_qUCCD0full(self): - """ singlet full uccd test """ + """singlet full uccd test""" optimizer = SLSQP(maxiter=100) - initial_state = HartreeFock(self.num_spin_orbitals, - self.num_particles, - self.qubit_converter) + initial_state = HartreeFock( + self.num_spin_orbitals, self.num_particles, self.qubit_converter + ) # TODO: add `full` option - ansatz = SUCCD(self.qubit_converter, - self.num_particles, - self.num_spin_orbitals, - initial_state=initial_state) - - solver = VQE(ansatz=ansatz, optimizer=optimizer, - quantum_instance=QuantumInstance( - backend=BasicAer.get_backend('statevector_simulator'))) + ansatz = SUCCD( + self.qubit_converter, + self.num_particles, + self.num_spin_orbitals, + initial_state=initial_state, + ) + + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + quantum_instance=QuantumInstance( + backend=BasicAer.get_backend("statevector_simulator") + ), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) result = gsc.solve(self.electronic_structure_problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy_UCCD0full, places=6) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy_UCCD0full, places=6 + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py b/test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py index a4e5895d34..fe2050e638 100644 --- a/test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py +++ b/test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py @@ -27,23 +27,28 @@ from qiskit.utils import QuantumInstance, algorithm_globals from qiskit_nature.algorithms import ( - GroundStateEigensolver, VQEUCCFactory, NumPyMinimumEigensolverFactory) + GroundStateEigensolver, + VQEUCCFactory, + NumPyMinimumEigensolverFactory, +) from qiskit_nature.circuit.library import HartreeFock, UCC, UCCSD from qiskit_nature.drivers import HDF5Driver from qiskit_nature.mappers.second_quantization import JordanWignerMapper, ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem -from qiskit_nature.problems.second_quantization.electronic.builders.fermionic_op_builder import \ - build_ferm_op_from_ints +from qiskit_nature.problems.second_quantization.electronic.builders.fermionic_op_builder import ( + build_ferm_op_from_ints, +) class TestGroundStateEigensolver(QiskitNatureTestCase): - """ Test GroundStateEigensolver """ + """Test GroundStateEigensolver""" def setUp(self): super().setUp() - self.driver = HDF5Driver(self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + self.driver = HDF5Driver( + self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) self.seed = 56 algorithm_globals.random_seed = self.seed @@ -56,38 +61,42 @@ def setUp(self): self.num_particles = (1, 1) def test_npme(self): - """ Test NumPyMinimumEigensolver """ + """Test NumPyMinimumEigensolver""" solver = NumPyMinimumEigensolverFactory() calc = GroundStateEigensolver(self.qubit_converter, solver) res = calc.solve(self.electronic_structure_problem) self.assertAlmostEqual(res.total_energies[0], self.reference_energy, places=6) def test_npme_with_default_filter(self): - """ Test NumPyMinimumEigensolver with default filter """ + """Test NumPyMinimumEigensolver with default filter""" solver = NumPyMinimumEigensolverFactory(use_default_filter_criterion=True) calc = GroundStateEigensolver(self.qubit_converter, solver) res = calc.solve(self.electronic_structure_problem) self.assertAlmostEqual(res.total_energies[0], self.reference_energy, places=6) def test_vqe_uccsd(self): - """ Test VQE UCCSD case """ + """Test VQE UCCSD case""" solver = VQEUCCFactory( - quantum_instance=QuantumInstance(BasicAer.get_backend('statevector_simulator')), - ansatz=UCC(excitations='d'), + quantum_instance=QuantumInstance( + BasicAer.get_backend("statevector_simulator") + ), + ansatz=UCC(excitations="d"), ) calc = GroundStateEigensolver(self.qubit_converter, solver) res = calc.solve(self.electronic_structure_problem) self.assertAlmostEqual(res.total_energies[0], self.reference_energy, places=6) def test_vqe_ucc_custom(self): - """ Test custom ansatz in Factory use case """ - solver = VQEUCCFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator'))) + """Test custom ansatz in Factory use case""" + solver = VQEUCCFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")) + ) calc = GroundStateEigensolver(self.qubit_converter, solver) res = calc.solve(self.electronic_structure_problem) self.assertAlmostEqual(res.total_energies[0], self.reference_energy, places=6) def test_aux_ops_reusability(self): - """ Test that the auxiliary operators can be reused """ + """Test that the auxiliary operators can be reused""" # Regression test against #1475 solver = NumPyMinimumEigensolverFactory() calc = GroundStateEigensolver(self.qubit_converter, solver) @@ -99,23 +108,28 @@ def test_aux_ops_reusability(self): aux_ops_copy = copy.deepcopy(aux_ops) _ = calc.solve(self.electronic_structure_problem) - assert all(frozenset(a.to_list()) == frozenset(b.to_list()) - for a, b in zip(aux_ops, aux_ops_copy)) + assert all( + frozenset(a.to_list()) == frozenset(b.to_list()) + for a, b in zip(aux_ops, aux_ops_copy) + ) def _setup_evaluation_operators(self): # first we run a ground state calculation - solver = VQEUCCFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator'))) + solver = VQEUCCFactory( + QuantumInstance(BasicAer.get_backend("statevector_simulator")) + ) calc = GroundStateEigensolver(self.qubit_converter, solver) res = calc.solve(self.electronic_structure_problem) # now we decide that we want to evaluate another operator # for testing simplicity, we just use some pre-constructed auxiliary operators _, *aux_ops = self.qubit_converter.convert_match( - self.electronic_structure_problem.second_q_ops()) + self.electronic_structure_problem.second_q_ops() + ) return calc, res, aux_ops def test_eval_op_single(self): - """ Test evaluating a single additional operator """ + """Test evaluating a single additional operator""" calc, res, aux_ops = self._setup_evaluation_operators() # we filter the list because in this test we test a single operator evaluation add_aux_op = aux_ops[0][0] @@ -126,7 +140,7 @@ def test_eval_op_single(self): self.assertAlmostEqual(add_aux_op_res[0].real, 2, places=6) def test_eval_op_single_none(self): - """ Test evaluating a single `None` operator """ + """Test evaluating a single `None` operator""" calc, res, _ = self._setup_evaluation_operators() # we filter the list because in this test we test a single operator evaluation add_aux_op = None @@ -136,12 +150,10 @@ def test_eval_op_single_none(self): self.assertIsNone(add_aux_op_res) def test_eval_op_list(self): - """ Test evaluating a list of additional operators """ + """Test evaluating a list of additional operators""" calc, res, aux_ops = self._setup_evaluation_operators() # we filter the list because of simplicity - expected_results = {'number of particles': 2, - 's^2': 0, - 'magnetization': 0} + expected_results = {"number of particles": 2, "s^2": 0, "magnetization": 0} add_aux_op = aux_ops[0:3] # now we have the ground state calculation evaluate them @@ -152,12 +164,10 @@ def test_eval_op_list(self): self.assertAlmostEqual(add_aux_op_res[idx][0].real, expected, places=6) def test_eval_op_list_none(self): - """ Test evaluating a list of additional operators incl. `None` """ + """Test evaluating a list of additional operators incl. `None`""" calc, res, aux_ops = self._setup_evaluation_operators() # we filter the list because of simplicity - expected_results = {'number of particles': 2, - 's^2': 0, - 'magnetization': 0} + expected_results = {"number of particles": 2, "s^2": 0, "magnetization": 0} add_aux_op = aux_ops[0:3] + [None] # now we have the ground state calculation evaluate them @@ -169,12 +179,10 @@ def test_eval_op_list_none(self): self.assertIsNone(add_aux_op_res[-1]) def test_eval_op_dict(self): - """ Test evaluating a dict of additional operators """ + """Test evaluating a dict of additional operators""" calc, res, aux_ops = self._setup_evaluation_operators() # we filter the list because of simplicity - expected_results = {'number of particles': 2, - 's^2': 0, - 'magnetization': 0} + expected_results = {"number of particles": 2, "s^2": 0, "magnetization": 0} add_aux_op = aux_ops[0:3] # now we convert it into a dictionary add_aux_op = dict(zip(expected_results.keys(), add_aux_op)) @@ -186,42 +194,43 @@ def test_eval_op_dict(self): self.assertAlmostEqual(add_aux_op_res[name][0].real, expected, places=6) def test_eval_op_dict_none(self): - """ Test evaluating a dict of additional operators incl. `None` """ + """Test evaluating a dict of additional operators incl. `None`""" calc, res, aux_ops = self._setup_evaluation_operators() # we filter the list because of simplicity - expected_results = {'number of particles': 2, - 's^2': 0, - 'magnetization': 0} + expected_results = {"number of particles": 2, "s^2": 0, "magnetization": 0} add_aux_op = aux_ops[0:3] # now we convert it into a dictionary add_aux_op = dict(zip(expected_results.keys(), add_aux_op)) - add_aux_op['None'] = None + add_aux_op["None"] = None # now we have the ground state calculation evaluate them add_aux_op_res = calc.evaluate_operators(res.raw_result.eigenstate, add_aux_op) self.assertIsInstance(add_aux_op_res, dict) for name, expected in expected_results.items(): self.assertAlmostEqual(add_aux_op_res[name][0].real, expected, places=6) - self.assertIsNone(add_aux_op_res['None']) + self.assertIsNone(add_aux_op_res["None"]) @slow_test def test_eval_op_qasm(self): """Regression tests against https://github.com/Qiskit/qiskit-nature/issues/53.""" - solver = VQEUCCFactory(optimizer=SLSQP(maxiter=100), - expectation=PauliExpectation(), - quantum_instance=QuantumInstance( - backend=BasicAer.get_backend('qasm_simulator'), - seed_simulator=algorithm_globals.random_seed, - seed_transpiler=algorithm_globals.random_seed) - ) + solver = VQEUCCFactory( + optimizer=SLSQP(maxiter=100), + expectation=PauliExpectation(), + quantum_instance=QuantumInstance( + backend=BasicAer.get_backend("qasm_simulator"), + seed_simulator=algorithm_globals.random_seed, + seed_transpiler=algorithm_globals.random_seed, + ), + ) calc = GroundStateEigensolver(self.qubit_converter, solver) res_qasm = calc.solve(self.electronic_structure_problem) hamiltonian = self.electronic_structure_problem.second_q_ops()[0] qubit_op = self.qubit_converter.map(hamiltonian) - ansatz = solver.get_solver(self.electronic_structure_problem, - self.qubit_converter).ansatz + ansatz = solver.get_solver( + self.electronic_structure_problem, self.qubit_converter + ).ansatz circuit = ansatz.assign_parameters(res_qasm.raw_result.optimal_point) mean = calc.evaluate_operators(circuit, qubit_op) @@ -233,73 +242,90 @@ def test_eval_op_qasm_aer(self): # pylint: disable=import-outside-toplevel # pylint: disable=unused-import from qiskit import Aer - backend = Aer.get_backend('qasm_simulator') + + backend = Aer.get_backend("qasm_simulator") except ImportError as ex: # pylint: disable=broad-except - self.skipTest("Aer doesn't appear to be installed. Error: '{}'".format(str(ex))) + self.skipTest( + "Aer doesn't appear to be installed. Error: '{}'".format(str(ex)) + ) return - solver = VQEUCCFactory(optimizer=SLSQP(maxiter=100), - expectation=AerPauliExpectation(), - include_custom=True, - quantum_instance=QuantumInstance( - backend=backend, - seed_simulator=algorithm_globals.random_seed, - seed_transpiler=algorithm_globals.random_seed) - ) + solver = VQEUCCFactory( + optimizer=SLSQP(maxiter=100), + expectation=AerPauliExpectation(), + include_custom=True, + quantum_instance=QuantumInstance( + backend=backend, + seed_simulator=algorithm_globals.random_seed, + seed_transpiler=algorithm_globals.random_seed, + ), + ) calc = GroundStateEigensolver(self.qubit_converter, solver) res_qasm = calc.solve(self.electronic_structure_problem) hamiltonian = self.electronic_structure_problem.second_q_ops()[0] qubit_op = self.qubit_converter.map(hamiltonian) - ansatz = solver.get_solver(self.electronic_structure_problem, - self.qubit_converter).ansatz + ansatz = solver.get_solver( + self.electronic_structure_problem, self.qubit_converter + ).ansatz circuit = ansatz.assign_parameters(res_qasm.raw_result.optimal_point) mean = calc.evaluate_operators(circuit, qubit_op) self.assertAlmostEqual(res_qasm.eigenenergies[0], mean[0].real) def _prepare_uccsd_hf(self, qubit_converter): - initial_state = HartreeFock(self.num_spin_orbitals, - self.num_particles, - qubit_converter) - ansatz = UCCSD(qubit_converter, - self.num_particles, - self.num_spin_orbitals, - initial_state=initial_state) + initial_state = HartreeFock( + self.num_spin_orbitals, self.num_particles, qubit_converter + ) + ansatz = UCCSD( + qubit_converter, + self.num_particles, + self.num_spin_orbitals, + initial_state=initial_state, + ) return ansatz def test_uccsd_hf(self): - """ uccsd hf test """ + """uccsd hf test""" ansatz = self._prepare_uccsd_hf(self.qubit_converter) optimizer = SLSQP(maxiter=100) - backend = BasicAer.get_backend('statevector_simulator') - solver = VQE(ansatz=ansatz, optimizer=optimizer, - quantum_instance=QuantumInstance(backend=backend)) + backend = BasicAer.get_backend("statevector_simulator") + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + quantum_instance=QuantumInstance(backend=backend), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) result = gsc.solve(self.electronic_structure_problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy, places=6) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy, places=6 + ) @slow_test def test_uccsd_hf_qasm(self): - """ uccsd hf test with qasm_simulator. """ + """uccsd hf test with qasm_simulator.""" qubit_converter = QubitConverter(ParityMapper()) ansatz = self._prepare_uccsd_hf(qubit_converter) - backend = BasicAer.get_backend('qasm_simulator') + backend = BasicAer.get_backend("qasm_simulator") optimizer = SPSA(maxiter=200, last_avg=5) - solver = VQE(ansatz=ansatz, optimizer=optimizer, - expectation=PauliExpectation(), - quantum_instance=QuantumInstance( - backend=backend, - seed_simulator=algorithm_globals.random_seed, - seed_transpiler=algorithm_globals.random_seed)) + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + expectation=PauliExpectation(), + quantum_instance=QuantumInstance( + backend=backend, + seed_simulator=algorithm_globals.random_seed, + seed_transpiler=algorithm_globals.random_seed, + ), + ) gsc = GroundStateEigensolver(qubit_converter, solver) @@ -307,46 +333,61 @@ def test_uccsd_hf_qasm(self): self.assertAlmostEqual(result.total_energies[0], -1.138, places=2) def test_uccsd_hf_aer_statevector(self): - """ uccsd hf test with Aer statevector """ + """uccsd hf test with Aer statevector""" try: # pylint: disable=import-outside-toplevel from qiskit import Aer - backend = Aer.get_backend('statevector_simulator') + + backend = Aer.get_backend("statevector_simulator") except ImportError as ex: # pylint: disable=broad-except - self.skipTest("Aer doesn't appear to be installed. Error: '{}'".format(str(ex))) + self.skipTest( + "Aer doesn't appear to be installed. Error: '{}'".format(str(ex)) + ) return ansatz = self._prepare_uccsd_hf(self.qubit_converter) optimizer = SLSQP(maxiter=100) - solver = VQE(ansatz=ansatz, optimizer=optimizer, - quantum_instance=QuantumInstance(backend=backend)) + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + quantum_instance=QuantumInstance(backend=backend), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) result = gsc.solve(self.electronic_structure_problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy, places=6) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy, places=6 + ) @slow_test def test_uccsd_hf_aer_qasm(self): - """ uccsd hf test with Aer qasm_simulator. """ + """uccsd hf test with Aer qasm_simulator.""" try: # pylint: disable=import-outside-toplevel from qiskit import Aer - backend = Aer.get_backend('qasm_simulator') + + backend = Aer.get_backend("qasm_simulator") except ImportError as ex: # pylint: disable=broad-except - self.skipTest("Aer doesn't appear to be installed. Error: '{}'".format(str(ex))) + self.skipTest( + "Aer doesn't appear to be installed. Error: '{}'".format(str(ex)) + ) return ansatz = self._prepare_uccsd_hf(self.qubit_converter) optimizer = SPSA(maxiter=200, last_avg=5) - solver = VQE(ansatz=ansatz, optimizer=optimizer, - expectation=PauliExpectation(), - quantum_instance=QuantumInstance( - backend=backend, - seed_simulator=algorithm_globals.random_seed, - seed_transpiler=algorithm_globals.random_seed)) + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + expectation=PauliExpectation(), + quantum_instance=QuantumInstance( + backend=backend, + seed_simulator=algorithm_globals.random_seed, + seed_transpiler=algorithm_globals.random_seed, + ), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) @@ -355,27 +396,35 @@ def test_uccsd_hf_aer_qasm(self): @slow_test def test_uccsd_hf_aer_qasm_snapshot(self): - """ uccsd hf test with Aer qasm_simulator snapshot. """ + """uccsd hf test with Aer qasm_simulator snapshot.""" try: # pylint: disable=import-outside-toplevel from qiskit import Aer - backend = Aer.get_backend('qasm_simulator') + + backend = Aer.get_backend("qasm_simulator") except ImportError as ex: # pylint: disable=broad-except - self.skipTest("Aer doesn't appear to be installed. Error: '{}'".format(str(ex))) + self.skipTest( + "Aer doesn't appear to be installed. Error: '{}'".format(str(ex)) + ) return ansatz = self._prepare_uccsd_hf(self.qubit_converter) optimizer = SPSA(maxiter=200, last_avg=5) - solver = VQE(ansatz=ansatz, optimizer=optimizer, - expectation=AerPauliExpectation(), - quantum_instance=QuantumInstance(backend=backend)) + solver = VQE( + ansatz=ansatz, + optimizer=optimizer, + expectation=AerPauliExpectation(), + quantum_instance=QuantumInstance(backend=backend), + ) gsc = GroundStateEigensolver(self.qubit_converter, solver) result = gsc.solve(self.electronic_structure_problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy, places=3) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy, places=3 + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/ground_state_solvers/test_swaprz.py b/test/algorithms/ground_state_solvers/test_swaprz.py index b6e7991504..707c7111f5 100644 --- a/test/algorithms/ground_state_solvers/test_swaprz.py +++ b/test/algorithms/ground_state_solvers/test_swaprz.py @@ -47,8 +47,9 @@ def setUp(self): def test_excitation_preserving(self): """Test the excitation preserving wavefunction on a chemistry example.""" - driver = HDF5Driver(self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + driver = HDF5Driver( + self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) converter = QubitConverter(ParityMapper()) @@ -56,8 +57,10 @@ def test_excitation_preserving(self): _ = problem.second_q_ops() - num_particles = (problem.molecule_data_transformed.num_alpha, - problem.molecule_data_transformed.num_beta) + num_particles = ( + problem.molecule_data_transformed.num_alpha, + problem.molecule_data_transformed.num_beta, + ) num_spin_orbitals = problem.molecule_data_transformed.num_molecular_orbitals * 2 @@ -68,17 +71,23 @@ def test_excitation_preserving(self): wavefunction = ExcitationPreserving(num_spin_orbitals) wavefunction.compose(initial_state, front=True, inplace=True) - solver = VQE(ansatz=wavefunction, optimizer=optimizer, - quantum_instance=QuantumInstance( - BasicAer.get_backend('statevector_simulator'), - seed_simulator=algorithm_globals.random_seed, - seed_transpiler=algorithm_globals.random_seed)) + solver = VQE( + ansatz=wavefunction, + optimizer=optimizer, + quantum_instance=QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + seed_simulator=algorithm_globals.random_seed, + seed_transpiler=algorithm_globals.random_seed, + ), + ) gsc = GroundStateEigensolver(converter, solver) result = gsc.solve(problem) - self.assertAlmostEqual(result.total_energies[0], self.reference_energy, places=4) + self.assertAlmostEqual( + result.total_energies[0], self.reference_energy, places=4 + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/pes_samplers/potentials/test_potential.py b/test/algorithms/pes_samplers/potentials/test_potential.py index d830008c99..b8e0435162 100644 --- a/test/algorithms/pes_samplers/potentials/test_potential.py +++ b/test/algorithms/pes_samplers/potentials/test_potential.py @@ -16,51 +16,143 @@ from functools import partial import numpy as np -from qiskit_nature.algorithms.pes_samplers.potentials.harmonic_potential import HarmonicPotential -from qiskit_nature.algorithms.pes_samplers.potentials.morse_potential import MorsePotential +from qiskit_nature.algorithms.pes_samplers.potentials.harmonic_potential import ( + HarmonicPotential, +) +from qiskit_nature.algorithms.pes_samplers.potentials.morse_potential import ( + MorsePotential, +) from qiskit_nature.constants import HARTREE_TO_J_PER_MOL from qiskit_nature.drivers.molecule import Molecule class TestPotential(unittest.TestCase): - """ Test Potential """ + """Test Potential""" @staticmethod def create_test_molecule(): - """ create test molecule """ - stretch = partial(Molecule.absolute_stretching, - kwargs={'atom_pair': (1, 0)}) - m = Molecule(geometry=[['H', [0., 0., 0.]], ['D', [0., 0., 1.]]], - degrees_of_freedom=[stretch], - masses=[1.6735328E-27, 3.444946E-27]) + """create test molecule""" + stretch = partial(Molecule.absolute_stretching, kwargs={"atom_pair": (1, 0)}) + m = Molecule( + geometry=[["H", [0.0, 0.0, 0.0]], ["D", [0.0, 0.0, 1.0]]], + degrees_of_freedom=[stretch], + masses=[1.6735328e-27, 3.444946e-27], + ) return m def test_morse(self): - """ test morse """ - xdata = np.array([0.45, 0.75, 1.05, 1.35, 1.65, 1.95, 2.25, 2.55, 2.85, 3.15, - 3.45, 3.75, 4.05, 4.35, 4.65, 4.95, 5.25, 0.45, 0.75, 1.05, - 1.35, 1.65, 1.95, 2.25, 2.55, 2.85, 3.15, 3.45, 3.75, 4.05, - 4.35, 4.65, 4.95, 5.25, 0.45, 0.75, 1.05, 1.35, 1.65, 1.95, - 2.25, 2.55, 2.85, 3.15, 3.45, 3.75, 4.05, 4.35, 4.65, 4.95, - 5.25]) - - ydata = np.array([-2254757.5348101, -2746067.46608231, -2664406.49829366, - -2611323.75276296, -2502198.92978322, -2417457.48952287, - -2390778.71123391, -2379482.70907613, -2373850.72354504, - -2361426.93801724, -2369992.6305902, -2363833.07716161, - -2360577.93019891, -2356002.65576262, -2355574.41051646, - -2357254.94032554, -2351656.71871981, -2308055.75509618, - -2797576.98597419, -2715367.76135088, -2616523.58105343, - -2498053.2658529, -2424288.88205414, -2393385.83237565, - -2371800.12956182, -2353202.82294735, -2346873.32092711, - -2343485.8487826, -2342937.74947792, -2350276.02096954, - -2347674.75469199, -2346912.78218669, -2339886.28877723, - -2353456.10489755, -2359599.85281831, -2811321.68662548, - -2763866.98837641, -2613385.92519959, -2506804.00364042, - -2419329.49702063, -2393428.68052976, -2374166.67617163, - -2352961.35574553, -2344972.64297329, -2356294.5588125, - -2341396.63369969, -2337344.83138146, -2339793.71365995, - -2335667.95101689, -2327347.45385524, -2341367.28061372]) + """test morse""" + xdata = np.array( + [ + 0.45, + 0.75, + 1.05, + 1.35, + 1.65, + 1.95, + 2.25, + 2.55, + 2.85, + 3.15, + 3.45, + 3.75, + 4.05, + 4.35, + 4.65, + 4.95, + 5.25, + 0.45, + 0.75, + 1.05, + 1.35, + 1.65, + 1.95, + 2.25, + 2.55, + 2.85, + 3.15, + 3.45, + 3.75, + 4.05, + 4.35, + 4.65, + 4.95, + 5.25, + 0.45, + 0.75, + 1.05, + 1.35, + 1.65, + 1.95, + 2.25, + 2.55, + 2.85, + 3.15, + 3.45, + 3.75, + 4.05, + 4.35, + 4.65, + 4.95, + 5.25, + ] + ) + + ydata = np.array( + [ + -2254757.5348101, + -2746067.46608231, + -2664406.49829366, + -2611323.75276296, + -2502198.92978322, + -2417457.48952287, + -2390778.71123391, + -2379482.70907613, + -2373850.72354504, + -2361426.93801724, + -2369992.6305902, + -2363833.07716161, + -2360577.93019891, + -2356002.65576262, + -2355574.41051646, + -2357254.94032554, + -2351656.71871981, + -2308055.75509618, + -2797576.98597419, + -2715367.76135088, + -2616523.58105343, + -2498053.2658529, + -2424288.88205414, + -2393385.83237565, + -2371800.12956182, + -2353202.82294735, + -2346873.32092711, + -2343485.8487826, + -2342937.74947792, + -2350276.02096954, + -2347674.75469199, + -2346912.78218669, + -2339886.28877723, + -2353456.10489755, + -2359599.85281831, + -2811321.68662548, + -2763866.98837641, + -2613385.92519959, + -2506804.00364042, + -2419329.49702063, + -2393428.68052976, + -2374166.67617163, + -2352961.35574553, + -2344972.64297329, + -2356294.5588125, + -2341396.63369969, + -2337344.83138146, + -2339793.71365995, + -2335667.95101689, + -2327347.45385524, + -2341367.28061372, + ] + ) ydata_hartree = ydata / HARTREE_TO_J_PER_MOL @@ -80,7 +172,9 @@ def test_morse(self): wave_number = morse.wave_number() result = np.array([minimal_energy_distance, minimal_energy, wave_number]) - benchmark = np.array([0.8106703001726382, -1.062422610690636, 3800.7855102410026]) + benchmark = np.array( + [0.8106703001726382, -1.062422610690636, 3800.7855102410026] + ) np.testing.assert_array_almost_equal(result, benchmark, decimal=4) radia = np.array([0.5, 1, 1.5, 2]) @@ -91,37 +185,131 @@ def test_morse(self): for level in range(2, 8): vib_levels.append(morse.vibrational_energy_level(level)) vib_levels = np.array(vib_levels) - vib_levels_ref = np.array([0.04052116451981064, 0.05517676610999135, - 0.06894501671860434, 0.08182591634564956, - 0.09381946499112709, 0.10492566265503685]) + vib_levels_ref = np.array( + [ + 0.04052116451981064, + 0.05517676610999135, + 0.06894501671860434, + 0.08182591634564956, + 0.09381946499112709, + 0.10492566265503685, + ] + ) np.testing.assert_array_almost_equal(vib_levels, vib_levels_ref, decimal=4) def test_harmonic(self): - """ test harmonic """ - xdata = np.array([0.45, 0.75, 1.05, 1.35, 1.65, 1.95, 2.25, 2.55, 2.85, 3.15, - 3.45, 3.75, 4.05, 4.35, 4.65, 4.95, 5.25, 0.45, 0.75, 1.05, - 1.35, 1.65, 1.95, 2.25, 2.55, 2.85, 3.15, 3.45, 3.75, 4.05, - 4.35, 4.65, 4.95, 5.25, 0.45, 0.75, 1.05, 1.35, 1.65, 1.95, - 2.25, 2.55, 2.85, 3.15, 3.45, 3.75, 4.05, 4.35, 4.65, 4.95, - 5.25]) - - ydata = np.array([-2254757.5348101, -2746067.46608231, -2664406.49829366, - -2611323.75276296, -2502198.92978322, -2417457.48952287, - -2390778.71123391, -2379482.70907613, -2373850.72354504, - -2361426.93801724, -2369992.6305902, -2363833.07716161, - -2360577.93019891, -2356002.65576262, -2355574.41051646, - -2357254.94032554, -2351656.71871981, -2308055.75509618, - -2797576.98597419, -2715367.76135088, -2616523.58105343, - -2498053.2658529, -2424288.88205414, -2393385.83237565, - -2371800.12956182, -2353202.82294735, -2346873.32092711, - -2343485.8487826, -2342937.74947792, -2350276.02096954, - -2347674.75469199, -2346912.78218669, -2339886.28877723, - -2353456.10489755, -2359599.85281831, -2811321.68662548, - -2763866.98837641, -2613385.92519959, -2506804.00364042, - -2419329.49702063, -2393428.68052976, -2374166.67617163, - -2352961.35574553, -2344972.64297329, -2356294.5588125, - -2341396.63369969, -2337344.83138146, -2339793.71365995, - -2335667.95101689, -2327347.45385524, -2341367.28061372]) + """test harmonic""" + xdata = np.array( + [ + 0.45, + 0.75, + 1.05, + 1.35, + 1.65, + 1.95, + 2.25, + 2.55, + 2.85, + 3.15, + 3.45, + 3.75, + 4.05, + 4.35, + 4.65, + 4.95, + 5.25, + 0.45, + 0.75, + 1.05, + 1.35, + 1.65, + 1.95, + 2.25, + 2.55, + 2.85, + 3.15, + 3.45, + 3.75, + 4.05, + 4.35, + 4.65, + 4.95, + 5.25, + 0.45, + 0.75, + 1.05, + 1.35, + 1.65, + 1.95, + 2.25, + 2.55, + 2.85, + 3.15, + 3.45, + 3.75, + 4.05, + 4.35, + 4.65, + 4.95, + 5.25, + ] + ) + + ydata = np.array( + [ + -2254757.5348101, + -2746067.46608231, + -2664406.49829366, + -2611323.75276296, + -2502198.92978322, + -2417457.48952287, + -2390778.71123391, + -2379482.70907613, + -2373850.72354504, + -2361426.93801724, + -2369992.6305902, + -2363833.07716161, + -2360577.93019891, + -2356002.65576262, + -2355574.41051646, + -2357254.94032554, + -2351656.71871981, + -2308055.75509618, + -2797576.98597419, + -2715367.76135088, + -2616523.58105343, + -2498053.2658529, + -2424288.88205414, + -2393385.83237565, + -2371800.12956182, + -2353202.82294735, + -2346873.32092711, + -2343485.8487826, + -2342937.74947792, + -2350276.02096954, + -2347674.75469199, + -2346912.78218669, + -2339886.28877723, + -2353456.10489755, + -2359599.85281831, + -2811321.68662548, + -2763866.98837641, + -2613385.92519959, + -2506804.00364042, + -2419329.49702063, + -2393428.68052976, + -2374166.67617163, + -2352961.35574553, + -2344972.64297329, + -2356294.5588125, + -2341396.63369969, + -2337344.83138146, + -2339793.71365995, + -2335667.95101689, + -2327347.45385524, + -2341367.28061372, + ] + ) ydata_hartree = ydata / HARTREE_TO_J_PER_MOL @@ -142,7 +330,9 @@ def test_harmonic(self): wave_number = harmonic.wave_number() result = np.array([minimal_energy_distance, minimal_energy, wave_number]) - benchmark = np.array([0.8792058944654566, -1.0678714520398802, 4670.969897517367]) + benchmark = np.array( + [0.8792058944654566, -1.0678714520398802, 4670.969897517367] + ) np.testing.assert_array_almost_equal(result, benchmark) radia = np.array([0.5, 1, 1.5, 2]) @@ -153,11 +343,18 @@ def test_harmonic(self): for level in range(2, 8): vib_levels.append(harmonic.vibrational_energy_level(level)) vib_levels = np.array(vib_levels) - vib_levels_ref = np.array([0.053206266711245426, 0.07448877339574358, - 0.09577128008024177, 0.11705378676473993, - 0.13833629344923812, 0.15961880013373628]) + vib_levels_ref = np.array( + [ + 0.053206266711245426, + 0.07448877339574358, + 0.09577128008024177, + 0.11705378676473993, + 0.13833629344923812, + 0.15961880013373628, + ] + ) np.testing.assert_array_almost_equal(vib_levels, vib_levels_ref) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/algorithms/pes_samplers/test_bopes_sampler.py b/test/algorithms/pes_samplers/test_bopes_sampler.py index 85101f9ceb..d3e6ee5e99 100644 --- a/test/algorithms/pes_samplers/test_bopes_sampler.py +++ b/test/algorithms/pes_samplers/test_bopes_sampler.py @@ -38,9 +38,10 @@ def test_h2_bopes_sampler(self): # Molecule dof = partial(Molecule.absolute_distance, atom_pair=(1, 0)) - m = Molecule(geometry=[['H', [0., 0., 1.]], - ['H', [0., 0.45, 1.]]], - degrees_of_freedom=[dof]) + m = Molecule( + geometry=[["H", [0.0, 0.0, 1.0]], ["H", [0.0, 0.45, 1.0]]], + degrees_of_freedom=[dof], + ) mapper = ParityMapper() converter = QubitConverter(mapper=mapper, two_qubit_reduction=True) @@ -62,8 +63,9 @@ def test_h2_bopes_sampler(self): energies = results.energies np.testing.assert_array_almost_equal(points_run, [0.7, 1.0, 1.3]) - np.testing.assert_array_almost_equal(energies, - [-1.13618945, -1.10115033, -1.03518627], decimal=2) + np.testing.assert_array_almost_equal( + energies, [-1.13618945, -1.10115033, -1.03518627], decimal=2 + ) def test_potential_interface(self): """Tests potential interface.""" @@ -72,11 +74,14 @@ def test_potential_interface(self): stretch = partial(Molecule.absolute_distance, atom_pair=(1, 0)) # H-H molecule near equilibrium geometry - m = Molecule(geometry=[['H', [0., 0., 0.]], - ['H', [1., 0., 0.]], - ], - degrees_of_freedom=[stretch], - masses=[1.6735328E-27, 1.6735328E-27]) + m = Molecule( + geometry=[ + ["H", [0.0, 0.0, 0.0]], + ["H", [1.0, 0.0, 0.0]], + ], + degrees_of_freedom=[stretch], + masses=[1.6735328e-27, 1.6735328e-27], + ) mapper = ParityMapper() converter = QubitConverter(mapper=mapper) @@ -97,8 +102,12 @@ def test_potential_interface(self): pot = MorsePotential(m) pot.fit(res.points, res.energies) - np.testing.assert_array_almost_equal([pot.alpha, pot.r_0], [2.235, 0.720], decimal=3) - np.testing.assert_array_almost_equal([pot.d_e, pot.m_shift], [0.2107, -1.1419], decimal=3) + np.testing.assert_array_almost_equal( + [pot.alpha, pot.r_0], [2.235, 0.720], decimal=3 + ) + np.testing.assert_array_almost_equal( + [pot.d_e, pot.m_shift], [0.2107, -1.1419], decimal=3 + ) if __name__ == "__main__": diff --git a/test/algorithms/pes_samplers/test_extrapolators.py b/test/algorithms/pes_samplers/test_extrapolators.py index 48e2168101..7eaff0fcd2 100644 --- a/test/algorithms/pes_samplers/test_extrapolators.py +++ b/test/algorithms/pes_samplers/test_extrapolators.py @@ -19,71 +19,196 @@ from sklearn import linear_model from qiskit_nature.exceptions import QiskitNatureError from qiskit_nature.algorithms.pes_samplers import ( - Extrapolator, WindowExtrapolator, PolynomialExtrapolator, DifferentialExtrapolator, - PCAExtrapolator, SieveExtrapolator) + Extrapolator, + WindowExtrapolator, + PolynomialExtrapolator, + DifferentialExtrapolator, + PCAExtrapolator, + SieveExtrapolator, +) PARAM_DICT = { - 0.5: [0.07649726233077458, 1.2340960400591198e-07, 2.719308771599091e-08, - 0.008390437810203526, 0.0764741614750971, 1.9132000956096602e-07, - 2.9065333930913485e-07, 0.00833313170973392, -0.05158805745745537, - 5.8737804595134226e-08], - 0.6: [0.047537653925701376, -1.917048657008852e-07, -3.422658080883276e-08, - 0.004906396230989982, 0.0475356511244039, -1.4858989951517077e-07, - -4.554118927702692e-07, 0.004904674017550646, -0.026469990208471097, - -7.247195166355873e-08], - 0.7: [0.03613992230685178, 4.741673241363808e-07, 2.3773620079947958e-07, - 0.0019807112069739983, 0.03613265701497832, 6.110370616271814e-07, - 4.7624119913927746e-07, 0.0019793617137878546, -0.022690629295970738, - 1.4536323300165836e-07], - 0.8: [0.032353493452967126, -5.988966845753558e-07, 5.745328822729277e-08, - 0.00021194523430201692, 0.032355414067993846, -5.189590826114998e-07, - -3.67836416341141e-07, 0.0002135481005546501, -0.021642050861260625, - -1.7031569870078584e-08], - 0.9: [0.029140898456611407, -6.173482350529143e-07, 6.195627362572485e-08, - -0.0003490974905228344, 0.029145442226752687, -6.121480980106215e-07, - -7.301901035010772e-07, -0.0003490856477090481, -0.02152841574436387, - 1.7275126260813324e-07], - 1.0: [0.029247914836804657, 5.406923000869481e-08, -1.2835940341198057e-08, - -0.00014550115747168215, 0.02924483275168305, 3.332715515541604e-08, - -4.214594252866692e-08, -0.00014476700526947067, -0.022193103836975897, - 1.8066966314280466e-07], - 1.1: [0.03006212028509998, 8.719643359505152e-07, 2.2976675446724122e-07, - 0.00047712315923690516, 0.03006488639435572, 1.1166361133977898e-06, - 5.061212361236216e-07, 0.00047764287100316387, -0.023178549796925824, - -2.928595563199974e-07], - 1.2: [0.030974376843233304, -1.0856144455895877e-06, -3.476503050548108e-07, - 0.001136538429249089, 0.03097485850614847, -9.341556711096642e-07, - -1.1105021085720809e-07, 0.0011365812922166018, -0.024770225335378506, - 3.1946997465490094e-07], - 1.3: [0.031882221296263585, 1.786623717240475e-06, 5.966161740895298e-07, - 0.0019238138369525367, 0.03188025548265294, 2.001914958908424e-06, - -7.558698586542756e-08, 0.0019267033837603463, -0.026633630436000855, - -4.838673928102748e-07], - 1.4: [0.03363319046621523, -6.215327218045763e-06, -1.707461485292177e-06, - 0.0022111427295926026, 0.03363427344016048, -6.479433272163631e-06, - -8.620279811840461e-07, 0.0022079369298442677, -0.029254200628083923, - 2.03258913595112e-06], - 1.5: [0.03566191437849682, 1.3175681716659443e-05, 3.3463916528882136e-06, - 0.0030670576873521546, 0.03565986755932079, 1.3808936313520536e-05, - 2.1227354591337757e-06, 0.0030639663487480417, -0.03203113690256062, - -2.988438361808215e-06], - 1.6: [0.03853048160610931, -4.500510577352305e-05, -1.1042391095055013e-05, - 0.003589496950963951, 0.03852649109560952, -4.632560074669591e-05, - -6.9604927841086826e-06, 0.003591766338853773, -0.03617535567521557, - 1.03526517642164e-05], - 1.7: [0.04166595503111059, 0.00012474608362087326, 3.0811181106852395e-05, - 0.004449408009656353, 0.04167583498336048, 0.0001291807564363206, - 1.9103762924011895e-05, 0.004443558543591776, -0.0411176424372442, - -3.143959686889569e-05], - 1.8: [0.04630023768704881, -0.0003032527231323504, -7.224290210451026e-05, - 0.004988381942930891, 0.04629620402315099, -0.0003111138155773558, - -4.900370932911525e-05, 0.004995942389375613, -0.047398106863887825, - 7.734110549927737e-05], - 1.9: [0.05237961421167222, 0.0006396923182584415, 0.00014873747649097767, - 0.005855974769304974, 0.05234227038906301, 0.0006540391246003456, - 0.00010652381338578109, 0.005850757199904456, -0.055346836396118364, - -0.00018559571977688104] + 0.5: [ + 0.07649726233077458, + 1.2340960400591198e-07, + 2.719308771599091e-08, + 0.008390437810203526, + 0.0764741614750971, + 1.9132000956096602e-07, + 2.9065333930913485e-07, + 0.00833313170973392, + -0.05158805745745537, + 5.8737804595134226e-08, + ], + 0.6: [ + 0.047537653925701376, + -1.917048657008852e-07, + -3.422658080883276e-08, + 0.004906396230989982, + 0.0475356511244039, + -1.4858989951517077e-07, + -4.554118927702692e-07, + 0.004904674017550646, + -0.026469990208471097, + -7.247195166355873e-08, + ], + 0.7: [ + 0.03613992230685178, + 4.741673241363808e-07, + 2.3773620079947958e-07, + 0.0019807112069739983, + 0.03613265701497832, + 6.110370616271814e-07, + 4.7624119913927746e-07, + 0.0019793617137878546, + -0.022690629295970738, + 1.4536323300165836e-07, + ], + 0.8: [ + 0.032353493452967126, + -5.988966845753558e-07, + 5.745328822729277e-08, + 0.00021194523430201692, + 0.032355414067993846, + -5.189590826114998e-07, + -3.67836416341141e-07, + 0.0002135481005546501, + -0.021642050861260625, + -1.7031569870078584e-08, + ], + 0.9: [ + 0.029140898456611407, + -6.173482350529143e-07, + 6.195627362572485e-08, + -0.0003490974905228344, + 0.029145442226752687, + -6.121480980106215e-07, + -7.301901035010772e-07, + -0.0003490856477090481, + -0.02152841574436387, + 1.7275126260813324e-07, + ], + 1.0: [ + 0.029247914836804657, + 5.406923000869481e-08, + -1.2835940341198057e-08, + -0.00014550115747168215, + 0.02924483275168305, + 3.332715515541604e-08, + -4.214594252866692e-08, + -0.00014476700526947067, + -0.022193103836975897, + 1.8066966314280466e-07, + ], + 1.1: [ + 0.03006212028509998, + 8.719643359505152e-07, + 2.2976675446724122e-07, + 0.00047712315923690516, + 0.03006488639435572, + 1.1166361133977898e-06, + 5.061212361236216e-07, + 0.00047764287100316387, + -0.023178549796925824, + -2.928595563199974e-07, + ], + 1.2: [ + 0.030974376843233304, + -1.0856144455895877e-06, + -3.476503050548108e-07, + 0.001136538429249089, + 0.03097485850614847, + -9.341556711096642e-07, + -1.1105021085720809e-07, + 0.0011365812922166018, + -0.024770225335378506, + 3.1946997465490094e-07, + ], + 1.3: [ + 0.031882221296263585, + 1.786623717240475e-06, + 5.966161740895298e-07, + 0.0019238138369525367, + 0.03188025548265294, + 2.001914958908424e-06, + -7.558698586542756e-08, + 0.0019267033837603463, + -0.026633630436000855, + -4.838673928102748e-07, + ], + 1.4: [ + 0.03363319046621523, + -6.215327218045763e-06, + -1.707461485292177e-06, + 0.0022111427295926026, + 0.03363427344016048, + -6.479433272163631e-06, + -8.620279811840461e-07, + 0.0022079369298442677, + -0.029254200628083923, + 2.03258913595112e-06, + ], + 1.5: [ + 0.03566191437849682, + 1.3175681716659443e-05, + 3.3463916528882136e-06, + 0.0030670576873521546, + 0.03565986755932079, + 1.3808936313520536e-05, + 2.1227354591337757e-06, + 0.0030639663487480417, + -0.03203113690256062, + -2.988438361808215e-06, + ], + 1.6: [ + 0.03853048160610931, + -4.500510577352305e-05, + -1.1042391095055013e-05, + 0.003589496950963951, + 0.03852649109560952, + -4.632560074669591e-05, + -6.9604927841086826e-06, + 0.003591766338853773, + -0.03617535567521557, + 1.03526517642164e-05, + ], + 1.7: [ + 0.04166595503111059, + 0.00012474608362087326, + 3.0811181106852395e-05, + 0.004449408009656353, + 0.04167583498336048, + 0.0001291807564363206, + 1.9103762924011895e-05, + 0.004443558543591776, + -0.0411176424372442, + -3.143959686889569e-05, + ], + 1.8: [ + 0.04630023768704881, + -0.0003032527231323504, + -7.224290210451026e-05, + 0.004988381942930891, + 0.04629620402315099, + -0.0003111138155773558, + -4.900370932911525e-05, + 0.004995942389375613, + -0.047398106863887825, + 7.734110549927737e-05, + ], + 1.9: [ + 0.05237961421167222, + 0.0006396923182584415, + 0.00014873747649097767, + 0.005855974769304974, + 0.05234227038906301, + 0.0006540391246003456, + 0.00010652381338578109, + 0.005850757199904456, + -0.055346836396118364, + -0.00018559571977688104, + ], } @@ -94,11 +219,13 @@ def test_factory(self): """ Test factory method implementation to create instances of various Extrapolators. """ - self.assertIsInstance(Extrapolator.factory(mode='window'), WindowExtrapolator) - self.assertIsInstance(Extrapolator.factory(mode='poly'), PolynomialExtrapolator) - self.assertIsInstance(Extrapolator.factory(mode='diff_model'), DifferentialExtrapolator) - self.assertIsInstance(Extrapolator.factory(mode='pca'), PCAExtrapolator) - self.assertIsInstance(Extrapolator.factory(mode='l1'), SieveExtrapolator) + self.assertIsInstance(Extrapolator.factory(mode="window"), WindowExtrapolator) + self.assertIsInstance(Extrapolator.factory(mode="poly"), PolynomialExtrapolator) + self.assertIsInstance( + Extrapolator.factory(mode="diff_model"), DifferentialExtrapolator + ) + self.assertIsInstance(Extrapolator.factory(mode="pca"), PCAExtrapolator) + self.assertIsInstance(Extrapolator.factory(mode="l1"), SieveExtrapolator) self.assertRaises(QiskitNatureError, Extrapolator.factory, mode="unknown") def test_polynomial_extrapolator(self): @@ -112,10 +239,13 @@ def test_polynomial_extrapolator(self): polynomial extrapolator. """ points = 0.7 - params = PolynomialExtrapolator(degree=3).extrapolate(points=[points], - param_dict=PARAM_DICT) - sq_diff = [(actual - expected) ** 2 for actual, expected in - zip(params[points], PARAM_DICT[points])] + params = PolynomialExtrapolator(degree=3).extrapolate( + points=[points], param_dict=PARAM_DICT + ) + sq_diff = [ + (actual - expected) ** 2 + for actual, expected in zip(params[points], PARAM_DICT[points]) + ] self.assertLess(sum(sq_diff), 1e-3) def test_poly_window_extrapolator(self): @@ -126,21 +256,29 @@ def test_poly_window_extrapolator(self): and that the extrapolation of the parameters on the last three points has a error below a threshold when compared to the actual parameter values. """ - points_interspersed = [.3, .5, .7, .8, 1.5] - window_extrapolator = Extrapolator.factory("window", - extrapolator=PolynomialExtrapolator(degree=1), - window=3) - params = window_extrapolator.extrapolate(points=points_interspersed, param_dict=PARAM_DICT) - self.assertFalse(params.get(.3)) - self.assertFalse(params.get(.5)) - sq_diff_1 = [(actual - expected) ** 2 - for actual, expected in zip(params[.7], PARAM_DICT[.7])] + points_interspersed = [0.3, 0.5, 0.7, 0.8, 1.5] + window_extrapolator = Extrapolator.factory( + "window", extrapolator=PolynomialExtrapolator(degree=1), window=3 + ) + params = window_extrapolator.extrapolate( + points=points_interspersed, param_dict=PARAM_DICT + ) + self.assertFalse(params.get(0.3)) + self.assertFalse(params.get(0.5)) + sq_diff_1 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.7], PARAM_DICT[0.7]) + ] self.assertLess(sum(sq_diff_1), 1e-1) - sq_diff_2 = [(actual - expected) ** 2 - for actual, expected in zip(params[.8], PARAM_DICT[.8])] + sq_diff_2 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.8], PARAM_DICT[0.8]) + ] self.assertLess(sum(sq_diff_2), 1e-2) - sq_diff_3 = [(actual - expected) ** 2 - for actual, expected in zip(params[1.5], PARAM_DICT[1.5])] + sq_diff_3 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[1.5], PARAM_DICT[1.5]) + ] self.assertLess(sum(sq_diff_3), 1e-2) def test_differential_model_window_extrapolator(self): @@ -151,20 +289,29 @@ def test_differential_model_window_extrapolator(self): before the data window, i.e, the first two points, and that the extrapolation of the parameters on the last three points has some specified error relative to the actual values. """ - points_interspersed = [.3, .5, .7, .8, 1.5] - window_extrapolator = WindowExtrapolator(extrapolator=DifferentialExtrapolator(degree=1), - window=3) - params = window_extrapolator.extrapolate(points=points_interspersed, param_dict=PARAM_DICT) - self.assertFalse(params.get(.3)) - self.assertFalse(params.get(.5)) - sq_diff_1 = [(actual - expected) ** 2 - for actual, expected in zip(params[.7], PARAM_DICT[.7])] + points_interspersed = [0.3, 0.5, 0.7, 0.8, 1.5] + window_extrapolator = WindowExtrapolator( + extrapolator=DifferentialExtrapolator(degree=1), window=3 + ) + params = window_extrapolator.extrapolate( + points=points_interspersed, param_dict=PARAM_DICT + ) + self.assertFalse(params.get(0.3)) + self.assertFalse(params.get(0.5)) + sq_diff_1 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.7], PARAM_DICT[0.7]) + ] self.assertLess(sum(sq_diff_1), 1e-2) - sq_diff_2 = [(actual - expected) ** 2 - for actual, expected in zip(params[.8], PARAM_DICT[.8])] + sq_diff_2 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.8], PARAM_DICT[0.8]) + ] self.assertLess(sum(sq_diff_2), 1e-3) - sq_diff_3 = [(actual - expected) ** 2 - for actual, expected in zip(params[1.5], PARAM_DICT[1.5])] + sq_diff_3 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[1.5], PARAM_DICT[1.5]) + ] self.assertLess(sum(sq_diff_3), 1e-3) def test_differential_model_window_alternate_model_extrapolator(self): @@ -175,23 +322,30 @@ def test_differential_model_window_alternate_model_extrapolator(self): the data window, i.e, the first two points, and that the extrapolation of the parameters on the last three points has some specified error relative to the actual parameter values. """ - points_interspersed = [.3, .5, .7, .8, 1.5] + points_interspersed = [0.3, 0.5, 0.7, 0.8, 1.5] model = linear_model.Ridge() - window_extrapolator = WindowExtrapolator(extrapolator=DifferentialExtrapolator(degree=1, - model=model), - window=3) - params = window_extrapolator.extrapolate(points=points_interspersed, param_dict=PARAM_DICT) - self.assertFalse(params.get(.3)) - self.assertFalse(params.get(.5)) - sq_diff_1 = [(actual - expected) ** 2 - for actual, expected in zip(params[.7], PARAM_DICT[.7])] + window_extrapolator = WindowExtrapolator( + extrapolator=DifferentialExtrapolator(degree=1, model=model), window=3 + ) + params = window_extrapolator.extrapolate( + points=points_interspersed, param_dict=PARAM_DICT + ) + self.assertFalse(params.get(0.3)) + self.assertFalse(params.get(0.5)) + sq_diff_1 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.7], PARAM_DICT[0.7]) + ] self.assertLess(sum(sq_diff_1), 1e-2) - sq_diff_2 = [(actual - expected) ** 2 - for actual, expected in zip(params[.8], PARAM_DICT[.8])] + sq_diff_2 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.8], PARAM_DICT[0.8]) + ] self.assertLess(sum(sq_diff_2), 1e-3) - sq_diff_3 = [(actual - expected) ** 2 - for actual, expected in - zip(params[1.5], PARAM_DICT[1.5])] + sq_diff_3 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[1.5], PARAM_DICT[1.5]) + ] self.assertLess(sum(sq_diff_3), 1e-3) def test_pca_polynomial_window_extrapolator(self): @@ -202,20 +356,29 @@ def test_pca_polynomial_window_extrapolator(self): data window, i.e, the first two points, and that the extrapolation of the parameters on last three points has a specified error relative to the actual parameter values. """ - points_interspersed = [.3, .5, .7, .8, 1.5] - pca_poly_win_ext = PCAExtrapolator(extrapolator=PolynomialExtrapolator(degree=1), - window=3) - params = pca_poly_win_ext.extrapolate(points=points_interspersed, param_dict=PARAM_DICT) - self.assertFalse(params.get(.3)) - self.assertFalse(params.get(.5)) - sq_diff_1 = [(actual - expected) ** 2 - for actual, expected in zip(params[.7], PARAM_DICT[.7])] + points_interspersed = [0.3, 0.5, 0.7, 0.8, 1.5] + pca_poly_win_ext = PCAExtrapolator( + extrapolator=PolynomialExtrapolator(degree=1), window=3 + ) + params = pca_poly_win_ext.extrapolate( + points=points_interspersed, param_dict=PARAM_DICT + ) + self.assertFalse(params.get(0.3)) + self.assertFalse(params.get(0.5)) + sq_diff_1 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.7], PARAM_DICT[0.7]) + ] self.assertLess(sum(sq_diff_1), 1e-2) - sq_diff_2 = [(actual - expected) ** 2 - for actual, expected in zip(params[.8], PARAM_DICT[.8])] + sq_diff_2 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.8], PARAM_DICT[0.8]) + ] self.assertLess(sum(sq_diff_2), 1e-2) - sq_diff_3 = [(actual - expected) ** 2 - for actual, expected in zip(params[1.5], PARAM_DICT[1.5])] + sq_diff_3 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[1.5], PARAM_DICT[1.5]) + ] self.assertLess(sum(sq_diff_3), 1e-2) def test_sieve_poly_window_extrapolator(self): @@ -226,23 +389,31 @@ def test_sieve_poly_window_extrapolator(self): data window, i.e, the first two points, and that the extrapolation of the parameters on the last three points has some specified error relative to the actual parameter values. """ - points_interspersed = [.3, .5, .7, .8, 1.5] - sieve_win_extrapolator = SieveExtrapolator(extrapolator=PolynomialExtrapolator(degree=1), - window=3) - params = sieve_win_extrapolator.extrapolate(points=points_interspersed, - param_dict=PARAM_DICT) - self.assertFalse(params.get(.3)) - self.assertFalse(params.get(.5)) - sq_diff_1 = [(actual - expected) ** 2 - for actual, expected in zip(params[.7], PARAM_DICT[.7])] + points_interspersed = [0.3, 0.5, 0.7, 0.8, 1.5] + sieve_win_extrapolator = SieveExtrapolator( + extrapolator=PolynomialExtrapolator(degree=1), window=3 + ) + params = sieve_win_extrapolator.extrapolate( + points=points_interspersed, param_dict=PARAM_DICT + ) + self.assertFalse(params.get(0.3)) + self.assertFalse(params.get(0.5)) + sq_diff_1 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.7], PARAM_DICT[0.7]) + ] self.assertLess(sum(sq_diff_1), 1e-1) - sq_diff_2 = [(actual - expected) ** 2 - for actual, expected in zip(params[.8], PARAM_DICT[.8])] + sq_diff_2 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[0.8], PARAM_DICT[0.8]) + ] self.assertLess(sum(sq_diff_2), 1e-1) - sq_diff_3 = [(actual - expected) ** 2 - for actual, expected in zip(params[1.5], PARAM_DICT[1.5])] + sq_diff_3 = [ + (actual - expected) ** 2 + for actual, expected in zip(params[1.5], PARAM_DICT[1.5]) + ] self.assertLess(sum(sq_diff_3), 1e-1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/circuit/library/ansatzes/test_chc.py b/test/circuit/library/ansatzes/test_chc.py index ae444d8333..69da86d7c3 100644 --- a/test/circuit/library/ansatzes/test_chc.py +++ b/test/circuit/library/ansatzes/test_chc.py @@ -21,17 +21,19 @@ from qiskit.algorithms import VQE from qiskit.algorithms.optimizers import COBYLA from qiskit_nature.circuit.library import CHC, VSCF -from qiskit_nature.circuit.library.ansatzes.utils.vibration_excitation_generator import \ - generate_vibration_excitations +from qiskit_nature.circuit.library.ansatzes.utils.vibration_excitation_generator import ( + generate_vibration_excitations, +) from qiskit_nature.mappers.second_quantization import DirectMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.operators.second_quantization import VibrationalOp -from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder \ - import _create_labels +from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder import ( + _create_labels, +) class TestCHCVSCF(QiskitNatureTestCase): - """Test for CHC and VSCF library circuits. """ + """Test for CHC and VSCF library circuits.""" def setUp(self): super().setUp() @@ -39,28 +41,34 @@ def setUp(self): algorithm_globals.random_seed = 14 def test_chc_vscf(self): - """ chc vscf test """ - - co2_2modes_2modals_2body = [[[[[0, 0, 0]], 320.8467332810141], - [[[0, 1, 1]], 1760.878530705873], - [[[1, 0, 0]], 342.8218290247543], - [[[1, 1, 1]], 1032.396323618631]], - [[[[0, 0, 0], [1, 0, 0]], -57.34003649795117], - [[[0, 0, 1], [1, 0, 0]], -56.33205925807966], - [[[0, 1, 0], [1, 0, 0]], -56.33205925807966], - [[[0, 1, 1], [1, 0, 0]], -60.13032761856809], - [[[0, 0, 0], [1, 0, 1]], -65.09576309934431], - [[[0, 0, 1], [1, 0, 1]], -62.2363839133389], - [[[0, 1, 0], [1, 0, 1]], -62.2363839133389], - [[[0, 1, 1], [1, 0, 1]], -121.5533969109279], - [[[0, 0, 0], [1, 1, 0]], -65.09576309934431], - [[[0, 0, 1], [1, 1, 0]], -62.2363839133389], - [[[0, 1, 0], [1, 1, 0]], -62.2363839133389], - [[[0, 1, 1], [1, 1, 0]], -121.5533969109279], - [[[0, 0, 0], [1, 1, 1]], -170.744837386338], - [[[0, 0, 1], [1, 1, 1]], -167.7433236025723], - [[[0, 1, 0], [1, 1, 1]], -167.7433236025723], - [[[0, 1, 1], [1, 1, 1]], -179.0536532281924]]] + """chc vscf test""" + + co2_2modes_2modals_2body = [ + [ + [[[0, 0, 0]], 320.8467332810141], + [[[0, 1, 1]], 1760.878530705873], + [[[1, 0, 0]], 342.8218290247543], + [[[1, 1, 1]], 1032.396323618631], + ], + [ + [[[0, 0, 0], [1, 0, 0]], -57.34003649795117], + [[[0, 0, 1], [1, 0, 0]], -56.33205925807966], + [[[0, 1, 0], [1, 0, 0]], -56.33205925807966], + [[[0, 1, 1], [1, 0, 0]], -60.13032761856809], + [[[0, 0, 0], [1, 0, 1]], -65.09576309934431], + [[[0, 0, 1], [1, 0, 1]], -62.2363839133389], + [[[0, 1, 0], [1, 0, 1]], -62.2363839133389], + [[[0, 1, 1], [1, 0, 1]], -121.5533969109279], + [[[0, 0, 0], [1, 1, 0]], -65.09576309934431], + [[[0, 0, 1], [1, 1, 0]], -62.2363839133389], + [[[0, 1, 0], [1, 1, 0]], -62.2363839133389], + [[[0, 1, 1], [1, 1, 0]], -121.5533969109279], + [[[0, 0, 0], [1, 1, 1]], -170.744837386338], + [[[0, 0, 1], [1, 1, 1]], -167.7433236025723], + [[[0, 1, 0], [1, 1, 1]], -167.7433236025723], + [[[0, 1, 1], [1, 1, 1]], -179.0536532281924], + ], + ] num_modes = 2 num_modals = [2, 2] @@ -75,13 +83,21 @@ def test_chc_vscf(self): num_qubits = sum(num_modals) excitations = [] - excitations += generate_vibration_excitations(num_excitations=1, num_modals=num_modals) - excitations += generate_vibration_excitations(num_excitations=2, num_modals=num_modals) - chc_ansatz = CHC(num_qubits, ladder=False, excitations=excitations, - initial_state=init_state) - - backend = QuantumInstance(BasicAer.get_backend('statevector_simulator'), - seed_transpiler=2, seed_simulator=2) + excitations += generate_vibration_excitations( + num_excitations=1, num_modals=num_modals + ) + excitations += generate_vibration_excitations( + num_excitations=2, num_modals=num_modals + ) + chc_ansatz = CHC( + num_qubits, ladder=False, excitations=excitations, initial_state=init_state + ) + + backend = QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + seed_transpiler=2, + seed_simulator=2, + ) optimizer = COBYLA(maxiter=1000) algo = VQE(chc_ansatz, optimizer=optimizer, quantum_instance=backend) @@ -91,5 +107,5 @@ def test_chc_vscf(self): self.assertAlmostEqual(energy, self.reference_energy, places=4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/circuit/library/ansatzes/test_evolved_op_ansatz.py b/test/circuit/library/ansatzes/test_evolved_op_ansatz.py index fc39f5160a..932a768106 100644 --- a/test/circuit/library/ansatzes/test_evolved_op_ansatz.py +++ b/test/circuit/library/ansatzes/test_evolved_op_ansatz.py @@ -28,7 +28,7 @@ def test_evolved_op_ansatz(self): num_qubits = 3 ops = [Z ^ num_qubits, Y ^ num_qubits, X ^ num_qubits] - strings = ['z' * num_qubits, 'y' * num_qubits, 'x' * num_qubits] * 2 + strings = ["z" * num_qubits, "y" * num_qubits, "x" * num_qubits] * 2 evo = EvolvedOperatorAnsatz(ops, 2) evo._build() # fixed by speedup parameter binds PR @@ -95,9 +95,9 @@ def evolve(pauli_string, time): num_qubits = len(pauli_string) forward = QuantumCircuit(num_qubits) for i, pauli in enumerate(pauli_string): - if pauli == 'x': + if pauli == "x": forward.h(i) - elif pauli == 'y': + elif pauli == "y": forward.sdg(i) forward.h(i) diff --git a/test/circuit/library/ansatzes/test_puccd.py b/test/circuit/library/ansatzes/test_puccd.py index 061f257ea3..834c2caba8 100644 --- a/test/circuit/library/ansatzes/test_puccd.py +++ b/test/circuit/library/ansatzes/test_puccd.py @@ -30,41 +30,73 @@ class TestPUCC(QiskitNatureTestCase): @unpack @data( - (4, (1, 1), [FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (8, (2, 2), [FermionicOp([('+I-I+I-I', 1j), ('-I+I-I+I', -1j)]), - FermionicOp([('+II-+II-', 1j), ('-II+-II+', -1j)]), - FermionicOp([('I+-II+-I', 1j), ('I-+II-+I', -1j)]), - FermionicOp([('I+I-I+I-', 1j), ('I-I+I-I+', -1j)])]), + (4, (1, 1), [FermionicOp([("+-+-", 1j), ("-+-+", -1j)])]), + ( + 8, + (2, 2), + [ + FermionicOp([("+I-I+I-I", 1j), ("-I+I-I+I", -1j)]), + FermionicOp([("+II-+II-", 1j), ("-II+-II+", -1j)]), + FermionicOp([("I+-II+-I", 1j), ("I-+II-+I", -1j)]), + FermionicOp([("I+I-I+I-", 1j), ("I-I+I-I+", -1j)]), + ], + ), ) def test_puccd_ansatz(self, num_spin_orbitals, num_particles, expect): """Tests the PUCCD Ansatz.""" converter = QubitConverter(JordanWignerMapper()) - ansatz = PUCCD(qubit_converter=converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals) + ansatz = PUCCD( + qubit_converter=converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + ) assert_ucc_like_ansatz(self, ansatz, num_spin_orbitals, expect) @unpack @data( - (4, (1, 1), (True, True), [FermionicOp([('+-II', 1j), ('-+II', 1j)]), - FermionicOp([('II+-', 1j), ('II-+', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (4, (1, 1), (True, False), [FermionicOp([('+-II', 1j), ('-+II', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (4, (1, 1), (False, True), [FermionicOp([('II+-', 1j), ('II-+', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), + ( + 4, + (1, 1), + (True, True), + [ + FermionicOp([("+-II", 1j), ("-+II", 1j)]), + FermionicOp([("II+-", 1j), ("II-+", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), + ( + 4, + (1, 1), + (True, False), + [ + FermionicOp([("+-II", 1j), ("-+II", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), + ( + 4, + (1, 1), + (False, True), + [ + FermionicOp([("II+-", 1j), ("II-+", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), ) - def test_puccd_ansatz_with_singles(self, num_spin_orbitals, num_particles, include_singles, - expect): + def test_puccd_ansatz_with_singles( + self, num_spin_orbitals, num_particles, include_singles, expect + ): """Tests the PUCCD Ansatz with included single excitations.""" converter = QubitConverter(JordanWignerMapper()) - ansatz = PUCCD(qubit_converter=converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - include_singles=include_singles) + ansatz = PUCCD( + qubit_converter=converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + include_singles=include_singles, + ) assert_ucc_like_ansatz(self, ansatz, num_spin_orbitals, expect) diff --git a/test/circuit/library/ansatzes/test_succd.py b/test/circuit/library/ansatzes/test_succd.py index 57a3aad6da..eb45aa56cf 100644 --- a/test/circuit/library/ansatzes/test_succd.py +++ b/test/circuit/library/ansatzes/test_succd.py @@ -30,47 +30,79 @@ class TestSUCCD(QiskitNatureTestCase): @unpack @data( - (4, (1, 1), [FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (8, (2, 2), [FermionicOp([('+I-I+I-I', 1j), ('-I+I-I+I', -1j)]), - FermionicOp([('+I-I+II-', 1j), ('-I+I-II+', -1j)]), - FermionicOp([('+I-II+-I', 1j), ('-I+II-+I', -1j)]), - FermionicOp([('+I-II+I-', 1j), ('-I+II-I+', -1j)]), - FermionicOp([('+II-+II-', 1j), ('-II+-II+', -1j)]), - FermionicOp([('+II-I+-I', 1j), ('-II+I-+I', -1j)]), - FermionicOp([('+II-I+I-', 1j), ('-II+I-I+', -1j)]), - FermionicOp([('I+-II+-I', 1j), ('I-+II-+I', -1j)]), - FermionicOp([('I+-II+I-', 1j), ('I-+II-I+', -1j)]), - FermionicOp([('I+I-I+I-', 1j), ('I-I+I-I+', -1j)])]), + (4, (1, 1), [FermionicOp([("+-+-", 1j), ("-+-+", -1j)])]), + ( + 8, + (2, 2), + [ + FermionicOp([("+I-I+I-I", 1j), ("-I+I-I+I", -1j)]), + FermionicOp([("+I-I+II-", 1j), ("-I+I-II+", -1j)]), + FermionicOp([("+I-II+-I", 1j), ("-I+II-+I", -1j)]), + FermionicOp([("+I-II+I-", 1j), ("-I+II-I+", -1j)]), + FermionicOp([("+II-+II-", 1j), ("-II+-II+", -1j)]), + FermionicOp([("+II-I+-I", 1j), ("-II+I-+I", -1j)]), + FermionicOp([("+II-I+I-", 1j), ("-II+I-I+", -1j)]), + FermionicOp([("I+-II+-I", 1j), ("I-+II-+I", -1j)]), + FermionicOp([("I+-II+I-", 1j), ("I-+II-I+", -1j)]), + FermionicOp([("I+I-I+I-", 1j), ("I-I+I-I+", -1j)]), + ], + ), ) def test_succd_ansatz(self, num_spin_orbitals, num_particles, expect): """Tests the SUCCD Ansatz.""" converter = QubitConverter(JordanWignerMapper()) - ansatz = SUCCD(qubit_converter=converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals) + ansatz = SUCCD( + qubit_converter=converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + ) assert_ucc_like_ansatz(self, ansatz, num_spin_orbitals, expect) @unpack @data( - (4, (1, 1), (True, True), [FermionicOp([('+-II', 1j), ('-+II', 1j)]), - FermionicOp([('II+-', 1j), ('II-+', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (4, (1, 1), (True, False), [FermionicOp([('+-II', 1j), ('-+II', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (4, (1, 1), (False, True), [FermionicOp([('II+-', 1j), ('II-+', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), + ( + 4, + (1, 1), + (True, True), + [ + FermionicOp([("+-II", 1j), ("-+II", 1j)]), + FermionicOp([("II+-", 1j), ("II-+", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), + ( + 4, + (1, 1), + (True, False), + [ + FermionicOp([("+-II", 1j), ("-+II", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), + ( + 4, + (1, 1), + (False, True), + [ + FermionicOp([("II+-", 1j), ("II-+", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), ) - def test_succd_ansatz_with_singles(self, num_spin_orbitals, num_particles, include_singles, - expect): + def test_succd_ansatz_with_singles( + self, num_spin_orbitals, num_particles, include_singles, expect + ): """Tests the SUCCD Ansatz with included single excitations.""" converter = QubitConverter(JordanWignerMapper()) - ansatz = SUCCD(qubit_converter=converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - include_singles=include_singles) + ansatz = SUCCD( + qubit_converter=converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + include_singles=include_singles, + ) assert_ucc_like_ansatz(self, ansatz, num_spin_orbitals, expect) diff --git a/test/circuit/library/ansatzes/test_ucc.py b/test/circuit/library/ansatzes/test_ucc.py index 2e8ff889b0..359afc6537 100644 --- a/test/circuit/library/ansatzes/test_ucc.py +++ b/test/circuit/library/ansatzes/test_ucc.py @@ -44,27 +44,43 @@ class TestUCC(QiskitNatureTestCase): @unpack @data( - ('t', 8, (2, 2), [FermionicOp([('++--+I-I', 1j), ('--++-I+I', 1j)]), - FermionicOp([('++--+II-', 1j), ('--++-II+', 1j)]), - FermionicOp([('++--I+-I', 1j), ('--++I-+I', 1j)]), - FermionicOp([('++--I+I-', 1j), ('--++I-I+', 1j)]), - FermionicOp([('+I-I++--', 1j), ('-I+I--++', 1j)]), - FermionicOp([('+II-++--', 1j), ('-II+--++', 1j)]), - FermionicOp([('I+-I++--', 1j), ('I-+I--++', 1j)]), - FermionicOp([('I+I-++--', 1j), ('I-I+--++', 1j)])]), - ('t', 8, (2, 1), [FermionicOp([('++--+-II', 1j), ('--++-+II', 1j)]), - FermionicOp([('++--+I-I', 1j), ('--++-I+I', 1j)]), - FermionicOp([('++--+II-', 1j), ('--++-II+', 1j)])]), - ('q', 8, (2, 2), [FermionicOp([('++--++--', 1j), ('--++--++', -1j)])]), + ( + "t", + 8, + (2, 2), + [ + FermionicOp([("++--+I-I", 1j), ("--++-I+I", 1j)]), + FermionicOp([("++--+II-", 1j), ("--++-II+", 1j)]), + FermionicOp([("++--I+-I", 1j), ("--++I-+I", 1j)]), + FermionicOp([("++--I+I-", 1j), ("--++I-I+", 1j)]), + FermionicOp([("+I-I++--", 1j), ("-I+I--++", 1j)]), + FermionicOp([("+II-++--", 1j), ("-II+--++", 1j)]), + FermionicOp([("I+-I++--", 1j), ("I-+I--++", 1j)]), + FermionicOp([("I+I-++--", 1j), ("I-I+--++", 1j)]), + ], + ), + ( + "t", + 8, + (2, 1), + [ + FermionicOp([("++--+-II", 1j), ("--++-+II", 1j)]), + FermionicOp([("++--+I-I", 1j), ("--++-I+I", 1j)]), + FermionicOp([("++--+II-", 1j), ("--++-II+", 1j)]), + ], + ), + ("q", 8, (2, 2), [FermionicOp([("++--++--", 1j), ("--++--++", -1j)])]), # TODO: add more edge cases? ) def test_ucc_ansatz(self, excitations, num_spin_orbitals, num_particles, expect): """Tests the UCC Ansatz.""" converter = QubitConverter(JordanWignerMapper()) - ansatz = UCC(qubit_converter=converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals, - excitations=excitations) + ansatz = UCC( + qubit_converter=converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + excitations=excitations, + ) assert_ucc_like_ansatz(self, ansatz, num_spin_orbitals, expect) diff --git a/test/circuit/library/ansatzes/test_uccsd.py b/test/circuit/library/ansatzes/test_uccsd.py index 2b9a1cdd04..eef7872a4b 100644 --- a/test/circuit/library/ansatzes/test_uccsd.py +++ b/test/circuit/library/ansatzes/test_uccsd.py @@ -29,62 +29,82 @@ class TestUCCSD(QiskitNatureTestCase): @unpack @data( - (4, (1, 1), [FermionicOp([('+-II', 1j), ('-+II', 1j)]), - FermionicOp([('II+-', 1j), ('II-+', 1j)]), - FermionicOp([('+-+-', 1j), ('-+-+', -1j)])]), - (8, (2, 2), [FermionicOp([('+I-IIIII', 1j), ('-I+IIIII', 1j)]), - FermionicOp([('+II-IIII', 1j), ('-II+IIII', 1j)]), - FermionicOp([('I+-IIIII', 1j), ('I-+IIIII', 1j)]), - FermionicOp([('I+I-IIII', 1j), ('I-I+IIII', 1j)]), - FermionicOp([('IIII+I-I', 1j), ('IIII-I+I', 1j)]), - FermionicOp([('IIII+II-', 1j), ('IIII-II+', 1j)]), - FermionicOp([('IIIII+-I', 1j), ('IIIII-+I', 1j)]), - FermionicOp([('IIIII+I-', 1j), ('IIIII-I+', 1j)]), - FermionicOp([('++--IIII', 1j), ('--++IIII', -1j)]), - FermionicOp([('+I-I+I-I', 1j), ('-I+I-I+I', -1j)]), - FermionicOp([('+I-I+II-', 1j), ('-I+I-II+', -1j)]), - FermionicOp([('+I-II+-I', 1j), ('-I+II-+I', -1j)]), - FermionicOp([('+I-II+I-', 1j), ('-I+II-I+', -1j)]), - FermionicOp([('+II-+I-I', 1j), ('-II+-I+I', -1j)]), - FermionicOp([('+II-+II-', 1j), ('-II+-II+', -1j)]), - FermionicOp([('+II-I+-I', 1j), ('-II+I-+I', -1j)]), - FermionicOp([('+II-I+I-', 1j), ('-II+I-I+', -1j)]), - FermionicOp([('I+-I+I-I', 1j), ('I-+I-I+I', -1j)]), - FermionicOp([('I+-I+II-', 1j), ('I-+I-II+', -1j)]), - FermionicOp([('I+-II+-I', 1j), ('I-+II-+I', -1j)]), - FermionicOp([('I+-II+I-', 1j), ('I-+II-I+', -1j)]), - FermionicOp([('I+I-+I-I', 1j), ('I-I+-I+I', -1j)]), - FermionicOp([('I+I-+II-', 1j), ('I-I+-II+', -1j)]), - FermionicOp([('I+I-I+-I', 1j), ('I-I+I-+I', -1j)]), - FermionicOp([('I+I-I+I-', 1j), ('I-I+I-I+', -1j)]), - FermionicOp([('IIII++--', 1j), ('IIII--++', -1j)])]), - (8, (2, 1), [FermionicOp([('+I-IIIII', 1j), ('-I+IIIII', 1j)]), - FermionicOp([('+II-IIII', 1j), ('-II+IIII', 1j)]), - FermionicOp([('I+-IIIII', 1j), ('I-+IIIII', 1j)]), - FermionicOp([('I+I-IIII', 1j), ('I-I+IIII', 1j)]), - FermionicOp([('IIII+-II', 1j), ('IIII-+II', 1j)]), - FermionicOp([('IIII+I-I', 1j), ('IIII-I+I', 1j)]), - FermionicOp([('IIII+II-', 1j), ('IIII-II+', 1j)]), - FermionicOp([('++--IIII', 1j), ('--++IIII', -1j)]), - FermionicOp([('+I-I+-II', 1j), ('-I+I-+II', -1j)]), - FermionicOp([('+I-I+I-I', 1j), ('-I+I-I+I', -1j)]), - FermionicOp([('+I-I+II-', 1j), ('-I+I-II+', -1j)]), - FermionicOp([('+II-+-II', 1j), ('-II+-+II', -1j)]), - FermionicOp([('+II-+I-I', 1j), ('-II+-I+I', -1j)]), - FermionicOp([('+II-+II-', 1j), ('-II+-II+', -1j)]), - FermionicOp([('I+-I+-II', 1j), ('I-+I-+II', -1j)]), - FermionicOp([('I+-I+I-I', 1j), ('I-+I-I+I', -1j)]), - FermionicOp([('I+-I+II-', 1j), ('I-+I-II+', -1j)]), - FermionicOp([('I+I-+-II', 1j), ('I-I+-+II', -1j)]), - FermionicOp([('I+I-+I-I', 1j), ('I-I+-I+I', -1j)]), - FermionicOp([('I+I-+II-', 1j), ('I-I+-II+', -1j)])]), + ( + 4, + (1, 1), + [ + FermionicOp([("+-II", 1j), ("-+II", 1j)]), + FermionicOp([("II+-", 1j), ("II-+", 1j)]), + FermionicOp([("+-+-", 1j), ("-+-+", -1j)]), + ], + ), + ( + 8, + (2, 2), + [ + FermionicOp([("+I-IIIII", 1j), ("-I+IIIII", 1j)]), + FermionicOp([("+II-IIII", 1j), ("-II+IIII", 1j)]), + FermionicOp([("I+-IIIII", 1j), ("I-+IIIII", 1j)]), + FermionicOp([("I+I-IIII", 1j), ("I-I+IIII", 1j)]), + FermionicOp([("IIII+I-I", 1j), ("IIII-I+I", 1j)]), + FermionicOp([("IIII+II-", 1j), ("IIII-II+", 1j)]), + FermionicOp([("IIIII+-I", 1j), ("IIIII-+I", 1j)]), + FermionicOp([("IIIII+I-", 1j), ("IIIII-I+", 1j)]), + FermionicOp([("++--IIII", 1j), ("--++IIII", -1j)]), + FermionicOp([("+I-I+I-I", 1j), ("-I+I-I+I", -1j)]), + FermionicOp([("+I-I+II-", 1j), ("-I+I-II+", -1j)]), + FermionicOp([("+I-II+-I", 1j), ("-I+II-+I", -1j)]), + FermionicOp([("+I-II+I-", 1j), ("-I+II-I+", -1j)]), + FermionicOp([("+II-+I-I", 1j), ("-II+-I+I", -1j)]), + FermionicOp([("+II-+II-", 1j), ("-II+-II+", -1j)]), + FermionicOp([("+II-I+-I", 1j), ("-II+I-+I", -1j)]), + FermionicOp([("+II-I+I-", 1j), ("-II+I-I+", -1j)]), + FermionicOp([("I+-I+I-I", 1j), ("I-+I-I+I", -1j)]), + FermionicOp([("I+-I+II-", 1j), ("I-+I-II+", -1j)]), + FermionicOp([("I+-II+-I", 1j), ("I-+II-+I", -1j)]), + FermionicOp([("I+-II+I-", 1j), ("I-+II-I+", -1j)]), + FermionicOp([("I+I-+I-I", 1j), ("I-I+-I+I", -1j)]), + FermionicOp([("I+I-+II-", 1j), ("I-I+-II+", -1j)]), + FermionicOp([("I+I-I+-I", 1j), ("I-I+I-+I", -1j)]), + FermionicOp([("I+I-I+I-", 1j), ("I-I+I-I+", -1j)]), + FermionicOp([("IIII++--", 1j), ("IIII--++", -1j)]), + ], + ), + ( + 8, + (2, 1), + [ + FermionicOp([("+I-IIIII", 1j), ("-I+IIIII", 1j)]), + FermionicOp([("+II-IIII", 1j), ("-II+IIII", 1j)]), + FermionicOp([("I+-IIIII", 1j), ("I-+IIIII", 1j)]), + FermionicOp([("I+I-IIII", 1j), ("I-I+IIII", 1j)]), + FermionicOp([("IIII+-II", 1j), ("IIII-+II", 1j)]), + FermionicOp([("IIII+I-I", 1j), ("IIII-I+I", 1j)]), + FermionicOp([("IIII+II-", 1j), ("IIII-II+", 1j)]), + FermionicOp([("++--IIII", 1j), ("--++IIII", -1j)]), + FermionicOp([("+I-I+-II", 1j), ("-I+I-+II", -1j)]), + FermionicOp([("+I-I+I-I", 1j), ("-I+I-I+I", -1j)]), + FermionicOp([("+I-I+II-", 1j), ("-I+I-II+", -1j)]), + FermionicOp([("+II-+-II", 1j), ("-II+-+II", -1j)]), + FermionicOp([("+II-+I-I", 1j), ("-II+-I+I", -1j)]), + FermionicOp([("+II-+II-", 1j), ("-II+-II+", -1j)]), + FermionicOp([("I+-I+-II", 1j), ("I-+I-+II", -1j)]), + FermionicOp([("I+-I+I-I", 1j), ("I-+I-I+I", -1j)]), + FermionicOp([("I+-I+II-", 1j), ("I-+I-II+", -1j)]), + FermionicOp([("I+I-+-II", 1j), ("I-I+-+II", -1j)]), + FermionicOp([("I+I-+I-I", 1j), ("I-I+-I+I", -1j)]), + FermionicOp([("I+I-+II-", 1j), ("I-I+-II+", -1j)]), + ], + ), ) def test_uccsd_ansatz(self, num_spin_orbitals, num_particles, expect): """Tests the UCCSD Ansatz.""" converter = QubitConverter(JordanWignerMapper()) - ansatz = UCCSD(qubit_converter=converter, - num_particles=num_particles, - num_spin_orbitals=num_spin_orbitals) + ansatz = UCCSD( + qubit_converter=converter, + num_particles=num_particles, + num_spin_orbitals=num_spin_orbitals, + ) assert_ucc_like_ansatz(self, ansatz, num_spin_orbitals, expect) diff --git a/test/circuit/library/ansatzes/test_uvcc.py b/test/circuit/library/ansatzes/test_uvcc.py index ea87c2d0c2..e5db0a0ee7 100644 --- a/test/circuit/library/ansatzes/test_uvcc.py +++ b/test/circuit/library/ansatzes/test_uvcc.py @@ -26,8 +26,9 @@ from qiskit_nature.mappers.second_quantization import DirectMapper from qiskit_nature.operators.second_quantization import VibrationalOp from qiskit_nature.converters.second_quantization import QubitConverter -from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder \ - import _create_labels +from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder import ( + _create_labels, +) def assert_ucc_like_ansatz(test_case, ansatz, num_modals, expected_ops): @@ -49,17 +50,23 @@ class TestUVCC(QiskitNatureTestCase): @unpack @data( - ('s', [2], [VibrationalOp([('+-', 1j), ('-+', -1j)], 1, 2)]), - ('s', [2, 2], [VibrationalOp([('+-II', 1j), ('-+II', -1j)], 2, 2), - VibrationalOp([('II+-', 1j), ('II-+', -1j)], 2, 2)]), + ("s", [2], [VibrationalOp([("+-", 1j), ("-+", -1j)], 1, 2)]), + ( + "s", + [2, 2], + [ + VibrationalOp([("+-II", 1j), ("-+II", -1j)], 2, 2), + VibrationalOp([("II+-", 1j), ("II-+", -1j)], 2, 2), + ], + ), ) def test_ucc_ansatz(self, excitations, num_modals, expect): """Tests the UVCC Ansatz.""" converter = QubitConverter(DirectMapper()) - ansatz = UVCC(qubit_converter=converter, - num_modals=num_modals, - excitations=excitations) + ansatz = UVCC( + qubit_converter=converter, num_modals=num_modals, excitations=excitations + ) assert_ucc_like_ansatz(self, ansatz, num_modals, expect) @@ -73,28 +80,34 @@ def setUp(self): self.reference_energy = 592.5346633819712 def test_uvcc_vscf(self): - """ uvcc vscf test """ - - co2_2modes_2modals_2body = [[[[[0, 0, 0]], 320.8467332810141], - [[[0, 1, 1]], 1760.878530705873], - [[[1, 0, 0]], 342.8218290247543], - [[[1, 1, 1]], 1032.396323618631]], - [[[[0, 0, 0], [1, 0, 0]], -57.34003649795117], - [[[0, 0, 1], [1, 0, 0]], -56.33205925807966], - [[[0, 1, 0], [1, 0, 0]], -56.33205925807966], - [[[0, 1, 1], [1, 0, 0]], -60.13032761856809], - [[[0, 0, 0], [1, 0, 1]], -65.09576309934431], - [[[0, 0, 1], [1, 0, 1]], -62.2363839133389], - [[[0, 1, 0], [1, 0, 1]], -62.2363839133389], - [[[0, 1, 1], [1, 0, 1]], -121.5533969109279], - [[[0, 0, 0], [1, 1, 0]], -65.09576309934431], - [[[0, 0, 1], [1, 1, 0]], -62.2363839133389], - [[[0, 1, 0], [1, 1, 0]], -62.2363839133389], - [[[0, 1, 1], [1, 1, 0]], -121.5533969109279], - [[[0, 0, 0], [1, 1, 1]], -170.744837386338], - [[[0, 0, 1], [1, 1, 1]], -167.7433236025723], - [[[0, 1, 0], [1, 1, 1]], -167.7433236025723], - [[[0, 1, 1], [1, 1, 1]], -179.0536532281924]]] + """uvcc vscf test""" + + co2_2modes_2modals_2body = [ + [ + [[[0, 0, 0]], 320.8467332810141], + [[[0, 1, 1]], 1760.878530705873], + [[[1, 0, 0]], 342.8218290247543], + [[[1, 1, 1]], 1032.396323618631], + ], + [ + [[[0, 0, 0], [1, 0, 0]], -57.34003649795117], + [[[0, 0, 1], [1, 0, 0]], -56.33205925807966], + [[[0, 1, 0], [1, 0, 0]], -56.33205925807966], + [[[0, 1, 1], [1, 0, 0]], -60.13032761856809], + [[[0, 0, 0], [1, 0, 1]], -65.09576309934431], + [[[0, 0, 1], [1, 0, 1]], -62.2363839133389], + [[[0, 1, 0], [1, 0, 1]], -62.2363839133389], + [[[0, 1, 1], [1, 0, 1]], -121.5533969109279], + [[[0, 0, 0], [1, 1, 0]], -65.09576309934431], + [[[0, 0, 1], [1, 1, 0]], -62.2363839133389], + [[[0, 1, 0], [1, 1, 0]], -62.2363839133389], + [[[0, 1, 1], [1, 1, 0]], -121.5533969109279], + [[[0, 0, 0], [1, 1, 1]], -170.744837386338], + [[[0, 0, 1], [1, 1, 1]], -167.7433236025723], + [[[0, 1, 0], [1, 1, 1]], -167.7433236025723], + [[[0, 1, 1], [1, 1, 1]], -179.0536532281924], + ], + ] num_modes = 2 num_modals = [2, 2] @@ -107,10 +120,13 @@ def test_uvcc_vscf(self): init_state = VSCF(num_modals) - uvcc_ansatz = UVCC(converter, num_modals, 'sd', initial_state=init_state) + uvcc_ansatz = UVCC(converter, num_modals, "sd", initial_state=init_state) - q_instance = QuantumInstance(BasicAer.get_backend('statevector_simulator'), - seed_transpiler=90, seed_simulator=12) + q_instance = QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + seed_transpiler=90, + seed_simulator=12, + ) optimizer = COBYLA(maxiter=1000) algo = VQE(uvcc_ansatz, optimizer=optimizer, quantum_instance=q_instance) @@ -121,5 +137,5 @@ def test_uvcc_vscf(self): self.assertAlmostEqual(energy, self.reference_energy, places=4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/circuit/library/ansatzes/utils/test_fermionic_excitation_generator.py b/test/circuit/library/ansatzes/utils/test_fermionic_excitation_generator.py index f9418ae23d..e4e9b244a7 100644 --- a/test/circuit/library/ansatzes/utils/test_fermionic_excitation_generator.py +++ b/test/circuit/library/ansatzes/utils/test_fermionic_excitation_generator.py @@ -16,8 +16,9 @@ from ddt import data, ddt, unpack -from qiskit_nature.circuit.library.ansatzes.utils.fermionic_excitation_generator import \ - generate_fermionic_excitations +from qiskit_nature.circuit.library.ansatzes.utils.fermionic_excitation_generator import ( + generate_fermionic_excitations, +) @ddt @@ -33,21 +34,58 @@ class TestFermionicExcitationGenerator(QiskitNatureTestCase): (1, 6, [3, 3], []), (2, 4, [1, 1], [((0, 2), (1, 3))]), (2, 4, [2, 2], []), - (2, 6, [1, 1], [((0, 3), (1, 4)), ((0, 3), (1, 5)), ((0, 3), (2, 4)), ((0, 3), (2, 5))]), - (2, 6, [2, 2], [((0, 3), (2, 5)), ((0, 4), (2, 5)), ((1, 3), (2, 5)), ((1, 4), (2, 5))]), + ( + 2, + 6, + [1, 1], + [((0, 3), (1, 4)), ((0, 3), (1, 5)), ((0, 3), (2, 4)), ((0, 3), (2, 5))], + ), + ( + 2, + 6, + [2, 2], + [((0, 3), (2, 5)), ((0, 4), (2, 5)), ((1, 3), (2, 5)), ((1, 4), (2, 5))], + ), (2, 6, [3, 3], []), - (2, 8, [2, 2], [((0, 1), (2, 3)), ((0, 4), (2, 6)), ((0, 4), (2, 7)), ((0, 5), (2, 6)), - ((0, 5), (2, 7)), ((0, 4), (3, 6)), ((0, 4), (3, 7)), ((0, 5), (3, 6)), - ((0, 5), (3, 7)), ((1, 4), (2, 6)), ((1, 4), (2, 7)), ((1, 5), (2, 6)), - ((1, 5), (2, 7)), ((1, 4), (3, 6)), ((1, 4), (3, 7)), ((1, 5), (3, 6)), - ((1, 5), (3, 7)), ((4, 5), (6, 7))]), - (3, 8, [2, 1], [((0, 1, 4), (2, 3, 5)), ((0, 1, 4), (2, 3, 6)), ((0, 1, 4), (2, 3, 7))]), + ( + 2, + 8, + [2, 2], + [ + ((0, 1), (2, 3)), + ((0, 4), (2, 6)), + ((0, 4), (2, 7)), + ((0, 5), (2, 6)), + ((0, 5), (2, 7)), + ((0, 4), (3, 6)), + ((0, 4), (3, 7)), + ((0, 5), (3, 6)), + ((0, 5), (3, 7)), + ((1, 4), (2, 6)), + ((1, 4), (2, 7)), + ((1, 5), (2, 6)), + ((1, 5), (2, 7)), + ((1, 4), (3, 6)), + ((1, 4), (3, 7)), + ((1, 5), (3, 6)), + ((1, 5), (3, 7)), + ((4, 5), (6, 7)), + ], + ), + ( + 3, + 8, + [2, 1], + [((0, 1, 4), (2, 3, 5)), ((0, 1, 4), (2, 3, 6)), ((0, 1, 4), (2, 3, 7))], + ), ) - def test_generate_excitations(self, num_excitations, num_spin_orbitals, num_particles, expect): + def test_generate_excitations( + self, num_excitations, num_spin_orbitals, num_particles, expect + ): """Test standard input arguments.""" - excitations = generate_fermionic_excitations(num_excitations, - num_spin_orbitals, - num_particles) + excitations = generate_fermionic_excitations( + num_excitations, num_spin_orbitals, num_particles + ) self.assertEqual(excitations, expect) @unpack @@ -55,19 +93,48 @@ def test_generate_excitations(self, num_excitations, num_spin_orbitals, num_part (1, 4, [1, 1], 1, [((0,), (1,)), ((2,), (3,))]), (2, 4, [1, 1], 1, [((0, 2), (1, 3))]), (1, 6, [1, 1], 1, [((0,), (1,)), ((0,), (2,)), ((3,), (4,)), ((3,), (5,))]), - (2, 6, [1, 1], 1, [((0, 3), (1, 4)), ((0, 3), (1, 5)), ((0, 3), (2, 4)), ((0, 3), (2, 5))]), - (2, 8, [2, 2], 1, [((0, 4), (2, 6)), ((0, 4), (2, 7)), ((0, 5), (2, 6)), ((0, 5), (2, 7)), - ((0, 4), (3, 6)), ((0, 4), (3, 7)), ((0, 5), (3, 6)), ((0, 5), (3, 7)), - ((1, 4), (2, 6)), ((1, 4), (2, 7)), ((1, 5), (2, 6)), ((1, 5), (2, 7)), - ((1, 4), (3, 6)), ((1, 4), (3, 7)), ((1, 5), (3, 6)), ((1, 5), (3, 7))]), + ( + 2, + 6, + [1, 1], + 1, + [((0, 3), (1, 4)), ((0, 3), (1, 5)), ((0, 3), (2, 4)), ((0, 3), (2, 5))], + ), + ( + 2, + 8, + [2, 2], + 1, + [ + ((0, 4), (2, 6)), + ((0, 4), (2, 7)), + ((0, 5), (2, 6)), + ((0, 5), (2, 7)), + ((0, 4), (3, 6)), + ((0, 4), (3, 7)), + ((0, 5), (3, 6)), + ((0, 5), (3, 7)), + ((1, 4), (2, 6)), + ((1, 4), (2, 7)), + ((1, 5), (2, 6)), + ((1, 5), (2, 7)), + ((1, 4), (3, 6)), + ((1, 4), (3, 7)), + ((1, 5), (3, 6)), + ((1, 5), (3, 7)), + ], + ), ) - def test_max_spin_excitation(self, num_excitations, num_spin_orbitals, num_particles, - max_spin, expect): + def test_max_spin_excitation( + self, num_excitations, num_spin_orbitals, num_particles, max_spin, expect + ): """Test limiting the maximum number of excitations per spin species.""" - excitations = generate_fermionic_excitations(num_excitations, - num_spin_orbitals, - num_particles, - max_spin_excitation=max_spin) + excitations = generate_fermionic_excitations( + num_excitations, + num_spin_orbitals, + num_particles, + max_spin_excitation=max_spin, + ) self.assertEqual(excitations, expect) @unpack @@ -76,12 +143,13 @@ def test_max_spin_excitation(self, num_excitations, num_spin_orbitals, num_parti (1, 6, [1, 1], [((0,), (1,)), ((0,), (2,))]), (2, 8, [2, 2], [((0, 1), (2, 3))]), ) - def test_pure_alpha_excitation(self, num_excitations, num_spin_orbitals, num_particles, expect): + def test_pure_alpha_excitation( + self, num_excitations, num_spin_orbitals, num_particles, expect + ): """Test disabling beta-spin excitations.""" - excitations = generate_fermionic_excitations(num_excitations, - num_spin_orbitals, - num_particles, - beta_spin=False) + excitations = generate_fermionic_excitations( + num_excitations, num_spin_orbitals, num_particles, beta_spin=False + ) self.assertEqual(excitations, expect) @unpack @@ -90,10 +158,11 @@ def test_pure_alpha_excitation(self, num_excitations, num_spin_orbitals, num_par (1, 6, [1, 1], [((3,), (4,)), ((3,), (5,))]), (2, 8, [2, 2], [((4, 5), (6, 7))]), ) - def test_pure_beta_excitation(self, num_excitations, num_spin_orbitals, num_particles, expect): + def test_pure_beta_excitation( + self, num_excitations, num_spin_orbitals, num_particles, expect + ): """Test disabling alpha-spin excitations.""" - excitations = generate_fermionic_excitations(num_excitations, - num_spin_orbitals, - num_particles, - alpha_spin=False) + excitations = generate_fermionic_excitations( + num_excitations, num_spin_orbitals, num_particles, alpha_spin=False + ) self.assertEqual(excitations, expect) diff --git a/test/circuit/library/ansatzes/utils/test_vibration_excitation_generator.py b/test/circuit/library/ansatzes/utils/test_vibration_excitation_generator.py index 8956ed982c..3111540e0b 100644 --- a/test/circuit/library/ansatzes/utils/test_vibration_excitation_generator.py +++ b/test/circuit/library/ansatzes/utils/test_vibration_excitation_generator.py @@ -16,8 +16,9 @@ from ddt import data, ddt, unpack -from qiskit_nature.circuit.library.ansatzes.utils.vibration_excitation_generator import \ - generate_vibration_excitations +from qiskit_nature.circuit.library.ansatzes.utils.vibration_excitation_generator import ( + generate_vibration_excitations, +) @ddt @@ -32,18 +33,30 @@ class TestVibrationExcitationGenerator(QiskitNatureTestCase): (1, [2, 2], [((0,), (1,)), ((2,), (3,))]), (2, [2, 2], [((0, 2), (1, 3))]), (1, [3, 3], [((0,), (1,)), ((0,), (2,)), ((3,), (4,)), ((3,), (5,))]), - (2, [3, 3], [((0, 3), (1, 4)), ((0, 3), (1, 5)), ((0, 3), (2, 4)), ((0, 3), (2, 5))]), + ( + 2, + [3, 3], + [((0, 3), (1, 4)), ((0, 3), (1, 5)), ((0, 3), (2, 4)), ((0, 3), (2, 5))], + ), (3, [3, 3], []), (2, [2, 2, 2], [((0, 2), (1, 3)), ((0, 4), (1, 5)), ((2, 4), (3, 5))]), (3, [2, 2, 2], [((0, 2, 4), (1, 3, 5))]), (4, [2, 2, 2], []), (2, [2, 3], [((0, 2), (1, 3)), ((0, 2), (1, 4))]), - (2, [2, 3, 2], [((0, 2), (1, 3)), ((0, 2), (1, 4)), ((0, 5), (1, 6)), - ((2, 5), (3, 6)), ((2, 5), (4, 6))]), + ( + 2, + [2, 3, 2], + [ + ((0, 2), (1, 3)), + ((0, 2), (1, 4)), + ((0, 5), (1, 6)), + ((2, 5), (3, 6)), + ((2, 5), (4, 6)), + ], + ), (3, [2, 3, 2], [((0, 2, 5), (1, 3, 6)), ((0, 2, 5), (1, 4, 6))]), ) def test_generate_excitations(self, num_excitations, num_modals, expect): """Test standard input arguments.""" - excitations = generate_vibration_excitations(num_excitations, - num_modals) + excitations = generate_vibration_excitations(num_excitations, num_modals) self.assertEqual(excitations, expect) diff --git a/test/circuit/library/initial_states/test_hartree_fock.py b/test/circuit/library/initial_states/test_hartree_fock.py index 9ebb73d823..77ca9dd677 100644 --- a/test/circuit/library/initial_states/test_hartree_fock.py +++ b/test/circuit/library/initial_states/test_hartree_fock.py @@ -20,14 +20,19 @@ from qiskit.opflow.primitive_ops.tapered_pauli_sum_op import Z2Symmetries from qiskit.quantum_info.operators.symplectic import Pauli from qiskit_nature.circuit.library import HartreeFock -from qiskit_nature.circuit.library.initial_states.hartree_fock import hartree_fock_bitstring +from qiskit_nature.circuit.library.initial_states.hartree_fock import ( + hartree_fock_bitstring, +) from qiskit_nature.mappers.second_quantization import ( - BravyiKitaevMapper, JordanWignerMapper, ParityMapper) + BravyiKitaevMapper, + JordanWignerMapper, + ParityMapper, +) from qiskit_nature.converters.second_quantization import QubitConverter class TestHartreeFock(QiskitNatureTestCase): - """ Initial State HartreeFock tests """ + """Initial State HartreeFock tests""" def test_bitstring(self): """Simple test for the bitstring function.""" @@ -37,37 +42,37 @@ def test_bitstring(self): def test_bitstring_invalid_input(self): """Test passing invalid input raises.""" - with self.subTest('too many particles'): + with self.subTest("too many particles"): with self.assertRaises(ValueError): _ = hartree_fock_bitstring(4, (3, 3)) - with self.subTest('too few orbitals'): + with self.subTest("too few orbitals"): with self.assertRaises(ValueError): _ = hartree_fock_bitstring(-1, (2, 2)) def test_qubits_4_jw_h2(self): - """ qubits 4 jw h2 test """ + """qubits 4 jw h2 test""" state = HartreeFock(4, (1, 1), QubitConverter(JordanWignerMapper())) ref = QuantumCircuit(4) ref.x([0, 2]) self.assertEqual(state, ref) def test_qubits_4_py_h2(self): - """ qubits 4 py h2 test """ + """qubits 4 py h2 test""" state = HartreeFock(4, (1, 1), QubitConverter(ParityMapper())) ref = QuantumCircuit(4) ref.x([0, 1]) self.assertEqual(state, ref) def test_qubits_4_bk_h2(self): - """ qubits 4 bk h2 test """ + """qubits 4 bk h2 test""" state = HartreeFock(4, (1, 1), QubitConverter(BravyiKitaevMapper())) ref = QuantumCircuit(4) ref.x([0, 1, 2]) self.assertEqual(state, ref) def test_qubits_2_py_h2(self): - """ qubits 2 py h2 test """ + """qubits 2 py h2 test""" num_particles = (1, 1) converter = QubitConverter(ParityMapper(), two_qubit_reduction=True) converter.force_match(num_particles=num_particles) @@ -77,12 +82,12 @@ def test_qubits_2_py_h2(self): self.assertEqual(state, ref) def test_qubits_6_py_lih(self): - """ qubits 6 py lih test """ + """qubits 6 py lih test""" num_particles = (1, 1) converter = QubitConverter(ParityMapper(), two_qubit_reduction=True) z2symmetries = Z2Symmetries( - symmetries=[Pauli('ZIZIZIZI'), Pauli('ZZIIZZII')], - sq_paulis=[Pauli('IIIIIIXI'), Pauli('IIIIIXII')], + symmetries=[Pauli("ZIZIZIZI"), Pauli("ZZIIZZII")], + sq_paulis=[Pauli("IIIIIIXI"), Pauli("IIIIIXII")], sq_list=[2, 3], tapering_values=[1, 1], ) @@ -93,5 +98,5 @@ def test_qubits_6_py_lih(self): self.assertEqual(state, ref) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/circuit/library/initial_states/test_vscf.py b/test/circuit/library/initial_states/test_vscf.py index a8c22ac500..4fe175ce81 100644 --- a/test/circuit/library/initial_states/test_vscf.py +++ b/test/circuit/library/initial_states/test_vscf.py @@ -22,12 +22,14 @@ class TestVSCF(QiskitNatureTestCase): - """ Initial State vscf tests """ + """Initial State vscf tests""" def test_bitstring(self): """Test the vscf_bitstring method.""" bitstr = vscf_bitstring([2, 2]) - self.assertTrue(all(bitstr == np.array([True, False, True, False]))) # big endian + self.assertTrue( + all(bitstr == np.array([True, False, True, False])) + ) # big endian def test_qubits_4(self): """Test 2 modes 2 modals.""" @@ -48,5 +50,5 @@ def test_qubits_5(self): self.assertEqual(ref, vscf) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/fcidumpd/test_driver_fcidump.py b/test/drivers/fcidumpd/test_driver_fcidump.py index b6769dad78..4b30ae845c 100644 --- a/test/drivers/fcidumpd/test_driver_fcidump.py +++ b/test/drivers/fcidumpd/test_driver_fcidump.py @@ -41,87 +41,130 @@ def __init__(self): @abstractmethod def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None): - """ assert Almost Equal """ - raise Exception('Abstract method') + """assert Almost Equal""" + raise Exception("Abstract method") @abstractmethod def assertEqual(self, first, second, msg=None): - """ assert equal """ - raise Exception('Abstract method') + """assert equal""" + raise Exception("Abstract method") @abstractmethod def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None): - """ assert Sequence Equal """ - raise Exception('Abstract method') + """assert Sequence Equal""" + raise Exception("Abstract method") def test_driver_inactive_energy(self): - """ driver inactive energy test """ - self.log.debug('QMolecule inactive energy is {}'.format( - self.qmolecule.nuclear_repulsion_energy)) - self.assertAlmostEqual(self.qmolecule.nuclear_repulsion_energy, - self.nuclear_repulsion_energy, places=3) + """driver inactive energy test""" + self.log.debug( + "QMolecule inactive energy is {}".format( + self.qmolecule.nuclear_repulsion_energy + ) + ) + self.assertAlmostEqual( + self.qmolecule.nuclear_repulsion_energy, + self.nuclear_repulsion_energy, + places=3, + ) def test_driver_num_molecular_orbitals(self): - """ driver num orbitals test """ - self.log.debug('QMolecule Number of orbitals is {}'.format( - self.qmolecule.num_molecular_orbitals)) - self.assertEqual(self.qmolecule.num_molecular_orbitals, self.num_molecular_orbitals) + """driver num orbitals test""" + self.log.debug( + "QMolecule Number of orbitals is {}".format( + self.qmolecule.num_molecular_orbitals + ) + ) + self.assertEqual( + self.qmolecule.num_molecular_orbitals, self.num_molecular_orbitals + ) def test_driver_num_alpha(self): - """ driver num alpha test """ - self.log.debug('QMolecule Number of alpha electrons is {}'.format(self.qmolecule.num_alpha)) + """driver num alpha test""" + self.log.debug( + "QMolecule Number of alpha electrons is {}".format(self.qmolecule.num_alpha) + ) self.assertEqual(self.qmolecule.num_alpha, self.num_alpha) def test_driver_num_beta(self): - """ driver num beta test """ - self.log.debug('QMolecule Number of beta electrons is {}'.format(self.qmolecule.num_beta)) + """driver num beta test""" + self.log.debug( + "QMolecule Number of beta electrons is {}".format(self.qmolecule.num_beta) + ) self.assertEqual(self.qmolecule.num_beta, self.num_beta) def test_driver_mo_onee_ints(self): - """ driver alpha mo onee ints test """ - self.log.debug('QMolecule MO alpha one electron integrals are {}'.format( - self.qmolecule.mo_onee_ints)) + """driver alpha mo onee ints test""" + self.log.debug( + "QMolecule MO alpha one electron integrals are {}".format( + self.qmolecule.mo_onee_ints + ) + ) self.assertEqual(self.qmolecule.mo_onee_ints.shape, self.mo_onee.shape) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_onee_ints), - np.absolute(self.mo_onee), decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_onee_ints), + np.absolute(self.mo_onee), + decimal=4, + ) def test_driver_mo_onee_b_ints(self): - """ driver beta mo onee ints test """ + """driver beta mo onee ints test""" if self.mo_onee_b is None: return - self.log.debug('QMolecule MO beta one electron integrals are {}'.format( - self.qmolecule.mo_onee_ints_b)) + self.log.debug( + "QMolecule MO beta one electron integrals are {}".format( + self.qmolecule.mo_onee_ints_b + ) + ) self.assertEqual(self.qmolecule.mo_onee_ints_b.shape, self.mo_onee_b.shape) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_onee_ints_b), - np.absolute(self.mo_onee_b), decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_onee_ints_b), + np.absolute(self.mo_onee_b), + decimal=4, + ) def test_driver_mo_eri_ints(self): - """ driver alpha-alpha mo eri ints test """ - self.log.debug('QMolecule MO alpha-alpha two electron integrals are {}'.format( - self.qmolecule.mo_eri_ints)) + """driver alpha-alpha mo eri ints test""" + self.log.debug( + "QMolecule MO alpha-alpha two electron integrals are {}".format( + self.qmolecule.mo_eri_ints + ) + ) self.assertEqual(self.qmolecule.mo_eri_ints.shape, self.mo_eri.shape) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_eri_ints), - np.absolute(self.mo_eri), decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_eri_ints), np.absolute(self.mo_eri), decimal=4 + ) def test_driver_mo_eri_ints_ba(self): - """ driver beta-alpha mo eri ints test """ + """driver beta-alpha mo eri ints test""" if self.mo_eri_ba is None: return - self.log.debug('QMolecule MO beta-alpha two electron integrals are {}'.format( - self.qmolecule.mo_eri_ints_ba)) + self.log.debug( + "QMolecule MO beta-alpha two electron integrals are {}".format( + self.qmolecule.mo_eri_ints_ba + ) + ) self.assertEqual(self.qmolecule.mo_eri_ints_ba.shape, self.mo_eri_ba.shape) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_eri_ints_ba), - np.absolute(self.mo_eri_ba), decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_eri_ints_ba), + np.absolute(self.mo_eri_ba), + decimal=4, + ) def test_driver_mo_eri_ints_bb(self): - """ driver beta-beta mo eri ints test """ + """driver beta-beta mo eri ints test""" if self.mo_eri_bb is None: return - self.log.debug('QMolecule MO beta-beta two electron integrals are {}'.format( - self.qmolecule.mo_eri_ints_bb)) + self.log.debug( + "QMolecule MO beta-beta two electron integrals are {}".format( + self.qmolecule.mo_eri_ints_bb + ) + ) self.assertEqual(self.qmolecule.mo_eri_ints_bb.shape, self.mo_eri_bb.shape) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_eri_ints_bb), - np.absolute(self.mo_eri_bb), decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_eri_ints_bb), + np.absolute(self.mo_eri_bb), + decimal=4, + ) class TestDriverFCIDumpH2(QiskitNatureTestCase, BaseTestDriverFCIDump): @@ -135,14 +178,17 @@ def setUp(self): self.num_beta = 1 self.mo_onee = np.array([[1.2563, 0.0], [0.0, 0.4719]]) self.mo_onee_b = None - self.mo_eri = np.array([[[[0.6757, 0.0], [0.0, 0.6646]], - [[0.0, 0.1809], [0.1809, 0.0]]], - [[[0.0, 0.1809], [0.1809, 0.0]], - [[0.6646, 0.0], [0.0, 0.6986]]]]) + self.mo_eri = np.array( + [ + [[[0.6757, 0.0], [0.0, 0.6646]], [[0.0, 0.1809], [0.1809, 0.0]]], + [[[0.0, 0.1809], [0.1809, 0.0]], [[0.6646, 0.0], [0.0, 0.6986]]], + ] + ) self.mo_eri_ba = None self.mo_eri_bb = None - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_h2.fcidump', - 'drivers/fcidumpd')) + driver = FCIDumpDriver( + self.get_resource_path("test_driver_fcidump_h2.fcidump", "drivers/fcidumpd") + ) self.qmolecule = driver.run() @@ -155,15 +201,19 @@ def setUp(self): self.num_molecular_orbitals = 6 self.num_alpha = 2 self.num_beta = 2 - loaded = np.load(self.get_resource_path('test_driver_fcidump_lih.npz', - 'drivers/fcidumpd')) - self.mo_onee = loaded['mo_onee'] + loaded = np.load( + self.get_resource_path("test_driver_fcidump_lih.npz", "drivers/fcidumpd") + ) + self.mo_onee = loaded["mo_onee"] self.mo_onee_b = None - self.mo_eri = loaded['mo_eri'] + self.mo_eri = loaded["mo_eri"] self.mo_eri_ba = None self.mo_eri_bb = None - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_lih.fcidump', - 'drivers/fcidumpd')) + driver = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_lih.fcidump", "drivers/fcidumpd" + ) + ) self.qmolecule = driver.run() @@ -176,17 +226,19 @@ def setUp(self): self.num_molecular_orbitals = 6 self.num_alpha = 5 self.num_beta = 4 - loaded = np.load(self.get_resource_path('test_driver_fcidump_oh.npz', - 'drivers/fcidumpd')) - self.mo_onee = loaded['mo_onee'] - self.mo_onee_b = loaded['mo_onee_b'] - self.mo_eri = loaded['mo_eri'] - self.mo_eri_ba = loaded['mo_eri_ba'] - self.mo_eri_bb = loaded['mo_eri_bb'] - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_oh.fcidump', - 'drivers/fcidumpd')) + loaded = np.load( + self.get_resource_path("test_driver_fcidump_oh.npz", "drivers/fcidumpd") + ) + self.mo_onee = loaded["mo_onee"] + self.mo_onee_b = loaded["mo_onee_b"] + self.mo_eri = loaded["mo_eri"] + self.mo_eri_ba = loaded["mo_eri_ba"] + self.mo_eri_bb = loaded["mo_eri_bb"] + driver = FCIDumpDriver( + self.get_resource_path("test_driver_fcidump_oh.fcidump", "drivers/fcidumpd") + ) self.qmolecule = driver.run() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/fcidumpd/test_driver_fcidump_dumper.py b/test/drivers/fcidumpd/test_driver_fcidump_dumper.py index 3916e814fa..9c1b885bb0 100644 --- a/test/drivers/fcidumpd/test_driver_fcidump_dumper.py +++ b/test/drivers/fcidumpd/test_driver_fcidump_dumper.py @@ -38,60 +38,66 @@ def __init__(self): @abstractmethod def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None): - """ assert Almost Equal """ - raise Exception('Abstract method') + """assert Almost Equal""" + raise Exception("Abstract method") @abstractmethod def assertEqual(self, first, second, msg=None): - """ assert equal """ - raise Exception('Abstract method') + """assert equal""" + raise Exception("Abstract method") @abstractmethod def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None): - """ assert Sequence Equal """ - raise Exception('Abstract method') + """assert Sequence Equal""" + raise Exception("Abstract method") def test_dumped_inactive_energy(self): - """ dumped inactive energy test """ - self.log.debug('Dumped inactive energy is {:g}'.format(self.dumped['ECORE'])) - self.assertAlmostEqual(self.dumped['ECORE'], self.core_energy, places=3) + """dumped inactive energy test""" + self.log.debug("Dumped inactive energy is {:g}".format(self.dumped["ECORE"])) + self.assertAlmostEqual(self.dumped["ECORE"], self.core_energy, places=3) def test_dumped_num_molecular_orbitals(self): - """ dumped number of orbitals test """ - self.log.debug('Dumped number of orbitals is {:d}'.format(self.dumped['NORB'])) - self.assertEqual(self.dumped['NORB'], self.num_molecular_orbitals) + """dumped number of orbitals test""" + self.log.debug("Dumped number of orbitals is {:d}".format(self.dumped["NORB"])) + self.assertEqual(self.dumped["NORB"], self.num_molecular_orbitals) def test_dumped_num_electrons(self): - """ dumped number of electrons test """ - self.log.debug('Dumped number of electrons is {:d}'.format(self.dumped['NELEC'])) - self.assertEqual(self.dumped['NELEC'], self.num_electrons) + """dumped number of electrons test""" + self.log.debug( + "Dumped number of electrons is {:d}".format(self.dumped["NELEC"]) + ) + self.assertEqual(self.dumped["NELEC"], self.num_electrons) def test_dumped_spin_number(self): - """ dumped spin number test """ - self.log.debug('Dumped spin number is {:d}'.format(self.dumped['MS2'])) - self.assertEqual(self.dumped['MS2'], self.spin_number) + """dumped spin number test""" + self.log.debug("Dumped spin number is {:d}".format(self.dumped["MS2"])) + self.assertEqual(self.dumped["MS2"], self.spin_number) def test_dumped_wave_function_sym(self): - """ dumped wave function symmetry test """ - self.log.debug('Dumped wave function symmetry is {:d}'.format(self.dumped['ISYM'])) - self.assertEqual(self.dumped['ISYM'], self.wf_symmetry) + """dumped wave function symmetry test""" + self.log.debug( + "Dumped wave function symmetry is {:d}".format(self.dumped["ISYM"]) + ) + self.assertEqual(self.dumped["ISYM"], self.wf_symmetry) def test_dumped_orbital_syms(self): - """ dumped orbital symmetries test """ - self.log.debug('Dumped orbital symmetries is %s', self.dumped['ORBSYM']) - self.assertEqual(self.dumped['ORBSYM'], self.orb_symmetries) + """dumped orbital symmetries test""" + self.log.debug("Dumped orbital symmetries is %s", self.dumped["ORBSYM"]) + self.assertEqual(self.dumped["ORBSYM"], self.orb_symmetries) def test_dumped_h1(self): - """ dumped h1 integrals test """ - self.log.debug('Dumped h1 integrals are %s', self.dumped['H1']) - np.testing.assert_array_almost_equal(np.absolute(self.dumped['H1']), - np.absolute(self.mo_onee), decimal=4) + """dumped h1 integrals test""" + self.log.debug("Dumped h1 integrals are %s", self.dumped["H1"]) + np.testing.assert_array_almost_equal( + np.absolute(self.dumped["H1"]), np.absolute(self.mo_onee), decimal=4 + ) def test_dumped_h2(self): - """ dumped h2 integrals test """ - self.log.debug('Dumped h2 integrals are %s', self.dumped['H2']) - np.testing.assert_array_almost_equal(np.absolute(self.dumped['H2']), - np.absolute(self.mo_eri), decimal=4) + """dumped h2 integrals test""" + self.log.debug("Dumped h2 integrals are %s", self.dumped["H2"]) + np.testing.assert_array_almost_equal( + np.absolute(self.dumped["H2"]), np.absolute(self.mo_eri), decimal=4 + ) class TestDriverFCIDumpDumpH2(QiskitNatureTestCase, BaseTestDriverFCIDumpDumper): @@ -108,23 +114,26 @@ def setUp(self): self.mo_onee = [[1.2563, 0.0], [0.0, 0.4719]] self.mo_eri = [0.6757, 0.0, 0.1809, 0.6646, 0.0, 0.6986] try: - driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', - unit=UnitsType.ANGSTROM, - charge=0, - spin=0, - basis='sto3g') + driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.735", + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto3g", + ) qmolecule = driver.run() with tempfile.NamedTemporaryFile() as dump: FCIDumpDriver.dump(qmolecule, dump.name) # pylint: disable=import-outside-toplevel from pyscf.tools import fcidump as pyscf_fcidump + self.dumped = pyscf_fcidump.read(dump.name) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed.') + self.skipTest("PYSCF driver does not appear to be installed.") except ImportError: - self.skipTest('PYSCF driver does not appear to be installed.') + self.skipTest("PYSCF driver does not appear to be installed.") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/fcidumpd/test_driver_methods_fcidump.py b/test/drivers/fcidumpd/test_driver_methods_fcidump.py index b7f8f4c5fd..0eb4f85867 100644 --- a/test/drivers/fcidumpd/test_driver_methods_fcidump.py +++ b/test/drivers/fcidumpd/test_driver_methods_fcidump.py @@ -22,59 +22,79 @@ @unittest.skip("Skip test until refactored.") class TestDriverMethodsFCIDump(TestDriverMethods): - """ Driver Methods FCIDump tests """ + """Driver Methods FCIDump tests""" def test_lih(self): - """ LiH test """ - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_lih.fcidump', - 'drivers/fcidumpd')) + """LiH test""" + driver = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_lih.fcidump", "drivers/fcidumpd" + ) + ) result = self._run_driver(driver) - self._assert_energy(result, 'lih') + self._assert_energy(result, "lih") def test_oh(self): - """ OH test """ - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_oh.fcidump', - 'drivers/fcidumpd')) + """OH test""" + driver = FCIDumpDriver( + self.get_resource_path("test_driver_fcidump_oh.fcidump", "drivers/fcidumpd") + ) result = self._run_driver(driver) - self._assert_energy(result, 'oh') + self._assert_energy(result, "oh") def test_lih_freeze_core(self): - """ LiH freeze core test """ - with self.assertLogs('qiskit_nature', level='WARNING') as log: - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_lih.fcidump', - 'drivers/fcidumpd')) + """LiH freeze core test""" + with self.assertLogs("qiskit_nature", level="WARNING") as log: + driver = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_lih.fcidump", "drivers/fcidumpd" + ) + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy(result, 'lih') - warning = 'WARNING:qiskit_nature.drivers.qmolecule:Missing molecule information! ' \ - 'Returning empty core orbital list.' + self._assert_energy(result, "lih") + warning = ( + "WARNING:qiskit_nature.drivers.qmolecule:Missing molecule information! " + "Returning empty core orbital list." + ) self.assertIn(warning, log.output) def test_oh_freeze_core(self): - """ OH freeze core test """ - with self.assertLogs('qiskit_nature', level='WARNING') as log: - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_oh.fcidump', - 'drivers/fcidumpd')) + """OH freeze core test""" + with self.assertLogs("qiskit_nature", level="WARNING") as log: + driver = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_oh.fcidump", "drivers/fcidumpd" + ) + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy(result, 'oh') - warning = 'WARNING:qiskit_nature.drivers.qmolecule:Missing molecule information! ' \ - 'Returning empty core orbital list.' + self._assert_energy(result, "oh") + warning = ( + "WARNING:qiskit_nature.drivers.qmolecule:Missing molecule information! " + "Returning empty core orbital list." + ) self.assertIn(warning, log.output) def test_lih_with_atoms(self): - """ LiH with num_atoms test """ - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_lih.fcidump', - 'drivers/fcidumpd'), - atoms=['Li', 'H']) + """LiH with num_atoms test""" + driver = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_lih.fcidump", "drivers/fcidumpd" + ), + atoms=["Li", "H"], + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy(result, 'lih') + self._assert_energy(result, "lih") def test_oh_with_atoms(self): - """ OH with num_atoms test """ - driver = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_oh.fcidump', - 'drivers/fcidumpd'), - atoms=['O', 'H']) + """OH with num_atoms test""" + driver = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_oh.fcidump", "drivers/fcidumpd" + ), + atoms=["O", "H"], + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy(result, 'oh') + self._assert_energy(result, "oh") class TestFCIDumpDriverQMolecule(QiskitNatureTestCase): @@ -82,19 +102,23 @@ class TestFCIDumpDriverQMolecule(QiskitNatureTestCase): def test_qmolecule_log(self): """Test QMolecule log function.""" - qmolecule = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_h2.fcidump', - 'drivers/fcidumpd')).run() - with self.assertLogs('qiskit_nature', level='DEBUG') as _: + qmolecule = FCIDumpDriver( + self.get_resource_path("test_driver_fcidump_h2.fcidump", "drivers/fcidumpd") + ).run() + with self.assertLogs("qiskit_nature", level="DEBUG") as _: qmolecule.log() def test_qmolecule_log_with_atoms(self): """Test QMolecule log function.""" - qmolecule = FCIDumpDriver(self.get_resource_path('test_driver_fcidump_h2.fcidump', - 'drivers/fcidumpd'), - atoms=['H', 'H']).run() - with self.assertLogs('qiskit_nature', level='DEBUG') as _: + qmolecule = FCIDumpDriver( + self.get_resource_path( + "test_driver_fcidump_h2.fcidump", "drivers/fcidumpd" + ), + atoms=["H", "H"], + ).run() + with self.assertLogs("qiskit_nature", level="DEBUG") as _: qmolecule.log() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/gaussiand/test_driver_gaussian.py b/test/drivers/gaussiand/test_driver_gaussian.py index 30a1f08a27..bc1862da69 100644 --- a/test/drivers/gaussiand/test_driver_gaussian.py +++ b/test/drivers/gaussiand/test_driver_gaussian.py @@ -27,17 +27,19 @@ def setUp(self): super().setUp() try: driver = GaussianDriver( - ['# rhf/sto-3g scf(conventional) geom=nocrowd', - '', - 'h2 molecule', - '', - '0 1', - 'H 0.0 0.0 0.0', - 'H 0.0 0.0 0.735', - '' - ]) + [ + "# rhf/sto-3g scf(conventional) geom=nocrowd", + "", + "h2 molecule", + "", + "0 1", + "H 0.0 0.0 0.0", + "H 0.0 0.0 0.735", + "", + ] + ) except QiskitNatureError: - self.skipTest('GAUSSIAN driver does not appear to be installed') + self.skipTest("GAUSSIAN driver does not appear to be installed") self.qmolecule = driver.run() @@ -49,9 +51,9 @@ def setUp(self): try: driver = GaussianDriver(molecule=TestDriver.MOLECULE) except QiskitNatureError: - self.skipTest('GAUSSIAN driver does not appear to be installed') + self.skipTest("GAUSSIAN driver does not appear to be installed") self.qmolecule = driver.run() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/gaussiand/test_driver_gaussian_extra.py b/test/drivers/gaussiand/test_driver_gaussian_extra.py index 78e0753287..f183a115f0 100644 --- a/test/drivers/gaussiand/test_driver_gaussian_extra.py +++ b/test/drivers/gaussiand/test_driver_gaussian_extra.py @@ -27,7 +27,7 @@ def _check_valid(): class TestDriverGaussianExtra(QiskitNatureTestCase): - """Gaussian Driver extra tests for driver specifics, errors etc """ + """Gaussian Driver extra tests for driver specifics, errors etc""" def setUp(self): super().setUp() @@ -39,18 +39,22 @@ def tearDown(self): GaussianDriver._check_valid = self.good_check def test_cfg_augment(self): - """ test input configuration augmentation """ - cfg = '# 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' + """test input configuration augmentation""" + cfg = ( + "# 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" + ) g16 = GaussianDriver(cfg) aug_cfg = g16._augment_config("mymatfile.mat", cfg) - expected = '# rhf/sto-3g scf(conventional)\n' \ - '# Window=Full Int=NoRaff Symm=(NoInt,None)' \ - ' output=(matrix,i4labels,mo2el) tran=full\n\n' \ - 'h2 molecule\n\n0 1\nH 0.0 0.0 0.0\nH 0.0 0.0 0.735' \ - '\n\nmymatfile.mat\n\n' + expected = ( + "# rhf/sto-3g scf(conventional)\n" + "# Window=Full Int=NoRaff Symm=(NoInt,None)" + " output=(matrix,i4labels,mo2el) tran=full\n\n" + "h2 molecule\n\n0 1\nH 0.0 0.0 0.0\nH 0.0 0.0 0.735" + "\n\nmymatfile.mat\n\n" + ) self.assertEqual(aug_cfg, expected) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/gaussiand/test_driver_gaussian_forces.py b/test/drivers/gaussiand/test_driver_gaussian_forces.py index 9b1ea2d0f1..34b80af267 100644 --- a/test/drivers/gaussiand/test_driver_gaussian_forces.py +++ b/test/drivers/gaussiand/test_driver_gaussian_forces.py @@ -24,84 +24,94 @@ class TestDriverGaussianForces(QiskitNatureTestCase): """Gaussian Forces Driver tests.""" def test_driver_jcf(self): - """ Test the driver works with job control file """ + """Test the driver works with job control file""" try: driver = GaussianForcesDriver( - ['#p B3LYP/6-31g Freq=(Anharm) Int=Ultrafine SCF=VeryTight', - '', - 'CO2 geometry optimization B3LYP/6-31g', - '', - '0 1', - 'C -0.848629 2.067624 0.160992', - 'O 0.098816 2.655801 -0.159738', - 'O -1.796073 1.479446 0.481721', - '', - '' - ]) + [ + "#p B3LYP/6-31g Freq=(Anharm) Int=Ultrafine SCF=VeryTight", + "", + "CO2 geometry optimization B3LYP/6-31g", + "", + "0 1", + "C -0.848629 2.067624 0.160992", + "O 0.098816 2.655801 -0.159738", + "O -1.796073 1.479446 0.481721", + "", + "", + ] + ) result = driver.run() self._check_driver_result(result) except QiskitNatureError: - self.skipTest('GAUSSIAN driver does not appear to be installed') + self.skipTest("GAUSSIAN driver does not appear to be installed") def test_driver_molecule(self): - """ Test the driver works with Molecule """ + """Test the driver works with Molecule""" try: driver = GaussianForcesDriver( - molecule=Molecule(geometry=[('C', [-0.848629, 2.067624, 0.160992]), - ('O', [0.098816, 2.655801, -0.159738]), - ('O', [-1.796073, 1.479446, 0.481721])], - multiplicity=1, - charge=0), - basis='6-31g') + molecule=Molecule( + geometry=[ + ("C", [-0.848629, 2.067624, 0.160992]), + ("O", [0.098816, 2.655801, -0.159738]), + ("O", [-1.796073, 1.479446, 0.481721]), + ], + multiplicity=1, + charge=0, + ), + basis="6-31g", + ) result = driver.run() self._check_driver_result(result) except QiskitNatureError: - self.skipTest('GAUSSIAN driver does not appear to be installed') + self.skipTest("GAUSSIAN driver does not appear to be installed") def test_driver_logfile(self): - """ Test the driver works with logfile (Gaussian does not need to be installed) """ + """Test the driver works with logfile (Gaussian does not need to be installed)""" driver = GaussianForcesDriver( - logfile=self.get_resource_path('test_driver_gaussian_log.txt', - 'drivers/gaussiand')) + logfile=self.get_resource_path( + "test_driver_gaussian_log.txt", "drivers/gaussiand" + ) + ) result = driver.run() self._check_driver_result(result) def _check_driver_result(self, watson): - expected = [[352.3005875, 2, 2], - [-352.3005875, -2, -2], - [631.6153975, 1, 1], - [-631.6153975, -1, -1], - [115.653915, 4, 4], - [-115.653915, -4, -4], - [115.653915, 3, 3], - [-115.653915, -3, -3], - [-15.341901966295344, 2, 2, 2], - [-88.2017421687633, 1, 1, 2], - [42.40478531359112, 4, 4, 2], - [26.25167512727164, 4, 3, 2], - [2.2874639206341865, 3, 3, 2], - [0.4207357291666667, 2, 2, 2, 2], - [4.9425425, 1, 1, 2, 2], - [1.6122932291666665, 1, 1, 1, 1], - [-4.194299375, 4, 4, 2, 2], - [-4.194299375, 3, 3, 2, 2], - [-10.20589125, 4, 4, 1, 1], - [-10.20589125, 3, 3, 1, 1], - [2.2973803125, 4, 4, 4, 4], - [2.7821204166666664, 4, 4, 4, 3], - [7.329224375, 4, 4, 3, 3], - [-2.7821200000000004, 4, 3, 3, 3], - [2.2973803125, 3, 3, 3, 3] - ] + expected = [ + [352.3005875, 2, 2], + [-352.3005875, -2, -2], + [631.6153975, 1, 1], + [-631.6153975, -1, -1], + [115.653915, 4, 4], + [-115.653915, -4, -4], + [115.653915, 3, 3], + [-115.653915, -3, -3], + [-15.341901966295344, 2, 2, 2], + [-88.2017421687633, 1, 1, 2], + [42.40478531359112, 4, 4, 2], + [26.25167512727164, 4, 3, 2], + [2.2874639206341865, 3, 3, 2], + [0.4207357291666667, 2, 2, 2, 2], + [4.9425425, 1, 1, 2, 2], + [1.6122932291666665, 1, 1, 1, 1], + [-4.194299375, 4, 4, 2, 2], + [-4.194299375, 3, 3, 2, 2], + [-10.20589125, 4, 4, 1, 1], + [-10.20589125, 3, 3, 1, 1], + [2.2973803125, 4, 4, 4, 4], + [2.7821204166666664, 4, 4, 4, 3], + [7.329224375, 4, 4, 3, 3], + [-2.7821200000000004, 4, 3, 3, 3], + [2.2973803125, 3, 3, 3, 3], + ] for i, entry in enumerate(watson.data): msg = "mode[{}]={} does not match expected {}".format(i, entry, expected[i]) self.assertAlmostEqual(entry[0], expected[i][0], msg=msg) self.assertListEqual(entry[1:], expected[i][1:], msg=msg) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/gaussiand/test_driver_gaussian_from_mat.py b/test/drivers/gaussiand/test_driver_gaussian_from_mat.py index 8d93380f76..5193d02b40 100644 --- a/test/drivers/gaussiand/test_driver_gaussian_from_mat.py +++ b/test/drivers/gaussiand/test_driver_gaussian_from_mat.py @@ -39,17 +39,18 @@ def setUp(self): # and create a qmolecule from the saved output matrix file. This will test the # parsing of it into the qmolecule is correct. g16 = GaussianDriver() - matfile = self.get_resource_path('test_driver_gaussian_from_mat.mat', - 'drivers/gaussiand') + matfile = self.get_resource_path( + "test_driver_gaussian_from_mat.mat", "drivers/gaussiand" + ) try: self.qmolecule = g16._parse_matrix_file(matfile) except QiskitNatureError: self.tearDown() - self.skipTest('GAUSSIAN qcmatrixio not found') + self.skipTest("GAUSSIAN qcmatrixio not found") def tearDown(self): GaussianDriver._check_valid = self.good_check -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/gaussiand/test_driver_gaussian_log.py b/test/drivers/gaussiand/test_driver_gaussian_log.py index 85e22eee93..27ee1d5696 100644 --- a/test/drivers/gaussiand/test_driver_gaussian_log.py +++ b/test/drivers/gaussiand/test_driver_gaussian_log.py @@ -25,139 +25,151 @@ class TestDriverGaussianLog(QiskitNatureTestCase): def setUp(self): super().setUp() - self.logfile = self.get_resource_path('test_driver_gaussian_log.txt', - 'drivers/gaussiand') + self.logfile = self.get_resource_path( + "test_driver_gaussian_log.txt", "drivers/gaussiand" + ) def test_log_driver(self): - """ Test the driver itself creates log and we can get a result """ + """Test the driver itself creates log and we can get a result""" try: driver = GaussianLogDriver( - ['#p B3LYP/6-31g Freq=(Anharm) Int=Ultrafine SCF=VeryTight', - '', - 'CO2 geometry optimization B3LYP/cc-pVTZ', - '', - '0 1', - 'C -0.848629 2.067624 0.160992', - 'O 0.098816 2.655801 -0.159738', - 'O -1.796073 1.479446 0.481721', - '', - '' - ]) + [ + "#p B3LYP/6-31g Freq=(Anharm) Int=Ultrafine SCF=VeryTight", + "", + "CO2 geometry optimization B3LYP/cc-pVTZ", + "", + "0 1", + "C -0.848629 2.067624 0.160992", + "O 0.098816 2.655801 -0.159738", + "O -1.796073 1.479446 0.481721", + "", + "", + ] + ) result = driver.run() qfc = result.quadratic_force_constants - expected = [('1', '1', 1409.20235, 1.17003, 0.07515), - ('2', '2', 2526.46159, 3.76076, 0.24156), - ('3a', '3a', 462.61566, 0.12609, 0.0081), - ('3b', '3b', 462.61566, 0.12609, 0.0081)] + expected = [ + ("1", "1", 1409.20235, 1.17003, 0.07515), + ("2", "2", 2526.46159, 3.76076, 0.24156), + ("3a", "3a", 462.61566, 0.12609, 0.0081), + ("3b", "3b", 462.61566, 0.12609, 0.0081), + ] self.assertListEqual(qfc, expected) except QiskitNatureError: - self.skipTest('GAUSSIAN driver does not appear to be installed') + self.skipTest("GAUSSIAN driver does not appear to be installed") # These tests check the gaussian log result and the parsing from a partial log file that is # located with the tests so that this aspect of the code can be tested independent of # Gaussian 16 being installed. def test_gaussian_log_result_file(self): - """ Test result from file """ + """Test result from file""" result = GaussianLogResult(self.logfile) with open(self.logfile) as file: - lines = file.read().split('\n') + lines = file.read().split("\n") - with self.subTest('Check list of lines'): + with self.subTest("Check list of lines"): self.assertListEqual(result.log, lines) - with self.subTest('Check as string'): - line = '\n'.join(lines) + with self.subTest("Check as string"): + line = "\n".join(lines) self.assertEqual(str(result), line) def test_gaussian_log_result_list(self): - """ Test result from list of strings """ + """Test result from list of strings""" with open(self.logfile) as file: - lines = file.read().split('\n') + lines = file.read().split("\n") result = GaussianLogResult(lines) self.assertListEqual(result.log, lines) def test_gaussian_log_result_string(self): - """ Test result from string """ + """Test result from string""" with open(self.logfile) as file: line = file.read() result = GaussianLogResult(line) - self.assertListEqual(result.log, line.split('\n')) + self.assertListEqual(result.log, line.split("\n")) def test_quadratic_force_constants(self): - """ Test quadratic force constants """ + """Test quadratic force constants""" result = GaussianLogResult(self.logfile) qfc = result.quadratic_force_constants - expected = [('1', '1', 1409.20235, 1.17003, 0.07515), - ('2', '2', 2526.46159, 3.76076, 0.24156), - ('3a', '3a', 462.61566, 0.12609, 0.0081), - ('3b', '3b', 462.61566, 0.12609, 0.0081)] + expected = [ + ("1", "1", 1409.20235, 1.17003, 0.07515), + ("2", "2", 2526.46159, 3.76076, 0.24156), + ("3a", "3a", 462.61566, 0.12609, 0.0081), + ("3b", "3b", 462.61566, 0.12609, 0.0081), + ] self.assertListEqual(qfc, expected) def test_cubic_force_constants(self): - """ Test cubic force constants """ + """Test cubic force constants""" result = GaussianLogResult(self.logfile) cfc = result.cubic_force_constants - expected = [('1', '1', '1', -260.36071, -1.39757, -0.0475), - ('2', '2', '1', -498.9444, -4.80163, -0.1632), - ('3a', '3a', '1', 239.87769, 0.4227, 0.01437), - ('3a', '3b', '1', 74.25095, 0.13084, 0.00445), - ('3b', '3b', '1', 12.93985, 0.0228, 0.00078)] + expected = [ + ("1", "1", "1", -260.36071, -1.39757, -0.0475), + ("2", "2", "1", -498.9444, -4.80163, -0.1632), + ("3a", "3a", "1", 239.87769, 0.4227, 0.01437), + ("3a", "3b", "1", 74.25095, 0.13084, 0.00445), + ("3b", "3b", "1", 12.93985, 0.0228, 0.00078), + ] self.assertListEqual(cfc, expected) def test_quartic_force_constants(self): - """ Test quartic force constants """ + """Test quartic force constants""" result = GaussianLogResult(self.logfile) qfc = result.quartic_force_constants - expected = [('1', '1', '1', '1', 40.39063, 1.40169, 0.02521), - ('2', '2', '1', '1', 79.08068, 4.92017, 0.0885), - ('2', '2', '2', '2', 154.78015, 17.26491, 0.31053), - ('3a', '3a', '1', '1', -67.10879, -0.76453, -0.01375), - ('3b', '3b', '1', '1', -67.10879, -0.76453, -0.01375), - ('3a', '3a', '2', '2', -163.29426, -3.33524, -0.05999), - ('3b', '3b', '2', '2', -163.29426, -3.33524, -0.05999), - ('3a', '3a', '3a', '3a', 220.54851, 0.82484, 0.01484), - ('3a', '3a', '3a', '3b', 66.77089, 0.24972, 0.00449), - ('3a', '3a', '3b', '3b', 117.26759, 0.43857, 0.00789), - ('3a', '3b', '3b', '3b', -66.77088, -0.24972, -0.00449), - ('3b', '3b', '3b', '3b', 220.54851, 0.82484, 0.01484)] + expected = [ + ("1", "1", "1", "1", 40.39063, 1.40169, 0.02521), + ("2", "2", "1", "1", 79.08068, 4.92017, 0.0885), + ("2", "2", "2", "2", 154.78015, 17.26491, 0.31053), + ("3a", "3a", "1", "1", -67.10879, -0.76453, -0.01375), + ("3b", "3b", "1", "1", -67.10879, -0.76453, -0.01375), + ("3a", "3a", "2", "2", -163.29426, -3.33524, -0.05999), + ("3b", "3b", "2", "2", -163.29426, -3.33524, -0.05999), + ("3a", "3a", "3a", "3a", 220.54851, 0.82484, 0.01484), + ("3a", "3a", "3a", "3b", 66.77089, 0.24972, 0.00449), + ("3a", "3a", "3b", "3b", 117.26759, 0.43857, 0.00789), + ("3a", "3b", "3b", "3b", -66.77088, -0.24972, -0.00449), + ("3b", "3b", "3b", "3b", 220.54851, 0.82484, 0.01484), + ] self.assertListEqual(qfc, expected) def test_watson_hamiltonian(self): - """ Test the watson hamiltonian """ + """Test the watson hamiltonian""" result = GaussianLogResult(self.logfile) watson = result.get_watson_hamiltonian() - expected = [[352.3005875, 2, 2], - [-352.3005875, -2, -2], - [631.6153975, 1, 1], - [-631.6153975, -1, -1], - [115.653915, 4, 4], - [-115.653915, -4, -4], - [115.653915, 3, 3], - [-115.653915, -3, -3], - [-15.341901966295344, 2, 2, 2], - [-88.2017421687633, 1, 1, 2], - [42.40478531359112, 4, 4, 2], - [26.25167512727164, 4, 3, 2], - [2.2874639206341865, 3, 3, 2], - [0.4207357291666667, 2, 2, 2, 2], - [4.9425425, 1, 1, 2, 2], - [1.6122932291666665, 1, 1, 1, 1], - [-4.194299375, 4, 4, 2, 2], - [-4.194299375, 3, 3, 2, 2], - [-10.20589125, 4, 4, 1, 1], - [-10.20589125, 3, 3, 1, 1], - [2.2973803125, 4, 4, 4, 4], - [2.7821204166666664, 4, 4, 4, 3], - [7.329224375, 4, 4, 3, 3], - [-2.7821200000000004, 4, 3, 3, 3], - [2.2973803125, 3, 3, 3, 3] - ] + expected = [ + [352.3005875, 2, 2], + [-352.3005875, -2, -2], + [631.6153975, 1, 1], + [-631.6153975, -1, -1], + [115.653915, 4, 4], + [-115.653915, -4, -4], + [115.653915, 3, 3], + [-115.653915, -3, -3], + [-15.341901966295344, 2, 2, 2], + [-88.2017421687633, 1, 1, 2], + [42.40478531359112, 4, 4, 2], + [26.25167512727164, 4, 3, 2], + [2.2874639206341865, 3, 3, 2], + [0.4207357291666667, 2, 2, 2, 2], + [4.9425425, 1, 1, 2, 2], + [1.6122932291666665, 1, 1, 1, 1], + [-4.194299375, 4, 4, 2, 2], + [-4.194299375, 3, 3, 2, 2], + [-10.20589125, 4, 4, 1, 1], + [-10.20589125, 3, 3, 1, 1], + [2.2973803125, 4, 4, 4, 4], + [2.7821204166666664, 4, 4, 4, 3], + [7.329224375, 4, 4, 3, 3], + [-2.7821200000000004, 4, 3, 3, 3], + [2.2973803125, 3, 3, 3, 3], + ] for i, entry in enumerate(watson.data): msg = "mode[{}]={} does not match expected {}".format(i, entry, expected[i]) self.assertAlmostEqual(entry[0], expected[i][0], msg=msg) self.assertListEqual(entry[1:], expected[i][1:], msg=msg) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/gaussiand/test_driver_methods_gaussian.py b/test/drivers/gaussiand/test_driver_methods_gaussian.py index 86a67c2e48..eaf95b8851 100644 --- a/test/drivers/gaussiand/test_driver_methods_gaussian.py +++ b/test/drivers/gaussiand/test_driver_methods_gaussian.py @@ -21,9 +21,9 @@ class TestDriverMethodsGaussian(TestDriverMethods): - """ Driver Methods Gaussian tests """ + """Driver Methods Gaussian tests""" - g16_lih_config = ''' + g16_lih_config = """ # {}/sto-3g scf(conventional) Lih molecule @@ -32,9 +32,9 @@ class TestDriverMethodsGaussian(TestDriverMethods): Li 0.0 0.0 0.0 H 0.0 0.0 1.6 -''' +""" - g16_oh_config = ''' + g16_oh_config = """ # {}/sto-3g scf(conventional) Lih molecule @@ -43,45 +43,45 @@ class TestDriverMethodsGaussian(TestDriverMethods): O 0.0 0.0 0.0 H 0.0 0.0 0.9697 -''' +""" def setUp(self): super().setUp() try: - GaussianDriver(config=self.g16_lih_config.format('rhf')) + GaussianDriver(config=self.g16_lih_config.format("rhf")) except QiskitNatureError: - self.skipTest('GAUSSIAN driver does not appear to be installed') + self.skipTest("GAUSSIAN driver does not appear to be installed") def test_lih_rhf(self): - """ lih rhf test """ - driver = GaussianDriver(config=self.g16_lih_config.format('rhf')) + """lih rhf test""" + driver = GaussianDriver(config=self.g16_lih_config.format("rhf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_rohf(self): - """ lih rohf test """ - driver = GaussianDriver(config=self.g16_lih_config.format('rohf')) + """lih rohf test""" + driver = GaussianDriver(config=self.g16_lih_config.format("rohf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_uhf(self): - """ lih uhf test """ - driver = GaussianDriver(config=self.g16_lih_config.format('uhf')) + """lih uhf test""" + driver = GaussianDriver(config=self.g16_lih_config.format("uhf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_oh_rohf(self): - """ oh rohf test """ - driver = GaussianDriver(config=self.g16_oh_config.format('rohf')) + """oh rohf test""" + driver = GaussianDriver(config=self.g16_oh_config.format("rohf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'oh') + self._assert_energy_and_dipole(result, "oh") def test_oh_uhf(self): - """ oh uhf test """ - driver = GaussianDriver(config=self.g16_oh_config.format('uhf')) + """oh uhf test""" + driver = GaussianDriver(config=self.g16_oh_config.format("uhf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'oh') + self._assert_energy_and_dipole(result, "oh") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/hdf5d/test_driver_hdf5.py b/test/drivers/hdf5d/test_driver_hdf5.py index 140266c3bd..fb43a817b1 100644 --- a/test/drivers/hdf5d/test_driver_hdf5.py +++ b/test/drivers/hdf5d/test_driver_hdf5.py @@ -23,10 +23,11 @@ class TestDriverHDF5(QiskitNatureTestCase, TestDriver): def setUp(self): super().setUp() - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) self.qmolecule = driver.run() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/hdf5d/test_driver_hdf5_save.py b/test/drivers/hdf5d/test_driver_hdf5_save.py index 7b348175d2..f6744d8a3e 100644 --- a/test/drivers/hdf5d/test_driver_hdf5_save.py +++ b/test/drivers/hdf5d/test_driver_hdf5_save.py @@ -22,14 +22,15 @@ class TestDriverHDF5Save(QiskitNatureTestCase, TestDriver): - """ Use HDF5 Driver to test saved HDF5 from QMolecule """ + """Use HDF5 Driver to test saved HDF5 from QMolecule""" def setUp(self): super().setUp() - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) temp_qmolecule = driver.run() - file, self.save_file = tempfile.mkstemp(suffix='.hdf5') + file, self.save_file = tempfile.mkstemp(suffix=".hdf5") os.close(file) temp_qmolecule.save(self.save_file) # Tests are run on self.qmolecule which is from new saved HDF5 file @@ -44,5 +45,5 @@ def tearDown(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/psi4d/test_driver_methods_psi4.py b/test/drivers/psi4d/test_driver_methods_psi4.py index 1fb332df5b..0dee0132a7 100644 --- a/test/drivers/psi4d/test_driver_methods_psi4.py +++ b/test/drivers/psi4d/test_driver_methods_psi4.py @@ -21,9 +21,9 @@ class TestDriverMethodsPSI4(TestDriverMethods): - """ Driver Methods PSI4 tests """ + """Driver Methods PSI4 tests""" - psi4_lih_config = ''' + psi4_lih_config = """ molecule mol {{ 0 1 Li 0.0 0.0 0.0 @@ -35,9 +35,9 @@ class TestDriverMethodsPSI4(TestDriverMethods): scf_type pk reference {} }} -''' +""" - psi4_oh_config = ''' + psi4_oh_config = """ molecule mol {{ 0 2 O 0.0 0.0 0.0 @@ -49,45 +49,45 @@ class TestDriverMethodsPSI4(TestDriverMethods): scf_type pk reference {} }} -''' +""" def setUp(self): super().setUp() try: - PSI4Driver(config=self.psi4_lih_config.format('rhf')) + PSI4Driver(config=self.psi4_lih_config.format("rhf")) except QiskitNatureError: - self.skipTest('PSI4 driver does not appear to be installed') + self.skipTest("PSI4 driver does not appear to be installed") def test_lih_rhf(self): - """ lih rhf test """ - driver = PSI4Driver(config=self.psi4_lih_config.format('rhf')) + """lih rhf test""" + driver = PSI4Driver(config=self.psi4_lih_config.format("rhf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_rohf(self): - """ lih rohf test """ - driver = PSI4Driver(config=self.psi4_lih_config.format('rohf')) + """lih rohf test""" + driver = PSI4Driver(config=self.psi4_lih_config.format("rohf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_uhf(self): - """ lih uhf test """ - driver = PSI4Driver(config=self.psi4_lih_config.format('uhf')) + """lih uhf test""" + driver = PSI4Driver(config=self.psi4_lih_config.format("uhf")) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_oh_rohf(self): - """ oh rohf test """ - driver = PSI4Driver(config=self.psi4_oh_config.format('rohf')) + """oh rohf test""" + driver = PSI4Driver(config=self.psi4_oh_config.format("rohf")) result = self._run_driver(driver) - self._assert_energy_and_dipole(result, 'oh') + self._assert_energy_and_dipole(result, "oh") def test_oh_uhf(self): - """ oh uhf test """ - driver = PSI4Driver(config=self.psi4_oh_config.format('uhf')) + """oh uhf test""" + driver = PSI4Driver(config=self.psi4_oh_config.format("uhf")) result = self._run_driver(driver) - self._assert_energy_and_dipole(result, 'oh') + self._assert_energy_and_dipole(result, "oh") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/psi4d/test_driver_psi4.py b/test/drivers/psi4d/test_driver_psi4.py index f9f37c3982..a87f9d2444 100644 --- a/test/drivers/psi4d/test_driver_psi4.py +++ b/test/drivers/psi4d/test_driver_psi4.py @@ -26,21 +26,24 @@ class TestDriverPSI4(QiskitNatureTestCase, TestDriver): def setUp(self): super().setUp() try: - driver = PSI4Driver([ - 'molecule h2 {', - ' 0 1', - ' H 0.0 0.0 0.0', - ' H 0.0 0.0 0.735', - ' no_com', - ' no_reorient', - '}', - '', - 'set {', - ' basis sto-3g', - ' scf_type pk', - '}']) + driver = PSI4Driver( + [ + "molecule h2 {", + " 0 1", + " H 0.0 0.0 0.0", + " H 0.0 0.0 0.735", + " no_com", + " no_reorient", + "}", + "", + "set {", + " basis sto-3g", + " scf_type pk", + "}", + ] + ) except QiskitNatureError: - self.skipTest('PSI4 driver does not appear to be installed') + self.skipTest("PSI4 driver does not appear to be installed") self.qmolecule = driver.run() @@ -53,9 +56,9 @@ def setUp(self): driver = PSI4Driver(molecule=TestDriver.MOLECULE) except QiskitNatureError as ex: print(ex) - self.skipTest('PSI4 driver does not appear to be installed') + self.skipTest("PSI4 driver does not appear to be installed") self.qmolecule = driver.run() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/psi4d/test_driver_psi4_extra.py b/test/drivers/psi4d/test_driver_psi4_extra.py index b6741357ef..9d6a8be93b 100644 --- a/test/drivers/psi4d/test_driver_psi4_extra.py +++ b/test/drivers/psi4d/test_driver_psi4_extra.py @@ -27,28 +27,31 @@ def setUp(self): try: PSI4Driver._check_valid() except QiskitNatureError: - self.skipTest('PSI4 driver does not appear to be installed') + self.skipTest("PSI4 driver does not appear to be installed") def test_input_format_list(self): - """ input as a list""" - driver = PSI4Driver([ - 'molecule h2 {', - ' 0 1', - ' H 0.0 0.0 0.0', - ' H 0.0 0.0 0.735', - ' no_com', - ' no_reorient', - '}', - '', - 'set {', - ' basis sto-3g', - ' scf_type pk', - '}']) + """input as a list""" + driver = PSI4Driver( + [ + "molecule h2 {", + " 0 1", + " H 0.0 0.0 0.0", + " H 0.0 0.0 0.735", + " no_com", + " no_reorient", + "}", + "", + "set {", + " basis sto-3g", + " scf_type pk", + "}", + ] + ) qmolecule = driver.run() self.assertAlmostEqual(qmolecule.hf_energy, -1.117, places=3) def test_input_format_string(self): - """ input as a multi line string """ + """input as a multi line string""" cfg = """ molecule h2 { 0 1 @@ -68,12 +71,12 @@ def test_input_format_string(self): self.assertAlmostEqual(qmolecule.hf_energy, -1.117, places=3) def test_input_format_fail(self): - """ input type failure """ + """input type failure""" with self.assertRaises(QiskitNatureError): _ = PSI4Driver(1.000) def test_psi4_failure(self): - """ check we catch psi4 failures (bad scf type used here) """ + """check we catch psi4 failures (bad scf type used here)""" bad_cfg = """ molecule h2 { 0 1 @@ -94,5 +97,5 @@ def test_psi4_failure(self): self.assertTrue(str(ctxmgr.exception).startswith("'psi4 process return code")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/pyquanted/test_driver_methods_pyquante.py b/test/drivers/pyquanted/test_driver_methods_pyquante.py index 2f322562b6..fb69e77f3e 100644 --- a/test/drivers/pyquanted/test_driver_methods_pyquante.py +++ b/test/drivers/pyquanted/test_driver_methods_pyquante.py @@ -20,55 +20,80 @@ class TestDriverMethodsPyquante(TestDriverMethods): - """ Driver Methods Pyquante tests """ + """Driver Methods Pyquante tests""" def setUp(self): super().setUp() try: PyQuanteDriver(atoms=self.lih) except QiskitNatureError: - self.skipTest('PyQuante driver does not appear to be installed') + self.skipTest("PyQuante driver does not appear to be installed") def test_lih_rhf(self): - """ lih rhf test """ - driver = PyQuanteDriver(atoms=self.lih, units=UnitsType.ANGSTROM, - charge=0, multiplicity=1, basis=BasisType.BSTO3G, - hf_method=HFMethodType.RHF) + """lih rhf test""" + driver = PyQuanteDriver( + atoms=self.lih, + units=UnitsType.ANGSTROM, + charge=0, + multiplicity=1, + basis=BasisType.BSTO3G, + hf_method=HFMethodType.RHF, + ) result = self._run_driver(driver) - self._assert_energy(result, 'lih') + self._assert_energy(result, "lih") def test_lih_rohf(self): - """ lijh rohf test """ - driver = PyQuanteDriver(atoms=self.lih, units=UnitsType.ANGSTROM, - charge=0, multiplicity=1, basis=BasisType.BSTO3G, - hf_method=HFMethodType.ROHF) + """lijh rohf test""" + driver = PyQuanteDriver( + atoms=self.lih, + units=UnitsType.ANGSTROM, + charge=0, + multiplicity=1, + basis=BasisType.BSTO3G, + hf_method=HFMethodType.ROHF, + ) result = self._run_driver(driver) - self._assert_energy(result, 'lih') + self._assert_energy(result, "lih") def test_lih_uhf(self): - """ lih uhf test """ - driver = PyQuanteDriver(atoms=self.lih, units=UnitsType.ANGSTROM, - charge=0, multiplicity=1, basis=BasisType.BSTO3G, - hf_method=HFMethodType.UHF) + """lih uhf test""" + driver = PyQuanteDriver( + atoms=self.lih, + units=UnitsType.ANGSTROM, + charge=0, + multiplicity=1, + basis=BasisType.BSTO3G, + hf_method=HFMethodType.UHF, + ) result = self._run_driver(driver) - self._assert_energy(result, 'lih') + self._assert_energy(result, "lih") def test_oh_rohf(self): - """ oh rohf test """ - driver = PyQuanteDriver(atoms=self.o_h, units=UnitsType.ANGSTROM, - charge=0, multiplicity=2, basis=BasisType.BSTO3G, - hf_method=HFMethodType.ROHF) + """oh rohf test""" + driver = PyQuanteDriver( + atoms=self.o_h, + units=UnitsType.ANGSTROM, + charge=0, + multiplicity=2, + basis=BasisType.BSTO3G, + hf_method=HFMethodType.ROHF, + ) result = self._run_driver(driver) - self._assert_energy(result, 'oh') + self._assert_energy(result, "oh") def test_oh_uhf(self): - """ oh uhf test """ - driver = PyQuanteDriver(atoms=self.o_h, units=UnitsType.ANGSTROM, - charge=0, multiplicity=2, basis=BasisType.BSTO3G, - hf_method=HFMethodType.UHF) + """oh uhf test""" + driver = PyQuanteDriver( + atoms=self.o_h, + units=UnitsType.ANGSTROM, + charge=0, + multiplicity=2, + basis=BasisType.BSTO3G, + hf_method=HFMethodType.UHF, + ) result = self._run_driver(driver) - self._assert_energy(result, 'oh') + self._assert_energy(result, "oh") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/pyquanted/test_driver_pyquante.py b/test/drivers/pyquanted/test_driver_pyquante.py index 9a50cab451..2995c5a111 100644 --- a/test/drivers/pyquanted/test_driver_pyquante.py +++ b/test/drivers/pyquanted/test_driver_pyquante.py @@ -25,13 +25,15 @@ class TestDriverPyQuante(QiskitNatureTestCase, TestDriver): def setUp(self): super().setUp() try: - driver = PyQuanteDriver(atoms='H .0 .0 .0; H .0 .0 0.735', - units=UnitsType.ANGSTROM, - charge=0, - multiplicity=1, - basis=BasisType.BSTO3G) + driver = PyQuanteDriver( + atoms="H .0 .0 .0; H .0 .0 0.735", + units=UnitsType.ANGSTROM, + charge=0, + multiplicity=1, + basis=BasisType.BSTO3G, + ) except QiskitNatureError: - self.skipTest('PYQUANTE driver does not appear to be installed') + self.skipTest("PYQUANTE driver does not appear to be installed") self.qmolecule = driver.run() @@ -43,9 +45,9 @@ def setUp(self): try: driver = PyQuanteDriver(molecule=TestDriver.MOLECULE) except QiskitNatureError: - self.skipTest('PYQUANTE driver does not appear to be installed') + self.skipTest("PYQUANTE driver does not appear to be installed") self.qmolecule = driver.run() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/pyscfd/test_driver_methods_pyscf.py b/test/drivers/pyscfd/test_driver_methods_pyscf.py index b9d688e918..382db9cd2f 100644 --- a/test/drivers/pyscfd/test_driver_methods_pyscf.py +++ b/test/drivers/pyscfd/test_driver_methods_pyscf.py @@ -23,142 +23,217 @@ class TestDriverMethodsPySCF(TestDriverMethods): - """ Driver Methods PySCF tests """ + """Driver Methods PySCF tests""" def setUp(self): super().setUp() try: PySCFDriver(atom=self.lih) except QiskitNatureError: - self.skipTest('PySCF driver does not appear to be installed') + self.skipTest("PySCF driver does not appear to be installed") def test_lih_rhf(self): - """ lih rhf test """ - driver = PySCFDriver(atom=self.lih, unit=UnitsType.ANGSTROM, - charge=0, spin=0, basis='sto-3g', - hf_method=HFMethodType.RHF) + """lih rhf test""" + driver = PySCFDriver( + atom=self.lih, + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto-3g", + hf_method=HFMethodType.RHF, + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_rohf(self): - """ lih rohf test """ - driver = PySCFDriver(atom=self.lih, unit=UnitsType.ANGSTROM, - charge=0, spin=0, basis='sto-3g', - hf_method=HFMethodType.ROHF) + """lih rohf test""" + driver = PySCFDriver( + atom=self.lih, + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto-3g", + hf_method=HFMethodType.ROHF, + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_uhf(self): - """ lih uhf test """ - driver = PySCFDriver(atom=self.lih, unit=UnitsType.ANGSTROM, - charge=0, spin=0, basis='sto-3g', - hf_method=HFMethodType.UHF) + """lih uhf test""" + driver = PySCFDriver( + atom=self.lih, + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto-3g", + hf_method=HFMethodType.UHF, + ) result = self._run_driver(driver, transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + self._assert_energy_and_dipole(result, "lih") def test_lih_rhf_parity(self): - """ lih rhf parity test """ - driver = PySCFDriver(atom=self.lih, unit=UnitsType.ANGSTROM, - charge=0, spin=0, basis='sto-3g', - hf_method=HFMethodType.RHF) - result = self._run_driver(driver, - converter=QubitConverter(ParityMapper()), - transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + """lih rhf parity test""" + driver = PySCFDriver( + atom=self.lih, + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto-3g", + hf_method=HFMethodType.RHF, + ) + result = self._run_driver( + driver, + converter=QubitConverter(ParityMapper()), + transformers=[FreezeCoreTransformer()], + ) + self._assert_energy_and_dipole(result, "lih") def test_lih_rhf_parity_2q(self): - """ lih rhf parity 2q test """ - driver = PySCFDriver(atom=self.lih, unit=UnitsType.ANGSTROM, - charge=0, spin=0, basis='sto-3g', - hf_method=HFMethodType.RHF) - result = self._run_driver(driver, - converter=QubitConverter(ParityMapper(), - two_qubit_reduction=True), - transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + """lih rhf parity 2q test""" + driver = PySCFDriver( + atom=self.lih, + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto-3g", + hf_method=HFMethodType.RHF, + ) + result = self._run_driver( + driver, + converter=QubitConverter(ParityMapper(), two_qubit_reduction=True), + transformers=[FreezeCoreTransformer()], + ) + self._assert_energy_and_dipole(result, "lih") def test_lih_rhf_bk(self): - """ lih rhf bk test """ - driver = PySCFDriver(atom=self.lih, unit=UnitsType.ANGSTROM, - charge=0, spin=0, basis='sto-3g', - hf_method=HFMethodType.RHF) - result = self._run_driver(driver, - converter=QubitConverter(BravyiKitaevMapper()), - transformers=[FreezeCoreTransformer()]) - self._assert_energy_and_dipole(result, 'lih') + """lih rhf bk test""" + driver = PySCFDriver( + atom=self.lih, + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto-3g", + hf_method=HFMethodType.RHF, + ) + result = self._run_driver( + driver, + converter=QubitConverter(BravyiKitaevMapper()), + transformers=[FreezeCoreTransformer()], + ) + self._assert_energy_and_dipole(result, "lih") def test_oh_rohf(self): - """ oh rohf test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.ROHF) + """oh rohf test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.ROHF, + ) result = self._run_driver(driver) - self._assert_energy_and_dipole(result, 'oh') + self._assert_energy_and_dipole(result, "oh") def test_oh_uhf(self): - """ oh uhf test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.UHF) + """oh uhf test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.UHF, + ) result = self._run_driver(driver) - self._assert_energy_and_dipole(result, 'oh') + self._assert_energy_and_dipole(result, "oh") def test_oh_rohf_parity(self): - """ oh rohf parity test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.ROHF) - result = self._run_driver(driver, - converter=QubitConverter(ParityMapper())) - self._assert_energy_and_dipole(result, 'oh') + """oh rohf parity test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.ROHF, + ) + result = self._run_driver(driver, converter=QubitConverter(ParityMapper())) + self._assert_energy_and_dipole(result, "oh") def test_oh_rohf_parity_2q(self): - """ oh rohf parity 2q test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.ROHF) - result = self._run_driver(driver, - converter=QubitConverter(ParityMapper(), - two_qubit_reduction=True)) - self._assert_energy_and_dipole(result, 'oh') + """oh rohf parity 2q test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.ROHF, + ) + result = self._run_driver( + driver, converter=QubitConverter(ParityMapper(), two_qubit_reduction=True) + ) + self._assert_energy_and_dipole(result, "oh") def test_oh_uhf_parity(self): - """ oh uhf parity test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.UHF) - result = self._run_driver(driver, - converter=QubitConverter(ParityMapper())) - self._assert_energy_and_dipole(result, 'oh') + """oh uhf parity test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.UHF, + ) + result = self._run_driver(driver, converter=QubitConverter(ParityMapper())) + self._assert_energy_and_dipole(result, "oh") def test_oh_uhf_parity_2q(self): - """ oh uhf parity 2q test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.UHF) - result = self._run_driver(driver, - converter=QubitConverter(ParityMapper(), - two_qubit_reduction=True)) - self._assert_energy_and_dipole(result, 'oh') + """oh uhf parity 2q test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.UHF, + ) + result = self._run_driver( + driver, converter=QubitConverter(ParityMapper(), two_qubit_reduction=True) + ) + self._assert_energy_and_dipole(result, "oh") def test_oh_rohf_bk(self): - """ oh rohf bk test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.ROHF) - result = self._run_driver(driver, - converter=QubitConverter(BravyiKitaevMapper())) - self._assert_energy_and_dipole(result, 'oh') + """oh rohf bk test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.ROHF, + ) + result = self._run_driver( + driver, converter=QubitConverter(BravyiKitaevMapper()) + ) + self._assert_energy_and_dipole(result, "oh") def test_oh_uhf_bk(self): - """ oh uhf bk test """ - driver = PySCFDriver(atom=self.o_h, unit=UnitsType.ANGSTROM, - charge=0, spin=1, basis='sto-3g', - hf_method=HFMethodType.UHF) - result = self._run_driver(driver, - converter=QubitConverter(BravyiKitaevMapper())) - self._assert_energy_and_dipole(result, 'oh') - - -if __name__ == '__main__': + """oh uhf bk test""" + driver = PySCFDriver( + atom=self.o_h, + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto-3g", + hf_method=HFMethodType.UHF, + ) + result = self._run_driver( + driver, converter=QubitConverter(BravyiKitaevMapper()) + ) + self._assert_energy_and_dipole(result, "oh") + + +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/pyscfd/test_driver_pyscf.py b/test/drivers/pyscfd/test_driver_pyscf.py index 0e4f06c1e7..c7a75098b3 100644 --- a/test/drivers/pyscfd/test_driver_pyscf.py +++ b/test/drivers/pyscfd/test_driver_pyscf.py @@ -25,13 +25,15 @@ class TestDriverPySCF(QiskitNatureTestCase, TestDriver): def setUp(self): super().setUp() try: - driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', - unit=UnitsType.ANGSTROM, - charge=0, - spin=0, - basis='sto3g') + driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.735", + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto3g", + ) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") self.qmolecule = driver.run() @@ -43,9 +45,9 @@ def setUp(self): try: driver = PySCFDriver(molecule=TestDriver.MOLECULE) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") self.qmolecule = driver.run() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/pyscfd/test_driver_pyscf_extra.py b/test/drivers/pyscfd/test_driver_pyscf_extra.py index f6bea6deac..55160e1159 100644 --- a/test/drivers/pyscfd/test_driver_pyscf_extra.py +++ b/test/drivers/pyscfd/test_driver_pyscf_extra.py @@ -24,48 +24,57 @@ class TestDriverPySCFExtra(QiskitNatureTestCase): def setUp(self): super().setUp() try: - PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', - unit=UnitsType.ANGSTROM, - charge=0, - spin=0, - basis='sto3g') + PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.735", + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto3g", + ) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") def test_h3(self): - """ Test for H3 chain, see also issue 1148 """ - atom = 'H 0 0 0; H 0 0 1; H 0 0 2' - driver = PySCFDriver(atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=1, basis='sto3g') + """Test for H3 chain, see also issue 1148""" + atom = "H 0 0 0; H 0 0 1; H 0 0 2" + driver = PySCFDriver( + atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=1, basis="sto3g" + ) molecule = driver.run() self.assertAlmostEqual(molecule.hf_energy, -1.523996200246108, places=5) def test_h4(self): - """ Test for H4 chain """ - atom = 'H 0 0 0; H 0 0 1; H 0 0 2; H 0 0 3' - driver = PySCFDriver(atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis='sto3g') + """Test for H4 chain""" + atom = "H 0 0 0; H 0 0 1; H 0 0 2; H 0 0 3" + driver = PySCFDriver( + atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis="sto3g" + ) molecule = driver.run() self.assertAlmostEqual(molecule.hf_energy, -2.09854593699776, places=5) def test_invalid_atom_type(self): - """ Atom is string with ; separator or list of string """ + """Atom is string with ; separator or list of string""" with self.assertRaises(QiskitNatureError): - PySCFDriver(atom=('H', 0, 0, 0)) + PySCFDriver(atom=("H", 0, 0, 0)) def test_list_atom(self): - """ Check input with list of strings """ - atom = ['H 0 0 0', - 'H 0 0 1'] - driver = PySCFDriver(atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis='sto3g') + """Check input with list of strings""" + atom = ["H 0 0 0", "H 0 0 1"] + driver = PySCFDriver( + atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis="sto3g" + ) molecule = driver.run() self.assertAlmostEqual(molecule.hf_energy, -1.0661086493179366, places=5) def test_zmatrix(self): - """ Check z-matrix input """ - atom = 'H; H 1 1.0' - driver = PySCFDriver(atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis='sto3g') + """Check z-matrix input""" + atom = "H; H 1 1.0" + driver = PySCFDriver( + atom=atom, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis="sto3g" + ) molecule = driver.run() self.assertAlmostEqual(molecule.hf_energy, -1.0661086493179366, places=5) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/test_driver.py b/test/drivers/test_driver.py index c5f18e0b39..c8b9395cc2 100644 --- a/test/drivers/test_driver.py +++ b/test/drivers/test_driver.py @@ -21,9 +21,11 @@ class TestDriver(ABC): """Common driver tests. For H2 @ 0.735, sto3g""" - MOLECULE = Molecule(geometry=[('H', [.0, .0, .0]), ('H', [.0, .0, 0.735])], - multiplicity=1, - charge=0) + MOLECULE = Molecule( + geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 0.735])], + multiplicity=1, + charge=0, + ) def __init__(self): self.log = None @@ -31,115 +33,161 @@ def __init__(self): @abstractmethod def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None): - """ assert Almost Equal """ - raise Exception('Abstract method') + """assert Almost Equal""" + raise Exception("Abstract method") @abstractmethod def assertEqual(self, first, second, msg=None): - """ assert equal """ - raise Exception('Abstract method') + """assert equal""" + raise Exception("Abstract method") @abstractmethod def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None): - """ assert Sequence Equal """ - raise Exception('Abstract method') + """assert Sequence Equal""" + raise Exception("Abstract method") def test_driver_hf_energy(self): - """ driver hf energy test """ - self.log.debug('QMolecule HF energy: {}'.format(self.qmolecule.hf_energy)) + """driver hf energy test""" + self.log.debug("QMolecule HF energy: {}".format(self.qmolecule.hf_energy)) self.assertAlmostEqual(self.qmolecule.hf_energy, -1.117, places=3) def test_driver_nuclear_repulsion_energy(self): - """ driver nuclear repulsion energy test """ - self.log.debug('QMolecule Nuclear repulsion energy: {}'.format( - self.qmolecule.nuclear_repulsion_energy)) + """driver nuclear repulsion energy test""" + self.log.debug( + "QMolecule Nuclear repulsion energy: {}".format( + self.qmolecule.nuclear_repulsion_energy + ) + ) self.assertAlmostEqual(self.qmolecule.nuclear_repulsion_energy, 0.72, places=2) def test_driver_num_molecular_orbitals(self): - """ driver num molecular orbitals test """ - self.log.debug('QMolecule Number of orbitals is {}'.format( - self.qmolecule.num_molecular_orbitals)) + """driver num molecular orbitals test""" + self.log.debug( + "QMolecule Number of orbitals is {}".format( + self.qmolecule.num_molecular_orbitals + ) + ) self.assertEqual(self.qmolecule.num_molecular_orbitals, 2) def test_driver_num_alpha(self): - """ driver num alpha test """ - self.log.debug('QMolecule Number of alpha electrons is {}'.format(self.qmolecule.num_alpha)) + """driver num alpha test""" + self.log.debug( + "QMolecule Number of alpha electrons is {}".format(self.qmolecule.num_alpha) + ) self.assertEqual(self.qmolecule.num_alpha, 1) def test_driver_num_beta(self): - """ driver num beta test """ - self.log.debug('QMolecule Number of beta electrons is {}'.format(self.qmolecule.num_beta)) + """driver num beta test""" + self.log.debug( + "QMolecule Number of beta electrons is {}".format(self.qmolecule.num_beta) + ) self.assertEqual(self.qmolecule.num_beta, 1) def test_driver_molecular_charge(self): - """ driver molecular charge test """ - self.log.debug('QMolecule molecular charge is {}'.format(self.qmolecule.molecular_charge)) + """driver molecular charge test""" + self.log.debug( + "QMolecule molecular charge is {}".format(self.qmolecule.molecular_charge) + ) self.assertEqual(self.qmolecule.molecular_charge, 0) def test_driver_multiplicity(self): - """ driver multiplicity test """ - self.log.debug('QMolecule multiplicity is {}'.format(self.qmolecule.multiplicity)) + """driver multiplicity test""" + self.log.debug( + "QMolecule multiplicity is {}".format(self.qmolecule.multiplicity) + ) self.assertEqual(self.qmolecule.multiplicity, 1) def test_driver_num_atoms(self): - """ driver num atoms test """ - self.log.debug('QMolecule num atoms {}'.format(self.qmolecule.num_atoms)) + """driver num atoms test""" + self.log.debug("QMolecule num atoms {}".format(self.qmolecule.num_atoms)) self.assertEqual(self.qmolecule.num_atoms, 2) def test_driver_atom_symbol(self): - """ driver atom symbol test """ - self.log.debug('QMolecule atom symbol {}'.format(self.qmolecule.atom_symbol)) - self.assertSequenceEqual(self.qmolecule.atom_symbol, ['H', 'H']) + """driver atom symbol test""" + self.log.debug("QMolecule atom symbol {}".format(self.qmolecule.atom_symbol)) + self.assertSequenceEqual(self.qmolecule.atom_symbol, ["H", "H"]) def test_driver_atom_xyz(self): - """ driver atom xyz test """ - self.log.debug('QMolecule atom xyz {}'.format(self.qmolecule.atom_xyz)) - np.testing.assert_array_almost_equal(self.qmolecule.atom_xyz, - [[0.0, 0.0, 0.0], [0.0, 0.0, 1.3889]], decimal=4) + """driver atom xyz test""" + self.log.debug("QMolecule atom xyz {}".format(self.qmolecule.atom_xyz)) + np.testing.assert_array_almost_equal( + self.qmolecule.atom_xyz, [[0.0, 0.0, 0.0], [0.0, 0.0, 1.3889]], decimal=4 + ) def test_driver_mo_coeff(self): - """ driver mo coeff test """ - self.log.debug('QMolecule MO coeffs xyz {}'.format(self.qmolecule.mo_coeff)) + """driver mo coeff test""" + self.log.debug("QMolecule MO coeffs xyz {}".format(self.qmolecule.mo_coeff)) self.assertEqual(self.qmolecule.mo_coeff.shape, (2, 2)) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_coeff), - [[0.5483, 1.2183], [0.5483, 1.2183]], decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_coeff), + [[0.5483, 1.2183], [0.5483, 1.2183]], + decimal=4, + ) def test_driver_orbital_energies(self): - """ driver orbital energies test """ - self.log.debug('QMolecule orbital energies {}'.format(self.qmolecule.orbital_energies)) - np.testing.assert_array_almost_equal(self.qmolecule.orbital_energies, - [-0.5806, 0.6763], decimal=4) + """driver orbital energies test""" + self.log.debug( + "QMolecule orbital energies {}".format(self.qmolecule.orbital_energies) + ) + np.testing.assert_array_almost_equal( + self.qmolecule.orbital_energies, [-0.5806, 0.6763], decimal=4 + ) def test_driver_mo_onee_ints(self): - """ driver mo onee ints test """ - self.log.debug('QMolecule MO one electron integrals {}'.format(self.qmolecule.mo_onee_ints)) + """driver mo onee ints test""" + self.log.debug( + "QMolecule MO one electron integrals {}".format(self.qmolecule.mo_onee_ints) + ) self.assertEqual(self.qmolecule.mo_onee_ints.shape, (2, 2)) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_onee_ints), - [[1.2563, 0.0], [0.0, 0.4719]], decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_onee_ints), + [[1.2563, 0.0], [0.0, 0.4719]], + decimal=4, + ) def test_driver_mo_eri_ints(self): - """ driver mo eri ints test """ - self.log.debug('QMolecule MO two electron integrals {}'.format(self.qmolecule.mo_eri_ints)) + """driver mo eri ints test""" + self.log.debug( + "QMolecule MO two electron integrals {}".format(self.qmolecule.mo_eri_ints) + ) self.assertEqual(self.qmolecule.mo_eri_ints.shape, (2, 2, 2, 2)) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.mo_eri_ints), - [[[[0.6757, 0.0], [0.0, 0.6646]], - [[0.0, 0.1809], [0.1809, 0.0]]], - [[[0.0, 0.1809], [0.1809, 0.0]], - [[0.6646, 0.0], [0.0, 0.6986]]]], decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.mo_eri_ints), + [ + [[[0.6757, 0.0], [0.0, 0.6646]], [[0.0, 0.1809], [0.1809, 0.0]]], + [[[0.0, 0.1809], [0.1809, 0.0]], [[0.6646, 0.0], [0.0, 0.6986]]], + ], + decimal=4, + ) def test_driver_dipole_integrals(self): - """ driver dipole integrals test """ - self.log.debug('QMolecule has dipole integrals {}'.format( - self.qmolecule.has_dipole_integrals())) + """driver dipole integrals test""" + self.log.debug( + "QMolecule has dipole integrals {}".format( + self.qmolecule.has_dipole_integrals() + ) + ) if self.qmolecule.has_dipole_integrals(): self.assertEqual(self.qmolecule.x_dip_mo_ints.shape, (2, 2)) self.assertEqual(self.qmolecule.y_dip_mo_ints.shape, (2, 2)) self.assertEqual(self.qmolecule.z_dip_mo_ints.shape, (2, 2)) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.x_dip_mo_ints), - [[0.0, 0.0], [0.0, 0.0]], decimal=4) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.y_dip_mo_ints), - [[0.0, 0.0], [0.0, 0.0]], decimal=4) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.z_dip_mo_ints), - [[0.6945, 0.9278], [0.9278, 0.6945]], decimal=4) - np.testing.assert_array_almost_equal(np.absolute(self.qmolecule.nuclear_dipole_moment), - [0.0, 0.0, 1.3889], decimal=4) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.x_dip_mo_ints), + [[0.0, 0.0], [0.0, 0.0]], + decimal=4, + ) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.y_dip_mo_ints), + [[0.0, 0.0], [0.0, 0.0]], + decimal=4, + ) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.z_dip_mo_ints), + [[0.6945, 0.9278], [0.9278, 0.6945]], + decimal=4, + ) + np.testing.assert_array_almost_equal( + np.absolute(self.qmolecule.nuclear_dipole_moment), + [0.0, 0.0, 1.3889], + decimal=4, + ) diff --git a/test/drivers/test_driver_methods_gsc.py b/test/drivers/test_driver_methods_gsc.py index ffde5c7479..f9ccbc1b3f 100644 --- a/test/drivers/test_driver_methods_gsc.py +++ b/test/drivers/test_driver_methods_gsc.py @@ -31,21 +31,17 @@ class TestDriverMethods(QiskitNatureTestCase): def setUp(self): super().setUp() - self.lih = 'LI 0 0 0; H 0 0 1.6' - self.o_h = 'O 0 0 0; H 0 0 0.9697' - self.ref_energies = { - 'lih': -7.882, - 'oh': -74.387 - } - self.ref_dipoles = { - 'lih': 1.818, - 'oh': 0.4615 - } + self.lih = "LI 0 0 0; H 0 0 1.6" + self.o_h = "O 0 0 0; H 0 0 0.9697" + self.ref_energies = {"lih": -7.882, "oh": -74.387} + self.ref_dipoles = {"lih": 1.818, "oh": 0.4615} @staticmethod - def _run_driver(driver: FermionicDriver, - converter: QubitConverter = QubitConverter(JordanWignerMapper()), - transformers: Optional[List[BaseTransformer]] = None): + def _run_driver( + driver: FermionicDriver, + converter: QubitConverter = QubitConverter(JordanWignerMapper()), + transformers: Optional[List[BaseTransformer]] = None, + ): problem = ElectronicStructureProblem(driver, transformers) @@ -57,12 +53,16 @@ def _run_driver(driver: FermionicDriver, return result def _assert_energy(self, result, mol): - self.assertAlmostEqual(self.ref_energies[mol], result.total_energies[0], places=3) + self.assertAlmostEqual( + self.ref_energies[mol], result.total_energies[0], places=3 + ) def _assert_energy_and_dipole(self, result, mol): self._assert_energy(result, mol) - self.assertAlmostEqual(self.ref_dipoles[mol], result.total_dipole_moment[0], places=3) + self.assertAlmostEqual( + self.ref_dipoles[mol], result.total_dipole_moment[0], places=3 + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/drivers/test_driver_molecule.py b/test/drivers/test_driver_molecule.py index 9e4e452b44..238ff40c69 100644 --- a/test/drivers/test_driver_molecule.py +++ b/test/drivers/test_driver_molecule.py @@ -25,147 +25,171 @@ class TestMolecule(QiskitNatureTestCase): """Test driver-independent molecule definition.""" def test_construct(self): - """ test construct """ - stretch = partial( - Molecule.absolute_stretching, - kwargs={'atom_pair': (1, 0)}) - - with self.subTest('Masses supplied'): - mol = Molecule(geometry=[('H', [0., 0., 0.]), ('H', [0., 0., 1.])], - degrees_of_freedom=[stretch], - masses=[1, 1]) - self.assertListEqual(mol.geometry, [('H', [0., 0., 0.]), ('H', [0., 0., 1.])]) + """test construct""" + stretch = partial(Molecule.absolute_stretching, kwargs={"atom_pair": (1, 0)}) + + with self.subTest("Masses supplied"): + mol = Molecule( + geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])], + degrees_of_freedom=[stretch], + masses=[1, 1], + ) + self.assertListEqual( + mol.geometry, [("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])] + ) self.assertEqual(mol.multiplicity, 1) self.assertEqual(mol.charge, 0) self.assertIsNone(mol.perturbations) self.assertListEqual(mol.masses, [1, 1]) - with self.subTest('No masses'): - mol = Molecule(geometry=[('H', [0., 0., 0.]), ('H', [0., 0., 1.])], - degrees_of_freedom=[stretch]) + with self.subTest("No masses"): + mol = Molecule( + geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])], + degrees_of_freedom=[stretch], + ) self.assertIsNone(mol.masses) - with self.subTest('All params'): - mol = Molecule(geometry=[('H', [0., 0., 0.]), ('H', [0., 0., 1.])], - multiplicity=2, charge=1, - degrees_of_freedom=[stretch], - masses=[0.7, 0.8]) + with self.subTest("All params"): + mol = Molecule( + geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])], + multiplicity=2, + charge=1, + degrees_of_freedom=[stretch], + masses=[0.7, 0.8], + ) self.assertEqual(mol.multiplicity, 2) self.assertEqual(mol.charge, 1) self.assertIsNone(mol.perturbations) self.assertListEqual(mol.masses, [0.7, 0.8]) - with self.subTest('Mismatched masses length'): + with self.subTest("Mismatched masses length"): with self.assertRaises(ValueError): - Molecule(geometry=[('H', [0., 0., 0.]), ('H', [0., 0., 1.])], masses=[1, 1, 1]) + Molecule( + geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])], + masses=[1, 1, 1], + ) def test_charge(self): - """ test charge """ - mol = Molecule(geometry=[('H', [0., 0., 0.]), ('H', [0., 0., 1.])]) + """test charge""" + mol = Molecule(geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])]) self.assertEqual(mol.charge, 0) mol.charge = 1 self.assertEqual(mol.charge, 1) def test_multiplicity(self): - """ test multiplicity """ - mol = Molecule(geometry=[('H', [0., 0., 0.]), ('H', [0., 0., 1.])]) + """test multiplicity""" + mol = Molecule(geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])]) self.assertEqual(mol.multiplicity, 1) mol.multiplicity = 0 self.assertEqual(mol.multiplicity, 0) def test_stretch(self): - """ test stretch """ + """test stretch""" geom = None - with self.subTest('From original'): - geom = Molecule.absolute_stretching(atom_pair=(1, 0), - perturbation=2, - geometry=[('H', [0., 0., 0.]), - ('H', [0., 0., 1.])]) - self.assertListEqual(geom[1][1], [0., 0., 3.]) + with self.subTest("From original"): + geom = Molecule.absolute_stretching( + atom_pair=(1, 0), + perturbation=2, + geometry=[("H", [0.0, 0.0, 0.0]), ("H", [0.0, 0.0, 1.0])], + ) + self.assertListEqual(geom[1][1], [0.0, 0.0, 3.0]) - with self.subTest('Reduce stretch'): - geom = Molecule.absolute_stretching(atom_pair=(1, 0), - perturbation=-.1, - geometry=geom) - self.assertListEqual(geom[1][1], [0., 0., 3. - .1]) + with self.subTest("Reduce stretch"): + geom = Molecule.absolute_stretching( + atom_pair=(1, 0), perturbation=-0.1, geometry=geom + ) + self.assertListEqual(geom[1][1], [0.0, 0.0, 3.0 - 0.1]) def test_bend(self): - """ test bend """ - with self.subTest('pi/2 bend 1-0-2'): - geom = Molecule.absolute_bending(atom_trio=(1, 0, 2), - bend=np.pi / 2, - geometry=[('H', [0., 0., 0.]), - ('H', [0., 0., 1.]), - ('Li', [0., 1., -1.])]) - self.assertListEqual(geom[1][1], [0., 1., 0.]) - - with self.subTest('-pi/4 bend 1-0-2'): - geom = Molecule.absolute_bending(atom_trio=(1, 0, 2), - bend=-np.pi / 4, - geometry=geom) + """test bend""" + with self.subTest("pi/2 bend 1-0-2"): + geom = Molecule.absolute_bending( + atom_trio=(1, 0, 2), + bend=np.pi / 2, + geometry=[ + ("H", [0.0, 0.0, 0.0]), + ("H", [0.0, 0.0, 1.0]), + ("Li", [0.0, 1.0, -1.0]), + ], + ) + self.assertListEqual(geom[1][1], [0.0, 1.0, 0.0]) + + with self.subTest("-pi/4 bend 1-0-2"): + geom = Molecule.absolute_bending( + atom_trio=(1, 0, 2), bend=-np.pi / 4, geometry=geom + ) np.testing.assert_array_almost_equal( - geom[1][1], [0., np.sqrt(2) / 2, np.sqrt(2) / 2]) + geom[1][1], [0.0, np.sqrt(2) / 2, np.sqrt(2) / 2] + ) - with self.subTest('-pi/4 bend 2-0-1'): - geom = Molecule.absolute_bending(atom_trio=(2, 0, 1), - bend=-np.pi / 4, - geometry=geom) - np.testing.assert_array_almost_equal(geom[2][1], [0., 0., -np.sqrt(2)]) + with self.subTest("-pi/4 bend 2-0-1"): + geom = Molecule.absolute_bending( + atom_trio=(2, 0, 1), bend=-np.pi / 4, geometry=geom + ) + np.testing.assert_array_almost_equal(geom[2][1], [0.0, 0.0, -np.sqrt(2)]) # Test linear case - with self.subTest('Linear case'): - geom = Molecule.absolute_bending(atom_trio=(1, 0, 2), - bend=np.pi / 2, - geometry=[('H', [0., 0., 0.]), - ('H', [0., 0., 1.]), - ('Li', [0., 0., -1.])]) - self.assertListEqual(geom[1][1], [1., 0., 0.]) + with self.subTest("Linear case"): + geom = Molecule.absolute_bending( + atom_trio=(1, 0, 2), + bend=np.pi / 2, + geometry=[ + ("H", [0.0, 0.0, 0.0]), + ("H", [0.0, 0.0, 1.0]), + ("Li", [0.0, 0.0, -1.0]), + ], + ) + self.assertListEqual(geom[1][1], [1.0, 0.0, 0.0]) def test_perturbations(self): - """ test perturbations """ + """test perturbations""" stretch1 = partial(Molecule.absolute_stretching, atom_pair=(1, 0)) bend = partial(Molecule.absolute_bending, atom_trio=(1, 0, 2)) stretch2 = partial(Molecule.absolute_stretching, atom_pair=(0, 1)) - mol = Molecule(geometry=[('H', [0., 0., 0.]), - ('O', [0., 0., 1.]), - ('Li', [0., 1., -1.])], - degrees_of_freedom=[stretch1, bend, stretch2], - masses=[1, 1, 1]) - - with self.subTest('Before perturbing'): + mol = Molecule( + geometry=[ + ("H", [0.0, 0.0, 0.0]), + ("O", [0.0, 0.0, 1.0]), + ("Li", [0.0, 1.0, -1.0]), + ], + degrees_of_freedom=[stretch1, bend, stretch2], + masses=[1, 1, 1], + ) + + with self.subTest("Before perturbing"): geom = mol.geometry - self.assertEqual(geom[0][0], 'H') - self.assertEqual(geom[1][0], 'O') - self.assertEqual(geom[2][0], 'Li') - np.testing.assert_array_almost_equal(geom[0][1], [0., 0., 0.]) - np.testing.assert_array_almost_equal(geom[1][1], [0., 0., 1.]) - np.testing.assert_array_almost_equal(geom[2][1], [0., 1., -1.]) + self.assertEqual(geom[0][0], "H") + self.assertEqual(geom[1][0], "O") + self.assertEqual(geom[2][0], "Li") + np.testing.assert_array_almost_equal(geom[0][1], [0.0, 0.0, 0.0]) + np.testing.assert_array_almost_equal(geom[1][1], [0.0, 0.0, 1.0]) + np.testing.assert_array_almost_equal(geom[2][1], [0.0, 1.0, -1.0]) self.assertIsNone(mol.perturbations) - with self.subTest('Perturbations: [2, np.pi / 2, -.5]'): - mol.perturbations = [2, np.pi / 2, -.5] + with self.subTest("Perturbations: [2, np.pi / 2, -.5]"): + mol.perturbations = [2, np.pi / 2, -0.5] geom = mol.geometry - self.assertEqual(geom[0][0], 'H') - self.assertEqual(geom[1][0], 'O') - self.assertEqual(geom[2][0], 'Li') + self.assertEqual(geom[0][0], "H") + self.assertEqual(geom[1][0], "O") + self.assertEqual(geom[2][0], "Li") np.testing.assert_array_almost_equal(geom[0][1], [0.0, 0.5, 0.0]) - np.testing.assert_array_almost_equal(geom[1][1], [0., 3., 0.]) - np.testing.assert_array_almost_equal(geom[2][1], [0., 1., -1.]) - self.assertListEqual(mol.perturbations, [2, np.pi / 2, -.5]) + np.testing.assert_array_almost_equal(geom[1][1], [0.0, 3.0, 0.0]) + np.testing.assert_array_almost_equal(geom[2][1], [0.0, 1.0, -1.0]) + self.assertListEqual(mol.perturbations, [2, np.pi / 2, -0.5]) - with self.subTest('Perturbations: None'): + with self.subTest("Perturbations: None"): mol.perturbations = None # Should be original geometry geom = mol.geometry - self.assertEqual(geom[0][0], 'H') - self.assertEqual(geom[1][0], 'O') - self.assertEqual(geom[2][0], 'Li') - np.testing.assert_array_almost_equal(geom[0][1], [0., 0., 0.]) - np.testing.assert_array_almost_equal(geom[1][1], [0., 0., 1.]) - np.testing.assert_array_almost_equal(geom[2][1], [0., 1., -1.]) + self.assertEqual(geom[0][0], "H") + self.assertEqual(geom[1][0], "O") + self.assertEqual(geom[2][0], "Li") + np.testing.assert_array_almost_equal(geom[0][1], [0.0, 0.0, 0.0]) + np.testing.assert_array_almost_equal(geom[1][1], [0.0, 0.0, 1.0]) + np.testing.assert_array_almost_equal(geom[2][1], [0.0, 1.0, -1.0]) self.assertIsNone(mol.perturbations) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/mappers/second_quantization/resources/reference_direct_mapper.py b/test/mappers/second_quantization/resources/reference_direct_mapper.py index f422ad283b..4ab46a384c 100644 --- a/test/mappers/second_quantization/resources/reference_direct_mapper.py +++ b/test/mappers/second_quantization/resources/reference_direct_mapper.py @@ -14,135 +14,136 @@ from qiskit.opflow import X, Y, Z, I -REFERENCE = \ - 5077.236560625012 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I) \ - - 472.28961593750034 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I) \ - - 157.22939093749991 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) \ - - 467.5058515625001 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) \ - - 1.2397992187500007 * (Z ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) \ - - 0.4132664062500002 * (I ^ Z ^ Z ^ I ^ I ^ I ^ I ^ I) \ - - 155.20426031249983 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) \ - - 0.4132664062500002 * (Z ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) \ - - 0.13775546875000005 * (I ^ Z ^ I ^ Z ^ I ^ I ^ I ^ I) \ - - 1027.4430731249997 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) \ - - 3.7889535937500023 * (Z ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) \ - - 1.2629845312500008 * (I ^ Z ^ I ^ I ^ Z ^ I ^ I ^ I) \ - - 5.772877031250004 * (I ^ I ^ Z ^ I ^ Z ^ I ^ I ^ I) \ - - 1.9242923437500008 * (I ^ I ^ I ^ Z ^ Z ^ I ^ I ^ I) \ - - 342.04261812500033 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) \ - - 1.2629845312500005 * (Z ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) \ - - 0.42099484375000024 * (I ^ Z ^ I ^ I ^ I ^ Z ^ I ^ I) \ - - 1.924292343750001 * (I ^ I ^ Z ^ I ^ I ^ Z ^ I ^ I) \ - - 0.6414307812500002 * (I ^ I ^ I ^ Z ^ I ^ Z ^ I ^ I) \ - - 1810.6538965625004 * (I ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) \ - - 10.340644218750004 * (Z ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) \ - - 3.4468814062500015 * (I ^ Z ^ I ^ I ^ I ^ I ^ Z ^ I) \ - - 14.366345625000008 * (I ^ I ^ Z ^ I ^ I ^ I ^ Z ^ I) \ - - 4.788781875000002 * (I ^ I ^ I ^ Z ^ I ^ I ^ Z ^ I) \ - + 11.339220937500007 * (I ^ I ^ I ^ I ^ Z ^ I ^ Z ^ I) \ - + 3.779740312500002 * (I ^ I ^ I ^ I ^ I ^ Z ^ Z ^ I) \ - - 601.9000340624999 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) \ - - 3.4468814062500015 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) \ - - 1.1489604687500004 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ Z) \ - - 4.788781875000002 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ Z) \ - - 1.5962606250000009 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ Z) \ - + 3.779740312500002 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ Z) \ - + 1.2599134375000005 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ Z) \ - - 2.358922187500002 * (X ^ X ^ X ^ X ^ I ^ I ^ I ^ I) \ - - 2.358922187500002 * (Y ^ Y ^ X ^ X ^ I ^ I ^ I ^ I) \ - - 2.358922187500002 * (X ^ X ^ Y ^ Y ^ I ^ I ^ I ^ I) \ - - 2.358922187500002 * (Y ^ Y ^ Y ^ Y ^ I ^ I ^ I ^ I) \ - + 1.0759307812500005 * (X ^ X ^ X ^ X ^ Z ^ I ^ I ^ I) \ - + 1.0759307812500005 * (Y ^ Y ^ X ^ X ^ Z ^ I ^ I ^ I) \ - + 1.0759307812500005 * (X ^ X ^ Y ^ Y ^ Z ^ I ^ I ^ I) \ - + 1.0759307812500005 * (Y ^ Y ^ Y ^ Y ^ Z ^ I ^ I ^ I) \ - + 0.35864359375000016 * (X ^ X ^ X ^ X ^ I ^ Z ^ I ^ I) \ - + 0.35864359375000016 * (Y ^ Y ^ X ^ X ^ I ^ Z ^ I ^ I) \ - + 0.35864359375000016 * (X ^ X ^ Y ^ Y ^ I ^ Z ^ I ^ I) \ - + 0.35864359375000016 * (Y ^ Y ^ Y ^ Y ^ I ^ Z ^ I ^ I) \ - + 2.183239218750001 * (X ^ X ^ X ^ X ^ I ^ I ^ Z ^ I) \ - + 2.183239218750001 * (Y ^ Y ^ X ^ X ^ I ^ I ^ Z ^ I) \ - + 2.183239218750001 * (X ^ X ^ Y ^ Y ^ I ^ I ^ Z ^ I) \ - + 2.183239218750001 * (Y ^ Y ^ Y ^ Y ^ I ^ I ^ Z ^ I) \ - + 0.7277464062500004 * (X ^ X ^ X ^ X ^ I ^ I ^ I ^ Z) \ - + 0.7277464062500004 * (Y ^ Y ^ X ^ X ^ I ^ I ^ I ^ Z) \ - + 0.7277464062500004 * (X ^ X ^ Y ^ Y ^ I ^ I ^ I ^ Z) \ - + 0.7277464062500004 * (Y ^ Y ^ Y ^ Y ^ I ^ I ^ I ^ Z) \ - - 84.41897986727398 * (I ^ I ^ I ^ I ^ X ^ X ^ I ^ I) \ - - 4.809566200586032 * (Z ^ I ^ I ^ I ^ X ^ X ^ I ^ I) \ - - 1.6031887335286772 * (I ^ Z ^ I ^ I ^ X ^ X ^ I ^ I) \ - - 16.233724778792137 * (I ^ I ^ Z ^ I ^ X ^ X ^ I ^ I) \ - - 5.411241592930711 * (I ^ I ^ I ^ Z ^ X ^ X ^ I ^ I) \ - - 84.41897986727398 * (I ^ I ^ I ^ I ^ Y ^ Y ^ I ^ I) \ - - 4.809566200586032 * (Z ^ I ^ I ^ I ^ Y ^ Y ^ I ^ I) \ - - 1.6031887335286772 * (I ^ Z ^ I ^ I ^ Y ^ Y ^ I ^ I) \ - - 16.233724778792137 * (I ^ I ^ Z ^ I ^ Y ^ Y ^ I ^ I) \ - - 5.411241592930711 * (I ^ I ^ I ^ Z ^ Y ^ Y ^ I ^ I) \ - + 66.81814897987134 * (I ^ I ^ I ^ I ^ X ^ X ^ Z ^ I) \ - + 66.81814897987134 * (I ^ I ^ I ^ I ^ Y ^ Y ^ Z ^ I) \ - + 22.272716326623776 * (I ^ I ^ I ^ I ^ X ^ X ^ I ^ Z) \ - + 22.272716326623776 * (I ^ I ^ I ^ I ^ Y ^ Y ^ I ^ Z) \ - + 2.144411357441029 * (X ^ X ^ X ^ X ^ X ^ X ^ I ^ I) \ - + 2.144411357441029 * (Y ^ Y ^ X ^ X ^ X ^ X ^ I ^ I) \ - + 2.144411357441029 * (X ^ X ^ Y ^ Y ^ X ^ X ^ I ^ I) \ - + 2.144411357441029 * (Y ^ Y ^ Y ^ Y ^ X ^ X ^ I ^ I) \ - + 2.144411357441029 * (X ^ X ^ X ^ X ^ Y ^ Y ^ I ^ I) \ - + 2.144411357441029 * (Y ^ Y ^ X ^ X ^ Y ^ Y ^ I ^ I) \ - + 2.144411357441029 * (X ^ X ^ Y ^ Y ^ Y ^ Y ^ I ^ I) \ - + 2.144411357441029 * (Y ^ Y ^ Y ^ Y ^ Y ^ Y ^ I ^ I) \ - - 0.5313231250000003 * (X ^ X ^ I ^ I ^ I ^ I ^ X ^ X) \ - - 0.5313231250000003 * (Y ^ Y ^ I ^ I ^ I ^ I ^ X ^ X) \ - + 3.577026093750003 * (X ^ X ^ Z ^ I ^ I ^ I ^ X ^ X) \ - + 3.577026093750003 * (Y ^ Y ^ Z ^ I ^ I ^ I ^ X ^ X) \ - + 1.1923420312500006 * (X ^ X ^ I ^ Z ^ I ^ I ^ X ^ X) \ - + 1.1923420312500006 * (Y ^ Y ^ I ^ Z ^ I ^ I ^ X ^ X) \ - - 2.505002343750002 * (X ^ X ^ I ^ I ^ Z ^ I ^ X ^ X) \ - - 2.505002343750002 * (Y ^ Y ^ I ^ I ^ Z ^ I ^ X ^ X) \ - - 0.8350007812500007 * (X ^ X ^ I ^ I ^ I ^ Z ^ X ^ X) \ - - 0.8350007812500007 * (Y ^ Y ^ I ^ I ^ I ^ Z ^ X ^ X) \ - - 0.5313231250000003 * (X ^ X ^ I ^ I ^ I ^ I ^ Y ^ Y) \ - - 0.5313231250000003 * (Y ^ Y ^ I ^ I ^ I ^ I ^ Y ^ Y) \ - + 3.577026093750003 * (X ^ X ^ Z ^ I ^ I ^ I ^ Y ^ Y) \ - + 3.577026093750003 * (Y ^ Y ^ Z ^ I ^ I ^ I ^ Y ^ Y) \ - + 1.1923420312500006 * (X ^ X ^ I ^ Z ^ I ^ I ^ Y ^ Y) \ - + 1.1923420312500006 * (Y ^ Y ^ I ^ Z ^ I ^ I ^ Y ^ Y) \ - - 2.505002343750002 * (X ^ X ^ I ^ I ^ Z ^ I ^ Y ^ Y) \ - - 2.505002343750002 * (Y ^ Y ^ I ^ I ^ Z ^ I ^ Y ^ Y) \ - - 0.8350007812500007 * (X ^ X ^ I ^ I ^ I ^ Z ^ Y ^ Y) \ - - 0.8350007812500007 * (Y ^ Y ^ I ^ I ^ I ^ Z ^ Y ^ Y) \ - + 0.29708968750000064 * (I ^ I ^ X ^ X ^ I ^ I ^ X ^ X) \ - - 2.0000971875000015 * (Z ^ I ^ X ^ X ^ I ^ I ^ X ^ X) \ - - 0.6666990625000003 * (I ^ Z ^ X ^ X ^ I ^ I ^ X ^ X) \ - + 0.29708968750000064 * (I ^ I ^ Y ^ Y ^ I ^ I ^ X ^ X) \ - - 2.0000971875000015 * (Z ^ I ^ Y ^ Y ^ I ^ I ^ X ^ X) \ - - 0.6666990625000003 * (I ^ Z ^ Y ^ Y ^ I ^ I ^ X ^ X) \ - + 1.4006742187500012 * (I ^ I ^ X ^ X ^ Z ^ I ^ X ^ X) \ - + 1.4006742187500012 * (I ^ I ^ Y ^ Y ^ Z ^ I ^ X ^ X) \ - + 0.4668914062500003 * (I ^ I ^ X ^ X ^ I ^ Z ^ X ^ X) \ - + 0.4668914062500003 * (I ^ I ^ Y ^ Y ^ I ^ Z ^ X ^ X) \ - + 0.29708968750000064 * (I ^ I ^ X ^ X ^ I ^ I ^ Y ^ Y) \ - - 2.0000971875000015 * (Z ^ I ^ X ^ X ^ I ^ I ^ Y ^ Y) \ - - 0.6666990625000003 * (I ^ Z ^ X ^ X ^ I ^ I ^ Y ^ Y) \ - + 0.29708968750000064 * (I ^ I ^ Y ^ Y ^ I ^ I ^ Y ^ Y) \ - - 2.0000971875000015 * (Z ^ I ^ Y ^ Y ^ I ^ I ^ Y ^ Y) \ - - 0.6666990625000003 * (I ^ Z ^ Y ^ Y ^ I ^ I ^ Y ^ Y) \ - + 1.4006742187500012 * (I ^ I ^ X ^ X ^ Z ^ I ^ Y ^ Y) \ - + 1.4006742187500012 * (I ^ I ^ Y ^ Y ^ Z ^ I ^ Y ^ Y) \ - + 0.4668914062500003 * (I ^ I ^ X ^ X ^ I ^ Z ^ Y ^ Y) \ - + 0.4668914062500003 * (I ^ I ^ Y ^ Y ^ I ^ Z ^ Y ^ Y) \ - - 9.839626415157296 * (X ^ X ^ I ^ I ^ X ^ X ^ X ^ X) \ - - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ X ^ X ^ X ^ X) \ - - 9.839626415157296 * (X ^ X ^ I ^ I ^ Y ^ Y ^ X ^ X) \ - - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ Y ^ Y ^ X ^ X) \ - - 9.839626415157296 * (X ^ X ^ I ^ I ^ X ^ X ^ Y ^ Y) \ - - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ X ^ X ^ Y ^ Y) \ - - 9.839626415157296 * (X ^ X ^ I ^ I ^ Y ^ Y ^ Y ^ Y) \ - - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ Y ^ Y ^ Y ^ Y) \ - + 5.501835671794594 * (I ^ I ^ X ^ X ^ X ^ X ^ X ^ X) \ - + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ X ^ X ^ X ^ X) \ - + 5.501835671794594 * (I ^ I ^ X ^ X ^ Y ^ Y ^ X ^ X) \ - + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ Y ^ Y ^ X ^ X) \ - + 5.501835671794594 * (I ^ I ^ X ^ X ^ X ^ X ^ Y ^ Y) \ - + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ X ^ X ^ Y ^ Y) \ - + 5.501835671794594 * (I ^ I ^ X ^ X ^ Y ^ Y ^ Y ^ Y) \ +REFERENCE = ( + 5077.236560625012 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + - 472.28961593750034 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + - 157.22939093749991 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) + - 467.5058515625001 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + - 1.2397992187500007 * (Z ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + - 0.4132664062500002 * (I ^ Z ^ Z ^ I ^ I ^ I ^ I ^ I) + - 155.20426031249983 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + - 0.4132664062500002 * (Z ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + - 0.13775546875000005 * (I ^ Z ^ I ^ Z ^ I ^ I ^ I ^ I) + - 1027.4430731249997 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) + - 3.7889535937500023 * (Z ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) + - 1.2629845312500008 * (I ^ Z ^ I ^ I ^ Z ^ I ^ I ^ I) + - 5.772877031250004 * (I ^ I ^ Z ^ I ^ Z ^ I ^ I ^ I) + - 1.9242923437500008 * (I ^ I ^ I ^ Z ^ Z ^ I ^ I ^ I) + - 342.04261812500033 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) + - 1.2629845312500005 * (Z ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) + - 0.42099484375000024 * (I ^ Z ^ I ^ I ^ I ^ Z ^ I ^ I) + - 1.924292343750001 * (I ^ I ^ Z ^ I ^ I ^ Z ^ I ^ I) + - 0.6414307812500002 * (I ^ I ^ I ^ Z ^ I ^ Z ^ I ^ I) + - 1810.6538965625004 * (I ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) + - 10.340644218750004 * (Z ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) + - 3.4468814062500015 * (I ^ Z ^ I ^ I ^ I ^ I ^ Z ^ I) + - 14.366345625000008 * (I ^ I ^ Z ^ I ^ I ^ I ^ Z ^ I) + - 4.788781875000002 * (I ^ I ^ I ^ Z ^ I ^ I ^ Z ^ I) + + 11.339220937500007 * (I ^ I ^ I ^ I ^ Z ^ I ^ Z ^ I) + + 3.779740312500002 * (I ^ I ^ I ^ I ^ I ^ Z ^ Z ^ I) + - 601.9000340624999 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) + - 3.4468814062500015 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) + - 1.1489604687500004 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ Z) + - 4.788781875000002 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ Z) + - 1.5962606250000009 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ Z) + + 3.779740312500002 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ Z) + + 1.2599134375000005 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ Z) + - 2.358922187500002 * (X ^ X ^ X ^ X ^ I ^ I ^ I ^ I) + - 2.358922187500002 * (Y ^ Y ^ X ^ X ^ I ^ I ^ I ^ I) + - 2.358922187500002 * (X ^ X ^ Y ^ Y ^ I ^ I ^ I ^ I) + - 2.358922187500002 * (Y ^ Y ^ Y ^ Y ^ I ^ I ^ I ^ I) + + 1.0759307812500005 * (X ^ X ^ X ^ X ^ Z ^ I ^ I ^ I) + + 1.0759307812500005 * (Y ^ Y ^ X ^ X ^ Z ^ I ^ I ^ I) + + 1.0759307812500005 * (X ^ X ^ Y ^ Y ^ Z ^ I ^ I ^ I) + + 1.0759307812500005 * (Y ^ Y ^ Y ^ Y ^ Z ^ I ^ I ^ I) + + 0.35864359375000016 * (X ^ X ^ X ^ X ^ I ^ Z ^ I ^ I) + + 0.35864359375000016 * (Y ^ Y ^ X ^ X ^ I ^ Z ^ I ^ I) + + 0.35864359375000016 * (X ^ X ^ Y ^ Y ^ I ^ Z ^ I ^ I) + + 0.35864359375000016 * (Y ^ Y ^ Y ^ Y ^ I ^ Z ^ I ^ I) + + 2.183239218750001 * (X ^ X ^ X ^ X ^ I ^ I ^ Z ^ I) + + 2.183239218750001 * (Y ^ Y ^ X ^ X ^ I ^ I ^ Z ^ I) + + 2.183239218750001 * (X ^ X ^ Y ^ Y ^ I ^ I ^ Z ^ I) + + 2.183239218750001 * (Y ^ Y ^ Y ^ Y ^ I ^ I ^ Z ^ I) + + 0.7277464062500004 * (X ^ X ^ X ^ X ^ I ^ I ^ I ^ Z) + + 0.7277464062500004 * (Y ^ Y ^ X ^ X ^ I ^ I ^ I ^ Z) + + 0.7277464062500004 * (X ^ X ^ Y ^ Y ^ I ^ I ^ I ^ Z) + + 0.7277464062500004 * (Y ^ Y ^ Y ^ Y ^ I ^ I ^ I ^ Z) + - 84.41897986727398 * (I ^ I ^ I ^ I ^ X ^ X ^ I ^ I) + - 4.809566200586032 * (Z ^ I ^ I ^ I ^ X ^ X ^ I ^ I) + - 1.6031887335286772 * (I ^ Z ^ I ^ I ^ X ^ X ^ I ^ I) + - 16.233724778792137 * (I ^ I ^ Z ^ I ^ X ^ X ^ I ^ I) + - 5.411241592930711 * (I ^ I ^ I ^ Z ^ X ^ X ^ I ^ I) + - 84.41897986727398 * (I ^ I ^ I ^ I ^ Y ^ Y ^ I ^ I) + - 4.809566200586032 * (Z ^ I ^ I ^ I ^ Y ^ Y ^ I ^ I) + - 1.6031887335286772 * (I ^ Z ^ I ^ I ^ Y ^ Y ^ I ^ I) + - 16.233724778792137 * (I ^ I ^ Z ^ I ^ Y ^ Y ^ I ^ I) + - 5.411241592930711 * (I ^ I ^ I ^ Z ^ Y ^ Y ^ I ^ I) + + 66.81814897987134 * (I ^ I ^ I ^ I ^ X ^ X ^ Z ^ I) + + 66.81814897987134 * (I ^ I ^ I ^ I ^ Y ^ Y ^ Z ^ I) + + 22.272716326623776 * (I ^ I ^ I ^ I ^ X ^ X ^ I ^ Z) + + 22.272716326623776 * (I ^ I ^ I ^ I ^ Y ^ Y ^ I ^ Z) + + 2.144411357441029 * (X ^ X ^ X ^ X ^ X ^ X ^ I ^ I) + + 2.144411357441029 * (Y ^ Y ^ X ^ X ^ X ^ X ^ I ^ I) + + 2.144411357441029 * (X ^ X ^ Y ^ Y ^ X ^ X ^ I ^ I) + + 2.144411357441029 * (Y ^ Y ^ Y ^ Y ^ X ^ X ^ I ^ I) + + 2.144411357441029 * (X ^ X ^ X ^ X ^ Y ^ Y ^ I ^ I) + + 2.144411357441029 * (Y ^ Y ^ X ^ X ^ Y ^ Y ^ I ^ I) + + 2.144411357441029 * (X ^ X ^ Y ^ Y ^ Y ^ Y ^ I ^ I) + + 2.144411357441029 * (Y ^ Y ^ Y ^ Y ^ Y ^ Y ^ I ^ I) + - 0.5313231250000003 * (X ^ X ^ I ^ I ^ I ^ I ^ X ^ X) + - 0.5313231250000003 * (Y ^ Y ^ I ^ I ^ I ^ I ^ X ^ X) + + 3.577026093750003 * (X ^ X ^ Z ^ I ^ I ^ I ^ X ^ X) + + 3.577026093750003 * (Y ^ Y ^ Z ^ I ^ I ^ I ^ X ^ X) + + 1.1923420312500006 * (X ^ X ^ I ^ Z ^ I ^ I ^ X ^ X) + + 1.1923420312500006 * (Y ^ Y ^ I ^ Z ^ I ^ I ^ X ^ X) + - 2.505002343750002 * (X ^ X ^ I ^ I ^ Z ^ I ^ X ^ X) + - 2.505002343750002 * (Y ^ Y ^ I ^ I ^ Z ^ I ^ X ^ X) + - 0.8350007812500007 * (X ^ X ^ I ^ I ^ I ^ Z ^ X ^ X) + - 0.8350007812500007 * (Y ^ Y ^ I ^ I ^ I ^ Z ^ X ^ X) + - 0.5313231250000003 * (X ^ X ^ I ^ I ^ I ^ I ^ Y ^ Y) + - 0.5313231250000003 * (Y ^ Y ^ I ^ I ^ I ^ I ^ Y ^ Y) + + 3.577026093750003 * (X ^ X ^ Z ^ I ^ I ^ I ^ Y ^ Y) + + 3.577026093750003 * (Y ^ Y ^ Z ^ I ^ I ^ I ^ Y ^ Y) + + 1.1923420312500006 * (X ^ X ^ I ^ Z ^ I ^ I ^ Y ^ Y) + + 1.1923420312500006 * (Y ^ Y ^ I ^ Z ^ I ^ I ^ Y ^ Y) + - 2.505002343750002 * (X ^ X ^ I ^ I ^ Z ^ I ^ Y ^ Y) + - 2.505002343750002 * (Y ^ Y ^ I ^ I ^ Z ^ I ^ Y ^ Y) + - 0.8350007812500007 * (X ^ X ^ I ^ I ^ I ^ Z ^ Y ^ Y) + - 0.8350007812500007 * (Y ^ Y ^ I ^ I ^ I ^ Z ^ Y ^ Y) + + 0.29708968750000064 * (I ^ I ^ X ^ X ^ I ^ I ^ X ^ X) + - 2.0000971875000015 * (Z ^ I ^ X ^ X ^ I ^ I ^ X ^ X) + - 0.6666990625000003 * (I ^ Z ^ X ^ X ^ I ^ I ^ X ^ X) + + 0.29708968750000064 * (I ^ I ^ Y ^ Y ^ I ^ I ^ X ^ X) + - 2.0000971875000015 * (Z ^ I ^ Y ^ Y ^ I ^ I ^ X ^ X) + - 0.6666990625000003 * (I ^ Z ^ Y ^ Y ^ I ^ I ^ X ^ X) + + 1.4006742187500012 * (I ^ I ^ X ^ X ^ Z ^ I ^ X ^ X) + + 1.4006742187500012 * (I ^ I ^ Y ^ Y ^ Z ^ I ^ X ^ X) + + 0.4668914062500003 * (I ^ I ^ X ^ X ^ I ^ Z ^ X ^ X) + + 0.4668914062500003 * (I ^ I ^ Y ^ Y ^ I ^ Z ^ X ^ X) + + 0.29708968750000064 * (I ^ I ^ X ^ X ^ I ^ I ^ Y ^ Y) + - 2.0000971875000015 * (Z ^ I ^ X ^ X ^ I ^ I ^ Y ^ Y) + - 0.6666990625000003 * (I ^ Z ^ X ^ X ^ I ^ I ^ Y ^ Y) + + 0.29708968750000064 * (I ^ I ^ Y ^ Y ^ I ^ I ^ Y ^ Y) + - 2.0000971875000015 * (Z ^ I ^ Y ^ Y ^ I ^ I ^ Y ^ Y) + - 0.6666990625000003 * (I ^ Z ^ Y ^ Y ^ I ^ I ^ Y ^ Y) + + 1.4006742187500012 * (I ^ I ^ X ^ X ^ Z ^ I ^ Y ^ Y) + + 1.4006742187500012 * (I ^ I ^ Y ^ Y ^ Z ^ I ^ Y ^ Y) + + 0.4668914062500003 * (I ^ I ^ X ^ X ^ I ^ Z ^ Y ^ Y) + + 0.4668914062500003 * (I ^ I ^ Y ^ Y ^ I ^ Z ^ Y ^ Y) + - 9.839626415157296 * (X ^ X ^ I ^ I ^ X ^ X ^ X ^ X) + - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ X ^ X ^ X ^ X) + - 9.839626415157296 * (X ^ X ^ I ^ I ^ Y ^ Y ^ X ^ X) + - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ Y ^ Y ^ X ^ X) + - 9.839626415157296 * (X ^ X ^ I ^ I ^ X ^ X ^ Y ^ Y) + - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ X ^ X ^ Y ^ Y) + - 9.839626415157296 * (X ^ X ^ I ^ I ^ Y ^ Y ^ Y ^ Y) + - 9.839626415157296 * (Y ^ Y ^ I ^ I ^ Y ^ Y ^ Y ^ Y) + + 5.501835671794594 * (I ^ I ^ X ^ X ^ X ^ X ^ X ^ X) + + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ X ^ X ^ X ^ X) + + 5.501835671794594 * (I ^ I ^ X ^ X ^ Y ^ Y ^ X ^ X) + + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ Y ^ Y ^ X ^ X) + + 5.501835671794594 * (I ^ I ^ X ^ X ^ X ^ X ^ Y ^ Y) + + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ X ^ X ^ Y ^ Y) + + 5.501835671794594 * (I ^ I ^ X ^ X ^ Y ^ Y ^ Y ^ Y) + 5.501835671794594 * (I ^ I ^ Y ^ Y ^ Y ^ Y ^ Y ^ Y) +) diff --git a/test/mappers/second_quantization/test_bravyi_kitaev_mapper.py b/test/mappers/second_quantization/test_bravyi_kitaev_mapper.py index b0687d3105..9f66cf925e 100644 --- a/test/mappers/second_quantization/test_bravyi_kitaev_mapper.py +++ b/test/mappers/second_quantization/test_bravyi_kitaev_mapper.py @@ -20,33 +20,37 @@ from qiskit_nature.drivers import HDF5Driver from qiskit_nature.mappers.second_quantization import BravyiKitaevMapper -from qiskit_nature.problems.second_quantization.electronic.builders import fermionic_op_builder +from qiskit_nature.problems.second_quantization.electronic.builders import ( + fermionic_op_builder, +) class TestBravyiKitaevMapper(QiskitNatureTestCase): - """ Test Bravyi-Kitaev Mapper """ + """Test Bravyi-Kitaev Mapper""" - REF_H2 = \ - - 0.81054798160031430 * (I ^ I ^ I ^ I) \ - + 0.17218393211855787 * (I ^ Z ^ I ^ I) \ - + 0.12091263243164174 * (I ^ I ^ Z ^ I) \ - + 0.12091263243164174 * (Z ^ I ^ Z ^ I) \ - - 0.22575349071287365 * (Z ^ Z ^ Z ^ I) \ - + 0.17218393211855818 * (I ^ I ^ I ^ Z) \ - + 0.16892753854646372 * (I ^ Z ^ I ^ Z) \ - + 0.17464343053355980 * (Z ^ Z ^ I ^ Z) \ - - 0.22575349071287362 * (I ^ I ^ Z ^ Z) \ - + 0.16614543242281926 * (I ^ Z ^ Z ^ Z) \ - + 0.16614543242281926 * (Z ^ Z ^ Z ^ Z) \ - + 0.04523279999117751 * (I ^ X ^ I ^ X) \ - + 0.04523279999117751 * (Z ^ X ^ I ^ X) \ - - 0.04523279999117751 * (I ^ X ^ Z ^ X) \ + REF_H2 = ( + -0.81054798160031430 * (I ^ I ^ I ^ I) + + 0.17218393211855787 * (I ^ Z ^ I ^ I) + + 0.12091263243164174 * (I ^ I ^ Z ^ I) + + 0.12091263243164174 * (Z ^ I ^ Z ^ I) + - 0.22575349071287365 * (Z ^ Z ^ Z ^ I) + + 0.17218393211855818 * (I ^ I ^ I ^ Z) + + 0.16892753854646372 * (I ^ Z ^ I ^ Z) + + 0.17464343053355980 * (Z ^ Z ^ I ^ Z) + - 0.22575349071287362 * (I ^ I ^ Z ^ Z) + + 0.16614543242281926 * (I ^ Z ^ Z ^ Z) + + 0.16614543242281926 * (Z ^ Z ^ Z ^ Z) + + 0.04523279999117751 * (I ^ X ^ I ^ X) + + 0.04523279999117751 * (Z ^ X ^ I ^ X) + - 0.04523279999117751 * (I ^ X ^ Z ^ X) - 0.04523279999117751 * (Z ^ X ^ Z ^ X) + ) def test_mapping(self): - """ Test mapping to qubit operator """ - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + """Test mapping to qubit operator""" + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) q_molecule = driver.run() fermionic_op = fermionic_op_builder._build_fermionic_op(q_molecule) mapper = BravyiKitaevMapper() @@ -60,10 +64,10 @@ def test_mapping(self): self.assertEqual(qubit_op, TestBravyiKitaevMapper.REF_H2) def test_allows_two_qubit_reduction(self): - """ Test this returns False for this mapper """ + """Test this returns False for this mapper""" mapper = BravyiKitaevMapper() self.assertFalse(mapper.allows_two_qubit_reduction) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/mappers/second_quantization/test_direct_mapper.py b/test/mappers/second_quantization/test_direct_mapper.py index d01773e8db..0bb7649cad 100644 --- a/test/mappers/second_quantization/test_direct_mapper.py +++ b/test/mappers/second_quantization/test_direct_mapper.py @@ -19,18 +19,22 @@ from qiskit_nature.drivers import GaussianForcesDriver from qiskit_nature.mappers.second_quantization import DirectMapper -from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_op_builder import \ - _build_vibrational_op +from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_op_builder import ( + _build_vibrational_op, +) class TestDirectMapper(QiskitNatureTestCase): - """ Test Direct Mapper """ + """Test Direct Mapper""" def test_mapping(self): - """ Test mapping to qubit operator """ - driver = GaussianForcesDriver(logfile=self.get_resource_path( - 'CO2_freq_B3LYP_ccpVDZ.log', 'problems/second_quantization/vibrational/resources' - )) + """Test mapping to qubit operator""" + driver = GaussianForcesDriver( + logfile=self.get_resource_path( + "CO2_freq_B3LYP_ccpVDZ.log", + "problems/second_quantization/vibrational/resources", + ) + ) watson_hamiltonian = driver.run() num_modals = 2 @@ -44,10 +48,10 @@ def test_mapping(self): self.assertEqual(qubit_op, REFERENCE) def test_allows_two_qubit_reduction(self): - """ Test this returns False for this mapper """ + """Test this returns False for this mapper""" mapper = DirectMapper() self.assertFalse(mapper.allows_two_qubit_reduction) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/mappers/second_quantization/test_jordan_wigner_mapper.py b/test/mappers/second_quantization/test_jordan_wigner_mapper.py index 67dec569e5..5d739e838a 100644 --- a/test/mappers/second_quantization/test_jordan_wigner_mapper.py +++ b/test/mappers/second_quantization/test_jordan_wigner_mapper.py @@ -20,33 +20,37 @@ from qiskit_nature.drivers import HDF5Driver from qiskit_nature.mappers.second_quantization import JordanWignerMapper -from qiskit_nature.problems.second_quantization.electronic.builders import fermionic_op_builder +from qiskit_nature.problems.second_quantization.electronic.builders import ( + fermionic_op_builder, +) class TestJordanWignerMapper(QiskitNatureTestCase): - """ Test Jordan Wigner Mapper """ + """Test Jordan Wigner Mapper""" - REF_H2 = \ - - 0.81054798160031430 * (I ^ I ^ I ^ I) \ - - 0.22575349071287365 * (Z ^ I ^ I ^ I) \ - + 0.17218393211855787 * (I ^ Z ^ I ^ I) \ - + 0.12091263243164174 * (Z ^ Z ^ I ^ I) \ - - 0.22575349071287362 * (I ^ I ^ Z ^ I) \ - + 0.17464343053355980 * (Z ^ I ^ Z ^ I) \ - + 0.16614543242281926 * (I ^ Z ^ Z ^ I) \ - + 0.17218393211855818 * (I ^ I ^ I ^ Z) \ - + 0.16614543242281926 * (Z ^ I ^ I ^ Z) \ - + 0.16892753854646372 * (I ^ Z ^ I ^ Z) \ - + 0.12091263243164174 * (I ^ I ^ Z ^ Z) \ - + 0.04523279999117751 * (X ^ X ^ X ^ X) \ - + 0.04523279999117751 * (Y ^ Y ^ X ^ X) \ - + 0.04523279999117751 * (X ^ X ^ Y ^ Y) \ + REF_H2 = ( + -0.81054798160031430 * (I ^ I ^ I ^ I) + - 0.22575349071287365 * (Z ^ I ^ I ^ I) + + 0.17218393211855787 * (I ^ Z ^ I ^ I) + + 0.12091263243164174 * (Z ^ Z ^ I ^ I) + - 0.22575349071287362 * (I ^ I ^ Z ^ I) + + 0.17464343053355980 * (Z ^ I ^ Z ^ I) + + 0.16614543242281926 * (I ^ Z ^ Z ^ I) + + 0.17218393211855818 * (I ^ I ^ I ^ Z) + + 0.16614543242281926 * (Z ^ I ^ I ^ Z) + + 0.16892753854646372 * (I ^ Z ^ I ^ Z) + + 0.12091263243164174 * (I ^ I ^ Z ^ Z) + + 0.04523279999117751 * (X ^ X ^ X ^ X) + + 0.04523279999117751 * (Y ^ Y ^ X ^ X) + + 0.04523279999117751 * (X ^ X ^ Y ^ Y) + 0.04523279999117751 * (Y ^ Y ^ Y ^ Y) + ) def test_mapping(self): - """ Test mapping to qubit operator """ - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + """Test mapping to qubit operator""" + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) q_molecule = driver.run() fermionic_op = fermionic_op_builder._build_fermionic_op(q_molecule) mapper = JordanWignerMapper() @@ -60,10 +64,10 @@ def test_mapping(self): self.assertEqual(qubit_op, TestJordanWignerMapper.REF_H2) def test_allows_two_qubit_reduction(self): - """ Test this returns False for this mapper """ + """Test this returns False for this mapper""" mapper = JordanWignerMapper() self.assertFalse(mapper.allows_two_qubit_reduction) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/mappers/second_quantization/test_linear_mapper.py b/test/mappers/second_quantization/test_linear_mapper.py index 0224ead2ee..edfe1b4e33 100644 --- a/test/mappers/second_quantization/test_linear_mapper.py +++ b/test/mappers/second_quantization/test_linear_mapper.py @@ -25,36 +25,44 @@ @ddt class TestLinearMapper(QiskitNatureTestCase): - """ Test Linear Mapper """ + """Test Linear Mapper""" - spin_op1 = SpinOp([('Y_0^2', -0.432 + 1.32j)], 0.5, 1) + spin_op1 = SpinOp([("Y_0^2", -0.432 + 1.32j)], 0.5, 1) ref_qubit_op1 = (-0.054 + 0.165j) * (I ^ I) + (0.054 - 0.165j) * (Z ^ Z) - spin_op2 = SpinOp([('X_0 Z_0 I_1', -1.139 + 0.083j)], 0.5, 2) - ref_qubit_op2 = (0.010375 + 0.142375j) * (I ^ I ^ Y ^ X) + \ - (-0.010375 - 0.142375j) * (I ^ I ^ X ^ Y) + spin_op2 = SpinOp([("X_0 Z_0 I_1", -1.139 + 0.083j)], 0.5, 2) + ref_qubit_op2 = (0.010375 + 0.142375j) * (I ^ I ^ Y ^ X) + ( + -0.010375 - 0.142375j + ) * (I ^ I ^ X ^ Y) - spin_op3 = SpinOp([('X_0 Y_0^2 Z_0 X_1 Y_1 Y_2 Z_2', -0.18 + 1.204j)], 0.5, 3) - ref_qubit_op3 = (0.000587890625 + 8.7890625e-05j) * (Y ^ Y ^ I ^ Z ^ Y ^ X) + \ - (0.000587890625 + 8.7890625e-05j) * (X ^ X ^ I ^ Z ^ Y ^ X) + \ - (-0.000587890625 - 8.7890625e-05j) * (Y ^ Y ^ Z ^ I ^ Y ^ X) + \ - (-0.000587890625 - 8.7890625e-05j) * (X ^ X ^ Z ^ I ^ Y ^ X) + \ - (-0.000587890625 - 8.7890625e-05j) * (Y ^ Y ^ I ^ Z ^ X ^ Y) + \ - (-0.000587890625 - 8.7890625e-05j) * (X ^ X ^ I ^ Z ^ X ^ Y) + \ - (0.000587890625 + 8.7890625e-05j) * (Y ^ Y ^ Z ^ I ^ X ^ Y) + \ - (0.000587890625 + 8.7890625e-05j) * (X ^ X ^ Z ^ I ^ X ^ Y) + spin_op3 = SpinOp([("X_0 Y_0^2 Z_0 X_1 Y_1 Y_2 Z_2", -0.18 + 1.204j)], 0.5, 3) + ref_qubit_op3 = ( + (0.000587890625 + 8.7890625e-05j) * (Y ^ Y ^ I ^ Z ^ Y ^ X) + + (0.000587890625 + 8.7890625e-05j) * (X ^ X ^ I ^ Z ^ Y ^ X) + + (-0.000587890625 - 8.7890625e-05j) * (Y ^ Y ^ Z ^ I ^ Y ^ X) + + (-0.000587890625 - 8.7890625e-05j) * (X ^ X ^ Z ^ I ^ Y ^ X) + + (-0.000587890625 - 8.7890625e-05j) * (Y ^ Y ^ I ^ Z ^ X ^ Y) + + (-0.000587890625 - 8.7890625e-05j) * (X ^ X ^ I ^ Z ^ X ^ Y) + + (0.000587890625 + 8.7890625e-05j) * (Y ^ Y ^ Z ^ I ^ X ^ Y) + + (0.000587890625 + 8.7890625e-05j) * (X ^ X ^ Z ^ I ^ X ^ Y) + ) - spin_op4 = SpinOp([('I_0 Z_1', -0.875 - 0.075j)], 1.5, 2) - ref_qubit_op4 = (-0.65625 - 0.05625j) * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + \ - (-0.21875 - 0.01875j) * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) + \ - (0.21875 + 0.01875j) * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + \ - (0.65625 + 0.05625j) * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + spin_op4 = SpinOp([("I_0 Z_1", -0.875 - 0.075j)], 1.5, 2) + ref_qubit_op4 = ( + (-0.65625 - 0.05625j) * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + + (-0.21875 - 0.01875j) * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) + + (0.21875 + 0.01875j) * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + + (0.65625 + 0.05625j) * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + ) - spin_op5 = SpinOp([('X_0 I_1 I_2 I_3 I_4 I_5 I_6 I_7', 4 + 0j)], 0.5, 8) + \ - SpinOp([('I_0^2 I_2 I_3 I_4 I_5 I_6 I_7 I_8', 8 + 0j)], 0.5, 8) - ref_qubit_op5 = (8.0 + 0j) * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + \ - (1.0 + 0j) * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ X ^ X) + \ - (1.0 + 0j) * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ Y ^ Y) + spin_op5 = SpinOp([("X_0 I_1 I_2 I_3 I_4 I_5 I_6 I_7", 4 + 0j)], 0.5, 8) + SpinOp( + [("I_0^2 I_2 I_3 I_4 I_5 I_6 I_7 I_8", 8 + 0j)], 0.5, 8 + ) + ref_qubit_op5 = ( + (8.0 + 0j) * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + + (1.0 + 0j) * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ X ^ X) + + (1.0 + 0j) * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ Y ^ Y) + ) @data( (spin_op1, ref_qubit_op1), @@ -65,11 +73,11 @@ class TestLinearMapper(QiskitNatureTestCase): ) @unpack def test_mapping(self, spin_op, ref_qubit_op): - """ Test mapping to qubit operator """ + """Test mapping to qubit operator""" mapper = LinearMapper() qubit_op = mapper.map(spin_op) self.assertEqual(qubit_op, ref_qubit_op) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/mappers/second_quantization/test_parity_mapper.py b/test/mappers/second_quantization/test_parity_mapper.py index 1e1de5938b..4354050183 100644 --- a/test/mappers/second_quantization/test_parity_mapper.py +++ b/test/mappers/second_quantization/test_parity_mapper.py @@ -20,33 +20,37 @@ from qiskit_nature.drivers import HDF5Driver from qiskit_nature.mappers.second_quantization import ParityMapper -from qiskit_nature.problems.second_quantization.electronic.builders import fermionic_op_builder +from qiskit_nature.problems.second_quantization.electronic.builders import ( + fermionic_op_builder, +) class TestParityMapper(QiskitNatureTestCase): - """ Test Parity Mapper """ + """Test Parity Mapper""" - REF_H2 = \ - - 0.81054798160031430 * (I ^ I ^ I ^ I) \ - - 0.22575349071287365 * (Z ^ Z ^ I ^ I) \ - + 0.12091263243164174 * (I ^ I ^ Z ^ I) \ - + 0.12091263243164174 * (Z ^ I ^ Z ^ I) \ - + 0.17218393211855787 * (I ^ Z ^ Z ^ I) \ - + 0.17218393211855818 * (I ^ I ^ I ^ Z) \ - + 0.16614543242281926 * (I ^ Z ^ I ^ Z) \ - + 0.16614543242281926 * (Z ^ Z ^ I ^ Z) \ - - 0.22575349071287362 * (I ^ I ^ Z ^ Z) \ - + 0.16892753854646372 * (I ^ Z ^ Z ^ Z) \ - + 0.17464343053355980 * (Z ^ Z ^ Z ^ Z) \ - + 0.04523279999117751 * (I ^ X ^ I ^ X) \ - + 0.04523279999117751 * (Z ^ X ^ I ^ X) \ - - 0.04523279999117751 * (I ^ X ^ Z ^ X) \ + REF_H2 = ( + -0.81054798160031430 * (I ^ I ^ I ^ I) + - 0.22575349071287365 * (Z ^ Z ^ I ^ I) + + 0.12091263243164174 * (I ^ I ^ Z ^ I) + + 0.12091263243164174 * (Z ^ I ^ Z ^ I) + + 0.17218393211855787 * (I ^ Z ^ Z ^ I) + + 0.17218393211855818 * (I ^ I ^ I ^ Z) + + 0.16614543242281926 * (I ^ Z ^ I ^ Z) + + 0.16614543242281926 * (Z ^ Z ^ I ^ Z) + - 0.22575349071287362 * (I ^ I ^ Z ^ Z) + + 0.16892753854646372 * (I ^ Z ^ Z ^ Z) + + 0.17464343053355980 * (Z ^ Z ^ Z ^ Z) + + 0.04523279999117751 * (I ^ X ^ I ^ X) + + 0.04523279999117751 * (Z ^ X ^ I ^ X) + - 0.04523279999117751 * (I ^ X ^ Z ^ X) - 0.04523279999117751 * (Z ^ X ^ Z ^ X) + ) def test_mapping(self): - """ Test mapping to qubit operator """ - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + """Test mapping to qubit operator""" + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) q_molecule = driver.run() fermionic_op = fermionic_op_builder._build_fermionic_op(q_molecule) mapper = ParityMapper() @@ -60,10 +64,10 @@ def test_mapping(self): self.assertEqual(qubit_op, TestParityMapper.REF_H2) def test_allows_two_qubit_reduction(self): - """ Test this returns True for this mapper """ + """Test this returns True for this mapper""" mapper = ParityMapper() self.assertTrue(mapper.allows_two_qubit_reduction) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/nature_test_case.py b/test/nature_test_case.py index e03c6e7fe3..427068f54c 100644 --- a/test/nature_test_case.py +++ b/test/nature_test_case.py @@ -40,15 +40,15 @@ class QiskitNatureTestCase(unittest.TestCase, ABC): log = None def setUp(self) -> None: - warnings.filterwarnings('default', category=DeprecationWarning) - warnings.filterwarnings('ignore', category=DeprecationWarning, module='pyscf') + warnings.filterwarnings("default", category=DeprecationWarning) + warnings.filterwarnings("ignore", category=DeprecationWarning, module="pyscf") self._started_at = time.time() self._class_location = __file__ def tearDown(self) -> None: elapsed = time.time() - self._started_at if elapsed > 5.0: - print('({:.2f}s)'.format(round(elapsed, 2)), flush=True) + print("({:.2f}s)".format(round(elapsed, 2)), flush=True) @classmethod def setUpClass(cls) -> None: @@ -57,28 +57,27 @@ def setUpClass(cls) -> None: # Set logging to file and stdout if the LOG_LEVEL environment variable # is set. - if os.getenv('LOG_LEVEL'): + if os.getenv("LOG_LEVEL"): # Set up formatter. - log_fmt = ('{}.%(funcName)s:%(levelname)s:%(asctime)s:' - ' %(message)s'.format(cls.__name__)) + log_fmt = ( + "{}.%(funcName)s:%(levelname)s:%(asctime)s:" + " %(message)s".format(cls.__name__) + ) formatter = logging.Formatter(log_fmt) # Set up the file handler. - log_file_name = '%s.log' % cls.moduleName + log_file_name = "%s.log" % cls.moduleName file_handler = logging.FileHandler(log_file_name) file_handler.setFormatter(formatter) cls.log.addHandler(file_handler) # Set the logging level from the environment variable, defaulting # to INFO if it is not a valid level. - level = logging._nameToLevel.get(os.getenv('LOG_LEVEL'), - logging.INFO) + level = logging._nameToLevel.get(os.getenv("LOG_LEVEL"), logging.INFO) cls.log.setLevel(level) - def get_resource_path(self, - filename: str, - path: Optional[str] = None) -> str: - """ Get the absolute path to a resource. + def get_resource_path(self, filename: str, path: Optional[str] = None) -> str: + """Get the absolute path to a resource. Args: filename: filename or relative path to the resource. path: path used as relative to the filename. diff --git a/test/operators/second_quantization/test_fermionic_op.py b/test/operators/second_quantization/test_fermionic_op.py index 27be2db63f..81d5a134f0 100644 --- a/test/operators/second_quantization/test_fermionic_op.py +++ b/test/operators/second_quantization/test_fermionic_op.py @@ -27,7 +27,9 @@ @lru_cache(3) def dense_labels(length): """Generate list of fermion labels with given length.""" - return ["".join(label) for label in product(["I", "+", "-", "N", "E"], repeat=length)] + return [ + "".join(label) for label in product(["I", "+", "-", "N", "E"], repeat=length) + ] @lru_cache(3) @@ -76,7 +78,9 @@ def test_init(self, label, pre_processing): def test_init_sparse_label(self, labels, pre_processing): """Test __init__ with sparse label""" dense_label, sparse_label = labels - fer_op = FermionicOp(pre_processing(sparse_label), register_length=len(dense_label)) + fer_op = FermionicOp( + pre_processing(sparse_label), register_length=len(dense_label) + ) targ = FermionicOp(dense_label) self.assertFermionEqual(fer_op, targ) diff --git a/test/operators/second_quantization/test_qubit_converter.py b/test/operators/second_quantization/test_qubit_converter.py index fce9498e8d..6e3400683a 100644 --- a/test/operators/second_quantization/test_qubit_converter.py +++ b/test/operators/second_quantization/test_qubit_converter.py @@ -24,73 +24,77 @@ from qiskit_nature.mappers.second_quantization import JordanWignerMapper, ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem -from qiskit_nature.problems.second_quantization.electronic.builders import fermionic_op_builder +from qiskit_nature.problems.second_quantization.electronic.builders import ( + fermionic_op_builder, +) class TestQubitConverter(QiskitNatureTestCase): - """ Test Qubit Converter """ - - REF_H2_JW = \ - - 0.81054798160031430 * (I ^ I ^ I ^ I) \ - - 0.22575349071287365 * (Z ^ I ^ I ^ I) \ - + 0.17218393211855787 * (I ^ Z ^ I ^ I) \ - + 0.12091263243164174 * (Z ^ Z ^ I ^ I) \ - - 0.22575349071287362 * (I ^ I ^ Z ^ I) \ - + 0.17464343053355980 * (Z ^ I ^ Z ^ I) \ - + 0.16614543242281926 * (I ^ Z ^ Z ^ I) \ - + 0.17218393211855818 * (I ^ I ^ I ^ Z) \ - + 0.16614543242281926 * (Z ^ I ^ I ^ Z) \ - + 0.16892753854646372 * (I ^ Z ^ I ^ Z) \ - + 0.12091263243164174 * (I ^ I ^ Z ^ Z) \ - + 0.04523279999117751 * (X ^ X ^ X ^ X) \ - + 0.04523279999117751 * (Y ^ Y ^ X ^ X) \ - + 0.04523279999117751 * (X ^ X ^ Y ^ Y) \ + """Test Qubit Converter""" + + REF_H2_JW = ( + -0.81054798160031430 * (I ^ I ^ I ^ I) + - 0.22575349071287365 * (Z ^ I ^ I ^ I) + + 0.17218393211855787 * (I ^ Z ^ I ^ I) + + 0.12091263243164174 * (Z ^ Z ^ I ^ I) + - 0.22575349071287362 * (I ^ I ^ Z ^ I) + + 0.17464343053355980 * (Z ^ I ^ Z ^ I) + + 0.16614543242281926 * (I ^ Z ^ Z ^ I) + + 0.17218393211855818 * (I ^ I ^ I ^ Z) + + 0.16614543242281926 * (Z ^ I ^ I ^ Z) + + 0.16892753854646372 * (I ^ Z ^ I ^ Z) + + 0.12091263243164174 * (I ^ I ^ Z ^ Z) + + 0.04523279999117751 * (X ^ X ^ X ^ X) + + 0.04523279999117751 * (Y ^ Y ^ X ^ X) + + 0.04523279999117751 * (X ^ X ^ Y ^ Y) + 0.04523279999117751 * (Y ^ Y ^ Y ^ Y) - - REF_H2_PARITY = \ - - 0.81054798160031430 * (I ^ I ^ I ^ I) \ - - 0.22575349071287365 * (Z ^ Z ^ I ^ I) \ - + 0.12091263243164174 * (I ^ I ^ Z ^ I) \ - + 0.12091263243164174 * (Z ^ I ^ Z ^ I) \ - + 0.17218393211855787 * (I ^ Z ^ Z ^ I) \ - + 0.17218393211855818 * (I ^ I ^ I ^ Z) \ - + 0.16614543242281926 * (I ^ Z ^ I ^ Z) \ - + 0.16614543242281926 * (Z ^ Z ^ I ^ Z) \ - - 0.22575349071287362 * (I ^ I ^ Z ^ Z) \ - + 0.16892753854646372 * (I ^ Z ^ Z ^ Z) \ - + 0.17464343053355980 * (Z ^ Z ^ Z ^ Z) \ - + 0.04523279999117751 * (I ^ X ^ I ^ X) \ - + 0.04523279999117751 * (Z ^ X ^ I ^ X) \ - - 0.04523279999117751 * (I ^ X ^ Z ^ X) \ + ) + + REF_H2_PARITY = ( + -0.81054798160031430 * (I ^ I ^ I ^ I) + - 0.22575349071287365 * (Z ^ Z ^ I ^ I) + + 0.12091263243164174 * (I ^ I ^ Z ^ I) + + 0.12091263243164174 * (Z ^ I ^ Z ^ I) + + 0.17218393211855787 * (I ^ Z ^ Z ^ I) + + 0.17218393211855818 * (I ^ I ^ I ^ Z) + + 0.16614543242281926 * (I ^ Z ^ I ^ Z) + + 0.16614543242281926 * (Z ^ Z ^ I ^ Z) + - 0.22575349071287362 * (I ^ I ^ Z ^ Z) + + 0.16892753854646372 * (I ^ Z ^ Z ^ Z) + + 0.17464343053355980 * (Z ^ Z ^ Z ^ Z) + + 0.04523279999117751 * (I ^ X ^ I ^ X) + + 0.04523279999117751 * (Z ^ X ^ I ^ X) + - 0.04523279999117751 * (I ^ X ^ Z ^ X) - 0.04523279999117751 * (Z ^ X ^ Z ^ X) + ) - REF_H2_PARITY_2Q_REDUCED = \ - - 1.05237324646359750 * (I ^ I) \ - - 0.39793742283143140 * (Z ^ I) \ - + 0.39793742283143163 * (I ^ Z) \ - - 0.01128010423438501 * (Z ^ Z) \ + REF_H2_PARITY_2Q_REDUCED = ( + -1.05237324646359750 * (I ^ I) + - 0.39793742283143140 * (Z ^ I) + + 0.39793742283143163 * (I ^ Z) + - 0.01128010423438501 * (Z ^ Z) + 0.18093119996471000 * (X ^ X) + ) - REF_H2_JW_TAPERED = \ - - 1.04109314222921270 * I \ - - 0.79587484566286240 * Z \ - + 0.18093119996470988 * X + REF_H2_JW_TAPERED = ( + -1.04109314222921270 * I - 0.79587484566286240 * Z + 0.18093119996470988 * X + ) - REF_H2_PARITY_2Q_REDUCED_TAPER = \ - - 1.04109314222921250 * I \ - - 0.79587484566286300 * Z \ - - 0.18093119996470994 * X + REF_H2_PARITY_2Q_REDUCED_TAPER = ( + -1.04109314222921250 * I - 0.79587484566286300 * Z - 0.18093119996470994 * X + ) def setUp(self): super().setUp() - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) self.molecule = driver.run() self.num_particles = (self.molecule.num_alpha, self.molecule.num_beta) self.h2_op = fermionic_op_builder._build_fermionic_op(self.molecule) def test_mapping_basic(self): - """ Test mapping to qubit operator """ + """Test mapping to qubit operator""" mapper = JordanWignerMapper() qubit_conv = QubitConverter(mapper) qubit_op = qubit_conv.convert(self.h2_op) @@ -104,66 +108,66 @@ def test_mapping_basic(self): self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW) - with self.subTest('Re-use test'): + with self.subTest("Re-use test"): qubit_op = qubit_conv.convert(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW) - with self.subTest('convert_match()'): + with self.subTest("convert_match()"): qubit_op = qubit_conv.convert_match(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW) - with self.subTest('Re-use with different mapper'): + with self.subTest("Re-use with different mapper"): qubit_conv.mapper = ParityMapper() qubit_op = qubit_conv.convert(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY) - with self.subTest('Set two qubit reduction - no effect without num particles'): + with self.subTest("Set two qubit reduction - no effect without num particles"): qubit_conv.two_qubit_reduction = True qubit_op = qubit_conv.convert_match(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY) - with self.subTest('Force match set num particles'): + with self.subTest("Force match set num particles"): qubit_conv.force_match(self.num_particles) qubit_op = qubit_conv.convert_match(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED) def test_two_qubit_reduction(self): - """ Test mapping to qubit operator with two qubit reduction """ + """Test mapping to qubit operator with two qubit reduction""" mapper = ParityMapper() qubit_conv = QubitConverter(mapper, two_qubit_reduction=True) - with self.subTest('Two qubit reduction ignored as no num particles given'): + with self.subTest("Two qubit reduction ignored as no num particles given"): qubit_op = qubit_conv.convert(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY) self.assertIsNone(qubit_conv.num_particles) - with self.subTest('Two qubit reduction, num particles given'): + with self.subTest("Two qubit reduction, num particles given"): qubit_op = qubit_conv.convert(self.h2_op, self.num_particles) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED) self.assertEqual(qubit_conv.num_particles, self.num_particles) - with self.subTest('convert_match()'): + with self.subTest("convert_match()"): qubit_op = qubit_conv.convert_match(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED) self.assertEqual(qubit_conv.num_particles, self.num_particles) - with self.subTest('State is reset (Num particles lost)'): + with self.subTest("State is reset (Num particles lost)"): qubit_op = qubit_conv.convert(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY) self.assertIsNone(qubit_conv.num_particles) - with self.subTest('Num particles given again'): + with self.subTest("Num particles given again"): qubit_op = qubit_conv.convert(self.h2_op, self.num_particles) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED) - with self.subTest('Set for no two qubit reduction'): + with self.subTest("Set for no two qubit reduction"): qubit_conv.two_qubit_reduction = False self.assertFalse(qubit_conv.two_qubit_reduction) qubit_op = qubit_conv.convert(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY) def test_z2_symmetry(self): - """ Test mapping to qubit operator with z2 symmetry tapering """ + """Test mapping to qubit operator with z2 symmetry tapering""" z2_sector = [-1, 1, -1] def finder(z2_symmetries: Z2Symmetries) -> Optional[List[int]]: @@ -173,78 +177,100 @@ def find_none(_z2_symmetries: Z2Symmetries) -> Optional[List[int]]: return None mapper = JordanWignerMapper() - qubit_conv = QubitConverter(mapper, z2symmetry_reduction='auto') + qubit_conv = QubitConverter(mapper, z2symmetry_reduction="auto") - with self.subTest('Locator returns None, should be untapered operator'): + with self.subTest("Locator returns None, should be untapered operator"): qubit_op = qubit_conv.convert(self.h2_op, sector_locator=find_none) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW) qubit_op = qubit_conv.convert(self.h2_op, sector_locator=finder) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW_TAPERED) - with self.subTest('convert_match()'): + with self.subTest("convert_match()"): qubit_op = qubit_conv.convert_match(self.h2_op) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW_TAPERED) self.assertIsNone(qubit_conv.num_particles) self.assertListEqual(qubit_conv.z2symmetries.tapering_values, z2_sector) def test_two_qubit_reduction_and_z2_symmetry(self): - """ Test mapping to qubit operator with z2 symmetry tapering and two qubit reduction """ + """Test mapping to qubit operator with z2 symmetry tapering and two qubit reduction""" z2_sector = [-1] def finder(z2_symmetries: Z2Symmetries) -> Optional[List[int]]: return z2_sector if not z2_symmetries.is_empty() else None mapper = ParityMapper() - qubit_conv = QubitConverter(mapper, two_qubit_reduction=True, z2symmetry_reduction='auto') - qubit_op = qubit_conv.convert(self.h2_op, self.num_particles, sector_locator=finder) + qubit_conv = QubitConverter( + mapper, two_qubit_reduction=True, z2symmetry_reduction="auto" + ) + qubit_op = qubit_conv.convert( + self.h2_op, self.num_particles, sector_locator=finder + ) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER) self.assertEqual(qubit_conv.num_particles, self.num_particles) self.assertListEqual(qubit_conv.z2symmetries.tapering_values, z2_sector) - with self.subTest('convert_match()'): + with self.subTest("convert_match()"): qubit_op = qubit_conv.convert_match(self.h2_op) - self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER) + self.assertEqual( + qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER + ) self.assertEqual(qubit_conv.num_particles, self.num_particles) self.assertListEqual(qubit_conv.z2symmetries.tapering_values, z2_sector) - with self.subTest('Change setting'): + with self.subTest("Change setting"): qubit_conv.z2symmetry_reduction = [1] qubit_op = qubit_conv.convert(self.h2_op, self.num_particles) - self.assertNotEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER) + self.assertNotEqual( + qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER + ) qubit_conv.z2symmetry_reduction = [-1] qubit_op = qubit_conv.convert(self.h2_op, self.num_particles) - self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER) - - with self.subTest('Specify sector upfront'): - qubit_conv = QubitConverter(mapper, two_qubit_reduction=True, - z2symmetry_reduction=z2_sector) + self.assertEqual( + qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER + ) + + with self.subTest("Specify sector upfront"): + qubit_conv = QubitConverter( + mapper, two_qubit_reduction=True, z2symmetry_reduction=z2_sector + ) qubit_op = qubit_conv.convert(self.h2_op, self.num_particles) - self.assertEqual(qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER) + self.assertEqual( + qubit_op, TestQubitConverter.REF_H2_PARITY_2Q_REDUCED_TAPER + ) - with self.subTest('Specify sector upfront, but invalid content'): + with self.subTest("Specify sector upfront, but invalid content"): with self.assertRaises(ValueError): - _ = QubitConverter(mapper, two_qubit_reduction=True, z2symmetry_reduction=[5]) - - with self.subTest('Specify sector upfront, but invalid length'): - qubit_conv = QubitConverter(mapper, two_qubit_reduction=True, - z2symmetry_reduction=[-1, 1]) + _ = QubitConverter( + mapper, two_qubit_reduction=True, z2symmetry_reduction=[5] + ) + + with self.subTest("Specify sector upfront, but invalid length"): + qubit_conv = QubitConverter( + mapper, two_qubit_reduction=True, z2symmetry_reduction=[-1, 1] + ) with self.assertRaises(QiskitNatureError): _ = qubit_conv.convert(self.h2_op, self.num_particles) def test_molecular_problem_sector_locator_z2_symmetry(self): - """ Test mapping to qubit operator with z2 symmetry tapering and two qubit reduction """ + """Test mapping to qubit operator with z2 symmetry tapering and two qubit reduction""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) problem = ElectronicStructureProblem(driver) mapper = JordanWignerMapper() - qubit_conv = QubitConverter(mapper, two_qubit_reduction=True, z2symmetry_reduction='auto') - qubit_op = qubit_conv.convert(problem.second_q_ops()[0], self.num_particles, - sector_locator=problem.symmetry_sector_locator) + qubit_conv = QubitConverter( + mapper, two_qubit_reduction=True, z2symmetry_reduction="auto" + ) + qubit_op = qubit_conv.convert( + problem.second_q_ops()[0], + self.num_particles, + sector_locator=problem.symmetry_sector_locator, + ) self.assertEqual(qubit_op, TestQubitConverter.REF_H2_JW_TAPERED) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/operators/second_quantization/test_spin_op.py b/test/operators/second_quantization/test_spin_op.py index 9b744964ec..0fced1b876 100644 --- a/test/operators/second_quantization/test_spin_op.py +++ b/test/operators/second_quantization/test_spin_op.py @@ -86,7 +86,7 @@ def assertSpinEqual(first: SpinOp, second: SpinOp): def test_init_label(self, label, pre_processing): """Test __init__""" spin = SpinOp(pre_processing(label), register_length=len(label) // 3) - expected_label = " ".join(l for l in label.split() if l[0] != "I") + expected_label = " ".join(lb for lb in label.split() if lb[0] != "I") if not expected_label: expected_label = f"I_{len(label) // 3 - 1}" self.assertListEqual(spin.to_list(), [(expected_label, 1)]) @@ -164,7 +164,9 @@ def test_init_heisenberg(self): def test_init_multiple_digits(self): """Test __init__ for sparse label with multiple digits""" - actual = SpinOp([("X_10^20", 1 + 2j), ("X_12^34", 56)], Fraction(5, 2), register_length=13) + actual = SpinOp( + [("X_10^20", 1 + 2j), ("X_12^34", 56)], Fraction(5, 2), register_length=13 + ) desired = [("X_10^20", 1 + 2j), ("X_12^34", 56)] self.assertListEqual(actual.to_list(), desired) @@ -178,7 +180,9 @@ def test_init_raising_lowering_ops(self): """Test __init__ for +_i -_i pattern""" with self.subTest("one reg"): actual = SpinOp("+_0 -_0", spin=1, register_length=1) - expected = SpinOp([("X_0^2", 1), ("Y_0^2", 1), ("Z_0", 1)], spin=1, register_length=1) + expected = SpinOp( + [("X_0^2", 1), ("Y_0^2", 1), ("Z_0", 1)], spin=1, register_length=1 + ) self.assertSpinEqual(actual, expected) with self.subTest("two reg"): actual = SpinOp("+_1 -_1 +_0 -_0", spin=3 / 2, register_length=2) @@ -208,20 +212,26 @@ def test_neg(self): def test_mul(self): """Test __mul__, and __rmul__""" actual = self.heisenberg * 2 - desired = SpinOp((self.heisenberg_spin_array, 2 * self.heisenberg_coeffs), spin=1) + desired = SpinOp( + (self.heisenberg_spin_array, 2 * self.heisenberg_coeffs), spin=1 + ) self.assertSpinEqual(actual, desired) def test_div(self): """Test __truediv__""" actual = self.heisenberg / 3 - desired = SpinOp((self.heisenberg_spin_array, self.heisenberg_coeffs / 3), spin=1) + desired = SpinOp( + (self.heisenberg_spin_array, self.heisenberg_coeffs / 3), spin=1 + ) self.assertSpinEqual(actual, desired) def test_add(self): """Test __add__""" with self.subTest("sum of heisenberg"): actual = self.heisenberg + self.heisenberg - desired = SpinOp((self.heisenberg_spin_array, 2 * self.heisenberg_coeffs), spin=1) + desired = SpinOp( + (self.heisenberg_spin_array, 2 * self.heisenberg_coeffs), spin=1 + ) self.assertSpinEqual(actual, desired) with self.subTest("raising operator"): @@ -240,14 +250,18 @@ def test_adjoint(self): with self.subTest("heisenberg adjoint"): actual = self.heisenberg.adjoint() desired = SpinOp( - (self.heisenberg_spin_array, self.heisenberg_coeffs.conjugate().T), spin=1 + (self.heisenberg_spin_array, self.heisenberg_coeffs.conjugate().T), + spin=1, ) self.assertSpinEqual(actual, desired) with self.subTest("imag heisenberg adjoint"): actual = ~((3 + 2j) * self.heisenberg) desired = SpinOp( - (self.heisenberg_spin_array, ((3 + 2j) * self.heisenberg_coeffs).conjugate().T), + ( + self.heisenberg_spin_array, + ((3 + 2j) * self.heisenberg_coeffs).conjugate().T, + ), spin=1, ) self.assertSpinEqual(actual, desired) @@ -296,7 +310,9 @@ def test_reduce(self): with self.subTest("nontrivial reduce 3"): test_op = SpinOp([("+_0 -_0", 1)], register_length=4) actual = test_op.reduce() - self.assertListEqual(actual.to_list(), [("Z_0", 1), ("Y_0^2", 1), ("X_0^2", 1)]) + self.assertListEqual( + actual.to_list(), [("Z_0", 1), ("Y_0^2", 1), ("X_0^2", 1)] + ) @data(*dense_labels(1)) def test_to_matrix_single_qutrit(self, label): diff --git a/test/operators/second_quantization/test_vibrational_op.py b/test/operators/second_quantization/test_vibrational_op.py index 4d6a1f3c94..7408ca3cb5 100644 --- a/test/operators/second_quantization/test_vibrational_op.py +++ b/test/operators/second_quantization/test_vibrational_op.py @@ -34,7 +34,10 @@ def setUp(self): ("+_1*0 -_1*1", 1215.375 / 3), ("+_2*0 -_2*1 +_3*0 -_3*0", -6.385 / 3), ] - self.labels_neg = [("+_1*0 -_1*1", -1215.375), ("+_2*0 -_2*1 +_3*0 -_3*0", 6.385)] + self.labels_neg = [ + ("+_1*0 -_1*1", -1215.375), + ("+_2*0 -_2*1 +_3*0 -_3*0", 6.385), + ] self.vibr_spin_op = VibrationalOp(self.labels, 4, 2) def assertSpinEqual(self, first: VibrationalOp, second: VibrationalOp): @@ -46,17 +49,17 @@ def test_init_pm_label(self): """Test __init__ with plus and minus label""" with self.subTest("minus plus"): result = VibrationalOp([("+_0*0 -_0*1", 2)], 1, 2) - desired = [('+-', (2 + 0j))] + desired = [("+-", (2 + 0j))] self.assertEqual(result.to_list(), desired) with self.subTest("plus minus"): result = VibrationalOp([("-_0*0 +_0*1", 2)], 1, 2) - desired = [('-+', (2 + 0j))] + desired = [("-+", (2 + 0j))] self.assertEqual(result.to_list(), desired) with self.subTest("plus minus minus plus"): result = VibrationalOp([("+_0*0 -_0*1 -_1*0 +_1*1", 3)], 2, 2) - desired = [('+--+', (3 + 0j))] + desired = [("+--+", (3 + 0j))] # Note: the order of list is irrelevant. self.assertSetEqual(frozenset(result.to_list()), frozenset(desired)) diff --git a/test/problems/second_quantization/electronic/builders/test_fermionic_op_builder.py b/test/problems/second_quantization/electronic/builders/test_fermionic_op_builder.py index 982c72a6c7..d60eb8c238 100644 --- a/test/problems/second_quantization/electronic/builders/test_fermionic_op_builder.py +++ b/test/problems/second_quantization/electronic/builders/test_fermionic_op_builder.py @@ -12,11 +12,14 @@ """Tests Fermionic Operator builder.""" from test import QiskitNatureTestCase -from test.problems.second_quantization.electronic.resources.resource_reader import \ - read_expected_file +from test.problems.second_quantization.electronic.resources.resource_reader import ( + read_expected_file, +) import numpy as np from qiskit_nature.operators.second_quantization import FermionicOp -from qiskit_nature.problems.second_quantization.electronic.builders import fermionic_op_builder +from qiskit_nature.problems.second_quantization.electronic.builders import ( + fermionic_op_builder, +) from qiskit_nature.drivers import HDF5Driver @@ -26,11 +29,14 @@ class TestFermionicOpBuilder(QiskitNatureTestCase): def test_build_fermionic_op(self): """Tests that the correct FermionicOp is built from QMolecule.""" expected_num_of_terms_ferm_op = 184 - expected_fermionic_op_path = self.get_resource_path('H2_631g_ferm_op_two_ints', - 'problems/second_quantization/' - 'electronic/resources') + expected_fermionic_op_path = self.get_resource_path( + "H2_631g_ferm_op_two_ints", + "problems/second_quantization/" "electronic/resources", + ) expected_fermionic_op = read_expected_file(expected_fermionic_op_path) - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) q_molecule = driver.run() fermionic_op = fermionic_op_builder._build_fermionic_op(q_molecule) with self.subTest("Check type of fermionic operator"): @@ -38,46 +44,60 @@ def test_build_fermionic_op(self): with self.subTest("Check expected number of terms in a fermionic operator."): assert len(fermionic_op) == expected_num_of_terms_ferm_op with self.subTest("Check expected content of a fermionic operator."): - assert all(s[0] == t[0] and np.isclose(s[1], t[1]) for s, t in - zip(fermionic_op.to_list(), expected_fermionic_op)) + assert all( + s[0] == t[0] and np.isclose(s[1], t[1]) + for s, t in zip(fermionic_op.to_list(), expected_fermionic_op) + ) def test_build_fermionic_op_from_ints_both(self): """Tests that the correct FermionicOp is built from 1- and 2-body integrals.""" expected_num_of_terms_ferm_op = 184 - expected_fermionic_op_path = self.get_resource_path('H2_631g_ferm_op_two_ints', - 'problems/second_quantization/' - 'electronic/resources') + expected_fermionic_op_path = self.get_resource_path( + "H2_631g_ferm_op_two_ints", + "problems/second_quantization/" "electronic/resources", + ) expected_fermionic_op = read_expected_file(expected_fermionic_op_path) - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) q_molecule = driver.run() fermionic_op = fermionic_op_builder.build_ferm_op_from_ints( - q_molecule.one_body_integrals, q_molecule.two_body_integrals) + q_molecule.one_body_integrals, q_molecule.two_body_integrals + ) with self.subTest("Check type of fermionic operator"): assert isinstance(fermionic_op, FermionicOp) with self.subTest("Check expected number of terms in a fermionic operator."): assert len(fermionic_op) == expected_num_of_terms_ferm_op with self.subTest("Check expected content of a fermionic operator."): - assert all(s[0] == t[0] and np.isclose(s[1], t[1]) for s, t in - zip(fermionic_op.to_list(), expected_fermionic_op)) + assert all( + s[0] == t[0] and np.isclose(s[1], t[1]) + for s, t in zip(fermionic_op.to_list(), expected_fermionic_op) + ) def test_build_fermionic_op_from_ints_one(self): """Tests that the correct FermionicOp is built from 1-body integrals.""" expected_num_of_terms_ferm_op = 16 - expected_fermionic_op_path = self.get_resource_path('H2_631g_ferm_op_one_int', - 'problems/second_quantization/' - 'electronic/resources') + expected_fermionic_op_path = self.get_resource_path( + "H2_631g_ferm_op_one_int", + "problems/second_quantization/" "electronic/resources", + ) expected_fermionic_op = read_expected_file(expected_fermionic_op_path) - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) q_molecule = driver.run() fermionic_op = fermionic_op_builder.build_ferm_op_from_ints( - q_molecule.one_body_integrals) + q_molecule.one_body_integrals + ) with self.subTest("Check type of fermionic operator"): assert isinstance(fermionic_op, FermionicOp) with self.subTest("Check expected number of terms in a fermionic operator."): assert len(fermionic_op) == expected_num_of_terms_ferm_op with self.subTest("Check expected content of a fermionic operator."): - assert all(s[0] == t[0] and np.isclose(s[1], t[1]) for s, t in - zip(fermionic_op.to_list(), expected_fermionic_op)) + assert all( + s[0] == t[0] and np.isclose(s[1], t[1]) + for s, t in zip(fermionic_op.to_list(), expected_fermionic_op) + ) diff --git a/test/problems/second_quantization/electronic/builders/test_hopping_ops_builder.py b/test/problems/second_quantization/electronic/builders/test_hopping_ops_builder.py index 8c7fb8f042..13fa3ec6dc 100644 --- a/test/problems/second_quantization/electronic/builders/test_hopping_ops_builder.py +++ b/test/problems/second_quantization/electronic/builders/test_hopping_ops_builder.py @@ -21,8 +21,9 @@ from qiskit_nature.mappers.second_quantization import JordanWignerMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import ElectronicStructureProblem -from qiskit_nature.problems.second_quantization.electronic.builders.hopping_ops_builder import \ - _build_qeom_hopping_ops +from qiskit_nature.problems.second_quantization.electronic.builders.hopping_ops_builder import ( + _build_qeom_hopping_ops, +) class TestHoppingOpsBuilder(QiskitNatureTestCase): @@ -32,13 +33,15 @@ def setUp(self): super().setUp() algorithm_globals.random_seed = 8 try: - self.driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.75', - unit=UnitsType.ANGSTROM, - charge=0, - spin=0, - basis='sto3g') + self.driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.75", + unit=UnitsType.ANGSTROM, + charge=0, + spin=0, + basis="sto3g", + ) except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") self.qubit_converter = QubitConverter(JordanWignerMapper()) self.electronic_structure_problem = ElectronicStructureProblem(self.driver) @@ -49,83 +52,150 @@ def test_build_hopping_operators(self): """Tests that the correct hopping operator is built from QMolecule.""" # TODO extract it somewhere expected_hopping_operators = ( - {'E_0': PauliSumOp( - SparsePauliOp([[True, True, False, False, False, False, False, False], - [True, True, False, False, False, True, False, False], - [True, True, False, False, True, False, False, False], - [True, True, False, False, True, True, False, False]], - coeffs=[1. + 0.j, 0. - 1.j, 0. + 1.j, 1. + 0.j]), - coeff=1.0), - 'Edag_0': PauliSumOp( - SparsePauliOp([[True, True, False, False, False, False, False, False], - [True, True, False, False, False, True, False, False], - [True, True, False, False, True, False, False, False], - [True, True, False, False, True, True, False, False]], - coeffs=[-1. + 0.j, 0. - 1.j, 0. + 1.j, -1. + 0.j]), - coeff=1.0), - 'E_1': PauliSumOp( - SparsePauliOp([[False, False, True, True, False, False, False, False], - [False, False, True, True, False, False, False, True], - [False, False, True, True, False, False, True, False], - [False, False, True, True, False, False, True, True]], - coeffs=[1. + 0.j, 0. - 1.j, 0. + 1.j, 1. + 0.j]), - coeff=1.0), - 'Edag_1': PauliSumOp( - SparsePauliOp([[False, False, True, True, False, False, False, False], - [False, False, True, True, False, False, False, True], - [False, False, True, True, False, False, True, False], - [False, False, True, True, False, False, True, True]], - coeffs=[-1. + 0.j, 0. - 1.j, 0. + 1.j, -1. + 0.j]), - coeff=1.0), - 'E_2': PauliSumOp( - SparsePauliOp([[True, True, True, True, False, False, False, False], - [True, True, True, True, False, False, False, True], - [True, True, True, True, False, False, True, False], - [True, True, True, True, False, False, True, True], - [True, True, True, True, False, True, False, False], - [True, True, True, True, False, True, False, True], - [True, True, True, True, False, True, True, False], - [True, True, True, True, False, True, True, True], - [True, True, True, True, True, False, False, False], - [True, True, True, True, True, False, False, True], - [True, True, True, True, True, False, True, False], - [True, True, True, True, True, False, True, True], - [True, True, True, True, True, True, False, False], - [True, True, True, True, True, True, False, True], - [True, True, True, True, True, True, True, False], - [True, True, True, True, True, True, True, True]], - coeffs=[1. + 0.j, 0. - 1.j, 0. + 1.j, 1. + 0.j, - 0. - 1.j, - -1. + 0.j, 1. + 0.j, 0. - 1.j, - 0. + 1.j, 1. + 0.j, -1. + 0.j, 0. + 1.j, - 1. + 0.j, - 0. - 1.j, 0. + 1.j, 1. + 0.j]), coeff=1.0), - 'Edag_2': PauliSumOp( - SparsePauliOp([[True, True, True, True, False, False, False, False], - [True, True, True, True, False, False, False, True], - [True, True, True, True, False, False, True, False], - [True, True, True, True, False, False, True, True], - [True, True, True, True, False, True, False, False], - [True, True, True, True, False, True, False, True], - [True, True, True, True, False, True, True, False], - [True, True, True, True, False, True, True, True], - [True, True, True, True, True, False, False, False], - [True, True, True, True, True, False, False, True], - [True, True, True, True, True, False, True, False], - [True, True, True, True, True, False, True, True], - [True, True, True, True, True, True, False, False], - [True, True, True, True, True, True, False, True], - [True, True, True, True, True, True, True, False], - [True, True, True, True, True, True, True, True]], - coeffs=[1. + 0.j, 0. + 1.j, 0. - 1.j, 1. + 0.j, - 0. + 1.j, -1. + 0.j, 1. + 0.j, 0. + 1.j, - 0. - 1.j, 1. + 0.j, -1. + 0.j, 0. - 1.j, - 1. + 0.j, 0. + 1.j, 0. - 1.j, 1. + 0.j]), - coeff=1.0)}, - {'E_0': [], 'Edag_0': [], 'E_1': [], 'Edag_1': [], 'E_2': [], 'Edag_2': []}, - {'E_0': ((0,), (1,)), 'Edag_0': ((1,), (0,)), 'E_1': ((2,), (3,)), - 'Edag_1': ((3,), (2,)), 'E_2': ((0, 2), (1, 3)), 'Edag_2': ((1, 3), (0, 2))}) + { + "E_0": PauliSumOp( + SparsePauliOp( + [ + [True, True, False, False, False, False, False, False], + [True, True, False, False, False, True, False, False], + [True, True, False, False, True, False, False, False], + [True, True, False, False, True, True, False, False], + ], + coeffs=[1.0 + 0.0j, 0.0 - 1.0j, 0.0 + 1.0j, 1.0 + 0.0j], + ), + coeff=1.0, + ), + "Edag_0": PauliSumOp( + SparsePauliOp( + [ + [True, True, False, False, False, False, False, False], + [True, True, False, False, False, True, False, False], + [True, True, False, False, True, False, False, False], + [True, True, False, False, True, True, False, False], + ], + coeffs=[-1.0 + 0.0j, 0.0 - 1.0j, 0.0 + 1.0j, -1.0 + 0.0j], + ), + coeff=1.0, + ), + "E_1": PauliSumOp( + SparsePauliOp( + [ + [False, False, True, True, False, False, False, False], + [False, False, True, True, False, False, False, True], + [False, False, True, True, False, False, True, False], + [False, False, True, True, False, False, True, True], + ], + coeffs=[1.0 + 0.0j, 0.0 - 1.0j, 0.0 + 1.0j, 1.0 + 0.0j], + ), + coeff=1.0, + ), + "Edag_1": PauliSumOp( + SparsePauliOp( + [ + [False, False, True, True, False, False, False, False], + [False, False, True, True, False, False, False, True], + [False, False, True, True, False, False, True, False], + [False, False, True, True, False, False, True, True], + ], + coeffs=[-1.0 + 0.0j, 0.0 - 1.0j, 0.0 + 1.0j, -1.0 + 0.0j], + ), + coeff=1.0, + ), + "E_2": PauliSumOp( + SparsePauliOp( + [ + [True, True, True, True, False, False, False, False], + [True, True, True, True, False, False, False, True], + [True, True, True, True, False, False, True, False], + [True, True, True, True, False, False, True, True], + [True, True, True, True, False, True, False, False], + [True, True, True, True, False, True, False, True], + [True, True, True, True, False, True, True, False], + [True, True, True, True, False, True, True, True], + [True, True, True, True, True, False, False, False], + [True, True, True, True, True, False, False, True], + [True, True, True, True, True, False, True, False], + [True, True, True, True, True, False, True, True], + [True, True, True, True, True, True, False, False], + [True, True, True, True, True, True, False, True], + [True, True, True, True, True, True, True, False], + [True, True, True, True, True, True, True, True], + ], + coeffs=[ + 1.0 + 0.0j, + 0.0 - 1.0j, + 0.0 + 1.0j, + 1.0 + 0.0j, + 0.0 - 1.0j, + -1.0 + 0.0j, + 1.0 + 0.0j, + 0.0 - 1.0j, + 0.0 + 1.0j, + 1.0 + 0.0j, + -1.0 + 0.0j, + 0.0 + 1.0j, + 1.0 + 0.0j, + 0.0 - 1.0j, + 0.0 + 1.0j, + 1.0 + 0.0j, + ], + ), + coeff=1.0, + ), + "Edag_2": PauliSumOp( + SparsePauliOp( + [ + [True, True, True, True, False, False, False, False], + [True, True, True, True, False, False, False, True], + [True, True, True, True, False, False, True, False], + [True, True, True, True, False, False, True, True], + [True, True, True, True, False, True, False, False], + [True, True, True, True, False, True, False, True], + [True, True, True, True, False, True, True, False], + [True, True, True, True, False, True, True, True], + [True, True, True, True, True, False, False, False], + [True, True, True, True, True, False, False, True], + [True, True, True, True, True, False, True, False], + [True, True, True, True, True, False, True, True], + [True, True, True, True, True, True, False, False], + [True, True, True, True, True, True, False, True], + [True, True, True, True, True, True, True, False], + [True, True, True, True, True, True, True, True], + ], + coeffs=[ + 1.0 + 0.0j, + 0.0 + 1.0j, + 0.0 - 1.0j, + 1.0 + 0.0j, + 0.0 + 1.0j, + -1.0 + 0.0j, + 1.0 + 0.0j, + 0.0 + 1.0j, + 0.0 - 1.0j, + 1.0 + 0.0j, + -1.0 + 0.0j, + 0.0 - 1.0j, + 1.0 + 0.0j, + 0.0 + 1.0j, + 0.0 - 1.0j, + 1.0 + 0.0j, + ], + ), + coeff=1.0, + ), + }, + {"E_0": [], "Edag_0": [], "E_1": [], "Edag_1": [], "E_2": [], "Edag_2": []}, + { + "E_0": ((0,), (1,)), + "Edag_0": ((1,), (0,)), + "E_1": ((2,), (3,)), + "Edag_1": ((3,), (2,)), + "E_2": ((0, 2), (1, 3)), + "Edag_2": ((1, 3), (0, 2)), + }, + ) - hopping_operators = _build_qeom_hopping_ops(self.q_molecule, - self.qubit_converter) + hopping_operators = _build_qeom_hopping_ops( + self.q_molecule, self.qubit_converter + ) self.assertEqual(hopping_operators, expected_hopping_operators) diff --git a/test/problems/second_quantization/electronic/integrals_calculators/test_angular_momentum_integrals_calculator.py b/test/problems/second_quantization/electronic/integrals_calculators/test_angular_momentum_integrals_calculator.py index 33f3e5ad76..ce950dd8fc 100644 --- a/test/problems/second_quantization/electronic/integrals_calculators/test_angular_momentum_integrals_calculator.py +++ b/test/problems/second_quantization/electronic/integrals_calculators/test_angular_momentum_integrals_calculator.py @@ -16,8 +16,9 @@ import numpy as np -from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import \ - calc_total_ang_momentum_ints +from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import ( + calc_total_ang_momentum_ints, +) @ddt @@ -25,49 +26,36 @@ class TestAngularMomentumIntegralsCalculator(QiskitNatureTestCase): """Tests total angular momentum integrals calculator.""" num_modes_list = [1, 2, 3] - expected_h_1_list = [[[0.]], - [[0.75, 0.], - [0., 0.75]], - [[0.75, 0., 0.], - [0., 0.75, 0.], - [0., 0., 0.]]] + expected_h_1_list = [ + [[0.0]], + [[0.75, 0.0], [0.0, 0.75]], + [[0.75, 0.0, 0.0], [0.0, 0.75, 0.0], [0.0, 0.0, 0.0]], + ] - expected_h_2_list = [[[[[0.]]]], - [[[[0., 0.], - [0., -0.5]], - [[0., 0.], - [0.25, 0.]]], - [[[0., 0.25], - [0., 0.]], - [[-0.5, 0.], - [0., 0.]]]], - [[[[0., 0., 0.], - [0., - 0.5, 0.], - [0., 0., 0.]], - [[0., 0., 0.], - [0.25, 0., 0.], - [0., 0., 0.]], - [[0., 0., 0.], - [0., 0., 0.], - [0., 0., 0.]]], - [[[0., 0.25, 0.], - [0., 0., 0.], - [0., 0., 0.]], - [[-0.5, 0., 0.], - [0., 0., 0.], - [0., 0., 0.]], - [[0., 0., 0.], - [0., 0., 0.], - [0., 0., 0.]]], - [[[0., 0., 0.], - [0., 0., 0.], - [0., 0., 0.]], - [[0., 0., 0.], - [0., 0., 0.], - [0., 0., 0.]], - [[0., 0., 0.], - [0., 0., 0.], - [0., 0., 0.]]]]] + expected_h_2_list = [ + [[[[0.0]]]], + [ + [[[0.0, 0.0], [0.0, -0.5]], [[0.0, 0.0], [0.25, 0.0]]], + [[[0.0, 0.25], [0.0, 0.0]], [[-0.5, 0.0], [0.0, 0.0]]], + ], + [ + [ + [[0.0, 0.0, 0.0], [0.0, -0.5, 0.0], [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [0.25, 0.0, 0.0], [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + ], + [ + [[0.0, 0.25, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + [[-0.5, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + ], + [ + [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + ], + ], + ] @data(*num_modes_list) def test_calc_total_ang_momentum_ints(self, num_modes): diff --git a/test/problems/second_quantization/electronic/integrals_calculators/test_magnetization_integrals_calculator.py b/test/problems/second_quantization/electronic/integrals_calculators/test_magnetization_integrals_calculator.py index ccf27efe4c..d77c53f62e 100644 --- a/test/problems/second_quantization/electronic/integrals_calculators/test_magnetization_integrals_calculator.py +++ b/test/problems/second_quantization/electronic/integrals_calculators/test_magnetization_integrals_calculator.py @@ -16,8 +16,9 @@ import numpy as np -from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import \ - calc_total_magnetization_ints +from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import ( + calc_total_magnetization_ints, +) @ddt @@ -25,12 +26,15 @@ class TestMagnetizationIntegralsCalculator(QiskitNatureTestCase): """Tests total magnetization integrals calculator.""" num_modes_list = [1, 2, 3] - expected_h_1_list = [[[-0.5 + 0.j]], - [[0.5 + 0.j, 0. + 0.j], - [0. + 0.j, -0.5 + 0.j]], - [[0.5 + 0.j, 0. + 0.j, 0. + 0.j], - [0. + 0.j, -0.5 + 0.j, -0. + 0.j], - [0. + 0.j, -0. + 0.j, -0.5 + 0.j]]] + expected_h_1_list = [ + [[-0.5 + 0.0j]], + [[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, -0.5 + 0.0j]], + [ + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.0 + 0.0j, -0.5 + 0.0j, -0.0 + 0.0j], + [0.0 + 0.0j, -0.0 + 0.0j, -0.5 + 0.0j], + ], + ] expected_h_2_list = [None, None, None] @data(*num_modes_list) diff --git a/test/problems/second_quantization/electronic/integrals_calculators/test_particle_number_integrals_calculator.py b/test/problems/second_quantization/electronic/integrals_calculators/test_particle_number_integrals_calculator.py index 4cc358d59a..da398ad57c 100644 --- a/test/problems/second_quantization/electronic/integrals_calculators/test_particle_number_integrals_calculator.py +++ b/test/problems/second_quantization/electronic/integrals_calculators/test_particle_number_integrals_calculator.py @@ -16,8 +16,9 @@ import numpy as np -from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import \ - calc_total_particle_num_ints +from qiskit_nature.problems.second_quantization.electronic.integrals_calculators import ( + calc_total_particle_num_ints, +) @ddt @@ -25,8 +26,11 @@ class TestParticleNumberIntegralsCalculator(QiskitNatureTestCase): """Tests total particle number integrals calculator.""" num_modes_list = [1, 2, 3] - expected_h_1_list = [np.eye(1, dtype=complex), np.eye(2, dtype=complex), - np.eye(3, dtype=complex)] + expected_h_1_list = [ + np.eye(1, dtype=complex), + np.eye(2, dtype=complex), + np.eye(3, dtype=complex), + ] expected_h_2_list = [None, None, None] @data(*num_modes_list) diff --git a/test/problems/second_quantization/electronic/resources/resource_reader.py b/test/problems/second_quantization/electronic/resources/resource_reader.py index a4653eef48..65c021242b 100644 --- a/test/problems/second_quantization/electronic/resources/resource_reader.py +++ b/test/problems/second_quantization/electronic/resources/resource_reader.py @@ -18,7 +18,8 @@ def read_expected_file(path: str) -> List[Tuple[Union[str, float], ...]]: """Reads and parses resource file.""" types = str, float - with open(path, 'r') as file: - expected_fermionic_op = [tuple(t(e) for t, e in zip(types, line.split())) - for line in file] + with open(path, "r") as file: + expected_fermionic_op = [ + tuple(t(e) for t, e in zip(types, line.split())) for line in file + ] return expected_fermionic_op diff --git a/test/problems/second_quantization/electronic/test_electronic_structure_problem.py b/test/problems/second_quantization/electronic/test_electronic_structure_problem.py index 7cfc34f903..7d73482ca1 100644 --- a/test/problems/second_quantization/electronic/test_electronic_structure_problem.py +++ b/test/problems/second_quantization/electronic/test_electronic_structure_problem.py @@ -13,8 +13,9 @@ """Tests Electronic Structure Problem.""" from test import QiskitNatureTestCase -from test.problems.second_quantization.electronic.resources.resource_reader import \ - read_expected_file +from test.problems.second_quantization.electronic.resources.resource_reader import ( + read_expected_file, +) import numpy as np from qiskit_nature.transformers import ActiveSpaceTransformer from qiskit_nature.drivers import HDF5Driver @@ -29,45 +30,59 @@ def test_second_q_ops_without_transformers(self): """Tests that the list of second quantized operators is created if no transformers provided.""" expected_num_of_sec_quant_ops = 7 - expected_fermionic_op_path = self.get_resource_path('H2_631g_ferm_op_two_ints', - 'problems/second_quantization/' - 'electronic/resources') + expected_fermionic_op_path = self.get_resource_path( + "H2_631g_ferm_op_two_ints", + "problems/second_quantization/" "electronic/resources", + ) expected_fermionic_op = read_expected_file(expected_fermionic_op_path) - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) electronic_structure_problem = ElectronicStructureProblem(driver) second_quantized_ops = electronic_structure_problem.second_q_ops() electr_sec_quant_op = second_quantized_ops[0] - with self.subTest("Check expected length of the list of second quantized operators."): + with self.subTest( + "Check expected length of the list of second quantized operators." + ): assert len(second_quantized_ops) == expected_num_of_sec_quant_ops with self.subTest("Check types in the list of second quantized operators."): for second_quantized_op in second_quantized_ops: assert isinstance(second_quantized_op, SecondQuantizedOp) with self.subTest("Check components of electronic second quantized operator."): - assert all(s[0] == t[0] and np.isclose(s[1], t[1]) for s, t in - zip(expected_fermionic_op, electr_sec_quant_op.to_list())) + assert all( + s[0] == t[0] and np.isclose(s[1], t[1]) + for s, t in zip(expected_fermionic_op, electr_sec_quant_op.to_list()) + ) def test_second_q_ops_with_active_space(self): """Tests that the correct second quantized operator is created if an active space transformer is provided.""" expected_num_of_sec_quant_ops = 7 - expected_fermionic_op_path = self.get_resource_path('H2_631g_ferm_op_active_space', - 'problems/second_quantization/' - 'electronic/resources') + expected_fermionic_op_path = self.get_resource_path( + "H2_631g_ferm_op_active_space", + "problems/second_quantization/" "electronic/resources", + ) expected_fermionic_op = read_expected_file(expected_fermionic_op_path) - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) trafo = ActiveSpaceTransformer(num_electrons=2, num_molecular_orbitals=2) electronic_structure_problem = ElectronicStructureProblem(driver, [trafo]) second_quantized_ops = electronic_structure_problem.second_q_ops() electr_sec_quant_op = second_quantized_ops[0] - with self.subTest("Check expected length of the list of second quantized operators."): + with self.subTest( + "Check expected length of the list of second quantized operators." + ): assert len(second_quantized_ops) == expected_num_of_sec_quant_ops with self.subTest("Check types in the list of second quantized operators."): for second_quantized_op in second_quantized_ops: assert isinstance(second_quantized_op, SecondQuantizedOp) with self.subTest("Check components of electronic second quantized operator."): - assert all(s[0] == t[0] and np.isclose(s[1], t[1]) for s, t in - zip(expected_fermionic_op, electr_sec_quant_op.to_list())) + assert all( + s[0] == t[0] and np.isclose(s[1], t[1]) + for s, t in zip(expected_fermionic_op, electr_sec_quant_op.to_list()) + ) diff --git a/test/problems/second_quantization/vibrational/builders/test_hopping_ops_builder.py b/test/problems/second_quantization/vibrational/builders/test_hopping_ops_builder.py index d6d7249a95..c77dd2e5e2 100644 --- a/test/problems/second_quantization/vibrational/builders/test_hopping_ops_builder.py +++ b/test/problems/second_quantization/vibrational/builders/test_hopping_ops_builder.py @@ -12,7 +12,9 @@ """Tests Hopping Operators builder.""" from test import QiskitNatureTestCase -from test.algorithms.excited_state_solvers.test_bosonic_esc_calculation import _DummyBosonicDriver +from test.algorithms.excited_state_solvers.test_bosonic_esc_calculation import ( + _DummyBosonicDriver, +) from qiskit.opflow import PauliSumOp from qiskit.quantum_info import SparsePauliOp from qiskit.utils import algorithm_globals @@ -20,8 +22,9 @@ from qiskit_nature.mappers.second_quantization import DirectMapper from qiskit_nature.converters.second_quantization import QubitConverter from qiskit_nature.problems.second_quantization import VibrationalStructureProblem -from qiskit_nature.problems.second_quantization.vibrational.builders.hopping_ops_builder import \ - _build_qeom_hopping_ops +from qiskit_nature.problems.second_quantization.vibrational.builders.hopping_ops_builder import ( + _build_qeom_hopping_ops, +) class TestHoppingOpsBuilder(QiskitNatureTestCase): @@ -35,8 +38,9 @@ def setUp(self): self.basis_size = 2 self.truncation_order = 2 - self.vibrational_problem = VibrationalStructureProblem(self.driver, self.basis_size, - self.truncation_order) + self.vibrational_problem = VibrationalStructureProblem( + self.driver, self.basis_size, self.truncation_order + ) self.qubit_converter = QubitConverter(DirectMapper()) self.vibrational_problem.second_q_ops() @@ -47,86 +51,150 @@ def test_build_hopping_operators(self): """Tests that the correct hopping operator is built from QMolecule.""" # TODO extract it somewhere expected_hopping_operators = ( - {'E_0': PauliSumOp( - SparsePauliOp([[True, True, False, False, False, False, False, False], - [True, True, False, False, False, True, False, False], - [True, True, False, False, True, False, False, False], - [True, True, False, False, True, True, False, False]], - coeffs=[0.25 + 0.j, 0. - 0.25j, 0. + 0.25j, 0.25 + 0.j]), coeff=1.0), - 'Edag_0': PauliSumOp( - SparsePauliOp([[True, True, False, False, False, False, False, False], - [True, True, False, False, False, True, False, False], - [True, True, False, False, True, False, False, False], - [True, True, False, False, True, True, False, False]], - coeffs=[0.25 + 0.j, 0. + 0.25j, 0. - 0.25j, 0.25 + 0.j]), - coeff=1.0), - 'E_1': PauliSumOp( - SparsePauliOp([[False, False, True, True, False, False, False, False], - [False, False, True, True, False, False, False, True], - [False, False, True, True, False, False, True, False], - [False, False, True, True, False, False, True, True]], - coeffs=[0.25 + 0.j, 0. - 0.25j, 0. + 0.25j, 0.25 + 0.j]), - coeff=1.0), - 'Edag_1': PauliSumOp( - SparsePauliOp([[False, False, True, True, False, False, False, False], - [False, False, True, True, False, False, False, True], - [False, False, True, True, False, False, True, False], - [False, False, True, True, False, False, True, True]], - coeffs=[0.25 + 0.j, 0. + 0.25j, 0. - 0.25j, 0.25 + 0.j]), - coeff=1.0), - 'E_2': PauliSumOp( - SparsePauliOp([[True, True, True, True, False, False, False, False], - [True, True, True, True, False, False, False, True], - [True, True, True, True, False, False, True, False], - [True, True, True, True, False, False, True, True], - [True, True, True, True, False, True, False, False], - [True, True, True, True, False, True, False, True], - [True, True, True, True, False, True, True, False], - [True, True, True, True, False, True, True, True], - [True, True, True, True, True, False, False, False], - [True, True, True, True, True, False, False, True], - [True, True, True, True, True, False, True, False], - [True, True, True, True, True, False, True, True], - [True, True, True, True, True, True, False, False], - [True, True, True, True, True, True, False, True], - [True, True, True, True, True, True, True, False], - [True, True, True, True, True, True, True, True]], - coeffs=[0.0625 + 0.j, 0. - 0.0625j, 0. + 0.0625j, - 0.0625 + 0.j, - 0. - 0.0625j, -0.0625 + 0.j, 0.0625 + 0.j, - 0. - 0.0625j, - 0. + 0.0625j, 0.0625 + 0.j, -0.0625 + 0.j, - 0. + 0.0625j, - 0.0625 + 0.j, 0. - 0.0625j, 0. + 0.0625j, - 0.0625 + 0.j]), coeff=1.0), - 'Edag_2': PauliSumOp( - SparsePauliOp([[True, True, True, True, False, False, False, False], - [True, True, True, True, False, False, False, True], - [True, True, True, True, False, False, True, False], - [True, True, True, True, False, False, True, True], - [True, True, True, True, False, True, False, False], - [True, True, True, True, False, True, False, True], - [True, True, True, True, False, True, True, False], - [True, True, True, True, False, True, True, True], - [True, True, True, True, True, False, False, False], - [True, True, True, True, True, False, False, True], - [True, True, True, True, True, False, True, False], - [True, True, True, True, True, False, True, True], - [True, True, True, True, True, True, False, False], - [True, True, True, True, True, True, False, True], - [True, True, True, True, True, True, True, False], - [True, True, True, True, True, True, True, True]], - coeffs=[0.0625 + 0.j, 0. + 0.0625j, 0. - 0.0625j, - 0.0625 + 0.j, - 0. + 0.0625j, -0.0625 + 0.j, 0.0625 + 0.j, - 0. + 0.0625j, - 0. - 0.0625j, 0.0625 + 0.j, -0.0625 + 0.j, - 0. - 0.0625j, - 0.0625 + 0.j, 0. + 0.0625j, 0. - 0.0625j, - 0.0625 + 0.j]), coeff=1.0)}, {}, - {'E_0': ((0,), (1,)), 'Edag_0': ((1,), (0,)), 'E_1': ((2,), (3,)), - 'Edag_1': ((3,), (2,)), - 'E_2': ((0, 2), (1, 3)), 'Edag_2': ((1, 3), (0, 2))}) + { + "E_0": PauliSumOp( + SparsePauliOp( + [ + [True, True, False, False, False, False, False, False], + [True, True, False, False, False, True, False, False], + [True, True, False, False, True, False, False, False], + [True, True, False, False, True, True, False, False], + ], + coeffs=[0.25 + 0.0j, 0.0 - 0.25j, 0.0 + 0.25j, 0.25 + 0.0j], + ), + coeff=1.0, + ), + "Edag_0": PauliSumOp( + SparsePauliOp( + [ + [True, True, False, False, False, False, False, False], + [True, True, False, False, False, True, False, False], + [True, True, False, False, True, False, False, False], + [True, True, False, False, True, True, False, False], + ], + coeffs=[0.25 + 0.0j, 0.0 + 0.25j, 0.0 - 0.25j, 0.25 + 0.0j], + ), + coeff=1.0, + ), + "E_1": PauliSumOp( + SparsePauliOp( + [ + [False, False, True, True, False, False, False, False], + [False, False, True, True, False, False, False, True], + [False, False, True, True, False, False, True, False], + [False, False, True, True, False, False, True, True], + ], + coeffs=[0.25 + 0.0j, 0.0 - 0.25j, 0.0 + 0.25j, 0.25 + 0.0j], + ), + coeff=1.0, + ), + "Edag_1": PauliSumOp( + SparsePauliOp( + [ + [False, False, True, True, False, False, False, False], + [False, False, True, True, False, False, False, True], + [False, False, True, True, False, False, True, False], + [False, False, True, True, False, False, True, True], + ], + coeffs=[0.25 + 0.0j, 0.0 + 0.25j, 0.0 - 0.25j, 0.25 + 0.0j], + ), + coeff=1.0, + ), + "E_2": PauliSumOp( + SparsePauliOp( + [ + [True, True, True, True, False, False, False, False], + [True, True, True, True, False, False, False, True], + [True, True, True, True, False, False, True, False], + [True, True, True, True, False, False, True, True], + [True, True, True, True, False, True, False, False], + [True, True, True, True, False, True, False, True], + [True, True, True, True, False, True, True, False], + [True, True, True, True, False, True, True, True], + [True, True, True, True, True, False, False, False], + [True, True, True, True, True, False, False, True], + [True, True, True, True, True, False, True, False], + [True, True, True, True, True, False, True, True], + [True, True, True, True, True, True, False, False], + [True, True, True, True, True, True, False, True], + [True, True, True, True, True, True, True, False], + [True, True, True, True, True, True, True, True], + ], + coeffs=[ + 0.0625 + 0.0j, + 0.0 - 0.0625j, + 0.0 + 0.0625j, + 0.0625 + 0.0j, + 0.0 - 0.0625j, + -0.0625 + 0.0j, + 0.0625 + 0.0j, + 0.0 - 0.0625j, + 0.0 + 0.0625j, + 0.0625 + 0.0j, + -0.0625 + 0.0j, + 0.0 + 0.0625j, + 0.0625 + 0.0j, + 0.0 - 0.0625j, + 0.0 + 0.0625j, + 0.0625 + 0.0j, + ], + ), + coeff=1.0, + ), + "Edag_2": PauliSumOp( + SparsePauliOp( + [ + [True, True, True, True, False, False, False, False], + [True, True, True, True, False, False, False, True], + [True, True, True, True, False, False, True, False], + [True, True, True, True, False, False, True, True], + [True, True, True, True, False, True, False, False], + [True, True, True, True, False, True, False, True], + [True, True, True, True, False, True, True, False], + [True, True, True, True, False, True, True, True], + [True, True, True, True, True, False, False, False], + [True, True, True, True, True, False, False, True], + [True, True, True, True, True, False, True, False], + [True, True, True, True, True, False, True, True], + [True, True, True, True, True, True, False, False], + [True, True, True, True, True, True, False, True], + [True, True, True, True, True, True, True, False], + [True, True, True, True, True, True, True, True], + ], + coeffs=[ + 0.0625 + 0.0j, + 0.0 + 0.0625j, + 0.0 - 0.0625j, + 0.0625 + 0.0j, + 0.0 + 0.0625j, + -0.0625 + 0.0j, + 0.0625 + 0.0j, + 0.0 + 0.0625j, + 0.0 - 0.0625j, + 0.0625 + 0.0j, + -0.0625 + 0.0j, + 0.0 - 0.0625j, + 0.0625 + 0.0j, + 0.0 + 0.0625j, + 0.0 - 0.0625j, + 0.0625 + 0.0j, + ], + ), + coeff=1.0, + ), + }, + {}, + { + "E_0": ((0,), (1,)), + "Edag_0": ((1,), (0,)), + "E_1": ((2,), (3,)), + "Edag_1": ((3,), (2,)), + "E_2": ((0, 2), (1, 3)), + "Edag_2": ((1, 3), (0, 2)), + }, + ) - hopping_operators = _build_qeom_hopping_ops(self.num_modals, self.qubit_converter) + hopping_operators = _build_qeom_hopping_ops( + self.num_modals, self.qubit_converter + ) self.assertEqual(hopping_operators, expected_hopping_operators) diff --git a/test/problems/second_quantization/vibrational/builders/test_vibrational_label_builder.py b/test/problems/second_quantization/vibrational/builders/test_vibrational_label_builder.py index e7f2085182..f7efbef1b4 100644 --- a/test/problems/second_quantization/vibrational/builders/test_vibrational_label_builder.py +++ b/test/problems/second_quantization/vibrational/builders/test_vibrational_label_builder.py @@ -11,15 +11,18 @@ # that they have been altered from the originals. """Tests Vibrational Label Builder.""" from test import QiskitNatureTestCase -from test.problems.second_quantization.vibrational.resources.expected_labels import \ - _co2_freq_b3lyp_sparse_labels as expected_labels -from test.problems.second_quantization.vibrational.resources.expected_labels import \ - _co2_freq_b3lyp_coeffs as expected_coeffs +from test.problems.second_quantization.vibrational.resources.expected_labels import ( + _co2_freq_b3lyp_sparse_labels as expected_labels, +) +from test.problems.second_quantization.vibrational.resources.expected_labels import ( + _co2_freq_b3lyp_coeffs as expected_coeffs, +) from qiskit_nature.drivers import GaussianForcesDriver from qiskit_nature.drivers.bosonic_bases import HarmonicBasis -from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder \ - import _create_labels +from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_label_builder import ( + _create_labels, +) class TestVibrationalLabelBuilder(QiskitNatureTestCase): @@ -28,7 +31,8 @@ class TestVibrationalLabelBuilder(QiskitNatureTestCase): def test_create_labels(self): """Tests that correct labels are built.""" logfile = self.get_resource_path( - 'CO2_freq_B3LYP_ccpVDZ.log', 'problems/second_quantization/vibrational/resources' + "CO2_freq_B3LYP_ccpVDZ.log", + "problems/second_quantization/vibrational/resources", ) driver = GaussianForcesDriver(logfile=logfile) watson_hamiltonian = driver.run() @@ -36,8 +40,9 @@ def test_create_labels(self): truncation_order = 3 num_modes = watson_hamiltonian.num_modes num_modals = [num_modals] * num_modes - boson_hamilt_harm_basis = HarmonicBasis(watson_hamiltonian, - num_modals, truncation_order).convert() + boson_hamilt_harm_basis = HarmonicBasis( + watson_hamiltonian, num_modals, truncation_order + ).convert() labels, coeffs = zip(*_create_labels(boson_hamilt_harm_basis)) self.assertSetEqual(frozenset(labels), frozenset(expected_labels)) self.assertSetEqual(frozenset(coeffs), frozenset(expected_coeffs)) diff --git a/test/problems/second_quantization/vibrational/builders/test_vibrational_op_builder.py b/test/problems/second_quantization/vibrational/builders/test_vibrational_op_builder.py index b1b425231f..0b83616a0d 100644 --- a/test/problems/second_quantization/vibrational/builders/test_vibrational_op_builder.py +++ b/test/problems/second_quantization/vibrational/builders/test_vibrational_op_builder.py @@ -12,14 +12,17 @@ """Tests Fermionic Operator builder.""" from test import QiskitNatureTestCase -from test.problems.second_quantization.vibrational.resources.expected_labels import \ - _co2_freq_b3lyp_dense_labels as expected_labels -from test.problems.second_quantization.vibrational.resources.expected_labels import \ - _co2_freq_b3lyp_coeffs as expected_coeffs +from test.problems.second_quantization.vibrational.resources.expected_labels import ( + _co2_freq_b3lyp_dense_labels as expected_labels, +) +from test.problems.second_quantization.vibrational.resources.expected_labels import ( + _co2_freq_b3lyp_coeffs as expected_coeffs, +) from qiskit_nature.operators.second_quantization.vibrational_op import VibrationalOp -from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_op_builder import \ - _build_vibrational_op +from qiskit_nature.problems.second_quantization.vibrational.builders.vibrational_op_builder import ( + _build_vibrational_op, +) from qiskit_nature.drivers import GaussianForcesDriver @@ -29,7 +32,8 @@ class TestVibrationalOpBuilder(QiskitNatureTestCase): def test_vibrational_op_builder(self): """Tests that a VibrationalOp is created correctly from a driver.""" logfile = self.get_resource_path( - 'CO2_freq_B3LYP_ccpVDZ.log', 'problems/second_quantization/vibrational/resources' + "CO2_freq_B3LYP_ccpVDZ.log", + "problems/second_quantization/vibrational/resources", ) driver = GaussianForcesDriver(logfile=logfile) @@ -37,7 +41,9 @@ def test_vibrational_op_builder(self): num_modals = 2 truncation_order = 3 - vibrational_op = _build_vibrational_op(watson_hamiltonian, num_modals, truncation_order) + vibrational_op = _build_vibrational_op( + watson_hamiltonian, num_modals, truncation_order + ) assert isinstance(vibrational_op, VibrationalOp) labels, coeffs = zip(*vibrational_op.to_list()) diff --git a/test/problems/second_quantization/vibrational/resources/expected_labels.py b/test/problems/second_quantization/vibrational/resources/expected_labels.py index 3df83c207b..977d1f9593 100644 --- a/test/problems/second_quantization/vibrational/resources/expected_labels.py +++ b/test/problems/second_quantization/vibrational/resources/expected_labels.py @@ -10,269 +10,269 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. _co2_freq_b3lyp_sparse_labels = [ - '+_0*0 -_0*0', - '+_0*1 -_0*1', - '+_1*0 -_1*0', - '+_1*0 -_1*1', - '-_1*0 +_1*1', - '+_1*1 -_1*1', - '+_2*0 -_2*0', - '+_2*1 -_2*1', - '+_3*0 -_3*0', - '+_3*1 -_3*1', - '+_0*0 -_0*0 +_1*0 -_1*0', - '+_0*1 -_0*1 +_1*0 -_1*0', - '+_0*0 -_0*0 +_1*0 -_1*1', - '+_0*1 -_0*1 +_1*0 -_1*1', - '+_0*0 -_0*0 -_1*0 +_1*1', - '+_0*1 -_0*1 -_1*0 +_1*1', - '+_0*0 -_0*0 +_1*1 -_1*1', - '+_0*1 -_0*1 +_1*1 -_1*1', - '+_0*0 -_0*0 +_2*0 -_2*0', - '+_0*1 -_0*1 +_2*0 -_2*0', - '+_1*0 -_1*0 +_2*0 -_2*0', - '+_1*0 -_1*1 +_2*0 -_2*0', - '-_1*0 +_1*1 +_2*0 -_2*0', - '+_1*1 -_1*1 +_2*0 -_2*0', - '+_0*0 -_0*1 +_2*0 -_2*1', - '-_0*0 +_0*1 +_2*0 -_2*1', - '+_0*0 -_0*1 -_2*0 +_2*1', - '-_0*0 +_0*1 -_2*0 +_2*1', - '+_0*0 -_0*0 +_2*1 -_2*1', - '+_0*1 -_0*1 +_2*1 -_2*1', - '+_1*0 -_1*0 +_2*1 -_2*1', - '+_1*0 -_1*1 +_2*1 -_2*1', - '-_1*0 +_1*1 +_2*1 -_2*1', - '+_1*1 -_1*1 +_2*1 -_2*1', - '+_0*0 -_0*0 +_3*0 -_3*0', - '+_0*1 -_0*1 +_3*0 -_3*0', - '+_1*0 -_1*0 +_3*0 -_3*0', - '+_1*0 -_1*1 +_3*0 -_3*0', - '-_1*0 +_1*1 +_3*0 -_3*0', - '+_1*1 -_1*1 +_3*0 -_3*0', - '+_2*0 -_2*0 +_3*0 -_3*0', - '+_2*1 -_2*1 +_3*0 -_3*0', - '+_0*0 -_0*1 +_3*0 -_3*1', - '-_0*0 +_0*1 +_3*0 -_3*1', - '+_2*0 -_2*1 +_3*0 -_3*1', - '-_2*0 +_2*1 +_3*0 -_3*1', - '+_0*0 -_0*1 -_3*0 +_3*1', - '-_0*0 +_0*1 -_3*0 +_3*1', - '+_2*0 -_2*1 -_3*0 +_3*1', - '-_2*0 +_2*1 -_3*0 +_3*1', - '+_0*0 -_0*0 +_3*1 -_3*1', - '+_0*1 -_0*1 +_3*1 -_3*1', - '+_1*0 -_1*0 +_3*1 -_3*1', - '+_1*0 -_1*1 +_3*1 -_3*1', - '-_1*0 +_1*1 +_3*1 -_3*1', - '+_1*1 -_1*1 +_3*1 -_3*1', - '+_2*0 -_2*0 +_3*1 -_3*1', - '+_2*1 -_2*1 +_3*1 -_3*1', - '+_0*0 -_0*1 +_1*0 -_1*0 +_2*0 -_2*1', - '-_0*0 +_0*1 +_1*0 -_1*0 +_2*0 -_2*1', - '+_0*0 -_0*1 +_1*0 -_1*1 +_2*0 -_2*1', - '-_0*0 +_0*1 +_1*0 -_1*1 +_2*0 -_2*1', - '+_0*0 -_0*1 -_1*0 +_1*1 +_2*0 -_2*1', - '-_0*0 +_0*1 -_1*0 +_1*1 +_2*0 -_2*1', - '+_0*0 -_0*1 +_1*1 -_1*1 +_2*0 -_2*1', - '-_0*0 +_0*1 +_1*1 -_1*1 +_2*0 -_2*1', - '+_0*0 -_0*1 +_1*0 -_1*0 -_2*0 +_2*1', - '-_0*0 +_0*1 +_1*0 -_1*0 -_2*0 +_2*1', - '+_0*0 -_0*1 +_1*0 -_1*1 -_2*0 +_2*1', - '-_0*0 +_0*1 +_1*0 -_1*1 -_2*0 +_2*1', - '+_0*0 -_0*1 -_1*0 +_1*1 -_2*0 +_2*1', - '-_0*0 +_0*1 -_1*0 +_1*1 -_2*0 +_2*1', - '+_0*0 -_0*1 +_1*1 -_1*1 -_2*0 +_2*1', - '-_0*0 +_0*1 +_1*1 -_1*1 -_2*0 +_2*1', - '+_0*0 -_0*1 +_2*0 -_2*1 +_3*0 -_3*0', - '-_0*0 +_0*1 +_2*0 -_2*1 +_3*0 -_3*0', - '+_0*0 -_0*1 -_2*0 +_2*1 +_3*0 -_3*0', - '-_0*0 +_0*1 -_2*0 +_2*1 +_3*0 -_3*0', - '+_0*0 -_0*1 +_1*0 -_1*0 +_3*0 -_3*1', - '-_0*0 +_0*1 +_1*0 -_1*0 +_3*0 -_3*1', - '+_0*0 -_0*1 +_1*0 -_1*1 +_3*0 -_3*1', - '-_0*0 +_0*1 +_1*0 -_1*1 +_3*0 -_3*1', - '+_0*0 -_0*1 -_1*0 +_1*1 +_3*0 -_3*1', - '-_0*0 +_0*1 -_1*0 +_1*1 +_3*0 -_3*1', - '+_0*0 -_0*1 +_1*1 -_1*1 +_3*0 -_3*1', - '-_0*0 +_0*1 +_1*1 -_1*1 +_3*0 -_3*1', - '+_0*0 -_0*1 +_2*0 -_2*0 +_3*0 -_3*1', - '-_0*0 +_0*1 +_2*0 -_2*0 +_3*0 -_3*1', - '+_0*0 -_0*0 +_2*0 -_2*1 +_3*0 -_3*1', - '+_0*1 -_0*1 +_2*0 -_2*1 +_3*0 -_3*1', - '+_1*0 -_1*0 +_2*0 -_2*1 +_3*0 -_3*1', - '+_1*0 -_1*1 +_2*0 -_2*1 +_3*0 -_3*1', - '-_1*0 +_1*1 +_2*0 -_2*1 +_3*0 -_3*1', - '+_1*1 -_1*1 +_2*0 -_2*1 +_3*0 -_3*1', - '+_0*0 -_0*0 -_2*0 +_2*1 +_3*0 -_3*1', - '+_0*1 -_0*1 -_2*0 +_2*1 +_3*0 -_3*1', - '+_1*0 -_1*0 -_2*0 +_2*1 +_3*0 -_3*1', - '+_1*0 -_1*1 -_2*0 +_2*1 +_3*0 -_3*1', - '-_1*0 +_1*1 -_2*0 +_2*1 +_3*0 -_3*1', - '+_1*1 -_1*1 -_2*0 +_2*1 +_3*0 -_3*1', - '+_0*0 -_0*1 +_2*1 -_2*1 +_3*0 -_3*1', - '-_0*0 +_0*1 +_2*1 -_2*1 +_3*0 -_3*1', - '+_0*0 -_0*1 +_1*0 -_1*0 -_3*0 +_3*1', - '-_0*0 +_0*1 +_1*0 -_1*0 -_3*0 +_3*1', - '+_0*0 -_0*1 +_1*0 -_1*1 -_3*0 +_3*1', - '-_0*0 +_0*1 +_1*0 -_1*1 -_3*0 +_3*1', - '+_0*0 -_0*1 -_1*0 +_1*1 -_3*0 +_3*1', - '-_0*0 +_0*1 -_1*0 +_1*1 -_3*0 +_3*1', - '+_0*0 -_0*1 +_1*1 -_1*1 -_3*0 +_3*1', - '-_0*0 +_0*1 +_1*1 -_1*1 -_3*0 +_3*1', - '+_0*0 -_0*1 +_2*0 -_2*0 -_3*0 +_3*1', - '-_0*0 +_0*1 +_2*0 -_2*0 -_3*0 +_3*1', - '+_0*0 -_0*0 +_2*0 -_2*1 -_3*0 +_3*1', - '+_0*1 -_0*1 +_2*0 -_2*1 -_3*0 +_3*1', - '+_1*0 -_1*0 +_2*0 -_2*1 -_3*0 +_3*1', - '+_1*0 -_1*1 +_2*0 -_2*1 -_3*0 +_3*1', - '-_1*0 +_1*1 +_2*0 -_2*1 -_3*0 +_3*1', - '+_1*1 -_1*1 +_2*0 -_2*1 -_3*0 +_3*1', - '+_0*0 -_0*0 -_2*0 +_2*1 -_3*0 +_3*1', - '+_0*1 -_0*1 -_2*0 +_2*1 -_3*0 +_3*1', - '+_1*0 -_1*0 -_2*0 +_2*1 -_3*0 +_3*1', - '+_1*0 -_1*1 -_2*0 +_2*1 -_3*0 +_3*1', - '-_1*0 +_1*1 -_2*0 +_2*1 -_3*0 +_3*1', - '+_1*1 -_1*1 -_2*0 +_2*1 -_3*0 +_3*1', - '+_0*0 -_0*1 +_2*1 -_2*1 -_3*0 +_3*1', - '-_0*0 +_0*1 +_2*1 -_2*1 -_3*0 +_3*1', - '+_0*0 -_0*1 +_2*0 -_2*1 +_3*1 -_3*1', - '-_0*0 +_0*1 +_2*0 -_2*1 +_3*1 -_3*1', - '+_0*0 -_0*1 -_2*0 +_2*1 +_3*1 -_3*1', - '-_0*0 +_0*1 -_2*0 +_2*1 +_3*1 -_3*1', + "+_0*0 -_0*0", + "+_0*1 -_0*1", + "+_1*0 -_1*0", + "+_1*0 -_1*1", + "-_1*0 +_1*1", + "+_1*1 -_1*1", + "+_2*0 -_2*0", + "+_2*1 -_2*1", + "+_3*0 -_3*0", + "+_3*1 -_3*1", + "+_0*0 -_0*0 +_1*0 -_1*0", + "+_0*1 -_0*1 +_1*0 -_1*0", + "+_0*0 -_0*0 +_1*0 -_1*1", + "+_0*1 -_0*1 +_1*0 -_1*1", + "+_0*0 -_0*0 -_1*0 +_1*1", + "+_0*1 -_0*1 -_1*0 +_1*1", + "+_0*0 -_0*0 +_1*1 -_1*1", + "+_0*1 -_0*1 +_1*1 -_1*1", + "+_0*0 -_0*0 +_2*0 -_2*0", + "+_0*1 -_0*1 +_2*0 -_2*0", + "+_1*0 -_1*0 +_2*0 -_2*0", + "+_1*0 -_1*1 +_2*0 -_2*0", + "-_1*0 +_1*1 +_2*0 -_2*0", + "+_1*1 -_1*1 +_2*0 -_2*0", + "+_0*0 -_0*1 +_2*0 -_2*1", + "-_0*0 +_0*1 +_2*0 -_2*1", + "+_0*0 -_0*1 -_2*0 +_2*1", + "-_0*0 +_0*1 -_2*0 +_2*1", + "+_0*0 -_0*0 +_2*1 -_2*1", + "+_0*1 -_0*1 +_2*1 -_2*1", + "+_1*0 -_1*0 +_2*1 -_2*1", + "+_1*0 -_1*1 +_2*1 -_2*1", + "-_1*0 +_1*1 +_2*1 -_2*1", + "+_1*1 -_1*1 +_2*1 -_2*1", + "+_0*0 -_0*0 +_3*0 -_3*0", + "+_0*1 -_0*1 +_3*0 -_3*0", + "+_1*0 -_1*0 +_3*0 -_3*0", + "+_1*0 -_1*1 +_3*0 -_3*0", + "-_1*0 +_1*1 +_3*0 -_3*0", + "+_1*1 -_1*1 +_3*0 -_3*0", + "+_2*0 -_2*0 +_3*0 -_3*0", + "+_2*1 -_2*1 +_3*0 -_3*0", + "+_0*0 -_0*1 +_3*0 -_3*1", + "-_0*0 +_0*1 +_3*0 -_3*1", + "+_2*0 -_2*1 +_3*0 -_3*1", + "-_2*0 +_2*1 +_3*0 -_3*1", + "+_0*0 -_0*1 -_3*0 +_3*1", + "-_0*0 +_0*1 -_3*0 +_3*1", + "+_2*0 -_2*1 -_3*0 +_3*1", + "-_2*0 +_2*1 -_3*0 +_3*1", + "+_0*0 -_0*0 +_3*1 -_3*1", + "+_0*1 -_0*1 +_3*1 -_3*1", + "+_1*0 -_1*0 +_3*1 -_3*1", + "+_1*0 -_1*1 +_3*1 -_3*1", + "-_1*0 +_1*1 +_3*1 -_3*1", + "+_1*1 -_1*1 +_3*1 -_3*1", + "+_2*0 -_2*0 +_3*1 -_3*1", + "+_2*1 -_2*1 +_3*1 -_3*1", + "+_0*0 -_0*1 +_1*0 -_1*0 +_2*0 -_2*1", + "-_0*0 +_0*1 +_1*0 -_1*0 +_2*0 -_2*1", + "+_0*0 -_0*1 +_1*0 -_1*1 +_2*0 -_2*1", + "-_0*0 +_0*1 +_1*0 -_1*1 +_2*0 -_2*1", + "+_0*0 -_0*1 -_1*0 +_1*1 +_2*0 -_2*1", + "-_0*0 +_0*1 -_1*0 +_1*1 +_2*0 -_2*1", + "+_0*0 -_0*1 +_1*1 -_1*1 +_2*0 -_2*1", + "-_0*0 +_0*1 +_1*1 -_1*1 +_2*0 -_2*1", + "+_0*0 -_0*1 +_1*0 -_1*0 -_2*0 +_2*1", + "-_0*0 +_0*1 +_1*0 -_1*0 -_2*0 +_2*1", + "+_0*0 -_0*1 +_1*0 -_1*1 -_2*0 +_2*1", + "-_0*0 +_0*1 +_1*0 -_1*1 -_2*0 +_2*1", + "+_0*0 -_0*1 -_1*0 +_1*1 -_2*0 +_2*1", + "-_0*0 +_0*1 -_1*0 +_1*1 -_2*0 +_2*1", + "+_0*0 -_0*1 +_1*1 -_1*1 -_2*0 +_2*1", + "-_0*0 +_0*1 +_1*1 -_1*1 -_2*0 +_2*1", + "+_0*0 -_0*1 +_2*0 -_2*1 +_3*0 -_3*0", + "-_0*0 +_0*1 +_2*0 -_2*1 +_3*0 -_3*0", + "+_0*0 -_0*1 -_2*0 +_2*1 +_3*0 -_3*0", + "-_0*0 +_0*1 -_2*0 +_2*1 +_3*0 -_3*0", + "+_0*0 -_0*1 +_1*0 -_1*0 +_3*0 -_3*1", + "-_0*0 +_0*1 +_1*0 -_1*0 +_3*0 -_3*1", + "+_0*0 -_0*1 +_1*0 -_1*1 +_3*0 -_3*1", + "-_0*0 +_0*1 +_1*0 -_1*1 +_3*0 -_3*1", + "+_0*0 -_0*1 -_1*0 +_1*1 +_3*0 -_3*1", + "-_0*0 +_0*1 -_1*0 +_1*1 +_3*0 -_3*1", + "+_0*0 -_0*1 +_1*1 -_1*1 +_3*0 -_3*1", + "-_0*0 +_0*1 +_1*1 -_1*1 +_3*0 -_3*1", + "+_0*0 -_0*1 +_2*0 -_2*0 +_3*0 -_3*1", + "-_0*0 +_0*1 +_2*0 -_2*0 +_3*0 -_3*1", + "+_0*0 -_0*0 +_2*0 -_2*1 +_3*0 -_3*1", + "+_0*1 -_0*1 +_2*0 -_2*1 +_3*0 -_3*1", + "+_1*0 -_1*0 +_2*0 -_2*1 +_3*0 -_3*1", + "+_1*0 -_1*1 +_2*0 -_2*1 +_3*0 -_3*1", + "-_1*0 +_1*1 +_2*0 -_2*1 +_3*0 -_3*1", + "+_1*1 -_1*1 +_2*0 -_2*1 +_3*0 -_3*1", + "+_0*0 -_0*0 -_2*0 +_2*1 +_3*0 -_3*1", + "+_0*1 -_0*1 -_2*0 +_2*1 +_3*0 -_3*1", + "+_1*0 -_1*0 -_2*0 +_2*1 +_3*0 -_3*1", + "+_1*0 -_1*1 -_2*0 +_2*1 +_3*0 -_3*1", + "-_1*0 +_1*1 -_2*0 +_2*1 +_3*0 -_3*1", + "+_1*1 -_1*1 -_2*0 +_2*1 +_3*0 -_3*1", + "+_0*0 -_0*1 +_2*1 -_2*1 +_3*0 -_3*1", + "-_0*0 +_0*1 +_2*1 -_2*1 +_3*0 -_3*1", + "+_0*0 -_0*1 +_1*0 -_1*0 -_3*0 +_3*1", + "-_0*0 +_0*1 +_1*0 -_1*0 -_3*0 +_3*1", + "+_0*0 -_0*1 +_1*0 -_1*1 -_3*0 +_3*1", + "-_0*0 +_0*1 +_1*0 -_1*1 -_3*0 +_3*1", + "+_0*0 -_0*1 -_1*0 +_1*1 -_3*0 +_3*1", + "-_0*0 +_0*1 -_1*0 +_1*1 -_3*0 +_3*1", + "+_0*0 -_0*1 +_1*1 -_1*1 -_3*0 +_3*1", + "-_0*0 +_0*1 +_1*1 -_1*1 -_3*0 +_3*1", + "+_0*0 -_0*1 +_2*0 -_2*0 -_3*0 +_3*1", + "-_0*0 +_0*1 +_2*0 -_2*0 -_3*0 +_3*1", + "+_0*0 -_0*0 +_2*0 -_2*1 -_3*0 +_3*1", + "+_0*1 -_0*1 +_2*0 -_2*1 -_3*0 +_3*1", + "+_1*0 -_1*0 +_2*0 -_2*1 -_3*0 +_3*1", + "+_1*0 -_1*1 +_2*0 -_2*1 -_3*0 +_3*1", + "-_1*0 +_1*1 +_2*0 -_2*1 -_3*0 +_3*1", + "+_1*1 -_1*1 +_2*0 -_2*1 -_3*0 +_3*1", + "+_0*0 -_0*0 -_2*0 +_2*1 -_3*0 +_3*1", + "+_0*1 -_0*1 -_2*0 +_2*1 -_3*0 +_3*1", + "+_1*0 -_1*0 -_2*0 +_2*1 -_3*0 +_3*1", + "+_1*0 -_1*1 -_2*0 +_2*1 -_3*0 +_3*1", + "-_1*0 +_1*1 -_2*0 +_2*1 -_3*0 +_3*1", + "+_1*1 -_1*1 -_2*0 +_2*1 -_3*0 +_3*1", + "+_0*0 -_0*1 +_2*1 -_2*1 -_3*0 +_3*1", + "-_0*0 +_0*1 +_2*1 -_2*1 -_3*0 +_3*1", + "+_0*0 -_0*1 +_2*0 -_2*1 +_3*1 -_3*1", + "-_0*0 +_0*1 +_2*0 -_2*1 +_3*1 -_3*1", + "+_0*0 -_0*1 -_2*0 +_2*1 +_3*1 -_3*1", + "-_0*0 +_0*1 -_2*0 +_2*1 +_3*1 -_3*1", ] _co2_freq_b3lyp_dense_labels = [ - 'NIIIIIII', - 'INIIIIII', - 'IINIIIII', - 'II+-IIII', - 'II-+IIII', - 'IIINIIII', - 'IIIINIII', - 'IIIIINII', - 'IIIIIINI', - 'IIIIIIIN', - 'NINIIIII', - 'INNIIIII', - 'NI+-IIII', - 'IN+-IIII', - 'NI-+IIII', - 'IN-+IIII', - 'NIINIIII', - 'ININIIII', - 'NIIINIII', - 'INIINIII', - 'IININIII', - 'II+-NIII', - 'II-+NIII', - 'IIINNIII', - '+-II+-II', - '-+II+-II', - '+-II-+II', - '-+II-+II', - 'NIIIINII', - 'INIIINII', - 'IINIINII', - 'II+-INII', - 'II-+INII', - 'IIININII', - 'NIIIIINI', - 'INIIIINI', - 'IINIIINI', - 'II+-IINI', - 'II-+IINI', - 'IIINIINI', - 'IIIININI', - 'IIIIINNI', - '+-IIII+-', - '-+IIII+-', - 'IIII+-+-', - 'IIII-++-', - '+-IIII-+', - '-+IIII-+', - 'IIII+--+', - 'IIII-+-+', - 'NIIIIIIN', - 'INIIIIIN', - 'IINIIIIN', - 'II+-IIIN', - 'II-+IIIN', - 'IIINIIIN', - 'IIIINIIN', - 'IIIIININ', - '+-NI+-II', - '-+NI+-II', - '+-+-+-II', - '-++-+-II', - '+--++-II', - '-+-++-II', - '+-IN+-II', - '-+IN+-II', - '+-NI-+II', - '-+NI-+II', - '+-+--+II', - '-++--+II', - '+--+-+II', - '-+-+-+II', - '+-IN-+II', - '-+IN-+II', - '+-II+-NI', - '-+II+-NI', - '+-II-+NI', - '-+II-+NI', - '+-NIII+-', - '-+NIII+-', - '+-+-II+-', - '-++-II+-', - '+--+II+-', - '-+-+II+-', - '+-INII+-', - '-+INII+-', - '+-IINI+-', - '-+IINI+-', - 'NIII+-+-', - 'INII+-+-', - 'IINI+-+-', - 'II+-+-+-', - 'II-++-+-', - 'IIIN+-+-', - 'NIII-++-', - 'INII-++-', - 'IINI-++-', - 'II+--++-', - 'II-+-++-', - 'IIIN-++-', - '+-IIIN+-', - '-+IIIN+-', - '+-NIII-+', - '-+NIII-+', - '+-+-II-+', - '-++-II-+', - '+--+II-+', - '-+-+II-+', - '+-INII-+', - '-+INII-+', - '+-IINI-+', - '-+IINI-+', - 'NIII+--+', - 'INII+--+', - 'IINI+--+', - 'II+-+--+', - 'II-++--+', - 'IIIN+--+', - 'NIII-+-+', - 'INII-+-+', - 'IINI-+-+', - 'II+--+-+', - 'II-+-+-+', - 'IIIN-+-+', - '+-IIIN-+', - '-+IIIN-+', - '+-II+-IN', - '-+II+-IN', - '+-II-+IN', - '-+II-+IN', + "NIIIIIII", + "INIIIIII", + "IINIIIII", + "II+-IIII", + "II-+IIII", + "IIINIIII", + "IIIINIII", + "IIIIINII", + "IIIIIINI", + "IIIIIIIN", + "NINIIIII", + "INNIIIII", + "NI+-IIII", + "IN+-IIII", + "NI-+IIII", + "IN-+IIII", + "NIINIIII", + "ININIIII", + "NIIINIII", + "INIINIII", + "IININIII", + "II+-NIII", + "II-+NIII", + "IIINNIII", + "+-II+-II", + "-+II+-II", + "+-II-+II", + "-+II-+II", + "NIIIINII", + "INIIINII", + "IINIINII", + "II+-INII", + "II-+INII", + "IIININII", + "NIIIIINI", + "INIIIINI", + "IINIIINI", + "II+-IINI", + "II-+IINI", + "IIINIINI", + "IIIININI", + "IIIIINNI", + "+-IIII+-", + "-+IIII+-", + "IIII+-+-", + "IIII-++-", + "+-IIII-+", + "-+IIII-+", + "IIII+--+", + "IIII-+-+", + "NIIIIIIN", + "INIIIIIN", + "IINIIIIN", + "II+-IIIN", + "II-+IIIN", + "IIINIIIN", + "IIIINIIN", + "IIIIININ", + "+-NI+-II", + "-+NI+-II", + "+-+-+-II", + "-++-+-II", + "+--++-II", + "-+-++-II", + "+-IN+-II", + "-+IN+-II", + "+-NI-+II", + "-+NI-+II", + "+-+--+II", + "-++--+II", + "+--+-+II", + "-+-+-+II", + "+-IN-+II", + "-+IN-+II", + "+-II+-NI", + "-+II+-NI", + "+-II-+NI", + "-+II-+NI", + "+-NIII+-", + "-+NIII+-", + "+-+-II+-", + "-++-II+-", + "+--+II+-", + "-+-+II+-", + "+-INII+-", + "-+INII+-", + "+-IINI+-", + "-+IINI+-", + "NIII+-+-", + "INII+-+-", + "IINI+-+-", + "II+-+-+-", + "II-++-+-", + "IIIN+-+-", + "NIII-++-", + "INII-++-", + "IINI-++-", + "II+--++-", + "II-+-++-", + "IIIN-++-", + "+-IIIN+-", + "-+IIIN+-", + "+-NIII-+", + "-+NIII-+", + "+-+-II-+", + "-++-II-+", + "+--+II-+", + "-+-+II-+", + "+-INII-+", + "-+INII-+", + "+-IINI-+", + "-+IINI-+", + "NIII+--+", + "INII+--+", + "IINI+--+", + "II+-+--+", + "II-++--+", + "IIIN+--+", + "NIII-+-+", + "INII-+-+", + "IINI-+-+", + "II+--+-+", + "II-+-+-+", + "IIIN-+-+", + "+-IIIN-+", + "-+IIIN-+", + "+-II+-IN", + "-+II+-IN", + "+-II-+IN", + "-+II-+IN", ] _co2_freq_b3lyp_coeffs = [ diff --git a/test/problems/second_quantization/vibrational/test_vibrational_problem.py b/test/problems/second_quantization/vibrational/test_vibrational_problem.py index a504d4281d..417a884088 100644 --- a/test/problems/second_quantization/vibrational/test_vibrational_problem.py +++ b/test/problems/second_quantization/vibrational/test_vibrational_problem.py @@ -25,7 +25,8 @@ def test_second_q_ops_without_transformers(self): provided.""" expected_num_of_sec_quant_ops = 5 logfile = self.get_resource_path( - 'CO2_freq_B3LYP_ccpVDZ.log', 'problems/second_quantization/vibrational/resources' + "CO2_freq_B3LYP_ccpVDZ.log", + "problems/second_quantization/vibrational/resources", ) driver = GaussianForcesDriver(logfile=logfile) @@ -34,10 +35,14 @@ def test_second_q_ops_without_transformers(self): truncation_order = 3 num_modes = watson_hamiltonian.num_modes num_modals = [num_modals] * num_modes - vibrational_problem = VibrationalStructureProblem(driver, num_modals, truncation_order) + vibrational_problem = VibrationalStructureProblem( + driver, num_modals, truncation_order + ) second_quantized_ops = vibrational_problem.second_q_ops() vibrational_op = second_quantized_ops[0] - with self.subTest("Check expected length of the list of second quantized operators."): + with self.subTest( + "Check expected length of the list of second quantized operators." + ): assert len(second_quantized_ops) == expected_num_of_sec_quant_ops with self.subTest("Check types in the list of second quantized operators."): assert isinstance(vibrational_op, VibrationalOp) diff --git a/test/test_end2end_with_vqe.py b/test/test_end2end_with_vqe.py index 745260bfa6..e11329c3d7 100644 --- a/test/test_end2end_with_vqe.py +++ b/test/test_end2end_with_vqe.py @@ -24,7 +24,9 @@ from qiskit_nature.drivers import HDF5Driver from qiskit_nature.mappers.second_quantization import ParityMapper from qiskit_nature.converters.second_quantization.qubit_converter import QubitConverter -from qiskit_nature.problems.second_quantization.electronic import ElectronicStructureProblem +from qiskit_nature.problems.second_quantization.electronic import ( + ElectronicStructureProblem, +) class TestEnd2End(QiskitNatureTestCase): @@ -34,28 +36,33 @@ def setUp(self): super().setUp() algorithm_globals.random_seed = 42 - driver = HDF5Driver(hdf5_input=self.get_resource_path('test_driver_hdf5.hdf5', - 'drivers/hdf5d')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("test_driver_hdf5.hdf5", "drivers/hdf5d") + ) problem = ElectronicStructureProblem(driver) second_q_ops = problem.second_q_ops() converter = QubitConverter(mapper=ParityMapper(), two_qubit_reduction=True) - num_particles = (problem.molecule_data_transformed.num_alpha, - problem.molecule_data_transformed.num_beta) + num_particles = ( + problem.molecule_data_transformed.num_alpha, + problem.molecule_data_transformed.num_beta, + ) self.qubit_op = converter.convert(second_q_ops[0], num_particles) self.aux_ops = converter.convert_match(second_q_ops[1:]) self.reference_energy = -1.857275027031588 def test_end2end_h2(self): - """ end to end h2 """ - backend = BasicAer.get_backend('statevector_simulator') + """end to end h2""" + backend = BasicAer.get_backend("statevector_simulator") shots = 1 optimizer = COBYLA(maxiter=1000) - ryrz = TwoLocal(rotation_blocks=['ry', 'rz'], entanglement_blocks='cz') + ryrz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz") quantum_instance = QuantumInstance(backend, shots=shots) vqe = VQE(ryrz, optimizer=optimizer, quantum_instance=quantum_instance) - result = vqe.compute_minimum_eigenvalue(self.qubit_op, aux_operators=self.aux_ops) + result = vqe.compute_minimum_eigenvalue( + self.qubit_op, aux_operators=self.aux_ops + ) self.assertAlmostEqual(result.eigenvalue.real, self.reference_energy, places=4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/test_readme_sample.py b/test/test_readme_sample.py index 3f6bdfed46..82f06be2aa 100644 --- a/test/test_readme_sample.py +++ b/test/test_readme_sample.py @@ -30,57 +30,67 @@ def setUp(self): try: # pylint: disable=import-outside-toplevel from qiskit_nature.drivers import PySCFDriver - PySCFDriver(atom='Li .0 .0 .0; H .0 .0 1.6') + + PySCFDriver(atom="Li .0 .0 .0; H .0 .0 1.6") except QiskitNatureError: - self.skipTest('PYSCF driver does not appear to be installed') + self.skipTest("PYSCF driver does not appear to be installed") try: # pylint: disable=import-outside-toplevel # pylint: disable=unused-import from qiskit import Aer - _ = Aer.get_backend('statevector_simulator') + + _ = Aer.get_backend("statevector_simulator") except ImportError as ex: # pylint: disable=broad-except - self.skipTest("Aer doesn't appear to be installed. Error: '{}'".format(str(ex))) + self.skipTest( + "Aer doesn't appear to be installed. Error: '{}'".format(str(ex)) + ) return def test_readme_sample(self): - """ readme sample test """ + """readme sample test""" # pylint: disable=import-outside-toplevel,redefined-builtin def print(*args): - """ overloads print to log values """ + """overloads print to log values""" if args: self.log.debug(args[0], *args[1:]) # --- Exact copy of sample code ---------------------------------------- from qiskit_nature.drivers import PySCFDriver, UnitsType - from qiskit_nature.problems.second_quantization.electronic import ElectronicStructureProblem + from qiskit_nature.problems.second_quantization.electronic import ( + ElectronicStructureProblem, + ) # Use PySCF, a classical computational chemistry software # package, to compute the one-body and two-body integrals in # electronic-orbital basis, necessary to form the Fermionic operator - driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', - unit=UnitsType.ANGSTROM, - basis='sto3g') + driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g" + ) problem = ElectronicStructureProblem(driver) # generate the second-quantized operators second_q_ops = problem.second_q_ops() main_op = second_q_ops[0] - num_particles = (problem.molecule_data_transformed.num_alpha, - problem.molecule_data_transformed.num_beta) + num_particles = ( + problem.molecule_data_transformed.num_alpha, + problem.molecule_data_transformed.num_beta, + ) num_spin_orbitals = 2 * problem.molecule_data.num_molecular_orbitals # setup the classical optimizer for VQE from qiskit.algorithms.optimizers import L_BFGS_B + optimizer = L_BFGS_B() # setup the mapper and qubit converter from qiskit_nature.mappers.second_quantization import ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter + mapper = ParityMapper() converter = QubitConverter(mapper=mapper, two_qubit_reduction=True) @@ -89,24 +99,26 @@ def print(*args): # setup the initial state for the ansatz from qiskit_nature.circuit.library import HartreeFock + init_state = HartreeFock(num_spin_orbitals, num_particles, converter) # setup the ansatz for VQE from qiskit.circuit.library import TwoLocal - ansatz = TwoLocal(num_spin_orbitals, ['ry', 'rz'], 'cz') + + ansatz = TwoLocal(num_spin_orbitals, ["ry", "rz"], "cz") # add the initial state ansatz.compose(init_state, front=True) # set the backend for the quantum computation from qiskit import Aer - backend = Aer.get_backend('statevector_simulator') + + backend = Aer.get_backend("statevector_simulator") # setup and run VQE from qiskit.algorithms import VQE - algorithm = VQE(ansatz, - optimizer=optimizer, - quantum_instance=backend) + + algorithm = VQE(ansatz, optimizer=optimizer, quantum_instance=backend) result = algorithm.compute_minimum_eigenvalue(qubit_op) print(result.eigenvalue.real) @@ -119,5 +131,5 @@ def print(*args): self.assertAlmostEqual(result.eigenvalue.real, -1.8572750301938803, places=6) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/transformers/test_active_space_transformer.py b/test/transformers/test_active_space_transformer.py index 4b6d51e109..ad24a90f70 100644 --- a/test/transformers/test_active_space_transformer.py +++ b/test/transformers/test_active_space_transformer.py @@ -28,44 +28,66 @@ class TestActiveSpaceTransformer(QiskitNatureTestCase): """ActiveSpaceTransformer tests.""" - def assertQMolecule(self, q_molecule, expected, dict_key='ActiveSpaceTransformer'): + def assertQMolecule(self, q_molecule, expected, dict_key="ActiveSpaceTransformer"): """Asserts that the two `QMolecule object's relevant fields are equivalent.""" - with self.subTest('MO 1-electron integrals'): - np.testing.assert_array_almost_equal(q_molecule.mo_onee_ints, expected.mo_onee_ints) - with self.subTest('MO 2-electron integrals'): - np.testing.assert_array_almost_equal(q_molecule.mo_eri_ints, expected.mo_eri_ints) - with self.subTest('Inactive energy'): - self.assertAlmostEqual(q_molecule.energy_shift[dict_key], - expected.energy_shift['ActiveSpaceTransformer']) - - with self.subTest('MO 1-electron x dipole integrals'): - np.testing.assert_array_almost_equal(q_molecule.x_dip_mo_ints, expected.x_dip_mo_ints) - with self.subTest('X dipole energy shift'): - self.assertAlmostEqual(q_molecule.x_dip_energy_shift[dict_key], - expected.x_dip_energy_shift['ActiveSpaceTransformer']) - with self.subTest('MO 1-electron y dipole integrals'): - np.testing.assert_array_almost_equal(q_molecule.y_dip_mo_ints, expected.y_dip_mo_ints) - with self.subTest('Y dipole energy shift'): - self.assertAlmostEqual(q_molecule.y_dip_energy_shift[dict_key], - expected.y_dip_energy_shift['ActiveSpaceTransformer']) - with self.subTest('MO 1-electron z dipole integrals'): - np.testing.assert_array_almost_equal(q_molecule.z_dip_mo_ints, expected.z_dip_mo_ints) - with self.subTest('Z dipole energy shift'): - self.assertAlmostEqual(q_molecule.z_dip_energy_shift[dict_key], - expected.z_dip_energy_shift['ActiveSpaceTransformer']) - - @idata([ - {'num_electrons': 2, 'num_molecular_orbitals': 2}, - ]) + with self.subTest("MO 1-electron integrals"): + np.testing.assert_array_almost_equal( + q_molecule.mo_onee_ints, expected.mo_onee_ints + ) + with self.subTest("MO 2-electron integrals"): + np.testing.assert_array_almost_equal( + q_molecule.mo_eri_ints, expected.mo_eri_ints + ) + with self.subTest("Inactive energy"): + self.assertAlmostEqual( + q_molecule.energy_shift[dict_key], + expected.energy_shift["ActiveSpaceTransformer"], + ) + + with self.subTest("MO 1-electron x dipole integrals"): + np.testing.assert_array_almost_equal( + q_molecule.x_dip_mo_ints, expected.x_dip_mo_ints + ) + with self.subTest("X dipole energy shift"): + self.assertAlmostEqual( + q_molecule.x_dip_energy_shift[dict_key], + expected.x_dip_energy_shift["ActiveSpaceTransformer"], + ) + with self.subTest("MO 1-electron y dipole integrals"): + np.testing.assert_array_almost_equal( + q_molecule.y_dip_mo_ints, expected.y_dip_mo_ints + ) + with self.subTest("Y dipole energy shift"): + self.assertAlmostEqual( + q_molecule.y_dip_energy_shift[dict_key], + expected.y_dip_energy_shift["ActiveSpaceTransformer"], + ) + with self.subTest("MO 1-electron z dipole integrals"): + np.testing.assert_array_almost_equal( + q_molecule.z_dip_mo_ints, expected.z_dip_mo_ints + ) + with self.subTest("Z dipole energy shift"): + self.assertAlmostEqual( + q_molecule.z_dip_energy_shift[dict_key], + expected.z_dip_energy_shift["ActiveSpaceTransformer"], + ) + + @idata( + [ + {"num_electrons": 2, "num_molecular_orbitals": 2}, + ] + ) def test_full_active_space(self, kwargs): """Test that transformer has no effect when all orbitals are active.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_sto3g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_sto3g.hdf5", "transformers") + ) q_molecule = driver.run() - q_molecule.energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.x_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.y_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.z_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 + q_molecule.energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.x_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.y_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.z_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 trafo = ActiveSpaceTransformer(**kwargs) q_molecule_reduced = trafo.transform(q_molecule) @@ -74,7 +96,9 @@ def test_full_active_space(self, kwargs): def test_minimal_active_space(self): """Test a minimal active space manually.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) q_molecule = driver.run() trafo = ActiveSpaceTransformer(num_electrons=2, num_molecular_orbitals=2) @@ -82,89 +106,125 @@ def test_minimal_active_space(self): expected = QMolecule() expected.mo_onee_ints = np.asarray([[-1.24943841, 0.0], [0.0, -0.547816138]]) - expected.mo_eri_ints = np.asarray([[[[0.652098466, 0.0], [0.0, 0.433536565]], - [[0.0, 0.0794483182], [0.0794483182, 0.0]]], - [[[0.0, 0.0794483182], [0.0794483182, 0.0]], - [[0.433536565, 0.0], [0.0, 0.385524695]]]]) + expected.mo_eri_ints = np.asarray( + [ + [ + [[0.652098466, 0.0], [0.0, 0.433536565]], + [[0.0, 0.0794483182], [0.0794483182, 0.0]], + ], + [ + [[0.0, 0.0794483182], [0.0794483182, 0.0]], + [[0.433536565, 0.0], [0.0, 0.385524695]], + ], + ] + ) expected.x_dip_mo_ints = np.zeros((2, 2)) expected.y_dip_mo_ints = np.zeros((2, 2)) - expected.z_dip_mo_ints = np.asarray([[0.69447435, -1.01418298], [-1.01418298, 0.69447435]]) + expected.z_dip_mo_ints = np.asarray( + [[0.69447435, -1.01418298], [-1.01418298, 0.69447435]] + ) - expected.energy_shift['ActiveSpaceTransformer'] = 0.0 - expected.x_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - expected.y_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - expected.z_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 + expected.energy_shift["ActiveSpaceTransformer"] = 0.0 + expected.x_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + expected.y_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + expected.z_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 self.assertQMolecule(q_molecule_reduced, expected) def test_unpaired_electron_active_space(self): """Test an active space with an unpaired electron.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('BeH_sto3g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("BeH_sto3g.hdf5", "transformers") + ) q_molecule = driver.run() trafo = ActiveSpaceTransformer(num_electrons=(2, 1), num_molecular_orbitals=3) q_molecule_reduced = trafo.transform(q_molecule) - expected = HDF5Driver(hdf5_input=self.get_resource_path('BeH_sto3g_reduced.hdf5', - 'transformers')).run() + expected = HDF5Driver( + hdf5_input=self.get_resource_path("BeH_sto3g_reduced.hdf5", "transformers") + ).run() self.assertQMolecule(q_molecule_reduced, expected) def test_arbitrary_active_orbitals(self): """Test manual selection of active orbital indices.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_631g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_631g.hdf5", "transformers") + ) q_molecule = driver.run() - trafo = ActiveSpaceTransformer(num_electrons=2, num_molecular_orbitals=2, - active_orbitals=[0, 2]) + trafo = ActiveSpaceTransformer( + num_electrons=2, num_molecular_orbitals=2, active_orbitals=[0, 2] + ) q_molecule_reduced = trafo.transform(q_molecule) expected = QMolecule() - expected.mo_onee_ints = np.asarray([[-1.24943841, -0.16790838], [-0.16790838, -0.18307469]]) - expected.mo_eri_ints = np.asarray([[[[0.65209847, 0.16790822], [0.16790822, 0.53250905]], - [[0.16790822, 0.10962908], [0.10962908, 0.11981429]]], - [[[0.16790822, 0.10962908], [0.10962908, 0.11981429]], - [[0.53250905, 0.11981429], [0.11981429, 0.46345617]]]]) + expected.mo_onee_ints = np.asarray( + [[-1.24943841, -0.16790838], [-0.16790838, -0.18307469]] + ) + expected.mo_eri_ints = np.asarray( + [ + [ + [[0.65209847, 0.16790822], [0.16790822, 0.53250905]], + [[0.16790822, 0.10962908], [0.10962908, 0.11981429]], + ], + [ + [[0.16790822, 0.10962908], [0.10962908, 0.11981429]], + [[0.53250905, 0.11981429], [0.11981429, 0.46345617]], + ], + ] + ) expected.x_dip_mo_ints = np.zeros((2, 2)) expected.y_dip_mo_ints = np.zeros((2, 2)) expected.z_dip_mo_ints = np.asarray([[0.69447435, 0.0], [0.0, 0.69447435]]) - expected.energy_shift['ActiveSpaceTransformer'] = 0.0 - expected.x_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - expected.y_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - expected.z_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 + expected.energy_shift["ActiveSpaceTransformer"] = 0.0 + expected.x_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + expected.y_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + expected.z_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 self.assertQMolecule(q_molecule_reduced, expected) - @idata([ - [2, 3, None, "More active orbitals requested than available in total."], - [4, 2, None, "More active electrons requested than available in total."], - [(1, 0), 2, None, "The number of inactive electrons may not be odd."], - [2, 2, [0, 1, 2], "The number of active orbitals do not match."], - [2, 2, [1, 2], "The number of active electrons do not match."], - ]) + @idata( + [ + [2, 3, None, "More active orbitals requested than available in total."], + [4, 2, None, "More active electrons requested than available in total."], + [(1, 0), 2, None, "The number of inactive electrons may not be odd."], + [2, 2, [0, 1, 2], "The number of active orbitals do not match."], + [2, 2, [1, 2], "The number of active electrons do not match."], + ] + ) @unpack - def test_error_raising(self, num_electrons, num_molecular_orbitals, active_orbitals, message): + def test_error_raising( + self, num_electrons, num_molecular_orbitals, active_orbitals, message + ): """Test errors are being raised in certain scenarios.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_sto3g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_sto3g.hdf5", "transformers") + ) q_molecule = driver.run() with self.assertRaises(QiskitNatureError, msg=message): - ActiveSpaceTransformer(num_electrons=num_electrons, - num_molecular_orbitals=num_molecular_orbitals, - active_orbitals=active_orbitals).transform(q_molecule) + ActiveSpaceTransformer( + num_electrons=num_electrons, + num_molecular_orbitals=num_molecular_orbitals, + active_orbitals=active_orbitals, + ).transform(q_molecule) def test_active_space_for_q_molecule_v2(self): """Test based on QMolecule v2 (mo_occ not available).""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_sto3g_v2.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_sto3g_v2.hdf5", "transformers") + ) q_molecule = driver.run() - q_molecule.energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.x_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.y_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.z_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 + q_molecule.energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.x_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.y_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.z_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 trafo = ActiveSpaceTransformer(num_electrons=2, num_molecular_orbitals=2) q_molecule_reduced = trafo.transform(q_molecule) @@ -172,5 +232,5 @@ def test_active_space_for_q_molecule_v2(self): self.assertQMolecule(q_molecule_reduced, q_molecule) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/test/transformers/test_freeze_core_transformer.py b/test/transformers/test_freeze_core_transformer.py index a980fba6b4..63a96eed89 100644 --- a/test/transformers/test_freeze_core_transformer.py +++ b/test/transformers/test_freeze_core_transformer.py @@ -26,52 +26,68 @@ class TestFreezeCoreTransformer(TestActiveSpaceTransformer): """FreezeCoreTransformer tests.""" - @idata([ - {'freeze_core': True}, - ]) + @idata( + [ + {"freeze_core": True}, + ] + ) def test_full_active_space(self, kwargs): """Test that transformer has no effect when all orbitals are active.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('H2_sto3g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("H2_sto3g.hdf5", "transformers") + ) q_molecule = driver.run() # The references which we compare too were produced by the `ActiveSpaceTransformer` and, # thus, the key here needs to stay the same as in that test case. - q_molecule.energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.x_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.y_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 - q_molecule.z_dip_energy_shift['ActiveSpaceTransformer'] = 0.0 + q_molecule.energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.x_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.y_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 + q_molecule.z_dip_energy_shift["ActiveSpaceTransformer"] = 0.0 trafo = FreezeCoreTransformer(**kwargs) q_molecule_reduced = trafo.transform(q_molecule) - self.assertQMolecule(q_molecule_reduced, q_molecule, dict_key='FreezeCoreTransformer') + self.assertQMolecule( + q_molecule_reduced, q_molecule, dict_key="FreezeCoreTransformer" + ) def test_freeze_core(self): """Test the `freeze_core` convenience argument.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('LiH_sto3g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("LiH_sto3g.hdf5", "transformers") + ) q_molecule = driver.run() trafo = FreezeCoreTransformer(freeze_core=True) q_molecule_reduced = trafo.transform(q_molecule) - expected = HDF5Driver(hdf5_input=self.get_resource_path('LiH_sto3g_reduced.hdf5', - 'transformers')).run() + expected = HDF5Driver( + hdf5_input=self.get_resource_path("LiH_sto3g_reduced.hdf5", "transformers") + ).run() - self.assertQMolecule(q_molecule_reduced, expected, dict_key='FreezeCoreTransformer') + self.assertQMolecule( + q_molecule_reduced, expected, dict_key="FreezeCoreTransformer" + ) def test_freeze_core_with_remove_orbitals(self): """Test the `freeze_core` convenience argument in combination with `remove_orbitals`.""" - driver = HDF5Driver(hdf5_input=self.get_resource_path('BeH_sto3g.hdf5', 'transformers')) + driver = HDF5Driver( + hdf5_input=self.get_resource_path("BeH_sto3g.hdf5", "transformers") + ) q_molecule = driver.run() trafo = FreezeCoreTransformer(freeze_core=True, remove_orbitals=[4, 5]) q_molecule_reduced = trafo.transform(q_molecule) - expected = HDF5Driver(hdf5_input=self.get_resource_path('BeH_sto3g_reduced.hdf5', - 'transformers')).run() + expected = HDF5Driver( + hdf5_input=self.get_resource_path("BeH_sto3g_reduced.hdf5", "transformers") + ).run() - self.assertQMolecule(q_molecule_reduced, expected, dict_key='FreezeCoreTransformer') + self.assertQMolecule( + q_molecule_reduced, expected, dict_key="FreezeCoreTransformer" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tools/check_copyright.py b/tools/check_copyright.py index d56cd88ce2..3905a313cc 100644 --- a/tools/check_copyright.py +++ b/tools/check_copyright.py @@ -22,19 +22,21 @@ class CopyrightChecker: - """ Check copyright """ + """Check copyright""" - _UTF_STRING = '# -*- coding: utf-8 -*-' - _COPYRIGHT_STRING = '# (C) Copyright IBM ' + _UTF_STRING = "# -*- coding: utf-8 -*-" + _COPYRIGHT_STRING = "# (C) Copyright IBM " def __init__(self, root_dir: str) -> None: self._root_dir = root_dir @staticmethod def _exception_to_string(excp: Exception) -> str: - stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__) + stack = traceback.extract_stack()[:-3] + traceback.extract_tb( + excp.__traceback__ + ) pretty = traceback.format_list(stack) - return ''.join(pretty) + '\n {} {}'.format(excp.__class__, excp) + return "".join(pretty) + "\n {} {}".format(excp.__class__, excp) @staticmethod def _get_year_from_date(date) -> int: @@ -45,29 +47,33 @@ def _get_year_from_date(date) -> int: @staticmethod def _format_output(out: bytes, err: bytes) -> Tuple[int, Union[None, str]]: - out_str = out.decode('utf-8').strip() - err_str = err.decode('utf-8').strip() + out_str = out.decode("utf-8").strip() + err_str = err.decode("utf-8").strip() err_str = err_str if err_str else None year = CopyrightChecker._get_year_from_date(out_str) return year, err_str - def _process_file_last_year(self, relative_path: str) -> Tuple[int, Union[None, str]]: + def _process_file_last_year( + self, relative_path: str + ) -> Tuple[int, Union[None, str]]: # construct minimal environment env = {} - for k in ['SYSTEMROOT', 'PATH']: + for k in ["SYSTEMROOT", "PATH"]: v = os.environ.get(k) if v is not None: env[k] = v # LANGUAGE is used on win32 - env['LANGUAGE'] = 'C' - env['LANG'] = 'C' - env['LC_ALL'] = 'C' - with subprocess.Popen(['git', 'log', '-1', '--format=%aI', relative_path], - cwd=self._root_dir, - env=env, - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) as popen: + env["LANGUAGE"] = "C" + env["LANG"] = "C" + env["LC_ALL"] = "C" + with subprocess.Popen( + ["git", "log", "-1", "--format=%aI", relative_path], + cwd=self._root_dir, + env=env, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) as popen: out, err = popen.communicate() popen.wait() return CopyrightChecker._format_output(out, err) @@ -83,18 +89,18 @@ def _get_file_last_year(self, relative_path: str) -> int: errors.append("'{}' Last year: {}".format(relative_path, str(ex))) if errors: - raise ValueError(' - '.join(errors)) + raise ValueError(" - ".join(errors)) return last_year def check_copyright(self, file_path) -> Tuple[bool, bool, bool]: - """ check copyright for a file """ + """check copyright for a file""" now = datetime.datetime.now() file_with_utf8 = False file_with_invalid_year = False file_has_header = False try: - with open(file_path, 'rt', encoding="utf8") as file: + with open(file_path, "rt", encoding="utf8") as file: for line in file: relative_path = os.path.relpath(file_path, self._root_dir) if line.startswith(CopyrightChecker._UTF_STRING): @@ -107,8 +113,8 @@ def check_copyright(self, file_path) -> Tuple[bool, bool, bool]: file_has_header = True curr_years = [] for word in line.strip().split(): - for year in word.strip().split(','): - if year.startswith('20') and len(year) >= 4: + for year in word.strip().split(","): + if year.startswith("20") and len(year) >= 4: try: curr_years.append(int(year[0:4])) except ValueError: @@ -124,13 +130,16 @@ def check_copyright(self, file_path) -> Tuple[bool, bool, bool]: last_year = self._get_file_last_year(relative_path) if last_year and header_last_year != last_year: - new_line = '# (C) Copyright IBM ' + new_line = "# (C) Copyright IBM " if header_start_year and header_start_year != last_year: - new_line += '{}, '.format(header_start_year) + new_line += "{}, ".format(header_start_year) - new_line += '{}.\n'.format(now.year) - print("Wrong Copyright Year: '{}': Current: '{}' Correct: '{}'".format( - relative_path, line[:-1], new_line[:-1])) + new_line += "{}.\n".format(now.year) + print( + "Wrong Copyright Year: '{}': Current: '{}' Correct: '{}'".format( + relative_path, line[:-1], new_line[:-1] + ) + ) file_with_invalid_year = True @@ -142,7 +151,7 @@ def check_copyright(self, file_path) -> Tuple[bool, bool, bool]: return file_with_utf8, file_with_invalid_year, file_has_header def check(self) -> Tuple[int, int, int]: - """ check copyright """ + """check copyright""" return self._check(self._root_dir) def _check(self, path: str) -> Tuple[int, int, int]: @@ -152,7 +161,7 @@ def _check(self, path: str) -> Tuple[int, int, int]: for item in os.listdir(path): fullpath = os.path.join(path, item) if os.path.isdir(fullpath): - if not item.startswith('.'): + if not item.startswith("."): files = self._check(fullpath) files_with_utf8 += files[0] files_with_invalid_year += files[1] @@ -161,8 +170,11 @@ def _check(self, path: str) -> Tuple[int, int, int]: if os.path.isfile(fullpath): # check copyright year - file_with_utf8, file_with_invalid_year, file_has_header = \ - self.check_copyright(fullpath) + ( + file_with_utf8, + file_with_invalid_year, + file_has_header, + ) = self.check_copyright(fullpath) if file_with_utf8: files_with_utf8 += 1 if file_with_invalid_year: @@ -174,19 +186,18 @@ def _check(self, path: str) -> Tuple[int, int, int]: def check_path(path): - """ valid path argument """ + """valid path argument""" if not path or os.path.isdir(path): return path raise argparse.ArgumentTypeError("readable_dir:{} is not a valid path".format(path)) -if __name__ == '__main__': - PARSER = argparse.ArgumentParser(description='Nature Check Copyright Tool') - PARSER.add_argument('-path', - type=check_path, - metavar='path', - help='Root path of project.') +if __name__ == "__main__": + PARSER = argparse.ArgumentParser(description="Nature Check Copyright Tool") + PARSER.add_argument( + "-path", type=check_path, metavar="path", help="Root path of project." + ) ARGS = PARSER.parse_args() if not ARGS.path: @@ -195,7 +206,10 @@ def check_path(path): ARGS.path = os.path.abspath(os.path.realpath(os.path.expanduser(ARGS.path))) INVALID_UTF8, INVALID_YEAR, HAS_HEADER = CopyrightChecker(ARGS.path).check() print("{} files have utf8 headers.".format(INVALID_UTF8)) - print("{} of {} files with copyright header have wrong years.".format( - INVALID_YEAR, HAS_HEADER)) + print( + "{} of {} files with copyright header have wrong years.".format( + INVALID_YEAR, HAS_HEADER + ) + ) sys.exit(os.EX_OK if INVALID_UTF8 == 0 and INVALID_YEAR == 0 else os.EX_SOFTWARE) diff --git a/tools/extract_deprecation.py b/tools/extract_deprecation.py index 250f6c5ac8..7441315434 100644 --- a/tools/extract_deprecation.py +++ b/tools/extract_deprecation.py @@ -19,7 +19,7 @@ class DeprecationExtractor: - """ Extract deprecation messages """ + """Extract deprecation messages""" def __init__(self, in_file: str, out_file: str) -> None: self._input_filename = in_file @@ -35,9 +35,9 @@ def extract_messages(self) -> bool: self._messages = None messages = set() - with open(self._input_filename, 'rt', encoding="utf8", errors='ignore') as file: + with open(self._input_filename, "rt", encoding="utf8", errors="ignore") as file: for line in file: - if line.find('DeprecationWarning:') > 0: + if line.find("DeprecationWarning:") > 0: messages.add(line.strip()) if messages: @@ -57,19 +57,19 @@ def save_to_output(self, force_create: bool) -> bool: if self._output_filename: # create file even if it is empty if self._messages or force_create: - with open(self._output_filename, 'w') as file: + with open(self._output_filename, "w") as file: if self._messages: - file.write('\n'.join(self._messages)) + file.write("\n".join(self._messages)) return True return False def print_messages(self) -> None: - """ print messages """ + """print messages""" if self._messages: - print('---------------------') - print('Deprecation Messages:') - print('---------------------') + print("---------------------") + print("Deprecation Messages:") + print("---------------------") for line in self._messages: print(line) @@ -81,16 +81,14 @@ def _check_file(path) -> str: return path -if __name__ == '__main__': - PARSER = argparse.ArgumentParser(description='Qiskit Extract Deprecation Messages Tool') - PARSER.add_argument('-file', - type=_check_file, - required=True, - metavar='file', - help='Input file.') - PARSER.add_argument('-output', - metavar='output', - help='Output file.') +if __name__ == "__main__": + PARSER = argparse.ArgumentParser( + description="Qiskit Extract Deprecation Messages Tool" + ) + PARSER.add_argument( + "-file", type=_check_file, required=True, metavar="file", help="Input file." + ) + PARSER.add_argument("-output", metavar="output", help="Output file.") ARGS = PARSER.parse_args() diff --git a/tox.ini b/tox.ini index a22311a909..33fd1db0e1 100644 --- a/tox.ini +++ b/tox.ini @@ -18,13 +18,18 @@ commands = stestr run {posargs} [testenv:lint] +envdir = .tox/lint basepython = python3 commands = - pycodestyle qiskit_nature test tools + black --check --exclude="gauopen" {posargs} qiskit_nature test tools pylint -rn --ignore=gauopen qiskit_nature test tools mypy qiskit_nature test tools python3 {toxinidir}/tools/check_copyright.py -path {toxinidir} +[testenv:black] +envdir = .tox/lint +commands = black --exclude="gauopen" {posargs} qiskit_nature test tools + [testenv:coverage] basepython = python3 setenv = @@ -41,7 +46,7 @@ commands = sphinx-build -b html {posargs} docs/ docs/_build/html [pycodestyle] +max-line-length = 105 exclude = gauopen -# default ignores + E741 -ignore = E121, E123, E126, E133, E226, E241, E242, E704, W503, W504, W505, E741 -max-line-length = 100 +# + E203 because of a difference of opinion with black +ignore = E121, E123, E126, E133, E226, E241, E242, E704, W503, W504, W505, E203