예제 #1
0
def test_add_repair_operator():
    """
    Tests if adding a repair operator correctly updates the number of
    operators available on the ALNS instance.
    """
    alns = ALNS()

    for count in [1, 2]:
        alns.add_repair_operator(lambda state, rnd: None)
        assert_equal(len(alns.repair_operators), count)
예제 #2
0
def test_add_destroy_operator():
    """
    Tests if adding a destroy operator correctly updates the number of
    operators available on the ALNS instance.
    """
    alns = ALNS()

    for count in [1, 2]:
        alns.add_destroy_operator(lambda state, rnd: None, name=str(count))
        assert_equal(len(alns.destroy_operators), count)
예제 #3
0
def main():
    if len(sys.argv) < 2:
        raise ValueError(f"{sys.argv[0]}: expected file location.")

    problem = Problem.from_file(sys.argv[1], delimiter=',')

    alns = ALNS(default_rng(problem.instance))

    for op in D_OPERATORS:
        alns.add_destroy_operator(op)

    for op in R_OPERATORS:
        alns.add_repair_operator(op)

    local_search = LocalSearch()

    for op in SOLUTION_OPERATORS:
        local_search.add_solution_operator(op)

    for op in ROUTE_OPERATORS:
        local_search.add_route_operator(op)

    alns.on_best(local_search)

    init = initial_solution()
    result = alns.iterate(init, WEIGHTS, DECAY, CRITERION, ITERATIONS)

    # noinspection PyTypeChecker
    solution: Solution = result.best_state
    solution.to_file(f"solutions/oracs_{problem.instance}.csv")
예제 #4
0
파일: test_alns.py 프로젝트: zsunpku/ALNS
def test_add_destroy_operator_name():
    """
    Tests if adding a destroy operator without an explicit name correctly
    takes the function name instead.
    """
    def destroy_operator():  # placeholder
        pass

    alns = ALNS()

    alns.add_destroy_operator(destroy_operator)

    name, operator = alns.destroy_operators[0]

    assert_equal(name, "destroy_operator")
    assert_(operator is destroy_operator)
예제 #5
0
파일: test_alns.py 프로젝트: zsunpku/ALNS
def test_add_repair_operator_name():
    """
    Tests if adding a repair operator without an explicit name correctly
    takes the function name instead.
    """
    def repair_operator():  # placeholder
        pass

    alns = ALNS()

    alns.add_repair_operator(repair_operator)

    name, operator = alns.repair_operators[0]

    assert_equal(name, "repair_operator")
    assert_(operator is repair_operator)
예제 #6
0
def test_add_operator_same_name_warns_per_type():
    """
    Adding an operator with the same name as an already added operator (of the
    same type) should warn that the previous operator will be overwritten.
    """
    alns = ALNS()

    with assert_no_warnings():
        # The same name is allowed for different types of operators.
        alns.add_destroy_operator(lambda state, rnd: None, "test")
        alns.add_repair_operator(lambda state, rnd: None, "test")

    with assert_warns(OverwriteWarning):
        # Already exists as a destroy operator.
        alns.add_destroy_operator(lambda state, rnd: None, "test")

    with assert_warns(OverwriteWarning):
        # Already exists as a repair operator.
        alns.add_repair_operator(lambda state, rnd: None, "test")
예제 #7
0
def main():
    if len(sys.argv) < 2:
        raise ValueError(f"{sys.argv[0]}: expected file location.")

    problem = Problem.from_file(sys.argv[1])

    alns = ALNS(default_rng(problem.instance))

    for op in D_OPERATORS:
        alns.add_destroy_operator(op)

    for op in R_OPERATORS:
        alns.add_repair_operator(op)
예제 #8
0
def main():
    args = parse_args()

    Problem.from_instance(args.experiment, args.instance)

    if args.experiment == "tuning":
        generator = rnd.default_rng(args.instance)
    else:
        # E.g. for exp 72 and inst. 1, this becomes 7201. This way, even for
        # inst. 100, there will never be overlap between random number streams
        # across experiments.
        generator = rnd.default_rng(100 * args.experiment + args.instance)

    alns = ALNS(generator)  # noqa

    for operator in DESTROY_OPERATORS:
        if args.exclude == operator.__name__:
            continue

        alns.add_destroy_operator(operator)

    for operator in REPAIR_OPERATORS:
        if args.exclude == operator.__name__:
            continue

        alns.add_repair_operator(operator)

    if args.exclude == "reinsert_learner":
        alns.on_best(reinsert_learner)

    init = initial_solution()
    criterion = get_criterion(init.objective())
    result = alns.iterate(init, WEIGHTS, DECAY, criterion, ITERATIONS)

    location = f"experiments/{args.experiment}/{args.instance}-heuristic.json"
    result.best_state.to_file(location)  # noqa
