-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix the AngularMomentum
(again)
#1292
Changes from 7 commits
1c4264c
c2d426a
abc6e0e
89f15ae
93b8bb6
212533d
531bb81
cf8ebf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
|
||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import Mapping | ||
|
||
import numpy as np | ||
|
@@ -23,6 +24,8 @@ | |
|
||
from .s_operators import s_minus_operator, s_plus_operator, s_z_operator | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
class AngularMomentum: | ||
r"""The AngularMomentum property. | ||
|
@@ -31,7 +34,7 @@ class AngularMomentum: | |
|
||
.. math:: | ||
|
||
S^2 = S^- S^+ + S^z (S^z + 1) | ||
S^2 = (S^+ S^- + S^- S^+) / 2 + S^z S^z | ||
|
||
.. warning:: | ||
|
||
|
@@ -49,20 +52,53 @@ class AngularMomentum: | |
|
||
Attributes: | ||
num_spatial_orbitals (int): the number of spatial orbitals. | ||
overlap (np.ndarray | None): the overlap-matrix between the $\alpha$- and $\beta$-spin | ||
orbitals. When this is `None`, the overlap-matrix is assumed to be identity. | ||
""" | ||
|
||
def __init__(self, num_spatial_orbitals: int, overlap: np.ndarray | None = None) -> None: | ||
r""" | ||
Args: | ||
num_spatial_orbitals: the number of spatial orbitals in the system. | ||
overlap: the overlap-matrix between the $\alpha$- and $\beta$-spin orbitals. When this | ||
is `None`, the overlap-matrix is assumed to be identity. | ||
is ``None``, the overlap-matrix is assumed to be identity. | ||
""" | ||
self.num_spatial_orbitals = num_spatial_orbitals | ||
self._overlap: np.ndarray | None = None | ||
self.overlap = overlap | ||
|
||
@property | ||
def overlap(self) -> np.ndarray | None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it ever possible for this to return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this can be left as |
||
r"""The overlap-matrix between the $\alpha$- and $\beta$-spin orbitals. | ||
|
||
When this is ``None``, the overlap-matrix is assumed to be identity. | ||
""" | ||
return self._overlap | ||
|
||
@overlap.setter | ||
def overlap(self, overlap: np.ndarray | None) -> None: | ||
self._overlap = overlap | ||
|
||
if overlap is not None: | ||
norb = self.num_spatial_orbitals | ||
delta = np.eye(2 * norb) | ||
delta[:norb, :norb] -= overlap.T @ overlap | ||
delta[norb:, norb:] -= overlap @ overlap.T | ||
summed = np.einsum("ij->", np.abs(delta)) | ||
if not np.isclose(summed, 0.0, atol=1e-6): | ||
LOGGER.warning( | ||
"The provided alpha-beta overlap matrix is NOT unitary! This can happen when " | ||
"the alpha- and beta-spin orbitals do not span the same space. To provide an " | ||
"example of what this means, consider an active space chosen from unrestricted-" | ||
"spin orbitals. Computing <S^2> within this active space may not result in the " | ||
"same <S^2> value as obtained on the single-reference starting point. More " | ||
"importantly, this implies that the inactive subspace will account for the " | ||
"difference between these two <S^2> values, possibly resulting in significant " | ||
"spin contamination in both subspaces. You should verify whether this is " | ||
"intentional/acceptable or whether your choice of active space can be improved." | ||
" As a reference, here is the summed-absolute deviation of `S^T @ S` from the " | ||
"identity: %s", | ||
str(summed), | ||
) | ||
|
||
def second_q_ops(self) -> Mapping[str, FermionicOp]: | ||
"""Returns the second quantized angular momentum operator. | ||
|
||
|
@@ -75,7 +111,8 @@ def second_q_ops(self) -> Mapping[str, FermionicOp]: | |
overlap_ba = overlap_ab.T if overlap_ab is not None else None | ||
s_m = s_minus_operator(self.num_spatial_orbitals, overlap=overlap_ba) | ||
|
||
op = s_m @ s_p + s_z @ (s_z + FermionicOp.one()) | ||
spm_smp = (s_p @ s_m + s_m @ s_p).normal_order() | ||
op = 0.5 * spm_smp + s_z @ s_z | ||
|
||
return {self.__class__.__name__: op} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
features: | ||
- | | ||
The :meth:`.AngularMomentum.overlap` property will now warn the user, when | ||
this matrix is non-unitary. | ||
fixes: | ||
- | | ||
Fixes the :class:`.AngularMomentum` operator further to also support cases | ||
where the number of beta-spin particles exceeds the number of alpha-spin | ||
particles. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my education: isn't this overridden by the
overlap
property?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it now (I think! 😺) this line will call the setter and apply the initialization logic. But then is there a point to type-hint
self._overlap
a union type? Couldn't it be justnp.ndarray
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first line here makes sure that pylint does not complain about the private
_overlap
attribute not being defined inside the__init__
(because otherwise it would be defined inside theproperty
method.I am typing it for the sake of completeness 👍