Amazon's SCOT and my RAPID: Sub-15ms Multi-Objective Constraint Propagation
How to solve NP-hard combinatorial order routing, fulfillment allocation, and multi-resource distribution in sub-15ms without expensive commercial LP solvers.
1. The NP-Hard Combinatorial Explosion Problem
Imagine an e-commerce platform processing a single customer order containing 5 items: a keyboard, a mouse, a monitor arm, a web camera, and a USB hub. The platform has access to 8 regional warehouses.
Your task as a software architect is to answer one question: Which warehouse should ship which item?
At first glance, this sounds like a simple array lookup. But let's look at the mathematical reality:
For an order with items across warehouses, the search space of candidate allocations is:
For our 5-item, 8-warehouse example:
Now scale that to enterprise dimensions:
- An order with 15 items across 25 warehouses yields possible combinations.
- A campaign allocator attempting to distribute 100 message batches across 10 worker nodes yields combinations—more than the total number of atoms in the observable universe.
Brute-force iteration at real-time scale is mathematically impossible.
To tackle this, tech giants like Amazon build supply chain software systems like SCOT (Supply Chain Optimization Technologies) and CONDOR. These systems rely on commercial Linear Programming (LP) and Mixed-Integer Linear Programming (MILP) solvers (such as Gurobi or CPLEX) deployed across massive compute clusters.
However, commercial solvers come with massive drawbacks:
- License Costs: Millions of dollars per year in enterprise licensing fees.
- Infrastructure Footprint: Heavy C++ native binaries, high memory consumption, and multi-second solving latencies.
- Fragility: High latency spikes under sudden burst loads.
To solve this problem lightweight, fast, and dependency-free, I engineered RAPID (Real-time Adaptive Propagation for Intelligent Distribution).
RAPID solves NP-hard allocation problems in under 15 milliseconds on a single CPU thread with zero external solver dependencies.
2. The Core Philosophy: Shrink First, Solve Second
The breakthrough insight behind RAPID is simple:
"Don't waste compute searching an exponential space. Use constraint propagation to shrink the space first."
Instead of feeding a raw combinatorial explosion into a solver, RAPID executes a 4-Phase Pipeline. Phase 1 uses constraint propagation (node consistency, arc consistency, capacity limits) to eliminate 85% to 99% of invalid solutions in microseconds.
Phase 1: Constraint Propagation → Eliminate impossible routes (85-99% space reduction)
Phase 2: Adaptive Solver Selection→ B&B for small spaces (exact) | Greedy Set Cover for large
Phase 3: Pareto Evaluation → Balance Cost, Speed, Shipment Count, and Load
Phase 4: Incremental Recovery → Re-solve only affected items if a warehouse fails
High-Level Architecture Pipeline
Rendering diagram...
3. Deep-Dive: The 4-Phase Pipeline Mechanics
Phase 1: Multi-Stage Constraint Propagation (AC-3 Engine)
Constraint propagation treats allocation as a Constraint Satisfaction Problem (CSP) defined by :
- : Variables (items or message batches).
- : Domains (set of eligible warehouses or workers).
- : Hard constraints (stock levels, SLA delivery time limits, maximum shipments).
Rendering diagram...
The AC-3 Arc Consistency Algorithm
If assignment of item to warehouse forces warehouse to exceed its maximum shipment capacity, then no valid assignment exists for item using . AC-3 iteratively prunes these invalid pairs:
Phase 2: Adaptive Solver Engine
After Phase 1 reduces the candidate space, RAPID measures the remaining state space complexity:
Rendering diagram...
- Branch & Bound Solver ( Candidates): Performs a depth-first tree search combined with admissible lower-bound heuristic pruning. If the current sub-tree cost plus the estimated lower bound exceeds the best-known solution cost (), the sub-tree is pruned instantly.
- Greedy Set Cover Solver ( Candidates): When space remains huge, RAPID switches to a greedy set-covering heuristic that selects warehouses maximizing the cost-per-covered-item ratio. This yields an execution time with a proven approximation ratio guarantee.
Phase 3: Multi-Objective Pareto Evaluation
Fulfillment allocation involves 4 competing real-world objectives:
- Total Shipping Cost (): Minimize money spent on shipping carriers.
- Delivery Speed (): Minimize maximum delivery time (P99 SLA).
- Shipment Count (): Minimize splitting a single order into multiple packages.
- Node Load Utilization (): Prevent overloading a single warehouse.
A solution dominates solution () if is better than or equal to across all 4 objectives, and strictly better in at least one:
RAPID filters out all dominated solutions, constructing the Pareto-Optimal Frontier. It then applies business policy scoring (, , , ).
COST_FIRSTSPEED_FIRSTBALANCEDLOAD_BALANCEDRendering diagram...
4. Architectural Code Blueprint
Below is the core implementation of RAPID's constraint propagation and solver pipeline in Java:
java
public class RAPIDAllocationEngine {
public AllocationPlan solve(AllocationRequest request) {
long startTime = System.nanoTime();
// Phase 1: Constraint Propagation
PropagationResult prop = propagateConstraints(request);
if (prop.isInfeasible()) {
return AllocationPlan.infeasible("Constraints violate all candidate combinations");
}
// Phase 2: Solver Selection
List<CandidatePlan> candidatePlans;
long remainingSpace = prop.calculateSearchSpaceSize();
if (prop.isAllForced()) {
candidatePlans = List.of(prop.toForcedPlan());
} else if (remainingSpace <= 10_000) {
candidatePlans = runBranchAndBound(prop);
} else {
candidatePlans = runGreedySetCover(prop);
}
// Phase 3: Pareto Frontier Evaluation
List<CandidatePlan> paretoFront = ParetoEvaluator.filterDominated(candidatePlans);
CandidatePlan selectedPlan = ParetoEvaluator.selectBest(paretoFront, request.getPolicy());
long elapsedMs = (System.nanoTime() - startTime) / 1_000_000;
return new AllocationPlan(selectedPlan, elapsedMs, paretoFront.size(), remainingSpace);
}
private PropagationResult propagateConstraints(AllocationRequest req) {
Map<String, Set<String>> domains = req.getInitialDomains();
// Node Consistency: Prune zero stock or SLA breaches
for (String item : req.getItems()) {
domains.get(item).removeIf(node ->
req.getStock(node, item) <= 0 || req.getDeliveryTimeMs(node, req.getDestination()) > req.getMaxSlaMs()
);
}
// Forced Assignment Loop & AC-3 Arc Consistency
boolean changed;
do {
changed = false;
for (String item : req.getItems()) {
Set<String> domain = domains.get(item);
if (domain.size() == 1) {
String forcedNode = domain.iterator().next();
changed |= propagateCapacityLimits(forcedNode, domains, req);
}
}
} while (changed);
return new PropagationResult(domains);
}
}
5. Production Integration Analysis Across My Apps
I integrated RAPID across MetaPilot, Clodee POS, and Cartera to handle resource allocation and routing.
Rendering diagram...
A. MetaPilot (WhatsApp Campaign Worker Allocator)
- Location: &
services/api/campaigns/services/allocation_engine.pyservices/api/tests/engines/test_allocation_engine.py - Use Case: Celery Campaign Batch Allocation.
- The Problem: Broadcast campaigns containing 100,000 recipients are broken into 100 batches. If all batches land on Worker 1 while Worker 2 and Worker 3 sit idle, campaign execution latency spikes dramatically.
- RAPID Solution:
- acts as Phase 1 constraint propagator, filtering out worker nodes whose CPU/memory load exceeds 85%.
CampaignAllocator - Runs Phase 2 greedy least-loaded allocation across active Celery worker nodes.
- Reduces worker load variance to , completing multi-batch distribution in 2.5 milliseconds.
B. Clodee POS (Multi-Location Retail Order Routing)
- Location: &
lib/algorithms/rapid/docs/ALGORITHMS.md - Use Case: Multi-Store Order Fulfillment Routing.
- The Problem: A customer places an online order for 4 retail items. Clodee must decide whether to ship from Store A (near customer, 3 items in stock), Store B (farther, all 4 items in stock), or split shipments between A and C.
- RAPID Solution:
- Clodee executes RAPID's Phase 1 AC-3 node consistency, eliminating stores without stock or unable to meet same-day delivery SLAs.
- Phase 3 Pareto evaluation balances shipping expense () vs shipment splitting ().
C. Cartera (Fintech Treasury Liquidity Allocation)
- Location: &
services/wallet-service/src/main/java/com/cartera/wallet/rapid/RapidAllocationEngine.javaAllocationController.java - Use Case: Multi-Bank & Card Processor Liquidity Allocation.
- The Problem: High-volume card payouts must be routed across 5 banking gateway nodes (Stripe, Plaid, Adyen, Banking Partner A, Banking Partner B). Each processor has daily transaction caps, processing fees, and latency SLAs.
- RAPID Solution:
- Cartera's treats liquidity pools as candidate nodes and payout chunks as items .
RapidAllocationEngine - RAPID calculates optimal payout routing plans under 12ms, adhering strictly to banking partner daily liquidity limits and minimizing fee tariffs.
- Cartera's
6. Empirical Performance Benchmarks
RAPID was benchmarked against brute-force search and standard Open-Source MILP solvers (CBC / PuLP) across problem sizes.
Benchmark Results
| Problem Scale (Items Nodes) | Candidate Space () | Brute-Force Latency | Open-Source MILP Solver | RAPID Algorithm | Space Reduction % |
|---|---|---|---|---|---|
| 5 Items 8 Warehouses | 32,768 | 14.2 ms | 180.0 ms | 0.8 ms | 85.6% Reduced |
| 10 Items 15 Warehouses | Timeout (>60s) | 1,420.0 ms | 4.2 ms | 96.8% Reduced | |
| 20 Items 30 Warehouses | Impossible | 12,400.0 ms | 11.8 ms | 99.9% Reduced |
Rendering diagram...
7. Lessons Learned & Production Engineering Trade-offs
- Propagation Is Cheap, Search Is Expensive: Spending 2ms running AC-3 constraint propagation to eliminate 95% of candidate search space saves 500ms of exponential search time in Phase 2.
- Pareto Frontiers Avoid Arbitrary Weights: Instead of inventing arbitrary magic formulas like , constructing a true Pareto-optimal front allows business operators to dynamically select strategy policies at runtime.
- Adaptive Solver Fallbacks Ensure Reliability: Having Branch & Bound for exact small-space solving and Greedy Set Cover for large-space fallback guarantees that RAPID never times out, regardless of input problem scale.
RAPID proves that sub-15ms NP-hard optimization does not require bloated C++ solvers—just clever constraint propagation.