Changelog¶
All notable changes to cmenpy are documented in this file.
The format is based on Keep a Changelog,
and this project uses calendar versioning (YYYYxN): the year, a release
channel (a = alpha, b = beta), and an increment within that channel.
The Unreleased section collects changes targeting the next release. See the
Roadmap for the scope
and ordering of that work.
Unreleased¶
Targeted at 2026b2 (tracked in the roadmap).
Added¶
Added¶
- Numba is now an optional backend. The core install only requires NumPy;
- The
numbacompile option controls whether compilation takes place: - Uncompiled kernels keep their specs (arguments are still auto-cast) and run
cm.prepare(model)reports uncompiled kernels as["<python>"].- Models accept a
prepareconstructor option: `MyOptimizer(numba=True, - Kernels cast array-protocol arguments **automatically, even when declared
-
from cmenpy import prangebinds numba'sprangewhen the backend is -
Composable termination criteria in
cmenpy.terminator:MaxEvaluation(withcm.Terminator(nfe=...)as an alias),MaxEpoch,MaxPatience,MaxTime,EpochStagnation,TargetFitness,SpreadFitnessandUserInterrupt, combined with&(AND) and|(OR) — issue #33. - Opt-in run history in
cmenpy.history: in-memory, JSONL, CSV and NPZ sinks with summary and full-snapshot levels, retention options, and a schema-versioned reader — issue #35. - Domain decoders and heterogeneous search spaces in
cmenpy.decoderandcmenpy.space(floats, integers, strings, categories, sequences, binaries, booleans) with both thecm.Space[...]standard form and thecm.Space(float=..., string=...)sugar form — issue #34. - Multiobjective optimization: vector fitness columns, per-objective
sense, Pareto dominance utilities, fronts and crowding distance, and an NSGA-II example — issue #36. - Per-dimension search-space helpers:
Bounds.lows,Bounds.ups,Bounds.sample()andBounds.clip()— issue #37. - Benchmark companions: reference test functions from
opfunu-core(500+ numerical functions) and engineering problems fromenoppy-coreare now used across the examples, the test suite and the new Test functions guide page; install them with the newbenchmarksextra — issue #39. example/engineering_demo.py: a constrained engineering problem solved withenoppy-core.- Roadmap documentation page.
Changed¶
- The changelog has a single source of truth (
CHANGELOG.md); the docs site includes it via a snippet instead of keeping a second copy that can drift. - Every optimizer example solves an
opfunu-corebenchmark function instead of an inline hand-rolled objective.
Removed¶
- The population agent types (
BaseAgent,ImmutableAgent,MutableAgent) and theAgentTemplateprotocol. Read an individual through the array-first surface —pop.access[pop.best](orpop.X/pop.F) for the solution and fitness — and re-score a row withpop.compute[pop.best] << solution, which writes the row and charges one evaluation, the same path the oldMutableAgent.solutionsetter took. - Unused surface around that array-first path:
TargetFunction.apply_axis()(the buffer already does the same row-wise scoring inline) andTargetFunction.f(an alias ofevaluate);KernelMask.passive;StreamOperator.rowsandStreamOperator.columns;DefaultGenerator.seed; theSpecTypetyping alias (it was justtyping.Any); and the__operator_module__marker attribute, which nothing read —@cm.modulestill keeps the class identity and installs its constants. - Positional field values on
cm.declare: it was accepted and ignored, so@cm.declare(...)is now written@cm.declare(). Declare fields with keyword arguments, as before.
Fixed¶
- The NFE counter now charges one evaluation per individual scored for
every way
pop.computeselects rows. A NumPy row index — whatpop.best,pop.worstandpop.sortreturn — used to be treated as a block: it spentndimevaluations and then called the objective with a single solution, which raised for vectorized targets.pop.insert,MutableAgent.solutionwrites and the documentedpop.compute[pop.best] << solutionrecipe are affected by the same dispatch and are fixed by it. - Row-wise scoring no longer raises when a mask selects nothing (an emptied
roster, or no row passing
cm.is_best); such a selection now spends zero evaluations instead of failing insidenp.apply_along_axis. pop.computealso accepts index iterators (pop.compute[~pop]) and the buffer'sKernelMask(pop.compute[ctx.buff.mask]) as selectors.TargetFunction.evaluate_matrixrejects a bare solution vector with a clear message instead of spendingndimevaluations on it; a single solution is scored withTargetFunction.evaluate, which now dispatches a vectorized target as a one-row block.
2026b1 - unreleased¶
Added¶
-
cm.cast(value, dtype=None, layout="A")is the explicit way to turn a -
@cm.moduleturns a class into a reusable Operator Module (a Ruby-style mixin). It marks the class, materializes itscm.Constantannotations and keeps it usable as a plain base:@cm.template class GA(Selection)inherits kernels, helper methods and fields fromSelection. Name collisions resolve through the MRO, andcm.prepare(model)now reports kernels inherited from an Operator Module (compilation walkscls.__mro__instead ofvars(cls)). cm.Constant[type, value]declares a fixed, read-only field for@cm.templatemodels and@cm.moduleOperator Modules. The value is checked at declaration, exposed through the class as a read-only descriptor (self.name/Cls.name), and is never constructor-bound — passing it to the model call raisesTypeError. Constants flow into every implementing model via normal inheritance, so they work identically on a template and on an Operator Module.
Documentation¶
- Guides reorganized into topic sections — Models, Population, Target functions and Numba kernels — each with per-category pages; all published URLs are preserved.
- API reference restructured into Classes, Functions and Modules.
2026b0 - 2026-10-14¶
A decent and civilized version, compatible with GNU GPLv3.
Added¶
- Numba decorators accept parameter annotations (
"Array[float, 2]","Scalar[float]", and mypy-cleanAnnotated[..., cm.Array[...]]), in addition to the positionalcm.Array/cm.Scalarmarkers. cm.precompile(and thecm.jitalias) expose thenumba.njitoptionsfastmathandparallel; other numba options are forwarded as keywords.cm.vectorizeandcm.reducealso acceptfastmath=Trueandparallel=True(parallelmaps to numba'starget="parallel").- Decorators return a deferred
_Kernel; kernels compile on first use (or viacm.prepare). A@cm.templatemodel configuresparallel,fastmathandcacheat instantiation and they propagate to its kernels. cm.best_index/cm.worst_indexsense-aware selectors incmenpy.functools.- Vectorized targets score a whole
(pop, ndim)block in one call (cmenpy.target.vectorized_target).
Changed¶
cm.jitis renamed tocm.precompile(both usenumba.njit);cm.jitremains as a deprecated alias that emits aDeprecationWarning.cm.guvectorizeis renamed tocm.reduce(generalized ufunc). The layout is inferred from typed annotations (Array[float, 'm,n'], last parameter is the output);cm.Contract[[inputs...], output]remains as the explicit signature marker.
Removed¶
cm.parallel; usecm.precompile(parallel=True)standalone, or a model instantiated withparallel=Truefor kernels markedparallel=True.
Documentation¶
- MkDocs site with guides and a full API reference, plus the "Build a custom model" tutorial.
2026a0 - 2026-08-05¶
Added¶
- First public version ("2026"): decorator-driven model declaration, vectorized population buffers and the basic engine structure, licensed under GNU GPLv3.
[0.0.0]¶
Added¶
- Experimental test version.
- Modeled by decorators.
- Implementation of basic and primitive structure.
- Population vectorization to leverage SIMD.