Skip to content
Epic Software Labs
← All work

Supply chain / operations planning

Global electronics & healthcare manufacturer

Built a decision-support engine that, per SKU per planning month, recommends how much of a plant’s output ships to each regional distribution center to meet demand at lowest total landed cost — as a transparent, auditable linear program a planner can trust and override.

Role
Software development partner
Stage
Enterprise
Sector
Supply chain / operations planning
One large machined block feeding through a splitter into five smaller blocks of proportioned sizes — one supply divided across many destinations.

Outcomes

Globally-optimal, explainable solver
LPGlobally-optimal, explainable solver
REST endpoints across 8 routers
~79REST endpoints across 8 routers
Per constraint — additive by design
1-fnPer constraint — additive by design
Cross-check for line-by-line validation
ExcelCross-check for line-by-line validation

Context

Planners were positioning inventory across distribution centers by spreadsheet, and a large share of shipments were ending up 'wrong-node' — one DC long-hauling to another region’s customers. Most of that wasn’t bad decision-making; it was forced by where stock happened to sit. The fix is better positioning up front, which is exactly what an allocation model can drive.

The problem

Deliver recommendations the business will actually trust: every number traceable to a named constraint, the model always feasible (a supply gap has to surface as a flagged shortage, never an 'infeasible' error), and every line validatable against the incumbent spreadsheet process before anyone relies on it.

  1. 01

    Modeled the allocation as a transparent linear program

    Framed the classic transportation-problem-with-soft-demand as a continuous LP in Pyomo, solved to guaranteed global optimality by the HiGHS solver — an exact, explainable optimizer rather than a black box.

  2. 02

    Encoded the business logic as a penalty ladder

    Soft constraints via penalized slack variables, ordered by economic priority: clear backlog → meet demand → fill safety stock → respect max-stock → pick the cheapest lane → never over-ship. The penalty order is the business logic, and every penalty is tunable per run.

  3. 03

    Split demand by where it actually is

    A disaggregation step that splits the regional forecast by ship-to region (where demand lives), not ship-from history (which DC happened to fulfil it), with a documented fallback ladder that provably sums back to the original forecast.

  4. 04

    Decoupled the solver core from the web and database layers

    Typed dataclass contracts → Pyomo model → stateless solve, with one function per constraint so new constraints are purely additive. The solver is trivially unit-testable and the optimization engine is swappable via a single setting.

  5. 05

    Built a BA-validation console and spreadsheet cross-check

    A Streamlit console plus a cross-check endpoint that runs the live solver on the exact inputs an analyst’s spreadsheet used, so the engine could be validated SKU-by-SKU against the existing Excel process before adoption.

  6. 06

    Made every run reproducible and auditable

    Versioned, timestamped runs (same inputs → same output) with severity-tagged exception flags, so a recommendation can always be explained and re-derived after the fact.

The Maverick moment: winning trust from the spreadsheet

The hard part of decision-support isn’t the maths — it’s getting planners to trust a new engine over the spreadsheet they’ve run for years. Instead of asking them to, we built a cross-check that runs the live solver on the exact inputs their spreadsheet used and returns a per-SKU diff of both the demand-split step and the allocation step. The engine could be proven apples-to-apples against the incumbent process, one SKU at a time, on their own numbers — so adoption became a matter of evidence, not faith.

Takeaway

For decision-support that replaces human judgment, being validatable against the old way matters more than being clever.

Trade-offs

Every architecture is a set of things you chose not to have. These are the ones that mattered here.

  1. Transparent LP over a black-box model

    Chose an exact, explainable optimizer so every recommendation is defensible to planners and auditors — and put the engineering investment into architecture and validation tooling, not model exotica.

  2. Recommend, don’t execute

    No write path into SAP/WMS — a planner reviews and approves before anything ships. Keeping a human in the loop is what made the engine adoptable rather than threatening.

Stack

  • Python
  • Pyomo
  • HiGHS
  • FastAPI
  • PostgreSQL
  • SQLAlchemy (async)
  • Alembic
  • Streamlit
  • Docker

Capabilities applied

What’s next

Extensible toward container and vessel capacity (turning the LP into a MILP), warehouse-space and labor constraints — each additive under the one-function-per-constraint design, with no change to the existing model.