Eric-Tsai's picture
Upload 36 files
7a3d380 verified
Raw
History Blame Contribute Delete
2.07 kB
"""Distance and travel-time matrices.
Node ordering convention used everywhere in this project:
nodes[0 .. n_adjusters-1] = adjuster home locations (route start/end)
nodes[n_adjusters .. ] = claim property locations
The solver only ever reads these matrices, so replacing haversine estimates
with real drive times (OSRM's /table endpoint, Google/HERE Distance Matrix)
means swapping build_matrices() and nothing else.
"""
from __future__ import annotations
import math
import config
from data_gen import Adjuster, Claim
EARTH_RADIUS_MILES = 3958.8
def haversine_miles(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
p1, p2 = math.radians(lat1), math.radians(lat2)
dp = math.radians(lat2 - lat1)
dl = math.radians(lon2 - lon1)
a = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
return 2 * EARTH_RADIUS_MILES * math.asin(math.sqrt(a))
def matrices_from_coords(coords: list[tuple[float, float]]
) -> tuple[list[list[float]], list[list[int]]]:
"""(miles, minutes) matrices over an arbitrary coordinate list -
haversine * circuity, minutes as integers for the solvers."""
n = len(coords)
miles = [[0.0] * n for _ in range(n)]
minutes = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(i + 1, n):
d = haversine_miles(*coords[i], *coords[j]) * config.CIRCUITY_FACTOR
t = int(round(d / config.AVG_SPEED_MPH * 60))
miles[i][j] = miles[j][i] = d
minutes[i][j] = minutes[j][i] = t
return miles, minutes
def build_matrices(adjusters: list[Adjuster], claims: list[Claim]
) -> tuple[list[list[float]], list[list[int]]]:
"""Return (miles_matrix, travel_minutes_matrix) over all nodes.
Miles are road-approximated (haversine * circuity factor); minutes are
integers as required by OR-Tools.
"""
coords = [(a.home_lat, a.home_lon) for a in adjusters]
coords += [(c.lat, c.lon) for c in claims]
return matrices_from_coords(coords)