Skip to content

Changelog — heusor (Python)

Before 1.0, a minor version may contain breaking changes; a patch version may not.

0.1.0 — 2026-10-25

First release: a constraint solver for planning and scheduling, driven from Python. Your problem is ordinary dataclasses; your rules are constraint streams of lambdas, compiled once when the problem is built — no Python runs while the solver searches.

Modelling - @problem_fact, @planning_entity, @planning_solution dataclasses. - PlanningVariable (optionally allows_unassigned=True), PlanningListVariable for ordered lists such as routes, PlanningPin. - Shadows on list elements: InverseRelationShadow, PreviousElementShadow, NextElementShadow, IndexShadow, CascadingShadow(fn) (e.g. arrival times). - Field types: int, bool, str, Enum, datetime, date, time, timedelta, fact classes, and list / set of those. - Scores: SimpleScore, HardSoftScore, HardMediumSoftScore.

Constraints - for_each, for_each_including_unassigned, for_each_unique_pair, filter, join, if_exists, if_not_exists, flatten_last. - group_by on one to four keys, with count, sum, min, max, count_distinct; complement; load_balance for fairness. - Joiners: equal, less_than, less_than_or_equal, greater_than, greater_than_or_equal, overlapping. - penalize / reward with a per-match weight. A negative weight is refused (constraint.negative_weight) rather than silently turning a penalty into a reward. - A lambda the compiler cannot translate fails when the problem is built, naming the file, the line and the construct.

Solving and explaining - heusor.solve(…, time_limit=…, step_limit=…, seed=…); step_limit with a seed is reproducible. - cancel=heusor.Cancel() from another thread; on_progress=… callbacks. - heusor.config_for(…) shows the exact configuration a solve would use. - heusor.score(…): the score, each constraint's share, and which objects each constraint's matches involve (indictments, blame). - Every error is a heusor.HeusorError with a stable code.

Platforms: Python ≥ 3.11 (one abi3 wheel per platform): Linux x86-64 (glibc ≥ 2.17), macOS arm64, Windows x86-64 — each built, installed and run in CI, with the seeded determinism scores reproduced on all three. Linux aarch64 is left out of 0.1.0: its wheel was built but never run.

Known limits: see Current limits in the README — no three-way joins, no group_by after a join or after a group_by (except load_balance), lambdas must be defined in a file.