예제 #1
0
def _process_lr3opt_debug_line(
        line,
        normalization_parameters,
        currentK,
        #output here
        rays,
        active_nodes,
        active_ray_idxs,
        points_of_interest,
        candidate_routes,
        infeasible_routes,
        complete_routes,
        labels):
    newK = None
    changed = False

    ism = initial_re.search(line)
    #msm = move_start_re.search(line)
    mdm = move_done_re.search(line)
    rim = remain_infeasible_re.search(line)
    ffm = feasible_found_re.search(line)
    ilm = inc_lambda_re.search(line)

    if ism:
        sol = eval(ism.group(1))
        infeasible_routes[:] = sol2routes(sol)
        labels[:] = ["l1_C=%s, l1_L=%s" % (ism.group(3), ism.group(4))]
        changed = True

    if mdm:
        sol = eval(mdm.group(1))
        candidate_routes[:] = sol2routes(sol)
        changed = False

    if rim:
        infeasible_routes[:] = eval(rim.group(1))
        print("REMAIN INFEASIBLE", infeasible_routes[:])
        candidate_routes[:] = [
            r for r in candidate_routes if r not in infeasible_routes
        ]
        changed = True

    if ffm:
        infeasible_routes[:] = []
        sol = eval(ffm.group(1))
        complete_routes[:] = sol2routes(sol)
        changed = True

    if ilm:
        labels[:] = ["l1_C=%s, l1_L=%s" % (ilm.group(1), ilm.group(2))]

    return changed, newK
예제 #2
0
    def test_improve_random_solution_first_accept(self):
        special_case_fails_message = (
            "NOTE: This may sometimes fail due to" +
            " how the naive implementation may coincidentally invert also routes"
            +
            " which are between the two routes that have their edges removed."
            +
            " Then subsequent moves may in some cases choose different equally"
            +
            " good improving moves and the final solutions differ. Both 2-opt*"
            " implementations still work properly.")
        sol = _get_random_solution(self.d, self.C)
        _compare_improved_from_solution(self,
                                        sol,
                                        self.D,
                                        self.d,
                                        self.C,
                                        None, [do_2optstar_move, do_2opt_move],
                                        [do_naive_2optstar_move],
                                        extra_msg=special_case_fails_message,
                                        operator_strategy=LSOPT.FIRST_ACCEPT)

        # Test with L constraint
        max_L = max(objf(r, self.D) for r in sol2routes(sol))
        _compare_improved_from_solution(self,
                                        sol,
                                        self.D,
                                        self.d,
                                        self.C,
                                        max_L,
                                        [do_2optstar_move, do_2opt_move],
                                        [do_naive_2optstar_move],
                                        extra_msg=special_case_fails_message,
                                        operator_strategy=LSOPT.FIRST_ACCEPT)
예제 #3
0
    def gilletMiller(self, runFromJson, input=None):
        runFromJson = True

        with open('request.json') as jsonFile:
            data = jsonFile.read()
        options = json.loads(data)

        if runFromJson == False:
            pass

        print("capacity_of_the_bus = ", options["capacity_of_the_bus"])
        points = input["points"] if runFromJson != True else options["points"]

        full_distance_matrix = input[
            "full_distance_matrix"] if runFromJson != True else options[
                "full_distance_matrix"]

        full_distance_matrix = numpy.array(full_distance_matrix)

        for i in range(full_distance_matrix.shape[0]):
            for j in range(i, full_distance_matrix.shape[1]):
                full_distance_matrix[i, j] = full_distance_matrix[j, i]

        pupils_on_each_bus_stop = input[
            "pupils_on_each_bus_stop"] if runFromJson != True else options[
                "pupils_on_each_bus_stop"]

        capacity_of_the_bus = input[
            "capacity_of_the_bus"] if runFromJson != True else options[
                "capacity_of_the_bus"]

        constraint = input["CONSTRAINT"]
        minimize_number_of_buses = False

        loader = Loader("Running Heuristics...", "Heuristics Done!",
                        0.1).start()
        solution = gillet_miller_init(points=points,
                                      D=full_distance_matrix,
                                      d=pupils_on_each_bus_stop,
                                      C=capacity_of_the_bus,
                                      L=constraint,
                                      minimize_K=minimize_number_of_buses)
        loader.stop()

        ROUTES = []

        loader.__init__("Preparing Response", "Response ready!!", timeout=0.1)
        loader.start()

        for route_idx, route in enumerate(sol2routes(solution)):
            print("Route #%d : %s" % (route_idx + 1, route))
            ROUTES.append({"routeId": route_idx + 1, "stops": route})

        loader.stop()

        with open("response.json", "w") as outfile:
            json.dump({"success": True, "data": {"routes": ROUTES}}, outfile)

        return ROUTES
