Skip to content

enislucas/lumenops

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LumenOps — Field Service Control Tower for Smart Street Lighting

An operations-research portfolio project: a multi-depot technician routing model (MILP + ALNS metaheuristic) wrapped in a live, interactive dispatch control tower — built around four field-service problems that are documented in industry and research but not solved by commercial dispatch tools.

▶ Live demo: enislucas.github.io/lumenops — no install, runs entirely in your browser. Model document: docs/model.pdf.

Case study, fictitious data. The scenario is modeled on how city-scale connected street-lighting networks are operated: luminaires report their own faults, and maintenance crews must visit and fix them under municipal SLAs. Every number in this repository is synthetic, generated by a seeded script; all asset, brand, and crew names are fictional. No affiliation with any lighting-systems vendor or logistics operator is implied.

Try it

git clone <this repo>
cd lumenops/app
python -m http.server 8000     # any static server works
# open http://localhost:8000

Double-clicking app/index.html also works (the optimizer then runs on the main thread instead of a Web Worker). No build step, no dependencies, no backend — the entire optimizer runs in your browser.

Two-minute demo script

  1. The app optimizes the day on load: 6 crews, 68 open work orders, 3 depots across Noord-Brabant. Watch the convergence chart (Optimizer tab) — you are watching an Adaptive Large Neighborhood Search escape local optima in real time.
  2. Click any bar on the dispatch board (or a map marker) → "Why this crew?" — the plan defends itself: marginal cost of the current slot, every alternative crew priced, infeasible crews ruled out with the binding constraint.
  3. Press and let the day run at ×120. At 09:45 a traffic jam hits; at 10:20 a critical fault (exposed wiring) is reported; at 12:00 a crew's van breaks down.
  4. Each disruption offers Re-optimize — the proposal shows KPI deltas and a plan-nervousness score with a churn diff (what moved, what's new). Accept it or reject it like a dispatcher would. Raise the plan stability slider and re-run to see churn priced against travel time.
  5. Switch Day to Normal operations (45 orders — slack exists) and toggle opportunistic preventive maintenance: crews with slack pick up nearby high-failure-risk assets (hatched bars), only where it costs zero SLA impact. On the overloaded backlog day the optimizer correctly refuses to do preventive work — capacity goes to the fire-fight. That contrast is the point.
  6. Snapshot plans under different weights (Scenarios tab) and compare trade-offs side by side.

Why this project is different

Most routing demos stop at "shortest route found." This one is built around four gaps that practitioners and the literature document as open — each is a first-class feature, with sources in docs/industry-context.md:

Documented gap What LumenOps does
Plan nervousness — dispatchers reject re-plans that churn the schedule (UPS ORION pilots saw ~20–30% driver rejection; "consistent VRP" is a research field, not a product feature) Churn is an objective term with a UI dial; every re-plan gets a nervousness score, a move-by-move diff, and an accept/reject workflow
Explainability — "why did job X go to crew Y?" is unanswerable in commercial tools; first academic framework only appeared in 2024 (RouteExplainer, PAKDD) Decision-level counterfactuals: every alternative crew priced or ruled out by its binding constraint, rendered in dispatcher language
Opportunistic preventive maintenance — predictive modules raise separate work orders → a second truck roll, instead of using slack in today's routes Assets above a failure-risk threshold are inserted into route slack, guarded to add zero lateness to real jobs
Graceful degradation — hard SLA constraints make optimizers return "infeasible" exactly on overloaded days Critical attendance is hard, timing is soft and graded; the KPI strip forecasts SLA breaches hours ahead; a hard-SLA toggle shows the trade-off

The operations research

The model is a multi-depot VRP with time windows, skills, crew-size requirements, soft SLAs and mandatory critical coverage. It started as a university proposal, was reviewed by a professor, and was then corrected and extended — the full formulation and a point-by-point changelog mapping every reviewer annotation to its fix is in docs/model.md, with a print-ready version in docs/model.pdf. Highlights:

  • Coverage was missing from the original objective — with ≤ 1 visit constraints and a pure travel-time objective, the optimum is to serve nothing. Fixed with a priority-scaled unserved-job penalty (making it a team-orienteering variant).
  • Critical jobs: hard attendance (Σₖ yᵢₖ = 1), soft graded lateness — the reviewer's suggested fix, adopted and defended (hard deadlines ⇒ infeasibility exactly when the tool is needed most).
  • The nonlinear max(0, ·) lateness was linearized; big-M got a concrete tight definition; the declared-but-unused crew_required and skills became an eligibility matrix; shift-start constraints and depot-departure relaxation were added.

Two solvers, one model:

model/milp_reference.py app/js/solver.js
Method Exact MILP (PuLP / CBC) ALNS: regret-2 construction; random/worst/Shaw removal; adaptive operator weights; simulated-annealing acceptance
Role Ground truth on small instances (~14 jobs, 3 crews) Full 68-job day in seconds, in the browser, deterministic under a fixed seed
Validation Independent feasibility checker re-derives all times Test suite (app/js/solver_test.js); on the reference instance the heuristic matches the CBC-proven optimum exactly (2335.1 vs 2335.1, ratio 1.000)

Repository layout

app/          the control tower (vanilla JS, no build step; Leaflet vendored)
  js/solver.js        ALNS optimizer — pure library, runs in browser & Node
  js/solver_test.js   test suite (node app/js/solver_test.js)
data/         seeded synthetic dataset generator + CSVs (data dictionary in data/README.md)
model/        exact MILP reference implementation + solved example
docs/model.md            corrected formulation + reviewer-annotation changelog
docs/industry-context.md  the four gaps, with sources; dataset realism notes
docs/contracts.md        internal interface contracts between components

Skills demonstrated

MILP modeling and the discipline to fix a flawed formulation · metaheuristic design (ALNS) · model validation against an exact baseline · synthetic-data engineering with domain grounding · decision-support UX (explainability, stability, human-in-the-loop replanning) · dependency-free front-end engineering (SVG charts, Web Worker with graceful fallback).


Author: Enis Lucas Ziadin. Built as a portfolio project for operations research & AI roles.

About

Field-service control tower + route optimizer for smart street-lighting maintenance. MILP + in-browser ALNS (matches proven optimum), explainable dispatching, plan-stability re-planning, opportunistic preventive maintenance. OR portfolio project - fictitious data.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors