예제 #1
0
def test_initial_routes():

    horizon = 20000
    m = reader.load_matrix_from_csv('test/data/matrix.csv')
    odpairs = reader.load_demand_from_csv('test/data/demand.csv')
    d = D.Demand(odpairs, m, horizon)
    m = d.generate_solver_space_matrix(m)
    x_m = d.insert_nodes_for_breaks(m)

    v = V.Vehicles(5, horizon)

    trip_chains_B = IR.initial_routes_2(d, v.vehicles, x_m)
    initial_routes_B = [tcv for tcv in trip_chains_B.values()]
    (assignment, routing, manager) = MR.model_run(d, x_m, v.vehicles, 10000,
                                                  None, initial_routes_B)
    assert assignment
    assert assignment.ObjectiveValue() == 43516

    for vehicle in v.vehicles:
        vehicle_id = vehicle.index
        original_chain = trip_chains_B[vehicle_id]
        index = routing.Start(vehicle_id)
        plan_output = []
        route_time = 0
        while not routing.IsEnd(index):
            # drop 0
            node = manager.IndexToNode(index)
            if node != 0:
                plan_output.append(node)
            index = assignment.Value(routing.NextVar(index))

        # print(original_chain)
        # print(plan_output)
        assert original_chain == plan_output
예제 #2
0
def test_insert_nodes_for_breaks():

    # now test the break generator inside demand
    # first read in the test demand
    horizon = 10000
    m = reader.load_matrix_from_csv('test/data/matrix.csv')
    odpairs = reader.load_demand_from_csv('test/data/demand.csv')
    d     = D.Demand(odpairs,m,horizon)
    # read in travel time
    # assume a mile a minute (60mph), so m in miles === m in minutes
    # convert to solver space
    m = d.generate_solver_space_matrix(m)
    # this should drastically trim travel matrix, since only one
    # demand is feasible before 10000
    assert len(m) == 3
    newtimes = d.insert_nodes_for_breaks(m)
    assert len(newtimes) > len(m)
    # expect to have added 4 nodes between 0-1, 5 nodes between 1-2, 2
    # nodes 2-0 plus original 2
    assert len(newtimes) == 11 + 3

    # check each row for reasonableness
    count_new_nodes = 0
    count_nodes = 0
    feasible_index = d.demand.feasible
    for idx in d.demand.index[feasible_index]:
        print(idx)
        origin = d.demand.loc[idx,'origin']
        dest   = d.demand.loc[idx,'destination']
        print(origin,dest,idx)
        # 5 nodes link to origin---depot plus 4 break nodes
        assert len(newtimes.loc[:,origin].index[newtimes.loc[:,origin].notna()]) == 5
        # 6 nodes link to destination---origin plus 5 break nodes
        assert len(newtimes.loc[:,dest].index[newtimes.loc[:,dest].notna()]) == 6
예제 #3
0
def test_create_time_matrix():
    matrix = reader.load_matrix_from_csv('test/data/matrix.csv')
    hours_matrix = reader.travel_time(60,matrix)
    assert (hours_matrix.loc[0,0] == 0)
    assert (hours_matrix.loc[0,1] == math.floor(21.15))
    minutes_matrix = reader.travel_time(1,matrix)
    assert (minutes_matrix.loc[0,0] == 0)
    assert (minutes_matrix.loc[0,1] == 1269.0) # a mile a minute
예제 #4
0
def test_load_distance_matrix():
    matrix = reader.load_matrix_from_csv('test/data/matrix.csv')
    assert(matrix.ndim == 2)
    assert(matrix.size == 10*10)
    assert(matrix.loc[0,0] == 0)
    assert(matrix.loc[0,1] == 1269)
    assert(matrix.loc[1,0] == 1275)
    assert(matrix.loc[0].max() == 1842)
    assert(matrix.loc[:,0].max() == 1857)