def _normalise_route_order(sol):
    routes = sol2routes(sol)
    # make sure route nodes are directed so that smaller end point is first
    for route in routes:
        if route[1] > route[-2]:
            route.reverse()
    # make sure routes are from smallest first node first
    routes.sort()
    return routes2sol(routes)
 def setUp(self):
     N = TestRandomStressOn3OptStarSolutionOperator.problem_size
     problem = generate_CVRP(N, 50, 10, 5)
     aN,pts,d,D,C = (problem.size, problem.coordinate_points,
                     problem.customer_demands, problem.distance_matrix,
                     problem.capacity_constraint)
     pts = None
     d = [int(dv) for dv in d]
     D = D.astype(int)
     problem = aN,pts,d,D,C
     
     self.naive_sol = routes2sol( [[n] for n in range(1,aN+1)] )
     self.nn_sol = nearest_neighbor_init(D, d, C)
     self.L = max( calculate_objective(r,D) for r in sol2routes(self.nn_sol) )
     self.N = aN
     self.problem = (aN,pts,d,D,C)
예제 #6
0
def print_solution_statistics(sol,
                              D,
                              D_cost,
                              d,
                              C,
                              L=None,
                              service_time=None,
                              verbosity=-1):
    print("\nSOLUTION:", sol)
    cover_ok, capa_ok, rlen_ok = cvrp_ops.check_solution_feasibility(
        sol, D_cost, d, C, L, True)

    if verbosity > 1:
        print("ALL SERVED:", cover_ok)
        if C:
            print("IS C FEASIBLE:", capa_ok)
        if L:
            print("IS L FEASIBLE:", rlen_ok)
    else:
        print("FEASIBLE:", cover_ok and capa_ok and rlen_ok)
    print("SOLUTION K:", sol.count(0) - 1)

    sol_f = None if D is None else objf(sol, D)
    sol_c = None if D_cost is None else objf(sol, D_cost)
    if (verbosity > 0 and sol_f != sol_c) or (not sol_c):
        print("SOLUTION COST:", sol_c, "\n")
    if sol_c:
        print("SOLUTION LENGTH:", sol_f)

    if verbosity > 1:
        routes = sol2routes(sol)
        print("ROUTES:")
        print("No.\tCost\tLength\tLoad\tRoute")
        for i, route in enumerate(routes):
            print(i + 1,
                  "%.2f" % objf(route, D_cost),
                  "%.2f" % objf(route, D),
                  sum((d[n] for n in route)) if C else "-",
                  route,
                  sep='\t')
        print("Total",
              "%.2f" % objf(sol, D_cost),
              "%.2f" % objf(sol, D),
              sep='\t')
 def test_improve_random_solution_first_accept(self):
     special_case_fails_message = ("NOTE: This may sometimes fail due to"+
      " how the naive implementation checks first all insertion positions"+
      " for one customer before moving on to next, while the local search"+
      " Implementation checks all intra route moves first and then the"+
      " inter route moves. If there is equally good move in intra and inter"+
      " route moves, it may be that both implementations do not select the"+
      " same one.")
     sol = _get_random_solution(self.d,self.C)
     _compare_improved_from_solution(
         self, sol, self.D,self.d,self.C,None,
         [do_relocate_move, do_1point_move], [do_naive_1point_move],
         extra_msg=special_case_fails_message,
         operator_strategy=LSOPT.FIRST_ACCEPT)
     
     # Test with L constraint        
     max_L = max( objf(r,self.D) for r in sol2routes(sol) )
     _compare_improved_from_solution(
         self, sol, self.D,self.d,self.C,max_L,
         [do_relocate_move, do_1point_move], [do_naive_1point_move],
         extra_msg=special_case_fails_message,
         operator_strategy=LSOPT.FIRST_ACCEPT)
