Exemplo n.º 1
0
 def problem(self):
     timer = Timer()
     print("Creating problem.")
     timer.start()
     p = cp.Problem(self.sense(self.objective()), self.constraints())
     print(f"Problem created in {timer.time_elapsed():0.2f} (s).")
     return p
Exemplo n.º 2
0
 def lower_control_ratio(self, user_equilibrium_link_flow, tolerance=1e-8):
     timer = Timer()
     print("Creating problem data.")
     timer.start()
     constants, variables = self._prepare_control_ratio(
         user_equilibrium_link_flow, tolerance)
     print(f"Prepared problem data in {timer.time_elapsed():0.2f} (s).")
     return LowerControlRatio(constants, variables)
Exemplo n.º 3
0
def test_path_cost_condition(transportation_network):
    ue_link_flow = transportation_network.solution.link_flow()
    link_cost_fn = transportation_network.network.to_link_cost_function()
    road_network = transportation_network.road_network()
    travel_demand = transportation_network.travel_demand()
    _link_path_key = f"{transportation_network.name}-link_path"
    _path_od_key = f"{transportation_network.name}-path_od"
    try:
        timer1 = Timer()
        timer1.start()
        link_path_incidence = path_incidence_cache[_link_path_key]
        path_od_incidence = path_incidence_cache[_path_od_key]
        print(f"cache hit: loaded arrays in {timer1.time_elapsed()} (s)")
    except KeyError:
        link_path_incidence, path_od_incidence, _ = road_network.path_incidences(
            travel_demand
        )
        path_incidence_cache[_link_path_key] = link_path_incidence
        path_incidence_cache[_path_od_key] = path_od_incidence
    n_links, n_paths = link_path_incidence.shape
    link_cost = link_cost_fn.link_cost(ue_link_flow)
    path_cost = link_path_incidence.T.dot(link_cost)
    demand_vec = travel_demand.to_array()

    min_paths = np.zeros(n_paths, dtype=np.uint8)

    cost_tolerance = 1e-8
    for j, _ in enumerate(travel_demand):
        path_selector = path_od_incidence[:, j].astype(bool)
        od_path_costs = path_cost[path_selector]
        min_paths[path_selector] = (od_path_costs <= (min(od_path_costs) * (1.0 + cost_tolerance))).astype(np.uint8)

    print("Creating problem.")
    path_flow_v = cp.Variable((n_paths,), name="path_flow")
    problem = cp.Problem(
        cp.Minimize(1),
        [
            path_flow_v >= 0,
            (path_od_incidence.T * min_paths) @ path_flow_v == demand_vec,
            (link_path_incidence * min_paths) @ path_flow_v == ue_link_flow,
        ]
    )
    print("Solving problem.")
    problem.solve(solver="SCS", verbose=True, eps=1e-8)
    computed_link_flow = (link_path_incidence @ path_flow_v).value
    computed_demand = (path_od_incidence.T @ path_flow_v).value
    path_flow = path_flow_v.value
    print("max link flow error: ", abs(computed_link_flow - ue_link_flow).max())
    print("max demand error: ", abs(computed_demand - demand_vec).max())
    assert np.allclose(computed_link_flow, ue_link_flow)
    assert np.allclose(path_flow[~min_paths.astype(bool)], 0)
    assert np.allclose(computed_demand, demand_vec)
Exemplo n.º 4
0
 def from_directory(cls, path: str) -> TNTPProblem:
     timer = Timer()
     print("Reading tntp problem.")
     timer.start()
     tntp_directory = TNTPDirectory(path)
     name = tntp_directory.name()
     with tntp_directory.network_file() as fp:
         network = TNTPNetwork.read_text(fp.read())
     with tntp_directory.trips_file() as fp:
         trips = TNTPTrips.read_text(fp.read())
     with tntp_directory.solution_file() as fp:
         solution = TNTPSolution.read_text(fp.read())
     print(f"Read tntp problem in {timer.time_elapsed():0.2f} (s).")
     return TNTPProblem(network, trips, solution, name)
