Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__pycache__/
*.pyc
.DS_Store
output/
.pytest_cache/
48 changes: 39 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,48 @@
# Smart Delivery Dispatch System

## Team Information
- **Team Name**: [Team Name]
- **Year**: [Year]
- **All-Female Team**: [Yes/No]
- **Team Name**: TOP-G
- **Year**: 2026
- **All-Female Team**: No

## Architecture Overview

#### Describe your approach here. Keep it short and clear.

- What is your dispatch strategy?
- How do you score agents for incoming orders?
- How do you manage SLA deadlines, priority orders, and agent capacity?
- What are the main steps in your pipeline?
Our system implements a **greedy multi-objective dispatch pipeline** designed for high-throughput real-time operations.

- **Dispatch Strategy**: We use a simulation-clock-driven approach that processes order arrivals in 1-minute ticks. Assignments are made using a priority-first greedy selection.
- **Scoring Logic**: Agents are scored for each order based on a weighted linear combination of five factors: **Delivery Time** (distance + prep), **SLA Risk** (urgency based on deadline), **Workload Fairness** (cumulative assignments), **Priority Boost** (weighted multipliers), and **Agent Rating**. The system selects the candidate that minimizes this composite cost.
- **Management**:
- **SLA/Priority**: A min-heap keyed by `(priority, timestamp)` ensures strict tiered processing.
- **Capacity**: A strict concurrency limit of **2 active orders** per agent is enforced via the Agent Registry.
- **Pipeline**:
1. **Ingest**: Orders are loaded into a priority heap upon arrival.
2. **Candidate Generation**: Available agents are filtered by graph connectivity.
3. **Optimization**: Shortest paths are resolved via **Floyd-Warshall** precomputation for O(1) lookups.
4. **Execution**: Atomic state updates move orders from `PENDING` to `DELIVERED`.

**Note:** Please do not change the format or spelling of anything in this README. The fields are extracted using a script, so any changes to the structure or formatting may break the extraction process.

## Issue Resolution Summary

| Issue | Resolution Description |
| :--- | :--- |
| **Issue 1** | Implemented `load_orders` in `src/data_loader.py` with full CSV validation and skip-on-error logic. |
| **Issue 2** | Implemented `load_agents` with rating clamping and graph-location referential integrity checks in `main.py`. |
| **Issue 3** | Built `EnvironmentGraph` in `src/graph.py` supporting Floyd-Warshall precomputation and Dijkstra for routing. |
| **Issue 4** | Created `PriorityOrderQueue` using a min-heap keyed by `(priority, timestamp)` for strict tiered dispatch. |
| **Issue 5** | Developed `AgentRegistry` to track location, workload (max 2), and availability state in O(1). |
| **Issue 6** | Implemented `generate_candidates` in `src/scorer.py` to filter agents by path connectivity and capacity. |
| **Issue 7** | Developed a multi-objective `score_candidates` function using weighted normalization of 5 key factors. |
| **Issue 8** | Added support for tuning objective weights via `constraints.csv` and interactive UI sliders. |
| **Issue 9** | Orchestrated atomic state updates between queue and registry within `Dispatcher._attempt_assignments`. |
| **Issue 10** | Implemented `_complete_delivery` to handle flight removal, agent relocation, and SLA verification. |
| **Issue 11** | Designed `Dispatcher` to auto-retry assignments upon every delivery completion to clear backlogs. |
| **Issue 12** | Integrated Welford's algorithm in `src/metrics.py` for numerically stable online mean tracking. |
| **Issue 13** | Implemented SLA violation tracking and average margin calculation reported by priority tier. |
| **Issue 14** | Added calculation of assignment variance and standard deviation to monitor workload fairness. |
| **Issue 15** | Developed `MetricsCollector.to_json()` for structured exports and a human-readable summary method. |
| **Issue 16** | Robust error handling in `data_loader.py` for missing columns, file errors, and malformed numeric fields. |
| **Issue 17** | Handled disconnected graphs, full agents, and stale deadlines with descriptive logging warnings. |
| **Issue 18** | Achieved sub-millisecond query time via $O(1)$ routing lookups and implemented latency monitoring. |
| **Issue 19** | Optimized processing pipeline to exceed 100 orders/min throughput, tracked via wall-clock time. |
| **Issue 20** | Completed comprehensive documentation of the greedy dispatch strategy and project architecture. |
6 changes: 5 additions & 1 deletion data/raw/constraints.csv
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ default_sla_minutes,50
priority_weight_high,1.5
priority_weight_normal,1.0
priority_weight_low,0.8