예제 #9
0
def get_alns_instance(repair_operators=None, destroy_operators=None, seed=None):
    """
    Test helper method.
    """
    alns = ALNS(rnd.RandomState(seed))

    if repair_operators is not None:
        for idx, repair_operator in enumerate(repair_operators):
            alns.add_repair_operator(repair_operator, name=str(idx))

    if destroy_operators is not None:
        for idx, destroy_operator in enumerate(destroy_operators):
            alns.add_destroy_operator(destroy_operator, name=str(idx))

    return alns
예제 #10
0
def get_alns_instance(repair_operators=None,
                      destroy_operators=None,
                      seed=None):
    """
    Test helper method.
    """
    alns = ALNS(rnd.RandomState(seed))

    if repair_operators is not None:
        for repair_operator in repair_operators:
            alns.add_repair_operator(repair_operator)

    if destroy_operators is not None:
        for destroy_operator in destroy_operators:
            alns.add_destroy_operator(destroy_operator)

    return alns
예제 #11
0
def solve_cvrp_with_alns(seed=SEED,
                         size=SIZE,
                         capacity=CAPACITY,
                         number_of_depots=NUMBER_OF_DEPOTS,
                         iterations=ITERATIONS,
                         collect_statistics=COLLECT_STATISTICS,
                         draw=False,
                         **kwargs):
    weights = WEIGHTS
    operator_decay = OPERATOR_DECAY
    start_temperature_control = settings.START_TEMPERATURE_CONTROL
    cooling_rate = settings.COOLING_RATE
    end_temperature = settings.END_TEMPERATURE

    verbose = False

    if 'weights' in kwargs:
        weights = kwargs['weights']
    if 'operator_decay' in kwargs:
        operator_decay = kwargs['operator_decay']
    if 'start_temperature_control' in kwargs:
        start_temperature_control = kwargs['start_temperature_control']
    if 'cooling_rate' in kwargs:
        cooling_rate = kwargs['cooling_rate']
    if 'end_temperature' in kwargs:
        end_temperature = kwargs['end_temperature']
    if 'verbose' in kwargs:
        verbose = kwargs['verbose']

    cvrp_instance = generate_cvrp_instance(size, capacity, number_of_depots,
                                           seed)
    if verbose:
        print("Created CVRP graph")
    # Create an empty state
    initial_state = CvrpState(cvrp_instance,
                              collect_alns_statistics=collect_statistics,
                              size=size,
                              number_of_depots=number_of_depots,
                              capacity=capacity)
    if verbose:
        print("Created CVRP state.\nGenerating initial solution... ",
              end='',
              flush=True)
    initial_solution = generate_initial_solution(initial_state)
    if verbose:
        print("done !")
    initial_distance = initial_solution.objective()
    if draw:
        initial_solution.draw()
    number_of_node_features = len(
        initial_solution.dgl_graph.ndata['n_feat'][0])
    number_of_edge_features = len(
        initial_solution.dgl_graph.edata['e_feat'][0])

    # Initialize ALNS
    random_state = rnd.RandomState(seed)
    alns = ALNS(random_state)
    # ml_removal_heuristic = define_ml_removal_heuristic(number_of_node_features, number_of_edge_features,
    #                                                    NETWORK_PARAMS_FILE, NETWORK_GCN)
    # ml_removal_heuristic = define_ml_removal_heuristic(number_of_node_features, number_of_edge_features,
    #                                                    'GatedGCN_ep71.pkl', NETWORK_GATEDGCN)
    alns.add_destroy_operator(removal_heuristic)
    alns.add_repair_operator(greedy_insertion)

    initial_temperature = compute_initial_temperature(
        initial_distance, start_temperature_control)
    criterion = SimulatedAnnealing(initial_temperature, end_temperature,
                                   cooling_rate)

    # Solve the cvrp using ALNS

    print("Starting ALNS, with {} iterations".format(iterations), flush=True)
    time_start = time.time()
    result = alns.iterate(initial_solution,
                          weights,
                          operator_decay,
                          criterion,
                          iterations=iterations,
                          collect_stats=collect_statistics)
    time_end = time.time()
    print("ALNS finished in {:.1f} seconds".format(time_end - time_start),
          flush=True)
    solution = result.best_state
    print("Initial objective : {:.4f}".format(initial_distance))
    print("Solution objective : {:.4f}".format(solution.objective()))
    if draw:
        solution.draw()

    # Create the statistics if necessary
    solution_data = {}
    if solution.collect_alns_statistics:
        solution_data = {
            'Size': solution.size,
            'Number_of_depots': solution.number_of_depots,
            'Capacity': solution.capacity,
            'Seed': seed,
            'Parameters': {
                'decay': operator_decay,
                'degree_destruction': DEGREE_OF_DESTRUCTION,
                'determinism': DETERMINISM
            }
        }
        solution_statistics = [{
            'destroyed_nodes':
            solution.statistics['destroyed_nodes'][i],
            'objective_difference':
            result.statistics.objectives[i + 1] -
            result.statistics.objectives[i],
            'list_of_edges':
            solution.statistics['list_of_edges'][i]
        } for i in range(iterations)]
        solution_data['Statistics'] = solution_statistics

        if 'display_proportion_objective_difference' in kwargs and kwargs[
                'display_proportion_objective_difference']:
            number_of_elements_train_set = {0: 0, 1: 0, 2: 0}
            for stat in solution_statistics:
                if stat['objective_difference'] > EPSILON:
                    stat_class = 0
                elif abs(stat['objective_difference']) < EPSILON:
                    stat_class = 1
                else:
                    stat_class = 2
                number_of_elements_train_set[stat_class] += 1
            print("{:^20}{:^7.2%}{:^7.2%}{:^7.2%}\n\n".format(
                'Proportions',
                round(number_of_elements_train_set[0] / iterations, 4),
                round(number_of_elements_train_set[1] / iterations, 4),
                round(number_of_elements_train_set[2] / iterations, 4),
            ))

        if 'pickle_single_stat' in kwargs and kwargs['pickle_single_stat']:
            if 'file_path' in kwargs:
                pickle_alns_solution_stats(solution_data,
                                           file_path=kwargs['file_path'])
            else:
                pickle_alns_solution_stats(solution_data)

    return solution_data
