pyscf 2.6.2__py3-none-macosx_11_0_arm64.whl → 2.8.0__py3-none-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. pyscf/__init__.py +2 -2
  2. pyscf/adc/__init__.py +3 -8
  3. pyscf/adc/dfadc.py +22 -6
  4. pyscf/adc/radc.py +106 -15
  5. pyscf/adc/radc_amplitudes.py +7 -1
  6. pyscf/adc/radc_ao2mo.py +4 -2
  7. pyscf/adc/radc_ea.py +524 -8
  8. pyscf/adc/radc_ip.py +492 -60
  9. pyscf/adc/radc_ip_cvs.py +4 -2
  10. pyscf/adc/uadc.py +116 -27
  11. pyscf/adc/uadc_amplitudes.py +215 -20
  12. pyscf/adc/uadc_ao2mo.py +30 -9
  13. pyscf/adc/uadc_ea.py +34 -44
  14. pyscf/adc/uadc_ip.py +9 -4
  15. pyscf/adc/uadc_ip_cvs.py +4 -1
  16. pyscf/agf2/__init__.py +2 -2
  17. pyscf/agf2/aux_space.py +1 -1
  18. pyscf/agf2/chkfile.py +1 -1
  19. pyscf/ao2mo/__init__.py +13 -2
  20. pyscf/ao2mo/_ao2mo.py +10 -1
  21. pyscf/ao2mo/incore.py +3 -0
  22. pyscf/ao2mo/nrr_outcore.py +2 -2
  23. pyscf/ao2mo/outcore.py +9 -7
  24. pyscf/ao2mo/r_outcore.py +2 -2
  25. pyscf/cc/__init__.py +21 -3
  26. pyscf/cc/bccd.py +0 -46
  27. pyscf/cc/ccsd.py +29 -13
  28. pyscf/cc/ccsd_rdm.py +6 -1
  29. pyscf/cc/gccsd.py +2 -2
  30. pyscf/cc/uccsd.py +7 -7
  31. pyscf/cc/uccsd_rdm.py +2 -2
  32. pyscf/data/elements.py +1 -1
  33. pyscf/df/__init__.py +2 -1
  34. pyscf/df/addons.py +79 -51
  35. pyscf/df/autoaux.py +195 -0
  36. pyscf/df/df.py +5 -1
  37. pyscf/df/df_jk.py +27 -25
  38. pyscf/df/grad/casscf.py +0 -41
  39. pyscf/df/grad/rhf.py +31 -1
  40. pyscf/df/hessian/rhf.py +2 -10
  41. pyscf/df/hessian/rks.py +1 -7
  42. pyscf/df/hessian/uhf.py +3 -13
  43. pyscf/df/hessian/uks.py +1 -8
  44. pyscf/df/incore.py +18 -6
  45. pyscf/df/outcore.py +6 -6
  46. pyscf/dft/dks.py +1 -1
  47. pyscf/dft/gks.py +25 -21
  48. pyscf/dft/libxc.py +91 -645
  49. pyscf/dft/numint.py +40 -19
  50. pyscf/dft/radi.py +48 -7
  51. pyscf/dft/rks.py +29 -25
  52. pyscf/dft/roks.py +7 -1
  53. pyscf/dft/uks.py +34 -25
  54. pyscf/dft/xc_deriv.py +1 -1
  55. pyscf/dft/xcfun.py +53 -2
  56. pyscf/eph/eph_fd.py +1 -1
  57. pyscf/eph/rhf.py +6 -36
  58. pyscf/eph/rks.py +0 -4
  59. pyscf/eph/uhf.py +1 -7
  60. pyscf/eph/uks.py +1 -7
  61. pyscf/fci/addons.py +117 -2
  62. pyscf/fci/cistring.py +1 -1
  63. pyscf/fci/direct_nosym.py +3 -3
  64. pyscf/fci/direct_spin0_symm.py +22 -43
  65. pyscf/fci/direct_spin1.py +65 -10
  66. pyscf/fci/direct_spin1_symm.py +49 -14
  67. pyscf/fci/direct_uhf.py +4 -4
  68. pyscf/fci/selected_ci_symm.py +1 -1
  69. pyscf/grad/ccsd.py +3 -7
  70. pyscf/grad/ccsd_slow.py +2 -3
  71. pyscf/grad/lagrange.py +11 -3
  72. pyscf/grad/mp2.py +13 -4
  73. pyscf/grad/sacasscf.py +1 -1
  74. pyscf/grad/tdrks.py +1 -1
  75. pyscf/grad/uccsd.py +3 -7
  76. pyscf/grad/ump2.py +2 -4
  77. pyscf/gto/basis/__init__.py +17 -4
  78. pyscf/gto/basis/bse.py +68 -15
  79. pyscf/gto/basis/def2-mtzvp.dat +4719 -0
  80. pyscf/gto/basis/def2-mtzvpp.dat +4739 -0
  81. pyscf/gto/basis/dyall-basis/__init__.py +0 -0
  82. pyscf/gto/basis/dyall-basis/dyall_2zp.py +6492 -0
  83. pyscf/gto/basis/dyall-basis/dyall_3zp.py +8343 -0
  84. pyscf/gto/basis/dyall-basis/dyall_4zp.py +10055 -0
  85. pyscf/gto/basis/dyall-basis/dyall_aae2z.py +1818 -0
  86. pyscf/gto/basis/dyall-basis/dyall_aae3z.py +2521 -0
  87. pyscf/gto/basis/dyall-basis/dyall_aae4z.py +3351 -0
  88. pyscf/gto/basis/dyall-basis/dyall_acv2z.py +1790 -0
  89. pyscf/gto/basis/dyall-basis/dyall_acv3z.py +2417 -0
  90. pyscf/gto/basis/dyall-basis/dyall_acv4z.py +3085 -0
  91. pyscf/gto/basis/dyall-basis/dyall_ae2z.py +6619 -0
  92. pyscf/gto/basis/dyall-basis/dyall_ae3z.py +9027 -0
  93. pyscf/gto/basis/dyall-basis/dyall_ae4z.py +11839 -0
  94. pyscf/gto/basis/dyall-basis/dyall_av2z.py +1742 -0
  95. pyscf/gto/basis/dyall-basis/dyall_av3z.py +2318 -0
  96. pyscf/gto/basis/dyall-basis/dyall_av4z.py +2905 -0
  97. pyscf/gto/basis/dyall-basis/dyall_cv2z.py +6558 -0
  98. pyscf/gto/basis/dyall-basis/dyall_cv3z.py +8767 -0
  99. pyscf/gto/basis/dyall-basis/dyall_cv4z.py +11098 -0
  100. pyscf/gto/basis/dyall-basis/dyall_v2z.py +6472 -0
  101. pyscf/gto/basis/dyall-basis/dyall_v3z.py +8539 -0
  102. pyscf/gto/basis/dyall-basis/dyall_v4z.py +10658 -0
  103. pyscf/gto/basis/ma-def2-qzvp.dat +5959 -0
  104. pyscf/gto/basis/ma-def2-qzvpp.dat +6195 -0
  105. pyscf/gto/basis/ma-def2-svp.dat +3504 -0
  106. pyscf/gto/basis/ma-def2-svpp.dat +3504 -0
  107. pyscf/gto/basis/ma-def2-tzvp.dat +4347 -0
  108. pyscf/gto/basis/ma-def2-tzvpp.dat +4549 -0
  109. pyscf/gto/basis/parse_cp2k.py +8 -7
  110. pyscf/gto/basis/parse_cp2k_pp.py +1 -1
  111. pyscf/gto/basis/parse_nwchem.py +26 -11
  112. pyscf/gto/basis/parse_nwchem_ecp.py +2 -1
  113. pyscf/gto/basis/sap_grasp_large.dat +2438 -0
  114. pyscf/gto/basis/sap_grasp_small.dat +1434 -0
  115. pyscf/gto/eval_gto.py +1 -1
  116. pyscf/gto/ft_ao.py +6 -6
  117. pyscf/gto/mole.py +123 -71
  118. pyscf/gto/moleintor.py +1 -1
  119. pyscf/gw/gw_ac.py +2 -2
  120. pyscf/gw/gw_cd.py +2 -2
  121. pyscf/gw/rpa.py +135 -246
  122. pyscf/gw/ugw_ac.py +2 -2
  123. pyscf/gw/urpa.py +80 -131
  124. pyscf/hessian/rhf.py +30 -128
  125. pyscf/hessian/rks.py +1 -6
  126. pyscf/hessian/uhf.py +28 -138
  127. pyscf/hessian/uks.py +1 -8
  128. pyscf/lib/CMakeLists.txt +6 -2
  129. pyscf/lib/ao2mo/nr_ao2mo.c +1 -1
  130. pyscf/lib/ao2mo/nrr_ao2mo.c +1 -1
  131. pyscf/lib/ao2mo/r_ao2mo.c +1 -1
  132. pyscf/lib/cc/ccsd_pack.c +1 -1
  133. pyscf/lib/cc/ccsd_t.c +6 -6
  134. pyscf/lib/cc/uccsd_t.c +4 -4
  135. pyscf/lib/config.h +0 -1
  136. pyscf/lib/config.h.in +0 -1
  137. pyscf/lib/deps/include/XCFun/XCFunExport.h +1 -0
  138. pyscf/lib/deps/include/xc.h +28 -18
  139. pyscf/lib/deps/include/xc_funcs.h +50 -2
  140. pyscf/lib/deps/include/xc_version.h +3 -3
  141. pyscf/lib/deps/lib/libcint.6.dylib +0 -0
  142. pyscf/lib/deps/lib/{libxc.12.dylib → libxc.15.dylib} +0 -0
  143. pyscf/lib/deps/lib/libxcfun.2.dylib +0 -0
  144. pyscf/lib/dft/grid_common.c +1 -1
  145. pyscf/lib/dft/libxc_itrf.c +10 -7
  146. pyscf/lib/dft/nr_numint_sparse.c +3 -3
  147. pyscf/lib/dft/xcfun_itrf.c +1 -1
  148. pyscf/lib/diis.py +2 -2
  149. pyscf/lib/exceptions.py +6 -0
  150. pyscf/lib/gto/fill_grids_int2c.c +11 -9
  151. pyscf/lib/gto/fill_int2e.c +7 -5
  152. pyscf/lib/gto/fill_r_4c.c +1 -1
  153. pyscf/lib/gto/ft_ao.c +1 -1
  154. pyscf/lib/gto/ft_ao.h +1 -1
  155. pyscf/lib/gto/gto.h +2 -2
  156. pyscf/lib/gto/nr_ecp.c +3 -2
  157. pyscf/lib/libagf2.dylib +0 -0
  158. pyscf/lib/libao2mo.dylib +0 -0
  159. pyscf/lib/libcc.dylib +0 -0
  160. pyscf/lib/libcgto.dylib +0 -0
  161. pyscf/lib/libcvhf.dylib +0 -0
  162. pyscf/lib/libdft.dylib +0 -0
  163. pyscf/lib/libfci.dylib +0 -0
  164. pyscf/lib/libmcscf.dylib +0 -0
  165. pyscf/lib/libmp.dylib +0 -0
  166. pyscf/lib/libnp_helper.dylib +0 -0
  167. pyscf/lib/libpbc.dylib +0 -0
  168. pyscf/lib/libri.dylib +0 -0
  169. pyscf/lib/libxc_itrf.dylib +0 -0
  170. pyscf/lib/libxcfun_itrf.dylib +0 -0
  171. pyscf/lib/linalg_helper.py +117 -198
  172. pyscf/lib/logger.py +2 -1
  173. pyscf/lib/mcscf/fci_contract.c +10 -3
  174. pyscf/lib/misc.py +63 -22
  175. pyscf/lib/mp/CMakeLists.txt +22 -0
  176. pyscf/lib/mp/mp2.c +518 -0
  177. pyscf/lib/mp/mp2.h +44 -0
  178. pyscf/lib/np_helper/CMakeLists.txt +1 -1
  179. pyscf/lib/np_helper/imatcopy.c +360 -0
  180. pyscf/lib/np_helper/np_helper.c +94 -0
  181. pyscf/lib/np_helper/np_helper.h +26 -0
  182. pyscf/lib/numpy_helper.py +195 -11
  183. pyscf/lib/pbc/nr_direct.c +2 -7
  184. pyscf/lib/pbc/nr_ecp.c +10 -3
  185. pyscf/lib/pbc/pbc.h +1 -1
  186. pyscf/lib/vhf/fblas.h +3 -0
  187. pyscf/lib/vhf/nr_sgx_direct.c +8 -6
  188. pyscf/lib/vhf/nr_sr_vhf.c +8 -12
  189. pyscf/lib/vhf/optimizer.c +2 -2
  190. pyscf/lib/vhf/rkb_screen.c +139 -0
  191. pyscf/lo/iao.py +1 -1
  192. pyscf/lo/ibo.py +3 -3
  193. pyscf/lo/pipek_jacobi.py +1 -1
  194. pyscf/mcscf/__init__.py +2 -2
  195. pyscf/mcscf/addons.py +3 -3
  196. pyscf/mcscf/apc.py +2 -2
  197. pyscf/mcscf/casci.py +13 -7
  198. pyscf/mcscf/chkfile.py +69 -41
  199. pyscf/mcscf/dmet_cas.py +2 -2
  200. pyscf/mcscf/mc1step.py +72 -44
  201. pyscf/mcscf/newton_casscf.py +5 -5
  202. pyscf/mcscf/ucasci.py +1 -1
  203. pyscf/mcscf/umc1step.py +49 -28
  204. pyscf/md/integrators.py +3 -3
  205. pyscf/mp/__init__.py +1 -0
  206. pyscf/mp/dfmp2.py +498 -59
  207. pyscf/mp/dfmp2_native.py +11 -1
  208. pyscf/mp/dfmp2_slow.py +133 -0
  209. pyscf/mp/dfump2.py +672 -0
  210. pyscf/mp/dfump2_native.py +9 -0
  211. pyscf/mp/dfump2_slow.py +161 -0
  212. pyscf/mp/gmp2.py +6 -47
  213. pyscf/mp/mp2.py +25 -10
  214. pyscf/mp/ump2.py +30 -24
  215. pyscf/pbc/adc/kadc_rhf.py +1 -1
  216. pyscf/pbc/adc/kadc_rhf_amplitudes.py +2 -2
  217. pyscf/pbc/ao2mo/eris.py +1 -1
  218. pyscf/pbc/cc/kccsd_rhf.py +3 -3
  219. pyscf/pbc/cc/kccsd_t_rhf.py +2 -2
  220. pyscf/pbc/ci/kcis_rhf.py +2 -2
  221. pyscf/pbc/df/aft.py +8 -9
  222. pyscf/pbc/df/aft_ao2mo.py +1 -1
  223. pyscf/pbc/df/df.py +85 -12
  224. pyscf/pbc/df/df_jk.py +6 -2
  225. pyscf/pbc/df/fft.py +9 -5
  226. pyscf/pbc/df/fft_ao2mo.py +4 -0
  227. pyscf/pbc/df/fft_jk.py +18 -10
  228. pyscf/pbc/df/ft_ao.py +4 -3
  229. pyscf/pbc/df/gdf_builder.py +5 -4
  230. pyscf/pbc/df/incore.py +2 -2
  231. pyscf/pbc/df/mdf.py +6 -3
  232. pyscf/pbc/df/mdf_jk.py +2 -1
  233. pyscf/pbc/df/outcore.py +10 -10
  234. pyscf/pbc/df/rsdf.py +2 -2
  235. pyscf/pbc/df/rsdf_builder.py +13 -8
  236. pyscf/pbc/df/rsdf_helper.py +6 -6
  237. pyscf/pbc/df/rsdf_jk.py +2 -1
  238. pyscf/pbc/dft/cdft.py +5 -5
  239. pyscf/pbc/dft/gen_grid.py +3 -2
  240. pyscf/pbc/dft/gks.py +14 -3
  241. pyscf/pbc/dft/kgks.py +15 -4
  242. pyscf/pbc/dft/krks.py +28 -10
  243. pyscf/pbc/dft/krks_ksymm.py +21 -9
  244. pyscf/pbc/dft/krkspu.py +1 -30
  245. pyscf/pbc/dft/krkspu_ksymm.py +0 -30
  246. pyscf/pbc/dft/kuks.py +30 -13
  247. pyscf/pbc/dft/kuks_ksymm.py +22 -10
  248. pyscf/pbc/dft/kukspu.py +0 -27
  249. pyscf/pbc/dft/kukspu_ksymm.py +0 -30
  250. pyscf/pbc/dft/multigrid/multigrid.py +36 -33
  251. pyscf/pbc/dft/multigrid/multigrid_pair.py +7 -2
  252. pyscf/pbc/dft/multigrid/pp.py +1 -1
  253. pyscf/pbc/dft/numint.py +56 -31
  254. pyscf/pbc/dft/rks.py +16 -24
  255. pyscf/pbc/dft/uks.py +21 -4
  256. pyscf/pbc/eph/eph_fd.py +1 -1
  257. pyscf/pbc/geomopt/geometric_solver.py +1 -1
  258. pyscf/pbc/gto/_pbcintor.py +1 -0
  259. pyscf/pbc/gto/cell.py +194 -23
  260. pyscf/pbc/gto/ecp.py +12 -12
  261. pyscf/pbc/gto/eval_gto.py +3 -3
  262. pyscf/pbc/gto/neighborlist.py +4 -1
  263. pyscf/pbc/gto/pseudo/pp.py +1 -1
  264. pyscf/pbc/gw/krgw_ac.py +4 -4
  265. pyscf/pbc/gw/krgw_cd.py +4 -4
  266. pyscf/pbc/gw/kugw_ac.py +3 -3
  267. pyscf/pbc/lib/kpts_helper.py +4 -3
  268. pyscf/pbc/lib/linalg_helper.py +1 -1
  269. pyscf/pbc/mp/kmp2.py +1 -1
  270. pyscf/pbc/mpitools/mpi.py +1 -1
  271. pyscf/pbc/scf/_response_functions.py +141 -34
  272. pyscf/pbc/scf/addons.py +15 -11
  273. pyscf/pbc/scf/cphf.py +1 -1
  274. pyscf/pbc/scf/ghf.py +1 -1
  275. pyscf/pbc/scf/hf.py +21 -32
  276. pyscf/pbc/scf/kghf.py +33 -29
  277. pyscf/pbc/scf/khf.py +103 -29
  278. pyscf/pbc/scf/khf_ksymm.py +15 -1
  279. pyscf/pbc/scf/krohf.py +5 -7
  280. pyscf/pbc/scf/kuhf.py +54 -23
  281. pyscf/pbc/scf/kuhf_ksymm.py +1 -1
  282. pyscf/pbc/scf/rsjk.py +14 -10
  283. pyscf/pbc/scf/scfint.py +1 -1
  284. pyscf/pbc/scf/stability.py +27 -15
  285. pyscf/pbc/scf/uhf.py +3 -1
  286. pyscf/pbc/symm/symmetry.py +2 -2
  287. pyscf/pbc/tdscf/krhf.py +238 -154
  288. pyscf/pbc/tdscf/krks.py +1 -45
  289. pyscf/pbc/tdscf/kuhf.py +319 -171
  290. pyscf/pbc/tdscf/kuks.py +0 -56
  291. pyscf/pbc/tdscf/rhf.py +116 -3
  292. pyscf/pbc/tdscf/rks.py +2 -1
  293. pyscf/pbc/tdscf/uhf.py +214 -1
  294. pyscf/pbc/tdscf/uks.py +2 -1
  295. pyscf/pbc/tools/k2gamma.py +20 -6
  296. pyscf/pbc/tools/lattice.py +3 -3
  297. pyscf/pbc/tools/pbc.py +111 -91
  298. pyscf/pbc/tools/pyscf_ase.py +0 -1
  299. pyscf/pbc/tools/pywannier90.py +1 -1
  300. pyscf/qmmm/mm_mole.py +1 -1
  301. pyscf/scf/_response_functions.py +87 -46
  302. pyscf/scf/_vhf.py +15 -10
  303. pyscf/scf/addons.py +29 -15
  304. pyscf/scf/cphf.py +14 -52
  305. pyscf/scf/dhf.py +121 -38
  306. pyscf/scf/dispersion.py +10 -9
  307. pyscf/scf/ghf.py +25 -13
  308. pyscf/scf/ghf_symm.py +2 -2
  309. pyscf/scf/hf.py +262 -30
  310. pyscf/scf/rohf.py +37 -5
  311. pyscf/scf/stability.py +142 -112
  312. pyscf/scf/ucphf.py +21 -16
  313. pyscf/scf/uhf.py +104 -61
  314. pyscf/sgx/sgx.py +1 -1
  315. pyscf/sgx/sgx_jk.py +4 -4
  316. pyscf/solvent/__init__.py +2 -2
  317. pyscf/solvent/_attach_solvent.py +2 -0
  318. pyscf/solvent/_ddcosmo_tdscf_grad.py +1 -1
  319. pyscf/solvent/cosmors.py +366 -0
  320. pyscf/solvent/ddcosmo.py +1 -1
  321. pyscf/solvent/pcm.py +4 -4
  322. pyscf/solvent/pol_embed.py +1 -1
  323. pyscf/solvent/smd.py +5 -3
  324. pyscf/soscf/ciah.py +3 -11
  325. pyscf/soscf/newton_ah.py +5 -2
  326. pyscf/symm/__init__.py +1 -1
  327. pyscf/symm/addons.py +5 -5
  328. pyscf/symm/geom.py +1 -5
  329. pyscf/tdscf/_lr_eig.py +1002 -0
  330. pyscf/tdscf/dhf.py +84 -87
  331. pyscf/tdscf/dks.py +0 -4
  332. pyscf/tdscf/ghf.py +139 -127
  333. pyscf/tdscf/gks.py +27 -25
  334. pyscf/tdscf/rhf.py +194 -147
  335. pyscf/tdscf/rks.py +26 -22
  336. pyscf/tdscf/uhf.py +166 -118
  337. pyscf/tdscf/uks.py +32 -31
  338. pyscf/tools/fcidump.py +3 -0
  339. pyscf/tools/qcschema.py +265 -0
  340. pyscf/x2c/sfx2c1e.py +1 -1
  341. pyscf/x2c/tdscf.py +41 -41
  342. pyscf/x2c/x2c.py +15 -11
  343. {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/METADATA +39 -36
  344. {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/NOTICE +14 -1
  345. {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/RECORD +348 -316
  346. {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/WHEEL +1 -1
  347. pyscf/dft/gen_libxc_param.py +0 -35
  348. pyscf/dft/gen_xcfun_param.py +0 -209
  349. pyscf/pbc/tdscf/kproxy.py +0 -189
  350. pyscf/pbc/tdscf/kproxy_supercell.py +0 -664
  351. pyscf/pbc/tdscf/krhf_slow.py +0 -300
  352. pyscf/pbc/tdscf/krhf_slow_gamma.py +0 -175
  353. pyscf/pbc/tdscf/krhf_slow_supercell.py +0 -250
  354. pyscf/pbc/tdscf/proxy.py +0 -39
  355. pyscf/pbc/tdscf/rhf_slow.py +0 -35
  356. pyscf/tdscf/common_slow.py +0 -799
  357. pyscf/tdscf/proxy.py +0 -258
  358. pyscf/tdscf/rhf_slow.py +0 -181
  359. {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/LICENSE +0 -0
  360. {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/top_level.txt +0 -0
pyscf/tdscf/_lr_eig.py ADDED
@@ -0,0 +1,1002 @@
1
+ #!/usr/bin/env python
2
+ # Copyright 2024 The PySCF Developers. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ import numpy as np
18
+ import scipy.linalg
19
+ from pyscf.lib.parameters import MAX_MEMORY
20
+ from pyscf.lib import logger
21
+ from pyscf.lib.exceptions import LinearDependencyError
22
+ from pyscf.lib.linalg_helper import _sort_elast, _outprod_to_subspace
23
+
24
+ # Add at most 20 states in each iteration
25
+ MAX_SPACE_INC = 20
26
+
27
+ def eigh(aop, x0, precond, tol_residual=1e-5, lindep=1e-12, nroots=1,
28
+ x0sym=None, pick=None, max_cycle=50, max_memory=MAX_MEMORY,
29
+ verbose=logger.WARN):
30
+ '''
31
+ Solve symmetric eigenvalues.
32
+
33
+ This solver is similar to the `linalg_helper.davidson` solver, with
34
+ optimizations for performance and wavefunction symmetry, specifically
35
+ tailored for linear response methods.
36
+
37
+ Args:
38
+ aop : function(x) => array_like_x
39
+ The matrix-vector product operator.
40
+ x0 : 1D array or a list of 1D array
41
+ Initial guess.
42
+ precond : function(dx, e) => array_like_dx
43
+ Preconditioner to generate new trial vector. The argument dx is a
44
+ residual vector ``A*x0-e*x0``; e is the eigenvalue.
45
+
46
+ Kwargs:
47
+ tol_residual : float
48
+ Convergence tolerance for the norm of residual vector ``A*x0-e*x0``.
49
+ lindep : float
50
+ Linear dependency threshold. The function is terminated when the
51
+ smallest eigenvalue of the metric of the trial vectors is lower
52
+ than this threshold.
53
+ nroots : int
54
+ Number of eigenvalues to be computed.
55
+ x0sym:
56
+ The symmetry label for each initial guess vectors.
57
+ pick : function(w,v,nroots) => (e[idx], w[:,idx], idx)
58
+ Function to filter eigenvalues and eigenvectors.
59
+ max_cycle : int
60
+ max number of iterations.
61
+ max_memory : int or float
62
+ Allowed memory in MB.
63
+
64
+ Returns:
65
+ e : list of floats
66
+ Eigenvalues.
67
+ c : list of 1D arrays
68
+ Eigenvectors.
69
+ '''
70
+
71
+ assert callable(pick)
72
+ assert callable(precond)
73
+
74
+ log = logger.new_logger(verbose)
75
+
76
+ if isinstance(x0, np.ndarray) and x0.ndim == 1:
77
+ x0 = x0[None,:]
78
+ x0 = np.asarray(x0)
79
+
80
+ x0_size = x0.shape[1]
81
+ if MAX_SPACE_INC is None:
82
+ space_inc = nroots
83
+ else:
84
+ # Adding too many trial bases in each iteration may cause larger errors
85
+ space_inc = max(nroots, min(MAX_SPACE_INC, x0_size//2))
86
+
87
+ max_space = int(max_memory*1e6/8/x0_size / 2 - nroots - space_inc)
88
+ if max_space < nroots * 4 < x0_size:
89
+ log.warn('Not enough memory to store trial space in _lr_eig.eigh')
90
+ max_space = max(max_space, nroots * 4)
91
+ max_space = min(max_space, x0_size)
92
+ log.debug(f'Set max_space {max_space}, space_inc {space_inc}')
93
+
94
+ xs = np.zeros((0, x0_size))
95
+ ax = np.zeros((0, x0_size))
96
+ e = w = v = None
97
+ conv_last = conv = np.zeros(nroots, dtype=bool)
98
+ xt = x0
99
+
100
+ if x0sym is not None:
101
+ xt_ir = np.asarray(x0sym)
102
+ xs_ir = np.array([], dtype=xt_ir.dtype)
103
+
104
+ for icyc in range(max_cycle):
105
+ xt, xt_idx = _qr(xt, lindep)
106
+ # Generate at most space_inc trial vectors
107
+ xt = xt[:space_inc]
108
+ xt_idx = xt_idx[:space_inc]
109
+
110
+ row0 = len(xs)
111
+ axt = aop(xt)
112
+ xs = np.vstack([xs, xt])
113
+ ax = np.vstack([ax, axt])
114
+ if x0sym is not None:
115
+ xs_ir = np.hstack([xs_ir, xt_ir[xt_idx]])
116
+
117
+ # Compute heff = xs.conj().dot(ax.T)
118
+ if w is None:
119
+ heff = xs.conj().dot(ax.T)
120
+ else:
121
+ hsub = xt.conj().dot(ax.T)
122
+ heff = np.block([[np.diag(w), hsub[:,:row0].conj().T],
123
+ [hsub[:,:row0], hsub[:,row0:]]])
124
+
125
+ if x0sym is None:
126
+ w, v = scipy.linalg.eigh(heff)
127
+ else:
128
+ # Diagonalize within eash symmetry sectors
129
+ row1 = len(xs)
130
+ w = np.empty(row1)
131
+ v = np.zeros((row1, row1))
132
+ v_ir = []
133
+ i1 = 0
134
+ for ir in set(xs_ir):
135
+ idx = np.where(xs_ir == ir)[0]
136
+ i0, i1 = i1, i1 + idx.size
137
+ w_sub, v_sub = scipy.linalg.eigh(heff[idx[:,None],idx])
138
+ w[i0:i1] = w_sub
139
+ v[idx,i0:i1] = v_sub
140
+ v_ir.append([ir] * idx.size)
141
+ w_idx = np.argsort(w)
142
+ w = w[w_idx]
143
+ v = v[:,w_idx]
144
+ xs_ir = np.hstack(v_ir)[w_idx]
145
+
146
+ w, v, idx = pick(w, v, nroots, locals())
147
+ if x0sym is not None:
148
+ xs_ir = xs_ir[idx]
149
+ if len(w) == 0:
150
+ raise RuntimeError('Not enough eigenvalues')
151
+
152
+ e, elast = w[:nroots], e
153
+ if elast is None:
154
+ de = e
155
+ elif elast.size != e.size:
156
+ log.debug('Number of roots different from the previous step (%d,%d)',
157
+ e.size, elast.size)
158
+ de = e
159
+ else:
160
+ # mapping to previous eigenvectors
161
+ vlast = np.eye(nroots)
162
+ elast, conv_last = _sort_elast(elast, conv, vlast,
163
+ v[:nroots,:nroots], log)
164
+ de = e - elast
165
+
166
+ xs = v.T.dot(xs)
167
+ ax = v.T.dot(ax)
168
+ if len(xs) * 2 > max_space:
169
+ row0 = max(nroots, max_space-space_inc)
170
+ xs = xs[:row0]
171
+ ax = ax[:row0]
172
+ w = w[:row0]
173
+ if x0sym is not None:
174
+ xs_ir = xs_ir[:row0]
175
+
176
+ t_size = max(nroots, max_space-len(xs))
177
+ xt = -w[:t_size,None] * xs[:t_size]
178
+ xt += ax[:t_size]
179
+ if x0sym is not None:
180
+ xt_ir = xs_ir[:t_size]
181
+
182
+ dx_norm = np.linalg.norm(xt, axis=1)
183
+ max_dx_norm = max(dx_norm[:nroots])
184
+ conv = dx_norm[:nroots] < tol_residual
185
+ for k, ek in enumerate(e[:nroots]):
186
+ if conv[k] and not conv_last[k]:
187
+ log.debug('root %d converged |r|= %4.3g e= %s max|de|= %4.3g',
188
+ k, dx_norm[k], ek, de[k])
189
+ else:
190
+ log.debug1('root %d |r|= %4.3g e= %s max|de|= %4.3g',
191
+ k, dx_norm[k], ek, de[k])
192
+ ide = np.argmax(abs(de))
193
+ if all(conv):
194
+ log.debug('converged %d %d |r|= %4.3g e= %s max|de|= %4.3g',
195
+ icyc, len(xs), max_dx_norm, e, de[ide])
196
+ break
197
+
198
+ # remove subspace linear dependency
199
+ for k, xk in enumerate(xt):
200
+ if dx_norm[k] > tol_residual:
201
+ xt[k] = precond(xk, e[0])
202
+ xt -= xs.conj().dot(xt.T).T.dot(xs)
203
+ xt_norm = np.linalg.norm(xt, axis=1)
204
+
205
+ remaining = []
206
+ for k, xk in enumerate(xt):
207
+ if dx_norm[k] > tol_residual and xt_norm[k]**2 > lindep:
208
+ xt[k] /= xt_norm[k]
209
+ remaining.append(k)
210
+ if len(remaining) == 0:
211
+ log.debug(f'Linear dependency in trial subspace. |r| for each state {dx_norm}')
212
+ break
213
+
214
+ xt = xt[remaining]
215
+ log.debug1('Generate %d trial vectors. Drop %d vectors',
216
+ len(xt), dx_norm.size - len(xt))
217
+
218
+ if x0sym is not None:
219
+ xt_ir = xt_ir[remaining]
220
+ norm_min = xt_norm[remaining].min()
221
+ log.debug('davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g',
222
+ icyc, len(xs), max_dx_norm, e, de[ide], norm_min)
223
+
224
+ x0 = xs[:nroots]
225
+ # Check whether the solver finds enough eigenvectors.
226
+ if len(x0) < min(x0_size, nroots):
227
+ log.warn(f'Not enough eigenvectors (len(x0)={len(x0)}, nroots={nroots})')
228
+
229
+ return conv, e, x0
230
+
231
+ def eig(aop, x0, precond, tol_residual=1e-5, nroots=1, x0sym=None, pick=None,
232
+ max_cycle=50, max_memory=MAX_MEMORY, lindep=1e-12, verbose=logger.WARN):
233
+ '''
234
+ Solver for linear response eigenvalues
235
+ [ A B] [X] = w [X]
236
+ [-B* -A*] [Y] [Y]
237
+
238
+ subject to normalization X^2 - Y^2 = 1
239
+
240
+ Reference:
241
+ Olsen, Jensen, and Jorgenson, J Comput Phys, 74, 265,
242
+ DOI: 10.1016/0021-9991(88)90081-2
243
+
244
+ Args:
245
+ aop : function(x) => array_like_x
246
+ The matrix-vector product operator.
247
+ x0 : 1D array or a list of 1D array
248
+ Initial guess.
249
+ precond : function(dx, e) => array_like_dx
250
+ Preconditioner to generate new trial vector.
251
+ The argument dx is a residual vector ``A*x0-e*x0``; e is the eigenvalue.
252
+
253
+ Kwargs:
254
+ tol_residual : float
255
+ Convergence tolerance for the norm of residual vector ``A*x0-e*x0``.
256
+ lindep : float
257
+ Linear dependency threshold.
258
+ nroots : int
259
+ Number of eigenvalues to be computed.
260
+ x0sym:
261
+ The symmetry label for each initial guess vectors.
262
+ pick : function(w,v,nroots) => (e[idx], w[:,idx], idx)
263
+ Function to filter eigenvalues and eigenvectors.
264
+ max_cycle : int
265
+ max number of iterations.
266
+ max_memory : int or float
267
+ Allowed memory in MB.
268
+
269
+ Returns:
270
+ conv : list of booleans
271
+ Whether each root is converged.
272
+ e : list of floats
273
+ Eigenvalues.
274
+ c : list of 1D arrays
275
+ Eigenvectors.
276
+ '''
277
+
278
+ assert callable(pick)
279
+ assert callable(precond)
280
+
281
+ log = logger.new_logger(verbose)
282
+
283
+ if isinstance(x0, np.ndarray) and x0.ndim == 1:
284
+ x0 = x0[None,:]
285
+ x0 = np.asarray(x0)
286
+ x0_size = x0.shape[1]
287
+ if MAX_SPACE_INC is None:
288
+ space_inc = nroots
289
+ else:
290
+ # Adding too many trial bases in each iteration may introduce more errors
291
+ space_inc = max(nroots, min(MAX_SPACE_INC, x0_size//4))
292
+
293
+ max_space = int(max_memory*1e6/8/(2*x0_size) / 2 - space_inc)
294
+ if max_space < nroots * 4 < x0_size:
295
+ log.warn('Not enough memory to store trial space in _lr_eig.eig')
296
+ max_space = space_inc * 2
297
+ max_space = max(max_space, nroots * 4)
298
+ max_space = min(max_space, x0_size)
299
+ log.debug(f'Set max_space {max_space}, space_inc {space_inc}')
300
+
301
+ if x0sym is None:
302
+ x0 = _symmetric_orth(x0)
303
+ else:
304
+ x0_ir = np.asarray(x0sym)
305
+ x0_orth = []
306
+ x0_orth_ir = []
307
+ for ir in set(x0_ir):
308
+ idx = np.where(x0_ir == ir)[0]
309
+ xt_sub = _symmetric_orth(x0[idx])
310
+ x0_orth.append(xt_sub)
311
+ x0_orth_ir.append([ir] * len(xt_sub))
312
+ if x0_orth:
313
+ x0 = np.vstack(x0_orth)
314
+ x0_ir = np.hstack(x0_orth_ir)
315
+ else:
316
+ x0 = []
317
+ x0_orth = x0_orth_ir = xt_sub = None
318
+ if len(x0) == 0:
319
+ raise LinearDependencyError('Empty initial guess')
320
+
321
+ heff = None
322
+ e = None
323
+ v = None
324
+ vlast = None
325
+ conv_last = conv = np.zeros(nroots, dtype=bool)
326
+
327
+ half_size = x0[0].size // 2
328
+ fresh_start = True
329
+ for icyc in range(max_cycle):
330
+ if fresh_start:
331
+ vlast = None
332
+ conv_last = conv = np.zeros(nroots, dtype=bool)
333
+ xs = np.zeros((0, x0_size))
334
+ ax = np.zeros((0, x0_size))
335
+ row1 = 0
336
+ xt = x0
337
+ if x0sym is not None:
338
+ xs_ir = x0_ir
339
+
340
+ axt = aop(xt)
341
+ xs = np.vstack([xs, xt])
342
+ ax = np.vstack([ax, axt])
343
+ row0, row1 = row1, row1+len(xt)
344
+
345
+ if heff is None:
346
+ dtype = np.result_type(axt, xt)
347
+ heff = np.empty((max_space*2,max_space*2), dtype=dtype)
348
+
349
+ h11 = xs[:row0].conj().dot(axt.T).astype(dtype)
350
+ h21 = _conj_dot(xs[:row0], axt).astype(dtype)
351
+ heff[0:row0*2:2, row0*2+0:row1*2:2] = h11
352
+ heff[1:row0*2:2, row0*2+0:row1*2:2] = h21
353
+ heff[0:row0*2:2, row0*2+1:row1*2:2] = -h21.conj()
354
+ heff[1:row0*2:2, row0*2+1:row1*2:2] = -h11.conj()
355
+
356
+ h11 = xt.conj().dot(ax.T).astype(dtype)
357
+ h21 = _conj_dot(xt, ax).astype(dtype)
358
+ heff[row0*2+0:row1*2:2, 0:row1*2:2] = h11
359
+ heff[row0*2+1:row1*2:2, 0:row1*2:2] = h21
360
+ heff[row0*2+0:row1*2:2, 1:row1*2:2] = -h21.conj()
361
+ heff[row0*2+1:row1*2:2, 1:row1*2:2] = -h11.conj()
362
+
363
+ if x0sym is None:
364
+ w, v = scipy.linalg.eig(heff[:row1*2,:row1*2])
365
+ else:
366
+ # Diagonalize within eash symmetry sectors
367
+ xs_ir2 = np.repeat(xs_ir, 2)
368
+ w = np.empty(row1*2, dtype=np.complex128)
369
+ v = np.zeros((row1*2, row1*2), dtype=np.complex128)
370
+ v_ir = []
371
+ i1 = 0
372
+ for ir in set(xs_ir):
373
+ idx = np.where(xs_ir2 == ir)[0]
374
+ i0, i1 = i1, i1 + idx.size
375
+ w_sub, v_sub = scipy.linalg.eig(heff[idx[:,None],idx])
376
+ w[i0:i1] = w_sub
377
+ v[idx,i0:i1] = v_sub
378
+ v_ir.append([ir] * idx.size)
379
+ v_ir = np.hstack(v_ir)
380
+
381
+ w, v, idx = pick(w, v, nroots, locals())
382
+ if x0sym is not None:
383
+ v_ir = v_ir[idx]
384
+ if len(w) == 0:
385
+ raise RuntimeError('Not enough eigenvalues')
386
+
387
+ w, e, elast = w[:space_inc], w[:nroots], e
388
+ v = v[:,:space_inc]
389
+ if vlast is not None:
390
+ elast, conv_last = _sort_elast(elast, conv, vlast, v[:,:nroots], log)
391
+ vlast = v[:,:nroots]
392
+
393
+ if elast is None:
394
+ de = e
395
+ elif elast.size != e.size:
396
+ log.debug('Number of roots different from the previous step (%d,%d)',
397
+ e.size, elast.size)
398
+ de = e
399
+ else:
400
+ de = e - elast
401
+
402
+ x0 = _gen_x0(v, xs)
403
+ ax0 = xt = _gen_ax0(v, ax)
404
+ xt -= w[:,None] * x0
405
+ ax0 = None
406
+ if x0sym is not None:
407
+ xt_ir = v_ir[:space_inc]
408
+ x0_ir = v_ir[:nroots]
409
+
410
+ dx_norm = np.linalg.norm(xt, axis=1)
411
+ max_dx_norm = max(dx_norm[:nroots])
412
+ conv = dx_norm[:nroots] < tol_residual
413
+ for k, ek in enumerate(e[:nroots]):
414
+ if conv[k] and not conv_last[k]:
415
+ log.debug('root %d converged |r|= %4.3g e= %s max|de|= %4.3g',
416
+ k, dx_norm[k], ek, de[k])
417
+ else:
418
+ log.debug1('root %d |r|= %4.3g e= %s max|de|= %4.3g',
419
+ k, dx_norm[k], ek, de[k])
420
+ ide = np.argmax(abs(de))
421
+ if all(conv):
422
+ log.debug('converged %d %d |r|= %4.3g e= %s max|de|= %4.3g',
423
+ icyc, len(xs), max_dx_norm, e, de[ide])
424
+ break
425
+
426
+ # remove subspace linear dependency
427
+ for k, xk in enumerate(xt):
428
+ if dx_norm[k] > tol_residual:
429
+ xt[k] = precond(xk, e[0])
430
+
431
+ xt -= xs.conj().dot(xt.T).T.dot(xs)
432
+ c = _conj_dot(xs, xt)
433
+ xt[:,:half_size] -= c.T.dot(xs[:,half_size:].conj())
434
+ xt[:,half_size:] -= c.T.dot(xs[:,:half_size].conj())
435
+
436
+ # Remove quasi linearly dependent bases, as they cause more numerical
437
+ # errors in _symmetric_orth
438
+ xt_norm = np.linalg.norm(xt, axis=1)
439
+ xt_to_keep = (dx_norm > tol_residual) & (xt_norm > max(lindep**.5, tol_residual))
440
+ xt = xt[xt_to_keep]
441
+ if len(xt) > 0:
442
+ xt /= xt_norm[xt_to_keep, None]
443
+ if x0sym is None:
444
+ xt = _symmetric_orth(xt)
445
+ else:
446
+ xt_ir = xt_ir[xt_to_keep]
447
+ xt_orth = []
448
+ xt_orth_ir = []
449
+ for ir in set(xt_ir):
450
+ idx = np.where(xt_ir == ir)[0]
451
+ xt_sub = _symmetric_orth(xt[idx])
452
+ xt_orth.append(xt_sub)
453
+ xt_orth_ir.append([ir] * len(xt_sub))
454
+ if xt_orth:
455
+ xt = np.vstack(xt_orth)
456
+ xs_ir = np.hstack([xs_ir, *xt_orth_ir])
457
+ else:
458
+ xt = []
459
+ xt_orth = xt_orth_ir = xt_sub = None
460
+
461
+ if len(xt) == 0:
462
+ log.debug(f'Linear dependency in trial subspace. |r| for each state {dx_norm}')
463
+ break
464
+ log.debug1('Generate %d trial vectors. Drop %d vectors',
465
+ len(xt), dx_norm.size - len(xt))
466
+
467
+ xt_norm = np.linalg.norm(xt, axis=1)
468
+ norm_min = xt_norm.min()
469
+ log.debug('lr_eig %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g',
470
+ icyc, len(xs), max_dx_norm, e, de[ide], norm_min)
471
+
472
+ fresh_start = len(xs)+space_inc > max_space
473
+
474
+ # Check whether the solver finds enough eigenvectors.
475
+ h_dim = x0[0].size
476
+ if len(x0) < min(h_dim, nroots):
477
+ log.warn(f'Not enough eigenvectors (len(x0)={len(x0)}, nroots={nroots})')
478
+
479
+ return conv[:nroots], e[:nroots], x0[:nroots]
480
+
481
+ def real_eig(aop, x0, precond, tol_residual=1e-5, nroots=1, x0sym=None, pick=None,
482
+ max_cycle=50, max_memory=MAX_MEMORY, lindep=1e-12, verbose=logger.WARN):
483
+ '''
484
+ Solve linear response eigenvalues for real A and B matrices
485
+ [ A B] [X] = w [X]
486
+ [-B -A] [Y] [Y]
487
+
488
+ subject to normalization X^2 - Y^2 = 1 . This function is based on the
489
+ algorithm implemented in https://github.com/John-zzh/improved-Davidson-Algorithm
490
+
491
+ Args:
492
+ aop : function(x) => array_like_x
493
+ The matrix-vector product operator.
494
+ x0 : 1D array or a list of 1D array
495
+ Initial guess.
496
+ precond : function(dx, e) => array_like_dx
497
+ Preconditioner to generate new trial vector.
498
+
499
+ Kwargs:
500
+ tol_residual : float
501
+ Convergence tolerance for the norm of residual vector ``A*x0-e*x0``.
502
+ lindep : float
503
+ Linear dependency threshold.
504
+ nroots : int
505
+ Number of eigenvalues to be computed.
506
+ x0sym:
507
+ The symmetry label for each initial guess vectors.
508
+ pick : function(w,v,nroots) => (e[idx], w[:,idx], idx)
509
+ Function to filter eigenvalues and eigenvectors.
510
+ max_cycle : int
511
+ max number of iterations.
512
+ max_memory : int or float
513
+ Allowed memory in MB.
514
+
515
+ Returns:
516
+ conv : list of booleans
517
+ Whether each root is converged.
518
+ e : list of floats
519
+ Eigenvalues.
520
+ c : list of 1D arrays
521
+ Eigenvectors.
522
+ '''
523
+
524
+ assert pick is None
525
+ assert callable(precond)
526
+
527
+ log = logger.new_logger(verbose)
528
+
529
+ assert x0.ndim == 2
530
+ A_size = x0.shape[1] // 2
531
+ V = x0[:,:A_size]
532
+ W = x0[:,A_size:]
533
+ x0 = (V, W)
534
+ if MAX_SPACE_INC is None:
535
+ space_inc = nroots
536
+ else:
537
+ # Adding too many trial bases in each iteration may cause larger errors
538
+ space_inc = max(nroots, min(MAX_SPACE_INC, A_size//2))
539
+
540
+ max_space = int(max_memory*1e6/8/(4*A_size) / 2 - space_inc)
541
+ if max_space < nroots * 4 < A_size:
542
+ log.warn('Not enough memory to store trial space in _lr_eig.eig')
543
+ max_space = space_inc * 2
544
+ max_space = max(max_space, nroots * 4)
545
+ max_space = min(max_space, A_size)
546
+ log.debug(f'Set max_space {max_space}, space_inc {space_inc}')
547
+
548
+ if x0sym is not None:
549
+ x0_ir = np.asarray(x0sym)
550
+
551
+ '''U1 = AV + BW
552
+ U2 = AW + BV'''
553
+ V_holder = np.empty((A_size, max_space), order='F')
554
+ W_holder = np.empty_like(V_holder)
555
+ U1_holder = np.empty_like(V_holder)
556
+ U2_holder = np.empty_like(V_holder)
557
+
558
+ a = np.empty((max_space*2,max_space*2))
559
+ b = np.empty_like(a)
560
+ sigma = np.empty_like(a)
561
+ pi = np.empty_like(a)
562
+ e = None
563
+ v_sub = None
564
+ vlast = None
565
+ conv_last = conv = np.zeros(nroots, dtype=bool)
566
+
567
+ fresh_start = True
568
+ for icyc in range(max_cycle):
569
+ if fresh_start:
570
+ m0 = m1 = 0
571
+ V, W = x0
572
+ if x0sym is not None:
573
+ xs_ir = xt_ir = x0_ir
574
+
575
+ axt = aop(np.hstack([V, W]))
576
+ U1 = axt[:,:A_size]
577
+ U2 = -axt[:,A_size:]
578
+ m0, m1 = m1, m1+len(U1)
579
+ V_holder [:,m0:m1] = V.T
580
+ W_holder [:,m0:m1] = W.T
581
+ U1_holder[:,m0:m1] = U1.T
582
+ U2_holder[:,m0:m1] = U2.T
583
+
584
+ '''
585
+ a = np.dot(V.T, U1)
586
+ a += np.dot(W.T, U2)
587
+ b = np.dot(V.T, U2)
588
+ b += np.dot(W.T, U1)
589
+ sigma = np.dot(V.T, V)
590
+ sigma -= np.dot(W.T, W)
591
+ pi = np.dot(V.T, W)
592
+ pi -= np.dot(W.T, V)
593
+ a = (a + a.T) / 2
594
+ b = (b + b.T) / 2
595
+ sigma = (sigma + sigma.T) / 2
596
+ pi = (pi - pi.T) / 2
597
+ '''
598
+ a_block = _sym_dot(V_holder, U1_holder, m0, m1)
599
+ a_block += _sym_dot(W_holder, U2_holder, m0, m1)
600
+ b_block = _sym_dot(V_holder, U2_holder, m0, m1)
601
+ b_block += _sym_dot(W_holder, U1_holder, m0, m1)
602
+ sigma_block = _sym_dot(V_holder, V_holder, m0, m1)
603
+ sigma_block -= _sym_dot(W_holder, W_holder, m0, m1)
604
+ pi_block = _asym_dot(V_holder, W_holder, m0, m1)
605
+ pi_block -= _asym_dot(W_holder, V_holder, m0, m1)
606
+ a[:m1,m0:m1] = a_block.T
607
+ a[m0:m1,:m1] = a_block
608
+ b[:m1,m0:m1] = b_block.T
609
+ b[m0:m1,:m1] = b_block
610
+ sigma[:m1,m0:m1] = sigma_block.T
611
+ sigma[m0:m1,:m1] = sigma_block
612
+ pi[:m1,m0:m1] = -pi_block.T
613
+ pi[m0:m1,:m1] = pi_block
614
+
615
+ if x0sym is None:
616
+ omega, x, y = TDDFT_subspace_eigen_solver(
617
+ a[:m1,:m1], b[:m1,:m1], sigma[:m1,:m1], pi[:m1,:m1], space_inc)
618
+ else:
619
+ # Diagonalize within eash symmetry sectors
620
+ omega = np.empty(m1)
621
+ x = np.zeros((m1, m1))
622
+ y = np.zeros_like(x)
623
+ v_ir = []
624
+ i1 = 0
625
+ for ir in set(xs_ir):
626
+ idx = np.nonzero(xs_ir[:m1] == ir)[0]
627
+ _w, _x, _y = TDDFT_subspace_eigen_solver(
628
+ a[idx[:,None],idx], b[idx[:,None],idx],
629
+ sigma[idx[:,None],idx], pi[idx[:,None],idx], idx.size)
630
+ i0, i1 = i1, i1 + idx.size
631
+ omega[i0:i1] = _w
632
+ x[idx,i0:i1] = _x
633
+ y[idx,i0:i1] = _y
634
+ v_ir.append([ir] * _w.size)
635
+ idx = np.argsort(omega)
636
+ omega = omega[idx]
637
+ v_ir = np.hstack(v_ir)[idx]
638
+ x = x[:,idx]
639
+ y = y[:,idx]
640
+
641
+ w, e, elast = omega[:space_inc], omega[:nroots], e
642
+ v_sub = x[:,:space_inc]
643
+ if not fresh_start:
644
+ elast, conv_last = _sort_elast(elast, conv, vlast, v_sub[:,:nroots], log)
645
+ vlast = v_sub[:,:nroots]
646
+
647
+ if elast is None:
648
+ de = e
649
+ elif elast.size != e.size:
650
+ log.debug('Number of roots different from the previous step (%d,%d)',
651
+ e.size, elast.size)
652
+ de = e
653
+ else:
654
+ de = e - elast
655
+
656
+ x = x[:,:space_inc]
657
+ y = y[:,:space_inc]
658
+ X_full = V_holder[:,:m1].dot(x)
659
+ X_full += W_holder[:,:m1].dot(y)
660
+ Y_full = W_holder[:,:m1].dot(x)
661
+ Y_full += V_holder[:,:m1].dot(y)
662
+ x0 = (X_full[:,:nroots].T, Y_full[:,:nroots].T)
663
+ # residuals
664
+ R_x = U1_holder[:,:m1].dot(x)
665
+ R_x += U2_holder[:,:m1].dot(y)
666
+ R_x -= X_full * w
667
+ R_y = U2_holder[:,:m1].dot(x)
668
+ R_y += U1_holder[:,:m1].dot(y)
669
+ R_y += Y_full * w
670
+
671
+ r_norms = np.linalg.norm(R_x, axis=0) ** 2
672
+ r_norms += np.linalg.norm(R_y, axis=0) ** 2
673
+ r_norms = r_norms ** .5
674
+
675
+ if x0sym is not None:
676
+ xt_ir = v_ir[:space_inc]
677
+ x0_ir = v_ir[:nroots]
678
+
679
+ max_r_norm = max(r_norms[:nroots])
680
+ conv = r_norms[:nroots] <= tol_residual
681
+ for k, ek in enumerate(e[:nroots]):
682
+ if conv[k] and not conv_last[k]:
683
+ log.debug('root %d converged |r|= %4.3g e= %s max|de|= %4.3g',
684
+ k, r_norms[k], ek, de[k])
685
+ else:
686
+ log.debug1('root %d |r|= %4.3g e= %s max|de|= %4.3g',
687
+ k, r_norms[k], ek, de[k])
688
+ ide = np.argmax(abs(de))
689
+ if all(conv):
690
+ log.debug('converged %d %d |r|= %4.3g e= %s max|de|= %4.3g',
691
+ icyc, len(conv), max_r_norm, e, de[ide])
692
+ break
693
+
694
+ r_index = r_norms > tol_residual
695
+ XY_new = precond(np.vstack([R_x[:,r_index], R_y[:,r_index]]).T, w[r_index])
696
+ X_new = XY_new[:,:A_size].T
697
+ Y_new = XY_new[:,A_size:].T
698
+ if x0sym is None:
699
+ V, W = VW_Gram_Schmidt_fill_holder(
700
+ V_holder[:,:m1], W_holder[:,:m1], X_new, Y_new)
701
+ else:
702
+ xt_ir = xt_ir[r_index]
703
+ xt_orth_ir = []
704
+ V = []
705
+ W = []
706
+ for ir in set(xt_ir):
707
+ idx = np.nonzero(xt_ir == ir)[0]
708
+ _V, _W = VW_Gram_Schmidt_fill_holder(
709
+ V_holder[:,:m1], W_holder[:,:m1], X_new[:,idx], Y_new[:,idx])
710
+ V.append(_V)
711
+ W.append(_W)
712
+ xt_orth_ir.append([ir] * len(_V))
713
+ if len(V) > 0:
714
+ V = np.vstack(V)
715
+ W = np.vstack(W)
716
+ xt_ir = np.hstack(xt_orth_ir)
717
+ xs_ir = np.hstack([xs_ir, xt_ir])
718
+
719
+ if len(V) == 0:
720
+ log.debug(f'Linear dependency in trial subspace. |r| for each state {r_norms}')
721
+ break
722
+
723
+ log.debug1('Generate %d trial vectors. Drop %d vectors',
724
+ len(V), r_norms.size - len(V))
725
+ X_new = Y_new = R_x = R_y = None
726
+
727
+ xy_norms = np.linalg.norm(V, axis=0) ** 2
728
+ xy_norms += np.linalg.norm(W, axis=0) ** 2
729
+ norm_min = (xy_norms ** .5).min()
730
+ log.debug('real_lr_eig %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g',
731
+ icyc, m1, max_r_norm, e, de[ide], norm_min)
732
+
733
+ fresh_start = m1 + len(V) > max_space
734
+
735
+ # Check whether the solver finds enough eigenvectors.
736
+ if len(x0[0]) < min(A_size, nroots):
737
+ log.warn(f'Not enough eigenvectors (len(x0)={len(x0[0])}, nroots={nroots})')
738
+
739
+ return conv[:nroots], e[:nroots], np.hstack(x0)
740
+
741
+ def _gen_x0(v, xs):
742
+ out = _outprod_to_subspace(v[::2], xs)
743
+ out_conj = _outprod_to_subspace(v[1::2].conj(), xs)
744
+ n = out.shape[1] // 2
745
+ # v[1::2] * xs.conj() = (v[1::2].conj() * xs).conj()
746
+ out[:,:n] += out_conj[:,n:].conj()
747
+ out[:,n:] += out_conj[:,:n].conj()
748
+ return out
749
+
750
+ def _gen_ax0(v, xs):
751
+ out = _outprod_to_subspace(v[::2], xs)
752
+ out_conj = _outprod_to_subspace(v[1::2].conj(), xs)
753
+ n = out.shape[1] // 2
754
+ out[:,:n] -= out_conj[:,n:].conj()
755
+ out[:,n:] -= out_conj[:,:n].conj()
756
+ return out
757
+
758
+ def _conj_dot(xi, xj):
759
+ '''Dot product between the conjugated basis of xi and xj.
760
+ The conjugated basis of xi is np.hstack([xi[half:], xi[:half]]).conj()
761
+ '''
762
+ n = xi.shape[-1] // 2
763
+ return xi[:,n:].dot(xj[:,:n].T) + xi[:,:n].dot(xj[:,n:].T)
764
+
765
+ def _qr(xs, lindep=1e-14):
766
+ '''QR decomposition for a list of vectors (for linearly independent vectors only).
767
+ xs = (r.T).dot(qs)
768
+ '''
769
+ nv = 0
770
+ idx = []
771
+ for i, xi in enumerate(xs):
772
+ for j in range(nv):
773
+ prod = xs[j].conj().dot(xi)
774
+ xi -= xs[j] * prod
775
+ norm = np.linalg.norm(xi)
776
+ if norm**2 > lindep:
777
+ xs[nv] = xi/norm
778
+ nv += 1
779
+ idx.append(i)
780
+ return xs[:nv], idx
781
+
782
+ def _symmetric_orth(xt, lindep=1e-6):
783
+ xt = np.asarray(xt)
784
+ if xt.dtype == np.float64:
785
+ return _symmetric_orth_real(xt, lindep)
786
+ else:
787
+ return _symmetric_orth_cmplx(xt, lindep)
788
+
789
+ def _symmetric_orth_real(xt, lindep=1e-6):
790
+ '''
791
+ Symmetric orthogonalization for xt = {[X, Y]},
792
+ and its dual basis vectors {[Y, X]}
793
+ '''
794
+ x0_size = xt.shape[1]
795
+ s11 = xt.dot(xt.T)
796
+ s21 = _conj_dot(xt, xt)
797
+ # Symmetric orthogonalize s, where
798
+ # s = [[s11, s21.conj().T],
799
+ # [s21, s11.conj() ]]
800
+ e, c = np.linalg.eigh(s11)
801
+ mask = e > lindep**2
802
+ e = e[mask]
803
+ if e.size == 0:
804
+ return np.zeros([0, x0_size], dtype=xt.dtype)
805
+ c = c[:,mask] * e**-.5
806
+
807
+ # c22 = c.conj()
808
+ # s21 -> c22.conj().T.dot(s21).dot(c11)
809
+ csc = c.T.dot(s21).dot(c)
810
+ n = csc.shape[0]
811
+ for i in range(n):
812
+ _s21 = csc[i:,i:]
813
+ # s21 is symmetric for real vectors
814
+ w, u = np.linalg.eigh(_s21)
815
+ mask = 1 - abs(w) > lindep
816
+ if np.any(mask):
817
+ c = c[:,i:]
818
+ break
819
+ else:
820
+ return np.zeros([0, x0_size], dtype=xt.dtype)
821
+ w = w[mask]
822
+ u = u[:,mask]
823
+ c_orth = c.dot(u)
824
+
825
+ if e[0] < 1e-6 or 1-abs(w[0]) < 1e-3:
826
+ # Rerun the orthogonalization to reduce numerical errors
827
+ e, c = np.linalg.eigh(c_orth.T.dot(s11).dot(c_orth))
828
+ c *= e**-.5
829
+ c_orth = c_orth.dot(c)
830
+ csc = c_orth.T.dot(s21).dot(c_orth)
831
+ w, u = np.linalg.eigh(csc)
832
+ c_orth = c_orth.dot(u)
833
+
834
+ # Symmetric diagonalize
835
+ # [1 w.conj()] => c = [a b]
836
+ # [w 1 ] [b a]
837
+ # where
838
+ # a = ((1+w)**-.5 + (1-w)**-.5)/2
839
+ # b = (phase*(1+w)**-.5 - phase*(1-w)**-.5)/2
840
+ a1 = (1 + w)**-.5
841
+ a2 = (1 - w)**-.5
842
+ a = (a1 + a2) / 2
843
+ b = (a1 - a2) / 2
844
+
845
+ m = xt.shape[1] // 2
846
+ x_orth = (c_orth * a).T.dot(xt)
847
+ # Contribution from the conjugated basis
848
+ x_orth[:,:m] += (c_orth * b).T.dot(xt[:,m:])
849
+ x_orth[:,m:] += (c_orth * b).T.dot(xt[:,:m])
850
+ return x_orth
851
+
852
+ def _symmetric_orth_cmplx(xt, lindep=1e-6):
853
+ n, m = xt.shape
854
+ if n == 0:
855
+ raise RuntimeError('Linear dependency in trial bases')
856
+ m = m // 2
857
+ # The conjugated basis np.hstack([xt[:,m:], xt[:,:m]]).conj()
858
+ s11 = xt.conj().dot(xt.T)
859
+ s21 = _conj_dot(xt, xt)
860
+ s = np.block([[s11, s21.conj().T],
861
+ [s21, s11.conj() ]])
862
+ e, c = scipy.linalg.eigh(s)
863
+ if e[0] < lindep:
864
+ if n == 1:
865
+ return xt
866
+ return _symmetric_orth_cmplx(xt[:-1], lindep)
867
+
868
+ c_orth = (c * e**-.5).dot(c[:n].conj().T)
869
+ x_orth = c_orth[:n].T.dot(xt)
870
+ # Contribution from the conjugated basis
871
+ x_orth[:,:m] += c_orth[n:].T.dot(xt[:,m:].conj())
872
+ x_orth[:,m:] += c_orth[n:].T.dot(xt[:,:m].conj())
873
+ return x_orth
874
+
875
+ def _sym_dot(V, U1, m0, m1):
876
+ '''(V*U1 + U1.T*V.T)[m0:m1,:m1]'''
877
+ a = V [:,m0:m1].T.dot(U1[:,:m1])
878
+ a += U1[:,m0:m1].T.dot(V [:,:m1])
879
+ a *= .5
880
+ return a
881
+
882
+ def _asym_dot(V, U1, m0, m1):
883
+ '''(V*U1 - U1.T*V.T)[m0:m1,:m1]'''
884
+ a = V [:,m0:m1].T.dot(U1[:,:m1])
885
+ a -= U1[:,m0:m1].T.dot(V [:,:m1])
886
+ a *= .5
887
+ return a
888
+
889
+ def TDDFT_subspace_eigen_solver(a, b, sigma, pi, nroots):
890
+ ''' [ a b ] x - [ σ π] x Ω = 0 '''
891
+ ''' [ b a ] y [-π -σ] y = 0 '''
892
+
893
+ d = abs(np.diag(sigma))
894
+ d_mh = d**(-0.5)
895
+
896
+ s_m_p = np.einsum('i,ij,j->ij', d_mh, sigma - pi, d_mh)
897
+
898
+ '''LU = d^−1/2 (σ − π) d^−1/2'''
899
+ ''' A = LU '''
900
+ L, U = scipy.linalg.lu(s_m_p, permute_l=True)
901
+ L_inv = np.linalg.inv(L)
902
+ U_inv = np.linalg.inv(U)
903
+
904
+ '''U^-T d^−1/2 (a−b) d^-1/2 U^-1 = GG^T '''
905
+ d_amb_d = np.einsum('i,ij,j->ij', d_mh, a-b, d_mh)
906
+ GGT = np.linalg.multi_dot([U_inv.T, d_amb_d, U_inv])
907
+
908
+ G = scipy.linalg.cholesky(GGT, lower=True)
909
+ G_inv = np.linalg.inv(G)
910
+
911
+ ''' M = G^T L^−1 d^−1/2 (a+b) d^−1/2 L^−T G '''
912
+ d_apb_d = np.einsum('i,ij,j->ij', d_mh, a+b, d_mh)
913
+ M = np.linalg.multi_dot([G.T, L_inv, d_apb_d, L_inv.T, G])
914
+
915
+ omega2, Z = np.linalg.eigh(M)
916
+ if np.any(omega2 <= 0):
917
+ idx = np.nonzero(omega2 > 0)[0]
918
+ omega2 = omega2[idx[:nroots]]
919
+ Z = Z[:,idx[:nroots]]
920
+ else:
921
+ omega2 = omega2[:nroots]
922
+ Z = Z[:,:nroots]
923
+ omega = omega2**0.5
924
+
925
+ ''' It requires Z^T Z = 1/Ω '''
926
+ ''' x+y = d^−1/2 L^−T GZ Ω^-0.5 '''
927
+ ''' x−y = d^−1/2 U^−1 G^−T Z Ω^0.5 '''
928
+ x_p_y = np.einsum('i,ik,k->ik', d_mh, L_inv.T.dot(G.dot(Z)), omega**-0.5)
929
+ x_m_y = np.einsum('i,ik,k->ik', d_mh, U_inv.dot(G_inv.T.dot(Z)), omega**0.5)
930
+
931
+ x = (x_p_y + x_m_y)/2
932
+ y = x_p_y - x
933
+ return omega, x, y
934
+
935
+ def VW_Gram_Schmidt_fill_holder(V_holder, W_holder, X_new, Y_new, lindep=1e-6):
936
+ '''
937
+ QR orthogonalization for (X_new, Y_new) basis vectors, then apply symmetric
938
+ orthogonalization for {[X, Y]}, and its dual basis vectors {[Y, X]}
939
+ '''
940
+ _x = V_holder.T.dot(X_new)
941
+ _x += W_holder.T.dot(Y_new)
942
+ _y = V_holder.T.dot(Y_new)
943
+ _y += W_holder.T.dot(X_new)
944
+ X_new -= V_holder.dot(_x)
945
+ X_new -= W_holder.dot(_y)
946
+ Y_new -= W_holder.dot(_x)
947
+ Y_new -= V_holder.dot(_y)
948
+ x0_size = X_new.shape[0]
949
+
950
+ s11 = X_new.T.dot(X_new)
951
+ s11 += Y_new.T.dot(Y_new)
952
+ # s21 is symmetric
953
+ s21 = X_new.T.dot(Y_new)
954
+ s21 += Y_new.T.dot(X_new)
955
+ e, c = np.linalg.eigh(s11)
956
+ mask = e > lindep**2
957
+ e = e[mask]
958
+ if e.size == 0:
959
+ return (np.zeros([0, x0_size], dtype=X_new.dtype),
960
+ np.zeros([0, x0_size], dtype=Y_new.dtype))
961
+ c = c[:,mask] * e**-.5
962
+
963
+ csc = c.T.dot(s21).dot(c)
964
+ n = csc.shape[0]
965
+ for i in range(n):
966
+ w, u = np.linalg.eigh(csc[i:,i:])
967
+ mask = 1 - abs(w) > lindep
968
+ if np.any(mask):
969
+ c = c[:,i:]
970
+ break
971
+ else:
972
+ return (np.zeros([0, x0_size], dtype=X_new.dtype),
973
+ np.zeros([0, x0_size], dtype=Y_new.dtype))
974
+ w = w[mask]
975
+ u = u[:,mask]
976
+ c_orth = c.dot(u)
977
+
978
+ if e[0] < 1e-6 or 1-abs(w[0]) < 1e-3:
979
+ # Rerun the orthogonalization to reduce numerical errors
980
+ e, c = np.linalg.eigh(c_orth.T.dot(s11).dot(c_orth))
981
+ c *= e**-.5
982
+ c_orth = c_orth.dot(c)
983
+ csc = c_orth.T.dot(s21).dot(c_orth)
984
+ w, u = np.linalg.eigh(csc)
985
+ c_orth = c_orth.dot(u)
986
+
987
+ # Symmetric diagonalize
988
+ # [1 w] => c = [a b]
989
+ # [w 1] [b a]
990
+ # where
991
+ # a = ((1+w)**-.5 + (1-w)**-.5)/2
992
+ # b = ((1+w)**-.5 - (1-w)**-.5)/2
993
+ a1 = (1 + w)**-.5
994
+ a2 = (1 - w)**-.5
995
+ a = (a1 + a2) / 2
996
+ b = (a1 - a2) / 2
997
+
998
+ x_orth = X_new.dot(c_orth * a)
999
+ x_orth += Y_new.dot(c_orth * b)
1000
+ y_orth = Y_new.dot(c_orth * a)
1001
+ y_orth += X_new.dot(c_orth * b)
1002
+ return x_orth.T, y_orth.T