From efab7e03cfc1904fdff49dd13ed7386bb2fb91ce Mon Sep 17 00:00:00 2001 From: Anthony-Gandon Date: Fri, 5 Aug 2022 08:28:33 +0200 Subject: [PATCH] Adds documentation for the default_filter_criterion (#726) * Adds documentation for the default_filter_criterion to explicit the singlet spin configuration assumption. * Fixes the documentation. * Fixes some checks. * Fixes style. * Moves the docstring from the method get_default_filter_criterion to the class docstring. Changes the test for custom filters to a more relevant example with the doublets of BeH * Changes are now applied to the class located at qiskit_nature/second_q/problems * Fixes the test * Fixes the test * Fixes the test * Updates documentation the test * Retests after coverall issue * Retest after coverall issue * Fix indenting of the docstring * Update qiskit_nature/second_q/problems/electronic_structure_problem.py Co-authored-by: Max Rossmannek Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Max Rossmannek --- .pylintdict | 1 + .../problems/electronic_structure_problem.py | 31 ++++++++++ .../test_excited_states_solvers.py | 58 +++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/.pylintdict b/.pylintdict index 1fc34c9770..ddfddba947 100644 --- a/.pylintdict +++ b/.pylintdict @@ -205,6 +205,7 @@ interatomic internuclear interpretable ints +isclose ising iso isoleucine diff --git a/qiskit_nature/second_q/problems/electronic_structure_problem.py b/qiskit_nature/second_q/problems/electronic_structure_problem.py index 12be2cbce0..d673f8cb64 100644 --- a/qiskit_nature/second_q/problems/electronic_structure_problem.py +++ b/qiskit_nature/second_q/problems/electronic_structure_problem.py @@ -43,6 +43,37 @@ class ElectronicStructureProblem(BaseProblem): The attributes `num_particles` and `num_spin_orbitals` are only available _after_ the `second_q_ops()` method has been called! Note, that if you do so, the method will be executed again when the problem is being solved. + + In the fermionic case the default filter ensures that the number of particles is being + preserved. + + .. note:: + + The default filter_criterion assumes a singlet spin configuration. This means, that the + number of alpha-spin electrons is equal to the number of beta-spin electrons. + If the :class:`~qiskit_nature.second_q.properties.AngularMomentum` + property is available, one can correctly filter a non-singlet spin configuration with a + custom `filter_criterion` similar to the following: + + .. code-block:: python + + import numpy as np + from qiskit_nature.second_q.algorithms import NumPyEigensolverFactory + + expected_spin = 2 + expected_num_electrons = 6 + + def filter_criterion_custom(eigenstate, eigenvalue, aux_values): + num_particles_aux = aux_values["ParticleNumber"][0] + total_angular_momentum_aux = aux_values["AngularMomentum"][0] + + return ( + np.isclose(expected_spin, total_angular_momentum_aux) and + np.isclose(expected_num_electrons, num_particles_aux) + ) + + solver = NumPyEigensolverFactory(filter_criterion=filter_criterion_spin) + """ def __init__( diff --git a/test/second_q/algorithms/excited_state_solvers/test_excited_states_solvers.py b/test/second_q/algorithms/excited_state_solvers/test_excited_states_solvers.py index 2fd9b1fa91..668a31f9f0 100644 --- a/test/second_q/algorithms/excited_state_solvers/test_excited_states_solvers.py +++ b/test/second_q/algorithms/excited_state_solvers/test_excited_states_solvers.py @@ -13,12 +13,14 @@ """ Test Numerical qEOM excited states calculation """ import unittest + from test import QiskitNatureTestCase import numpy as np from qiskit import BasicAer from qiskit.utils import algorithm_globals, QuantumInstance from qiskit.algorithms import NumPyMinimumEigensolver, NumPyEigensolver +from qiskit_nature.second_q.transformers import ActiveSpaceTransformer from qiskit_nature.second_q.drivers import UnitsType from qiskit_nature.second_q.drivers import PySCFDriver from qiskit_nature.second_q.mappers import ( @@ -151,6 +153,62 @@ def filter_criterion(eigenstate, eigenvalue, aux_values): for idx, energy in enumerate(self.reference_energies): self.assertAlmostEqual(computed_energies[idx], energy, places=4) + def test_custom_filter_criterion(self): + """Test NumPyEigenSolverFactory with ExcitedStatesEigensolver + Custom filter criterion + for doublet states""" + + driver = PySCFDriver( + atom="Be .0 .0 .0; H .0 .0 0.75", + unit=UnitsType.ANGSTROM, + charge=0, + spin=1, + basis="sto3g", + ) + + transformer = ActiveSpaceTransformer( + num_electrons=(1, 2), + num_molecular_orbitals=4, + ) + # We define an ActiveSpaceTransformer to reduce the duration of this test example. + + converter = QubitConverter(JordanWignerMapper(), z2symmetry_reduction="auto") + + esp = ElectronicStructureProblem(driver, [transformer]) + + expected_spin = 0.75 # Doublet states + expected_num_electrons = 3 # 1 alpha electron + 2 beta electrons + + # pylint: disable=unused-argument + def custom_filter_criterion(eigenstate, eigenvalue, aux_values): + num_particles_aux = aux_values["ParticleNumber"][0] + total_angular_momentum_aux = aux_values["AngularMomentum"][0] + + return np.isclose(expected_spin, total_angular_momentum_aux) and np.isclose( + expected_num_electrons, num_particles_aux + ) + + solver = NumPyEigensolverFactory(filter_criterion=custom_filter_criterion) + esc = ExcitedStatesEigensolver(converter, solver) + results = esc.solve(esp) + + # filter duplicates from list + computed_energies = [results.computed_energies[0]] + for comp_energy in results.computed_energies[1:]: + if not np.isclose(comp_energy, computed_energies[-1]): + computed_energies.append(comp_energy) + + ref_energies = [ + -2.6362023196223254, + -2.2971398524128923, + -2.2020252702733165, + -2.1044859216523752, + -1.696132447109807, + -1.6416831059956618, + ] + + for idx, energy in enumerate(ref_energies): + self.assertAlmostEqual(computed_energies[idx], energy, places=3) + if __name__ == "__main__": unittest.main()