weight_delivery_time,0.35
weight_sla_risk,0.30
weight_workload,0.20
weight_priority,0.10
weight_rating,0.05
209 changes: 209 additions & 0 deletions frontend/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// app.js — UI controller, charts, canvas grid

// ── Data (embedded from CSVs) ─────────────────────────────────────────────
const ORDERS_RAW = `O001,2026-05-03 09:00:00,2,3,12,high,45
O002,2026-05-03 09:04:00,5,1,8,normal,50
O003,2026-05-03 09:08:00,1,6,15,high,40
O004,2026-05-03 09:12:00,7,4,10,normal,55
O005,2026-05-03 09:18:00,3,8,6,low,60
O006,2026-05-03 09:22:00,9,2,14,high,42
O007,2026-05-03 09:25:00,4,5,9,normal,52
O008,2026-05-03 09:28:00,6,7,11,low,58
O009,2026-05-03 09:32:00,1,1,7,high,38
O010,2026-05-03 09:35:00,8,3,13,normal,54
O011,2026-05-03 09:38:00,2,9,10,low,62
O012,2026-05-03 09:42:00,5,4,8,high,44
O013,2026-05-03 09:45:00,7,8,12,normal,50
O014,2026-05-03 09:48:00,3,2,6,low,60
O015,2026-05-03 09:52:00,9,6,15,high,40
O016,2026-05-03 09:55:00,1,4,9,normal,53
O017,2026-05-03 09:58:00,6,1,11,low,59
O018,2026-05-03 10:02:00,4,9,7,high,43
O019,2026-05-03 10:05:00,8,5,14,normal,51
O020,2026-05-03 10:08:00,2,7,10,low,61
O021,2026-05-03 10:12:00,5,3,8,high,45
O022,2026-05-03 10:15:00,9,9,13,normal,55
O023,2026-05-03 10:18:00,3,6,6,low,58
O024,2026-05-03 10:22:00,7,2,12,high,41
O025,2026-05-03 10:25:00,1,8,9,normal,52
O026,2026-05-03 10:28:00,6,4,11,low,60
O027,2026-05-03 10:32:00,4,1,7,high,44
O028,2026-05-03 10:35:00,8,7,15,normal,50
O029,2026-05-03 10:38:00,2,5,10,low,62
O030,2026-05-03 10:42:00,9,3,8,high,42
O031,2026-05-03 10:45:00,5,9,14,normal,54
O032,2026-05-03 10:48:00,3,4,6,low,59
O033,2026-05-03 10:52:00,7,6,12,high,43
O034,2026-05-03 10:55:00,1,2,9,normal,51
O035,2026-05-03 10:58:00,6,8,11,low,61
O036,2026-05-03 11:02:00,4,3,7,high,45
O037,2026-05-03 11:05:00,8,1,13,normal,53
O038,2026-05-03 11:08:00,2,6,10,low,58
O039,2026-05-03 11:12:00,9,4,8,high,44
O040,2026-05-03 11:15:00,5,7,15,normal,50
O041,2026-05-03 11:18:00,3,1,6,low,60
O042,2026-05-03 11:22:00,7,9,12,high,41
O043,2026-05-03 11:25:00,1,5,9,normal,52
O044,2026-05-03 11:28:00,6,3,11,low,62
O045,2026-05-03 11:32:00,4,8,7,high,43
O046,2026-05-03 11:35:00,8,2,14,normal,54
O047,2026-05-03 11:38:00,2,4,10,low,59
O048,2026-05-03 11:42:00,9,7,8,high,42
O049,2026-05-03 11:45:00,5,5,13,normal,51
O050,2026-05-03 11:48:00,3,9,6,low,61
O051,2026-05-03 11:52:00,7,1,12,high,45
O052,2026-05-03 11:55:00,1,3,9,normal,53
O053,2026-05-03 11:58:00,6,6,11,low,58
O054,2026-05-03 12:02:00,4,4,7,high,44
O055,2026-05-03 12:05:00,8,9,15,normal,50
O056,2026-05-03 12:08:00,2,2,10,low,60
O057,2026-05-03 12:12:00,9,5,8,high,42
O058,2026-05-03 12:15:00,5,8,14,normal,52
O059,2026-05-03 12:18:00,3,3,6,low,62
O060,2026-05-03 12:22:00,7,7,12,high,41
O061,2026-05-03 12:25:00,1,9,9,normal,54
O062,2026-05-03 12:28:00,6,2,11,low,59
O063,2026-05-03 12:32:00,4,6,7,high,43
O064,2026-05-03 12:35:00,8,4,13,normal,51
O065,2026-05-03 12:38:00,2,8,10,low,61
O066,2026-05-03 12:42:00,9,1,8,high,45
O067,2026-05-03 12:45:00,5,6,15,normal,53
O068,2026-05-03 12:48:00,3,5,6,low,58
O069,2026-05-03 12:52:00,7,3,12,high,44
O070,2026-05-03 12:55:00,1,7,9,normal,50
O071,2026-05-03 12:58:00,6,9,11,low,60
O072,2026-05-03 13:02:00,4,2,7,high,42
O073,2026-05-03 13:05:00,8,6,14,normal,52
O074,2026-05-03 13:08:00,2,1,10,low,62
O075,2026-05-03 13:12:00,9,8,8,high,41
O076,2026-05-03 13:15:00,5,4,13,normal,54
O077,2026-05-03 13:18:00,3,7,6,low,59
O078,2026-05-03 13:22:00,7,5,12,high,43
O079,2026-05-03 13:25:00,1,1,9,normal,51
O080,2026-05-03 13:28:00,6,5,11,low,61
O081,2026-05-03 13:32:00,4,7,7,high,45
O082,2026-05-03 13:35:00,8,8,15,normal,53
O083,2026-05-03 13:38:00,2,3,10,low,58
O084,2026-05-03 13:42:00,9,2,8,high,44
O085,2026-05-03 13:45:00,5,2,14,normal,50
O086,2026-05-03 13:48:00,3,1,6,low,60
O087,2026-05-03 13:52:00,7,8,12,high,42
O088,2026-05-03 13:55:00,1,6,9,normal,52
O089,2026-05-03 13:58:00,6,3,11,low,62
O090,2026-05-03 14:02:00,4,9,7,high,41
O091,2026-05-03 14:05:00,8,1,13,normal,54
O092,2026-05-03 14:08:00,2,4,10,low,59
O093,2026-05-03 14:12:00,9,6,8,high,43
O094,2026-05-03 14:15:00,5,9,15,normal,51
O095,2026-05-03 14:18:00,3,2,6,low,61
O096,2026-05-03 14:22:00,7,4,12,high,45
O097,2026-05-03 14:25:00,1,8,9,normal,53
O098,2026-05-03 14:28:00,6,7,11,low,58
O099,2026-05-03 14:32:00,4,5,7,high,44
O100,2026-05-03 14:35:00,8,3,14,normal,50
O101,2026-05-03 14:38:00,2,9,10,low,60
O102,2026-05-03 14:42:00,9,4,8,high,42
O103,2026-05-03 14:45:00,5,1,13,normal,52
O104,2026-05-03 14:48:00,3,6,6,low,62
O105,2026-05-03 14:52:00,7,2,12,high,41
O106,2026-05-03 14:55:00,1,4,9,normal,54
O107,2026-05-03 14:58:00,6,8,11,low,59
O108,2026-05-03 15:02:00,4,1,7,high,43
O109,2026-05-03 15:05:00,8,7,15,normal,51
O110,2026-05-03 15:08:00,2,5,10,low,61
O111,2026-05-03 15:12:00,9,9,8,high,45
O112,2026-05-03 15:15:00,5,3,14,normal,53
O113,2026-05-03 15:18:00,3,8,6,low,58
O114,2026-05-03 15:22:00,7,6,12,high,44
O115,2026-05-03 15:25:00,1,2,9,normal,50
O116,2026-05-03 15:28:00,6,4,11,low,60
O117,2026-05-03 15:32:00,4,3,7,high,42
O118,2026-05-03 15:35:00,8,5,13,normal,52
O119,2026-05-03 15:38:00,2,7,10,low,62
O120,2026-05-03 15:42:00,9,1,8,high,41
O121,2026-05-03 15:45:00,5,7,15,normal,54
O122,2026-05-03 15:48:00,3,4,6,low,59
O123,2026-05-03 15:52:00,7,9,12,high,43
O124,2026-05-03 15:55:00,1,5,9,normal,51
O125,2026-05-03 15:58:00,6,1,11,low,61
O126,2026-05-03 16:02:00,4,8,7,high,45
O127,2026-05-03 16:05:00,8,2,14,normal,53
O128,2026-05-03 16:08:00,2,6,10,low,58
O129,2026-05-03 16:12:00,9,3,8,high,44
O130,2026-05-03 16:15:00,5,5,13,normal,50
O131,2026-05-03 16:18:00,3,9,6,low,60
O132,2026-05-03 16:22:00,7,7,12,high,42
O133,2026-05-03 16:25:00,1,3,9,normal,52
O134,2026-05-03 16:28:00,6,6,11,low,62
O135,2026-05-03 16:32:00,4,4,7,high,41
O136,2026-05-03 16:35:00,8,9,15,normal,54
O137,2026-05-03 16:38:00,2,2,10,low,59
O138,2026-05-03 16:42:00,9,7,8,high,43
O139,2026-05-03 16:45:00,5,8,14,normal,51
O140,2026-05-03 16:48:00,3,3,6,low,61
O141,2026-05-03 16:52:00,7,1,12,high,45
O142,2026-05-03 16:55:00,1,9,9,normal,53
O143,2026-05-03 16:58:00,6,2,11,low,58
O144,2026-05-03 17:02:00,4,6,7,high,44
O145,2026-05-03 17:05:00,8,4,13,normal,50
O146,2026-05-03 17:08:00,2,8,10,low,60
O147,2026-05-03 17:12:00,9,5,8,high,42
O148,2026-05-03 17:15:00,5,6,15,normal,52
O149,2026-05-03 17:18:00,3,5,6,low,62
O150,2026-05-03 17:22:00,7,3,12,high,41`;