예제 #5
0
def test_time_callback():
    pickup_time = 20
    dropoff_time = 10
    horizon = 10000
    m = reader.load_matrix_from_csv('test/data/matrix.csv')
    odpairs = reader.load_demand_from_csv('test/data/demand.csv')
    d = D.Demand(odpairs,
                 m,
                 horizon,
                 pickup_time=pickup_time,
                 dropoff_time=dropoff_time)
    max_distance = m.max().max()
    m_m = reader.travel_time(1, m)
    max_time = m_m.max().max()

    # test fixing travel time matrix into model space
    m_m = d.generate_solver_space_matrix(m_m)
    assert m_m.ndim == 2
    # did I get it right?  the time from
    # node 0 to node 1 is depot to node 5, is 930
    assert m_m.loc[0, 1] == m.loc[0, d.get_map_node(1)]

    # with horizon of 10000, only one OD pair is feasible
    assert len(m_m.index) == 3  # 2 nodes, 1 depot
    assert len(m_m.loc[0]) == 3

    demand_callback = E.create_demand_callback(m.index, d)

    manager = MockManager()

    assert demand_callback(manager, 0) == 0
    assert demand_callback(manager, 1) == 1
    assert demand_callback(manager, 2) == -1
    assert demand_callback(manager, 3) == 0

    # Distance tests, no pickup or dropoff times
    dist_callback = E.create_dist_callback(m_m, d)

    assert dist_callback(manager, 0, 0) == 0  # depot to depot is zero
    # Again that first line in demand is mapnode 7 to mapnode 9
    # so node 0 to node 1 is depot to node 7, is 930
    assert dist_callback(manager, 0, 1) == m.loc[0, d.get_map_node(1)]
    assert dist_callback(manager, 1, 2) == m.loc[d.get_map_node(1),
                                                 d.get_map_node(2)]
    assert dist_callback(manager, 2, 0) == m.loc[d.get_map_node(2), 0]
    # everything else is forbidden
    assert dist_callback(manager, 0, 2) > max_distance  # can't skip pickup
    assert dist_callback(manager, 2, 1) > max_distance  # can't go backwards
    assert dist_callback(manager, 1, 0) > max_distance  # can't skip dropoff

    # Time tests add pickup and delivery time

    # simple time callback with original minutes matrix
    time_callback = E.create_time_callback2(m_m, d)

    assert time_callback(manager, 0, 0) == 0
    # note that pickup time at node, dropoff time at node is transit
    # time across node, so is only added in when node is origin
    assert time_callback(manager, 0, 1) == m.loc[0, d.get_map_node(1)]
    assert time_callback(
        manager, 1,
        2) == m.loc[d.get_map_node(1), d.get_map_node(2)] + pickup_time
    assert time_callback(manager, 2,
                         0) == m.loc[d.get_map_node(2), 0] + dropoff_time
    # everything else is forbidden
    assert time_callback(manager, 0, 2) > max_time  # can't skip pickup
    assert time_callback(manager, 2, 1) > max_time  # can't go backwards
    assert time_callback(manager, 1, 0) > max_time  # can't skip dropoff

    # more extensive time callback with break nodes too
    m_m_more = d.insert_nodes_for_breaks(m_m)

    print('len m_m_more is ', len(m_m_more))

    assert len(m_m_more) > len(m_m)
    time_callback = E.create_time_callback2(m_m_more, d)
    # the following are same as above, should not have changed
    assert time_callback(manager, 0, 0) == 0
    assert time_callback(manager, 0, 1) == m.loc[0, d.get_map_node(1)]
    assert time_callback(
        manager, 1,
        2) == m.loc[d.get_map_node(1), d.get_map_node(2)] + pickup_time
    assert time_callback(manager, 2,
                         0) == m.loc[d.get_map_node(2), 0] + dropoff_time
    assert time_callback(manager, 0, 2) > max_time  # can't skip pickup
    assert time_callback(manager, 2, 1) > max_time  # can't go backwards
    assert time_callback(manager, 1, 0) > max_time  # can't skip dropoff

    # now test new nodes, 3+
    assert len(m_m_more.index) == 14

    # test long break from 0 to 1
    assert time_callback(manager, 0, 3) == 660
    # short break
    assert time_callback(manager, 0, 4) == 480
    # short break happens
    assert time_callback(manager, 4, 3) == (660 - 480) + 30
    # long break happens
    assert time_callback(manager, 3,
                         1) == (m.loc[0, d.get_map_node(1)] - 660) + 600
    # can't go
    assert time_callback(manager, 3, 4) > max_time

    # test the drive callback accumulator
    drive_callback = partial(
        E.create_drive_callback(m_m_more, d, 11 * 60, 10 * 60), manager)

    # drive callback is just the drive time, but gets reset at long breaks
    bn11 = d.get_break_node(3)
    assert bn11.drive_time_restore() == -660

    assert drive_callback(0, 0) == 0
    # no pickup, no dropoff time added to drive dimension
    assert drive_callback(0, 1) == m.loc[0, d.get_map_node(1)]
    assert drive_callback(1, 2) == m.loc[d.get_map_node(1), d.get_map_node(2)]
    assert drive_callback(2, 0) == m.loc[d.get_map_node(2), 0]
    assert drive_callback(0, 2) > max_time  # can't skip pickup
    assert drive_callback(2, 1) > max_time  # can't go backwards
    assert drive_callback(1, 0) > max_time  # can't skip dropoff

    # now test break nodes
    # test long break from 0 to 1
    assert drive_callback(0, 3) == 660  # just drive, haven't taken break
    # short break
    assert drive_callback(0, 4) == 480  # just drive, haven't taken break
    # short break happens, no impact
    assert drive_callback(4, 3) == (660 - 480)  # no 30 minute break added
    # long break happens
    assert drive_callback(
        3,
        1) == (m.loc[0, d.get_map_node(1)] - 660) + bn11.drive_time_restore()
    # can't go
    assert drive_callback(3, 4) > max_time

    # now short break callback
    short_callback = partial(
        E.create_short_break_callback(m_m_more, d, 8 * 60, 30), manager)

    # drive callback is just the drive time, but gets reset at long breaks
    bn8 = d.get_break_node(4)
    assert bn8.drive_time_restore() == -480
    assert short_callback(0, 0) == 0
    # no pickup, no dropoff time added to drive dimension
    assert short_callback(0, 1) == m.loc[0, d.get_map_node(1)]
    assert short_callback(1, 2) == m.loc[d.get_map_node(1), d.get_map_node(2)]
    assert short_callback(2, 0) == m.loc[d.get_map_node(2), 0]
    assert short_callback(0, 2) > max_time  # can't skip pickup
    assert short_callback(2, 1) > max_time  # can't go backwards
    assert short_callback(1, 0) > max_time  # can't skip dropoff

    # now test break nodes
    # test long break from 0 to 1
    assert short_callback(0, 3) == 660  # just drive, haven't taken break
    # short break
    assert short_callback(0, 4) == 480  # just drive, haven't taken break
    # short break happens, triggers restore of 480
    assert short_callback(4, 3) == (660 - 480) + bn8.drive_time_restore()
    # long break happens.  Okay, the source code is lame, but it also restores 660 - 480
    assert short_callback(
        3, 1) == (m.loc[0, d.get_map_node(1)] -
                  660) + (bn11.drive_time_restore() - bn8.drive_time_restore())
    # can't go
    assert short_callback(3, 4) > max_time
