Skip to main content

Hilsha Fish Migration Optimization (HFMO): A Novel Optimization Algorithm Based on Hilsha Fish Migration Pattern

Hilsha Fish Migration Optimization (HFMO) — a phase-scheduled hybrid metaheuristic for continuous, bound-constrained optimization, inspired by the salinity-driven migration of Hilsha (Tenualosa ilisha) between marine and freshwater habitats in the Bay of Bengal.

pip install hfmo
import numpy as np
from hfmo import minimize

result = minimize(lambda x: np.sum(x**2, axis=1), bounds=[(-100, 100)] * 30, seed=0)
print(result.best_f, result.best_x)

License: MIT Python Tests


Contents


What is HFMO

Hilsha exhibit a distinctive anadromous life cycle: they spend most of their life foraging in the marine waters of the Bay of Bengal, then migrate upstream into the Ganges-Brahmaputra-Meghna delta to spawn in freshwater as salinity drops, before returning to sea. HFMO uses this cycle as a template for scheduling a population-based search: a single scalar "salinity" signal, computed from the iteration index, switches the population between four search behaviors over the course of a run — a wide-ranging exploratory phase early on, a directed phase, an intense local-refinement phase, and a periodic diversification phase that resets part of the population.

It is implemented here as a drop-in, scipy.optimize-style optimizer: give it a bound-constrained objective function, get back a best solution and a convergence history.

How it works

HFMO maintains a population of N candidate solutions ("fish") in a D-dimensional search space. Each iteration t, a salinity value

S(t) = |sin(pi * t / T_max)| * exp(-gamma * t / T_max)

determines which of four phases runs:

Condition Phase Behavior
S(t) > 0.7 Marine Global exploration via Lévy-flight steps
0.3 < S(t) <= 0.7 Migration Directed search: a PSO-style velocity update
S(t) <= 0.3 Spawning Local exploitation: Gaussian mutation of above-median individuals
S(t) > S(t-1) Return Diversification: the worst individuals are replaced, layered independently on top of whichever of the three phases above also ran

Because t only ever ranges over [1, T_max], sin(pi t / T_max) stays non-negative throughout a run, so S(t) traces exactly one rise and fall — not a repeating oscillation. Concretely, for the defaults (T_max=500, gamma=0.2): the run opens in the spawning phase (S(1) ≈ 0.006), rises through migration by around iteration 50, reaches marine by around iteration 133, peaks near the run's midpoint, falls back through migration by around iteration 351 and back to spawning by around iteration 442. The return phase, triggered whenever S(t) > S(t-1), fires on every one of those rising iterations — roughly the first half of the run — and never during the falling half. Exact transition points depend on gamma and T_max; the shape does not.

Important characteristic, stated plainly: S(t) is a deterministic function of the iteration index alone. It does not read population diversity, fitness stagnation, or any other property of the search state. Every run — on every problem, at every population size — executes the identical phase sequence at the identical iteration indices, single-hump shape included. This is closer to a fixed annealing-style schedule than to a state-dependent controller, and you should not expect the schedule to adapt to how a particular run is actually going. See Known limitations.

Attribution — what's actually novel here

Each phase update is, on its own, an established mechanism from the metaheuristics literature. HFMO's contribution is the specific composition of these mechanisms under the salinity schedule above, not the mechanisms themselves — and we think a package like this should say so plainly rather than let a biological metaphor imply more originality than there is.

Phase Mechanism Origin
Marine Lévy-flight step via Mantegna's algorithm Mantegna (1994); used in Cuckoo Search, Yang & Deb (2009)
Migration PSO velocity update with linearly-decaying inertia Kennedy & Eberhart (1995); Shi & Eberhart (1998)
Migration (social term) Fitness-weighted average over all personal bests, not just the global best Fully Informed Particle Swarm, Mendes, Kennedy & Neves (2004)
Spawning Gaussian local-search mutation scaled by distance to the incumbent best Bare-bones PSO, Kennedy (2003)
Return Elite-guided reinitialization of the worst individuals Common to scout-bee and migration-based algorithms generally

Installation

# From PyPI
pip install hfmo

# Or directly from GitHub
pip install git+https://github.com/razibmustafiz/hfmo-optimizer.git

