releases
SolverForge 0.14.x: Complemented Cross-Join Groups and Metric-Class Routes
SolverForge 0.14.x publishes direct complemented cross-join grouping, fixes filtered keyed join retention, unifies owner-aware route hooks, and adds route metric classes for Clarke-Wright construction.
SolverForge 0.14.x was the previous core runtime line. It starts with
v0.14.0,
tagged at 27329bd and published on 2026-05-16. The final patch is
v0.14.1,
tagged at 446b35e and published on 2026-05-16. The final 0.14.x crate is available
as solverforge 0.14.1 on
crates.io, with API docs at docs.rs.
The release is a core runtime release, not a CLI scaffold refresh.
At the time of this runtime release, solverforge-cli 2.0.4 scaffolded
solverforge 0.11.1,
solverforge-ui 0.6.5, and solverforge-maps 2.1.4. Direct Cargo projects
and deliberately upgraded generated apps can target the published
solverforge 0.14.1 crate.
What Changed
Direct cross-join groups can be complemented
0.13.1 made direct cross-join grouping public. 0.14.0 completes that path by
letting grouped cross joins continue into complement(...), so a rule can
aggregate joined pairs and still emit default rows for keys with no matches.
type Streams = ConstraintFactory<Plan, HardSoftScore>;
Streams::new()
.for_each(Plan::assignments())
.join((
Streams::new().for_each(Plan::capacities()),
equal_bi(
|assignment: &Assignment| assignment.capacity_id,
|capacity: &Capacity| Some(capacity.id),
),
))
.group_by(
|_assignment: &Assignment, capacity: &Capacity| capacity.id,
sum(|(assignment, _capacity): (&Assignment, &Capacity)| assignment.demand),
)
.complement(
Plan::capacities(),
|capacity: &Capacity| capacity.id,
|_capacity: &Capacity| 0i64,
)
.penalize(hard_weight(|_capacity_id: &usize, used: &i64| {
HardSoftScore::of_hard((*used - 40).max(0))
}))
.named("Capacity overuse");
Use this shape when the business rule is naturally “facts joined to entities, grouped by a target key, with explicit zero rows for uncovered targets.” It avoids the extra projected-row step when the joined pair does not need to be a named retained scoring row.
Filtered keyed joins retain the right sources
The scoring layer now honors filters on both sides of keyed joins and on complement sources. That fixes retained state for these paths:
- filtered streams used as the right side of a keyed cross join
- custom keyed join extractors after a filtered source
- flattened keyed join targets after filtering
- projected joined rows whose left or right source is filtered
Normal .filter(|left, right| ...) application code does not change. The fix
matters because incremental scoring now builds, retracts, and re-inserts only
the rows that still pass their source filters.
Route hooks are unified and owner-aware
List construction no longer has separate Clarke-Wright and k-opt hook names.
Both route constructors consume the same owner-aware route hooks from
#[planning_list_variable]:
#[planning_list_variable(
element_collection = "deliveries",
solution_trait = "solverforge::cvrp::VrpSolution",
distance_meter = "solverforge::cvrp::MatrixDistanceMeter",
intra_distance_meter = "solverforge::cvrp::MatrixIntraDistanceMeter",
route_get_fn = "solverforge::cvrp::get_route",
route_set_fn = "solverforge::cvrp::replace_route",
route_depot_fn = "solverforge::cvrp::depot_for_entity",
route_metric_class_fn = "solverforge::cvrp::route_metric_class",
route_distance_fn = "solverforge::cvrp::route_distance",
route_feasible_fn = "solverforge::cvrp::route_feasible"
)]
pub delivery_order: Vec<usize>;
The facade now re-exports the matching CVRP helpers from
solverforge::cvrp: get_route, replace_route, depot_for_entity,
route_metric_class, route_distance, and route_feasible.
Clarke-Wright savings are evaluated for the owner that supplies the distance and feasibility context, and merged routes remain bound to that scored owner through final assignment. That prevents a route scored under one vehicle’s depot, distance, capacity, or time-window context from being assigned to a different owner just because the route values look feasible elsewhere.
0.14.1 adds route_metric_class_fn for route owners that share depot and
distance behavior. Owners in the same metric class compute Clarke-Wright savings
once per class, but feasibility remains owner-specific through
route_feasible_fn. The stock CVRP helper route_metric_class(...) groups
owners by their backing ProblemData pointer, which fits homogeneous fleets
sharing one matrix while still allowing each owner to reject routes that violate
capacity, time windows, or other route-local rules.
Install And Scaffold Status
For direct Cargo projects:
solverforge = { version = "0.14.1", features = ["serde", "console"] }
If you write custom incremental constraints that need lower-level identities,
the companion workspace crates are also published at the same 0.14.1 line:
solverforge-core = "0.14.1"
For generated apps, confirm the installed CLI target:
solverforge --version
At the time of this release, solverforge-cli 2.0.4 reported:
CLI version: 2.0.4
Scaffold runtime target: SolverForge crate target 0.11.1
Scaffold UI target: solverforge-ui 0.6.5
Scaffold maps target: solverforge-maps 2.1.4
Runtime source: crates.io: solverforge 0.11.1
UI source: crates.io: solverforge-ui 0.6.5
Maps source: crates.io: solverforge-maps 2.1.4
Generated apps created with that CLI start on solverforge 0.11.1. Move a
generated app to solverforge 0.14.1 only when you are deliberately upgrading
that app’s runtime dependency and validating the generated code against the
newer core crate.
Patch History
| Version | Date | Notes |
|---|---|---|
0.14.1 |
2026-05-16 | Adds route_metric_class_fn, re-exports solverforge::cvrp::route_metric_class, groups Clarke-Wright savings by shared route metric class, and preserves owner-specific feasibility within each class. |
0.14.0 |
2026-05-16 | Adds complemented direct cross-join groups, preserves filters through keyed and flattened joins, unifies route hooks for Clarke-Wright and k-opt, and binds Clarke-Wright merges to the scored owner. |
Documentation Changes
At publication, the docs tree was updated for the 0.14.1 runtime surface:
- Constraint Streams shows complemented direct cross-join groups and the filtered joined-source retention contract.
- Collectors documents
complement(...)after direct cross-joingroup_by(...). - Projected Scoring Rows separates projected grouped complements from direct cross-join grouped complements.
- List Variables and List Move Selectors document the unified owner-aware route hooks and optional route metric classes.
- Status & Roadmap separates the published
solverforge 0.14.1runtime from the then-currentsolverforge-cli 2.0.4scaffold target.