def generate_routes(schools, permutation=None, partial_route_plan=None, sped=False): all_stops = [] for school in schools: all_stops.extend(school.unrouted_stops) #Initialize stop values for stop in all_stops: stop.update_value(None) #We will process the stops in order of distance #from their schools #The second and part of the tuple improves #determinism of the sorting algorithm. all_stops = sorted(all_stops, key=lambda s: (-trav_time(s, s.school), s.school.school_name)) if len(all_stops) == 0: return [] if permutation != None: all_stops = [all_stops[i] for i in permutation] routes = [] near_schools = determine_school_proximities(schools) if partial_route_plan != None: apply_partial_route_plan(partial_route_plan, all_stops, routes) while len(all_stops) > 0: current_route = Route() #Pick up the most distant stop init_stop = all_stops[0] root_school = init_stop.school root_school.unrouted_stops.remove(init_stop) all_stops.remove(init_stop) #Figure out which schools can be mixed with the stop admissible_schools = near_schools[root_school] if sped: #special ed: no mixed load routing admissible_schools = set([root_school]) current_route.add_stop(init_stop) e_no_h = False h_no_e = False if init_stop.e > 0 and init_stop.h == 0: e_no_h = True if init_stop.h > 0 and init_stop.e == 0: h_no_e = True #Now we will try to add a stop while True: oldlength = current_route.length current_route.backup("generation") #best_score = -100000 best_score = constants.EVALUATION_CUTOFF best_stop = None for school in admissible_schools: for stop in school.unrouted_stops: #Not feasibile with respect to age types if (e_no_h and stop.h > 0 and stop.e == 0 or h_no_e and stop.e > 0 and stop.h == 0): continue if current_route.insert_mincost(stop): #Stop was successfully inserted. #Determine the score of the stop #We want to penalize large time #increases while rewarding collecting #faraway stops. time_cost = current_route.length - oldlength value = stop.value score = value - time_cost #stop in the same place, but different age if time_cost == 0: score = 100000 if score > best_score: best_score = score best_stop = stop current_route.restore("generation") if best_stop == None: break msg = "Failed to insert stop after insertion was verified" assert current_route.insert_mincost(best_stop), msg best_stop.school.unrouted_stops.remove(best_stop) all_stops.remove(best_stop) for stop in best_stop.school.unrouted_stops: stop.update_value(best_stop) if best_stop.e > 0 and best_stop.h == 0: e_no_h = True if best_stop.h > 0 and best_stop.e == 0: h_no_e = True routes.append(current_route) return list(routes)