# Or, for local development
git clone https://github.com/razibmustafiz/hfmo-optimizer.git
cd hfmo-optimizer
pip install -e ".[dev,examples]"

Requires Python 3.8+, NumPy, and SciPy.

Usage

import numpy as np
from hfmo import minimize

def rastrigin(x: np.ndarray) -> np.ndarray:
    """x: shape (n_particles, D) -> shape (n_particles,)"""
    A = 10
    return A * x.shape[1] + np.sum(x**2 - A * np.cos(2 * np.pi * x), axis=1)

result = minimize(
    rastrigin,
    bounds=[(-5.12, 5.12)] * 10,   # one (low, high) pair per dimension, as in scipy.optimize
    n_particles=60,
    n_iterations=500,
    seed=0,                         # always set a seed for reproducible results
)

print(result.best_f)        # best fitness found
print(result.best_x)        # the corresponding solution
print(result.history)       # best-so-far fitness at each iteration
print(result.n_evaluations) # total objective-function calls used

Use the HFMO class directly when you need more control — inspecting intermediate state, running in chunks with a custom stopping rule, or objective functions that only accept a single candidate at a time:

from hfmo import HFMO

optimizer = HFMO(rastrigin, bounds=[(-5.12, 5.12)] * 10, n_particles=60, n_iterations=500, seed=0)
result = optimizer.optimize()

# Run more iterations later -- continues the same schedule, doesn't restart it
more = optimizer.optimize(n_iterations=100)

See examples/ for complete, runnable scripts:

Using HFMO in an optimization pipeline

