示例#1
0
def mutation_insert(flowshop, population, mutation_probability=0.4):
    """
    Returns a new population after mutation given an instance of the flowshop permutation problem, a population and a
    mutation probability (insert method)
    :param flowshop: a Flowshop object
    :param population: list of Ordonnancement objects
    :param mutation_probability: probability for each Ordonnancement object in the population to mutate
    :return: the population after mutation
    """
    nb_jobs = flowshop.nombre_jobs()
    mutated_population = []
    for sched in population:
        if random.random() < mutation_probability:
            sequence = sched.sequence().copy()
            indices = [i for i in range(nb_jobs)]
            elt_index, insert_index = random.sample(indices, 2)
            temp = sequence[elt_index]
            sequence.remove(temp)
            sequence.insert(insert_index, temp)

            mutated_sched = Ordonnancement(sched.nb_machines)
            mutated_sched.ordonnancer_liste_job(sequence)
            mutated_population.append(mutated_sched)
        else:
            mutated_population.append(sched)
    return mutated_population
def crossover_position(sched1, sched2):
    """
    crossing rules : two lists of jobs' positions : [2,3,5,1,4] & [3,4,1,2,5] the index of the lists are the jobs
    and the values are the positions. We sum the two lists : [5,7,6,3,9] and we rearenge it [2,4,3,1,5]
    :param sched1: the first parent
    :param sched2: the second parent
    :return: the new Ordonnancenement object
    """
    seq1 = sched1.sequence()
    seq2 = sched2.sequence()
    positionschild = [0] * len(seq1)
    for i in range(len(seq1)):
        job = seq1[i]
        positionschild[i] = seq1.index(job) + seq2.index(job)
    childseq = []
    for i in range(len(positionschild)):
        min_position = min(positionschild)
        indices_next_job = []
        for j in range(len(positionschild)):
            if positionschild[j] == min_position:
                indices_next_job.append(j)
        index_next_job = random.sample(indices_next_job, 1)[0]
        next_job = seq1[index_next_job]
        childseq.append(next_job)
        positionschild[index_next_job] = 2 * len(seq1) + 1
    nb_machines = sched1.nb_machines
    childsched = Ordonnancement(nb_machines)
    childsched.ordonnancer_liste_job(childseq)
    return [childsched]
def crossover_1_point(sched1, sched2, point1):
    """
    Crosses two schedulings with the
    :param sched1: parent 1 for crossover (Ordonnancement object)
    :param sched2: parent 2 for crossover (Ordonnancement object)
    :param point1: separation point to swap the sub-sequences, INTEGER between 0 and nb_jobs
    :return population: the two children schedulings (Ordonnancement objects)
    """
    seq1 = sched1.sequence().copy()
    seq2 = sched2.sequence().copy()
    seq11 = seq1[0:point1]
    seq12 = seq1[point1:]
    seq21 = seq2[0:point1]
    seq22 = seq2[point1:]
    list_exclude = [[], []]
    for i in range(len(seq11)):
        if seq11[i] not in seq21:
            list_exclude[0].append(i)
        if seq21[i] not in seq11:
            list_exclude[1].append(i)
    for j in range(len(list_exclude[0])):
        k = random.randint(0, len(list_exclude[1]) - 1)
        n = list_exclude[1][k]
        m = list_exclude[0][j]
        seq11[m], seq21[n] = seq21[n], seq11[m]
        list_exclude[1].pop(k)
    new_seq1 = seq11 + seq22
    new_seq2 = seq21 + seq12
    nb_machines = sched1.nb_machines
    scheduling1 = Ordonnancement(nb_machines)
    scheduling2 = Ordonnancement(nb_machines)
    scheduling1.ordonnancer_liste_job(new_seq1)
    scheduling2.ordonnancer_liste_job(new_seq2)
    return [scheduling1, scheduling2]
 def test_improvement_with_ls(self):
     job_a = Job(0, [1, 5])
     job_b = Job(1, [5, 1])
     flow_shop_2 = Flowshop(2, 2, [job_a, job_b])
     swap_neighbors = create_swap_neighbors(flow_shop_2)
     insert_neighbors = create_insert_neighbors(flow_shop_2)
     scheduling = Ordonnancement(job_a.nb_op)
     scheduling.ordonnancer_liste_job([job_b, job_a])
     new_scheduling_swap = local_search_swap(scheduling,
                                             1,
                                             max_neighbors_nb=50,
                                             neighbors=swap_neighbors)
     new_scheduling_insert = local_search_insert(scheduling,
                                                 1,
                                                 max_neighbors_nb=50,
                                                 neighbors=insert_neighbors)
     self.assertTrue(scheduling.duree() == 11)
     self.assertTrue(new_scheduling_swap.duree() < scheduling.duree())
     self.assertTrue(new_scheduling_insert.duree() < scheduling.duree())
     self.assertTrue(new_scheduling_swap.duree() == 7)
     self.assertTrue(new_scheduling_insert.duree() == 7)
     self.assertEqual(len(new_scheduling_swap.sequence()), 2)
     self.assertEqual(len(new_scheduling_insert.sequence()), 2)
     for job in [job_a, job_b]:
         self.assertIn(job, new_scheduling_swap.sequence())
         self.assertIn(job, new_scheduling_insert.sequence())