예제 #12
0
if __name__ == '__main__':
    random_state = rnd.RandomState(seed)

    matplotlib.use('TkAgg')

    irp = ItemRecoveryProblem()
    try:
        instance_path = "./instances/" + str(sys.argv[1])
    except IndexError:
        instance_path = "./instances/" + str(instance_to_run)
        print("Executing hard-coded instance:", instance_to_run)

    irp.load_file(instance_path)

    alns = ALNS(random_state)
    alns.add_destroy_operator(remove_rand_pos)
    alns.add_destroy_operator(swap_rand_pos)
    alns.add_destroy_operator(remove_rand_sps)
    alns.add_destroy_operator(remove_worst_sps)
    alns.add_repair_operator(greedy_repair)

    initial_solution = greedy_repair(Solution(irp), random_state)
    print(instance_path)
    print("Initial solution:", int(initial_solution.get_cost()))
    #criterion = HillClimbing()
    criterion = SimulatedAnnealing(100, 5, 5, method='linear')
    start_time = time.time()
    result = alns.iterate(initial_solution, [3, 2, 1, 0.5],
                          0.8,
                          criterion,
예제 #13
0
def Large_Neighborhood_Search(Y):
    class TopKState(State):
        """
        Solution class for the top k worker task assignment problem, Series (vector) of tasks as index and workers as values
        the assignment quality matrix
        """
        def __init__(self, solution, AssQuality_matrix):
            self.solution = solution  # vector of tasks as indcies and workers as values
            self.tasks = solution.index
            self.workers = [
                self.solution[task] for task in self.solution.index
            ]
            self.L_dash = []  # to keep the removed workers list
            self.AssQuality_matrix = AssQuality_matrix  # the assignment values matrix A

        def copy(self):
            """
            Helper method to ensure each solution state is immutable.
            """
            return TopKState(self.solution.copy(),
                             self.AssQuality_matrix.copy())

        def objective(self):
            """
            The objective function is simply the sum of all Assignment qualities
            """
            value = 0.0
            for task in self.solution.index:
                if not pd.isna(self.solution[task]):
                    value += self.AssQuality_matrix.loc[task,
                                                        self.solution[task]]
            return -value

        def find_L(self):
            worker_lose = pd.Series()
            lose = pd.Series()
            for worker in self.workers:
                worker_lose[worker] = 0.0
                for task in self.tasks:
                    if (self.solution[task]) == worker:
                        worker_lose[worker] += self.AssQuality_matrix.loc[
                            task, worker]
                # total objective value (mins) the quality of the worker at hand
                lose.loc[worker] = self.objective() - (self.objective() -
                                                       worker_lose[worker])
                lose = lose.sort_values(ascending=True)
            return list(lose.index)

    """----------------------------------------------------------------------------"""
    """                              Destroy method                                """
    """----------------------------------------------------------------------------"""

    degree_of_destruction = random.random()  # Random float x, 0.0 <= x < 1.0

    def workers_to_remove(state):
        # How many worker to be removed based on the degree of destruction
        return int(len(state.workers) * degree_of_destruction)

    def worst_removal(current, random_state):
        """
        Worst removal iteratively removes the 'worst' workers, that is,
        those workers that have the lowest quality.
        """

        destroyed = current.copy()

        worst_workers = destroyed.find_L()  # L

        h = workers_to_remove(current)  # h the number of workers to be removed
        p = 5  # the parameter p set to 5 according to ref ----

        while (h > 0):
            for task in destroyed.tasks:
                z = random.random()  # random number in [0,1)
                E = int((z**p) * len(worst_workers))
                if destroyed.solution.loc[task] == worst_workers[
                        E]:  # try to find the worst worker
                    destroyed.solution.loc[
                        task] = np.nan  # set the task with the worst worker to NAN
                    destroyed.workers.remove(
                        worst_workers[E]
                    )  # remove the worst worker from the solution
                    destroyed.L_dash.append(worst_workers[E])
                    h = h - 1
        return destroyed

    """----------------------------------------------------------------------------"""
    """                              Repair method                                 """
    """----------------------------------------------------------------------------"""

    def greedy_repair(current, random_state):
        """
        Greedily repairs a solution,
        """
        # each worker has a capacity
        capacity = pd.Series()
        for worker in current.L_dash:
            capacity[worker] = 10

        current.L_dash = set(
            current.L_dash)  # L' the list of removed workers from Y'

        U_dash = []  # U' the list of unassigned task in  Y'

        for task in current.solution.index:
            if pd.isna(current.solution.loc[task]):
                U_dash.append(task)

        # the objective value of the destroyed solution
        objective_value_of_destroyed = current.objective()

        # find Delta fw,
        Delta_f = pd.DataFrame(index=[task for task in U_dash])

        for task in U_dash:
            for worker in current.L_dash:
                Delta_f.loc[
                    task,
                    worker] = (objective_value_of_destroyed +
                               current.AssQuality_matrix.loc[task, worker]
                               ) - objective_value_of_destroyed

        for task in U_dash:
            if (capacity[Delta_f.loc[task, :].idxmax()]) > 0:
                current.solution.loc[task] = Delta_f.loc[task, :].idxmax(
                )  # Get the BEST worker for the task at hand
                capacity[Delta_f.loc[
                    task, :].idxmax()] -= 1  # reduce the capacity by one
                if (capacity[Delta_f.loc[task, :].idxmax()]) == 0:
                    Delta_f.loc[:, Delta_f.loc[task, :].idxmax(
                    )] = 0.0  # Burn the Best worker (Best worker will not be chosen next time)

        return current

    AssQuality_matrix = pd.read_csv(
        "C:/Users/Arwa/Desktop/datasets/MOO/A_matrix.csv", index_col=0)
    AssQuality_matrix = AssQuality_matrix.fillna(0.0)
    random_state = rnd.RandomState(
        SEED
    )  #generating random numbers drawn from a variety of probability distributions
    state = TopKState(Y, AssQuality_matrix)

    initial_solution = greedy_repair(state, random_state)
    print("########################initial###########################",
          type(initial_solution))
    print("Initial solution objective is {0}.".format(
        initial_solution.objective()))
    """----------------------------------------------------------------------------"""
    """                              Heuristic solution                            """
    """----------------------------------------------------------------------------"""

    alns = ALNS(random_state)
    alns.add_destroy_operator(worst_removal)
    alns.add_repair_operator(greedy_repair)
    criterion = SimulatedAnnealing(
        1, 0.1, 0.6)  #'start_temperature', 'end_temperature', and 'step'

    result = alns.iterate(initial_solution, [3, 2, 1, 0.5],
                          0.8,
                          criterion,
                          iterations=100,
                          collect_stats=True)

    H_solution = result.best_state

    objective = H_solution.objective()

    print(
        "########################the best heuristic solution########################\n",
        H_solution.solution, "with objective value\n", objective)
    return H_solution.solution, objective