Source code for shepherd_score.score.gaussian_overlap_np
"""
Gaussian volume overlap scoring functions -- Shape-only (i.e., not color)
NUMPY VERSION
Single instance functionality only.
Reference math:
https://doi.org/10.1002/(SICI)1096-987X(19961115)17:14<1653::AID-JCC7>3.0.CO;2-K
https://doi.org/10.1021/j100011a016
"""
import numpy as np
from scipy.spatial import distance
###################################################################################################
####### NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY NUMPY #######
###################################################################################################
[docs]
def VAB_2nd_order_np(centers_1, centers_2, alpha) -> np.ndarray:
""" 2nd order volume overlap of AB """
R2 = (distance.cdist(centers_1, centers_2)**2.0).T
VAB_2nd_order = np.sum(np.pi**(1.5) * np.exp(-(alpha / 2) * R2) / ((2*alpha)**(1.5)))
return VAB_2nd_order
[docs]
def shape_tanimoto_np(centers_1, centers_2, alpha) -> np.ndarray:
""" Compute Tanimoto shape similarity """
VAA = VAB_2nd_order_np(centers_1, centers_1, alpha)
VBB = VAB_2nd_order_np(centers_2, centers_2, alpha)
VAB = VAB_2nd_order_np(centers_1, centers_2, alpha)
return VAB / (VAA + VBB - VAB)
[docs]
def get_overlap_np(centers_1:np.ndarray,
centers_2:np.ndarray,
alpha:float = 0.81
) -> np.ndarray:
""" NumPy implementation of shape similarity via gaussian overlaps (single instance) """
tanimoto = shape_tanimoto_np(centers_1, centers_2, alpha)
return tanimoto
[docs]
def get_max_overlap_np(centers_1: np.ndarray,
centers_2: np.ndarray,
alpha: float = 0.81
) -> np.ndarray:
""" Maximum overlap volume among any pair of centers (always in [0, 1] range)."""
R2 = (distance.cdist(centers_1, centers_2)**2.0).T
return np.max(np.exp(-(alpha / 2) * R2))
[docs]
def get_linear_hard_sphere_overlap_np(centers_1: np.ndarray, centers_2: np.ndarray, min_dist: float) -> np.ndarray:
""" Compute linear hard sphere overlap.
This function is linear based on the distance between centers
For distance d
d > min_dist: 0
0 < d < min_dist: linear from 0 to 1
d == 0: 1
Returns:
np.ndarray shape (1,) with the sum of hard sphere overlaps between)
"""
dists = distance.cdist(centers_1, centers_2)
return np.sum(np.maximum((min_dist - dists) / min_dist, 0.0))
[docs]
def VAB_2nd_order_cosine_np(centers_1: np.ndarray,
centers_2: np.ndarray,
vectors_1: np.ndarray,
vectors_2: np.ndarray,
alpha: float,
allow_antiparallel: bool,
) -> np.ndarray:
"""
2nd order volume overlap of AB weighted by cosine similarity.
NumPy implementation with single instance functionality.
"""
if len(centers_1.shape) == 2:
# Normalize vectors for cosine similarity
norm_v1 = np.linalg.norm(vectors_1, axis=1, keepdims=True)
norm_v2 = np.linalg.norm(vectors_2, axis=1, keepdims=True)
# Avoid division by zero if a vector is all zeros
vec1_norm = np.divide(vectors_1, norm_v1, out=np.zeros_like(vectors_1), where=norm_v1!=0)
vec2_norm = np.divide(vectors_2, norm_v2, out=np.zeros_like(vectors_2), where=norm_v2!=0)
# cosine similarity
V2 = np.matmul(vec1_norm, vec2_norm.T).T # Now uses normalized vectors
if allow_antiparallel:
V2 = np.abs(V2)
else:
V2 = np.clip(V2, 0., 1.)
V2 = (V2 + 2.)/3. # Following PheSA's suggestion for weighting
R2 = (distance.cdist(centers_1, centers_2)**2.0).T
VAB_second_order = np.sum(np.pi**(1.5) * V2 * np.exp(-(alpha / 2) * R2) / ((2*alpha)**(1.5)))
return VAB_second_order