Skip to content

feat(objectives): add minimize-depot-travel-time objective#13

Merged
hutchinsp01 merged 3 commits into
masterfrom
feat/prefer-near-depot-objective
Jun 23, 2026
Merged

feat(objectives): add minimize-depot-travel-time objective#13
hutchinsp01 merged 3 commits into
masterfrom
feat/prefer-near-depot-objective

Conversation

@hutchinsp01

Copy link
Copy Markdown
Collaborator

Motivation

Workforce wants a scheduling recipe that keeps each technician working in their local patch — assigning jobs to the vehicle whose depot (shift start) is closest to the job. The existing minimize-cost/minimize-distance objectives minimise total route travel (not per-job depot proximity), and CompactTour clusters a tour's jobs near each other (not near the depot). This adds a dedicated objective for that.

This is the uptick/vrp half of a two-repo change; the Workforce side adds a near-depot recipe that uses it (and bumps the vrp-cli dependency once this releases).

Changes

  • New core feature vrp-core/.../features/depot_proximity.rs — a FeatureObjective scoring each job by the travel duration from its route's depot (route.actor.detail.start) to the nearest of the job's candidate locations (handles Single and Multi). Objective-only; no constraint or state. The DepotPenaltyFn type alias is the seam for a future non-linear penalty (linear/identity today).
  • Two modes via an optional cap:
    • soft (cap = None) — a per-assigned-job penalty, intended as a member of a weighted-sum tier. Degenerate if used standalone (assigning nothing has zero travel).
    • capped "depot radius" (cap = Some(c)) — leaving a job unassigned costs c, while assigning it costs its depot→job travel. Minimising this assigns every job within c of a depot (nearest first) and drops the rest — proximity-gated assignment, safe as a dominant lexicographic tier (the empty solution costs N*c, never wins). Mirrors minimize_unassigned's handling of unassigned/ignored jobs.
  • Pragmatic format: new Objective::MinimizeDepotTravelTime { cap: Option<Float> }{"type":"minimize-depot-travel-time"} or {"type":"minimize-depot-travel-time","cap":1200.0}. Wired through goal_reader.rs.
  • Version bumped to 1.25.3 (+ rosomaxa 0.9.3, lockstep) and CHANGELOG updated, so Workforce can depend on the published build.

Verification

  • cargo test -p vrp-core depot_proximity — 11 unit tests (estimate at route vs activity context, nearest-of-multiple-places, Multi jobs, no-location → 0, capped reward/penalty, capped fitness penalises unassigned).
  • cargo test -p vrp-pragmatic minimize_depot_travel_time — round-trip parse (with/without cap) + goal-build.
  • cargo fmt / clippy clean on the changed files; full workspace cargo check passes.

🤖 Generated with Claude Code

hutchinsp01 and others added 3 commits June 22, 2026 12:06
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prefer assigning each job to the vehicle whose depot (shift start) is
closest to it by travel duration. Two modes via an optional `cap`:

- soft (cap omitted): a per-assigned-job penalty intended for use inside a
  weighted-sum tier; degenerate if used standalone (assigning nothing wins).
- capped "depot radius" (cap set): leaving a job unassigned costs `cap`, so
  the objective assigns jobs within the radius (nearest first) and drops the
  rest. Safe as a dominant tier — the empty solution costs N*cap, never wins.

Exposed in the pragmatic format as
{"type":"minimize-depot-travel-time","cap"?:<seconds>}. Objective-only (no
constraint/state).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vrp-core unit tests covering soft and capped ("depot radius") modes, plus a
vrp-pragmatic round-trip + goal-build test for the
{"type":"minimize-depot-travel-time","cap"?:<seconds>} format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hutchinsp01 hutchinsp01 force-pushed the feat/prefer-near-depot-objective branch from 6b461ce to 824ea05 Compare June 22, 2026 02:15

@kraklo kraklo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh I don't think I know enough of the vrp internals to check it off with full confidence, but nothing is jumping out at me and the unit tests seem to give us good confidence

@adamdickinson adamdickinson left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving, not really because I can read the code, but because I'm keen to get it shipped 😄.

@hutchinsp01 hutchinsp01 merged commit 310dbd8 into master Jun 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants