-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
186 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
.idea/ | ||
*~ | ||
images/ | ||
data/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
data/ | ||
*~ | ||
submission.zip | ||
*__pycache__* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import csv | ||
import math | ||
import os | ||
from typing import Dict, List, Tuple | ||
|
||
|
||
class Grid: | ||
def __init__(self): | ||
self.ids = [] # type: List[str] | ||
self.coords = dict() # type: Dict[str, Tuple[float, float]] | ||
coords_list = [] | ||
|
||
grid_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/hexagon_grid_table.csv') | ||
with open(grid_path, 'r') as csvfile: | ||
for row in csv.reader(csvfile): | ||
if len(row) != 13: | ||
continue | ||
grid_id = row[0] | ||
self.ids.append(grid_id) | ||
lng = sum([float(row[i]) for i in range(1, 13, 2)]) / 6 | ||
lat = sum([float(row[i]) for i in range(2, 13, 2)]) / 6 | ||
coords_list.append((lng, lat)) | ||
self.coords[grid_id] = (lng, lat) | ||
|
||
assert len(coords_list) == 8518, f'Failed to initialize hex grid: found {len(coords_list)} of 8518 expected ids' | ||
|
||
def lookup(self, lng: float, lat: float) -> str: | ||
best_id, best_distance = None, 1000 | ||
for grid_id, (grid_lng, grid_lat) in self.coords.items(): | ||
dist = abs(lng - grid_lng) + abs(lat - grid_lat) | ||
if dist < best_distance: | ||
best_id, best_distance = grid_id, dist | ||
|
||
return best_id | ||
|
||
def distance(self, x: str, y: str) -> float: | ||
""" Return haversine distance in meters """ | ||
lng_x, lat_x = self.coords[x] | ||
lng_y, lat_y = self.coords[y] | ||
|
||
# Haversine | ||
lng_x, lng_y, lat_x, lat_y = map(math.radians, [lng_x, lng_y, lat_x, lat_y]) | ||
lng_delta, lat_delta = abs(lng_x - lng_y), abs(lat_x - lat_y) | ||
a = math.sin(lat_delta / 2) ** 2 + math.cos(lat_x) * math.cos(lat_y) * math.sin(lng_delta / 2) ** 2 | ||
return 6371000 * 2 * math.asin(a ** 0.5) | ||
|
||
def cancel_prob(self, id: str) -> float: | ||
# TODO | ||
return 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import unittest | ||
|
||
from grid import Grid | ||
|
||
|
||
class GridTest(unittest.TestCase): | ||
def setUp(self): | ||
self.grid = Grid() | ||
|
||
def test_hex(self): | ||
grid_id = self.grid.lookup(104.50, 30.71) | ||
assert grid_id == '5973d1e3fdf1f878', grid_id | ||
grid_id = self.grid.lookup(103.99, 30.40) | ||
assert grid_id == '27471aff3df268a1', grid_id | ||
grid_id = self.grid.lookup(104.52, 30.37) | ||
assert grid_id == '15948343c6223064', grid_id | ||
|
||
def test_distance(self): | ||
# SE: (30.65924666666667, 104.12614), NW: (30.73054666666667, 104.04442) | ||
distance = self.grid.distance('386c78bc3c226d88', '926d27c14e84f5d0') | ||
expected = 11126 | ||
error = abs(distance - expected) | ||
assert error < 100, distance | ||
|
||
# NE: (30.725296666666665, 104.13031000000001), NW: (30.73054666666667, 104.04442) | ||
distance = self.grid.distance('111297464a0c9cc8', '926d27c14e84f5d0') | ||
expected = 8247 | ||
error = abs(distance - expected) | ||
assert error < 100, distance | ||
|
||
# NE: (30.725296666666665, 104.13031000000001), SE: (30.65924666666667, 104.12614) | ||
distance = self.grid.distance('111297464a0c9cc8', '386c78bc3c226d88') | ||
expected = 7333 | ||
error = abs(distance - expected) | ||
assert error < 100, distance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from abc import abstractmethod | ||
from typing import Dict, List, Set | ||
|
||
from dispatch import Dispatcher | ||
from parser import HEX_GRID, RepositionData | ||
|
||
SPEED = 6 # 3 m/s @ 2 second interval | ||
|
||
|
||
class Repositioner: | ||
def __init__(self, dispatcher: Dispatcher, gamma: float): | ||
self.dispatcher = dispatcher | ||
self.gamma = gamma | ||
|
||
@abstractmethod | ||
def reposition(self, data: RepositionData) -> List[Dict[str, str]]: | ||
... | ||
|
||
|
||
class ScoredCandidate: | ||
def __init__(self, grid_id: str, score: float): | ||
self.grid_id = grid_id | ||
self.score = score | ||
|
||
|
||
class StateValueGreedy(Repositioner): | ||
def reposition(self, data: RepositionData) -> List[Dict[str, str]]: | ||
reposition = [] # type: List[Dict[str, str]] | ||
candidate_grid_ids = [] # type: List[ScoredCandidate] | ||
for grid_id in self.dispatcher.get_grid_ids(): | ||
value = self.dispatcher.state_value(grid_id) | ||
candidate_grid_ids.append(ScoredCandidate(grid_id, value)) | ||
|
||
max_candidates = (len(data.drivers) + 1) ** 2 | ||
candidate_grid_ids = sorted(candidate_grid_ids, key=lambda x: x.score, reverse=True)[:max_candidates] | ||
|
||
assigned_grid_ids = set() # type: Set[str] | ||
for driver_id, current_grid_id in data.drivers: | ||
current_value = self.dispatcher.state_value(current_grid_id) | ||
best_grid_id, best_value = None, 0 # don't move if negative value | ||
for grid_candidate in candidate_grid_ids: | ||
if grid_candidate.grid_id in assigned_grid_ids: | ||
continue | ||
|
||
eta = HEX_GRID.distance(current_grid_id, grid_id) / SPEED | ||
discount = self.gamma ** eta | ||
incremental_value = discount * self.dispatcher.state_value(grid_id) - current_value | ||
if incremental_value > best_value: | ||
best_grid_id, best_value = grid_id, incremental_value | ||
|
||
new_grid_id = best_grid_id if best_grid_id else current_grid_id | ||
assigned_grid_ids.add(new_grid_id) | ||
reposition.append(dict(driver_id=driver_id, destination=new_grid_id)) | ||
|
||
# TODO: Brute-force expected reward + update discounted by GAMMA^ETA | ||
return reposition |
This file was deleted.
Oops, something went wrong.