Headway
1 Codebase

test_integration.py

tests/test_integration.py · 71 lines · Download

1import numpy as np2import pytest3 4from delivery.eval import ReplaySampler, replay5from delivery.instances import Instance, Order, Van, generate_instance6from delivery.integration import plan7from conftest import line_tm8 9 10# ----------------------------------------------------------------------------- normal11@pytest.mark.parametrize("seed", range(3))12def test_plan_serves_every_order_once_on_time(tm, seed):13    inst = generate_instance(20, seed, n_zones=tm.Z)14    res = plan(inst, tm)15    assert res.status == "ok", res.message16    served = sorted(i for r in res.routes.values() for i in r.sequence)17    assert served == sorted(o.id for o in inst.orders)18    for v in inst.vans:19        r = res.routes[v.id]20        assert r.feasible and r.n_late == 021        assert sum(inst.order(i).demand for i in r.sequence) <= v.capacity22        assert len(r.sequence) <= v.max_stops23 24 25def test_replay_counts_late_deliveries_with_known_durations():26    tm = line_tm()27    inst = Instance([Order(0, 2, 480, 495, 1, 5)], [Van(0, 5, 480, 1000)], 0, 1)28    res = plan(inst, tm)29    assert res.status == "ok"30    import pandas as pd31    slow = pd.DataFrame({"pu": [0] * 5, "do": [2] * 5, "hour": [8] * 5, "duration_min": [20.0] * 5})32    fast = slow.assign(duration_min=5.0)33    assert replay(inst, res, ReplaySampler(slow, factor=1.0), tm, n_reps=3)["late_mean"] == 1.034    assert replay(inst, res, ReplaySampler(fast, factor=1.0), tm, n_reps=3)["late_mean"] == 0.035 36 37# ----------------------------------------------------------------------------- edge38def test_edge_more_vans_than_orders():39    tm = line_tm()40    inst = Instance([Order(0, 3, 480, 700, 1, 5)],41                    [Van(0, 5, 480, 1000), Van(1, 5, 480, 1000), Van(2, 5, 480, 1000)], 0, 1)42    res = plan(inst, tm)43    assert res.status == "ok"44    assert sum(len(r.sequence) for r in res.routes.values()) == 145 46 47# ----------------------------------------------------------------------------- impossible48def test_impossible_unreachable_window_reports_reason_and_widening(capsys):49    tm = line_tm()50    vans = [Van(0, 5, 480, 1000), Van(1, 5, 540, 1000), Van(2, 5, 600, 1000)]51    orders = [Order(0, 1, 480, 600, 1, 5), Order(1, 4, 480, 490, 1, 5)]   # 0 -> 4 takes 21 min52    res = plan(Instance(orders, vans, 0, 1), tm)53    print(res.message)54    out = capsys.readouterr().out55    assert res.status == "no_solution"56    assert "NO SOLUTION" in out and "order 1" in out and "not reachable" in out57    assert res.widening["found"] and res.widening["minutes"] == 1558 59 60def test_impossible_single_van_loop_ends_in_no_solution():61    tm = line_tm()62    # every PAIR fits in one van (no "nn" edge), but all three do not: the route is late,63    # the loop learns the first late pair as a different-van rule, and with one van the CSP64    # then has no solution65    orders = [Order(0, 4, 480, 510, 1, 5), Order(1, 2, 480, 500, 1, 5), Order(2, 0, 480, 530, 1, 5)]66    res = plan(Instance(orders, [Van(0, 10, 480, 1000)], 0, 1), tm, suggest=False)67    assert res.loops[0]["csp_status"] == "solved" and res.loops[0]["n_edges_nn"] == 068    assert res.loops[0]["new_rules"], "late route must produce a learned rule"69    assert res.status == "no_solution" and len(res.loops) == 270    assert res.loops[1]["n_edges_learned"] == 171    assert "NO SOLUTION" in res.message