Exemplo n.º 5
0
def test_lower_control_ratio(transportation_network):
    print("testing lower control ratio")
    ue_link_flow = transportation_network.solution.link_flow()
    lower_control_ratio = transportation_network.lower_control_ratio(ue_link_flow)
    lcr_lp = lower_control_ratio.problem()
    variables = lower_control_ratio.variables
    constants = lower_control_ratio.constants
    print("Solving problem.")
    timer = Timer()
    timer.start()
    solver_tolerance = 1e-4
    lcr_lp.solve(solver='SCS', eps=solver_tolerance, verbose=True)
    print(f"Terminated in {timer.time_elapsed():0.2f} (s).")
    stats = lcr_lp.solver_stats
    total_demand = transportation_network.travel_demand().to_array().sum()
    print(f"""
    {transportation_network.name}
    {'='*len(transportation_network.name)}
    solver terminated with status '{lcr_lp.status}' in {stats.solve_time} (s).
    setup time: {stats.setup_time} (s)
    eps: {solver_tolerance}
    number of iterations: {stats.num_iters}
     
    lower control ratio: {lcr_lp.value / total_demand:0.4f} ({lcr_lp.value:0.2f} total).
    
    fleet path flow is between [{min(variables.fleet_link_flow.value)}, {max(variables.fleet_link_flow.value)}]
    total fleet flow is {variables.fleet_demand.value.sum()} (== {variables.fleet_path_flow.value.sum()})
    
    user path flow is between [{min(variables.user_link_flow.value)}, {max(variables.user_link_flow.value)}]
    total user flow is {variables.user_demand.value.sum()} (== {variables.user_path_flow.value.sum()}
    
    maximum link flow error: {(variables.fleet_link_flow + variables.user_link_flow - constants.target_link_flow).value.max()}
    maximum demand error: {(variables.fleet_demand + variables.user_demand - constants.total_demand).value.max()}
    """)
    path_incidence_cache[f"{transportation_network.name}-maximum_ue_ratio-fleet_demand"] = variables.fleet_demand.value
    assert lcr_lp.status == 'optimal'
Exemplo n.º 6
0
class Solver:
    step_size: StepSize
    search_direction: SearchDirection
    link_cost_function: LinkCostFunction
    iterations: List[Iteration] = field(default_factory=list)
    max_iterations: int = 100
    tolerance: float = 1e-15
    timer: Timer = Timer()
    report_interval: int = 1000
    initial_point: np.ndarray = None

    def __post_init__(self):
        self.iterations.append(self.initial_iteration())

    def initial_iteration(self) -> Iteration:
        self.timer.start()
        if self.initial_point is None:
            print("Starting from free flow travel cost.")
            cost = self.link_cost_function.link_cost(0.0)
            link_flow = self.search_direction.minimum_point(cost, 0.0)
        else:
            print("Warm start.")
            cost = self.link_cost_function.link_cost(self.initial_point)
            link_flow = self.initial_point
        return Iteration(iteration=0,
                         cost=cost,
                         link_flow=link_flow,
                         step=np.NaN,
                         search_direction=np.zeros(len(link_flow)),
                         best_lower_bound=0.0,
                         gap=np.inf,
                         duration=self.timer.time_elapsed())

    @property
    def iteration(self) -> Iteration:
        return self.iterations[-1]

    @property
    def gaps(self):
        return np.array([i.gap for i in self.iterations])

    def update(self, iteration: Iteration) -> Iteration:
        self.timer.start()
        i = iteration.iteration
        link_flow = iteration.link_flow
        cost = self.link_cost_function.link_cost(link_flow)
        direction = self.search_direction.search_direction(cost, link_flow)
        step = self.step_size.step(i, link_flow, direction)
        new_link_flow = iteration.link_flow + step * direction
        gap, best_lower_bound = self._relative_gap(cost, direction,
                                                   new_link_flow)
        return Iteration(iteration=i + 1,
                         cost=cost,
                         link_flow=new_link_flow,
                         step=step,
                         search_direction=direction,
                         best_lower_bound=best_lower_bound,
                         gap=gap,
                         duration=self.timer.time_elapsed())

    def log_progress(self):
        i = self.iteration.iteration
        if (i == 1) or ((i > 0) and (i % self.report_interval == 0)):
            print(
                f"iteration {i}: relative gap = {self.iteration.gap:g} (absolute gap = {self.iteration.absolute_gap:g})"
            )

    def objective_value(self, link_flow: np.ndarray) -> float:
        return self.link_cost_function.integral_link_cost(link_flow).sum()

    def _relative_gap(self, cost, direction, link_flow):
        gap = np.dot(cost, direction)
        best_lower_bound = max(
            self.objective_value(link_flow) + gap,
            self.iteration.best_lower_bound)
        relative_gap = -gap / best_lower_bound
        return relative_gap, best_lower_bound

    def _continue(self) -> bool:
        return ((self.iteration.gap > self.tolerance)
                and (self.iteration.iteration < self.max_iterations))

    def solve(self) -> Iteration:
        while self._continue():
            self.log_progress()
            next_iteration = self.update(self.iteration)
            self.iterations.append(next_iteration)
        return self.iteration

    def best_iteration(self):
        return min(self.iterations, key=lambda it: it.gap)
