BSO — Binary Snake Optimizer
A sigmoid-binarized adaptation of the Snake Optimizer metaheuristic for feature selection and binary combinatorial optimization.
Note on the name. The bare name
BSOis taken on PyPI by an unrelated package, so this is published as the short formbsopt. The Python import path matches:import bsopt.
Overview
Snake Optimizer (SO) is a population-based metaheuristic proposed by Hashim & Hussien (2022), inspired by snake mating behavior. It splits its population into two cooperating sub-swarms and alternates between exploration and exploitation phases based on a temperature signal and a food-quantity signal — with dedicated "fight," "mate," and "egg-laying" dynamics during exploitation.
bsopt binarizes that search via a sigmoid transfer function,
so the same population dynamics can operate directly on binary
decision vectors — most commonly, "which of N candidate features to
keep." The optimizer itself is fully agnostic to what the mask
represents: it only needs a function that scores a binary vector.
Features
- Pure NumPy core — no heavy dependencies for the optimizer itself.
- Pluggable fitness function — works for feature selection, or any other binary combinatorial problem you can score.
- Reproducible by design — all randomness is drawn from a local,
seeded
numpy.random.Generator; no mutation of global NumPy state. - Optional scikit-learn helper —
bsopt.sklearn_selector.select_featureswraps the optimizer for the common case of wrapper-based feature selection against any sklearn-compatible classifier. - Fully documented algorithm — see
docs/pseudocode.mdfor line-by-line pseudocode and notes on where this implementation deviates from the published continuous algorithm (including a fix for an index-out-of-bounds edge case in the original mating step when the population size is odd). - Tested — unit tests cover the transfer function, convergence behavior, reproducibility, and edge cases; run in CI across Python 3.9–3.12 on every push.
Installation
pip install bsopt
With the optional scikit-learn feature-selection helper:
pip install "bsopt[sklearn]"
Quickstart
import numpy as np
from bsopt import binary_snake_optimizer
def fitness(mask: np.ndarray) -> float:
"""Toy example: minimize the number of selected bits, unless
none are selected (which is disallowed)."""
return mask.sum() if mask.sum() > 0 else len(mask)
result = binary_snake_optimizer(
fitness_fn=fitness,
dim=20,
n_agents=30,
n_iter=50,
seed=42,
)
print(result.best_mask) # binary array, shape (20,)
print(result.best_fitness) # scalar fitness of best_mask
print(result.history) # best-so-far fitness per iteration
Feature selection with scikit-learn
from sklearn.ensemble import RandomForestClassifier
from bsopt.sklearn_selector import select_features
result = select_features(
estimator=RandomForestClassifier(n_estimators=50, random_state=42),
X=X_train, # DataFrame or array, shape (n_samples, n_features)
y=y_train,
n_agents=30,
n_iter=50,
random_state=42,
)
print(result.selected_features) # list of selected feature names
print(result.mask) # binary mask over all input features
select_features scores each candidate mask by fitting a clone of your
estimator on a held-out split and combining validation error with a
sparsity penalty, so the search favors compact, accurate feature
subsets. See docs/pseudocode.md for the exact
fitness formula and examples/ for a runnable end-to-end
script.
API reference
| Symbol | Description |
|---|---|
bsopt.binary_snake_optimizer(fitness_fn, dim, n_agents=30, n_iter=50, lb=-3.0, ub=3.0, threshold=0.25, threshold2=0.6, c1=0.5, c2=0.05, c3=2.0, seed=None, verbose=False) |
Core optimizer. Returns a BSOResult. |
bsopt.BSOResult |
Dataclass with best_mask, best_fitness, history. |
bsopt.sigmoid, bsopt.binarize |
The transfer function and stochastic binarization step, exposed for reuse/testing. |
bsopt.sklearn_selector.select_features(...) |
Convenience wrapper for sklearn-based feature selection. Requires the sklearn extra. Returns a FeatureSelectionResult. |
Every public function has a complete NumPy/Google-style docstring —
see help(binary_snake_optimizer) or browse
src/bsopt/core.py.
Algorithm
The population is split into two equal sub-swarms (male/female). Each iteration:
- A temperature term
Tempand food-quantity termQare computed for the current iteration. - If
Qis below a threshold, snakes explore: random walks around a randomly chosen leader in their own sub-swarm. - Otherwise, snakes exploit:
- If
Tempis high ("hot"), snakes move directly toward the current best-known position ("food"). - If
Tempis low ("cold"), snakes either fight (move toward the opposite sub-swarm's best individual) or mate (move toward a paired individual in the opposite sub-swarm), which can also trigger an egg-laying reset of the worst individual in each sub-swarm.
- If
- Every proposed position is clipped to bounds, passed through a
sigmoid transfer function to get an inclusion probability per
bit, stochastically binarized, scored with
fitness_fn, and greedily accepted if it improves on the snake's current fitness.
Full pseudocode, equation references back to the original paper, and a
list of every place this implementation deviates from it (with
justification) live in docs/pseudocode.md.
Development
git clone https://github.com/InquietoPartho/bsopt
cd bsopt
pip install -e ".[dev,sklearn]"
pytest -v
Continuous integration runs the test suite on Python 3.9–3.12 for
every push and pull request (see .github/workflows/ci.yml).
Releases are published to PyPI automatically via
trusted publishing when a
GitHub Release is cut (see .github/workflows/publish.yml).
Contributions, issues, and feature requests are welcome — please open an issue or a pull request.
Citation
If you use this package in academic work, please cite the original Snake Optimizer paper:
@article{hashim2022snake,
title = {Snake Optimizer: A novel meta-heuristic optimization algorithm},
author = {Hashim, Fatma A. and Hussien, Abdelazim G.},
journal = {Knowledge-Based Systems},
year = {2022},
doi = {10.1016/j.knosys.2022.108320}
}
and, if useful, this package:
@software{bsopt,
title = {bsopt: A Python implementation of the Binary Snake Optimizer},
author = {Roy Partho, Pijush Kanti},
year = {2026},
url = {https://github.com/InquietoPartho/bsopt}
}
License
Released under the MIT License. This is an independent reimplementation of a published algorithm — the algorithm itself is not owned by this package, but please credit the original authors' work (linked above) appropriately, and check the license of the original MATLAB reference code if you redistribute code derived from it directly.
Release files for bsopt 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bsopt-0.1.0.tar.gz | 13.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bsopt-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.7 kB
Release files / bsopt-0.1.0.tar.gz
| Download URL | bsopt-0.1.0.tar.gz |
|---|---|
| Size | 13.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e905888a472c6776a848109c3e5fa299bda9c4aaa8785018b4b9f082e33f7159
|
|
BLAKE2b-256 checksum How to use checksums |
154974662431eec3f969be5531e36c1bb9c9e99b42cfc758b64781135babaa42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.
Transparency logRelease files / bsopt-0.1.0-py3-none-any.whl
| Download URL | bsopt-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c9313eeae8458fdad087da4098dfb13db87e208ecb7a33b2468d713a53f28bad
|
|
BLAKE2b-256 checksum How to use checksums |
5341cc565bb07e85f2eb125c58dff78dad208ad8bf5dafa79ef30cb090fa08db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.
Transparency log