def test_accepts_better():
    for _ in range(1, 100):
        simulated_annealing = SimulatedAnnealing(2, 1, 1)

        assert_(
            simulated_annealing.accept(rnd.RandomState(), One(), Zero(),
                                       Zero()))
def test_accepts_equal():
    simulated_annealing = SimulatedAnnealing(2, 1, 1)

    for _ in range(100):
        # This results in an acceptance probability of exp{0}, that is, one.
        # Thus, the candidate state should always be accepted.
        assert_(
            simulated_annealing.accept(rnd.RandomState(), One(), One(), One()))
def test_raises_start_smaller_than_end():
    """
    The initial temperature at the start should be bigger (or equal) to the end
    temperature.
    """
    with assert_raises(ValueError):
        SimulatedAnnealing(0.5, 1, 1)

    SimulatedAnnealing(1, 1, 1)  # should not raise for equality
def test_raises_explosive_step():
    """
    For exponential updating, the step parameter must not be bigger than one,
    as that would result in an explosive threshold.
    """
    with assert_raises(ValueError):
        SimulatedAnnealing(2, 1, 2, "exponential")

    SimulatedAnnealing(2, 1, 1, "exponential")  # boundary should be fine
def test_exponential_random_solutions():
    """
    Checks if the exponential ``accept`` method correctly decides in two known
    cases for a fixed seed. This is the exponential equivalent to the linear
    random solutions test above.
    """
    simulated_annealing = SimulatedAnnealing(2, 1, 0.5, "exponential")

    state = rnd.RandomState(0)

    assert_(simulated_annealing.accept(state, Zero(), Zero(), One()))
    assert_(not simulated_annealing.accept(state, Zero(), Zero(), One()))
def test_raises_negative_parameters():
    """
    Simulated annealing does not work with negative parameters, so those should
    not be accepted.
    """
    with assert_raises(ValueError):  # start temperature cannot be
        SimulatedAnnealing(-1, 1, 1)  # negative

    with assert_raises(ValueError):  # nor can the end temperature
        SimulatedAnnealing(1, -1, 1)

    with assert_raises(ValueError):  # nor the updating step
        SimulatedAnnealing(1, 1, -1)
def test_linear_random_solutions():
    """
    Checks if the linear ``accept`` method correctly decides in two known cases
    for a fixed seed.
    """
    simulated_annealing = SimulatedAnnealing(2, 1, 1)

    state = rnd.RandomState(0)

    # Using the above seed, the first two random numbers are 0.55 and .72,
    # respectively. The acceptance probability is 0.61 first, so the first
    # should be accepted (0.61 > 0.55). Thereafter, it drops to 0.37, so the
    # second should not (0.37 < 0.72).
    assert_(simulated_annealing.accept(state, Zero(), Zero(), One()))
    assert_(not simulated_annealing.accept(state, Zero(), Zero(), One()))
def test_temperature_boundary():
    """
    The boundary case for the end temperature parameter is at zero, which must
    *not* be accepted, as it would result in a division-by-zero.
    """
    with assert_raises(ValueError):
        SimulatedAnnealing(1, 0, 1)
Exemple #9
0
def get_criterion(init_objective: float) -> SimulatedAnnealing:
    """
    Returns an SA object with initial temperature such that there is a 50%
    chance of selecting a solution up to 5% worse than the initial solution.
    The step parameter is then chosen such that the temperature reaches 1 in
    the set number of iterations.
    """
    start_temp = MAX_WORSE * init_objective / np.log(ACCEPTANCE_PROBABILITY)
    step = (1 / start_temp) ** (1 / ITERATIONS)

    return SimulatedAnnealing(start_temp, 1, step, method="exponential")
Exemple #10
0
def test_fixed_seed_outcomes():
    """
    Tests if fixing a seed results in deterministic outcomes even when using a
    'random' acceptance criterion (here SA).
    """
    outcomes = [0.01171, 0.00011, 0.01025]

    for seed, desired in enumerate(outcomes):  # idx is seed
        alns = get_alns_instance(
            [lambda state, rnd: ValueState(rnd.random_sample())],
            [lambda state, rnd: None],
            seed)

        simulated_annealing = SimulatedAnnealing(1, .25, 1 / 100)

        result = alns.iterate(One(), [1, 1, 1, 1], .5, simulated_annealing, 100)

        assert_almost_equal(result.best_state.objective(), desired, decimal=5)
def test_accepts_generator_and_random_state():
    """
    Tests if SimulatedAnnealing works with both Generator and RandomState
    randomness classes.

    See also https://numpy.org/doc/1.18/reference/random/index.html#quick-start
    """
    class Old:  # old RandomState interface mock
        def random_sample(self):  # pylint: disable=no-self-use
            return 0.5

    simulated_annealing = SimulatedAnnealing(2, 1, 1)
    assert_(simulated_annealing.accept(Old(), One(), One(), Zero()))

    class New:  # new Generator interface mock
        def random(self):  # pylint: disable=no-self-use
            return 0.5

    simulated_annealing = SimulatedAnnealing(2, 1, 1)
    assert_(simulated_annealing.accept(New(), One(), One(), Zero()))
def test_end_temperature():
    """
    Tests if the end_temperature parameter is correctly set.
    """
    for end in range(1, 100):
        assert_equal(SimulatedAnnealing(100, end, 1).end_temperature, end)
def test_start_temperature():
    """
    Tests if the start_temperature parameter is correctly set.
    """
    for start in range(1, 100):
        assert_equal(SimulatedAnnealing(start, 1, 1).start_temperature, start)
Exemple #14
0
import os

from alns.criteria import RecordToRecordTravel, SimulatedAnnealing

DEPOT = -1
TEAM_NUMBER = 3

if "TRAVIS" in os.environ:
    NEARNESS = 3
    DEGREE_OF_DESTRUCTION = 0.2
    WEIGHTS = [25, 5, 1, 1]
    DECAY = 0.6

    ITERATIONS = 1000
    CRITERION = RecordToRecordTravel(200, 0, step=200 / ITERATIONS)
else:
    # Use these to play around with - the above is for Travis runs, and should
    # not be changed too much.
    NEARNESS = 3
    DEGREE_OF_DESTRUCTION = 0.1
    WEIGHTS = [25, 10, 1, 0.8]
    DECAY = 0.9

    ITERATIONS = 25000
    CRITERION = SimulatedAnnealing(2000, 1, 0.999696, method="exponential")
Exemple #15
0
        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,
                          iterations=iterations,
                          collect_stats=True)
    end_time = time.time()
    solution = result.best_state
    print("Best solution:", int(solution.objective()))
    print("Time taken (s):", int(end_time - start_time))
    print("Iterations:", iterations)
    _, ax = plt.subplots(figsize=(12, 6))
    result.plot_objectives(ax=ax, lw=2)
    figure = plt.figure("method_counts", figsize=(14, 6))
    figure.subplots_adjust(bottom=0.15, hspace=.5)
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
def test_does_not_raise():
    """
    This set of parameters should work correctly.
    """
    SimulatedAnnealing(10, 5, 2)
def test_step():
    """
    Tests if the step parameter is correctly set.
    """
    for step in range(100):
        assert_equal(SimulatedAnnealing(1, 1, step).step, step)
Exemple #19
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