File size: 1,350 Bytes
cc298f9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | """Optimization problem: existing stations + candidates + objective + how many to add."""
from dataclasses import dataclass
from functools import cached_property
import numpy as np
from .objective import SeparableObjective
from .placement import PlacementSet
@dataclass
class Problem:
existing: PlacementSet # fixed ψ⁰
candidates: PlacementSet # 𝒞 — choose m of these
objective: SeparableObjective
m: int
def __post_init__(self):
if self.existing.travel_times.shape[1] != self.candidates.travel_times.shape[1]:
raise ValueError("existing and candidates must share the same grid (N)")
if self.objective.weights.shape[0] != self.candidates.travel_times.shape[1]:
raise ValueError("objective.weights length must match grid size N")
if self.m < 0 or self.m > self.candidates.K:
raise ValueError(f"m must be in [0, K]; got m={self.m}, K={self.candidates.K}")
@cached_property
def base_field(self) -> np.ndarray:
"""t⁰ — minimum arrival time over all existing stations."""
if self.existing.K == 0:
return np.full(self.candidates.N, np.inf, dtype=np.float64)
return self.existing.travel_times.min(axis=0)
@property
def base_value(self) -> float:
return self.objective.value(self.base_field)
|