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.
- pyscf/__init__.py +2 -2
- pyscf/adc/__init__.py +3 -8
- pyscf/adc/dfadc.py +22 -6
- pyscf/adc/radc.py +106 -15
- pyscf/adc/radc_amplitudes.py +7 -1
- pyscf/adc/radc_ao2mo.py +4 -2
- pyscf/adc/radc_ea.py +524 -8
- pyscf/adc/radc_ip.py +492 -60
- pyscf/adc/radc_ip_cvs.py +4 -2
- pyscf/adc/uadc.py +116 -27
- pyscf/adc/uadc_amplitudes.py +215 -20
- pyscf/adc/uadc_ao2mo.py +30 -9
- pyscf/adc/uadc_ea.py +34 -44
- pyscf/adc/uadc_ip.py +9 -4
- pyscf/adc/uadc_ip_cvs.py +4 -1
- pyscf/agf2/__init__.py +2 -2
- pyscf/agf2/aux_space.py +1 -1
- pyscf/agf2/chkfile.py +1 -1
- pyscf/ao2mo/__init__.py +13 -2
- pyscf/ao2mo/_ao2mo.py +10 -1
- pyscf/ao2mo/incore.py +3 -0
- pyscf/ao2mo/nrr_outcore.py +2 -2
- pyscf/ao2mo/outcore.py +9 -7
- pyscf/ao2mo/r_outcore.py +2 -2
- pyscf/cc/__init__.py +21 -3
- pyscf/cc/bccd.py +0 -46
- pyscf/cc/ccsd.py +29 -13
- pyscf/cc/ccsd_rdm.py +6 -1
- pyscf/cc/gccsd.py +2 -2
- pyscf/cc/uccsd.py +7 -7
- pyscf/cc/uccsd_rdm.py +2 -2
- pyscf/data/elements.py +1 -1
- pyscf/df/__init__.py +2 -1
- pyscf/df/addons.py +79 -51
- pyscf/df/autoaux.py +195 -0
- pyscf/df/df.py +5 -1
- pyscf/df/df_jk.py +27 -25
- pyscf/df/grad/casscf.py +0 -41
- pyscf/df/grad/rhf.py +31 -1
- pyscf/df/hessian/rhf.py +2 -10
- pyscf/df/hessian/rks.py +1 -7
- pyscf/df/hessian/uhf.py +3 -13
- pyscf/df/hessian/uks.py +1 -8
- pyscf/df/incore.py +18 -6
- pyscf/df/outcore.py +6 -6
- pyscf/dft/dks.py +1 -1
- pyscf/dft/gks.py +25 -21
- pyscf/dft/libxc.py +91 -645
- pyscf/dft/numint.py +40 -19
- pyscf/dft/radi.py +48 -7
- pyscf/dft/rks.py +29 -25
- pyscf/dft/roks.py +7 -1
- pyscf/dft/uks.py +34 -25
- pyscf/dft/xc_deriv.py +1 -1
- pyscf/dft/xcfun.py +53 -2
- pyscf/eph/eph_fd.py +1 -1
- pyscf/eph/rhf.py +6 -36
- pyscf/eph/rks.py +0 -4
- pyscf/eph/uhf.py +1 -7
- pyscf/eph/uks.py +1 -7
- pyscf/fci/addons.py +117 -2
- pyscf/fci/cistring.py +1 -1
- pyscf/fci/direct_nosym.py +3 -3
- pyscf/fci/direct_spin0_symm.py +22 -43
- pyscf/fci/direct_spin1.py +65 -10
- pyscf/fci/direct_spin1_symm.py +49 -14
- pyscf/fci/direct_uhf.py +4 -4
- pyscf/fci/selected_ci_symm.py +1 -1
- pyscf/grad/ccsd.py +3 -7
- pyscf/grad/ccsd_slow.py +2 -3
- pyscf/grad/lagrange.py +11 -3
- pyscf/grad/mp2.py +13 -4
- pyscf/grad/sacasscf.py +1 -1
- pyscf/grad/tdrks.py +1 -1
- pyscf/grad/uccsd.py +3 -7
- pyscf/grad/ump2.py +2 -4
- pyscf/gto/basis/__init__.py +17 -4
- pyscf/gto/basis/bse.py +68 -15
- pyscf/gto/basis/def2-mtzvp.dat +4719 -0
- pyscf/gto/basis/def2-mtzvpp.dat +4739 -0
- pyscf/gto/basis/dyall-basis/__init__.py +0 -0
- pyscf/gto/basis/dyall-basis/dyall_2zp.py +6492 -0
- pyscf/gto/basis/dyall-basis/dyall_3zp.py +8343 -0
- pyscf/gto/basis/dyall-basis/dyall_4zp.py +10055 -0
- pyscf/gto/basis/dyall-basis/dyall_aae2z.py +1818 -0
- pyscf/gto/basis/dyall-basis/dyall_aae3z.py +2521 -0
- pyscf/gto/basis/dyall-basis/dyall_aae4z.py +3351 -0
- pyscf/gto/basis/dyall-basis/dyall_acv2z.py +1790 -0
- pyscf/gto/basis/dyall-basis/dyall_acv3z.py +2417 -0
- pyscf/gto/basis/dyall-basis/dyall_acv4z.py +3085 -0
- pyscf/gto/basis/dyall-basis/dyall_ae2z.py +6619 -0
- pyscf/gto/basis/dyall-basis/dyall_ae3z.py +9027 -0
- pyscf/gto/basis/dyall-basis/dyall_ae4z.py +11839 -0
- pyscf/gto/basis/dyall-basis/dyall_av2z.py +1742 -0
- pyscf/gto/basis/dyall-basis/dyall_av3z.py +2318 -0
- pyscf/gto/basis/dyall-basis/dyall_av4z.py +2905 -0
- pyscf/gto/basis/dyall-basis/dyall_cv2z.py +6558 -0
- pyscf/gto/basis/dyall-basis/dyall_cv3z.py +8767 -0
- pyscf/gto/basis/dyall-basis/dyall_cv4z.py +11098 -0
- pyscf/gto/basis/dyall-basis/dyall_v2z.py +6472 -0
- pyscf/gto/basis/dyall-basis/dyall_v3z.py +8539 -0
- pyscf/gto/basis/dyall-basis/dyall_v4z.py +10658 -0
- pyscf/gto/basis/ma-def2-qzvp.dat +5959 -0
- pyscf/gto/basis/ma-def2-qzvpp.dat +6195 -0
- pyscf/gto/basis/ma-def2-svp.dat +3504 -0
- pyscf/gto/basis/ma-def2-svpp.dat +3504 -0
- pyscf/gto/basis/ma-def2-tzvp.dat +4347 -0
- pyscf/gto/basis/ma-def2-tzvpp.dat +4549 -0
- pyscf/gto/basis/parse_cp2k.py +8 -7
- pyscf/gto/basis/parse_cp2k_pp.py +1 -1
- pyscf/gto/basis/parse_nwchem.py +26 -11
- pyscf/gto/basis/parse_nwchem_ecp.py +2 -1
- pyscf/gto/basis/sap_grasp_large.dat +2438 -0
- pyscf/gto/basis/sap_grasp_small.dat +1434 -0
- pyscf/gto/eval_gto.py +1 -1
- pyscf/gto/ft_ao.py +6 -6
- pyscf/gto/mole.py +123 -71
- pyscf/gto/moleintor.py +1 -1
- pyscf/gw/gw_ac.py +2 -2
- pyscf/gw/gw_cd.py +2 -2
- pyscf/gw/rpa.py +135 -246
- pyscf/gw/ugw_ac.py +2 -2
- pyscf/gw/urpa.py +80 -131
- pyscf/hessian/rhf.py +30 -128
- pyscf/hessian/rks.py +1 -6
- pyscf/hessian/uhf.py +28 -138
- pyscf/hessian/uks.py +1 -8
- pyscf/lib/CMakeLists.txt +6 -2
- pyscf/lib/ao2mo/nr_ao2mo.c +1 -1
- pyscf/lib/ao2mo/nrr_ao2mo.c +1 -1
- pyscf/lib/ao2mo/r_ao2mo.c +1 -1
- pyscf/lib/cc/ccsd_pack.c +1 -1
- pyscf/lib/cc/ccsd_t.c +6 -6
- pyscf/lib/cc/uccsd_t.c +4 -4
- pyscf/lib/config.h +0 -1
- pyscf/lib/config.h.in +0 -1
- pyscf/lib/deps/include/XCFun/XCFunExport.h +1 -0
- pyscf/lib/deps/include/xc.h +28 -18
- pyscf/lib/deps/include/xc_funcs.h +50 -2
- pyscf/lib/deps/include/xc_version.h +3 -3
- pyscf/lib/deps/lib/libcint.6.dylib +0 -0
- pyscf/lib/deps/lib/{libxc.12.dylib → libxc.15.dylib} +0 -0
- pyscf/lib/deps/lib/libxcfun.2.dylib +0 -0
- pyscf/lib/dft/grid_common.c +1 -1
- pyscf/lib/dft/libxc_itrf.c +10 -7
- pyscf/lib/dft/nr_numint_sparse.c +3 -3
- pyscf/lib/dft/xcfun_itrf.c +1 -1
- pyscf/lib/diis.py +2 -2
- pyscf/lib/exceptions.py +6 -0
- pyscf/lib/gto/fill_grids_int2c.c +11 -9
- pyscf/lib/gto/fill_int2e.c +7 -5
- pyscf/lib/gto/fill_r_4c.c +1 -1
- pyscf/lib/gto/ft_ao.c +1 -1
- pyscf/lib/gto/ft_ao.h +1 -1
- pyscf/lib/gto/gto.h +2 -2
- pyscf/lib/gto/nr_ecp.c +3 -2
- pyscf/lib/libagf2.dylib +0 -0
- pyscf/lib/libao2mo.dylib +0 -0
- pyscf/lib/libcc.dylib +0 -0
- pyscf/lib/libcgto.dylib +0 -0
- pyscf/lib/libcvhf.dylib +0 -0
- pyscf/lib/libdft.dylib +0 -0
- pyscf/lib/libfci.dylib +0 -0
- pyscf/lib/libmcscf.dylib +0 -0
- pyscf/lib/libmp.dylib +0 -0
- pyscf/lib/libnp_helper.dylib +0 -0
- pyscf/lib/libpbc.dylib +0 -0
- pyscf/lib/libri.dylib +0 -0
- pyscf/lib/libxc_itrf.dylib +0 -0
- pyscf/lib/libxcfun_itrf.dylib +0 -0
- pyscf/lib/linalg_helper.py +117 -198
- pyscf/lib/logger.py +2 -1
- pyscf/lib/mcscf/fci_contract.c +10 -3
- pyscf/lib/misc.py +63 -22
- pyscf/lib/mp/CMakeLists.txt +22 -0
- pyscf/lib/mp/mp2.c +518 -0
- pyscf/lib/mp/mp2.h +44 -0
- pyscf/lib/np_helper/CMakeLists.txt +1 -1
- pyscf/lib/np_helper/imatcopy.c +360 -0
- pyscf/lib/np_helper/np_helper.c +94 -0
- pyscf/lib/np_helper/np_helper.h +26 -0
- pyscf/lib/numpy_helper.py +195 -11
- pyscf/lib/pbc/nr_direct.c +2 -7
- pyscf/lib/pbc/nr_ecp.c +10 -3
- pyscf/lib/pbc/pbc.h +1 -1
- pyscf/lib/vhf/fblas.h +3 -0
- pyscf/lib/vhf/nr_sgx_direct.c +8 -6
- pyscf/lib/vhf/nr_sr_vhf.c +8 -12
- pyscf/lib/vhf/optimizer.c +2 -2
- pyscf/lib/vhf/rkb_screen.c +139 -0
- pyscf/lo/iao.py +1 -1
- pyscf/lo/ibo.py +3 -3
- pyscf/lo/pipek_jacobi.py +1 -1
- pyscf/mcscf/__init__.py +2 -2
- pyscf/mcscf/addons.py +3 -3
- pyscf/mcscf/apc.py +2 -2
- pyscf/mcscf/casci.py +13 -7
- pyscf/mcscf/chkfile.py +69 -41
- pyscf/mcscf/dmet_cas.py +2 -2
- pyscf/mcscf/mc1step.py +72 -44
- pyscf/mcscf/newton_casscf.py +5 -5
- pyscf/mcscf/ucasci.py +1 -1
- pyscf/mcscf/umc1step.py +49 -28
- pyscf/md/integrators.py +3 -3
- pyscf/mp/__init__.py +1 -0
- pyscf/mp/dfmp2.py +498 -59
- pyscf/mp/dfmp2_native.py +11 -1
- pyscf/mp/dfmp2_slow.py +133 -0
- pyscf/mp/dfump2.py +672 -0
- pyscf/mp/dfump2_native.py +9 -0
- pyscf/mp/dfump2_slow.py +161 -0
- pyscf/mp/gmp2.py +6 -47
- pyscf/mp/mp2.py +25 -10
- pyscf/mp/ump2.py +30 -24
- pyscf/pbc/adc/kadc_rhf.py +1 -1
- pyscf/pbc/adc/kadc_rhf_amplitudes.py +2 -2
- pyscf/pbc/ao2mo/eris.py +1 -1
- pyscf/pbc/cc/kccsd_rhf.py +3 -3
- pyscf/pbc/cc/kccsd_t_rhf.py +2 -2
- pyscf/pbc/ci/kcis_rhf.py +2 -2
- pyscf/pbc/df/aft.py +8 -9
- pyscf/pbc/df/aft_ao2mo.py +1 -1
- pyscf/pbc/df/df.py +85 -12
- pyscf/pbc/df/df_jk.py +6 -2
- pyscf/pbc/df/fft.py +9 -5
- pyscf/pbc/df/fft_ao2mo.py +4 -0
- pyscf/pbc/df/fft_jk.py +18 -10
- pyscf/pbc/df/ft_ao.py +4 -3
- pyscf/pbc/df/gdf_builder.py +5 -4
- pyscf/pbc/df/incore.py +2 -2
- pyscf/pbc/df/mdf.py +6 -3
- pyscf/pbc/df/mdf_jk.py +2 -1
- pyscf/pbc/df/outcore.py +10 -10
- pyscf/pbc/df/rsdf.py +2 -2
- pyscf/pbc/df/rsdf_builder.py +13 -8
- pyscf/pbc/df/rsdf_helper.py +6 -6
- pyscf/pbc/df/rsdf_jk.py +2 -1
- pyscf/pbc/dft/cdft.py +5 -5
- pyscf/pbc/dft/gen_grid.py +3 -2
- pyscf/pbc/dft/gks.py +14 -3
- pyscf/pbc/dft/kgks.py +15 -4
- pyscf/pbc/dft/krks.py +28 -10
- pyscf/pbc/dft/krks_ksymm.py +21 -9
- pyscf/pbc/dft/krkspu.py +1 -30
- pyscf/pbc/dft/krkspu_ksymm.py +0 -30
- pyscf/pbc/dft/kuks.py +30 -13
- pyscf/pbc/dft/kuks_ksymm.py +22 -10
- pyscf/pbc/dft/kukspu.py +0 -27
- pyscf/pbc/dft/kukspu_ksymm.py +0 -30
- pyscf/pbc/dft/multigrid/multigrid.py +36 -33
- pyscf/pbc/dft/multigrid/multigrid_pair.py +7 -2
- pyscf/pbc/dft/multigrid/pp.py +1 -1
- pyscf/pbc/dft/numint.py +56 -31
- pyscf/pbc/dft/rks.py +16 -24
- pyscf/pbc/dft/uks.py +21 -4
- pyscf/pbc/eph/eph_fd.py +1 -1
- pyscf/pbc/geomopt/geometric_solver.py +1 -1
- pyscf/pbc/gto/_pbcintor.py +1 -0
- pyscf/pbc/gto/cell.py +194 -23
- pyscf/pbc/gto/ecp.py +12 -12
- pyscf/pbc/gto/eval_gto.py +3 -3
- pyscf/pbc/gto/neighborlist.py +4 -1
- pyscf/pbc/gto/pseudo/pp.py +1 -1
- pyscf/pbc/gw/krgw_ac.py +4 -4
- pyscf/pbc/gw/krgw_cd.py +4 -4
- pyscf/pbc/gw/kugw_ac.py +3 -3
- pyscf/pbc/lib/kpts_helper.py +4 -3
- pyscf/pbc/lib/linalg_helper.py +1 -1
- pyscf/pbc/mp/kmp2.py +1 -1
- pyscf/pbc/mpitools/mpi.py +1 -1
- pyscf/pbc/scf/_response_functions.py +141 -34
- pyscf/pbc/scf/addons.py +15 -11
- pyscf/pbc/scf/cphf.py +1 -1
- pyscf/pbc/scf/ghf.py +1 -1
- pyscf/pbc/scf/hf.py +21 -32
- pyscf/pbc/scf/kghf.py +33 -29
- pyscf/pbc/scf/khf.py +103 -29
- pyscf/pbc/scf/khf_ksymm.py +15 -1
- pyscf/pbc/scf/krohf.py +5 -7
- pyscf/pbc/scf/kuhf.py +54 -23
- pyscf/pbc/scf/kuhf_ksymm.py +1 -1
- pyscf/pbc/scf/rsjk.py +14 -10
- pyscf/pbc/scf/scfint.py +1 -1
- pyscf/pbc/scf/stability.py +27 -15
- pyscf/pbc/scf/uhf.py +3 -1
- pyscf/pbc/symm/symmetry.py +2 -2
- pyscf/pbc/tdscf/krhf.py +238 -154
- pyscf/pbc/tdscf/krks.py +1 -45
- pyscf/pbc/tdscf/kuhf.py +319 -171
- pyscf/pbc/tdscf/kuks.py +0 -56
- pyscf/pbc/tdscf/rhf.py +116 -3
- pyscf/pbc/tdscf/rks.py +2 -1
- pyscf/pbc/tdscf/uhf.py +214 -1
- pyscf/pbc/tdscf/uks.py +2 -1
- pyscf/pbc/tools/k2gamma.py +20 -6
- pyscf/pbc/tools/lattice.py +3 -3
- pyscf/pbc/tools/pbc.py +111 -91
- pyscf/pbc/tools/pyscf_ase.py +0 -1
- pyscf/pbc/tools/pywannier90.py +1 -1
- pyscf/qmmm/mm_mole.py +1 -1
- pyscf/scf/_response_functions.py +87 -46
- pyscf/scf/_vhf.py +15 -10
- pyscf/scf/addons.py +29 -15
- pyscf/scf/cphf.py +14 -52
- pyscf/scf/dhf.py +121 -38
- pyscf/scf/dispersion.py +10 -9
- pyscf/scf/ghf.py +25 -13
- pyscf/scf/ghf_symm.py +2 -2
- pyscf/scf/hf.py +262 -30
- pyscf/scf/rohf.py +37 -5
- pyscf/scf/stability.py +142 -112
- pyscf/scf/ucphf.py +21 -16
- pyscf/scf/uhf.py +104 -61
- pyscf/sgx/sgx.py +1 -1
- pyscf/sgx/sgx_jk.py +4 -4
- pyscf/solvent/__init__.py +2 -2
- pyscf/solvent/_attach_solvent.py +2 -0
- pyscf/solvent/_ddcosmo_tdscf_grad.py +1 -1
- pyscf/solvent/cosmors.py +366 -0
- pyscf/solvent/ddcosmo.py +1 -1
- pyscf/solvent/pcm.py +4 -4
- pyscf/solvent/pol_embed.py +1 -1
- pyscf/solvent/smd.py +5 -3
- pyscf/soscf/ciah.py +3 -11
- pyscf/soscf/newton_ah.py +5 -2
- pyscf/symm/__init__.py +1 -1
- pyscf/symm/addons.py +5 -5
- pyscf/symm/geom.py +1 -5
- pyscf/tdscf/_lr_eig.py +1002 -0
- pyscf/tdscf/dhf.py +84 -87
- pyscf/tdscf/dks.py +0 -4
- pyscf/tdscf/ghf.py +139 -127
- pyscf/tdscf/gks.py +27 -25
- pyscf/tdscf/rhf.py +194 -147
- pyscf/tdscf/rks.py +26 -22
- pyscf/tdscf/uhf.py +166 -118
- pyscf/tdscf/uks.py +32 -31
- pyscf/tools/fcidump.py +3 -0
- pyscf/tools/qcschema.py +265 -0
- pyscf/x2c/sfx2c1e.py +1 -1
- pyscf/x2c/tdscf.py +41 -41
- pyscf/x2c/x2c.py +15 -11
- {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/METADATA +39 -36
- {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/NOTICE +14 -1
- {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/RECORD +348 -316
- {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/WHEEL +1 -1
- pyscf/dft/gen_libxc_param.py +0 -35
- pyscf/dft/gen_xcfun_param.py +0 -209
- pyscf/pbc/tdscf/kproxy.py +0 -189
- pyscf/pbc/tdscf/kproxy_supercell.py +0 -664
- pyscf/pbc/tdscf/krhf_slow.py +0 -300
- pyscf/pbc/tdscf/krhf_slow_gamma.py +0 -175
- pyscf/pbc/tdscf/krhf_slow_supercell.py +0 -250
- pyscf/pbc/tdscf/proxy.py +0 -39
- pyscf/pbc/tdscf/rhf_slow.py +0 -35
- pyscf/tdscf/common_slow.py +0 -799
- pyscf/tdscf/proxy.py +0 -258
- pyscf/tdscf/rhf_slow.py +0 -181
- {pyscf-2.6.2.dist-info → pyscf-2.8.0.dist-info}/LICENSE +0 -0
- {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
|