const AGENTS_RAW = `A001,0,0,4.8
A002,1,1,4.5
A003,2,2,4.9
A004,3,3,4.2
A005,4,4,4.7
A006,5,5,4.6
A007,6,6,4.3
A008,7,7,4.8
A009,8,8,4.4
A010,9,9,4.5
A011,0,5,4.7
A012,1,6,4.9
A013,2,7,4.1
A014,3,8,4.6
A015,4,9,4.8
A016,5,0,4.3
A017,6,1,4.5
A018,7,2,4.7
A019,8,3,4.2
A020,9,4,4.9
A021,1,4,4.6
A022,3,5,4.4
A023,5,7,4.8
A024,7,9,4.5
A025,9,1,4.7`;

// parse
function parseOrders() {
return ORDERS_RAW.trim().split('\n').map(line => {
const [id, ts, x, y, prep, priority, sla] = line.split(',');
return { id, ts, x: +x, y: +y, prep: +prep, priority, sla: +sla };
});
}
function parseAgents() {
return AGENTS_RAW.trim().split('\n').map(line => {
const [id, x, y, rating] = line.split(',');
return { id, loc: [+x, +y], rating: +rating };
});
}
function buildEdges() {
const edges = [];
for (let x = 0; x <= 9; x++) for (let y = 0; y <= 9; y++) {
if (x + 1 <= 9) edges.push({ from: [x, y], to: [x+1, y], dist: 3, delay: 1.0 });
if (y + 1 <= 9) edges.push({ from: [x, y], to: [x, y+1], dist: 3, delay: 1.0 });
}
return edges;
}
const CONSTRAINTS = {
maxActive: 2,
latencyTarget: 5,
defaultSLA: 50,
priHigh: 1.5,
priNormal: 1.0,
priLow: 0.8
};
Loading