Source code for pyscf.gw.utils.gw_np_helper
#!/usr/bin/env python
# Copyright 2014-2026 The PySCF Developers. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Christopher Hillenbrand <chillenbrand15@gmail.com>
#
"""
Math functions for GW and RPA.
References:
T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
New J. Phys. 14 053020 (2012)
"""
import scipy.linalg as sla
import numpy as np
def _is_contiguous(arr):
return arr.flags['C_CONTIGUOUS'] or arr.flags['F_CONTIGUOUS']
[docs]
def array_scale(arr, alpha):
"""Scale an array in place by a scalar with BLAS if possible.
arr <- alpha * arr
Parameters
----------
arr : array_like
Array to be scaled.
alpha : scalar
Scale factor.
"""
if _is_contiguous(arr):
# level 1 BLAS is usually multithreaded
scal = sla.get_blas_funcs('scal', (arr,))
scal(a=alpha, x=arr.reshape(-1))
else:
arr *= alpha
[docs]
def addto_diagonal(arr, x):
"""Add a scalar or vector to the diagonal of a matrix.
Parameters
----------
arr : (M, M) array_like
Square matrix (will be modified)
x : (M,) array_like | scalar
Vector or scalar.
Returns
-------
arr : (M, M) ndarray
arr[i, i] <- arr[i, i] + x[i].
"""
diag = arr.diagonal()
np.fill_diagonal(arr, diag + x)
return arr
[docs]
def get_id_minus_pi(Pi):
"""Calculate I - Pi in place.
Parameters
----------
Pi : (M, M) array_like
Input matrix.
Returns
-------
id_minus_pi : (M, M) ndarray
(I - Pi)
"""
array_scale(Pi, -1.0)
addto_diagonal(Pi, 1.0)
return Pi
[docs]
def get_id_minus_pi_inv(Pi, overwrite_input=False):
"""Calculate (I - Pi)^-1, given Pi
Parameters
----------
Pi : (M, M) array_like
Input matrix. Must be C-contiguous.
Returns
-------
Pi_inv : (M, M) ndarray
(I - Pi)^-1
"""
assert Pi.flags.c_contiguous
id_minus_pi = get_id_minus_pi(Pi)
id_minus_pi_inv = sla.inv(id_minus_pi.T, overwrite_a=overwrite_input, check_finite=False).T
return id_minus_pi_inv
[docs]
def get_id_minus_pi_inv_minus_id(Pi, overwrite_input=False):
"""Calculate (I - Pi)^-1 - I.
Parameters
----------
Pi : (M, M) array_like
Input matrix. Must be C-contiguous.
Returns
-------
Pi_inv : (M, M) ndarray
(I - Pi)^-1 - I.
"""
id_minus_pi_inv = get_id_minus_pi_inv(Pi, overwrite_input=overwrite_input)
return addto_diagonal(id_minus_pi_inv, -1.0)
[docs]
def mkslice(l):
"""
Try to make a slice from a list of integers.
If this is not possible, return the input unchanged.
Parameters
----------
l : slice | list | range | ndarray
Various ways of representing a list of integer indices
Returns
-------
slice | list | ndarray
slice if possible, otherwise returns the input unchanged
"""
# If l is already a slice, return it
if isinstance(l, slice):
return l
if l is None or l == ():
return slice(None)
# range to slice is easy
if isinstance(l, range):
return slice(l.start, l.stop, l.step)
if len(l) < 2:
return l
strides = np.diff(l)
if not np.all(strides == strides[0]):
return l
else:
start = l[0]
stop = l[-1] + strides[0]
step = strides[0]
return slice(start, stop, step)