Exemplo n.º 7
0
def timer():
    t = Timer()
    t.start()
    yield
    print(f"{t.time_elapsed():0.2f} seconds elapsed.")
Exemplo n.º 8
0
def test_so_path_cost_condition(transportation_network):
    so_link_flow_key = f"{transportation_network.name}-so_link_flow"
    warm_start_key = f"{so_link_flow_key}-final"
    so_solver = transportation_network.so_solver(
        tolerance=1e-15,
        max_iterations=10000,
        initial_point=path_incidence_cache.get(warm_start_key),
        large_initial_step=False
    )
    print("Solving SO link flow")
    with timer():
        final_iteration = so_solver.solve()
        so_solution = so_solver.best_iteration()
    print(f"Solved SO link flow (gap={so_solution.absolute_gap}, relative gap = {so_solution.gap})")
    so_link_flow = so_solution.link_flow
    path_incidence_cache[so_link_flow_key] = so_link_flow
    path_incidence_cache[warm_start_key] = final_iteration.link_flow
    link_cost_fn = transportation_network.network.to_marginal_link_cost_function()
    road_network = transportation_network.road_network()
    travel_demand = transportation_network.travel_demand()
    _link_path_key = f"{transportation_network.name}-link_path"
    _path_od_key = f"{transportation_network.name}-path_od"
    try:
        timer1 = Timer()
        timer1.start()
        link_path_incidence = path_incidence_cache[_link_path_key]
        path_od_incidence = path_incidence_cache[_path_od_key]
        print(f"cache hit: loaded arrays in {timer1.time_elapsed()} (s)")
    except KeyError:
        link_path_incidence, path_od_incidence, _ = road_network.path_incidences(
            travel_demand
        )
        path_incidence_cache[_link_path_key] = link_path_incidence
        path_incidence_cache[_path_od_key] = path_od_incidence
    n_links, n_paths = link_path_incidence.shape
    link_cost = link_cost_fn.link_cost(so_link_flow)
    path_cost = link_path_incidence.T.dot(link_cost)
    demand_vec = travel_demand.to_array()

    min_paths = np.zeros(n_paths, dtype=np.uint8)

    cost_tolerance = 1e-5
    for j, _ in enumerate(travel_demand):
        path_selector = path_od_incidence[:, j].astype(bool)
        od_path_costs = path_cost[path_selector]
        min_paths[path_selector] = (od_path_costs <= (
                    min(od_path_costs) * (1.0 + cost_tolerance))).astype(
            np.uint8)

    print("Creating problem.")
    path_flow_v = cp.Variable((n_paths,), name="path_flow")
    problem = cp.Problem(
        cp.Minimize(1),
        [
            path_flow_v >= 0,
            (path_od_incidence.T * min_paths) @ path_flow_v == demand_vec,
            (link_path_incidence * min_paths) @ path_flow_v == so_link_flow,
        ]
    )
    print("Solving problem.")
    problem.solve(solver="SCS", verbose=True, eps=1e-6)
    assert problem.status == 'optimal'
    computed_link_flow = (link_path_incidence @ path_flow_v).value
    computed_demand = (path_od_incidence.T @ path_flow_v).value
    path_flow = path_flow_v.value
    print("max link flow error: ", abs(computed_link_flow - so_link_flow).max())
    print("max demand error: ", abs(computed_demand - demand_vec).max())
    assert np.allclose(computed_link_flow, so_link_flow)
    assert np.allclose(path_flow[~min_paths.astype(bool)], 0)
    assert np.allclose(computed_demand, demand_vec)