1
1
r"""Molkit Module."""
2
2
3
- from .utils .spinops import antisymmetrize_two_body , get_spin_blocks
3
+ from .utils .spinops import (
4
+ antisymmetrize_two_body ,
5
+ get_spin_blocks ,
6
+ upscale_one_body
7
+ )
4
8
import numpy as np
5
9
6
10
@@ -28,12 +32,100 @@ def __init__(self, one_body, two_body):
28
32
self .n_spin = 2 * self .n_spatial
29
33
self .reduced_ham = None
30
34
35
+ def antisymmetrize (self ):
36
+ """Apply proper antisymmetrization to two-electron integrals."""
37
+ self .two_body = antisymmetrize_two_body (self .two_body , inplace = True )
38
+
39
+ def get_spin_blocks (self ):
40
+ """Return the main spin blocks of the two-body spin-orbital tensor.
41
+
42
+ Returns
43
+ -------
44
+ dict
45
+ Dictionary with spin blocks: 'aaaa', 'bbbb', 'abab'
46
+
47
+ """
48
+ if not hasattr (self , "two_body_spin" ):
49
+ raise RuntimeError (
50
+ "Call .spinize() first to compute spin-orbital form." )
51
+
52
+ return get_spin_blocks (self .two_body_spin , self .n_spatial )
53
+
54
+ def to_geminal (self , two_body = None , type = 'h2' ):
55
+ r"""
56
+ Convert the two-body term to the geminal basis.
57
+
58
+ Parameters
59
+ ----------
60
+ two_body : np.ndarray
61
+ Two-body term in spin-orbital basis in physics notation.
62
+ type : str
63
+ ['rdm2', 'h2']. Type of the two-body term.
64
+ - 'rdm2' : 2 body reduced density matrix
65
+ - 'h2' : 2 body Hamiltonian
66
+
67
+ Returns
68
+ -------
69
+ two_body_gem : np.ndarray
70
+ Two-body term in the geminal basis
71
+
72
+ Notes
73
+ -----
74
+ Assuming that rdm2 obbey the following permutation rules:
75
+ - :math:`\Gamma_{p q r s}=-\Gamma_{q p r s}=-\Gamma_{p q s r}
76
+ =\Gamma_{q p s r}`
77
+ we can convert the two-body term to the geminal basis
78
+ by the following formula:
79
+
80
+ .. math::
81
+
82
+ \Gamma_{p q}=0.5 * 4 \Gamma_{p q r s}
83
+
84
+ where:
85
+ - :math:`\Gamma_{p q}` is the two-body term in the geminal basis
86
+ - :math:`\Gamma_{p q r s}` is the two-body term in the spin-orbital
87
+ Hamiltonian in the geminal basis is obtained by the following formula:
88
+
89
+ .. math::
90
+
91
+ V_{A B}
92
+ =\frac{1}{2}\left(V_{p q r s}-V_{q p r s}-V_{p q r s}+V_{qprs}\right)
93
+
94
+ """
95
+ n = two_body .shape [0 ]
96
+ two_body_gem = []
97
+
98
+ # i,j,k,l -> pqrs
99
+ for p in range (n ):
100
+ for q in range (p + 1 , n ):
101
+ for r in range (n ):
102
+ for s in range (r + 1 , n ):
103
+ if type == 'rdm2' :
104
+ two_body_gem .append (
105
+ 0.5 * 4 * two_body [p , q , r , s ]
106
+ )
107
+ elif type == 'h2' :
108
+ two_body_gem .append (
109
+ 0.5 * (
110
+ two_body [p , q , r , s ]
111
+ - two_body [q , p , r , s ]
112
+ - two_body [p , q , s , r ]
113
+ + two_body [q , p , s , r ]
114
+ )
115
+ )
116
+
117
+ n_gem = n * (n - 1 ) // 2
118
+ return np .array (two_body_gem ).reshape (n_gem , n_gem )
119
+
31
120
def spinize_H (self ) -> tuple [np .ndarray , np .ndarray ]:
32
121
r"""Convert the one/two body terms from spatial to spin-orbital basis.
33
122
34
123
Parameters
35
124
----------
36
- None
125
+ one_body : np.ndarray
126
+ One-body term in spatial orbital basis (shape (n, n)).
127
+ two_body : np.ndarray
128
+ Two-body term in spatial orbital basis (shape (n, n, n, n)).
37
129
38
130
Returns
39
131
-------
@@ -56,8 +148,7 @@ def spinize_H(self) -> tuple[np.ndarray, np.ndarray]:
56
148
V_{pqrs}^{\\text{spatial}}`
57
149
58
150
"""
59
- one_body = self .one_body
60
- two_body = self .two_body
151
+ one_body , two_body = self .one_body , self .two_body
61
152
one_body = np .asarray (one_body )
62
153
two_body = np .asarray (two_body )
63
154
@@ -85,85 +176,39 @@ def spinize_H(self) -> tuple[np.ndarray, np.ndarray]:
85
176
86
177
return one_body_spin , two_body_spin
87
178
88
- def antisymmetrize (self ):
89
- """Apply proper antisymmetrization to two-electron integrals."""
90
- self .two_body = antisymmetrize_two_body (self .two_body , inplace = True )
91
-
92
- def get_spin_blocks (self ):
93
- """Return the main spin blocks of the two-body spin-orbital tensor.
94
-
95
- Returns
96
- -------
97
- dict
98
- Dictionary with spin blocks: 'aaaa', 'bbbb', 'abab'
99
-
100
- """
101
- if not hasattr (self , "two_body_spin" ):
102
- raise RuntimeError (
103
- "Call .spinize() first to compute spin-orbital form." )
179
+ def to_reduced (self , n_elec ):
180
+ r"""Return the reduced 4-index Hamiltonian tensor.
104
181
105
- return get_spin_blocks ( self . two_body_spin , self . n_spatial )
182
+ .. math::
106
183
107
- def to_geminal ( two_body ):
108
- r"""Convert the two-body term to the geminal basis .
184
+ k_{pqrs}=\frac{1}{2\,(N-1)}\bigl(h_{pq}\,\delta_{rs}
185
+ +h_{rs}\,\delta_{pq}\bigr)+\tfrac12\,V_{pqrs} .
109
186
110
187
Parameters
111
188
----------
112
- two_body : np.ndarray
113
- Two-body term in spin-orbital basis in physics notation.
189
+ one_body_spatial : ndarray, shape (n, n)
190
+ One‑electron integral matrix :math:`h_{pq}` in a spatial‑orbital
191
+ basis.
192
+ two_body_spatial : ndarray, shape (n, n, n, n)
193
+ Two‑electron integral tensor :math:`V_{pqrs}` (Dirac convention,
194
+ spatial orbitals).
195
+ n_elec : int
196
+ Number of electrons *N* in the system.
114
197
115
198
Returns
116
199
-------
117
- two_body_gem : np.ndarray
118
- Two-body term in the geminal basis
200
+ ndarray, shape (2n, 2n, 2n, 2n)
201
+ Reduced Hamiltonian tensor :math:`k_{pqrs}` in the
202
+ spin‑orbital basis.
119
203
120
204
Notes
121
205
-----
122
- Assuming that rdm2 obbey the following permutation rules:
123
- - :math:`\Gamma_{p q r s}=-\Gamma_{q p r s}=-\Gamma_{p q s r}
124
- =\Gamma_{q p s r}`
125
- we can convert the two-body term to the geminal basis
126
- by the following formula:
127
-
128
- .. math::
129
-
130
- \Gamma_{p q}=0.5 * 4 \Gamma_{p q r s}
131
-
132
- where:
133
- - :math:`\Gamma_{p q}` is the two-body term in the geminal basis
134
- - :math:`\Gamma_{p q r s}` is the two-body term in the spin-orbital
135
- Hamiltonian in the geminal basis is obtained by the following formula:
136
-
137
- .. math::
138
-
139
- V_{A B}
140
- =\frac{1}{2}\left(V_{p q r s}-V_{q p r s}-V_{p q r s}+V_{qprs}\right)
141
-
142
- This is coming from the fact, that the Hamiltonian object
143
- retured from the fcidump (converted to the physics notation)
144
- doesn't obbey the permutation rules.
145
- Thus, the full formula has to be used.
146
-
206
+ The function is stateless; it does not modify the parent
207
+ ``MolHam`` instance.
147
208
"""
148
- n = two_body .shape [0 ]
149
- two_body_gem = []
209
+ h_spin , V_spin = self .spinize_H ()
150
210
151
- # i,j,k,l -> pqrs
152
- for p in range (n ):
153
- for q in range (p + 1 , n ):
154
- for r in range (n ):
155
- for s in range (r + 1 , n ):
156
- term = 0.5 * (
157
- two_body [p , q , r , s ]
158
- - two_body [q , p , r , s ]
159
- - two_body [p , q , s , r ]
160
- + two_body [q , p , s , r ]
161
- )
162
- two_body_gem .append (term )
163
-
164
- n_gem = n * (n - 1 ) // 2
165
- return np .array (two_body_gem ).reshape (n_gem , n_gem )
211
+ h_upscaled = upscale_one_body (h_spin , n_elec )
166
212
167
- def build_reduced (self ):
168
- """Build the reduced hamiltonian form."""
169
- pass
213
+ k = h_upscaled + 0.5 * V_spin
214
+ return k
0 commit comments