예제 #6
0
def main():
    """Entry point of the program."""
    parser = argparse.ArgumentParser(
        description=
        'Solve assignment of truck load routing problem, give hours of service rules and a specified list of origins and destinations'
    )
    # parser.add_argument('--resume_file',type=str,dest='resumefile',
    #                     help="resume a failed solver run from this file")
    parser.add_argument('-m,--matrixfile',
                        type=str,
                        dest='matrixfile',
                        help='CSV file for travel matrix (distances)')
    parser.add_argument(
        '-d,--demandfile',
        type=str,
        dest='demand',
        help='CSV file for demand pairs (origin, dest, time windows)')
    parser.add_argument('-o,--vehicleoutput',
                        type=str,
                        dest='vehicle_output',
                        default='vehicle_output.csv',
                        help='CSV file for dumping output')
    parser.add_argument(
        '--demandoutput',
        type=str,
        dest='demand_output',
        default='demand_output.csv',
        help=
        'CSV file for dumping output for demand details (including invalid demands, etc)'
    )
    parser.add_argument(
        '--summaryoutput',
        type=str,
        dest='summary_output',
        help=
        'A file for dumping the human-readable summary output for the assignment'
    )
    parser.add_argument(
        '--speed',
        type=float,
        dest='speed',
        default=55.0,
        help=
        'Average speed, miles per hour.  Default is 55 (miles per hour).  Distance unit should match that of the matrix of distances.  The time part should be per hours'
    )
    parser.add_argument(
        '--maxtime',
        type=int,
        dest='horizon',
        default=10080,
        help='Max time in minutes.  Default is 10080 minutes, which is 7 days.'
    )

    parser.add_argument('-v,--vehicles',
                        type=int,
                        dest='numvehicles',
                        default=100,
                        help='Number of vehicles to create.  Default is 100.')
    parser.add_argument(
        '--pickup_time',
        type=int,
        dest='pickup_time',
        default=15,
        help='Pick up time in minutes.  Default is 15 minutes.')
    parser.add_argument(
        '--dropoff_time',
        type=int,
        dest='dropoff_time',
        default=15,
        help='Drop off time in minutes.  Default is 15 minutes.')

    parser.add_argument(
        '-t, --timelimit',
        type=int,
        dest='timelimit',
        default=5,
        help='Maximum run time for solver, in minutes.  Default is 5 minutes.')

    parser.add_argument(
        '--narrow_destination_timewindows',
        type=bool,
        dest='destination_time_windows',
        default=True,
        help=
        "If true, limit destination node time windows based on travel time from corresponding origin.  If false, destination nodes time windows are 0 to args.horizon.  Default true (limit the time window)."
    )

    parser.add_argument(
        '--drive_dim_start_value',
        type=int,
        dest='drive_dimension_start_value',
        default=1000,
        help=
        "Due to internal solver mechanics, the drive dimension can't go below zero (it gets truncated at zero).  So to get around this, the starting point for the drive time dimension has to be greater than zero.  The default is 1000.  Change it with this variable"
    )

    parser.add_argument('--debug',
                        type=bool,
                        dest='debug',
                        default=False,
                        help="Turn on some print statements.")

    parser.add_argument(
        '--noroutes',
        type=bool,
        dest='noroutes',
        default=False,
        help="Disable generating initial routes.  Not recommended")
    args = parser.parse_args()

    print('read in distance matrix')
    matrix = reader.load_matrix_from_csv(args.matrixfile)
    minutes_matrix = reader.travel_time(args.speed / 60, matrix)

    print('read in demand data')
    odpairs = reader.load_demand_from_csv(args.demand)
    d = D.Demand(odpairs, minutes_matrix, args.horizon)

    # convert nodes to solver space from input map space
    mm = d.generate_solver_space_matrix(minutes_matrix, args.horizon)

    # create dummy nodes for breaks
    expanded_mm = d.insert_nodes_for_breaks(mm)

    # copy new nodes to distance matrix
    expanded_m = reader.travel_time(60 / args.speed, expanded_mm)
    # print('original matrix of',len(matrix.index),'expanded to ',len(expanded_m.index))

    # vehicles:
    vehicles = V.Vehicles(args.numvehicles, args.horizon)

    # Create the routing index manager.

    # number of nodes is now given by the travel time matrix
    # probably should refactor to put time under control of
    # demand class
    num_nodes = len(expanded_mm.index)
    print('After augmenting network with break nodes, solving with ',
          num_nodes, 'nodes')
    #print(d.demand.loc[d.demand.feasible,:])
    print(d.demand.loc[:, [
        'from_node', 'to_node', 'early', 'late', 'pickup_time', 'dropoff_time',
        'round_trip', 'depot_origin', 'earliest_destination', 'feasible',
        'origin', 'destination'
    ]])

    initial_routes = None
    trip_chains = {}

    trip_chainsb = IR.initial_routes_2(d, vehicles.vehicles, expanded_mm)
    initial_routesb = [v for v in trip_chainsb.values()]
    (assB, routing, manager) = MR.model_run(d, expanded_mm, vehicles.vehicles,
                                            args.drive_dimension_start_value,
                                            None, initial_routesb,
                                            args.timelimit)
    # 1201918

    # # set up initial routes by creating a lot of little problems
    # for d_idx in d.demand.index:
    #     # depot to pickup
    #     record = d.demand.loc[d_idx]
    #     if not record.feasible:
    #         continue
    #     nodes = MR.use_nodes(record,d)
    #     (subassignment,minirouting,minimanager) = MR.model_run(d,expanded_mm,[vehicles.vehicles[0]],args.drive_dimension_start_value,nodes)
    #     trip_chains[record.origin] = MR.get_route(0,subassignment,minirouting,minimanager)
    # initial_routes = [v for v in trip_chains.values()]
    # (assA,routingA,managerA) = MR.model_run(d,expanded_mm,vehicles.vehicles,args.drive_dimension_start_value,None,initial_routes)
    # 1201918 ---  same, but slower, so don't do it

    if assB:
        assignment = assB
        ## save the assignment, (Google Protobuf format)
        #save_file_base = os.path.realpath(__file__).split('.')[0]
        #if routing.WriteAssignment(save_file_base + '_assignment.ass'):
        #    print('succesfully wrote assignment to file ' + save_file_base +
        #          '_assignment.ass')

        #print(expanded_mm)
        print('The Objective Value is {0}'.format(assignment.ObjectiveValue()))
        print('details:')

        SO.print_solution(d, expanded_m, expanded_mm, vehicles, manager,
                          routing, assignment, args.horizon,
                          args.drive_dimension_start_value, args)

        SO.csv_output(d, expanded_m, expanded_mm, vehicles, manager, routing,
                      assignment, args.horizon, args.vehicle_output)
        SO.csv_demand_output(d, expanded_m, expanded_mm, vehicles, manager,
                             routing, assignment, args.horizon,
                             args.demand_output)

    else:
        print('assignment failed')