示例#5
0
 def test_crossover_positions(self):
     parent_1 = Ordonnancement(job_1.nb_op)
     parent_2 = Ordonnancement(job_1.nb_op)
     parent_1.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])
     parent_2.ordonnancer_liste_job([job_1, job_4, job_5, job_2, job_3])
     new_pop = crossover_position(parent_1, parent_2)
     for sched in new_pop:
         self.assertEqual(len(sched.sequence()), 5)
         self.assertEqual(sched.has_duplicate(), False)
         for job in [job_1, job_2, job_3, job_4, job_5]:
             self.assertIn(job, sched.sequence())
示例#6
0
def random_initial_pop(flow_shop, rdm_size):
    """
    Generates randomly the initial population
    :param flow_shop: an instance of the flow shop permutation problem
    :param rdm_size: number of element in the initial population to generate
    :return: the random part of the initial population for the memetic algorithm
    """
    population_seq = []
    population = []
    start = [flow_shop.liste_jobs(i) for i in range(flow_shop.nb_jobs)]
    for i in range(rdm_size):
        random.shuffle(start)
        elem = copy.copy(start)
        population_seq.append(elem)
    for seq in population_seq:
        temp_scheduling = Ordonnancement(flow_shop.nb_machines)
        temp_scheduling.ordonnancer_liste_job(seq)
        population.append(temp_scheduling)
    return population
示例#7
0
 def test_crossover_2_points(self):
     parent_1 = Ordonnancement(job_1.nb_op)
     parent_2 = Ordonnancement(job_1.nb_op)
     parent_1.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])
     parent_2.ordonnancer_liste_job([job_1, job_4, job_5, job_2, job_3])
     initial_pop = [parent_1, parent_2]
     new_pop = crossover_2_points(parent_1, parent_2, 1, 3)
     self.assertEqual(len(initial_pop), len(new_pop))
     for sched in new_pop:
         self.assertEqual(len(sched.sequence()), 5)
         self.assertEqual(sched.has_duplicate(), False)
         for job in [job_1, job_2, job_3, job_4, job_5]:
             self.assertIn(job, sched.sequence())