예제 #8
0
파일: lr3opt.py 프로젝트: yorak/VeRyPy
def _force_feasible(sol, D, d, C, L):
    # Force an incomplete solution feasible
    feasible_routes = []
    routes = sol2routes(sol)
    for r in routes:
        feasibler, totald, totall = [0], 0.0, 0.0
        prevn = 0
        for n in r[1:]:
            C_violated = (C and totald + d[n] - C_EPS > C)
            L_violated = (L and totall + D[prevn, n] + D[n, 0] - S_EPS > L)
            if (n == 0 or C_violated or L_violated) and len(feasibler) > 1:
                feasibler.append(0)
                feasible_routes.append(feasibler)
                feasibler, totald, totall = [0], 0.0, 0.0
                prevn = 0
            if C:
                totald += d[n]
            if L:
                totall += D[prevn, n]
            if n != 0:
                feasibler.append(n)
            prevn = n
    return routes2sol(feasible_routes)
예제 #9
0
파일: lr3opt.py 프로젝트: yorak/VeRyPy
def lr3opt_init(D,
                d,
                C,
                L,
                initial_lambda1_C=None,
                initial_lambda1_L=None,
                initialization_algorithm=_init_with_tsp,
                postoptimize_with_3optstar=True,
                max_concecutive_lamba_incs=None):
    """ An implementation of the Stewart & Golden [1]_ 3-opt* heuristic
    with Lagrangean relaxation.
    
    The algorithm starts from a solution that can be either feasible or
    infeasible and uses local search to move towards better and feasible 
    solutions. More specifically, it works by replacing the constraint checks 
    of the 3-opt* with a penalty that depends on how much the constraint was 
    violated. The 3-opt* that operates on the entire solution, that is, checks 
    for both intra and inter route moves on one pass, was used. The penalties
    are iteratively doubled as the local search progresses and it is assumed
    that this eventually forces the solutions to feasible region.

    .. [1] Stewart, W. R. and Golden, B. L. (1984). A lagrangean relaxation 
           heuristic for vehicle routing. European Journal of Operational
           Research, 15(1):84–88.
    
    Parameters
    ----------
    D : numpy.ndarray
        is the full 2D distance matrix.
    d : list
        is a list of demands. d[0] should be 0.0 as it is the depot.
    C : float
        is the capacity constraint limit for the identical vehicles.
    L : float
        is the optional constraint for the maximum route length/duration/cost.
    
    initial_lambda1_C : float
        is the initial Langrange multiplier value for the capacity constraint C.
        If left empty (None) the formula ``l1_C=average(d)/(20*max(D))`` is used.
        The alternative value suggested by Stewart & Golden (1984) was 0.05.
    initial_lambda1_L : float
        is the initial Langrange multiplier value for the maximum route cost/
        duration/length constraint. If left empty (None) the formula
        ``l1_L=average(distance to nearest neighbor)/(10*max(D))`` is used.
    initialization_algorithm (function): is a function that retuns a TSP or VRP 
        solution and its objective function value. The default is to use LKH TSP 
        solution, but the function _init_with_random can be used to replicate the
        results of Stewart & Golden (1984) where a random solution is used.
    
    Returns
    -------
    list
        The solution as a list of node indices to visit.
    
    .. todo:: due to how the algorithm works, introducing minimize_K would require
    balancing between penalizing constraint violations and penalizing new 
    routes with an additional multipiler. This was not implemented.
    """

    sol = None
    try:
        ## STEP 1: Generate an initial solution
        sol, initial_f = initialization_algorithm(D, d, C, L)

        max_D = None
        lambdas = [initial_lambda1_C, initial_lambda1_L]
        if C and lambdas[0] == None:
            max_D = _get_max(D, sol)
            lambdas[0] = np.average(d) / (20 * max_D)
        if L and lambdas[1] == None:
            # Stewart & Golden (1984) did not propose an extension for the maximum
            #  route duration/length/cost constraint, but here we have something
            #  similar to L than they used for C constraint relaxation.
            max_D = _get_max(D, sol) if (max_D is None) else max_D
            closest_neighbor_D = D.copy()
            np.fill_diagonal(closest_neighbor_D, max_D)
            lambdas[1] = np.average(
                closest_neighbor_D.min(axis=0)) / (10 * max_D)

        if __debug__:
            log(
                DEBUG,
                "Start from initial solution %s (%.2f), and with l1=%.2f, l2=%.2f"
                % (sol, calculate_objective(sol, D),
                   (0 if lambdas[0] is None else lambdas[0]),
                   (0 if lambdas[1] is None else lambdas[1])))

        checker_function = partial(_check_lr3opt_move, lambdas=lambdas)

        # STEP 2: Solve the relaxed problem using 3-opt*
        c_lambda_incs = 0
        while True:
            # Make sure there is an empty route (for giving the 3-opt* procedure
            #  the option of adding vehicles)
            while not (sol[-1] == 0 and sol[-2] == 0):
                sol += [0]

            if __debug__:
                log(
                    DEBUG - 2, "Finding a LR3OPT move for %s (%.2f)" %
                    (sol, calculate_objective(sol, D)))
            new_sol, delta = do_3optstar_move(sol,
                                              D,
                                              d,
                                              C,
                                              L,
                                              strategy=LSOPT.FIRST_ACCEPT,
                                              move_checker=checker_function)

            # local optima reached, tighten the relaxation
            # TODO: it should not happen that the sol==new_sol. However it happens and as a quickfix check for it.
            if delta is None or sol == new_sol:
                # return the first feasible solution (note: does not check for covering)
                if fast_constraint_check(sol, D, d, C, L):
                    if __debug__:
                        log(
                            DEBUG, "Reached feasible solution %s (%.2f)" %
                            (sol, calculate_objective(sol, D)))
                    while postoptimize_with_3optstar:
                        opt_sol, delta = do_3optstar_move(
                            sol, D, d, C, L, strategy=LSOPT.FIRST_ACCEPT)
                        if delta is None:
                            return normalize_solution(
                                sol)  # remove any [0,0]'s
                        else:
                            sol = opt_sol
                            #print("REMOVEME improved with post-optimization 3-opt*")
                            log(
                                DEBUG,
                                "Found improving 3-opt* move leading to %s (%.2f)"
                                % (sol, calculate_objective(sol, D)))

                    return normalize_solution(sol)  # remove any [0,0]'s
                else:
                    # STEP 3: Update lambdas
                    lambda_at_inf = False
                    if lambdas[0] is not None:
                        lambdas[0] = lambdas[0] * 2
                        lambda_at_inf = lambdas[0] == float('inf')
                    if lambdas[1] is not None:
                        lambdas[1] = lambdas[1] * 2
                        lambda_at_inf = lambda_at_inf or lambdas[0] == float(
                            'inf')
                    if __debug__:
                        log(
                            DEBUG - 1,
                            "No improving moves left, increasing lambda to l1=%.2f, l2=%.2f"
                            % ((0 if lambdas[0] is None else lambdas[0]),
                               (0 if lambdas[1] is None else lambdas[1])))
                    #print("No improving moves left, increasing lambda to l1=%.2f, l2=%.2f"%
                    #        ((0 if lambdas[0] is None else lambdas[0]),
                    #         (0 if lambdas[1] is None else lambdas[1])))

                    #TODO: if penalty >> cost, break (stuck on a infeasible region)
                    # how much bigger can be determined by finding such a
                    # pathological problem instance?

                    # safeguard for getting stuck
                    c_lambda_incs += 1
                    #print("REMOVEME: c_lambda_incs", c_lambda_incs)
                    if lambda_at_inf or (
                            max_concecutive_lamba_incs is not None
                            and c_lambda_incs > max_concecutive_lamba_incs):
                        return _force_feasible(sol, D, d, C, L)

            else:
                if __debug__:
                    log(
                        DEBUG,
                        "Found improving LR3OPT move leading to %s (%.2f)" %
                        (new_sol, calculate_objective(new_sol, D)))
                    log(
                        DEBUG - 2, "However, routes %s remain infeasible." % [
                            r for r in sol2routes(new_sol)
                            if not fast_constraint_check(r, D, d, C, L)
                        ])

                sol = new_sol
                c_lambda_incs = 0

    except KeyboardInterrupt:  # or SIGINT
        # Pass on the current solution forced feasbile by splitting routes
        #  according to the constraints.
        raise KeyboardInterrupt(_force_feasible(sol, D, d, C, L))

    return without_empty_routes(sol)