예제 #7
0
def main():
    """Entry point of the program."""
    parser = argparse.ArgumentParser(
        description=
        'Solve assignment of truck load routing problem, with specified list of origins and destinations, ignoring hours of service rules'
    )
    # parser.add_argument('--resume_file',type=str,dest='resumefile',
    #                     help="resume a failed solver run from this file")
    parser.add_argument('-m,--matrixfile',
                        type=str,
                        dest='matrixfile',
                        help='CSV file for travel matrix (distances)')
    parser.add_argument(
        '-d,--demandfile',
        type=str,
        dest='demand',
        help='CSV file for demand pairs (origin, dest, time windows)')
    parser.add_argument('-o,--vehicleoutput',
                        type=str,
                        dest='vehicle_output',
                        default='vehicle_output.csv',
                        help='CSV file for dumping output')
    parser.add_argument(
        '--demandoutput',
        type=str,
        dest='demand_output',
        default='demand_output.csv',
        help=
        'CSV file for dumping output for demand details (including invalid demands, etc)'
    )
    parser.add_argument(
        '--summaryoutput',
        type=str,
        dest='summary_output',
        help=
        'A file for dumping the human-readable summary output for the assignment'
    )
    parser.add_argument(
        '--speed',
        type=float,
        dest='speed',
        default=55.0,
        help=
        'Average speed, miles per hour.  Default is 55 (miles per hour).  Distance unit should match that of the matrix of distances.  The time part should be per hours'
    )
    parser.add_argument(
        '--maxtime',
        type=int,
        dest='horizon',
        default=10080,
        help='Max time in minutes.  Default is 10080 minutes, which is 7 days.'
    )

    parser.add_argument('-v,--vehicles',
                        type=int,
                        dest='numvehicles',
                        default=100,
                        help='Number of vehicles to create.  Default is 100.')
    parser.add_argument(
        '--pickup_time',
        type=int,
        dest='pickup_time',
        default=15,
        help='Pick up time in minutes.  Default is 15 minutes.')
    parser.add_argument(
        '--dropoff_time',
        type=int,
        dest='dropoff_time',
        default=15,
        help='Drop off time in minutes.  Default is 15 minutes.')

    parser.add_argument(
        '-t, --timelimit',
        type=int,
        dest='timelimit',
        default=5,
        help='Maximum run time for solver, in minutes.  Default is 5 minutes.')

    parser.add_argument(
        '--initial_routes',
        type=bool,
        dest='initial_routes',
        default=False,
        help=
        "If true, generate initial routes.  Sometimes the solution isn't as good as letting the solver do its thing, but sometimes it is better.  In tests, with all 100 trips active it is slightly better to set initial routes, but with just 50 routes active, the solution is better without initial routes."
    )

    parser.add_argument(
        '--narrow_destination_timewindows',
        type=bool,
        dest='destination_time_windows',
        default=True,
        help=
        "If true, limit destination node time windows based on travel time from corresponding origin.  If false, destination nodes time windows are 0 to args.horizon.  Default true (limit the time window)."
    )

    parser.add_argument('--debug',
                        type=bool,
                        dest='debug',
                        default=False,
                        help="Turn on some print statements.")

    args = parser.parse_args()

    print('read in distance matrix')
    matrix = reader.load_matrix_from_csv(args.matrixfile)
    minutes_matrix = reader.travel_time(args.speed / 60, matrix)

    print('read in demand data')
    odpairs = reader.load_demand_from_csv(args.demand)
    d = D.Demand(odpairs, minutes_matrix, args.horizon, use_breaks=False)

    # convert nodes to solver space from input map space
    expanded_mm = d.generate_solver_space_matrix(minutes_matrix, args.horizon)

    # echo nodes to distance matrix
    expanded_m = reader.travel_time(60 / args.speed, expanded_mm)
    # print('original matrix of',len(matrix.index),'expanded to ',len(expanded_m.index))

    # vehicles:
    vehicles = V.Vehicles(args.numvehicles, args.horizon)

    # number of nodes is now given by the travel time matrix
    # probably should refactor to put time under control of
    # demand class
    num_nodes = len(expanded_mm.index)
    print('Solving with ', num_nodes, 'nodes')
    print(d.demand.loc[:, [
        'from_node', 'to_node', 'early', 'late', 'pickup_time', 'dropoff_time',
        'round_trip', 'depot_origin', 'earliest_destination', 'feasible',
        'origin', 'destination'
    ]])

    initial_routes = None
    trip_chains = {}
    assignment = None
    routing = None
    manager = None
    if args.initial_routes:
        trip_chains = IR.initial_routes_no_breaks(d,
                                                  vehicles.vehicles,
                                                  expanded_mm,
                                                  debug=args.debug)
        initial_routes = [v for v in trip_chains.values()]
        (assignment, routing,
         manager) = MR.model_run_nobreaks(d, expanded_mm, vehicles.vehicles,
                                          None, initial_routes, args)
    else:
        (assignment, routing,
         manager) = MR.model_run_nobreaks(d,
                                          expanded_mm,
                                          vehicles.vehicles,
                                          args=args)

    if assignment:
        ## save the assignment, (Google Protobuf format)
        #save_file_base = os.path.realpath(__file__).split('.')[0]
        #if routing.WriteAssignment(save_file_base + '_assignment.ass'):
        #    print('succesfully wrote assignment to file ' + save_file_base +
        #          '_assignment.ass')

        #print(expanded_mm)
        print('The Objective Value is {0}'.format(assignment.ObjectiveValue()))
        print('details:')

        SO.print_solution(d, expanded_m, expanded_mm, vehicles, manager,
                          routing, assignment, args.horizon, 0, args)
        SO.csv_output(d, expanded_m, expanded_mm, vehicles, manager, routing,
                      assignment, args.horizon, args.vehicle_output)
        SO.csv_demand_output(d, expanded_m, expanded_mm, vehicles, manager,
                             routing, assignment, args.horizon,
                             args.demand_output)

    else:
        print('assignment failed')