示例#8
0
def local_search_insert(scheduling, iteration, max_neighbors_nb, neighbors):
    """
    Returns a (new) scheduling after local search on the given initial scheduling during the maximum number of
    iterations given to find a minimum local, given an instance of the flowshop population (insert neighborhood)
    An iteration is an exploration of all the insert neighborhood of the current best scheduling
    :param scheduling: a scheduling (Ordonnancement object)
    :param iteration: maximum number of iterations (explorations of the insert neighborhood) to find a minimum local
    :param max_neighbors_nb: number of neighbors to visit at each iteration
    :param neighbors: list of neighbors
    :return: the scheduling after the given number of iteration of local search
    """
    best_scheduling = copy.copy(scheduling)
    candidate = copy.copy(scheduling)
    duration = best_scheduling.duree()
    duration_candidate = candidate.duree()
    if max_neighbors_nb > len(neighbors):
        max_neighbors_nb = len(neighbors)

    for a in range(0, iteration):
        visited_neighbors = neighbors.copy()
        for k in range(max_neighbors_nb):
            index = random.randint(0, len(visited_neighbors) - 1)
            i, j = visited_neighbors[index][0], visited_neighbors[index][1]
            visited_neighbors.pop(index)
            temp = copy.copy(best_scheduling)
            sequence = temp.sequence().copy()
            ls_insert = sequence[i]
            sequence.remove(ls_insert)
            sequence.insert(j, ls_insert)
            new_scheduling = Ordonnancement(temp.nb_machines)
            new_scheduling.ordonnancer_liste_job(sequence)
            duration_temp = new_scheduling.duree()
            if duration_temp < duration_candidate:
                duration_candidate = duration_temp
                candidate = new_scheduling
        if duration > duration_candidate:
            best_scheduling = candidate
            duration = duration_candidate
        else:
            break
    return best_scheduling
示例#9
0
def mutation_swap(flowshop, population, mutation_probability=0.4):
    """
    Returns a new population after mutation given an instance of the flowshop permutation problem, a population and a
    mutation probability (swap method)
    :param flowshop: a Flowshop object
    :param population: list of Ordonnancement objects
    :param mutation_probability: probability for each Ordonnancement object in the population to mutate
    :return: the population after mutation
    """
    nb_jobs = flowshop.nombre_jobs()
    mutated_population = []
    for sched in population:
        if random.random() < mutation_probability:
            sequence = sched.sequence().copy()
            indices = [j for j in range(nb_jobs)]
            a, b = random.sample(indices, 2)
            sequence[a], sequence[b] = sequence[b], sequence[a]

            mutated_sched = Ordonnancement(sched.nb_machines)
            mutated_sched.ordonnancer_liste_job(sequence)
            mutated_population.append(mutated_sched)
        else:
            mutated_population.append(sched)
    return mutated_population
示例#10
0
 def test_crossover(self):
     parent_1 = Ordonnancement(job_1.nb_op)
     parent_2 = Ordonnancement(job_1.nb_op)
     parent_1.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])
     parent_2.ordonnancer_liste_job([job_1, job_4, job_5, job_2, job_3])
     initial_pop = [parent_1, parent_2]
     flowshop = Flowshop(5, 5)
     new_pop = crossover(flowshop,
                         initial_pop,
                         cross_1_point_prob=0.5,
                         cross_2_points_prob=0.5,
                         cross_position_prob=0.3,
                         gentrification=True)
     self.assertEqual(len(initial_pop), len(new_pop))
     for sched in new_pop:
         self.assertEqual(len(sched.sequence()), 5)
         self.assertEqual(sched.has_duplicate(), False)
         for job in [job_1, job_2, job_3, job_4, job_5]:
             self.assertIn(job, sched.sequence())