HFMO's public API is deliberately shaped like scipy.optimize.minimize / scipy.optimize.differential_evolution, so it drops into the same place in a pipeline:

  • Hyperparameter tuning — wrap a cross-validated model-scoring function as the objective and search a bounded hyperparameter space (see examples/02_pipeline_integration.py).
  • Simulation calibration — minimize the discrepancy between a simulator's output and observed data over its input parameters.
  • As one candidate among several — since HFMOResult exposes n_evaluations, you can run HFMO alongside other optimizers (scipy's, or your own) under an explicitly matched evaluation budget and compare fairly, rather than by iteration count or wall-clock time alone (see examples/03_compare_with_scipy.py).
  • Long-running or checkpointed searches — call HFMO.optimize(n_iterations=...) repeatedly (it continues the schedule rather than restarting it) to interleave the search with logging, checkpointing, or an early-stopping rule based on optimizer.G_fitness (see examples/04_convergence_plot.py).

If your objective only accepts one candidate at a time rather than a batch, pass vectorized=False and HFMO will call it once per candidate internally.

API reference

hfmo.minimize(func, bounds, dim=None, n_particles=50, n_iterations=500, vectorized=True, seed=None, **kwargs) -> HFMOResult

One-shot convenience function. Constructs an HFMO instance and calls .optimize(). Any additional keyword arguments (w_start, c1, beta, ...) are forwarded to HFMO.__init__.

hfmo.HFMO(func, bounds, dim=None, n_particles=50, n_iterations=500, ...)

The optimizer class. Key methods:

  • optimize(n_iterations=None) -> HFMOResult — run (further) iterations.
  • step(t) -> float — run a single iteration t and return the salinity S(t); for pipelines that need to interleave HFMO with other work at the granularity of a single iteration.

Key attributes after construction or during a run: X (population positions), fitness, G / G_fitness (global best and its fitness), n_evaluations.

hfmo.HFMOResult

A dataclass: best_x, best_f, history (best-so-far fitness per iteration, as a NumPy array), n_evaluations, n_iterations.

bounds

Either convention works:

bounds=[(-5, 5)] * D                       # scipy-style: one (low, high) pair per dimension
bounds=(np.full(D, -5), np.full(D, 5))     # (low_array, high_array)
bounds=(-5, 5); dim=D                      # scalar low/high, dim required

Parameters

Parameter Default Description
n_particles 50 Population size
n_iterations 500 Iterations to run in optimize()
w_start, w_end 0.9, 0.4 Inertia weight at the start/end of the run (migration phase)
c1, c2 1.7, 1.7 Cognitive / social coefficients (migration phase)
s_min 0.1 Salinity threshold governing the spawning-phase mutation scale
beta 1.5 Lévy-flight stability exponent, in (1, 2]
alpha_scale 0.01 Scales the Lévy step relative to the search-space width
eta 0.1 Scales the return-phase reinitialization perturbation
gamma 0.2 Decay rate of the salinity schedule, in [0, 0.5]
epsilon 1e-6 Prevents division by zero when fitness-weighting personal bests
vectorized True Set False if func takes one candidate at a time
seed None Int or numpy.random.Generator, for reproducibility

Benchmark results

HFMO was evaluated in the study accompanying this repository on two problem classes:

  • QAPLIB (ten chr instances, chr12a–chr20b, via a random-key encoding — see the manuscript for how a continuous optimizer is mapped onto a permutation problem): HFMO obtained the best mean solution quality of five compared metaheuristics (HFMO, CSMA, FSS, HHO, AFMO). In the one comparison in that study run under a matched iteration budget — HFMO against Fish School Search, both at 10,000 iterations — HFMO was better on solution quality, optimality gap, and runtime simultaneously.
  • CEC-2015 (five composition/hybrid functions, F10–F14, D=10, 20 runs): HFMO ranked mid-table among seven compared algorithms (HFMO, AFMO, MSA, HHO, DAIW-PSO, FSS, CSMA), leading on none of the five functions.

We are not aware of any evaluation in which HFMO led on both problem classes simultaneously, and we don't present it as state-of-the-art on either. The manuscript describing this evaluation in full — including instance-by-instance results, the encoding used for QAPLIB, and the evaluation protocol's own limitations — is in preparation; this README will be updated with a link once it is available.

Known limitations

  • The salinity schedule is not adaptive. As described above, S(t) depends only on the iteration index. Making it responsive to a measured population-diversity or stagnation statistic is a natural next step and is not yet implemented.
  • No component of the algorithm is novel in isolation — see Attribution. Treat HFMO as a particular scheduling strategy over established operators, evaluated empirically, rather than as a new search operator in its own right.
  • The closest related algorithm is CSMA (Calico Salmon Migration Algorithm, Min et al. 2023), another four-stage migratory-fish metaheuristic with an adaptive population-energy operator. A rigorous component-level comparison between the two has not yet been published.
  • This package implements the continuous optimizer only. Applying it to combinatorial problems (as in the QAPLIB evaluation above) requires an encoding step — a random-key / argsort decoding was used in that study — which is not included here, since it is specific to the target problem rather than part of the core algorithm.
  • No claim of general superiority is made or implied, consistent with the No Free Lunch theorems for optimization (Wolpert & Macready, 1997): the results above describe two specific problem families, not optimization in general.

Development

git clone https://github.com/razibmustafiz/hfmo-optimizer.git
cd hfmo-optimizer
pip install -e ".[dev]"
pytest

Citation

See CITATION.cff. The associated manuscript is in preparation; this file will be updated with a DOI once it is published.

License

MIT © 2026 Mohammad Razib Mustafiz

Metadata

Release files for hfmo 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hfmo 0.1.0
File Size Uploaded
hfmo-0.1.0.tar.gz 21.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hfmo 0.1.0
File Interpreter ABI Platform
hfmo-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 36.6 kB

Release files / hfmo-0.1.0.tar.gz

Download URL hfmo-0.1.0.tar.gz
Size 21.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5379bb634ec3de5d5f8c3d6b97493e84195303b464dfa291ed50736a0284565e
BLAKE2b-256 checksum
How to use checksums
d9acc8a16728edf170c7ba30944cd77c1a30973aa45a0af14f81921f1b50518d
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 Sep 12, 2026.

Transparency log

Release files / hfmo-0.1.0-py3-none-any.whl

Download URL hfmo-0.1.0-py3-none-any.whl
Size 15.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
24fcb44898e18b0796abedb4270a94c315d853d83259acb41dd5e16fd8df3d8a
BLAKE2b-256 checksum
How to use checksums
cd457ba5cf86c401342dd457ca8e227fd9ef48e64ac51a90882f06ba0351a14c
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 Sep 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page