예제 #8
0
def test_demand():
    horizon = 10000
    putime = 20
    dotime = 25
    m = reader.load_matrix_from_csv('test/data/matrix.csv')
    odpairs = reader.load_demand_from_csv('test/data/demand.csv')
    d = D.Demand(odpairs, m, horizon)
    d_alt = D.Demand(odpairs, m, horizon * 10, putime, dotime)

    assert (d.demand.early.min() > 0)
    assert (d.demand.early.max() < horizon)
    assert (d.demand.late.min() > 0)
    assert (d.demand.late.max() < horizon)

    # test that horizon weeded out OD pairs
    assert (len(d.equivalence) == 2)
    assert (len(d_alt.equivalence) == 10)

    listing = d.get_node_list()
    assert len(listing) == 2
    for i in listing:
        assert isinstance(i, np.int64)
    # print(d.demand.loc[:,['feasible','from_node','to_node','origin','destination']])
    assert d.get_map_node(0) == 0
    assert d.get_map_node(
        1) == 5  # first few are not feasible with short horizon
    assert d.get_map_node(2) == 2
    assert d.get_map_node(
        3) == -1  # only one pickup pair is feasible with short horizon

    # loading time is 15 as default
    assert d.get_service_time(1) == 15
    # unloading time is 15 as default
    assert d.get_service_time(2) == 15
    assert d.get_service_time(0) == 0
    assert d.get_service_time(3) == 0

    # loading time is 20 in alternate
    assert d_alt.get_service_time(1) == 20
    # unloading time is 25 in alternate
    assert d_alt.get_service_time(6) == 25  # and long horizon has more pairs

    # other functions tested in test_evaluators, as they involve other modules?
    node_list = d.get_node_list()
    assert node_list[0] == 1
    assert node_list[1] == 2

    assert d.get_demand_number(1) == 3
    assert d_alt.get_demand_number(1) == 0

    assert d.get_demand_number(2) == 3
    assert d.get_demand_number(0) == -1
    assert d.get_demand_number(3) == -1

    assert d.get_demand(0) == 0
    assert d.get_demand(1) == 1
    assert d.get_demand(2) == -1
    assert d.get_demand(3) == 0

    mm = d.generate_solver_space_matrix(m)
    assert mm.max().max() > 0
    assert len(mm.index) == 3
    assert mm.loc[0, 0] == 0
    assert mm.loc[0, 1] == 930
    assert np.isnan(mm.loc[0, 2])

    mm = d_alt.generate_solver_space_matrix(m)
    assert mm.max().max() > 0
    assert len(mm.index) == 11  # 5 nodes plus depot
    assert mm.loc[0, 0] == 0
    assert mm.loc[0, 1] == 1150
    assert np.isnan(mm.loc[6, 1])
    assert np.isnan(mm.loc[0, 6])
    mm_ex = d_alt.insert_nodes_for_breaks(mm)
    for idx in mm.index:
        assert mm.loc[idx, idx] == mm_ex.loc[idx, idx]

    assert len(mm_ex.index) > len(mm.index)
    # travel times from new nodes to all nodes is less than max of original matrix
    new_nodes = range(len(mm.index), len(mm_ex.index))
    assert mm_ex.loc[new_nodes, :].max().max() < mm.max().max()
    # and all to new, ditto
    assert mm_ex.loc[:, new_nodes].max().max() < mm.max().max()

    break_chain = d_alt.get_break_node_chain(0, 1)
    new_node_start = len(mm.index)
    assert len(break_chain) == 5
    assert break_chain[0] == new_node_start + 1
    assert break_chain[1] == new_node_start + 0
    assert break_chain[2] == new_node_start + 3
    assert break_chain[3] == new_node_start + 2
    assert break_chain[4] == new_node_start + 4

    assert d_alt.get_break_node(0) == None
    bn8 = d_alt.get_break_node(new_node_start)
    bn10 = d_alt.get_break_node(new_node_start + 1)

    bn8.node = new_node_start
    bn8.origin = 0
    bn8.destination = bn10.node
    bn8.break_time = 30
    bn8.drive_time_restore = -480

    bn10.node = new_node_start + 1
    bn10.origin = 0
    bn10.destination = 1
    bn10.break_time = 600
    bn10.drive_time_restore = -660