示例#11
0
def deterministic_initial_pop(flow_shop, deter_size, best_deter):
    """
    Generates deterministically the initial population
    :param flow_shop: an instance of the flow shop permutation problem
    :param deter_size: number of element in the initial population to generate
    :param best_deter: if true, select the initial population by scheduling duration, else random selection
    :return: the deterministic part of the initial population for the memetic algorithm
    """
    all_deterministic_seq = []
    neh_seq = neh_order(flow_shop)
    all_deterministic_seq.append(neh_seq)
    for m_index in range(flow_shop.nb_machines):
        temp_sep_desc = job_duration_order_desc(flow_shop, m_index)
        temp_sep_asc = job_duration_order_asc(flow_shop, m_index)
        all_deterministic_seq.append(temp_sep_asc)
        all_deterministic_seq.append(temp_sep_desc)
    for sum_index in range(flow_shop.nb_machines - 1):
        temp_johnson_seq = johnson_rule_order(flow_shop, sum_index)
        all_deterministic_seq.append(temp_johnson_seq)

    deter_pop = []
    if best_deter:
        all_deterministic_ordo = []
        for seq in all_deterministic_seq:
            sched = Ordonnancement(flow_shop.nb_machines)
            sched.ordonnancer_liste_job(seq)
            all_deterministic_ordo.append(sched)
        sorted_scheduling = sorted(all_deterministic_ordo, key=lambda o: o.duree(), reverse=False)
        if deter_size > len(sorted_scheduling):
            deter_pop = sorted_scheduling
        else:
            deter_pop = sorted_scheduling[0:deter_size]
    else:
        if deter_size > len(all_deterministic_seq):
            seq_deter_sample = all_deterministic_seq
        else:
            seq_deter_sample = random.sample(all_deterministic_seq, deter_size)
        for seq in seq_deter_sample:
            sched = Ordonnancement(flow_shop.nb_machines)
            sched.ordonnancer_liste_job(seq)
            deter_pop.append(sched)
    return deter_pop
示例#12
0
def crossover_2_points(sched1, sched2, point1, point2):
    """
    Crosses two schedulings with the
    :param sched1: parent 1 for crossover (Ordonnancement object)
    :param sched2: parent 2 for crossover (Ordonnancement object)
    :param point1: first point of the interval to swap, INTEGER between 0 and nb_jobs
    :param point2: second point of the interval to swap, INTEGER between 0 and nb_jobs, different of point1
    :return population: the two children schedulings (Ordonnancement objects)
    """
    nb_jobs = len(sched1.sequence())
    point1, point2 = min(point1, point2), max(point1, point2)
    seq1 = sched1.sequence().copy()
    seq2 = sched2.sequence().copy()
    seq11 = seq1[0:point1]
    seq12 = seq1[point1:point2]
    seq13 = seq1[point2:nb_jobs]
    seq21 = seq2[0:point1]
    seq22 = seq2[point1:point2]
    seq23 = seq2[point2:nb_jobs]
    list_exclude = [[], []]
    for i in range(len(seq12)):
        if seq12[i] not in seq22:
            list_exclude[0].append(i)
        if seq22[i] not in seq12:
            list_exclude[1].append(i)
    for j in range(len(list_exclude[0])):
        k = random.randint(0, len(list_exclude[1]) - 1)
        n = list_exclude[1][k]
        m = list_exclude[0][j]
        seq12[m], seq22[n] = seq22[n], seq12[m]
        list_exclude[1].pop(k)
    new_seq1 = seq11 + seq22 + seq13
    new_seq2 = seq21 + seq12 + seq23
    nb_machines = sched1.nb_machines
    scheduling1 = Ordonnancement(nb_machines)
    scheduling2 = Ordonnancement(nb_machines)
    scheduling1.ordonnancer_liste_job(new_seq1)
    scheduling2.ordonnancer_liste_job(new_seq2)
    return [scheduling1, scheduling2]
示例#13
0
def neh_order(flow_shop):
    """
    Compute the NEH scheduling of flow_shop
    :param flow_shop: an instance of the flow shop permutation problem
    :return: return the NEH scheduling of flow_shop
    """
    sorted_jobs = sorted(flow_shop.l_job, key=lambda j: j.duree(), reverse=True)
    best_order = []
    for job in sorted_jobs:
        min_duration = MAXINT
        best_pos = 0
        for i in range(0, len(best_order) + 1):
            scheduling = Ordonnancement(flow_shop.nb_machines)
            new_list = [j for j in best_order]
            new_list.insert(i, job)
            scheduling.ordonnancer_liste_job(new_list)
            if scheduling.duree() < min_duration:
                min_duration = scheduling.duree()
                best_pos = i
        best_order.insert(best_pos, job)
    return best_order
