diff --git a/python/lib.cpp b/python/lib.cpp index c21f330a..3bdad419 100644 --- a/python/lib.cpp +++ b/python/lib.cpp @@ -871,8 +871,13 @@ PYBIND11_MODULE(compiled, m) { m.attr("DEFAULT_EXPANSION_SEARCH") = py::int_(default_expansion_search()); m.attr("USES_OPENMP") = py::int_(USEARCH_USE_OPENMP); - m.attr("USES_SIMSIMD") = py::int_(USEARCH_USE_SIMSIMD); m.attr("USES_FP16LIB") = py::int_(USEARCH_USE_FP16LIB); + m.attr("USES_SIMSIMD") = py::int_(USEARCH_USE_SIMSIMD); +#if USEARCH_USE_SIMSIMD + m.attr("USES_SIMSIMD_DYNAMIC_DISPATCH") = py::int_(simsimd_uses_dynamic_dispatch()); +#else + m.attr("USES_SIMSIMD_DYNAMIC_DISPATCH") = py::int_(0); +#endif m.attr("VERSION_MAJOR") = py::int_(USEARCH_VERSION_MAJOR); m.attr("VERSION_MINOR") = py::int_(USEARCH_VERSION_MINOR); diff --git a/python/usearch/__init__.py b/python/usearch/__init__.py index e9505418..1e2b2b2b 100644 --- a/python/usearch/__init__.py +++ b/python/usearch/__init__.py @@ -1,16 +1,30 @@ import os import platform -import tempfile import warnings import urllib.request from typing import Optional, Tuple from urllib.error import HTTPError +#! SimSIMD must come before USearch import +try: + import simsimd +except ImportError: + pass + from usearch.compiled import ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, + # Default values: + DEFAULT_CONNECTIVITY, + DEFAULT_EXPANSION_ADD, + DEFAULT_EXPANSION_SEARCH, + # Dependencies: + USES_OPENMP, + USES_FP16LIB, + USES_SIMSIMD, + USES_SIMSIMD_DYNAMIC_DISPATCH, ) __version__ = f"{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_PATCH}" diff --git a/python/usearch/index.py b/python/usearch/index.py index fe344431..f73997bc 100644 --- a/python/usearch/index.py +++ b/python/usearch/index.py @@ -25,6 +25,12 @@ import numpy as np from tqdm import tqdm +#! SimSIMD must come before USearch import +try: + import simsimd +except ImportError: + pass + # Precompiled symbols that won't be exposed directly: from usearch.compiled import ( Index as _CompiledIndex, diff --git a/setup.py b/setup.py index 0188f5fd..47ff5572 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ from pybind11.setup_helpers import Pybind11Extension -sources = ["python/lib.cpp"] compile_args = [] link_args = [] macros_args = [] @@ -46,17 +45,39 @@ def get_bool_env_w_name(name: str, preference: bool) -> tuple: prefer_fp16lib: bool = True prefer_openmp: bool = is_linux and is_gcc -use_simsimd: bool = get_bool_env("USEARCH_USE_SIMSIMD", prefer_simsimd) +use_simsimd: bool = True # get_bool_env("USEARCH_USE_SIMSIMD", prefer_simsimd) use_fp16lib: bool = get_bool_env("USEARCH_USE_FP16LIB", prefer_fp16lib) use_openmp: bool = get_bool_env("USEARCH_USE_OPENMP", prefer_openmp) -if use_simsimd: - sources.append("simsimd/c/lib.c") - # Common arguments for all platforms macros_args.append(("USEARCH_USE_OPENMP", "1" if use_openmp else "0")) -macros_args.append(("USEARCH_USE_SIMSIMD", "1" if use_simsimd else "0")) macros_args.append(("USEARCH_USE_FP16LIB", "1" if use_fp16lib else "0")) +macros_args.append(("USEARCH_USE_SIMSIMD", "1" if use_simsimd else "0")) + + +#! Unlike OpenMP and FP16LIB, the SimSIMD is integrated differently. +#! It will anyways use dynamic dispatch, and will not build the library as part of `usearch` package. +#! It relies on the fact that SimSIMD ships it's own bindings for most platforms, and the user should +#! install it separately! +macros_args.extend( + [ + ("SIMSIMD_DYNAMIC_DISPATCH", "1" if use_simsimd else "0"), + ("SIMSIMD_TARGET_NEON", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_NEON_BF16", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_NEON_F16", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_NEON_I8", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SVE", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SVE_BF16", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SVE_F16", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SVE_I8", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SVE2", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_HASWELL", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SKYLAKE", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_ICE", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_SAPPHIRE", "0"), # ? Hide-out all complex intrinsics + ("SIMSIMD_TARGET_GENOA", "0"), # ? Hide-out all complex intrinsics + ] +) if is_linux: compile_args.append("-std=c++17") @@ -72,21 +93,6 @@ def get_bool_env_w_name(name: str, preference: bool) -> tuple: compile_args.append("-fopenmp") link_args.append("-lgomp") - if use_simsimd: - macros_args.extend( - [ - get_bool_env_w_name("SIMSIMD_TARGET_NEON", True), - get_bool_env_w_name("SIMSIMD_TARGET_NEON_BF16", False), - get_bool_env_w_name("SIMSIMD_TARGET_SVE", True), - get_bool_env_w_name("SIMSIMD_TARGET_SVE_BF16", False), - get_bool_env_w_name("SIMSIMD_TARGET_HASWELL", True), - get_bool_env_w_name("SIMSIMD_TARGET_SKYLAKE", True), - get_bool_env_w_name("SIMSIMD_TARGET_ICE", True), - get_bool_env_w_name("SIMSIMD_TARGET_GENOA", True), - get_bool_env_w_name("SIMSIMD_TARGET_SAPPHIRE", True), - ] - ) - if is_macos: # MacOS 10.15 or higher is needed for `aligned_alloc` support. # https://github.com/unum-cloud/usearch/actions/runs/4975434891/jobs/8902603392 @@ -111,47 +117,16 @@ def get_bool_env_w_name(name: str, preference: bool) -> tuple: # link_args.append("-lomp") # macros_args.append(("USEARCH_USE_OPENMP", "1")) - if use_simsimd: - macros_args.extend( - [ - get_bool_env_w_name("SIMSIMD_TARGET_NEON", True), - get_bool_env_w_name("SIMSIMD_TARGET_NEON_BF16", False), - get_bool_env_w_name("SIMSIMD_TARGET_SVE", False), - get_bool_env_w_name("SIMSIMD_TARGET_SVE_BF16", False), - get_bool_env_w_name("SIMSIMD_TARGET_HASWELL", True), - get_bool_env_w_name("SIMSIMD_TARGET_SKYLAKE", False), - get_bool_env_w_name("SIMSIMD_TARGET_ICE", False), - get_bool_env_w_name("SIMSIMD_TARGET_GENOA", False), - get_bool_env_w_name("SIMSIMD_TARGET_SAPPHIRE", False), - ] - ) - - if is_windows: compile_args.append("/std:c++17") compile_args.append("/O2") compile_args.append("/fp:fast") # Enable fast math for MSVC compile_args.append("/W1") # Reduce warnings verbosity - if use_simsimd: - macros_args.extend( - [ - get_bool_env_w_name("SIMSIMD_TARGET_NEON", True), - get_bool_env_w_name("SIMSIMD_TARGET_NEON_BF16", False), - get_bool_env_w_name("SIMSIMD_TARGET_SVE", False), - get_bool_env_w_name("SIMSIMD_TARGET_SVE_BF16", False), - get_bool_env_w_name("SIMSIMD_TARGET_HASWELL", True), - get_bool_env_w_name("SIMSIMD_TARGET_SKYLAKE", True), - get_bool_env_w_name("SIMSIMD_TARGET_ICE", True), - get_bool_env_w_name("SIMSIMD_TARGET_GENOA", False), - get_bool_env_w_name("SIMSIMD_TARGET_SAPPHIRE", False), - ] - ) - ext_modules = [ Pybind11Extension( "usearch.compiled", - sources, + ["python/lib.cpp"], extra_compile_args=compile_args, extra_link_args=link_args, define_macros=macros_args, @@ -172,8 +147,13 @@ def get_bool_env_w_name(name: str, preference: bool) -> tuple: "python", "stringzilla/include", ] +install_requires = [ + "numpy", + "tqdm", +] if use_simsimd: include_dirs.append("simsimd/include") + install_requires.append("simsimd>=5.6.3") if use_fp16lib: include_dirs.append("fp16/include") @@ -222,10 +202,7 @@ def get_bool_env_w_name(name: str, preference: bool) -> tuple: ], include_dirs=include_dirs, ext_modules=ext_modules, - install_requires=[ - "numpy", - "tqdm", - ], + install_requires=install_requires, ) # Reset the CC environment variable, that we overrode earlier. diff --git a/simsimd b/simsimd index 88f67e67..88088c36 160000 --- a/simsimd +++ b/simsimd @@ -1 +1 @@ -Subproject commit 88f67e67797c7d015e56e9badd585f922476fbb0 +Subproject commit 88088c36ec9fbdf3f671af24c09bcd0e3b0ffc74