예제 #10
0
def _calculate_penalty(sol_or_route, D, d, C):
    penalty = 0
    routes = sol2routes(sol_or_route)
    for r in routes:
        penalty += C - totald(r, d) * objf(r, D)
    return penalty
예제 #11
0
def tyagi_init(D,
               d,
               C,
               L=None,
               only_large_and_close_customer_single_routes=False,
               try_interchange_with_all_group_customers=True,
               select_grouping="min_penalty"):
    """ This is an implementation of the Tyagi (1968) nearest neighbor 
    heurstic. In the first phase the method distributes customers into groups
    using bulding a nearest neighbor chains leaving from the depot. The group
    is deemed complete when a constraint is violated. Then an interchange 
    heuristic tries to remove one node from the group so that the one left out 
    can be fitted. This interchange is done if the demand of the route 
    increases due to the swap. If a group with only one customer is generated, 
    all of the candidates that are close to the depot and have large demand are 
    considered to be served with a route with a single customer. Furthermore 
    the entire procedure is repeated for all single customer route candidates 
    and the one that has "maximum use of the capacity" is used (see option 
    select_grouping). Then a TSP procedure is used to route the customer
    groups. This this implementation uses 3-Opt local search to do the routing 
    instead of the greedy TSP heuristic described in Tyagi (1968).
    
    The procedure above is used when the function is called with parameters:
     * only_large_and_close_customer_single_routes = True,
     * try_interchange_with_all_group_customers = False,
     * select_grouping = "max_demand"
    The "max_demand" selects the grouping where the non-single routes carry
    most capacity.
      
    However, these settings do not greate the grouping nor solution presented
    as an illustrative example in Tyagi (1968). It seems he uses different
    undocumented variant of his heuristic to solve the 12 customer problem
    from Dantzig and Ramser (1958). Therefore, following changes and options 
    were added, and can be used, to replicate the result:
     * only_large_and_close_customer_single_routes = False, which allows any 
        customer be served with a single customer route. 
     * try_interchange_with_all_group_customers = True, which tries to do the
        interchange with all of the nodes in a group (proto-route), instead of
        trying just the first and last customers.
     * select_grouping = "balanced", which selects the most balanced
        alternative among the grouping candidates with single customer route.
        Here, only the non-single customer routes are considered.
    Alternatively, another option for selecting grouping (which more closely
    follows the idea of Tyagi) can be used:
     * select_grouping = "min_penalty", which selects the option where 
        the routes with lot of free capacity are shortest (individual edges 
        or the used vehicle capacity when traversing them are not considered).
        This is calculated on the optimized routes.
        
    Note that if C is not set the select_grouping and its functionality is not
     used.
    
    With these options the grouping of customers given in illustrative
    example is replicated and as is the solution quality. Unfortunately it 
    is impossible to say if the modifications are the ones Tyagi (1968) used.
        
    Tyagi, M.S. (1968), "A Practical Method for Truck Dispatching Problem",
        J. Operations Research Society of Japan, 10, 76-92.
    Dantzig, G. B., & Ramser, J. H. (1959), "The truck dispatching problem",
        Management science, 6(1), 80-91.
    Helsgaun, K. (2006), "An Effective Implementation of K-opt Moves for the 
      Lin-Kernighan TSP Heuristic." DATALOGISKE SKRIFTER, No. 109, 2006. 
      Roskilde University.
    Helsgaun, K. (2009), "General k-opt submoves for the Lin-Kernighan TSP 
      heuristic." Mathematical Programming Computation, 1(2), 119-163.    
    """

    ## 0. Determine the number of vehicles
    may_have_single_node_route = False
    if C:
        tot_d = sum(d)
        K = ceil(tot_d / float(C))
        may_have_single_node_route = min(d[1:]) > tot_d - C * (K - 1)

    ## 1. "Grouping the delivery points" (nodes) to routes with nearest nbour.
    interchange_variant = lambda r, r_d, r_l, D, d, C, L, svd, nnn : \
        route_end_interchange(r, r_d, r_l, D, d, C, L, svd, nnn,
                              try_interchange_with_all_group_customers)
    solution = \
        nearest_neighbor_init(D, d, C, L,
                              initialize_routes_with=TYAGI_SEED_METHOD,
                              emerging_route_count=1, add_only_to_end=True,
                              route_improvement_callback=interchange_variant)

    routes = sol2routes(solution)

    if not C:
        best_C_utilization = None
    elif select_grouping == "balanced":
        # the best will be one that will have balanced routes
        best_C_utilization = \
            _calculate_route_demand_statistics(solution, d, K=len(routes))
    elif select_grouping == "max_demand":
        # the best will be the one that is best to top up the vehicle capacity
        best_C_utilization = sum(d[n]
                                 for n in solution) / float(len(routes) * C)
    elif select_grouping == "min_penalty":
        # the best will be the one with least distance traveled with unused capacity
        best_C_utilization = _calculate_penalty(solution, D, d, C)
    else:
        raise ValueError('"Invalid select_grouping parameter "%s"' %
                         select_grouping)

    if __debug__:
        if C:
            log(DEBUG - 1, "Initial Grouping = %s\n" % (solution))

    ## Tyagi heuristic has a special case for the single node routes
    try:
        single_nodes = [r[1] for r in routes if len(r) == 3]
        if C and (may_have_single_node_route or len(single_nodes) > 0):
            N = len(D)
            best_K = solution.count(0) - 1

            if only_large_and_close_customer_single_routes:
                # According to Tyagi1967, only the large demand nodes close to the
                #  depot are considered ...
                max_dist_from_depot = max(D[0, :])
                candidates = [n for n in range(1,N) \
                          if (d[n]>0.5*C and D[0,n]<0.5*max_dist_from_depot)]
            else:
                # ... however, using this criteria does not allow replicating the
                #  results (the illustrative example) of the paper. Therefore,
                #  there is an option to try with complete set of nodes.
                candidates = list(range(1, len(D)))

            for single_route_candidate in candidates:
                if __debug__:
                    log(
                        DEBUG - 2, "Try to find grouping with n%d forbidden" %
                        (single_route_candidate))
                cndt_sol = nearest_neighbor_init(
                    D,
                    d,
                    C,
                    L,
                    initialize_routes_with=TYAGI_SEED_METHOD,
                    emerging_route_count=1,
                    forbidden_nodes=[single_route_candidate],
                    route_improvement_callback=interchange_variant)

                cndt_K = cndt_sol.count(
                    0) - 1 + 1  #the single_route_candidate_node
                if cndt_K > best_K:
                    if __debug__:
                        log(DEBUG - 1, "No valid grouping found\n")

                    continue

                if select_grouping == "balanced":
                    cndt_C_utilization = \
                        _calculate_route_demand_statistics(cndt_sol, d, K=cndt_K-1)
                elif select_grouping == "max_demand":
                    cndt_C_utilization = sum(d[n] for n in cndt_sol) / float(
                        cndt_K * C)
                elif select_grouping == "min_penalty":
                    cndt_C_utilization = _calculate_penalty(cndt_sol, D, d, C)

                if __debug__:
                    log(
                        DEBUG - 1, "Grouping = %s (utilization %s)\n" %
                        (cndt_sol + [single_route_candidate, 0],
                         str(cndt_C_utilization)))

                # select the one with maximum possible use of carrier capacity
                if cndt_C_utilization > best_C_utilization:
                    best_C_utilization = cndt_C_utilization
                    solution = cndt_sol + [single_route_candidate, 0]
                    routes = sol2routes(solution)

        ## 2. "Finding the optimal tours"
        #instead of the heuristic of Tyagi, just solve it with a TSP solver
        if __debug__:
            log(
                DEBUG - 1, "Post-optimize solution %s (%.2f)" %
                (solution, objf(solution, D)))
        for i in range(len(routes)):
            routes[i], route_f = solve_tsp(D, routes[i][:-1])

            if __debug__:
                log(DEBUG - 2,
                    "Got TSP solution %s (%.2f)" % (str(routes[i]), route_f))
    except KeyboardInterrupt:  #or SIGINT
        raise KeyboardInterrupt(solution)

    return routes2sol(routes)