示例#14
0
def swap(i, j, scheduling):
    sequence = scheduling.sequence().copy()
    sequence[i], sequence[j] = sequence[j], sequence[i]
    new_scheduling = Ordonnancement(scheduling.nb_machines)
    new_scheduling.ordonnancer_liste_job(sequence)
    return new_scheduling
示例#15
0
import unittest
import copy
from src.job import Job
from src.ordonnancement import Ordonnancement
from src.flowshop import Flowshop
from src.local_search import local_search_swap, local_search_insert, swap, local_search, create_swap_neighbors, \
    create_insert_neighbors

job_1 = Job(1, [1, 1, 1, 1, 10])
job_2 = Job(2, [1, 1, 1, 4, 8])
job_3 = Job(3, [2, 1, 3, 5, 1])
job_4 = Job(4, [2, 5, 5, 3, 3])
job_5 = Job(5, [1, 1, 3, 7, 1])
flow_shop = Flowshop(5, 5)
scheduling_1 = Ordonnancement(job_1.nb_op)
scheduling_2 = Ordonnancement(job_2.nb_op)
scheduling_1.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])
scheduling_2.ordonnancer_liste_job([job_1, job_4, job_5, job_2, job_3])
initial_scheduling = Ordonnancement(job_1.nb_op)
initial_scheduling.ordonnancer_liste_job([job_1, job_2, job_3, job_4, job_5])


class TestSolutionLocalSearchClassMethods(unittest.TestCase):
    def test_local_search(self):
        initial_pop = [scheduling_1, scheduling_2, initial_scheduling]
        swap_neighbors = create_swap_neighbors(flow_shop)
        insert_neighbors = create_insert_neighbors(flow_shop)
        new_pop = local_search(initial_pop,
                               local_search_swap_prob=0.5,
                               local_search_insert_prob=0.5,
                               maximum_nb_iterations=20,
示例#16
0
    return sorted_jobs


def custom_formatwarning(msg, *args, **kwargs):
    # ignore everything except the message
    return str(msg) + '\n'


# Executable part to prompt the NEH results for each instance
if __name__ == "__main__":
    import os
    from src.flowshop import Flowshop
    from src.utils import read_global_memetic_results, get_best_known_and_found_solutions
    data_path = "../data/"
    global_memetic_results_path = "../res/global_memetic_results.csv"
    for dataSet in os.listdir(data_path):
        for instance in os.listdir(data_path + dataSet):
            flow_shop_file_path = data_path + dataSet + "/" + instance
            flow_shop_instance = Flowshop()
            flow_shop_instance.definir_par(flow_shop_file_path)
            file_name = instance.split('.txt')[0]
            global_memetic_results = read_global_memetic_results(global_memetic_results_path)
            best_known, best_found = get_best_known_and_found_solutions(global_memetic_results, file_name)
            neh_scheduling = Ordonnancement(flow_shop_instance.nombre_machines())
            neh_scheduling.ordonnancer_liste_job(neh_order(flow_shop_instance))
            neh_c_max = neh_scheduling.duree()
            relative_gap = round(((neh_c_max - best_known) / best_known) * 100, 2)
            print("Solving instance " + data_path + dataSet + '/' + file_name + ' with NEH... ' +
                  str(neh_c_max) + ' ' + str(relative_gap) + '%')
    print("Finished!")
示例#17
0
 def test_neh_order(self):
     seq = ip.neh_order(flowshop_2)
     sched = Ordonnancement(flowshop_2.nb_machines)
     sched.ordonnancer_liste_job(seq)
     self.assertEqual(sched.duree(), 705)
import unittest
from src.ordonnancement import Ordonnancement
from src.job import Job

job_1 = Job(1, [1, 1, 1, 1, 10])
job_2 = Job(2, [1, 1, 1, 4, 8])
job_3 = Job(3, [2, 1, 3, 5, 1])
job_4 = Job(4, [2, 5, 5, 3, 3])
job_5 = Job(5, [1, 1, 3, 7, 1])
ord_1 = Ordonnancement(job_1.nb_op)
ord_2 = Ordonnancement(job_1.nb_op)
ord_3 = Ordonnancement(job_1.nb_op)
ord_1.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])
ord_2.ordonnancer_liste_job([job_1, job_4, job_5, job_2, job_3])
ord_3.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])