예제 #9
0
def test_output():

    horizon = 20000
    m = reader.load_matrix_from_csv('test/data/matrix.csv')
    odpairs = reader.load_demand_from_csv('test/data/demand.csv')
    d = D.Demand(odpairs, m, horizon)
    m = d.generate_solver_space_matrix(m)

    v = V.Vehicles(5, horizon)
    # (assignment,routing,manager) = MR.model_run_nobreaks3(d,m,v)
    (assignment, routing, manager) = MR.model_run_nobreaks(d, m, v.vehicles)

    assert assignment

    out = io.StringIO()
    err = io.StringIO()
    args = MockArgs()
    with redirected(out=out, err=err):
        out.flush()
        err.flush()
        SO.print_solution(d, m, m, v, manager, routing, assignment, horizon, 0,
                          args)
        output = out.getvalue()

        expected_output = ""
        assert output == expected_output
        assert filecmp.cmp(output_file, expected_file)

    # make sure output file was created as directed
    assert os.path.exists(args.summary_output)

    # write details again, and this time there should be a _1 version of args.summary_output
    assert not os.path.exists(second_output_file)
    SO.print_solution(d, m, m, v, manager, routing, assignment, horizon, 0,
                      args)
    # created alternate named file
    assert os.path.exists(second_output_file)
    assert filecmp.cmp(output_file, second_output_file)

    # now try again without the file

    out = io.StringIO()
    err = io.StringIO()
    args.summary_output = None
    with redirected(out=out, err=err):
        out.flush()
        err.flush()
        SO.print_solution(d, m, m, v, manager, routing, assignment, horizon, 0,
                          args)
        output = out.getvalue()

        f = open(expected_file, "r", encoding="utf-8")
        expected_output = f.read()
        assert output == expected_output

    assert not os.path.exists(third_output_file)

    os.unlink(output_file)
    os.unlink(second_output_file)
    # reset args to dump output file
    args = MockArgs()

    # test when run with breaks
    x_m = d.insert_nodes_for_breaks(m)
    trip_chains = IR.initial_routes_2(d, v.vehicles, x_m)
    initial_routes = [v for v in trip_chains.values()]
    (assignment, routing, manager) = MR.model_run(d, x_m, v.vehicles, 10000,
                                                  None, initial_routes)
    SO.print_solution(d, x_m, x_m, v, manager, routing, assignment, horizon,
                      10000, args)

    assert filecmp.cmp(output_file, expected_breaks_file)
    os.unlink(output_file)