This release is a pre-release and may not be stable for production use.
fortran-nlp-kernels
Python-facing exact lexical and dense-vector similarity search backed by Fortran, OpenMP, and OpenBLAS.
fortran-nlp-kernels provides a clean Python API while executing the computational kernels in compiled native code. The initial CPU beta includes exact word-shingle Jaccard search, exact inner-product search, exact squared-L2 search, cosine similarity, multicore OpenMP execution, and batched BLAS search.
Beta status
0.1.0b2 is the current Linux CPU beta.
This release adds batched lexical Jaccard search, automatic backend selection, expanded input validation, package-version exposure, and tested manylinux wheels for CPython 3.10–3.13.
The beta is intended for evaluation, reproducible systems work, and early integration. Public APIs may still evolve before the stable 0.1.0 release.
Included
- Exact word-shingle Jaccard search
- Serial Fortran lexical scoring
- OpenMP Fortran lexical scoring
- Exact inner-product vector search
- Exact squared-L2 vector search
- Exact cosine-similarity search
- Serial Fortran vector scoring
- OpenMP Fortran vector scoring
- OpenBLAS
SGEMVsingle-query search - OpenBLAS
SGEMMbatched-query search - Exact top-k selection
- NumPy correctness references
- Python, native Fortran, C ABI, and integration tests
- Batched lexical Jaccard search
- OpenMP parallelism across candidate-document pairs
- Automatic backend selection
- CPython 3.10–3.13 manylinux wheels
Current limitations
- Linux x86-64 only
- Result IDs are currently zero-based positional indexes
- Batched lexical search requires
backend="fortran_openmp"orbackend="auto" - Batched vector search requires
backend="fortran_blas"orbackend="auto" - Handwritten top-k selection currently uses an
O(Nk)reference implementation - CUDA Fortran and GPU backends are not included in this beta
Architecture
Python public API
↓
Python validation, preprocessing, and orchestration
↓
nanobind C++ extension
↓
stable C ABI
↓
Fortran / OpenMP / OpenBLAS kernels
The native lexical path is separated into focused layers:
lexical_core.f90 → lexical algorithms
lexical_c_api.f90 → Fortran-to-C adapter
.h header → C declarations
cpu_bindings.cpp → C-to-Python adapter
The vector-search path follows the same structure:
vector_search_core.f90 → handwritten IP and squared-L2 kernels
vector_search_blas.f90 → SGEMV and SGEMM implementations
topk_core.f90 → exact top-k selection
vector_search_c_api.f90 → Fortran-to-C adapter
cpu_bindings.cpp → C-to-Python adapter
Platform support
The initial 0.1.0b1 wheel targets CPython 3.12. The current development branch is continuously built and tested for:
Operating system: Linux
Architecture: x86-64
Python: CPython 3.10, 3.11, 3.12, and 3.13
Wheel policy: manylinux_2_28
The source package declares Python 3.10 or newer, but this beta has currently been built and validated with CPython 3.12 on Ubuntu 24.04.
System prerequisites
Installing the prebuilt Linux wheel
The published manylinux wheel bundles the required non-policy native libraries. No Fortran compiler or OpenBLAS development package is needed when installing a compatible prebuilt wheel.
Building from source
Install the compiler and development libraries:
sudo apt update
sudo apt install gfortran g++ libopenblas-dev libgomp1
A source build also requires a supported Python environment and pip. Build-time Python dependencies are installed through pyproject.toml.
Installation
PyPI Beta
Install the latest available pre-release:
python -m pip install --pre fortran-nlp-kernels
To request this exact beta:
python -m pip install fortran-nlp-kernels==0.1.0b2
Local wheel
Download the wheel matching the installed CPython version from the GitHub release or CI artifacts, then install it by path:
python -m pip install \
./fortran_nlp_kernels-0.1.0b2-cp312-cp312-manylinux_2_28_x86_64.whl
Editable source installation
git clone https://github.com/suwesh/fortran-nlp-kernels.git
cd fortran-nlp-kernels
python -m pip install -e .
Quick start
Exact lexical Jaccard search
from fortran_nlp.lexical import JaccardIndex
index = JaccardIndex(
[
"reset the account password",
"update seller information",
"create a new loan application",
],
backend="fortran_openmp",
)
results = index.search(
"how to reset the account password",
k=2,
minimum_score=0.01,
)
for result in results:
print(result)
Example result:
JaccardResult(
document_id=0,
score=0.5,
intersection_count=2,
union_count=4
)
Text preprocessing performs Unicode normalization, case folding, fixed-size word shingling, deterministic 64-bit hashing, sorting, and deduplication before invoking the native kernel.
Batched lexical Jaccard search
JaccardIndex.search_batch() compares multiple candidate texts against
the same indexed corpus.
from fortran_nlp.lexical import JaccardIndex
index = JaccardIndex(
[
"reset the account password",
"update seller information",
"create a new loan application",
],
backend="auto",
)
batch_results = index.search_batch(
[
"how to reset the account password",
"seller information update",
],
k=2,
minimum_score=0.01,
)
for candidate_index, candidate_results in enumerate(batch_results):
print(candidate_index, candidate_results)
The return type is:
list[list[JaccardResult]]
The outer list contains one entry per candidate. Each inner list contains the ranked corpus matches for that candidate.
Candidate shingles are stored in a packed variable-length representation with candidate offsets. The OpenMP backend distributes independent candidate-document comparisons across threads.
Batched lexical search requires:
backend="fortran_openmp"
or:
backend="auto"
Use OMP_NUM_THREADS to control parallel execution.
Exact vector search
The Python-facing database layout is:
(vector_count, dimension)
All public vector-search inputs are converted to contiguous float32 arrays. The package internally stores the database in a Fortran-compatible native layout.
Inner product
Higher scores are better.
import numpy as np
from fortran_nlp.vector_search import FlatIndexIP
database = np.array(
[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[-1.0, 2.0, 1.0],
],
dtype=np.float32,
)
query = np.array(
[1.0, 2.0, 3.0],
dtype=np.float32,
)
index = FlatIndexIP(
database,
backend="fortran_openmp",
)
scores, ids = index.search(query, k=2)
print(scores)
print(ids)
Squared-L2 distance
Lower distances are better. The package returns squared Euclidean distance and does not calculate the square root.
from fortran_nlp.vector_search import FlatIndexL2
index = FlatIndexL2(
database,
backend="fortran",
)
distances, ids = index.search(query, k=2)
Cosine similarity
Database vectors and queries are L2-normalized, then searched using the inner-product backend.
from fortran_nlp.vector_search import FlatIndexCosine
index = FlatIndexCosine(
database,
backend="fortran_blas",
)
scores, ids = index.search(query, k=2)
Zero vectors cannot be used with FlatIndexCosine because cosine normalization is undefined for a zero norm.
Batched vector search
Batched search uses OpenBLAS SGEMM and currently requires:
backend="fortran_blas"
The public query layout is:
(query_count, dimension)
Example:
queries = np.array(
[
[1.0, 2.0, 3.0],
[0.0, 1.0, 0.0],
],
dtype=np.float32,
)
index = FlatIndexIP(
database,
backend="fortran_blas",
)
scores, ids = index.search_batch(
queries,
k=2,
)
print(scores.shape) # (query_count, k)
print(ids.shape) # (query_count, k)
FlatIndexL2 and FlatIndexCosine expose the same search_batch() interface.
Backends
Lexical search
fortran → handwritten serial Fortran
fortran_openmp → handwritten OpenMP Fortran
Vector search
fortran → handwritten serial Fortran
fortran_openmp → handwritten OpenMP Fortran
fortran_blas → OpenBLAS SGEMV/SGEMM through Fortran
Automatic backend selection
Both public index families accept:
backend="auto"
The current deterministic policy is:
JaccardIndex
auto → fortran_openmp
FlatIndexIP
FlatIndexL2
FlatIndexCosine
auto → fortran_blas
Example:
from fortran_nlp.lexical import JaccardIndex
from fortran_nlp.vector_search import FlatIndexCosine
lexical_index = JaccardIndex(
corpus_texts,
backend="auto",
)
vector_index = FlatIndexCosine(
database_vectors,
backend="auto",
)
The current policy selects stable production defaults. It does not benchmark the host machine dynamically. Future releases may use measured workload crossover points to refine automatic selection.
Thread control
The handwritten OpenMP and OpenBLAS backends use different thread controls.
Handwritten OpenMP backend
OMP_NUM_THREADS=4 python your_script.py
OpenBLAS backend
OPENBLAS_NUM_THREADS=4 python your_script.py
For controlled benchmarks, avoid enabling high thread counts in both runtimes simultaneously:
# Handwritten serial
OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 python benchmark.py
# Handwritten OpenMP
OMP_NUM_THREADS=12 OPENBLAS_NUM_THREADS=1 python benchmark.py
# BLAS
OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=12 python benchmark.py
The library does not globally overwrite these environment variables.
Correctness and tests
The implementation is validated across several boundaries:
native Fortran core tests
C ABI tests
nanobind extension tests
NumPy equivalence tests
serial/OpenMP equivalence tests
BLAS/handwritten equivalence tests
single-query and batched-query tests
public Python API tests
input-validation and edge-case tests
deterministic tie-handling tests
package-metadata tests
wheel smoke tests
The 0.1.0b2 release passes 98 Python tests covering lexical search,
batched lexical search, exact vector search, native bindings, automatic
backend selection, memory layouts, input validation, deterministic tie
handling, and package metadata.
Run the Python test suite:
OPENBLAS_NUM_THREADS=1 \
OMP_NUM_THREADS=4 \
python -m pytest tests/ -v
Native test programs are available under:
tests/native/
Continuous integration
The repository includes two Linux CI workflows:
CPU Tests
→ builds the package from source
→ runs the complete test suite on CPython 3.10–3.13
Build Linux Wheels
→ builds and tests manylinux wheels with cibuildwheel
→ targets CPython 3.10, 3.11, 3.12, and 3.13
The wheel workflow runs manually or when a version tag matching v*
is pushed. Generated wheels are stored as temporary workflow artifacts.
The workflow does not automatically attach wheels to GitHub Releases or
upload them to PyPI.
Build system
The project uses:
meson-python → Python build backend
Meson → native build configuration
GFortran → Fortran compilation
nanobind → compiled Python extension
OpenMP → handwritten multicore kernels
OpenBLAS → SGEMV and SGEMM vector-search backends
Build the wheel and source distribution:
python -m pip install build
rm -rf dist/ build/ .mesonpy-*
python -m build
Expected release artifacts:
fortran_nlp_kernels-0.1.0b2-cp310-cp310-manylinux_2_28_x86_64.whl
fortran_nlp_kernels-0.1.0b2-cp311-cp311-manylinux_2_28_x86_64.whl
fortran_nlp_kernels-0.1.0b2-cp312-cp312-manylinux_2_28_x86_64.whl
fortran_nlp_kernels-0.1.0b2-cp313-cp313-manylinux_2_28_x86_64.whl
fortran_nlp_kernels-0.1.0b2.tar.gz
Validate distribution metadata and README rendering:
python -m pip install twine
python -m twine check dist/*
Research direction
The library is being developed as a reusable software artifact and performance-engineering study covering:
- exact lexical and dense-vector similarity search;
- Python/native interface overhead;
- serial and multicore CPU scaling;
- handwritten Fortran versus optimized BLAS;
- C++ and CUDA C++ research baselines;
- CUDA Fortran and cuBLAS backends;
- CPU/GPU crossover points;
- kernel-only and end-to-end performance.
Working technical-report title:
Fortran Kernels for NLP: Exact Lexical and Vector Similarity Search Across Multicore CPUs and NVIDIA GPUs
Roadmap
Planned follow-up work includes:
- benchmark-informed automatic backend selection;
- benchmark-informed OpenMP scheduling for batched lexical search;
- optional document and vector IDs;
- handwritten serial and OpenMP batched vector-search baselines;
- optimized exact top-k selection;
- CPU performance evaluation against NumPy, C++, and FAISS;
- automated PyPI Trusted Publishing;
- CUDA Fortran lexical and vector-search kernels;
- cuBLAS-backed vector search;
- CUDA C++ research baselines;
- FAISS GPU exact-flat comparisons;
- GPU-resident corpora and vector databases.
License
This project is licensed under GPL-3.0-only. See LICENSE.
Author
Suwesh Prasad Sah
- Homepage: https://suwesh.github.io/
- Repository: https://github.com/suwesh/fortran-nlp-kernels
- Issues: https://github.com/suwesh/fortran-nlp-kernels/issues
Metadata
Release files for fortran-nlp-kernels 0.1.0b2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fortran_nlp_kernels-0.1.0b2.tar.gz | 51.4 kB | Without provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| fortran_nlp_kernels-0.1.0b2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
| fortran_nlp_kernels-0.1.0b2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| fortran_nlp_kernels-0.1.0b2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| fortran_nlp_kernels-0.1.0b2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
Total release size: 48.8 MB
Release files / fortran_nlp_kernels-0.1.0b2.tar.gz
| Download URL | fortran_nlp_kernels-0.1.0b2.tar.gz |
|---|---|
| Size | 51.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ee9064f3204166135c0d6479ff3092a60794867039d1e670695f6d04b329efe6
|
|
BLAKE2b-256 checksum How to use checksums |
5ff47811132575f4284408cdf495857d6acbe9d2769ca25b69abf22ead7694ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / fortran_nlp_kernels-0.1.0b2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fortran_nlp_kernels-0.1.0b2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 12.2 MB |
| Tags | CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
2f9944d209b7281202a6cfc6f57a857cf08521e368622a0b5d507d9534c6dbdb
|
|
BLAKE2b-256 checksum How to use checksums |
f9bb04db441b9ebf053c333c5e04f98c25cc8fe6513c322ed90253b3591db299
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / fortran_nlp_kernels-0.1.0b2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fortran_nlp_kernels-0.1.0b2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 12.2 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
ec1c296df9642a91cedba0900de001f4618b10b78b36e5927e6f659b434d2d47
|
|
BLAKE2b-256 checksum How to use checksums |
a7cc6e13c7854a7e37b652e27c6e0bf5dfd03afb8cc0703fde45b113aaef9a72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / fortran_nlp_kernels-0.1.0b2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fortran_nlp_kernels-0.1.0b2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 12.2 MB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
17511bb0e077ec1fd96a477ec0a3518863383504e307d6f6a064c17725efe38b
|
|
BLAKE2b-256 checksum How to use checksums |
4e2e846ec051d491143401eaaa2bac9b603992ac859bcb62c647ca42b36c16a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / fortran_nlp_kernels-0.1.0b2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fortran_nlp_kernels-0.1.0b2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 12.2 MB |
| Tags | CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
6cbc0d8a969377a688a9d4706941cfc6b53e23d0ae0176b0a047b3c3a8c4b69e
|
|
BLAKE2b-256 checksum How to use checksums |
581c8d6b6c0171f856db21f00b72aab4c4320e6d100b1d7da376479df2d10400
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for fortran-nlp-kernels 0.1.0b2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.