예제 #12
0
def _process_savings_debug_line(
        line,
        normalization_parameters,
        currentK,
        #output here
        rays,
        active_nodes,
        active_ray_idxs,
        points_of_interest,
        candidate_routes,
        infeasible_routes,
        complete_routes,
        labels):

    global to_restore_routes

    newK = None
    changed = False

    mmo = merged_re.search(line)
    if mmo:
        infeasible_routes[:] = []
        complete_routes[:] = sol2routes(eval(mmo.group(1)))
        to_restore_routes = list(complete_routes)
        changed = True

    pmo = popped_re.search(line)
    if pmo:
        complete_routes[:] = to_restore_routes
        active_nodes[:] = [int(pmo.group(1)), int(pmo.group(2))]
        changed = False

    if SHOW_INFEASIBLE and "Reject merge due" in line:
        left_merge_node, right_merge_node = active_nodes[0], active_nodes[1]
        left_route_idx, right_route_idx = None, None
        for ri, r in enumerate(complete_routes):
            if left_merge_node in r:
                left_route_idx = ri
            if right_merge_node in r:
                right_route_idx = ri

        # make the merged route

        if complete_routes[left_route_idx][1]==left_merge_node and\
           complete_routes[right_route_idx][1]==right_merge_node:
            infeasible_routes[:] = [
                complete_routes[left_route_idx][:0:-1] +
                complete_routes[right_route_idx][1:]
            ]
        elif complete_routes[left_route_idx][1]==left_merge_node and\
             complete_routes[right_route_idx][-2]==right_merge_node:
            infeasible_routes[:] = [
                complete_routes[left_route_idx][:0:-1] +
                complete_routes[right_route_idx][-2::-1]
            ]
        elif complete_routes[left_route_idx][-2]==left_merge_node and\
             complete_routes[right_route_idx][1]==right_merge_node:
            infeasible_routes[:] = [
                complete_routes[left_route_idx][:-1] +
                complete_routes[right_route_idx][1:]
            ]
        elif complete_routes[left_route_idx][-2]==left_merge_node and\
             complete_routes[right_route_idx][-2]==right_merge_node:
            infeasible_routes[:] = [
                complete_routes[left_route_idx][:-1] +
                complete_routes[right_route_idx][-2::-1]
            ]
        complete_routes[left_route_idx] = []
        complete_routes[right_route_idx] = []

        #print "REMOVEME", left_route_idx, right_route_idx, infeasible_routes

        changed = True

    return changed, newK
예제 #13
0
    pprint(D)
elif args.D:
    D = pickle.load(args.D)
else:
    assert (False)  # argparse should take care that we never arrive here
    pass

## Solve the related CVRP using VeRyPy ##
if args.C:
    from classic_heuristics.parallel_savings import parallel_savings_init
    from util import sol2routes

    if locations:
        d = [loc["demand"] for loc in locations]
    else:
        d = [0.] + [1.0] * (len(D) - 1)
        if args.verbose:
            sys.stderr.write(
                "WARNING: Setting all goods demands to be 1.0 (no data).\n")

    if args.verbose:
        sys.stderr.write(
            "INFO: Solving a %d customer CVRP with Savings heuristic.\n" %
            (len(locations) - 1))

    # Solve and print the resulting routes
    solution = parallel_savings_init(D=D, d=d, C=args.C)
    print("\nCorresponding CVRP solution is")
    for route_idx, route in enumerate(sol2routes(solution)):
        print("Route #%d : %s" % (route_idx + 1, route))