class TestOrdonnancementClassMethods(unittest.TestCase):
    def test_eq(self):
        self.assertEqual(ord_1, ord_3)
        self.assertNotEqual(ord_1, ord_2)


if __name__ == '__main__':
    unittest.main()
示例#19
0
    :param ordonnancement: an Ordonnancement object where the scheduling of all jobs is done (in other words which
    represents a solution to an instance of the flow-shop permutation problem)
    :param file_path: path where the html file corresponding to the representation of the solution is stored (it needs
    to have the character "/" at the end or be the empty string)
    :param file_name: name of the html file corresponding to the representation of the solution
    :param show_durations: boolean which indicates if the duration of the tasks have to be represented (True by default)
    """
    figure, figure_name = create_solution_figure(ordonnancement,
                                                 show_durations)
    if not file_name == "":
        figure_name = file_name
    figure.write_html(file_path + figure_name + '.html')
    return None


# "main" to give an example of how to use the "visualisation.py" methods
if __name__ == "__main__":
    a = Job(1, [1, 1, 1, 1, 10])
    b = Job(2, [1, 1, 1, 4, 8])
    c = Job(3, [2, 1, 3, 5, 1])
    d = Job(4, [2, 5, 5, 3, 3])
    e = Job(5, [1, 1, 3, 7, 1])
    scheduling = Ordonnancement(5)
    scheduling.ordonnancer_job(a)
    scheduling.ordonnancer_job(b)
    scheduling.ordonnancer_job(c)
    scheduling.ordonnancer_job(d)
    scheduling.ordonnancer_job(e)
    # show_solution_figure(scheduling)
    save_solution_as_html(scheduling)
示例#20
0
import unittest
from src.mutation import mutation, mutation_insert, mutation_swap
from src.flowshop import Flowshop
from src.job import Job
from src.ordonnancement import Ordonnancement

flow_shop = Flowshop(5, 5)
job_1 = Job(1, [1, 1, 1, 1, 10])
job_2 = Job(2, [1, 1, 1, 4, 8])
job_3 = Job(3, [2, 1, 3, 5, 1])
job_4 = Job(4, [2, 5, 5, 3, 3])
job_5 = Job(5, [1, 1, 3, 7, 1])
scheduling_1 = Ordonnancement(job_1.nb_op)
scheduling_2 = Ordonnancement(job_1.nb_op)
scheduling_3 = Ordonnancement(job_1.nb_op)
scheduling_1.ordonnancer_liste_job([job_2, job_3, job_4, job_5, job_1])
scheduling_2.ordonnancer_liste_job([job_1, job_4, job_5, job_2, job_3])
scheduling_3.ordonnancer_liste_job([job_5, job_4, job_3, job_2, job_1])
initial_pop = [scheduling_1, scheduling_2, scheduling_3]


class TestMutationFileMethods(unittest.TestCase):
    def test_mutation_swap(self):
        new_pop = mutation_swap(flow_shop,
                                initial_pop,
                                mutation_probability=1.0)
        self.assertEqual(len(initial_pop), len(new_pop))
        for scheduling in new_pop:
            self.assertEqual(len(scheduling.sequence()), 5)
            self.assertEqual(scheduling.has_duplicate(), False)
            for job in [job_1, job_2, job_3, job_4, job_5]: