Release notes
Versions follow Semantic Versioning; before 1.0, minor versions may
change the API. Install a specific version with pip install pylignum==<version>.
0.4.1 — 2026-10-30
Section titled “0.4.1 — 2026-10-30”Changed
Section titled “Changed”- New benchmarks.
benchmarks/suite.pyreplaces the earlier comparisons: the same models on every machine (500 rounds; LightGBMnum_leaves=63, XGBoostlossguidewithmax_leaves=63, CatBoost depth 6), seven data sets, batches of 1 to 1,000,000 rows on one thread and all threads, p50 / p99 / p99.9 latencies, preparation (compile) times and a bit-exactness check, against LightGBM, XGBoost, CatBoost, lleaves and TL2cgen, from numpy and from Arrow. Single rows now differ on every call: the earlier latencies predicted the same row again and again, which the branch predictor learns, so they were too optimistic for every engine. With that, the new models and another server, one California row on x86 went from 2.9 to 11 µs for lignum and from 7.8 to 24.6 µs for lleaves. The benchmarks page, the README and the home page show only the new results (Apple M4 and a Hetzner CCX33 with AMD EPYC-Milan); the old reports are removed.
compile()on macOS compiles in parallel again. The generated files were compiled from several threads throughsystem(), which macOS serialises with a global lock, so they ran one after another. The compiler is now started withposix_spawnon Linux and macOS. Apple M4, 500 rounds with 63 leaves: California 8.4 -> 2.1 s, Diabetes 7.0 -> 1.7 s; Covertype (3,500 trees) 63 -> 13 s. Linux (glibc) already ran them in parallel; Windows is unchanged.
0.4.0 — 2026-10-27
Section titled “0.4.0 — 2026-10-27”Changed
Section titled “Changed”-
Breaking: column names are checked. When a model was trained on named columns and the input has column names (pandas DataFrame, pyarrow, polars or other Arrow data),
predictchecks that the columns start with the model’sfeature_names, in the same order, and raisesValueErrorotherwise. Before, a reordered or missing column silently gave other predictions. numpy arrays, frames without column names, models without names and the C API are unchanged (by position).predict(..., validate_features=False),load(..., validate_features=False)ormodel.validate_features = Falseturn the check off; it costs 0-5 µs per call (Apple M4). -
Breaking:
.binformat 0.8. It adds the feature names, the library the model was trained with, its objective and the lignum version that wrote the file. Files written by lignum 0.3 are rejected: save them again from the original model. -
Compiled-library files (
Model.compile()): withoutlibrary=, libraries go to a per-user cache (~/.cache/lignum,~/Library/Caches/lignum,%LOCALAPPDATA%\lignum\Cache, orLIGNUM_CACHE_DIR) instead oflignum_compiledin the temp directory, and the code is built in a temporary folder that is always removed: no.c,.oor log files are left behind (a failed build keeps only its log, named in the error together with the compiler’s last lines).library=writes the library exactly there, always compiling it and bypassing the cache. -
Breaking:
compile()has nowork_dirany more (setLIGNUM_CACHE_DIRto move the cache), and its options afterflagsare keyword-only. In the C API the fourth argument ofLignumModelCompileis now the cache folder (NULL: the per-user cache).
- Model inspection:
Model.n_trees,Model.source("lightgbm","xgboost"or"catboost"),Model.objective(the library’s name, e.g."binary","multi:softprob","Logloss") andModel.info(), a dict that adds the output transform, the number of leaves, the kernel in use, the compiled library and, for.binfiles, the lignum version that wrote them.repr(model)shows the source, objective, trees and features. C API:LignumModelNumTrees. Model.feature_names: the names of the training columns (LightGBM, XGBoost and CatBoost files, kept in.bin), orNonefor models trained on a matrix.lignum.cache_dir(),lignum.clear_cache()andModel.compiled_library(the path of the library in use).compile(library=folder)writeslignum_<model fingerprint>_<platform>.so(.dllon Windows) into the folder, andload(..., compiled=folder)picks the file for the model and platform, so one folder can hold the libraries of several models and platforms.
- Processes compiling the same model at once no longer write the same files: each builds in its own folder and the library is moved into place with an atomic rename.
- The cache key includes the CPU architecture: x86-64 (e.g. under Rosetta) and arm64 processes no
longer load each other’s libraries. The key is also stable across compilers (FNV-1a instead of
std::hash), and a cached library that fails to load is rebuilt. - Errors when loading a library built for another platform name the platform that is needed.
- XGBoost models that were predicted wrongly without an error are now rejected: linear boosters
(
booster="gblinear", which loaded as an empty forest predictingbase_score) and DART models that dropped trees (rate_drop > 0: XGBoost weights each tree, lignum ignored the weights). DART files from XGBoost before 3.4 (trees nested undergbtree) used to load as an empty forest too; they now predict correctly when no tree was dropped. LightGBM DART models were and are exact.
The old lignum_compiled folder in the temp directory is no longer used and can be deleted.
0.3.1 — 2026-10-27
Section titled “0.3.1 — 2026-10-27”- License notices:
NOTICEnow carries the notices of the third-party code lignum derives from, as their licenses require for source and binary copies: CityHash (Copyright (c) 2011 Google, Inc., MIT License; CatBoost’s category hash) and fmath by herumi (BSD 3-Clause; theexpCatBoost uses on x86). The 0.3.0 wheels lacked them. No change to predictions or the API. - Two GCC warnings (
-Wall -Wextra): an unchecked simdjson result for an optional field of CatBoost JSON models, and an unused variable on ARM. - The CatBoost benchmark no longer asks CatBoost to read polars 2.x Categorical columns, which it does not support (on Windows CatBoost could crash on them); lignum was not affected.
0.3.0 — 2026-10-27
Section titled “0.3.0 — 2026-10-27”- CatBoost models, bit-identical to CatBoost: symmetric trees of any depth up to 16, float
features (NaN as
Min/Max), categorical features as one-hot or CTRs (Borders,Buckets,Counter,BinarizedTargetMeanValue) including combinations of categories with each other and with float features; binary, regression,Poisson,Tweedie,MultiClassandMultiClassOneVsAll. Reads.cbm(without the flatbuffers library) and JSON. - Categorical input as strings or integers from pandas (object, string and category columns), numpy object arrays, lists, pyarrow and polars (string and dictionary columns). Large DataFrames go through pyarrow when it is installed.
lignum.catboost_hash(value),lignum::catboost_hashin C++ andLignumCatBoostHashin the C API, for callers that pass category hashes in a float64 matrix.- The CatBoost kernel is built twice on x86-64 (generic and AVX2) and picks the AVX2 build by cpuid
at run time;
LIGNUM_ISA=genericforces the generic one. Linux, macOS and Windows (MSVC). - Speed, against CatBoost 1.2.10’s C API on one thread (500 trees of depth 6): 1.9-2.2x faster on models with categories, 1.1-2.4x on numeric models on x86-64 (AMD EPYC 9V45), 2.2-3.6x on ARM (Neoverse-N2) and 2.3-2.8x on an Apple M4; one row 7-14x faster with categories. Details on the benchmarks page.
- Security policy (
SECURITY.md), contributing guide, citation file and this changelog.
Changed
Section titled “Changed”- License: Apache License 2.0 (was MIT). Releases up to 0.2.0 remain available under MIT.
- The
.binformat is now version 0.7 (CatBoost models)..binfiles written by 0.2.0 are rejected with a clear error: export them again from the original model. - A 1-D array or flat list is one row for every model.
predictaccepts read-only arrays (pandas 3.1 returns them fromnp.asarray(DataFrame)).
0.2.0 — 2026-10-23
Section titled “0.2.0 — 2026-10-23”First release on PyPI (pip install pylignum, import lignum).
- Bit-exact LightGBM and XGBoost semantics: thresholds, NaN and zero-as-missing, categorical splits, multiclass models and XGBoost’s float32 arithmetic, checked against the real libraries in every test.
- Two engines: a binned interpreter for any batch size, and a compiled mode (
model.compile()) that turns the trees into native code with the system C compiler in a few seconds. A compiled library ships next to the model and loads in about 2 ms without a compiler;model.autotune(X)picks the interpreter or the compiled code per batch size. - Formats: LightGBM
model.txtand JSON, XGBoost JSON and UBJSON, detected from the file content.model.save("model.bin")writes a binary file that loads by memory mapping in under a millisecond. - Arrow input without copies: pyarrow tables and batches, polars data frames and any object with the Arrow PyCapsule interface; dictionary columns are categories.
- C API for other languages, with Arrow input and the compiled mode.
- Wheels for Linux x86_64 and aarch64 (manylinux_2_28), macOS 15+ (arm64, x86_64) and Windows x64; Python 3.10, 3.11 and abi3 for 3.12+.
Not supported
Section titled “Not supported”- LightGBM linear trees and random forests, XGBoost multi-target / vector-leaf models: rejected at load time.
0.1.0 — 2026-06-10
Section titled “0.1.0 — 2026-06-10”Initial release of the package (GitHub only).