diff --git a/Makefile b/Makefile index 9175b1c0..5f5c964d 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ format: ${python} pre_commit run --all-files test: - ${python} -m pytest -rs ./tests/test_solvers.py + ${python} -m pytest -rs ./tests/test_kernels.py types: # ${python} -m monkeytype run $(which pytest) ./tests/test_solvers.py @@ -27,6 +27,12 @@ types: cov: ${python} -m pytest -vrs --cov=${pkg} --cov-report html tests +compile: + ${python} _compile.py + +build: compile + ${python} -m build . + clean: rm -rf ./env/ find ./src/ | grep -E "\(/__pycache__$$|\.pyc$$|\.pyo$$\)" | xargs rm -rf diff --git a/_compile.py b/_compile.py new file mode 100644 index 00000000..7a8f34c0 --- /dev/null +++ b/_compile.py @@ -0,0 +1,72 @@ +""" Compile script for Fortran """ + +import os +import subprocess + +f90_modules = { + # "": "representations/frepresentations.f90", + # "": "representations/facsf.f90", + # "": "representations/fslatm.f90", + # "": "representations/fchl/ffchl_module.f90", + # "": "representations/fchl/ffchl_kernels.f90", + # "": "representations/fchl/ffchl_electric_field_kernels.f90", + # "": "representations/fchl/ffchl_kernel_types.f90", + # "": "representations/fchl/ffchl_force_kernels.f90", + # "": "representations/fchl/ffchl_scalar_kernels.f90", + "solvers.fsolvers": ["solvers/fsolvers.f90"], + "kernels.fdistance": ["kernels/fdistance.f90"], + "kernels.fkernels": ["kernels/fkernels.f90", "kernels/fkpca.f90"], + "kernels.fgradient_kernels": ["kernels/fgradient_kernels.f90"], +} + + +def find_mkl(): + + return + + +def find_flags(fcc: str): + """Find compiler flags""" + + flags = ["-L/usr/lib/", "-lblas", "-llapack"] + + return flags + + +def find_fcc(): + """Find the fortran compiler. Either gnu or intel""" + + fcc = "gfortran" + + return fcc + + +def main(): + """Compile f90 in src/qmllib""" + + fcc = find_fcc() + flags = find_flags(fcc) + + os.environ["FCC"] = fcc + + for module_name, module_sources in f90_modules.items(): + + cmd = f"f2py {' '.join(flags)} -c {' '.join(module_sources)} -m {module_name}" + print(cmd) + + proc = subprocess.run(cmd.split(), cwd="src/qmllib", capture_output=True, text=True) + log = proc.stdout + error = proc.stderr + exitcode = proc.returncode + + if exitcode > 0: + print(log) + print() + print(error) + exit(exitcode) + + exit(0) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 263f2da1..67be17ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools", "setuptools-scm"] +requires = ["setuptools", "setuptools-scm", "numpy"] build-backend = "setuptools.build_meta" [project] diff --git a/src/qmllib/kernels/kernels.py b/src/qmllib/kernels/kernels.py index 532e1b42..e567efbe 100644 --- a/src/qmllib/kernels/kernels.py +++ b/src/qmllib/kernels/kernels.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import numpy as np from .fkernels import ( @@ -20,7 +18,7 @@ def wasserstein_kernel(A, B, sigma, p=1, q=1): """Calculates the Wasserstein kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = \\exp \\big( -\\frac{(W_p(A_i, B_i))^q}{\sigma} \\big)` + :math:`K_{ij} = \\exp \\big( -\\frac{(W_p(A_i, B_i))^q}{\\sigma} \\big)` Where :math:`A_{i}` and :math:`B_{j}` are representation vectors. K is calculated using an OpenMP parallel Fortran routine. @@ -50,7 +48,7 @@ def wasserstein_kernel(A, B, sigma, p=1, q=1): def laplacian_kernel(A, B, sigma): """Calculates the Laplacian kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - B_j\\|_1}{\sigma} \\big)` + :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - B_j\\|_1}{\\sigma} \\big)` Where :math:`A_{i}` and :math:`B_{j}` are representation vectors. K is calculated using an OpenMP parallel Fortran routine. @@ -80,7 +78,7 @@ def laplacian_kernel(A, B, sigma): def laplacian_kernel_symmetric(A, sigma): """Calculates the symmetric Laplacian kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - A_j\\|_1}{\sigma} \\big)` + :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - A_j\\|_1}{\\sigma} \\big)` Where :math:`A_{i}` are representation vectors. K is calculated using an OpenMP parallel Fortran routine. @@ -107,7 +105,7 @@ def laplacian_kernel_symmetric(A, sigma): def gaussian_kernel(A, B, sigma): """Calculates the Gaussian kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - B_j\\|_2^2}{2\sigma^2} \\big)` + :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - B_j\\|_2^2}{2\\sigma^2} \\big)` Where :math:`A_{i}` and :math:`B_{j}` are representation vectors. K is calculated using an OpenMP parallel Fortran routine. @@ -137,7 +135,7 @@ def gaussian_kernel(A, B, sigma): def gaussian_kernel_symmetric(A, sigma): """Calculates the symmetric Gaussian kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - A_j\\|_2^2}{2\sigma^2} \\big)` + :math:`K_{ij} = \\exp \\big( -\\frac{\\|A_i - A_j\\|_2^2}{2\\sigma^2} \\big)` Where :math:`A_{i}` are representation vectors. K is calculated using an OpenMP parallel Fortran routine. @@ -164,7 +162,7 @@ def gaussian_kernel_symmetric(A, sigma): def linear_kernel(A, B): """Calculates the linear kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = A_i \cdot B_j` + :math:`K_{ij} = A_i \\cdot B_j` VWhere :math:`A_{i}` and :math:`B_{j}` are representation vectors. @@ -193,7 +191,7 @@ def linear_kernel(A, B): def sargan_kernel(A, B, sigma, gammas): """Calculates the Sargan kernel matrix K, where :math:`K_{ij}`: - :math:`K_{ij} = \\exp \\big( -\\frac{\\| A_i - B_j \\|_1)}{\sigma} \\big) \\big(1 + \\sum_{k} \\frac{\gamma_{k} \\| A_i - B_j \\|_1^k}{\sigma^k} \\big)` + :math:`K_{ij} = \\exp \\big( -\\frac{\\| A_i - B_j \\|_1)}{\\sigma} \\big) \\big(1 + \\sum_{k} \\frac{\\gamma_{k} \\| A_i - B_j \\|_1^k}{\\sigma^k} \\big)` Where :math:`A_{i}` and :math:`B_{j}` are representation vectors. K is calculated using an OpenMP parallel Fortran routine. @@ -231,11 +229,11 @@ def matern_kernel(A, B, sigma, order=0, metric="l1"): """Calculates the Matern kernel matrix K, where :math:`K_{ij}`: for order = 0: - :math:`K_{ij} = \\exp\\big( -\\frac{d}{\sigma} \\big)` + :math:`K_{ij} = \\exp\\big( -\\frac{d}{\\sigma} \\big)` for order = 1: - :math:`K_{ij} = \\exp\\big( -\\frac{\\sqrt{3} d}{\sigma} \\big) \\big(1 + \\frac{\\sqrt{3} d}{\sigma} \\big)` + :math:`K_{ij} = \\exp\\big( -\\frac{\\sqrt{3} d}{\\sigma} \\big) \\big(1 + \\frac{\\sqrt{3} d}{\\sigma} \\big)` for order = 2: - :math:`K_{ij} = \\exp\\big( -\\frac{\\sqrt{5} d}{d} \\big) \\big( 1 + \\frac{\\sqrt{5} d}{\sigma} + \\frac{5 d^2}{3\sigma^2} \\big)` + :math:`K_{ij} = \\exp\\big( -\\frac{\\sqrt{5} d}{d} \\big) \\big( 1 + \\frac{\\sqrt{5} d}{\\sigma} + \\frac{5 d^2}{3\\sigma^2} \\big)` Where :math:`A_i` and :math:`B_j` are representation vectors, and d is a distance measure. @@ -291,7 +289,7 @@ def matern_kernel(A, B, sigma, order=0, metric="l1"): def get_local_kernels_gaussian(A, B, na, nb, sigmas): """Calculates the Gaussian kernel matrix K, for a local representation where :math:`K_{ij}`: - :math:`K_{ij} = \sum_{a \in i} \sum_{b \in j} \\exp \\big( -\\frac{\\|A_a - B_b\\|_2^2}{2\sigma^2} \\big)` + :math:`K_{ij} = \\sum_{a \\in i} \\sum_{b \\in j} \\exp \\big( -\\frac{\\|A_a - B_b\\|_2^2}{2\\sigma^2} \\big)` Where :math:`A_{a}` and :math:`B_{b}` are representation vectors. @@ -333,7 +331,7 @@ def get_local_kernels_gaussian(A, B, na, nb, sigmas): def get_local_kernels_laplacian(A, B, na, nb, sigmas): """Calculates the Local Laplacian kernel matrix K, for a local representation where :math:`K_{ij}`: - :math:`K_{ij} = \sum_{a \in i} \sum_{b \in j} \\exp \\big( -\\frac{\\|A_a - B_b\\|_1}{\sigma} \\big)` + :math:`K_{ij} = \\sum_{a \\in i} \\sum_{b \\in j} \\exp \\big( -\\frac{\\|A_a - B_b\\|_1}{\\sigma} \\big)` Where :math:`A_{a}` and :math:`B_{b}` are representation vectors. diff --git a/tests/test_distance.py b/tests/test_distance.py index 12b8a899..baed3a2d 100644 --- a/tests/test_distance.py +++ b/tests/test_distance.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import numpy as np from qmllib.kernels.distance import l2_distance, manhattan_distance, p_distance diff --git a/tests/test_kernels.py b/tests/test_kernels.py index 975d66b1..913b1ee3 100644 --- a/tests/test_kernels.py +++ b/tests/test_kernels.py @@ -1,8 +1,7 @@ -from __future__ import print_function - import os import numpy as np +import pytest from scipy.stats import wasserstein_distance from sklearn.decomposition import KernelPCA @@ -121,7 +120,7 @@ def test_linear_kernel(): X = np.random.rand(n_train, 1000) Xs = np.random.rand(n_test, 1000) - sigma = 100.0 + # UNUSED sigma = 100.0 Ktest = np.zeros((n_train, n_test)) @@ -240,6 +239,7 @@ def array_nan_close(a, b): return np.allclose(a[m], b[m], atol=1e-8, rtol=0.0) +@pytest.mark.skip(reason="Removing all Compound classes") def test_kpca(): test_dir = os.path.dirname(os.path.realpath(__file__)) @@ -283,8 +283,8 @@ def test_wasserstein_kernel(): n_test = 3 # List of dummy representations - X = np.array(np.random.randint(0, 10, size=(n_train, 3)), dtype=np.float) - Xs = np.array(np.random.randint(0, 10, size=(n_test, 3)), dtype=np.float) + X = np.array(np.random.randint(0, 10, size=(n_train, 3)), dtype=np.float64) + Xs = np.array(np.random.randint(0, 10, size=(n_test, 3)), dtype=np.float64) sigma = 100.0