├── MO-G-FJSP_P1.txt ├── README.md ├── code ├── Class_define.py ├── Class_define_ESNSGA.py ├── Class_define_ESNSGA_VB.py ├── Class_define_ESNSGA_jsp.py ├── Class_define_ESNSGA_nonVB.py ├── Class_define_NSGA_nonVB.py ├── MO-G-FJSP.py ├── MO_G_FJSP_VB.py ├── MO_G_FJSP_nonVB.py ├── MO_G_FJSP_nonVB_NSGA.py ├── MO_G_JSP.py └── preprocessing.py ├── data ├── JSP_ft06.fjs ├── JSP_ft10.fjs ├── JSP_ft20.fjs ├── MO-G-FJSP_P1.fjs ├── MO-G-FJSP_P10.fjs ├── MO-G-FJSP_P11.fjs ├── MO-G-FJSP_P2.fjs ├── MO-G-FJSP_P3.fjs ├── MO-G-FJSP_P4.fjs ├── MO-G-FJSP_P5.fjs ├── MO-G-FJSP_P6.fjs ├── MO-G-FJSP_P7.fjs ├── MO-G-FJSP_P8.fjs └── MO-G-FJSP_P9.fjs └── description.txt /MO-G-FJSP_P1.txt: -------------------------------------------------------------------------------- 1 | 6 5 2 | 1 2 3 4 5 6 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 0 2 8 9 2 9 | 2 0 3 1 10 10 | 8 3 0 7 6 11 | 9 1 7 0 5 12 | 2 10 6 5 0 13 | 6 2 1 5 3 4 3 5 3 3 5 2 1 2 3 4 5 2 3 5 5 2 6 1 1 1 3 1 3 5 6 3 6 4 3 14 | 5 1 2 6 1 3 1 1 1 2 2 2 6 4 6 3 5 5 2 6 1 1 15 | 5 1 2 6 2 3 4 5 2 3 5 5 2 6 1 1 3 3 4 2 6 5 6 2 1 1 5 5 16 | 5 3 5 5 2 6 1 1 1 2 6 1 3 1 3 5 3 3 5 2 1 2 3 4 5 2 17 | 6 3 5 3 3 5 2 1 3 5 5 2 6 1 1 1 2 6 2 1 5 3 4 2 2 6 4 6 3 3 4 2 6 5 6 18 | 6 2 3 4 5 2 1 1 2 3 3 4 2 6 5 6 1 2 6 3 5 5 2 6 1 1 2 1 3 4 2 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ES-NSGAII 2 | Evolution strategy NSGA-II for MO-G-FJSP 3 | 需先安裝nsga-ii套件 pip install nsga-2 4 | 程式碼搭配 5 | 1. Class_define.py -- preprocessing.py 6 | 2. Class_define_ESNSGA.py -- MO-G-FJSP.py 7 | 3. Class_define_ESNSGA_VB.py -- MO_G_FJSP_VB.py 8 | 4. Class_define_ESNSGA_nonVB.py -- MO_G_FJSP_nonVB.py (主要執行此版) 9 | 5. Class_define_NSGA_nonVB.py -- MO_G_FJSP_nonVB_NSGA.py 10 | 6. Class_define_ESNSGA_jsp.py -- MO_G_JSP.py 11 | 12 | description.txt為描述data資料夾中資料 13 | -------------------------------------------------------------------------------- /code/Class_define.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Dec 25 16:25:35 2021 4 | 5 | @author: acanlab 6 | """ 7 | from nsga2.utils import NSGA2Utils 8 | from nsga2.problem import Problem 9 | from nsga2.evolution import Evolution 10 | import matplotlib.pyplot as plt 11 | import random 12 | import numpy as np 13 | from nsga2.individual import Individual 14 | from nsga2.population import Population 15 | #%% 16 | class myIndividual(Individual): 17 | def __init__(self): 18 | super(myIndividual,self).__init__() 19 | self.features = [] 20 | def __eq__(self, other): 21 | if isinstance(self, other.__class__): 22 | for x in range(len(self.features)): 23 | for y in range(len(self.features[x])): 24 | if self.features[x][y] != other.features[x][y]: 25 | # print(self.features[x][y]) 26 | return False 27 | return True 28 | return False 29 | #%% 30 | class myProblem(Problem): 31 | def __init__(self, objectives, num_of_variables, variables_range, operation_num_per_jobs, job_machine_operation_map, expand=True, same_range=False): 32 | super(myProblem,self).__init__(objectives, num_of_variables, variables_range, expand, same_range) 33 | self.operation_num_per_jobs = operation_num_per_jobs 34 | self.job_machine_operation_map = job_machine_operation_map 35 | if same_range: 36 | for _ in range(num_of_variables): 37 | self.variables_range.append(variables_range[0]) 38 | else: 39 | self.variables_range = variables_range 40 | def valid_individual(self,individual): 41 | j=0 42 | for job in range(len(self.operation_num_per_jobs)): 43 | operation_num_per_jobs=self.operation_num_per_jobs[job] 44 | for i in range(operation_num_per_jobs): 45 | for k in range(j,j+self.operation_num_per_jobs[job]-1): 46 | if individual.features[1][k]>individual.features[1][k+1]: 47 | tmp = individual.features[1][k] 48 | individual.features[1][k] = individual.features[1][k+1] 49 | individual.features[1][k+1] = tmp 50 | j+=operation_num_per_jobs 51 | job=self.operation_num_per_jobs 52 | operation_index=0 53 | job_index=0 54 | for times in range(self.variables_range[1]): #for all operation 55 | #改到這 56 | if job[job_index]==operation_index: 57 | operation_index=0 58 | job_index+=1 59 | machine_index = individual.features[0][times] 60 | if self.job_machine_operation_map[job_index][operation_index][machine_index]==10000: 61 | N_machine = self.variables_range[0][0][1]+1 62 | for m in range(N_machine): #find the machine can operate this operation 63 | if self.job_machine_operation_map[job_index][operation_index][m] != 10000: 64 | individual.features[0][times] = m 65 | break 66 | operation_index +=1 67 | return individual 68 | def generate_individual(self): 69 | individual = myIndividual() 70 | individual.features.append([int(random.uniform(*x)) for x in self.variables_range[0]]) 71 | tmp = np.array(range(self.variables_range[1])) 72 | random.shuffle(tmp) 73 | individual.features.append(tmp) 74 | individual = self.valid_individual(individual) 75 | #print("test") 76 | return individual 77 | 78 | def calculate_objectives(self, individual): 79 | if self.expand: 80 | individual.objectives = [f(*individual.features) for f in self.objectives] 81 | else: 82 | individual.objectives = [f(individual.features) for f in self.objectives] 83 | #%% 84 | class myUtils(NSGA2Utils): 85 | 86 | def __init__(self, problem, num_of_individuals=100, 87 | num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5): 88 | super(myUtils, self).__init__(problem, num_of_individuals, 89 | num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 90 | def create_children(self, population): 91 | children = [] 92 | while len(children) < len(population): 93 | parent1 = self.__tournament(population) 94 | parent2 = parent1 95 | while parent1 == parent2: 96 | # print("equil_check") 97 | parent2 = self.__tournament(population) 98 | child1, child2 = self.__crossover(parent1, parent2) 99 | self.__mutate(child1) 100 | self.__mutate(child2) 101 | self.problem.calculate_objectives(child1) 102 | self.problem.calculate_objectives(child2) 103 | 104 | children.append(child1) 105 | children.append(child2) 106 | 107 | return children 108 | def __mutate(self, child): 109 | for gene_gene in range(len(child.features[0])): 110 | u, delta = self.__get_delta() 111 | if u < 0.5: 112 | child.features[0][gene_gene] = random.randint(self.problem.variables_range[0][gene_gene][0],self.problem.variables_range[0][gene_gene][1]) 113 | child = self.problem.valid_individual(child) 114 | def __crossover(self, individual1, individual2): 115 | crossover_point = 2 116 | child1 = self.problem.generate_individual() 117 | child2 = self.problem.generate_individual() 118 | tmp1 = [] 119 | tmp2 = [] 120 | for gene in range(len(individual1.features[0])): 121 | if gene < crossover_point: 122 | child1.features[0][gene] = individual1.features[0][gene] 123 | child2.features[0][gene] = individual2.features[0][gene] 124 | else: 125 | child1.features[0][gene] = individual2.features[0][gene] 126 | child2.features[0][gene] = individual2.features[0][gene] 127 | if individual1.features[1][gene] > crossover_point: 128 | tmp1.append(individual1.features[1][gene]) 129 | if individual2.features[1][gene] > crossover_point: 130 | tmp2.append(individual2.features[1][gene]) 131 | cnt=0 132 | for t in tmp1: 133 | while individual2.features[1][cnt] <= crossover_point: 134 | child2.features[1][cnt] = individual2.features[1][cnt] 135 | cnt+=1 136 | child2.features[1][cnt] = t 137 | cnt+=1 138 | cnt=0 139 | for t in tmp2: 140 | while individual1.features[1][cnt] <= crossover_point: 141 | child1.features[1][cnt] = individual1.features[1][cnt] 142 | cnt+=1 143 | child1.features[1][cnt] = t 144 | cnt+=1 145 | child1 = self.problem.valid_individual(child1) 146 | child2 = self.problem.valid_individual(child2) 147 | return child1, child2 148 | def __tournament(self, population): 149 | participants = random.sample(population.population, self.num_of_tour_particips) 150 | best = None 151 | for participant in participants: 152 | if best is None or (self.crowding_operator(participant, best) == 1 and self.__choose_with_prob(self.tournament_prob)): 153 | best = participant 154 | return best 155 | def __get_delta(self): 156 | u = random.random() 157 | if u < 0.5: 158 | return u, (2*u)**(1/(self.mutation_param + 1)) - 1 159 | return u, 1 - (2*(1-u))**(1/(self.mutation_param + 1)) 160 | def __choose_with_prob(self, prob): 161 | if random.random() <= prob: 162 | return True 163 | return False 164 | def calculate_crowding_distance(self, front): 165 | if len(front) > 0: 166 | solutions_num = len(front) 167 | for individual in front: 168 | individual.crowding_distance = 0 169 | 170 | for m in range(len(front[0].objectives)): 171 | front.sort(key=lambda individual: individual.objectives[m]) 172 | front[0].crowding_distance = 10**9 173 | front[solutions_num-1].crowding_distance = 10**9 174 | m_values = [individual.objectives[m] for individual in front] 175 | scale = max(m_values) - min(m_values) 176 | if scale == 0: scale = 1 177 | for i in range(1, solutions_num-1): 178 | front[i].crowding_distance += (front[i+1].objectives[m] - front[i-1].objectives[m])/scale 179 | 180 | #%% 181 | class myEvolution(Evolution): 182 | 183 | def __init__(self, problem, num_of_generations=1000, num_of_individuals=100, num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5): 184 | self.population = None 185 | self.num_of_generations = num_of_generations 186 | self.on_generation_finished = [] 187 | self.num_of_individuals = num_of_individuals 188 | self.utils = myUtils(problem, num_of_individuals, num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 189 | def evolve(self): 190 | self.population = self.utils.create_initial_population() 191 | self.utils.fast_nondominated_sort(self.population) 192 | for front in self.population.fronts: 193 | self.utils.calculate_crowding_distance(front) 194 | children = self.utils.create_children(self.population) 195 | returned_population = None 196 | for i in range(self.num_of_generations): 197 | print('generation : ' + str(i)) 198 | self.population.extend(children) 199 | self.utils.fast_nondominated_sort(self.population) 200 | new_population = Population() 201 | front_num = 0 202 | while len(new_population) + len(self.population.fronts[front_num]) <= self.num_of_individuals: 203 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 204 | new_population.extend(self.population.fronts[front_num]) 205 | front_num += 1 206 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 207 | self.population.fronts[front_num].sort(key=lambda individual: individual.crowding_distance, reverse=True) 208 | new_population.extend(self.population.fronts[front_num][0:self.num_of_individuals-len(new_population)]) 209 | returned_population = self.population 210 | self.population = new_population 211 | self.utils.fast_nondominated_sort(self.population) 212 | for front in self.population.fronts: 213 | self.utils.calculate_crowding_distance(front) 214 | children = self.utils.create_children(self.population) 215 | return returned_population.fronts[0] 216 | -------------------------------------------------------------------------------- /code/Class_define_ESNSGA.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Dec 25 16:25:35 2021 4 | 5 | @author: acanlab 6 | """ 7 | from nsga2.utils import NSGA2Utils 8 | from nsga2.problem import Problem 9 | from nsga2.evolution import Evolution 10 | import matplotlib.pyplot as plt 11 | import random 12 | import numpy as np 13 | from nsga2.individual import Individual 14 | from nsga2.population import Population 15 | import copy 16 | #%% 17 | class myIndividual(Individual): 18 | def __init__(self): 19 | super(myIndividual,self).__init__() 20 | self.features = [] 21 | def __eq__(self, other): 22 | if isinstance(self, other.__class__): 23 | for x in range(len(self.features)): 24 | for y in range(len(self.features[x])): 25 | if self.features[x][y] != other.features[x][y]: 26 | # print(self.features[x][y]) 27 | return False 28 | return True 29 | return False 30 | def dominates(self, other_individual): 31 | and_condition = True 32 | or_condition = False 33 | for first, second in zip(self.objectives, other_individual.objectives): 34 | and_condition = and_condition and first <= second 35 | or_condition = or_condition or first < second 36 | return (and_condition and or_condition) 37 | #%% 38 | class myProblem(Problem): 39 | def __init__(self, objectives, num_of_variables, variables_range, operation_num_per_jobs, job_machine_operation_map, expand=True, same_range=False): 40 | super(myProblem,self).__init__(objectives, num_of_variables, variables_range, expand, same_range) 41 | self.operation_num_per_jobs = operation_num_per_jobs 42 | self.job_machine_operation_map = job_machine_operation_map 43 | if same_range: 44 | for _ in range(num_of_variables): 45 | self.variables_range.append(variables_range[0]) 46 | else: 47 | self.variables_range = variables_range 48 | def valid_individual(self,individual): 49 | j=0 50 | for job in range(len(self.operation_num_per_jobs)): 51 | operation_num_per_jobs=self.operation_num_per_jobs[job] 52 | for i in range(operation_num_per_jobs): 53 | for k in range(j,j+self.operation_num_per_jobs[job]-1): 54 | if individual.features[1][k]>individual.features[1][k+1]: 55 | tmp = individual.features[1][k] 56 | individual.features[1][k] = individual.features[1][k+1] 57 | individual.features[1][k+1] = tmp 58 | j+=operation_num_per_jobs 59 | job=self.operation_num_per_jobs 60 | operation_index=0 61 | job_index=0 62 | for times in range(self.variables_range[1]): #for all operation 63 | #改到這 64 | if job[job_index]==operation_index: 65 | operation_index=0 66 | job_index+=1 67 | machine_index = individual.features[0][times] 68 | if self.job_machine_operation_map[job_index][operation_index][machine_index]==10000: 69 | N_machine = self.variables_range[0][0][1]+1 70 | for m in range(N_machine): #find the machine can operate this operation 71 | if self.job_machine_operation_map[job_index][operation_index][m] != 10000: 72 | individual.features[0][times] = m 73 | break 74 | operation_index +=1 75 | return individual 76 | def generate_individual_2(self): 77 | individual = myIndividual() 78 | individual.features.append([int(random.uniform(*x)) for x in self.variables_range[0]]) 79 | tmp = np.array(range(self.variables_range[1])) 80 | random.shuffle(tmp) 81 | individual.features.append(tmp) 82 | individual = self.valid_individual(individual) 83 | #print("test") 84 | return individual 85 | def generate_individual(self): 86 | individual = myIndividual() 87 | tmp_feature = [] 88 | for i in range(len(self.variables_range[0])): 89 | threshold = random.random() 90 | if self.variables_range[0][i] <2: 91 | tmp_feature.append(1) 92 | else: 93 | if threshold >0.5: 94 | tmp_feature.append(1) 95 | else: 96 | tmp_feature.append(2) 97 | schedule =[] 98 | for i in range(len(self.variables_range[0])): 99 | if tmp_feature[i]==1: 100 | tmp_feature.append(self.variables_range[0][i]) 101 | for j in range(self.variables_range[1][i]): 102 | schedule.append([i,1]) 103 | else: 104 | batch1 = random.randint(1,self.variables_range[0][i]-1) 105 | batch2 = self.variables_range[0][i] - batch1 106 | tmp_feature.append(batch1) 107 | tmp_feature.append(batch2) 108 | for j in range(self.variables_range[1][i]): 109 | schedule.append([i,1]) 110 | for j in range(self.variables_range[1][i]): 111 | schedule.append([i,2]) 112 | random.shuffle(schedule) 113 | tmp_feature.append(schedule) 114 | individual.features.append(tmp_feature) 115 | #individual = self.valid_individual(individual) 116 | #print("test") 117 | return individual 118 | 119 | def calculate_objectives(self, individual): 120 | if self.expand: 121 | individual.objectives = [f(*individual.features) for f in self.objectives] 122 | else: 123 | individual.objectives = [f(individual.features) for f in self.objectives] 124 | #%% 125 | class myUtils(NSGA2Utils): 126 | 127 | def __init__(self, problem, num_of_individuals=100, 128 | num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5): 129 | super(myUtils, self).__init__(problem, num_of_individuals, 130 | num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 131 | def create_children(self, population, num_mutate): 132 | children = [] 133 | #print("len : " + str(len(population))) 134 | child_mutate_set = self.__mutate(population, num_mutate) 135 | child_reseeding_set = self.__reseeding(population) 136 | for child_mutate in child_mutate_set: 137 | self.problem.calculate_objectives(child_mutate) 138 | for child_reseeding in child_reseeding_set: 139 | self.problem.calculate_objectives(child_reseeding) 140 | 141 | children.extend(child_mutate_set) 142 | children.extend(child_reseeding_set) 143 | 144 | return children 145 | def fast_nondominated_sort(self, population): 146 | population.fronts = [[]] 147 | for individual in population: 148 | individual.domination_count = 0 149 | individual.dominated_solutions = [] 150 | for other_individual in population: 151 | if individual.dominates(other_individual): 152 | individual.dominated_solutions.append(other_individual) 153 | elif other_individual.dominates(individual): 154 | individual.domination_count += 1 155 | if individual.domination_count == 0: 156 | individual.rank = 0 157 | population.fronts[0].append(individual) 158 | i = 0 159 | while len(population.fronts[i]) > 0: 160 | temp = [] 161 | for individual in population.fronts[i]: 162 | for other_individual in individual.dominated_solutions: 163 | other_individual.domination_count -= 1 164 | if other_individual.domination_count == 0: 165 | other_individual.rank = i+1 166 | temp.append(other_individual) 167 | i = i+1 168 | population.fronts.append(temp) 169 | # print("poplen : "+str(len(population))) 170 | def __mutate(self, population, num_mutate): 171 | half_population = int(len(population)/2) 172 | front_num = 0 173 | children = Population() 174 | mutate_population = copy.deepcopy(population) 175 | # select half best individual 176 | while len(children) < half_population: 177 | if len(children)+len(mutate_population.fronts[front_num]) <= half_population: 178 | children.extend(mutate_population.fronts[front_num]) 179 | else: 180 | children.extend(mutate_population.fronts[front_num][0:half_population-len(children)]) 181 | front_num += 1 182 | half_population = int(self.num_of_individuals/2) 183 | while len(children) < half_population: 184 | children.append(mutate_population.fronts[0][0]) 185 | # mutate half best individual 186 | for individual in children: 187 | cnt_mutate = 0 188 | #print(individual) 189 | operation_index = len(individual.features[0][-1])-1 190 | while cnt_mutate < num_mutate : 191 | index1 = random.randint(0,operation_index) 192 | index2 = random.randint(0,operation_index) 193 | if individual.features[0][-1][index1]!=individual.features[0][-1][index2]: 194 | tmp = individual.features[0][-1][index1] 195 | individual.features[0][-1][index1] = individual.features[0][-1][index2] 196 | individual.features[0][-1][index2] = tmp 197 | cnt_mutate+=1 198 | return children 199 | def __reseeding(self, population): 200 | half_population = int(self.num_of_individuals/2) # reseed half of initial population 201 | children = Population() 202 | for _ in range(half_population): 203 | individual = self.problem.generate_individual() 204 | children.append(individual) 205 | return children 206 | def __tournament(self, population): 207 | participants = random.sample(population.population, self.num_of_tour_particips) 208 | best = None 209 | for participant in participants: 210 | if best is None or (self.crowding_operator(participant, best) == 1 and self.__choose_with_prob(self.tournament_prob)): 211 | best = participant 212 | return best 213 | def __get_delta(self): 214 | u = random.random() 215 | if u < 0.5: 216 | return u, (2*u)**(1/(self.mutation_param + 1)) - 1 217 | return u, 1 - (2*(1-u))**(1/(self.mutation_param + 1)) 218 | def __choose_with_prob(self, prob): 219 | if random.random() <= prob: 220 | return True 221 | return False 222 | def calculate_crowding_distance(self, front): 223 | if len(front) > 0: 224 | solutions_num = len(front) 225 | for individual in front: 226 | individual.crowding_distance = 0 227 | 228 | for m in range(len(front[0].objectives)): 229 | front.sort(key=lambda individual: individual.objectives[m]) 230 | front[0].crowding_distance = 10**9 231 | front[solutions_num-1].crowding_distance = 10**9 232 | m_values = [individual.objectives[m] for individual in front] 233 | scale = max(m_values) - min(m_values) 234 | if scale == 0: scale = 1 235 | for i in range(1, solutions_num-1): 236 | front[i].crowding_distance += (front[i+1].objectives[m] - front[i-1].objectives[m])/scale 237 | #%% 238 | class myEvolution(Evolution): 239 | 240 | def __init__(self, problem, num_of_generations=1000, num_of_individuals=100, num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5,mutation_schedule=[[0,20],[50,15],[100,10]]): 241 | self.population = None 242 | self.num_of_generations = num_of_generations 243 | self.on_generation_finished = [] 244 | self.num_of_individuals = num_of_individuals 245 | self.mutation_schedule = mutation_schedule 246 | self.utils = myUtils(problem, num_of_individuals, num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 247 | def evolve(self): 248 | self.population = self.utils.create_initial_population() 249 | self.utils.fast_nondominated_sort(self.population) 250 | for front in self.population.fronts: 251 | self.utils.calculate_crowding_distance(front) 252 | num_mutate = self.mutation_schedule[0][1] 253 | mutate_index = 1 254 | 255 | returned_population = None 256 | for i in range(self.num_of_generations): 257 | print('generation : ' + str(i)) 258 | children = self.utils.create_children(self.population,num_mutate) 259 | self.population.extend(children) 260 | self.utils.fast_nondominated_sort(self.population) 261 | # for tmptest in self.population.fronts: 262 | # print(len(tmptest)) 263 | new_population = Population() 264 | front_num = 0 265 | # print(self.population.fronts) 266 | while len(new_population) + len(self.population.fronts[front_num]) <= self.num_of_individuals : 267 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 268 | new_population.extend(self.population.fronts[front_num]) 269 | front_num += 1 270 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 271 | self.population.fronts[front_num].sort(key=lambda individual: individual.crowding_distance, reverse=True) 272 | new_population.extend(self.population.fronts[front_num][0:self.num_of_individuals-len(new_population)]) 273 | returned_population = self.population 274 | self.population = new_population 275 | self.utils.fast_nondominated_sort(self.population) 276 | for front in self.population.fronts: 277 | self.utils.calculate_crowding_distance(front) 278 | if mutate_index < len(self.mutation_schedule) and i == self.mutation_schedule[mutate_index][0]: 279 | num_mutate = self.mutation_schedule[mutate_index][1] 280 | mutate_index+=1 281 | return returned_population.fronts[0] 282 | -------------------------------------------------------------------------------- /code/Class_define_ESNSGA_VB.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Dec 25 16:25:35 2021 4 | 5 | @author: acanlab 6 | """ 7 | from nsga2.utils import NSGA2Utils 8 | from nsga2.problem import Problem 9 | from nsga2.evolution import Evolution 10 | import matplotlib.pyplot as plt 11 | import random 12 | import numpy as np 13 | from nsga2.individual import Individual 14 | from nsga2.population import Population 15 | import copy 16 | #%% 17 | class myIndividual(Individual): 18 | def __init__(self): 19 | super(myIndividual,self).__init__() 20 | self.features = [] 21 | def __eq__(self, other): 22 | if isinstance(self, other.__class__): 23 | for x in range(len(self.features)): 24 | for y in range(len(self.features[x])): 25 | if self.features[x][y] != other.features[x][y]: 26 | # print(self.features[x][y]) 27 | return False 28 | return True 29 | return False 30 | def dominates(self, other_individual): 31 | and_condition = True 32 | or_condition = False 33 | for first, second in zip(self.objectives, other_individual.objectives): 34 | and_condition = and_condition and first <= second 35 | or_condition = or_condition or first < second 36 | return (and_condition and or_condition) 37 | #%% 38 | class myProblem(Problem): 39 | def __init__(self, objectives, num_of_variables, variables_range, operation_num_per_jobs, job_machine_operation_map, expand=True, same_range=False): 40 | super(myProblem,self).__init__(objectives, num_of_variables, variables_range, expand, same_range) 41 | self.operation_num_per_jobs = operation_num_per_jobs 42 | self.job_machine_operation_map = job_machine_operation_map 43 | if same_range: 44 | for _ in range(num_of_variables): 45 | self.variables_range.append(variables_range[0]) 46 | else: 47 | self.variables_range = variables_range 48 | def valid_individual(self,individual): 49 | j=0 50 | for job in range(len(self.operation_num_per_jobs)): 51 | operation_num_per_jobs=self.operation_num_per_jobs[job] 52 | for i in range(operation_num_per_jobs): 53 | for k in range(j,j+self.operation_num_per_jobs[job]-1): 54 | if individual.features[1][k]>individual.features[1][k+1]: 55 | tmp = individual.features[1][k] 56 | individual.features[1][k] = individual.features[1][k+1] 57 | individual.features[1][k+1] = tmp 58 | j+=operation_num_per_jobs 59 | job=self.operation_num_per_jobs 60 | operation_index=0 61 | job_index=0 62 | for times in range(self.variables_range[1]): #for all operation 63 | #改到這 64 | if job[job_index]==operation_index: 65 | operation_index=0 66 | job_index+=1 67 | machine_index = individual.features[0][times] 68 | if self.job_machine_operation_map[job_index][operation_index][machine_index]==10000: 69 | N_machine = self.variables_range[0][0][1]+1 70 | for m in range(N_machine): #find the machine can operate this operation 71 | if self.job_machine_operation_map[job_index][operation_index][m] != 10000: 72 | individual.features[0][times] = m 73 | break 74 | operation_index +=1 75 | return individual 76 | def generate_individual_2(self): 77 | individual = myIndividual() 78 | individual.features.append([int(random.uniform(*x)) for x in self.variables_range[0]]) 79 | tmp = np.array(range(self.variables_range[1])) 80 | random.shuffle(tmp) 81 | individual.features.append(tmp) 82 | individual = self.valid_individual(individual) 83 | #print("test") 84 | return individual 85 | def generate_individual(self): 86 | individual = myIndividual() 87 | tmp_feature = [] 88 | for i in range(len(self.variables_range[0])): 89 | threshold = random.random() 90 | if self.variables_range[0][i] <2: 91 | tmp_feature.append(1) 92 | else: 93 | if threshold >0.5: 94 | tmp_feature.append(1) 95 | else: 96 | tmp_feature.append(2) 97 | schedule =[] 98 | for i in range(len(self.variables_range[0])): 99 | if tmp_feature[i]==1: 100 | tmp_feature.append(self.variables_range[0][i]) 101 | for j in range(self.variables_range[1][i]): 102 | schedule.append([i,1]) 103 | else: 104 | batch1 = random.randint(1,self.variables_range[0][i]-1) 105 | batch2 = self.variables_range[0][i] - batch1 106 | tmp_feature.append(batch1) 107 | tmp_feature.append(batch2) 108 | for j in range(self.variables_range[1][i]): 109 | schedule.append([i,1]) 110 | for j in range(self.variables_range[1][i]): 111 | schedule.append([i,2]) 112 | random.shuffle(schedule) 113 | tmp_feature.append(schedule) 114 | individual.features.append(tmp_feature) 115 | #individual = self.valid_individual(individual) 116 | #print("test") 117 | return individual 118 | 119 | def calculate_objectives(self, individual): 120 | if self.expand: 121 | individual.objectives = [f(*individual.features) for f in self.objectives] 122 | else: 123 | individual.objectives = [f(individual.features) for f in self.objectives] 124 | #%% 125 | class myUtils(NSGA2Utils): 126 | 127 | def __init__(self, problem, num_of_individuals=100, 128 | num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5): 129 | super(myUtils, self).__init__(problem, num_of_individuals, 130 | num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 131 | def create_children(self, population, num_mutate): 132 | children = [] 133 | #print("len : " + str(len(population))) 134 | child_mutate_set = self.__mutate(population, num_mutate) 135 | child_reseeding_set = self.__reseeding(population) 136 | for child_mutate in child_mutate_set: 137 | self.problem.calculate_objectives(child_mutate) 138 | for child_reseeding in child_reseeding_set: 139 | self.problem.calculate_objectives(child_reseeding) 140 | 141 | children.extend(child_mutate_set) 142 | children.extend(child_reseeding_set) 143 | 144 | return children 145 | def fast_nondominated_sort(self, population): 146 | population.fronts = [[]] 147 | for individual in population: 148 | individual.domination_count = 0 149 | individual.dominated_solutions = [] 150 | for other_individual in population: 151 | if individual.dominates(other_individual): 152 | individual.dominated_solutions.append(other_individual) 153 | elif other_individual.dominates(individual): 154 | individual.domination_count += 1 155 | if individual.domination_count == 0: 156 | individual.rank = 0 157 | population.fronts[0].append(individual) 158 | i = 0 159 | while len(population.fronts[i]) > 0: 160 | temp = [] 161 | for individual in population.fronts[i]: 162 | for other_individual in individual.dominated_solutions: 163 | other_individual.domination_count -= 1 164 | if other_individual.domination_count == 0: 165 | other_individual.rank = i+1 166 | temp.append(other_individual) 167 | i = i+1 168 | population.fronts.append(temp) 169 | # print("poplen : "+str(len(population))) 170 | def __mutate(self, population, num_mutate): 171 | half_population = int(len(population)/2) 172 | front_num = 0 173 | children = Population() 174 | mutate_population = copy.deepcopy(population) 175 | # select half best individual 176 | while len(children) < half_population: 177 | if len(children)+len(mutate_population.fronts[front_num]) <= half_population: 178 | children.extend(mutate_population.fronts[front_num]) 179 | else: 180 | children.extend(mutate_population.fronts[front_num][0:half_population-len(children)]) 181 | front_num += 1 182 | half_population = int(self.num_of_individuals/2) 183 | while len(children) < half_population: 184 | children.append(mutate_population.fronts[0][0]) 185 | # mutate half best individual 186 | for individual in children: 187 | cnt_mutate = 0 188 | #print(individual) 189 | operation_index = len(individual.features[0][-1])-1 190 | while cnt_mutate < num_mutate : 191 | index1 = random.randint(0,operation_index) 192 | index2 = random.randint(0,operation_index) 193 | if individual.features[0][-1][index1]!=individual.features[0][-1][index2]: 194 | tmp = individual.features[0][-1][index1] 195 | individual.features[0][-1][index1] = individual.features[0][-1][index2] 196 | individual.features[0][-1][index2] = tmp 197 | cnt_mutate+=1 198 | return children 199 | def __reseeding(self, population): 200 | half_population = int(self.num_of_individuals/2) # reseed half of initial population 201 | children = Population() 202 | for _ in range(half_population): 203 | individual = self.problem.generate_individual() 204 | children.append(individual) 205 | return children 206 | def __tournament(self, population): 207 | participants = random.sample(population.population, self.num_of_tour_particips) 208 | best = None 209 | for participant in participants: 210 | if best is None or (self.crowding_operator(participant, best) == 1 and self.__choose_with_prob(self.tournament_prob)): 211 | best = participant 212 | return best 213 | def __get_delta(self): 214 | u = random.random() 215 | if u < 0.5: 216 | return u, (2*u)**(1/(self.mutation_param + 1)) - 1 217 | return u, 1 - (2*(1-u))**(1/(self.mutation_param + 1)) 218 | def __choose_with_prob(self, prob): 219 | if random.random() <= prob: 220 | return True 221 | return False 222 | def calculate_crowding_distance(self, front): 223 | if len(front) > 0: 224 | solutions_num = len(front) 225 | for individual in front: 226 | individual.crowding_distance = 0 227 | 228 | for m in range(len(front[0].objectives)): 229 | front.sort(key=lambda individual: individual.objectives[m]) 230 | front[0].crowding_distance = 10**9 231 | front[solutions_num-1].crowding_distance = 10**9 232 | m_values = [individual.objectives[m] for individual in front] 233 | scale = max(m_values) - min(m_values) 234 | if scale == 0: scale = 1 235 | for i in range(1, solutions_num-1): 236 | front[i].crowding_distance += (front[i+1].objectives[m] - front[i-1].objectives[m])/scale 237 | #%% 238 | class myEvolution(Evolution): 239 | 240 | def __init__(self, problem, num_of_generations=1000, num_of_individuals=100, num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5,mutation_schedule=[[0,20],[50,15],[100,10]]): 241 | self.population = None 242 | self.num_of_generations = num_of_generations 243 | self.on_generation_finished = [] 244 | self.num_of_individuals = num_of_individuals 245 | self.mutation_schedule = mutation_schedule 246 | self.utils = myUtils(problem, num_of_individuals, num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 247 | def evolve(self): 248 | self.population = self.utils.create_initial_population() 249 | self.utils.fast_nondominated_sort(self.population) 250 | for front in self.population.fronts: 251 | self.utils.calculate_crowding_distance(front) 252 | num_mutate = self.mutation_schedule[0][1] 253 | mutate_index = 1 254 | 255 | returned_population = None 256 | for i in range(self.num_of_generations): 257 | print('generation : ' + str(i)) 258 | children = self.utils.create_children(self.population,num_mutate) 259 | self.population.extend(children) 260 | self.utils.fast_nondominated_sort(self.population) 261 | # for tmptest in self.population.fronts: 262 | # print(len(tmptest)) 263 | new_population = Population() 264 | front_num = 0 265 | # print(self.population.fronts) 266 | while len(new_population) + len(self.population.fronts[front_num]) <= self.num_of_individuals : 267 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 268 | new_population.extend(self.population.fronts[front_num]) 269 | front_num += 1 270 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 271 | self.population.fronts[front_num].sort(key=lambda individual: individual.crowding_distance, reverse=True) 272 | new_population.extend(self.population.fronts[front_num][0:self.num_of_individuals-len(new_population)]) 273 | returned_population = self.population 274 | self.population = new_population 275 | self.utils.fast_nondominated_sort(self.population) 276 | for front in self.population.fronts: 277 | self.utils.calculate_crowding_distance(front) 278 | if mutate_index < len(self.mutation_schedule) and i == self.mutation_schedule[mutate_index][0]: 279 | num_mutate = self.mutation_schedule[mutate_index][1] 280 | mutate_index+=1 281 | return returned_population.fronts[0] 282 | -------------------------------------------------------------------------------- /code/Class_define_ESNSGA_jsp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Dec 25 16:25:35 2021 4 | 5 | @author: acanlab 6 | """ 7 | from nsga2.utils import NSGA2Utils 8 | from nsga2.problem import Problem 9 | from nsga2.evolution import Evolution 10 | import matplotlib.pyplot as plt 11 | import random 12 | import numpy as np 13 | from nsga2.individual import Individual 14 | from nsga2.population import Population 15 | import copy 16 | import queue 17 | #%% 18 | class myIndividual(Individual): 19 | def __init__(self): 20 | super(myIndividual,self).__init__() 21 | self.features = [] 22 | def __eq__(self, other): 23 | if isinstance(self, other.__class__): 24 | for x in range(len(self.features)): 25 | for y in range(len(self.features[x])): 26 | if self.features[x][y] != other.features[x][y]: 27 | # print(self.features[x][y]) 28 | return False 29 | return True 30 | return False 31 | def dominates(self, other_individual): 32 | and_condition = True 33 | or_condition = False 34 | for first, second in zip(self.objectives, other_individual.objectives): 35 | and_condition = and_condition and first <= second 36 | or_condition = or_condition or first < second 37 | return (and_condition and or_condition) 38 | #%% 39 | class myProblem(Problem): 40 | def __init__(self, objectives, num_of_variables, variables_range, operation_num_per_jobs, job_machine_operation_map, objective_obj, expand=True, same_range=False): 41 | super(myProblem,self).__init__(objectives, num_of_variables, variables_range, expand, same_range) 42 | self.operation_num_per_jobs = operation_num_per_jobs 43 | self.job_machine_operation_map = job_machine_operation_map 44 | self.objective_obj = objective_obj 45 | if same_range: 46 | for _ in range(num_of_variables): 47 | self.variables_range.append(variables_range[0]) 48 | else: 49 | self.variables_range = variables_range 50 | def generate_machine_schedule(self,job_nums): 51 | tmp = self.variables_range[2] 52 | schedule = [] 53 | for job_index in range(job_nums): 54 | operate_nums = self.variables_range[1][job_index] 55 | tmp_schedule = [] 56 | for operate in range(operate_nums): 57 | #set each operation operate on machine in random 58 | operate_machine_nums = len(tmp[job_index][operate]) 59 | index = random.randint(0,operate_machine_nums-1) 60 | tmp_schedule.append(tmp[job_index][operate][index]) 61 | schedule.append(tmp_schedule) 62 | return schedule 63 | def generate_individual(self): 64 | individual = myIndividual() 65 | job_nums = len(self.variables_range[0]) 66 | tmp_feature = [] 67 | for i in range(job_nums): 68 | threshold = random.random() 69 | if self.variables_range[0][i] <2: 70 | tmp_feature.append(1) 71 | else: 72 | if threshold >0.5: 73 | tmp_feature.append(1) 74 | else: 75 | tmp_feature.append(2) 76 | schedule = [] 77 | machine_schedule = [] 78 | for i in range(job_nums): 79 | if tmp_feature[i]==1: 80 | tmp_feature.append(self.variables_range[0][i]) 81 | for j in range(self.variables_range[1][i]): 82 | schedule.append([i,1]) 83 | else: 84 | batch1 = random.randint(1,self.variables_range[0][i]-1) 85 | batch2 = self.variables_range[0][i] - batch1 86 | tmp_feature.append(batch1) 87 | tmp_feature.append(batch2) 88 | for j in range(self.variables_range[1][i]): 89 | schedule.append([i,1]) 90 | #for j in range(self.variables_range[1][i]): 91 | schedule.append([i,2]) 92 | machine_schedule.append(self.generate_machine_schedule(job_nums)) 93 | random.shuffle(schedule) 94 | tmp_feature.append(schedule) 95 | tmp_feature.append(machine_schedule) 96 | individual.features.append(tmp_feature) 97 | return individual 98 | 99 | def calculate_objectives(self, individual): 100 | if self.expand: 101 | individual.objectives = [f(*individual.features) for f in self.objectives] 102 | else: 103 | individual.objectives = [f(individual.features) for f in self.objectives] 104 | #%% 105 | class myUtils(NSGA2Utils): 106 | 107 | def __init__(self, problem, num_of_individuals=100, 108 | num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5): 109 | super(myUtils, self).__init__(problem, num_of_individuals, 110 | num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 111 | def create_initial_population(self): 112 | population = Population() 113 | for _ in range(self.num_of_individuals): 114 | individual = self.problem.generate_individual() 115 | self.problem.calculate_objectives(individual) 116 | #print(individual.objectives) 117 | population.append(individual) 118 | return population 119 | def create_children(self, population, num_mutate): 120 | children = [] 121 | #print("len : " + str(len(population))) 122 | child_mutate_set = self.__mutate(population, num_mutate) 123 | child_reseeding_set = self.__reseeding(population) 124 | for child_mutate in child_mutate_set: 125 | self.problem.calculate_objectives(child_mutate) 126 | for child_reseeding in child_reseeding_set: 127 | self.problem.calculate_objectives(child_reseeding) 128 | 129 | children.extend(child_mutate_set) 130 | children.extend(child_reseeding_set) 131 | 132 | return children 133 | def __mutate(self, population, num_mutate): 134 | half_population = int(len(population)/2) 135 | front_num = 0 136 | children = Population() 137 | mutate_population = copy.deepcopy(population) 138 | # select half best individual 139 | while len(children) < half_population: 140 | if len(children)+len(mutate_population.fronts[front_num]) <= half_population: 141 | children.extend(mutate_population.fronts[front_num]) 142 | else: 143 | children.extend(mutate_population.fronts[front_num][0:half_population-len(children)]) 144 | front_num += 1 145 | # half_population = int(self.num_of_individuals/2) 146 | # while len(children) < half_population: 147 | # children.append(mutate_population.fronts[0][0]) 148 | # mutate half best individual 149 | for individual in children: 150 | cnt_mutate = 0 151 | #print(individual) 152 | operation_index = len(individual.features[0][-2])-1 153 | while cnt_mutate < num_mutate : 154 | index1 = random.randint(0,operation_index) 155 | index2 = random.randint(0,operation_index) 156 | 157 | if individual.features[0][-2][index1]!=individual.features[0][-2][index2]: 158 | tmp = copy.deepcopy(individual.features[0][-2][index1]) 159 | individual.features[0][-2][index1] = copy.deepcopy(individual.features[0][-2][index2]) 160 | individual.features[0][-2][index2] = tmp 161 | cnt_mutate+=1 162 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = self.problem.objective_obj.Calculate(*individual.features) 163 | threshold = random.random() 164 | return children 165 | def __reseeding(self, population): 166 | half_population = int(self.num_of_individuals/2) # reseed half of initial population 167 | children = Population() 168 | for _ in range(half_population): 169 | individual = self.problem.generate_individual() 170 | children.append(individual) 171 | return children 172 | def tabu_search(self,individual): 173 | tabu_list_len = 5 174 | tabu_list = [] 175 | best_individual = individual 176 | neighbor_searched = individual 177 | best_neighbor = [individual] 178 | iteration = 5 179 | pop_index = 0 180 | for i in range(iteration): 181 | #print("tabu searching ...") 182 | #print("iteration : "+str(i)) 183 | neighbor_searched, pop_index = self.tabu_search_iteration(neighbor_searched, 184 | best_individual, 185 | best_neighbor,tabu_list, 186 | tabu_list_len, 187 | pop_index) 188 | best_neighbor = [neighbor_searched] 189 | individual = best_individual 190 | 191 | 192 | def tabu_search_iteration(self,individual,best_individual,best_neighbor,tabu_list, 193 | tabu_list_len,pop_index): 194 | machine_schedule = individual.features[0][-1] 195 | cnt_machine = self.problem.variables_range[2] 196 | index = 0 197 | for batch in range(len(machine_schedule)): 198 | for job in range(len(machine_schedule[batch])): 199 | for operation in range(len(machine_schedule[batch][job])): 200 | #create one neighbor (change one machine schedule of one operation) 201 | machine_nums = len(cnt_machine[job][operation]) 202 | machine_index = random.randint(0,machine_nums-1) 203 | tmp_individual = copy.deepcopy(individual) 204 | tmp_individual.features[0][-1][batch][job][operation] = cnt_machine[job][operation][machine_index] 205 | 206 | # create another kind of neighbor (swap operation schedule one times) 207 | operation_index = len(individual.features[0][-2])-1 208 | index1 = 0 209 | index2 = 0 210 | while index1 == index2: 211 | index1 = random.randint(0,operation_index) 212 | index2 = random.randint(0,operation_index) 213 | tmp_individual2 = copy.deepcopy(individual) 214 | tmp = copy.deepcopy(tmp_individual2.features[0][-2][index1]) 215 | tmp_individual2.features[0][-2][index1] = copy.deepcopy(tmp_individual2.features[0][-2][index2]) 216 | tmp_individual2.features[0][-2][index2] = tmp 217 | #create third neighbor (change schedule like first neighbor with neightbor2) 218 | tmp_individual3 = copy.deepcopy(tmp_individual2) 219 | tmp_individual3.features[0][-1][batch][job][operation] = cnt_machine[job][operation][machine_index] 220 | 221 | self.problem.calculate_objectives(tmp_individual) 222 | self.problem.calculate_objectives(tmp_individual2) 223 | self.problem.calculate_objectives(tmp_individual3) 224 | if tmp_individual.dominates(best_neighbor[index]): 225 | #print("add neighbor") 226 | index+=1 227 | best_neighbor.append(tmp_individual) 228 | if tmp_individual2.dominates(best_neighbor[index]): 229 | #print("add neighbor") 230 | index+=1 231 | best_neighbor.append(tmp_individual2) 232 | if tmp_individual3.dominates(best_neighbor[index]): 233 | #print("add neighbor") 234 | index+=1 235 | best_neighbor.append(tmp_individual3) 236 | tabu_list_checked = False 237 | #print("checking") 238 | while not tabu_list_checked: 239 | if best_neighbor[index].dominates(best_individual): 240 | #print("update individual") 241 | best_individual = copy.deepcopy(best_neighbor[index]) 242 | if best_individual not in tabu_list: 243 | if len(tabu_list) == tabu_list_len: 244 | tabu_list[pop_index] = best_individual 245 | pop_index += 1 246 | if pop_index == tabu_list_len: 247 | pop_index = 0 248 | else: 249 | tabu_list.append(best_individual) 250 | tabu_list_checked=True 251 | else: 252 | if best_neighbor[index] not in tabu_list: 253 | if len(tabu_list) == tabu_list_len: 254 | tabu_list[pop_index] = best_neighbor[index] 255 | pop_index += 1 256 | if pop_index == tabu_list_len: 257 | pop_index = 0 258 | else: 259 | tabu_list.append(best_neighbor[index]) 260 | tabu_list_checked=True 261 | #any((1, 1) in item for item in q.queue) 262 | else: 263 | index-=1 264 | if index == -1: 265 | break 266 | return copy.deepcopy(best_neighbor[index]),pop_index 267 | def fast_nondominated_sort(self, population): 268 | population.fronts = [[]] 269 | for individual in population: 270 | individual.domination_count = 0 271 | individual.dominated_solutions = [] 272 | for other_individual in population: 273 | if individual.dominates(other_individual): 274 | individual.dominated_solutions.append(other_individual) 275 | elif other_individual.dominates(individual): 276 | individual.domination_count += 1 277 | if individual.domination_count == 0: 278 | individual.rank = 0 279 | population.fronts[0].append(individual) 280 | i = 0 281 | while len(population.fronts[i]) > 0: 282 | temp = [] 283 | for individual in population.fronts[i]: 284 | for other_individual in individual.dominated_solutions: 285 | other_individual.domination_count -= 1 286 | if other_individual.domination_count == 0: 287 | other_individual.rank = i+1 288 | temp.append(other_individual) 289 | i = i+1 290 | population.fronts.append(temp) 291 | # print("poplen : "+str(len(population))) 292 | def __tournament(self, population): 293 | participants = random.sample(population.population, self.num_of_tour_particips) 294 | best = None 295 | for participant in participants: 296 | if best is None or (self.crowding_operator(participant, best) == 1 and self.__choose_with_prob(self.tournament_prob)): 297 | best = participant 298 | return best 299 | def __get_delta(self): 300 | u = random.random() 301 | if u < 0.5: 302 | return u, (2*u)**(1/(self.mutation_param + 1)) - 1 303 | return u, 1 - (2*(1-u))**(1/(self.mutation_param + 1)) 304 | def __choose_with_prob(self, prob): 305 | if random.random() <= prob: 306 | return True 307 | return False 308 | def calculate_crowding_distance(self, front): 309 | if len(front) > 0: 310 | solutions_num = len(front) 311 | for individual in front: 312 | individual.crowding_distance = 0 313 | 314 | for m in range(len(front[0].objectives)): 315 | front.sort(key=lambda individual: individual.objectives[m]) 316 | front[0].crowding_distance = 10**9 317 | front[solutions_num-1].crowding_distance = 10**9 318 | m_values = [individual.objectives[m] for individual in front] 319 | scale = max(m_values) - min(m_values) 320 | if scale == 0: scale = 1 321 | for i in range(1, solutions_num-1): 322 | front[i].crowding_distance += (front[i+1].objectives[m] - front[i-1].objectives[m])/scale 323 | #%% 324 | class myEvolution(Evolution): 325 | 326 | def __init__(self, problem, num_of_generations=1000, num_of_individuals=100, num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5,mutation_schedule=[[0,20],[50,15],[100,10]]): 327 | self.population = None 328 | self.num_of_generations = num_of_generations 329 | self.on_generation_finished = [] 330 | self.num_of_individuals = num_of_individuals 331 | self.mutation_schedule = mutation_schedule 332 | self.utils = myUtils(problem, num_of_individuals, num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 333 | def evolve(self): 334 | self.population = self.utils.create_initial_population() 335 | #檢查到這 336 | self.utils.fast_nondominated_sort(self.population) 337 | for front in self.population.fronts: 338 | self.utils.calculate_crowding_distance(front) 339 | num_mutate = self.mutation_schedule[0][1] 340 | mutate_index = 1 341 | max_search_nums = 100 342 | returned_population = None 343 | min_makespan = np.inf 344 | for i in range(self.num_of_generations): 345 | print('generation : ' + str(i)) 346 | children = self.utils.create_children(self.population,num_mutate) 347 | # self.population = Population() 348 | self.population.extend(children) 349 | self.utils.fast_nondominated_sort(self.population) 350 | # self.utils.fast_nondominated_sort(children) 351 | for individual in self.population: 352 | if individual.objectives[0] < min_makespan: 353 | min_makespan = individual.objectives[0] 354 | print('Makespan : ' +str(min_makespan)) 355 | # for individual in children: 356 | # if individual.objectives[0] < min_makespan: 357 | # min_makespan = individual.objectives[0] 358 | # print('Makespan : ' +str(min_makespan)) 359 | cnt=0 360 | # tabu_search_rate = 100 361 | # if ((i+1) % tabu_search_rate)==0: 362 | # for individual in self.population.fronts[0]: 363 | # print("tabu searching") 364 | # print("individual : " + str(cnt)) 365 | # self.utils.tabu_search(individual) 366 | # cnt+=1 367 | # if cnt==max_search_nums: 368 | # break 369 | new_population = Population() 370 | front_num = 0 371 | # print(self.population.fronts) 372 | while len(new_population) + len(self.population.fronts[front_num]) <= self.num_of_individuals : 373 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 374 | new_population.extend(self.population.fronts[front_num]) 375 | front_num += 1 376 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 377 | self.population.fronts[front_num].sort(key=lambda individual: individual.crowding_distance, reverse=True) 378 | new_population.extend(self.population.fronts[front_num][0:self.num_of_individuals-len(new_population)]) 379 | returned_population = copy.deepcopy(self.population) 380 | 381 | self.population = copy.deepcopy(new_population) 382 | self.utils.fast_nondominated_sort(self.population) 383 | for front in self.population.fronts: 384 | self.utils.calculate_crowding_distance(front) 385 | if mutate_index < len(self.mutation_schedule) and i == self.mutation_schedule[mutate_index][0]: 386 | num_mutate = self.mutation_schedule[mutate_index][1] 387 | mutate_index+=1 388 | # cnt=0 389 | # for individual in returned_population.fronts[0]: 390 | # print("tabu searching") 391 | # print("individual : " + str(cnt)) 392 | # self.utils.tabu_search(individual) 393 | # cnt+=1 394 | # if cnt==max_search_nums: 395 | # break 396 | # if individual.objectives[0] < min_makespan: 397 | # min_makespan = individual.objectives[0] 398 | # print('Makespan : ' +str(min_makespan)) 399 | return returned_population.fronts[0], min_makespan 400 | class objective_calculation: 401 | def __init__(self, job_cnt, machine_cnt, job_machine_operation_map, obj_matrix, machine_distance,color): 402 | self.job_cnt = job_cnt 403 | self.machine_cnt = machine_cnt 404 | self.job_machine_operation_map = job_machine_operation_map 405 | self.obj_matrix = obj_matrix 406 | self.machine_distance = machine_distance 407 | self.color = color 408 | def split_Gene(self,Gene): 409 | job_batch = [] 410 | tmp_batch_size = [] 411 | cnt = 0 412 | #print(Gene) 413 | while cnt < len(Gene): 414 | if cnt==0: 415 | for i in range(len(self.job_cnt)): 416 | job_batch.append(Gene[cnt]) 417 | cnt+=1 418 | tmp_batch_size.append(Gene[cnt]) 419 | cnt+=1 420 | batch_size = tmp_batch_size[:-2] 421 | schedule = tmp_batch_size[-2] 422 | machine_schedule = tmp_batch_size[-1] 423 | cnt1=0 424 | batch_size_per_job=[]*len(job_batch) 425 | operation_processing=[]*len(job_batch) 426 | last_machine_operate=[]*len(job_batch) 427 | last_operate_end_time=[]*len(job_batch) 428 | for job_cnt_tmp in job_batch: 429 | batch_set = [] 430 | tmp_set1 = [] 431 | tmp_set2 = [] 432 | tmp_set3 = [] 433 | for i in range(cnt1,job_cnt_tmp+cnt1): 434 | batch_set.append(batch_size[i]) 435 | tmp_set1.append(0) 436 | tmp_set2.append(-1) 437 | tmp_set3.append(0) 438 | batch_size_per_job.append(batch_set) 439 | operation_processing.append(tmp_set1) 440 | last_machine_operate.append(tmp_set2) 441 | last_operate_end_time.append(tmp_set3) 442 | cnt1+=job_cnt_tmp 443 | 444 | return job_batch, batch_size, schedule, batch_size_per_job, operation_processing, last_machine_operate, last_operate_end_time, machine_schedule 445 | def Calculate(self,Gene): 446 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = self.split_Gene(Gene) 447 | machine_nums = self.machine_cnt 448 | # job_nums = N_jobs #global variable job count 449 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 450 | machine_blank_space = [[0] for _ in range(machine_nums) ] # store each machine blank space 451 | schedule_results = [[] for _ in range(machine_nums)] #schedule results version 1 452 | schedule_results_v2 = copy.deepcopy(machine_schedule)#schedule results version 2 453 | transportation_time = 0 454 | transfer_time = 0 455 | energy = 0 456 | for operation in schedule: 457 | 458 | job_index = operation[0] 459 | batch_index = operation[1]-1 460 | op = operation_processing[job_index][batch_index] 461 | machine_schedule_index = machine_schedule[batch_index][job_index][op] 462 | time = self.job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 463 | last_machine = last_machine_operate[job_index][batch_index] 464 | operate_time = last_operate_end_time[job_index][batch_index] 465 | machine_blank_space_size = len(machine_blank_space[machine_schedule_index]) 466 | find_blank = False 467 | # for blank_index in range(1,machine_blank_space_size): 468 | # blank_start = machine_blank_space[machine_schedule_index][blank_index][0] 469 | # blank_end = machine_blank_space[machine_schedule_index][blank_index][1] 470 | # blank_size = blank_end-blank_start 471 | # if blank_size >= time and blank_start>=operate_time: 472 | # find_blank = True 473 | # total_time = blank_start + time 474 | # machine_blank_space[machine_schedule_index][blank_index][0] = total_time 475 | # last_operate_end_time[job_index][batch_index] = total_time 476 | # last_machine_operate[job_index][batch_index] =machine_schedule_index 477 | # schedule_results[machine_schedule_index].append([job_index, 478 | # batch_index, 479 | # op, 480 | # blank_start, 481 | # time]) 482 | # schedule_results_v2[batch_index][job_index][op] = \ 483 | # [machine_schedule_index, 484 | # blank_start,time] 485 | # break 486 | # elif blank_size >= time and blank_start= time+operate_time: 488 | # find_blank = True 489 | # total_time = operate_time + time 490 | # machine_blank_space[machine_schedule_index][blank_index][1] = operate_time 491 | # last_operate_end_time[job_index][batch_index] = total_time 492 | # last_machine_operate[job_index][batch_index] =machine_schedule_index 493 | # schedule_results[machine_schedule_index].append([job_index, 494 | # batch_index, 495 | # op, 496 | # operate_time, 497 | # time]) 498 | # schedule_results_v2[batch_index][job_index][op] = \ 499 | # [machine_schedule_index, 500 | # operate_time,time] 501 | # break 502 | if not find_blank: 503 | machine_time = time + machine_end_time[machine_schedule_index] 504 | op_time = time + operate_time 505 | total_time = max(machine_time, op_time) 506 | last_operate_end_time[job_index][batch_index] = total_time 507 | machine_end_time[machine_schedule_index] = total_time 508 | last_machine_operate[job_index][batch_index] = machine_schedule_index 509 | if machine_time == total_time: 510 | machine_blank_space[machine_schedule_index][0] = total_time 511 | schedule_results[machine_schedule_index].append([job_index, 512 | batch_index, 513 | op, 514 | machine_time-time, 515 | time]) 516 | schedule_results_v2[batch_index][job_index][op] = \ 517 | [machine_schedule_index, 518 | machine_time-time,time] 519 | else: 520 | machine_blank_space[machine_schedule_index].append([machine_time-time,op_time-time]) 521 | schedule_results[machine_schedule_index].append([job_index, 522 | batch_index, 523 | op, 524 | op_time-time, 525 | time]) 526 | schedule_results_v2[batch_index][job_index][op] = \ 527 | [machine_schedule_index, 528 | op_time-time,time] 529 | 530 | operation_processing[job_index][batch_index] += 1 531 | if last_machine!=-1: 532 | transportation_time += self.machine_distance[last_machine][machine_schedule_index] 533 | # if last_machine!=machine_schedule_index: 534 | # transfer_time += (self.obj_matrix[last_machine][1]+self.obj_matrix[machine_schedule_index][0]) 535 | # energy += self.obj_matrix[machine_schedule_index][3]*total_time 536 | 537 | 538 | 539 | 540 | 541 | 542 | makespan = max(machine_end_time) 543 | makespan_index = np.argmax(machine_end_time) 544 | for machine in schedule_results: 545 | machine.sort(key = lambda x:x[3]) 546 | return makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 547 | def Makespan(self,Gene): 548 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = self.Calculate(Gene) 549 | return makespan 550 | def Transfer_time(self,Gene): 551 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = self.Calculate(Gene) 552 | return transfer_time 553 | def Transportation_time(self,Gene): 554 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = self.Calculate(Gene) 555 | return transportation_time 556 | def Energy(self,Gene): 557 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = self.Calculate(Gene) 558 | return energy 559 | def plot_gantt(self,schedule_results): 560 | for machine_index in range(len(schedule_results)): 561 | for schedule in schedule_results[machine_index]: 562 | job_index = schedule[0] 563 | batch_index = schedule[1] 564 | operation_index = schedule[2] 565 | start_time = schedule[3] 566 | time = schedule[4] 567 | c = self.color[job_index] 568 | plt.barh(machine_index,time,left=start_time,color=c) 569 | plt.text(time/4+start_time,machine_index,'J'+str(job_index)+'o'+str(operation_index),color='white') 570 | # plt.barh(machine_schedule_index,time,left=machine_end_time[machine_schedule_index]-time,color=c) 571 | # plt.text(time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(0),color='white') 572 | 573 | 574 | plt.show() 575 | def check_schedule(self,schedule_results,schedule_results_v2): 576 | self.check_schedule1(schedule_results) 577 | self.check_schedule2(schedule_results_v2) 578 | print("Schedule is Valid !!") 579 | def check_schedule1(self,schedule_results): 580 | for machine in schedule_results: 581 | for machine_schedule_index1 in range(len(machine)): 582 | for machine_schedule_index2 in range(machine_schedule_index1+1,len(machine)): 583 | start_time1 = machine[machine_schedule_index1][3] 584 | time1 = machine[machine_schedule_index1][4] 585 | start_time2 = machine[machine_schedule_index2][3] 586 | if start_time1 + time1 > start_time2: 587 | print("index1: " + str(machine_schedule_index1)) 588 | print("index2: " + str(machine_schedule_index2)) 589 | print("False") 590 | return 591 | def check_schedule2(self,schedule_results_v2): 592 | for batch in schedule_results_v2: 593 | for job in batch: 594 | for operation_index1 in range(len(job)): 595 | for operation_index2 in range(operation_index1+1,len(job)): 596 | start_time1 = job[operation_index1][1] 597 | time1 = job[operation_index1][2] 598 | start_time2 = job[operation_index2][1] 599 | if start_time1 + time1 > start_time2: 600 | print("index1: " + str(operation_index1)) 601 | print("index2: " + str(operation_index2)) 602 | print("False") 603 | return 604 | 605 | -------------------------------------------------------------------------------- /code/Class_define_NSGA_nonVB.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Dec 25 16:25:35 2021 4 | 5 | @author: acanlab 6 | """ 7 | from nsga2.utils import NSGA2Utils 8 | from nsga2.problem import Problem 9 | from nsga2.evolution import Evolution 10 | import matplotlib.pyplot as plt 11 | import random 12 | import numpy as np 13 | from nsga2.individual import Individual 14 | from nsga2.population import Population 15 | import copy 16 | #%% 17 | class myIndividual(Individual): 18 | def __init__(self): 19 | super(myIndividual,self).__init__() 20 | self.features = [] 21 | def __eq__(self, other): 22 | if isinstance(self, other.__class__): 23 | for x in range(len(self.features)): 24 | for y in range(len(self.features[x])): 25 | if self.features[x][y] != other.features[x][y]: 26 | # print(self.features[x][y]) 27 | return False 28 | return True 29 | return False 30 | def dominates(self, other_individual): 31 | and_condition = True 32 | or_condition = False 33 | for first, second in zip(self.objectives, other_individual.objectives): 34 | and_condition = and_condition and first <= second 35 | or_condition = or_condition or first < second 36 | return (and_condition and or_condition) 37 | #%% 38 | class myProblem(Problem): 39 | def __init__(self, objectives, num_of_variables, variables_range, operation_num_per_jobs, job_machine_operation_map, expand=True, same_range=False): 40 | super(myProblem,self).__init__(objectives, num_of_variables, variables_range, expand, same_range) 41 | self.operation_num_per_jobs = operation_num_per_jobs 42 | self.job_machine_operation_map = job_machine_operation_map 43 | if same_range: 44 | for _ in range(num_of_variables): 45 | self.variables_range.append(variables_range[0]) 46 | else: 47 | self.variables_range = variables_range 48 | def valid_individual(self,individual): 49 | j=0 50 | for job in range(len(self.operation_num_per_jobs)): 51 | operation_num_per_jobs=self.operation_num_per_jobs[job] 52 | for i in range(operation_num_per_jobs): 53 | for k in range(j,j+self.operation_num_per_jobs[job]-1): 54 | if individual.features[1][k]>individual.features[1][k+1]: 55 | tmp = individual.features[1][k] 56 | individual.features[1][k] = individual.features[1][k+1] 57 | individual.features[1][k+1] = tmp 58 | j+=operation_num_per_jobs 59 | job=self.operation_num_per_jobs 60 | operation_index=0 61 | job_index=0 62 | for times in range(self.variables_range[1]): #for all operation 63 | #改到這 64 | if job[job_index]==operation_index: 65 | operation_index=0 66 | job_index+=1 67 | machine_index = individual.features[0][times] 68 | if self.job_machine_operation_map[job_index][operation_index][machine_index]==10000: 69 | N_machine = self.variables_range[0][0][1]+1 70 | for m in range(N_machine): #find the machine can operate this operation 71 | if self.job_machine_operation_map[job_index][operation_index][m] != 10000: 72 | individual.features[0][times] = m 73 | break 74 | operation_index +=1 75 | return individual 76 | def generate_machine_schedule(self,job_nums): 77 | machine_nums = len(self.job_machine_operation_map[0][0]) 78 | tmp = [] 79 | for job_index in range(job_nums): 80 | operate_nums = self.variables_range[1][job_index] 81 | record_machine_index_can_operate = [[] for _ in range(operate_nums)] 82 | for operate in range(operate_nums): 83 | for machine in range(machine_nums): 84 | if self.job_machine_operation_map[job_index][operate][machine]<10000: 85 | record_machine_index_can_operate[operate].append(machine) 86 | tmp.append(record_machine_index_can_operate) 87 | schedule = [] 88 | for job_index in range(job_nums): 89 | operate_nums = self.variables_range[1][job_index] 90 | tmp_schedule = [] 91 | for operate in range(operate_nums): 92 | #set each operation operate on machine in random 93 | operate_machine_nums = len(tmp[job_index][operate]) 94 | index = random.randint(0,operate_machine_nums-1) 95 | tmp_schedule.append(tmp[job_index][operate][index]) 96 | schedule.append(tmp_schedule) 97 | return schedule 98 | def generate_individual_2(self): 99 | individual = myIndividual() 100 | individual.features.append([int(random.uniform(*x)) for x in self.variables_range[0]]) 101 | tmp = np.array(range(self.variables_range[1])) 102 | random.shuffle(tmp) 103 | individual.features.append(tmp) 104 | individual = self.valid_individual(individual) 105 | #print("test") 106 | return individual 107 | def generate_individual(self): 108 | individual = myIndividual() 109 | job_nums = len(self.variables_range[0]) 110 | tmp_feature = [] 111 | for i in range(job_nums): 112 | threshold = random.random() 113 | if self.variables_range[0][i] <2: 114 | tmp_feature.append(1) 115 | else: 116 | if threshold >0.5: 117 | tmp_feature.append(1) 118 | else: 119 | tmp_feature.append(2) 120 | schedule = [] 121 | machine_schedule = [] 122 | for i in range(job_nums): 123 | if tmp_feature[i]==1: 124 | tmp_feature.append(self.variables_range[0][i]) 125 | for j in range(self.variables_range[1][i]): 126 | schedule.append([i,1]) 127 | else: 128 | batch1 = random.randint(1,self.variables_range[0][i]-1) 129 | batch2 = self.variables_range[0][i] - batch1 130 | tmp_feature.append(batch1) 131 | tmp_feature.append(batch2) 132 | for j in range(self.variables_range[1][i]): 133 | schedule.append([i,1]) 134 | for j in range(self.variables_range[1][i]): 135 | schedule.append([i,2]) 136 | machine_schedule.append(self.generate_machine_schedule(job_nums)) 137 | random.shuffle(schedule) 138 | tmp_feature.append(schedule) 139 | tmp_feature.append(machine_schedule) 140 | individual.features.append(tmp_feature) 141 | #individual = self.valid_individual(individual) 142 | #print("test") 143 | return individual 144 | 145 | def calculate_objectives(self, individual): 146 | if self.expand: 147 | individual.objectives = [f(*individual.features) for f in self.objectives] 148 | else: 149 | individual.objectives = [f(individual.features) for f in self.objectives] 150 | #%% 151 | class myUtils(NSGA2Utils): 152 | 153 | def __init__(self, problem, num_of_individuals=100, 154 | num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5): 155 | super(myUtils, self).__init__(problem, num_of_individuals, 156 | num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 157 | def create_children(self, population, num_mutate): 158 | children = [] 159 | while len(children) < len(population): 160 | parent1 = self.__tournament(population) 161 | parent2 = parent1 162 | while parent1 == parent2: 163 | parent2 = self.__tournament(population) 164 | child1, child2 = self.__crossover(parent1, parent2) 165 | threshold = random.random() 166 | if threshold < 0.3: 167 | self.__mutate(child1, num_mutate) 168 | self.__mutate(child2, num_mutate) 169 | self.problem.calculate_objectives(child1) 170 | self.problem.calculate_objectives(child2) 171 | children.append(child1) 172 | children.append(child2) 173 | 174 | return children 175 | def __crossover(self, individual1, individual2): 176 | child1 = self.problem.generate_individual() 177 | child2 = self.problem.generate_individual() 178 | child1.features[0][:-1] = copy.deepcopy(individual1.features[0][:-1]) 179 | child2.features[0][:-1] = copy.deepcopy(individual2.features[0][:-1]) 180 | #feature1 181 | job_cnt = len(self.problem.operation_num_per_jobs) 182 | jobset_1 = random.randint(0,job_cnt-1) 183 | feature1_len = len(individual1.features[0][-2]) 184 | tmp_index1 = 0 185 | tmp_index2 = 0 186 | for i in range(feature1_len): 187 | if individual1.features[0][-2][i][0] == jobset_1: 188 | child1.features[0][-2][i] = copy.deepcopy(individual1.features[0][-2][i]) 189 | else: 190 | while individual2.features[0][-2][tmp_index2][0] == jobset_1: 191 | tmp_index2+=1 192 | child1.features[0][-2][i] = copy.deepcopy(individual2.features[0][-2][tmp_index2]) 193 | tmp_index2+=1 194 | if individual2.features[0][-2][i][0] == jobset_1: 195 | child2.features[0][-2][i] = copy.deepcopy(individual2.features[0][-2][i]) 196 | else: 197 | while individual1.features[0][-2][tmp_index1][0] == jobset_1: 198 | tmp_index1+=1 199 | child2.features[0][-2][i] = copy.deepcopy(individual1.features[0][-2][tmp_index1]) 200 | tmp_index1+=1 201 | 202 | #feature2 203 | batch_size1 = len(individual1.features[0][-1]) 204 | batch_size2 = len(individual2.features[0][-1]) 205 | min_batch_size = min(batch_size1, batch_size2) 206 | for batch in range(min_batch_size): 207 | job_len = len(individual1.features[0][-1][batch]) 208 | crossover_point = random.randint(0,job_len-1) 209 | child1.features[0][-1][batch][:crossover_point] = copy.deepcopy(individual1.features[0][-1][batch][:crossover_point]) 210 | child1.features[0][-1][batch][crossover_point:] = copy.deepcopy(individual2.features[0][-1][batch][crossover_point:]) 211 | child2.features[0][-1][batch][:crossover_point] = copy.deepcopy(individual2.features[0][-1][batch][:crossover_point]) 212 | child2.features[0][-1][batch][crossover_point:] = copy.deepcopy(individual1.features[0][-1][batch][crossover_point:]) 213 | 214 | return child1, child2 215 | def __mutate(self, individual, num_mutate): 216 | cnt_mutate = 0 217 | #print(individual) 218 | cnt_mutate = 0 219 | #print(individual) 220 | operation_index = len(individual.features[0][-2])-1 221 | while cnt_mutate < num_mutate : 222 | index1 = random.randint(0,operation_index) 223 | index2 = random.randint(0,operation_index) 224 | 225 | if individual.features[0][-2][index1]!=individual.features[0][-2][index2]: 226 | tmp = individual.features[0][-2][index1] 227 | individual.features[0][-2][index1] = individual.features[0][-2][index2] 228 | individual.features[0][-2][index2] = tmp 229 | cnt_mutate+=1 230 | cnt_machine = self.problem.variables_range[2] 231 | for batch in range(len(individual.features[0][-1])): 232 | for job in range(len(individual.features[0][-1][batch])): 233 | operate_size = len(individual.features[0][-1][batch][job]) 234 | mutate_flag = 0 235 | while mutate_flag<=0: 236 | operate_index = random.randint(0,operate_size-1) 237 | cnt_machine_size = len(cnt_machine[job][operate_index]) 238 | machine_index = random.randint(0,cnt_machine_size-1) 239 | if machine_index != individual.features[0][-1][batch][job][operate_index]: 240 | individual.features[0][-1][batch][job][operate_index] = cnt_machine[job][operate_index][machine_index] 241 | mutate_flag += 1 242 | return individual 243 | def __reseeding(self, population): 244 | half_population = int(self.num_of_individuals/2) # reseed half of initial population 245 | children = Population() 246 | for _ in range(half_population): 247 | individual = self.problem.generate_individual() 248 | children.append(individual) 249 | return children 250 | 251 | def fast_nondominated_sort(self, population): 252 | population.fronts = [[]] 253 | for individual in population: 254 | individual.domination_count = 0 255 | individual.dominated_solutions = [] 256 | for other_individual in population: 257 | if individual.dominates(other_individual): 258 | individual.dominated_solutions.append(other_individual) 259 | elif other_individual.dominates(individual): 260 | individual.domination_count += 1 261 | if individual.domination_count == 0: 262 | individual.rank = 0 263 | population.fronts[0].append(individual) 264 | i = 0 265 | while len(population.fronts[i]) > 0: 266 | temp = [] 267 | for individual in population.fronts[i]: 268 | for other_individual in individual.dominated_solutions: 269 | other_individual.domination_count -= 1 270 | if other_individual.domination_count == 0: 271 | other_individual.rank = i+1 272 | temp.append(other_individual) 273 | i = i+1 274 | population.fronts.append(temp) 275 | # print("poplen : "+str(len(population))) 276 | def __tournament(self, population): 277 | participants = random.sample(population.population, self.num_of_tour_particips) 278 | best = None 279 | for participant in participants: 280 | if best is None or (self.crowding_operator(participant, best) == 1 and self.__choose_with_prob(self.tournament_prob)): 281 | best = participant 282 | return best 283 | def __get_delta(self): 284 | u = random.random() 285 | if u < 0.5: 286 | return u, (2*u)**(1/(self.mutation_param + 1)) - 1 287 | return u, 1 - (2*(1-u))**(1/(self.mutation_param + 1)) 288 | def __choose_with_prob(self, prob): 289 | if random.random() <= prob: 290 | return True 291 | return False 292 | def calculate_crowding_distance(self, front): 293 | if len(front) > 0: 294 | solutions_num = len(front) 295 | for individual in front: 296 | individual.crowding_distance = 0 297 | 298 | for m in range(len(front[0].objectives)): 299 | front.sort(key=lambda individual: individual.objectives[m]) 300 | front[0].crowding_distance = 10**9 301 | front[solutions_num-1].crowding_distance = 10**9 302 | m_values = [individual.objectives[m] for individual in front] 303 | scale = max(m_values) - min(m_values) 304 | if scale == 0: scale = 1 305 | for i in range(1, solutions_num-1): 306 | front[i].crowding_distance += (front[i+1].objectives[m] - front[i-1].objectives[m])/scale 307 | #%% 308 | class myEvolution(Evolution): 309 | 310 | def __init__(self, problem, num_of_generations=1000, num_of_individuals=100, num_of_tour_particips=2, tournament_prob=0.9, crossover_param=2, mutation_param=5,mutation_schedule=[[0,20],[50,15],[100,10]]): 311 | self.population = None 312 | self.num_of_generations = num_of_generations 313 | self.on_generation_finished = [] 314 | self.num_of_individuals = num_of_individuals 315 | self.mutation_schedule = mutation_schedule 316 | self.utils = myUtils(problem, num_of_individuals, num_of_tour_particips, tournament_prob, crossover_param, mutation_param) 317 | def evolve(self): 318 | self.population = self.utils.create_initial_population() 319 | self.utils.fast_nondominated_sort(self.population) 320 | for front in self.population.fronts: 321 | self.utils.calculate_crowding_distance(front) 322 | num_mutate = self.mutation_schedule[0][1] 323 | mutate_index = 1 324 | min_makespan = np.inf 325 | returned_population = None 326 | for i in range(self.num_of_generations): 327 | print('generation : ' + str(i)) 328 | children = self.utils.create_children(self.population,num_mutate) 329 | self.population.extend(children) 330 | self.utils.fast_nondominated_sort(self.population) 331 | # for tmptest in self.population.fronts: 332 | # print(len(tmptest)) 333 | new_population = Population() 334 | front_num = 0 335 | # print(self.population.fronts) 336 | for individual in self.population: 337 | if individual.objectives[0] < min_makespan: 338 | min_makespan = individual.objectives[0] 339 | print('Makespan : ' +str(min_makespan)) 340 | while len(new_population) + len(self.population.fronts[front_num]) <= self.num_of_individuals : 341 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 342 | new_population.extend(self.population.fronts[front_num]) 343 | front_num += 1 344 | self.utils.calculate_crowding_distance(self.population.fronts[front_num]) 345 | self.population.fronts[front_num].sort(key=lambda individual: individual.crowding_distance, reverse=True) 346 | 347 | if front_num==0: 348 | random.shuffle(self.population.fronts[front_num]) 349 | last = self.num_of_individuals-len(new_population) 350 | # new_population.extend(self.population.fronts[front_num]) 351 | new_population.extend(self.population.fronts[front_num][:last]) 352 | returned_population = copy.deepcopy(self.population) 353 | self.population = copy.deepcopy(new_population) 354 | self.utils.fast_nondominated_sort(self.population) 355 | for front in self.population.fronts: 356 | self.utils.calculate_crowding_distance(front) 357 | if mutate_index < len(self.mutation_schedule) and i == self.mutation_schedule[mutate_index][0]: 358 | num_mutate = self.mutation_schedule[mutate_index][1] 359 | mutate_index+=1 360 | 361 | return returned_population.fronts[0] 362 | -------------------------------------------------------------------------------- /code/MO-G-FJSP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 21 13:39:12 2021 4 | 5 | @author: acanlab 6 | """ 7 | import matplotlib.pyplot as plt 8 | import random 9 | import numpy as np 10 | from Class_define_ESNSGA import myProblem 11 | from Class_define_ESNSGA import myEvolution 12 | #%% 13 | path = 'C:\\Users\\acanlab\\Desktop\\sihan\\nsga\\nsga2_data\\MO-G-FJSP_P1.fjs' 14 | f = open(path, 'r') 15 | line_cnt=0 16 | index_of_map=0 17 | total_operation=0 18 | 19 | color = ['red','green','blue','orange','yellow','purple','gray','pink','brown','black'] 20 | for line in f: 21 | line_split = line.split() 22 | if len(line_split)==0: 23 | continue 24 | if line_cnt==0: 25 | N_jobs = int(line_split[0]) 26 | N_machines = int(line_split[1]) 27 | job_machine_operation_map = [[]for _ in range(N_jobs)] 28 | operation_arr = [] 29 | job_cnt=[]*N_jobs 30 | machine_distance = [[0]*N_machines]*N_machines 31 | obj_matrix=[] 32 | elif line_cnt==1: #load job cnt 33 | job_cnt = [int(d) for d in line_split] 34 | elif line_cnt>=2 and line_cnt<2+N_machines: # load objective (total n_machine lines) 35 | tmp = []*5 36 | tmp = [int(d) for d in line_split] 37 | obj_matrix.append(tmp) 38 | elif line_cnt>=2+N_machines and line_cnt<2+N_machines+N_machines: #load machine distance 39 | #print(cnt) 40 | machine_distance[line_cnt-2-N_machines] = [int(d) for d in line_split] 41 | else: 42 | index_of_line_split = 0 43 | #Get numbers of operation of each job 44 | N_operations = int(line_split[index_of_line_split]) 45 | index_of_line_split +=1 46 | total_operation+=N_operations 47 | for i in range(N_operations): 48 | operation_arr.append([i,line_cnt-2-N_machines-N_machines]) #add to operation list for computing objective 49 | N_nums = int(line_split[index_of_line_split]) 50 | tmp = [10000 for _ in range(N_machines)] 51 | for j in range(N_nums): 52 | machine_index = int(line_split[index_of_line_split+1])-1 53 | operate_time = int(line_split[index_of_line_split+2]) 54 | tmp[machine_index] = operate_time 55 | index_of_line_split += 2 56 | job_machine_operation_map[index_of_map].append(tmp) 57 | index_of_line_split += 1 58 | index_of_map += 1 59 | line_cnt+=1 60 | f.close() 61 | #%% 62 | 63 | def split_Gene(Gene): 64 | job_batch = [] 65 | tmp_batch_size = [] 66 | cnt = 0 67 | #print(Gene) 68 | while cnt < len(Gene): 69 | if cnt==0: 70 | for i in range(len(job_cnt)): # job_cnt global variable 71 | job_batch.append(Gene[cnt]) 72 | cnt+=1 73 | tmp_batch_size.append(Gene[cnt]) 74 | cnt+=1 75 | batch_size = tmp_batch_size[:-1] 76 | schedule = tmp_batch_size[-1] 77 | cnt1=0 78 | batch_size_per_job=[]*len(job_batch) 79 | operation_processing=[]*len(job_batch) 80 | last_machine_operate=[]*len(job_batch) 81 | last_operate_end_time=[]*len(job_batch) 82 | for job_cnt_tmp in job_batch: 83 | batch_set = [] 84 | tmp_set1 = [] 85 | tmp_set2 = [] 86 | tmp_set3 = [] 87 | for i in range(cnt1,job_cnt_tmp+cnt1): 88 | batch_set.append(batch_size[i]) 89 | tmp_set1.append(-1) 90 | tmp_set2.append(-1) 91 | tmp_set3.append(-1) 92 | batch_size_per_job.append(batch_set) 93 | operation_processing.append(tmp_set1) 94 | last_machine_operate.append(tmp_set2) 95 | last_operate_end_time.append(tmp_set3) 96 | cnt1+=job_cnt_tmp 97 | 98 | return job_batch, batch_size, schedule, batch_size_per_job, operation_processing, last_machine_operate, last_operate_end_time 99 | def Calculate(Gene): 100 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time = split_Gene(Gene) 101 | machine_nums = N_machines # global variable machine count 102 | job_nums = N_jobs #global variable job count 103 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 104 | transportation_time = 0 105 | transfer_time = 0 106 | energy = 0 107 | for operation in schedule: 108 | 109 | job_index = operation[0] 110 | batch_index = operation[1]-1 111 | 112 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 113 | minima = 1000000 114 | mini_index = -1 115 | for i in range(machine_nums): 116 | time = job_machine_operation_map[job_index][0][i]*batch_size_per_job[job_index][batch_index] 117 | total_time = time + machine_end_time[i] 118 | if total_time < minima: 119 | minima = total_time 120 | mini_index = i 121 | # time = job_machine_operation_map[job_index][0][mini_index]*batch_size_per_job[job_index][batch_index] 122 | last_operate_end_time[job_index][batch_index] = minima 123 | machine_end_time[mini_index] = minima 124 | last_machine_operate[job_index][batch_index] = mini_index 125 | # plt.barh(mini_index,time,left=machine_end_time[mini_index],color=c) 126 | # plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 127 | 128 | operation_processing[job_index][batch_index] = 1 129 | transfer_time += obj_matrix[mini_index][0] 130 | energy += (obj_matrix[mini_index][3]*minima + obj_matrix[mini_index][4]) 131 | else: 132 | minima = 1000000 133 | mini_index = -1 134 | 135 | op = operation_processing[job_index][batch_index] 136 | last_machine = last_machine_operate[job_index][batch_index] 137 | operate_time = last_operate_end_time[job_index][batch_index] 138 | for i in range(machine_nums): 139 | time = job_machine_operation_map[job_index][op][i]*batch_size_per_job[job_index][batch_index] 140 | if time!= 10000: 141 | machine_time = time + machine_end_time[i] 142 | op_time = time + operate_time 143 | total_time = max(machine_time,op_time) 144 | if total_time < minima: 145 | minima = total_time 146 | mini_index = i 147 | #time = job_machine_operation_map[job_index][op][mini_index]*batch_size_per_job[job_index][batch_index] 148 | last_operate_end_time[job_index][batch_index] = minima 149 | machine_end_time[mini_index] = minima 150 | last_machine_operate[job_index][batch_index] = mini_index 151 | # plt.barh(mini_index,time,left=minima-time,color=c) 152 | # plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 153 | operation_processing[job_index][batch_index] += 1 154 | transportation_time += machine_distance[last_machine][mini_index] 155 | if last_machine!=mini_index: 156 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[mini_index][0]) 157 | energy += obj_matrix[mini_index][3]*minima 158 | 159 | 160 | makespan = max(machine_end_time) 161 | return makespan, transfer_time, transportation_time, energy 162 | def Makespan(Gene): 163 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 164 | return makespan 165 | def Transfer_time(Gene): 166 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 167 | return transfer_time 168 | def Transportation_time(Gene): 169 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 170 | return transportation_time 171 | def Energy(Gene): 172 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 173 | return energy 174 | def plot_gantt(feature): 175 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time = split_Gene(feature) 176 | machine_nums = N_machines # global variable machine count 177 | job_nums = N_jobs #global variable job count 178 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 179 | transportation_time = 0 180 | transfer_time = 0 181 | energy = 0 182 | for operation in schedule: 183 | 184 | job_index = operation[0] 185 | batch_index = operation[1]-1 186 | c = color[job_index] 187 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 188 | minima = 1000000 189 | mini_index = -1 190 | for i in range(machine_nums): 191 | time = job_machine_operation_map[job_index][0][i]*batch_size_per_job[job_index][batch_index] 192 | total_time = time + machine_end_time[i] 193 | if total_time < minima: 194 | minima = total_time 195 | mini_index = i 196 | time = job_machine_operation_map[job_index][0][mini_index]*batch_size_per_job[job_index][batch_index] 197 | last_operate_end_time[job_index][batch_index] = minima 198 | machine_end_time[mini_index] = minima 199 | last_machine_operate[job_index][batch_index] = mini_index 200 | plt.barh(mini_index,time,left=machine_end_time[mini_index]-time,color=c) 201 | plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 202 | 203 | operation_processing[job_index][batch_index] = 1 204 | transfer_time += obj_matrix[mini_index][0] 205 | energy += (obj_matrix[mini_index][3]*minima + obj_matrix[mini_index][4]) 206 | else: 207 | minima = 1000000 208 | mini_index = -1 209 | 210 | op = operation_processing[job_index][batch_index] 211 | last_machine = last_machine_operate[job_index][batch_index] 212 | operate_time = last_operate_end_time[job_index][batch_index] 213 | for i in range(machine_nums): 214 | time = job_machine_operation_map[job_index][op][i]*batch_size_per_job[job_index][batch_index] 215 | machine_time = time + machine_end_time[i] 216 | op_time = time + operate_time 217 | total_time = max(machine_time,op_time) 218 | if total_time < minima: 219 | minima = total_time 220 | mini_index = i 221 | time = job_machine_operation_map[job_index][op][mini_index]*batch_size_per_job[job_index][batch_index] 222 | last_operate_end_time[job_index][batch_index] = minima 223 | machine_end_time[mini_index] = minima 224 | last_machine_operate[job_index][batch_index] = mini_index 225 | plt.barh(mini_index,time,left=minima-time,color=c) 226 | plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 227 | operation_processing[job_index][batch_index] += 1 228 | transportation_time += machine_distance[last_machine][mini_index] 229 | if last_machine!=mini_index: 230 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[mini_index][0]) 231 | energy += obj_matrix[mini_index][3]*minima 232 | plt.show() 233 | #%% 234 | if __name__ == '__main__' : 235 | variables_range=[[(0,N_machines-1)]*total_operation,total_operation] 236 | operation_num_per_jobs = [] 237 | for i in range(len(job_machine_operation_map)): 238 | operation_num_per_jobs.append(len(job_machine_operation_map[i])) 239 | variable = [] 240 | job_cnt = [1]*N_jobs 241 | variable.append(job_cnt) 242 | variable.append(operation_num_per_jobs) 243 | fittness = [Makespan, Transfer_time] 244 | problem = myProblem(num_of_variables=1, 245 | objectives=fittness, 246 | variables_range=variable, 247 | operation_num_per_jobs=operation_num_per_jobs, 248 | job_machine_operation_map = job_machine_operation_map) 249 | individual_1 = problem.generate_individual() 250 | individual_2 = problem.generate_individual() 251 | problem.calculate_objectives(individual_1) 252 | problem.calculate_objectives(individual_2) 253 | print("Evolutioin......") 254 | evo = myEvolution(problem, num_of_generations=1000, num_of_individuals=1000, mutation_schedule=[[0,100],[100,50],[200,20],[300,10],[400,5],[500,3]]) 255 | evol = evo.evolve() 256 | func=[] 257 | feature=[] 258 | for i in range(len(evol)): 259 | func.append(evol[i].objectives) 260 | feature.append(evol[i].features) 261 | function1 = [i[0] for i in func] 262 | function2 = [i[1] for i in func] 263 | # function3 = [i[2] for i in func] 264 | # function4 = [i[3] for i in func] 265 | plt.xlabel('maxspan', fontsize=15) 266 | plt.ylabel('transfer_time', fontsize=15) 267 | plt.scatter(function1, function2) 268 | plt.show() 269 | 270 | print("End......") 271 | #%% testing 272 | # a, b ,c, d, e, f = split_Gene(individual_1.features[0]) 273 | # test = [f(*individual_1.features) for f in fittness] 274 | plot_gantt(feature[-1][0]) 275 | -------------------------------------------------------------------------------- /code/MO_G_FJSP_VB.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 21 13:39:12 2021 4 | 5 | @author: acanlab 6 | """ 7 | import matplotlib.pyplot as plt 8 | import random 9 | import numpy as np 10 | from Class_define_ESNSGA_VB import myProblem 11 | from Class_define_ESNSGA_VB import myEvolution 12 | #%% 13 | path = 'C:\\Users\\acanlab\\Desktop\\sihan\\nsga\\nsga2_data\\MO-G-FJSP_P1.fjs' 14 | f = open(path, 'r') 15 | line_cnt=0 16 | index_of_map=0 17 | total_operation=0 18 | 19 | color = ['red','green','blue','orange','yellow','purple','gray','pink','brown','black'] 20 | for line in f: 21 | line_split = line.split() 22 | if len(line_split)==0: 23 | continue 24 | if line_cnt==0: 25 | N_jobs = int(line_split[0]) 26 | N_machines = int(line_split[1]) 27 | job_machine_operation_map = [[]for _ in range(N_jobs)] 28 | operation_arr = [] 29 | job_cnt=[]*N_jobs 30 | machine_distance = [[0]*N_machines]*N_machines 31 | obj_matrix=[] 32 | elif line_cnt==1: #load job cnt 33 | job_cnt = [int(d) for d in line_split] 34 | elif line_cnt>=2 and line_cnt<2+N_machines: # load objective (total n_machine lines) 35 | tmp = []*5 36 | tmp = [int(d) for d in line_split] 37 | obj_matrix.append(tmp) 38 | elif line_cnt>=2+N_machines and line_cnt<2+N_machines+N_machines: #load machine distance 39 | #print(cnt) 40 | machine_distance[line_cnt-2-N_machines] = [int(d) for d in line_split] 41 | else: 42 | index_of_line_split = 0 43 | #Get numbers of operation of each job 44 | N_operations = int(line_split[index_of_line_split]) 45 | index_of_line_split +=1 46 | total_operation+=N_operations 47 | for i in range(N_operations): 48 | operation_arr.append([i,line_cnt-2-N_machines-N_machines]) #add to operation list for computing objective 49 | N_nums = int(line_split[index_of_line_split]) 50 | tmp = [10000 for _ in range(N_machines)] 51 | for j in range(N_nums): 52 | machine_index = int(line_split[index_of_line_split+1])-1 53 | operate_time = int(line_split[index_of_line_split+2]) 54 | tmp[machine_index] = operate_time 55 | index_of_line_split += 2 56 | job_machine_operation_map[index_of_map].append(tmp) 57 | index_of_line_split += 1 58 | index_of_map += 1 59 | line_cnt+=1 60 | f.close() 61 | #%% 62 | 63 | def split_Gene(Gene): 64 | job_batch = [] 65 | tmp_batch_size = [] 66 | cnt = 0 67 | #print(Gene) 68 | while cnt < len(Gene): 69 | if cnt==0: 70 | for i in range(len(job_cnt)): # job_cnt global variable 71 | job_batch.append(Gene[cnt]) 72 | cnt+=1 73 | tmp_batch_size.append(Gene[cnt]) 74 | cnt+=1 75 | batch_size = tmp_batch_size[:-1] 76 | schedule = tmp_batch_size[-1] 77 | cnt1=0 78 | batch_size_per_job=[]*len(job_batch) 79 | operation_processing=[]*len(job_batch) 80 | last_machine_operate=[]*len(job_batch) 81 | last_operate_end_time=[]*len(job_batch) 82 | for job_cnt_tmp in job_batch: 83 | batch_set = [] 84 | tmp_set1 = [] 85 | tmp_set2 = [] 86 | tmp_set3 = [] 87 | for i in range(cnt1,job_cnt_tmp+cnt1): 88 | batch_set.append(batch_size[i]) 89 | tmp_set1.append(-1) 90 | tmp_set2.append(-1) 91 | tmp_set3.append(-1) 92 | batch_size_per_job.append(batch_set) 93 | operation_processing.append(tmp_set1) 94 | last_machine_operate.append(tmp_set2) 95 | last_operate_end_time.append(tmp_set3) 96 | cnt1+=job_cnt_tmp 97 | 98 | return job_batch, batch_size, schedule, batch_size_per_job, operation_processing, last_machine_operate, last_operate_end_time 99 | def Calculate(Gene): 100 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time = split_Gene(Gene) 101 | machine_nums = N_machines # global variable machine count 102 | job_nums = N_jobs #global variable job count 103 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 104 | transportation_time = 0 105 | transfer_time = 0 106 | energy = 0 107 | for operation in schedule: 108 | 109 | job_index = operation[0] 110 | batch_index = operation[1]-1 111 | 112 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 113 | minima = 1000000 114 | mini_index = -1 115 | for i in range(machine_nums): 116 | time = job_machine_operation_map[job_index][0][i]*batch_size_per_job[job_index][batch_index] 117 | total_time = time + machine_end_time[i] 118 | if total_time < minima: 119 | minima = total_time 120 | mini_index = i 121 | # time = job_machine_operation_map[job_index][0][mini_index]*batch_size_per_job[job_index][batch_index] 122 | last_operate_end_time[job_index][batch_index] = minima 123 | machine_end_time[mini_index] = minima 124 | last_machine_operate[job_index][batch_index] = mini_index 125 | # plt.barh(mini_index,time,left=machine_end_time[mini_index],color=c) 126 | # plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 127 | 128 | operation_processing[job_index][batch_index] = 1 129 | transfer_time += obj_matrix[mini_index][0] 130 | energy += (obj_matrix[mini_index][3]*minima + obj_matrix[mini_index][4]) 131 | else: 132 | minima = 1000000 133 | mini_index = -1 134 | 135 | op = operation_processing[job_index][batch_index] 136 | last_machine = last_machine_operate[job_index][batch_index] 137 | operate_time = last_operate_end_time[job_index][batch_index] 138 | for i in range(machine_nums): 139 | time = job_machine_operation_map[job_index][op][i]*batch_size_per_job[job_index][batch_index] 140 | if time!= 10000: 141 | machine_time = time + machine_end_time[i] 142 | op_time = time + operate_time 143 | total_time = max(machine_time,op_time) 144 | if total_time < minima: 145 | minima = total_time 146 | mini_index = i 147 | #time = job_machine_operation_map[job_index][op][mini_index]*batch_size_per_job[job_index][batch_index] 148 | last_operate_end_time[job_index][batch_index] = minima 149 | machine_end_time[mini_index] = minima 150 | last_machine_operate[job_index][batch_index] = mini_index 151 | # plt.barh(mini_index,time,left=minima-time,color=c) 152 | # plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 153 | operation_processing[job_index][batch_index] += 1 154 | transportation_time += machine_distance[last_machine][mini_index] 155 | if last_machine!=mini_index: 156 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[mini_index][0]) 157 | energy += obj_matrix[mini_index][3]*minima 158 | 159 | 160 | makespan = max(machine_end_time) 161 | return makespan, transfer_time, transportation_time, energy 162 | def Makespan(Gene): 163 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 164 | return makespan 165 | def Transfer_time(Gene): 166 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 167 | return transfer_time 168 | def Transportation_time(Gene): 169 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 170 | return transportation_time 171 | def Energy(Gene): 172 | makespan, transfer_time, transportation_time, energy = Calculate(Gene) 173 | return energy 174 | def plot_gantt(feature): 175 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time = split_Gene(feature) 176 | machine_nums = N_machines # global variable machine count 177 | job_nums = N_jobs #global variable job count 178 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 179 | transportation_time = 0 180 | transfer_time = 0 181 | energy = 0 182 | for operation in schedule: 183 | 184 | job_index = operation[0] 185 | batch_index = operation[1]-1 186 | c = color[job_index] 187 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 188 | minima = 1000000 189 | mini_index = -1 190 | for i in range(machine_nums): 191 | time = job_machine_operation_map[job_index][0][i]*batch_size_per_job[job_index][batch_index] 192 | total_time = time + machine_end_time[i] 193 | if total_time < minima: 194 | minima = total_time 195 | mini_index = i 196 | time = job_machine_operation_map[job_index][0][mini_index]*batch_size_per_job[job_index][batch_index] 197 | last_operate_end_time[job_index][batch_index] = minima 198 | machine_end_time[mini_index] = minima 199 | last_machine_operate[job_index][batch_index] = mini_index 200 | plt.barh(mini_index,time,left=machine_end_time[mini_index]-time,color=c) 201 | plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 202 | 203 | operation_processing[job_index][batch_index] = 1 204 | transfer_time += obj_matrix[mini_index][0] 205 | energy += (obj_matrix[mini_index][3]*minima + obj_matrix[mini_index][4]) 206 | else: 207 | minima = 1000000 208 | mini_index = -1 209 | 210 | op = operation_processing[job_index][batch_index] 211 | last_machine = last_machine_operate[job_index][batch_index] 212 | operate_time = last_operate_end_time[job_index][batch_index] 213 | for i in range(machine_nums): 214 | time = job_machine_operation_map[job_index][op][i]*batch_size_per_job[job_index][batch_index] 215 | machine_time = time + machine_end_time[i] 216 | op_time = time + operate_time 217 | total_time = max(machine_time,op_time) 218 | if total_time < minima: 219 | minima = total_time 220 | mini_index = i 221 | time = job_machine_operation_map[job_index][op][mini_index]*batch_size_per_job[job_index][batch_index] 222 | last_operate_end_time[job_index][batch_index] = minima 223 | machine_end_time[mini_index] = minima 224 | last_machine_operate[job_index][batch_index] = mini_index 225 | plt.barh(mini_index,time,left=minima-time,color=c) 226 | plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 227 | operation_processing[job_index][batch_index] += 1 228 | transportation_time += machine_distance[last_machine][mini_index] 229 | if last_machine!=mini_index: 230 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[mini_index][0]) 231 | energy += obj_matrix[mini_index][3]*minima 232 | plt.show() 233 | #%% 234 | if __name__ == '__main__' : 235 | variables_range=[[(0,N_machines-1)]*total_operation,total_operation] 236 | operation_num_per_jobs = [] 237 | for i in range(len(job_machine_operation_map)): 238 | operation_num_per_jobs.append(len(job_machine_operation_map[i])) 239 | variable = [] 240 | job_cnt = [1]*N_jobs 241 | variable.append(job_cnt) 242 | variable.append(operation_num_per_jobs) 243 | fittness = [Makespan, Transfer_time] 244 | problem = myProblem(num_of_variables=1, 245 | objectives=fittness, 246 | variables_range=variable, 247 | operation_num_per_jobs=operation_num_per_jobs, 248 | job_machine_operation_map = job_machine_operation_map) 249 | individual_1 = problem.generate_individual() 250 | individual_2 = problem.generate_individual() 251 | problem.calculate_objectives(individual_1) 252 | problem.calculate_objectives(individual_2) 253 | print("Evolutioin......") 254 | evo = myEvolution(problem, num_of_generations=100, num_of_individuals=1000, mutation_schedule=[[0,10],[100,100],[200,80],[300,60],[400,40],[500,20],[600,10]]) 255 | evol = evo.evolve() 256 | func=[] 257 | feature=[] 258 | for i in range(len(evol)): 259 | func.append(evol[i].objectives) 260 | feature.append(evol[i].features) 261 | function1 = [i[0] for i in func] 262 | function2 = [i[1] for i in func] 263 | # function3 = [i[2] for i in func] 264 | # function4 = [i[3] for i in func] 265 | plt.xlabel('maxspan', fontsize=15) 266 | plt.ylabel('transfer_time', fontsize=15) 267 | plt.scatter(function1, function2) 268 | plt.show() 269 | 270 | print("End......") 271 | #%% testing 272 | # a, b ,c, d, e, f = split_Gene(individual_1.features[0]) 273 | # test = [f(*individual_1.features) for f in fittness] 274 | plot_gantt(feature[-1][0]) 275 | -------------------------------------------------------------------------------- /code/MO_G_FJSP_nonVB.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 21 13:39:12 2021 4 | 5 | @author: acanlab 6 | """ 7 | import matplotlib.pyplot as plt 8 | import random 9 | import numpy as np 10 | import time 11 | from Class_define_ESNSGA_nonVB import myProblem 12 | from Class_define_ESNSGA_nonVB import myEvolution 13 | from Class_define_ESNSGA_nonVB import objective_calculation 14 | from Class_define_ESNSGA_nonVB import myUtils 15 | from nsga2.population import Population 16 | #%% 17 | path = 'C:\\Users\\acanlab\\Desktop\\sihan\\nsga\\nsga2_data\\MO-G-FJSP_P1.fjs' 18 | f = open(path, 'r') 19 | line_cnt=0 20 | index_of_map=0 21 | total_operation=0 22 | 23 | color = ['red','green','blue','orange','yellow','purple','gray','pink','brown','black'] 24 | for line in f: 25 | line_split = line.split() 26 | if len(line_split)==0: 27 | continue 28 | if line_cnt==0: 29 | N_jobs = int(line_split[0]) 30 | N_machines = int(line_split[1]) 31 | job_machine_operation_map = [[]for _ in range(N_jobs)] 32 | # operation_arr = [] 33 | # job_cnt=[]*N_jobs 34 | machine_distance = [[0]*N_machines]*N_machines 35 | obj_matrix=[] 36 | elif line_cnt==1: #load job cnt 37 | job_cnt = [int(d) for d in line_split] 38 | elif line_cnt>=2 and line_cnt<2+N_machines: # load objective (total n_machine lines) 39 | # tmp = []*5 40 | obj_matrix.append([int(d) for d in line_split]) 41 | elif line_cnt>=2+N_machines and line_cnt<2+N_machines+N_machines: #load machine distance 42 | #print(cnt) 43 | machine_distance[line_cnt-2-N_machines] = [int(d) for d in line_split] 44 | else: 45 | index_of_line_split = 0 46 | #Get numbers of operation of each job 47 | N_operations = int(line_split[index_of_line_split]) 48 | index_of_line_split +=1 49 | total_operation+=N_operations 50 | for i in range(N_operations): 51 | # operation_arr.append([i,line_cnt-2-N_machines-N_machines]) #add to operation list for computing objective 52 | N_nums = int(line_split[index_of_line_split]) 53 | tmp = [np.inf for _ in range(N_machines)] 54 | for j in range(N_nums): 55 | machine_index = int(line_split[index_of_line_split+1])-1 56 | operate_time = int(line_split[index_of_line_split+2]) 57 | tmp[machine_index] = operate_time 58 | index_of_line_split += 2 59 | job_machine_operation_map[index_of_map].append(tmp) 60 | index_of_line_split += 1 61 | index_of_map += 1 62 | line_cnt+=1 63 | machine_per_job_operation = [] 64 | for job in job_machine_operation_map: 65 | tmp1 = [] 66 | for operation in job: 67 | tmp2 = [] 68 | for machine in range(len(operation)): 69 | if operation[machine]!=np.inf: 70 | tmp2.append(machine) 71 | tmp1.append(tmp2) 72 | machine_per_job_operation.append(tmp1) 73 | f.close() 74 | #%% 75 | """ 76 | def objective_calculation(): 77 | def split_Gene(Gene): 78 | job_batch = [] 79 | tmp_batch_size = [] 80 | cnt = 0 81 | #print(Gene) 82 | while cnt < len(Gene): 83 | if cnt==0: 84 | for i in range(len(job_cnt)): # job_cnt global variable 85 | job_batch.append(Gene[cnt]) 86 | cnt+=1 87 | tmp_batch_size.append(Gene[cnt]) 88 | cnt+=1 89 | batch_size = tmp_batch_size[:-2] 90 | schedule = tmp_batch_size[-2] 91 | machine_schedule = tmp_batch_size[-1] 92 | cnt1=0 93 | batch_size_per_job=[]*len(job_batch) 94 | operation_processing=[]*len(job_batch) 95 | last_machine_operate=[]*len(job_batch) 96 | last_operate_end_time=[]*len(job_batch) 97 | for job_cnt_tmp in job_batch: 98 | batch_set = [] 99 | tmp_set1 = [] 100 | tmp_set2 = [] 101 | tmp_set3 = [] 102 | for i in range(cnt1,job_cnt_tmp+cnt1): 103 | batch_set.append(batch_size[i]) 104 | tmp_set1.append(-1) 105 | tmp_set2.append(-1) 106 | tmp_set3.append(0) 107 | batch_size_per_job.append(batch_set) 108 | operation_processing.append(tmp_set1) 109 | last_machine_operate.append(tmp_set2) 110 | last_operate_end_time.append(tmp_set3) 111 | cnt1+=job_cnt_tmp 112 | 113 | return job_batch, batch_size, schedule, batch_size_per_job, operation_processing, last_machine_operate, last_operate_end_time, machine_schedule 114 | def Calculate(Gene): 115 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = split_Gene(Gene) 116 | machine_nums = N_machines # global variable machine count 117 | # job_nums = N_jobs #global variable job count 118 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 119 | transportation_time = 0 120 | transfer_time = 0 121 | energy = 0 122 | for operation in schedule: 123 | 124 | job_index = operation[0] 125 | batch_index = operation[1]-1 126 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 127 | machine_schedule_index = machine_schedule[batch_index][job_index][0] 128 | time = job_machine_operation_map[job_index][0][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 129 | machine_end_time[machine_schedule_index] += time 130 | last_operate_end_time[job_index][batch_index] = machine_end_time[machine_schedule_index] 131 | last_machine_operate[job_index][batch_index] = machine_schedule_index 132 | # plt.barh(mini_index,time,left=machine_end_time[mini_index],color=c) 133 | # plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 134 | 135 | operation_processing[job_index][batch_index] = 1 136 | transfer_time += obj_matrix[machine_schedule_index][0] 137 | energy += (obj_matrix[machine_schedule_index][3]*time + obj_matrix[machine_schedule_index][4]) 138 | else: 139 | op = operation_processing[job_index][batch_index] 140 | machine_schedule_index = machine_schedule[batch_index][job_index][op] 141 | last_machine = last_machine_operate[job_index][batch_index] 142 | operate_time = last_operate_end_time[job_index][batch_index] 143 | time = job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 144 | machine_time = time + machine_end_time[machine_schedule_index] 145 | op_time = time + operate_time 146 | total_time = max(machine_time, op_time) 147 | last_operate_end_time[job_index][batch_index] = total_time 148 | machine_end_time[machine_schedule_index] = total_time 149 | last_machine_operate[job_index][batch_index] = machine_schedule_index 150 | # plt.barh(mini_index,time,left=minima-time,color=c) 151 | # plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 152 | operation_processing[job_index][batch_index] += 1 153 | transportation_time += machine_distance[last_machine][machine_schedule_index] 154 | if last_machine!=machine_schedule_index: 155 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[machine_schedule_index][0]) 156 | energy += obj_matrix[machine_schedule_index][3]*total_time 157 | 158 | 159 | makespan = max(machine_end_time) 160 | makespan_index = np.argmax(machine_end_time) 161 | return makespan, transfer_time, transportation_time, energy, makespan_index 162 | def Makespan(Gene): 163 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 164 | return makespan 165 | def Transfer_time(Gene): 166 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 167 | return transfer_time 168 | def Transportation_time(Gene): 169 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 170 | return transportation_time 171 | def Energy(Gene): 172 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 173 | return energy 174 | def plot_gantt(feature): 175 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = split_Gene(feature) 176 | machine_nums = N_machines # global variable machine count 177 | # job_nums = N_jobs #global variable job count 178 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 179 | transportation_time = 0 180 | transfer_time = 0 181 | energy = 0 182 | for operation in schedule: 183 | 184 | job_index = operation[0] 185 | batch_index = operation[1]-1 186 | c = color[job_index] 187 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 188 | machine_schedule_index = machine_schedule[batch_index][job_index][0] 189 | time = job_machine_operation_map[job_index][0][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 190 | machine_end_time[machine_schedule_index] += time 191 | last_operate_end_time[job_index][batch_index] = machine_end_time[machine_schedule_index] 192 | last_machine_operate[job_index][batch_index] = machine_schedule_index 193 | plt.barh(machine_schedule_index,time,left=machine_end_time[machine_schedule_index]-time,color=c) 194 | plt.text(time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(0),color='white') 195 | 196 | operation_processing[job_index][batch_index] = 1 197 | transfer_time += obj_matrix[machine_schedule_index][0] 198 | energy += (obj_matrix[machine_schedule_index][3]*time + obj_matrix[machine_schedule_index][4]) 199 | else: 200 | op = operation_processing[job_index][batch_index] 201 | machine_schedule_index = machine_schedule[batch_index][job_index][op] 202 | last_machine = last_machine_operate[job_index][batch_index] 203 | operate_time = last_operate_end_time[job_index][batch_index] 204 | time = job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 205 | machine_time = time + machine_end_time[machine_schedule_index] 206 | op_time = time + operate_time 207 | total_time = max(machine_time, op_time) 208 | last_operate_end_time[job_index][batch_index] = total_time 209 | machine_end_time[machine_schedule_index] = total_time 210 | last_machine_operate[job_index][batch_index] = machine_schedule_index 211 | plt.barh(machine_schedule_index,time,left=total_time-time,color=c) 212 | plt.text(total_time-time+time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 213 | operation_processing[job_index][batch_index] += 1 214 | transportation_time += machine_distance[last_machine][machine_schedule_index] 215 | if last_machine!=machine_schedule_index: 216 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[machine_schedule_index][0]) 217 | energy += obj_matrix[machine_schedule_index][3]*total_time 218 | plt.show() 219 | """ 220 | #%% 221 | if __name__ == '__main__' : 222 | job_cnt = [1]*N_jobs 223 | objective = objective_calculation(job_cnt,N_machines,job_machine_operation_map,obj_matrix, 224 | machine_distance,color) 225 | #variables_range=[[(0,N_machines-1)]*total_operation,total_operation] 226 | operation_num_per_jobs = [] 227 | 228 | for i in range(len(job_machine_operation_map)): 229 | operation_num_per_jobs.append(len(job_machine_operation_map[i])) 230 | variable = [] 231 | job_cnt = [1]*N_jobs 232 | variable.append(job_cnt) 233 | variable.append(operation_num_per_jobs) 234 | variable.append(machine_per_job_operation) 235 | # objective = objective_calculation() 236 | fittness = [objective.Makespan]#, objective.Transfer_time] 237 | problem = myProblem(num_of_variables=1, 238 | objectives=fittness, 239 | variables_range=variable, 240 | operation_num_per_jobs=operation_num_per_jobs, 241 | job_machine_operation_map = job_machine_operation_map, 242 | objective_obj = objective) 243 | 244 | print("Evolutioin......") 245 | mutation_schedule=[[0,1]]#[[0,120],[100,100],[200,80],[300,60],[400,40],[500,20],[600,10]] ,[1000,10],[2000,8],[3000,6],[4000,4],[5000,2],[6000,1] 246 | evo = myEvolution(problem, num_of_generations=500, num_of_individuals=1000, mutation_schedule=mutation_schedule) 247 | start = time.time() 248 | evol, evol_makespan = evo.evolve() 249 | end = time.time() 250 | func=[] 251 | feature=[] 252 | for i in range(len(evol)): 253 | func.append(evol[i].objectives) 254 | feature.append(evol[i].features) 255 | function1 = [i[0] for i in func] 256 | # function2 = [i[1] for i in func] 257 | # # function3 = [i[2] for i in func] 258 | # # function4 = [i[3] for i in func] 259 | # plt.xlabel('maxspan', fontsize=15) 260 | # plt.ylabel('transfer_time', fontsize=15) 261 | # plt.scatter(function1, function2) 262 | # plt.show() 263 | 264 | print("End......") 265 | #%% testing 266 | # a1, a2 ,a3, a4, a5, a6, a7, a8 = split_Gene(individual_1.features[0]) 267 | # test = [f(*individual_1.features) for f in fittness] 268 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = objective.Calculate(feature[0][0]) 269 | objective.plot_gantt(schedule_results) 270 | objective.check_schedule(schedule_results, schedule_results_v2) 271 | print("Total executed time : " + str(end-start)) 272 | print("Min makespan : " + str(min(function1))) 273 | min_makespan = 10000 274 | if min(function1) < min_makespan: 275 | min_makespan = min(function1) 276 | population = Population() 277 | for _ in range(100): 278 | individual = problem.generate_individual() 279 | problem.calculate_objectives(individual) 280 | #print(individual.objectives) 281 | population.append(individual) 282 | util = myUtils(problem) 283 | util.fast_nondominated_sort(population) 284 | individual_1 = problem.generate_individual() 285 | individual_2 = problem.generate_individual() 286 | problem.calculate_objectives(individual_1) 287 | problem.calculate_objectives(individual_2) 288 | -------------------------------------------------------------------------------- /code/MO_G_FJSP_nonVB_NSGA.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 21 13:39:12 2021 4 | 5 | @author: acanlab 6 | """ 7 | import matplotlib.pyplot as plt 8 | import random 9 | import numpy as np 10 | from Class_define_NSGA_nonVB import myProblem 11 | from Class_define_NSGA_nonVB import myEvolution 12 | from Class_define_ESNSGA_nonVB import objective_calculation 13 | import time 14 | #%% 15 | path = 'C:\\Users\\acanlab\\Desktop\\sihan\\nsga\\nsga2_data\\MO-G-FJSP_P1.fjs' 16 | f = open(path, 'r') 17 | line_cnt=0 18 | index_of_map=0 19 | total_operation=0 20 | 21 | color = ['red','green','blue','orange','yellow','purple','gray','pink','brown','black'] 22 | for line in f: 23 | line_split = line.split() 24 | if len(line_split)==0: 25 | continue 26 | if line_cnt==0: 27 | N_jobs = int(line_split[0]) 28 | N_machines = int(line_split[1]) 29 | job_machine_operation_map = [[]for _ in range(N_jobs)] 30 | operation_arr = [] 31 | job_cnt=[]*N_jobs 32 | machine_distance = [[0]*N_machines]*N_machines 33 | obj_matrix=[] 34 | elif line_cnt==1: #load job cnt 35 | job_cnt = [int(d) for d in line_split] 36 | elif line_cnt>=2 and line_cnt<2+N_machines: # load objective (total n_machine lines) 37 | tmp = []*5 38 | tmp = [int(d) for d in line_split] 39 | obj_matrix.append(tmp) 40 | elif line_cnt>=2+N_machines and line_cnt<2+N_machines+N_machines: #load machine distance 41 | #print(cnt) 42 | machine_distance[line_cnt-2-N_machines] = [int(d) for d in line_split] 43 | else: 44 | index_of_line_split = 0 45 | #Get numbers of operation of each job 46 | N_operations = int(line_split[index_of_line_split]) 47 | index_of_line_split +=1 48 | total_operation+=N_operations 49 | for i in range(N_operations): 50 | operation_arr.append([i,line_cnt-2-N_machines-N_machines]) #add to operation list for computing objective 51 | N_nums = int(line_split[index_of_line_split]) 52 | tmp = [10000 for _ in range(N_machines)] 53 | for j in range(N_nums): 54 | machine_index = int(line_split[index_of_line_split+1])-1 55 | operate_time = int(line_split[index_of_line_split+2]) 56 | tmp[machine_index] = operate_time 57 | index_of_line_split += 2 58 | job_machine_operation_map[index_of_map].append(tmp) 59 | index_of_line_split += 1 60 | index_of_map += 1 61 | line_cnt+=1 62 | machine_per_job_operation = [] 63 | for job in job_machine_operation_map: 64 | tmp1 = [] 65 | for operation in job: 66 | tmp2 = [] 67 | for machine in range(len(operation)): 68 | if operation[machine]!=10000: 69 | tmp2.append(machine) 70 | tmp1.append(tmp2) 71 | machine_per_job_operation.append(tmp1) 72 | f.close() 73 | #%% 74 | 75 | # def split_Gene(Gene): 76 | # job_batch = [] 77 | # tmp_batch_size = [] 78 | # cnt = 0 79 | # #print(Gene) 80 | # while cnt < len(Gene): 81 | # if cnt==0: 82 | # for i in range(len(job_cnt)): # job_cnt global variable 83 | # job_batch.append(Gene[cnt]) 84 | # cnt+=1 85 | # tmp_batch_size.append(Gene[cnt]) 86 | # cnt+=1 87 | # batch_size = tmp_batch_size[:-2] 88 | # schedule = tmp_batch_size[-2] 89 | # machine_schedule = tmp_batch_size[-1] 90 | # cnt1=0 91 | # batch_size_per_job=[]*len(job_batch) 92 | # operation_processing=[]*len(job_batch) 93 | # last_machine_operate=[]*len(job_batch) 94 | # last_operate_end_time=[]*len(job_batch) 95 | # for job_cnt_tmp in job_batch: 96 | # batch_set = [] 97 | # tmp_set1 = [] 98 | # tmp_set2 = [] 99 | # tmp_set3 = [] 100 | # for i in range(cnt1,job_cnt_tmp+cnt1): 101 | # batch_set.append(batch_size[i]) 102 | # tmp_set1.append(-1) 103 | # tmp_set2.append(-1) 104 | # tmp_set3.append(0) 105 | # batch_size_per_job.append(batch_set) 106 | # operation_processing.append(tmp_set1) 107 | # last_machine_operate.append(tmp_set2) 108 | # last_operate_end_time.append(tmp_set3) 109 | # cnt1+=job_cnt_tmp 110 | 111 | # return job_batch, batch_size, schedule, batch_size_per_job, operation_processing, last_machine_operate, last_operate_end_time, machine_schedule 112 | # def Calculate(Gene): 113 | # job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = split_Gene(Gene) 114 | # machine_nums = N_machines # global variable machine count 115 | # # job_nums = N_jobs #global variable job count 116 | # machine_end_time = [0]*machine_nums # store last operation end time of each machine 117 | # transportation_time = 0 118 | # transfer_time = 0 119 | # energy = 0 120 | # for operation in schedule: 121 | 122 | # job_index = operation[0] 123 | # batch_index = operation[1]-1 124 | # if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 125 | # machine_schedule_index = machine_schedule[batch_index][job_index][0] 126 | # time = job_machine_operation_map[job_index][0][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 127 | # machine_end_time[machine_schedule_index] += time 128 | # last_operate_end_time[job_index][batch_index] = machine_end_time[machine_schedule_index] 129 | # last_machine_operate[job_index][batch_index] = machine_schedule_index 130 | # # plt.barh(mini_index,time,left=machine_end_time[mini_index],color=c) 131 | # # plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 132 | 133 | # operation_processing[job_index][batch_index] = 1 134 | # transfer_time += obj_matrix[machine_schedule_index][0] 135 | # energy += (obj_matrix[machine_schedule_index][3]*time + obj_matrix[machine_schedule_index][4]) 136 | # else: 137 | # op = operation_processing[job_index][batch_index] 138 | # machine_schedule_index = machine_schedule[batch_index][job_index][op] 139 | # last_machine = last_machine_operate[job_index][batch_index] 140 | # operate_time = last_operate_end_time[job_index][batch_index] 141 | # time = job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 142 | # machine_time = time + machine_end_time[machine_schedule_index] 143 | # op_time = time + operate_time 144 | # total_time = max(machine_time, op_time) 145 | # last_operate_end_time[job_index][batch_index] = total_time 146 | # machine_end_time[machine_schedule_index] = total_time 147 | # last_machine_operate[job_index][batch_index] = machine_schedule_index 148 | # # plt.barh(mini_index,time,left=minima-time,color=c) 149 | # # plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 150 | # operation_processing[job_index][batch_index] += 1 151 | # transportation_time += machine_distance[last_machine][machine_schedule_index] 152 | # if last_machine!=machine_schedule_index: 153 | # transfer_time += (obj_matrix[last_machine][1]+obj_matrix[machine_schedule_index][0]) 154 | # energy += obj_matrix[machine_schedule_index][3]*total_time 155 | 156 | 157 | # makespan = max(machine_end_time) 158 | # return makespan, transfer_time, transportation_time, energy 159 | # def Makespan(Gene): 160 | # makespan, transfer_time, transportation_time, energy = Calculate(Gene) 161 | # return makespan 162 | # def Transfer_time(Gene): 163 | # makespan, transfer_time, transportation_time, energy = Calculate(Gene) 164 | # return transfer_time 165 | # def Transportation_time(Gene): 166 | # makespan, transfer_time, transportation_time, energy = Calculate(Gene) 167 | # return transportation_time 168 | # def Energy(Gene): 169 | # makespan, transfer_time, transportation_time, energy = Calculate(Gene) 170 | # return energy 171 | # def plot_gantt(feature): 172 | # job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = split_Gene(feature) 173 | # machine_nums = N_machines # global variable machine count 174 | # # job_nums = N_jobs #global variable job count 175 | # machine_end_time = [0]*machine_nums # store last operation end time of each machine 176 | # transportation_time = 0 177 | # transfer_time = 0 178 | # energy = 0 179 | # for operation in schedule: 180 | 181 | # job_index = operation[0] 182 | # batch_index = operation[1]-1 183 | # c = color[job_index] 184 | # if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 185 | # machine_schedule_index = machine_schedule[batch_index][job_index][0] 186 | # time = job_machine_operation_map[job_index][0][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 187 | # machine_end_time[machine_schedule_index] += time 188 | # last_operate_end_time[job_index][batch_index] = machine_end_time[machine_schedule_index] 189 | # last_machine_operate[job_index][batch_index] = machine_schedule_index 190 | # plt.barh(machine_schedule_index,time,left=machine_end_time[machine_schedule_index]-time,color=c) 191 | # plt.text(time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(0),color='white') 192 | 193 | # operation_processing[job_index][batch_index] = 1 194 | # transfer_time += obj_matrix[machine_schedule_index][0] 195 | # energy += (obj_matrix[machine_schedule_index][3]*time + obj_matrix[machine_schedule_index][4]) 196 | # else: 197 | # op = operation_processing[job_index][batch_index] 198 | # machine_schedule_index = machine_schedule[batch_index][job_index][op] 199 | # last_machine = last_machine_operate[job_index][batch_index] 200 | # operate_time = last_operate_end_time[job_index][batch_index] 201 | # time = job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 202 | # machine_time = time + machine_end_time[machine_schedule_index] 203 | # op_time = time + operate_time 204 | # total_time = max(machine_time, op_time) 205 | # last_operate_end_time[job_index][batch_index] = total_time 206 | # machine_end_time[machine_schedule_index] = total_time 207 | # last_machine_operate[job_index][batch_index] = machine_schedule_index 208 | # plt.barh(machine_schedule_index,time,left=total_time-time,color=c) 209 | # plt.text(total_time-time+time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 210 | # operation_processing[job_index][batch_index] += 1 211 | # transportation_time += machine_distance[last_machine][machine_schedule_index] 212 | # if last_machine!=machine_schedule_index: 213 | # transfer_time += (obj_matrix[last_machine][1]+obj_matrix[machine_schedule_index][0]) 214 | # energy += obj_matrix[machine_schedule_index][3]*total_time 215 | # plt.show() 216 | #%% 217 | if __name__ == '__main__' : 218 | 219 | job_cnt = [1]*N_jobs 220 | variables_range=[[(0,N_machines-1)]*total_operation,total_operation] 221 | operation_num_per_jobs = [] 222 | for i in range(len(job_machine_operation_map)): 223 | operation_num_per_jobs.append(len(job_machine_operation_map[i])) 224 | objective = objective_calculation(job_cnt,N_machines,job_machine_operation_map,obj_matrix, 225 | machine_distance,color) 226 | variable = [] 227 | job_cnt = [1]*N_jobs 228 | variable.append(job_cnt) 229 | variable.append(operation_num_per_jobs) 230 | variable.append(machine_per_job_operation) 231 | fittness = [objective.Makespan] 232 | problem = myProblem(num_of_variables=1, 233 | objectives=fittness, 234 | variables_range=variable, 235 | operation_num_per_jobs=operation_num_per_jobs, 236 | job_machine_operation_map = job_machine_operation_map) 237 | individual_1 = problem.generate_individual() 238 | individual_2 = problem.generate_individual() 239 | problem.calculate_objectives(individual_1) 240 | problem.calculate_objectives(individual_2) 241 | print("Evolutioin......") 242 | mutation_schedule=[[0,1]]#[[0,120],[100,100],[200,80],[300,60],[400,40],[500,20],[600,10]] 243 | evo = myEvolution(problem, num_of_generations=500, num_of_individuals=1000, mutation_schedule=mutation_schedule) 244 | start = time.time() 245 | evol = evo.evolve() 246 | end = time.time() 247 | func=[] 248 | 249 | feature=[] 250 | for i in range(len(evol)): 251 | func.append(evol[i].objectives) 252 | feature.append(evol[i].features) 253 | function1 = [i[0] for i in func] 254 | # function2 = [i[1] for i in func] 255 | # function3 = [i[2] for i in func] 256 | # # function4 = [i[3] for i in func] 257 | # plt.xlabel('maxspan', fontsize=15) 258 | # plt.ylabel('transfer_time', fontsize=15) 259 | # plt.scatter(function1, function2) 260 | # plt.show() 261 | 262 | print("End......") 263 | #%% testing 264 | # a, b ,c, d, e, f, g, h = split_Gene(individual_1.features[0]) 265 | # test = [f(*individual_1.features) for f in fittness] 266 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = objective.Calculate(feature[2][0]) 267 | objective.plot_gantt(schedule_results) 268 | objective.check_schedule(schedule_results, schedule_results_v2) 269 | print("Total executed time : " + str(end-start)) 270 | print("Min makespan : " + str(min(function1))) 271 | min_makespan = 10000 272 | if min(function1) < min_makespan: 273 | min_makespan = min(function1) 274 | -------------------------------------------------------------------------------- /code/MO_G_JSP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 21 13:39:12 2021 4 | 5 | @author: acanlab 6 | """ 7 | import matplotlib.pyplot as plt 8 | import random 9 | import numpy as np 10 | import time 11 | from Class_define_ESNSGA_jsp import myProblem 12 | from Class_define_ESNSGA_jsp import myEvolution 13 | from Class_define_ESNSGA_jsp import objective_calculation 14 | from Class_define_ESNSGA_jsp import myUtils 15 | from nsga2.population import Population 16 | #%% 17 | path = 'C:\\Users\\acanlab\\Desktop\\sihan\\nsga\\nsga2_data\\JSP_ft20.fjs' 18 | f = open(path, 'r') 19 | line_cnt=0 20 | index_of_map=0 21 | total_operation=0 22 | 23 | color = ['red','green','blue','orange','yellow','purple','gray','pink','brown','black'] 24 | for line in f: 25 | line_split = line.split() 26 | if len(line_split)==0: 27 | continue 28 | if line_cnt==0: 29 | N_jobs = int(line_split[0]) 30 | N_machines = int(line_split[1]) 31 | job_machine_operation_map = [[]for _ in range(N_jobs)] 32 | # operation_arr = [] 33 | # job_cnt=[]*N_jobs 34 | machine_distance = [[0]*N_machines]*N_machines 35 | obj_matrix=[] 36 | else: 37 | cnt_operation=0 38 | line_index = 0 39 | while line_index < len(line_split): 40 | tmp = [np.inf for _ in range(N_machines)] 41 | num = int(line_split[line_index]) 42 | op_time = int(line_split[line_index+1]) 43 | tmp[num]=op_time 44 | job_machine_operation_map[index_of_map].append(tmp) 45 | line_index+=2 46 | index_of_map += 1 47 | line_cnt+=1 48 | machine_per_job_operation = [] 49 | for job in job_machine_operation_map: 50 | tmp1 = [] 51 | for operation in job: 52 | tmp2 = [] 53 | for machine in range(len(operation)): 54 | if operation[machine]!=np.inf: 55 | tmp2.append(machine) 56 | tmp1.append(tmp2) 57 | machine_per_job_operation.append(tmp1) 58 | f.close() 59 | #%% 60 | """ 61 | def objective_calculation(): 62 | def split_Gene(Gene): 63 | job_batch = [] 64 | tmp_batch_size = [] 65 | cnt = 0 66 | #print(Gene) 67 | while cnt < len(Gene): 68 | if cnt==0: 69 | for i in range(len(job_cnt)): # job_cnt global variable 70 | job_batch.append(Gene[cnt]) 71 | cnt+=1 72 | tmp_batch_size.append(Gene[cnt]) 73 | cnt+=1 74 | batch_size = tmp_batch_size[:-2] 75 | schedule = tmp_batch_size[-2] 76 | machine_schedule = tmp_batch_size[-1] 77 | cnt1=0 78 | batch_size_per_job=[]*len(job_batch) 79 | operation_processing=[]*len(job_batch) 80 | last_machine_operate=[]*len(job_batch) 81 | last_operate_end_time=[]*len(job_batch) 82 | for job_cnt_tmp in job_batch: 83 | batch_set = [] 84 | tmp_set1 = [] 85 | tmp_set2 = [] 86 | tmp_set3 = [] 87 | for i in range(cnt1,job_cnt_tmp+cnt1): 88 | batch_set.append(batch_size[i]) 89 | tmp_set1.append(-1) 90 | tmp_set2.append(-1) 91 | tmp_set3.append(0) 92 | batch_size_per_job.append(batch_set) 93 | operation_processing.append(tmp_set1) 94 | last_machine_operate.append(tmp_set2) 95 | last_operate_end_time.append(tmp_set3) 96 | cnt1+=job_cnt_tmp 97 | 98 | return job_batch, batch_size, schedule, batch_size_per_job, operation_processing, last_machine_operate, last_operate_end_time, machine_schedule 99 | def Calculate(Gene): 100 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = split_Gene(Gene) 101 | machine_nums = N_machines # global variable machine count 102 | # job_nums = N_jobs #global variable job count 103 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 104 | transportation_time = 0 105 | transfer_time = 0 106 | energy = 0 107 | for operation in schedule: 108 | 109 | job_index = operation[0] 110 | batch_index = operation[1]-1 111 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 112 | machine_schedule_index = machine_schedule[batch_index][job_index][0] 113 | time = job_machine_operation_map[job_index][0][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 114 | machine_end_time[machine_schedule_index] += time 115 | last_operate_end_time[job_index][batch_index] = machine_end_time[machine_schedule_index] 116 | last_machine_operate[job_index][batch_index] = machine_schedule_index 117 | # plt.barh(mini_index,time,left=machine_end_time[mini_index],color=c) 118 | # plt.text(machine_end_time[mini_index]+time/4,mini_index,'J'+str(job_index)+'o'+str(0),color='white') 119 | 120 | operation_processing[job_index][batch_index] = 1 121 | transfer_time += obj_matrix[machine_schedule_index][0] 122 | energy += (obj_matrix[machine_schedule_index][3]*time + obj_matrix[machine_schedule_index][4]) 123 | else: 124 | op = operation_processing[job_index][batch_index] 125 | machine_schedule_index = machine_schedule[batch_index][job_index][op] 126 | last_machine = last_machine_operate[job_index][batch_index] 127 | operate_time = last_operate_end_time[job_index][batch_index] 128 | time = job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 129 | machine_time = time + machine_end_time[machine_schedule_index] 130 | op_time = time + operate_time 131 | total_time = max(machine_time, op_time) 132 | last_operate_end_time[job_index][batch_index] = total_time 133 | machine_end_time[machine_schedule_index] = total_time 134 | last_machine_operate[job_index][batch_index] = machine_schedule_index 135 | # plt.barh(mini_index,time,left=minima-time,color=c) 136 | # plt.text(minima-time+time/4,mini_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 137 | operation_processing[job_index][batch_index] += 1 138 | transportation_time += machine_distance[last_machine][machine_schedule_index] 139 | if last_machine!=machine_schedule_index: 140 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[machine_schedule_index][0]) 141 | energy += obj_matrix[machine_schedule_index][3]*total_time 142 | 143 | 144 | makespan = max(machine_end_time) 145 | makespan_index = np.argmax(machine_end_time) 146 | return makespan, transfer_time, transportation_time, energy, makespan_index 147 | def Makespan(Gene): 148 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 149 | return makespan 150 | def Transfer_time(Gene): 151 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 152 | return transfer_time 153 | def Transportation_time(Gene): 154 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 155 | return transportation_time 156 | def Energy(Gene): 157 | makespan, transfer_time, transportation_time, energy, makespan_index = Calculate(Gene) 158 | return energy 159 | def plot_gantt(feature): 160 | job_batch, batch_size, schedule, batch_size_per_job,operation_processing ,last_machine_operate, last_operate_end_time, machine_schedule = split_Gene(feature) 161 | machine_nums = N_machines # global variable machine count 162 | # job_nums = N_jobs #global variable job count 163 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 164 | transportation_time = 0 165 | transfer_time = 0 166 | energy = 0 167 | for operation in schedule: 168 | 169 | job_index = operation[0] 170 | batch_index = operation[1]-1 171 | c = color[job_index] 172 | if last_machine_operate[job_index][batch_index] == -1: #each job for the first operation 173 | machine_schedule_index = machine_schedule[batch_index][job_index][0] 174 | time = job_machine_operation_map[job_index][0][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 175 | machine_end_time[machine_schedule_index] += time 176 | last_operate_end_time[job_index][batch_index] = machine_end_time[machine_schedule_index] 177 | last_machine_operate[job_index][batch_index] = machine_schedule_index 178 | plt.barh(machine_schedule_index,time,left=machine_end_time[machine_schedule_index]-time,color=c) 179 | plt.text(time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(0),color='white') 180 | 181 | operation_processing[job_index][batch_index] = 1 182 | transfer_time += obj_matrix[machine_schedule_index][0] 183 | energy += (obj_matrix[machine_schedule_index][3]*time + obj_matrix[machine_schedule_index][4]) 184 | else: 185 | op = operation_processing[job_index][batch_index] 186 | machine_schedule_index = machine_schedule[batch_index][job_index][op] 187 | last_machine = last_machine_operate[job_index][batch_index] 188 | operate_time = last_operate_end_time[job_index][batch_index] 189 | time = job_machine_operation_map[job_index][op][machine_schedule_index]*batch_size_per_job[job_index][batch_index] 190 | machine_time = time + machine_end_time[machine_schedule_index] 191 | op_time = time + operate_time 192 | total_time = max(machine_time, op_time) 193 | last_operate_end_time[job_index][batch_index] = total_time 194 | machine_end_time[machine_schedule_index] = total_time 195 | last_machine_operate[job_index][batch_index] = machine_schedule_index 196 | plt.barh(machine_schedule_index,time,left=total_time-time,color=c) 197 | plt.text(total_time-time+time/4,machine_schedule_index,'J'+str(job_index)+'o'+str(operation_processing[job_index][batch_index]),color='white') 198 | operation_processing[job_index][batch_index] += 1 199 | transportation_time += machine_distance[last_machine][machine_schedule_index] 200 | if last_machine!=machine_schedule_index: 201 | transfer_time += (obj_matrix[last_machine][1]+obj_matrix[machine_schedule_index][0]) 202 | energy += obj_matrix[machine_schedule_index][3]*total_time 203 | plt.show() 204 | """ 205 | #%% 206 | if __name__ == '__main__' : 207 | 208 | job_cnt = [1]*N_jobs 209 | objective = objective_calculation(job_cnt,N_machines,job_machine_operation_map,obj_matrix, 210 | machine_distance,color) 211 | #variables_range=[[(0,N_machines-1)]*total_operation,total_operation] 212 | operation_num_per_jobs = [] 213 | 214 | for i in range(len(job_machine_operation_map)): 215 | operation_num_per_jobs.append(len(job_machine_operation_map[i])) 216 | variable = [] 217 | job_cnt = [1]*N_jobs 218 | variable.append(job_cnt) 219 | variable.append(operation_num_per_jobs) 220 | variable.append(machine_per_job_operation) 221 | # objective = objective_calculation() 222 | fittness = [objective.Makespan]#, objective.Transfer_time] 223 | problem = myProblem(num_of_variables=1, 224 | objectives=fittness, 225 | variables_range=variable, 226 | operation_num_per_jobs=operation_num_per_jobs, 227 | job_machine_operation_map = job_machine_operation_map, 228 | objective_obj = objective) 229 | 230 | print("Evolutioin......") 231 | mutation_schedule=[[0,1]]#[[0,120],[100,100],[200,80],[300,60],[400,40],[500,20],[600,10]] ,[1000,10],[2000,8],[3000,6],[4000,4],[5000,2],[6000,1] 232 | evo = myEvolution(problem, num_of_generations=5000, num_of_individuals=100, mutation_schedule=mutation_schedule) 233 | start = time.time() 234 | evol, evol_makespan = evo.evolve() 235 | end = time.time() 236 | print("time : " + str(end-start)) 237 | func=[] 238 | feature=[] 239 | for i in range(len(evol)): 240 | func.append(evol[i].objectives) 241 | feature.append(evol[i].features) 242 | function1 = [i[0] for i in func] 243 | # function2 = [i[1] for i in func] 244 | # # function3 = [i[2] for i in func] 245 | # # function4 = [i[3] for i in func] 246 | # plt.xlabel('maxspan', fontsize=15) 247 | # plt.ylabel('transfer_time', fontsize=15) 248 | # plt.scatter(function1, function2) 249 | # plt.show() 250 | 251 | print("End......") 252 | #%% testing 253 | # a1, a2 ,a3, a4, a5, a6, a7, a8 = split_Gene(individual_1.features[0]) 254 | # test = [f(*individual_1.features) for f in fittness] 255 | makespan, transfer_time, transportation_time, energy, makespan_index, schedule_results, schedule_results_v2 = objective.Calculate(feature[0][0]) 256 | objective.plot_gantt(schedule_results) 257 | objective.check_schedule(schedule_results, schedule_results_v2) 258 | print("Total executed time : " + str(end-start)) 259 | print("Min makespan : " + str(min(function1))) 260 | min_makespan = 10000 261 | if min(function1) < min_makespan: 262 | min_makespan = min(function1) 263 | population = Population() 264 | for _ in range(100): 265 | individual = problem.generate_individual() 266 | problem.calculate_objectives(individual) 267 | #print(individual.objectives) 268 | population.append(individual) 269 | util = myUtils(problem) 270 | util.fast_nondominated_sort(population) 271 | individual_1 = problem.generate_individual() 272 | individual_2 = problem.generate_individual() 273 | problem.calculate_objectives(individual_1) 274 | problem.calculate_objectives(individual_2) 275 | -------------------------------------------------------------------------------- /code/preprocessing.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 21 13:39:12 2021 4 | 5 | @author: acanlab 6 | """ 7 | import matplotlib.pyplot as plt 8 | import random 9 | import numpy as np 10 | from Class_define import myProblem 11 | from Class_define import myEvolution 12 | #%% 13 | path = 'C:\\Users\\acanlab\\Desktop\\sihan\\TextData\\Monaldo\\Fjsp\\Job_Data\\Brandimarte_Data\\Text\\Mk01.fjs' 14 | f = open(path, 'r') 15 | line_cnt=0 16 | index_of_map=0 17 | total_operation=0 18 | color = ['red','green','blue','orange','yellow','purple','gray','pink','brown','black'] 19 | for line in f: 20 | line_split = line.split() 21 | if len(line_split)==0: 22 | continue 23 | if line_cnt==0: 24 | N_jobs = int(line_split[0]) 25 | N_machines = int(line_split[1]) 26 | avg_machine_per_operation = int(line_split[2]) 27 | job_machine_operation_map = [[]for _ in range(N_jobs)] 28 | operation_arr = [] 29 | machine_distance = [[0]*N_machines]*N_machines 30 | elif line_cnt>=1 and line_cnt<1+N_machines: 31 | #print(cnt) 32 | machine_distance[line_cnt-1] = [int(d) for d in line_split] 33 | else: 34 | index_of_line_split = 0 35 | #Get numbers of operation of each job 36 | N_operations = int(line_split[index_of_line_split]) 37 | index_of_line_split +=1 38 | total_operation+=N_operations 39 | for i in range(N_operations): 40 | operation_arr.append([i,line_cnt-7]) #add to operation list for computing objective 41 | N_nums = int(line_split[index_of_line_split]) 42 | tmp = [10000 for _ in range(N_machines)] 43 | for j in range(N_nums): 44 | machine_index = int(line_split[index_of_line_split+1])-1 45 | operate_time = int(line_split[index_of_line_split+2]) 46 | tmp[machine_index] = operate_time 47 | index_of_line_split += 2 48 | job_machine_operation_map[index_of_map].append(tmp) 49 | index_of_line_split += 1 50 | index_of_map += 1 51 | line_cnt+=1 52 | f.close() 53 | #%% 54 | def Calculate(MGen,OGen): 55 | operation_nums = len(MGen) 56 | machine_nums = N_machines #Global variable for number of machines 57 | maxspan = 0 58 | job_nums = N_jobs #Global variable for number of jobs 59 | operation_end_time = [0]*machine_nums # store the end time of last operation in each job 60 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 61 | last_machine_operate = [-1]*job_nums 62 | transfer_time = 0 63 | for i in range(operation_nums): 64 | arg_index = np.argsort(OGen) 65 | operation_index = operation_arr[arg_index[i]][0] 66 | job_index = operation_arr[arg_index[i]][1] 67 | machine_index = MGen[arg_index[i]] 68 | # print(job_index) 69 | # print(operation_index) 70 | # print(machine_index) 71 | span = job_machine_operation_map[job_index][operation_index][machine_index] 72 | if operation_index == 0: 73 | machine_end_time[machine_index] += span 74 | operation_end_time[machine_index] = machine_end_time[machine_index] 75 | last_machine_operate[job_index] = machine_index 76 | else: 77 | last_machine_index = last_machine_operate[job_index] 78 | # print(last_machine_index) 79 | operation_end = operation_end_time[last_machine_index] 80 | machine_end = machine_end_time[machine_index] 81 | transfer_time += machine_distance[last_machine_index][machine_index] 82 | if operation_end > machine_end: 83 | machine_end_time[machine_index] = operation_end + span 84 | operation_end_time[machine_index] = machine_end_time[machine_index] 85 | last_machine_operate[job_index] = machine_index 86 | else: 87 | machine_end_time[machine_index] += span 88 | operation_end_time[machine_index] = machine_end_time[machine_index] 89 | last_machine_operate[job_index] = machine_index 90 | maxspan = max(machine_end_time) 91 | return maxspan, transfer_time 92 | def maxspan(MGen,OGen): 93 | maxspan, transfer_time = Calculate(MGen, OGen) 94 | return maxspan 95 | def transfer_time(MGen,OGen): 96 | maxspan, transfer_time = Calculate(MGen, OGen) 97 | return transfer_time 98 | def plot_gantt(feature): 99 | MGen=feature[0] 100 | OGen=feature[1] 101 | job_nums = N_jobs 102 | operation_nums = len(MGen) 103 | machine_nums = N_machines #Global variable for number of machines 104 | operation_end_time = [0]*machine_nums # store the end time of last operation in each job 105 | machine_end_time = [0]*machine_nums # store last operation end time of each machine 106 | last_machine_operate = [-1]*job_nums 107 | transfer_time = 0 108 | for i in range(len(MGen)): 109 | arg_index = np.argsort(OGen) 110 | operation_index = operation_arr[arg_index[i]][0] 111 | job_index = operation_arr[arg_index[i]][1] 112 | machine_index = MGen[arg_index[i]] 113 | span = job_machine_operation_map[job_index][operation_index][machine_index] 114 | 115 | c = color[job_index] 116 | if operation_index == 0: 117 | plt.barh(machine_index,span,left=machine_end_time[machine_index],color=c) 118 | plt.text(machine_end_time[machine_index]+span/4,machine_index,'J'+str(job_index)+'o'+str(operation_index),color='white') 119 | machine_end_time[machine_index] += span 120 | operation_end_time[machine_index] = machine_end_time[machine_index] 121 | last_machine_operate[job_index] = machine_index 122 | else: 123 | last_machine_index = last_machine_operate[job_index] 124 | # print(last_machine_index) 125 | operation_end = operation_end_time[last_machine_index] 126 | machine_end = machine_end_time[machine_index] 127 | transfer_time += machine_distance[last_machine_index][machine_index] 128 | if operation_end > machine_end: 129 | plt.barh(machine_index,span,left=operation_end,color=c) 130 | plt.text(operation_end+span/4,machine_index,'J'+str(job_index)+'o'+str(operation_index),color='white') 131 | machine_end_time[machine_index] = operation_end + span 132 | operation_end_time[machine_index] = machine_end_time[machine_index] 133 | last_machine_operate[job_index] = machine_index 134 | else: 135 | plt.barh(machine_index,span,left=machine_end_time[machine_index],color=c) 136 | plt.text(machine_end_time[machine_index]+span/4,machine_index,'J'+str(job_index)+'o'+str(operation_index),color='white') 137 | machine_end_time[machine_index] += span 138 | operation_end_time[machine_index] = machine_end_time[machine_index] 139 | last_machine_operate[job_index] = machine_index 140 | plt.show() 141 | #%% 142 | if __name__ == '__main__' : 143 | variables_range=[[(0,N_machines-1)]*total_operation,total_operation] 144 | operation_num_per_jobs = [] 145 | for i in range(len(job_machine_operation_map)): 146 | operation_num_per_jobs.append(len(job_machine_operation_map[i])) 147 | problem = myProblem(num_of_variables=1, 148 | objectives=[maxspan, transfer_time], 149 | variables_range=variables_range, 150 | operation_num_per_jobs=operation_num_per_jobs, 151 | job_machine_operation_map = job_machine_operation_map) 152 | i = problem.generate_individual() 153 | j = problem.generate_individual() 154 | problem.calculate_objectives(i) 155 | problem.calculate_objectives(j) 156 | 157 | print("Evolutioin......") 158 | evo = myEvolution(problem, num_of_generations=1000, num_of_individuals=1000) 159 | evol = evo.evolve() 160 | func=[] 161 | feature=[] 162 | for i in range(len(evol)): 163 | func.append(evol[i].objectives) 164 | feature.append(evol[i].features) 165 | function1 = [i[0] for i in func] 166 | function2 = [i[1] for i in func] 167 | plt.xlabel('transfer time', fontsize=15) 168 | plt.ylabel('maxspan', fontsize=15) 169 | plt.scatter(function1, function2) 170 | plt.show() 171 | 172 | print("End......") 173 | #%% testing 174 | """ 175 | job=operation_num_per_jobs 176 | operation_index=0 177 | job_index=0 178 | for times in range(variables_range[1]): #for all operation 179 | if job[job_index]==operation_index: 180 | operation_index=0 181 | job_index+=1 182 | machine_index = i.features[0][times] 183 | tmp = job_machine_operation_map[job_index][operation_index][machine_index] 184 | print('tmp ' + str(tmp)) 185 | if tmp ==10000: 186 | print("test1") 187 | N_machine = variables_range[0][0][1]+1 188 | for m in range(N_machine): #find the machine can operate this operation 189 | print("m "+str(m) +" job_index "+str(job_index)+" operation_index "+str(operation_index) +" test1 "+str(job_machine_operation_map[job_index][operation_index][m])) 190 | if job_machine_operation_map[job_index][operation_index][m] != 10000: 191 | i.features[0][times] = m 192 | print('m ' + str(m)) 193 | print('index '+ str(machine_index)) 194 | break 195 | operation_index +=1 196 | problem.calculate_objectives(i) 197 | 198 | time = [] 199 | cnt=0 200 | for job_index in range(len(job_machine_operation_map)): 201 | tmp = operation_num_per_jobs[job_index] 202 | for i in range(tmp): 203 | machine_index = feature[9][0][cnt] 204 | cnt+=1 205 | time.append(job_machine_operation_map[job_index][i][machine_index]) 206 | """ 207 | plot_gantt(feature[3]) 208 | arg_index = np.argsort(feature[3][1]) 209 | for i in arg_index: 210 | print(feature[3][1][i]) 211 | -------------------------------------------------------------------------------- /data/JSP_ft06.fjs: -------------------------------------------------------------------------------- 1 | 6 6 2 | 2 1 0 3 1 6 3 7 5 3 4 6 3 | 1 8 2 5 4 10 5 10 0 10 3 4 4 | 2 5 3 4 5 8 0 9 1 1 4 7 5 | 1 5 0 5 2 5 3 3 4 8 5 9 6 | 2 9 1 3 4 5 5 4 0 3 3 1 7 | 1 3 3 3 5 9 0 10 4 4 2 1 8 | -------------------------------------------------------------------------------- /data/JSP_ft10.fjs: -------------------------------------------------------------------------------- 1 | 10 10 2 | 0 29 1 78 2 9 3 36 4 49 5 11 6 62 7 56 8 44 9 21 3 | 0 43 2 90 4 75 9 11 3 69 1 28 6 46 5 46 7 72 8 30 4 | 1 91 0 85 3 39 2 74 8 90 5 10 7 12 6 89 9 45 4 33 5 | 1 81 2 95 0 71 4 99 6 9 8 52 7 85 3 98 9 22 5 43 6 | 2 14 0 6 1 22 5 61 3 26 4 69 8 21 7 49 9 72 6 53 7 | 2 84 1 2 5 52 3 95 8 48 9 72 0 47 6 65 4 6 7 25 8 | 1 46 0 37 3 61 2 13 6 32 5 21 9 32 8 89 7 30 4 55 9 | 2 31 0 86 1 46 5 74 4 32 6 88 8 19 9 48 7 36 3 79 10 | 0 76 1 69 3 76 5 51 2 85 9 11 6 40 7 89 4 26 8 74 11 | 1 85 0 13 2 61 6 7 8 64 9 76 5 47 3 52 4 90 7 45 12 | -------------------------------------------------------------------------------- /data/JSP_ft20.fjs: -------------------------------------------------------------------------------- 1 | 20 5 2 | 0 29 1 9 2 49 3 62 4 44 3 | 0 43 1 75 3 69 2 46 4 72 4 | 1 91 0 39 2 90 4 12 3 45 5 | 1 81 0 71 4 9 2 85 3 22 6 | 2 14 1 22 0 26 3 21 4 72 7 | 2 84 1 52 4 48 0 47 3 6 8 | 1 46 0 61 2 32 3 32 4 30 9 | 2 31 1 46 0 32 3 19 4 36 10 | 0 76 3 76 2 85 1 40 4 26 11 | 1 85 2 61 0 64 3 47 4 90 12 | 1 78 3 36 0 11 4 56 2 21 13 | 2 90 0 11 1 28 3 46 4 30 14 | 0 85 2 74 1 10 3 89 4 33 15 | 2 95 0 99 1 52 3 98 4 43 16 | 0 6 1 61 4 69 2 49 3 53 17 | 1 2 0 95 3 72 4 65 2 25 18 | 0 37 2 13 1 21 3 89 4 55 19 | 0 86 1 74 4 88 2 48 3 79 20 | 1 69 2 51 0 11 3 89 4 74 21 | 0 13 1 7 2 76 3 52 4 45 22 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P1.fjs: -------------------------------------------------------------------------------- 1 | 10 6 2 2 | 10 20 15 2 5 10 5 5 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 0 2 3 2 3 1 10 | 2 0 5 5 4 1 11 | 3 5 0 1 2 6 12 | 2 5 4 0 4 6 13 | 3 4 2 4 0 8 14 | 1 1 6 6 8 0 15 | 6 2 1 5 3 4 3 5 3 3 5 2 1 2 3 4 6 2 3 6 5 2 6 1 1 1 3 1 3 6 6 3 6 4 3 16 | 5 1 2 6 1 3 1 1 1 2 2 2 6 4 6 3 6 5 2 6 1 1 17 | 5 1 2 6 2 3 4 6 2 3 6 5 2 6 1 1 3 3 4 2 6 6 6 2 1 1 5 5 18 | 5 3 6 5 2 6 1 1 1 2 6 1 3 1 3 5 3 3 5 2 1 2 3 4 6 2 19 | 6 3 5 3 3 5 2 1 3 6 5 2 6 1 1 1 2 6 2 1 5 3 4 2 2 6 4 6 3 3 4 2 6 6 6 20 | 6 2 3 4 6 2 1 1 2 3 3 4 2 6 6 6 1 2 6 3 6 5 2 6 1 1 2 1 3 4 2 21 | 5 1 6 1 2 1 3 4 2 3 3 4 2 6 6 6 3 2 6 5 1 1 6 1 3 1 22 | 5 2 3 4 6 2 3 3 4 2 6 6 6 3 6 5 2 6 1 1 1 2 6 2 2 6 4 6 23 | 6 1 6 1 2 1 1 5 5 3 6 6 3 6 4 3 1 1 2 3 3 4 2 6 6 6 2 2 6 4 6 24 | 6 2 3 4 6 2 3 3 4 2 6 6 6 3 5 3 3 5 2 1 1 6 1 2 2 6 4 6 2 1 3 4 2 25 | 26 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P10.fjs: -------------------------------------------------------------------------------- 1 | 20 15 3 2 | 10 20 15 2 5 10 5 5 4 1 10 10 25 5 3 1 2 2 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 1 1 10 1000 10 | 20 2 2 20 2000 11 | 20 30 3 10 3000 12 | 20 2 4 20 2000 13 | 2 30 5 10 1000 14 | 15 5 6 20 3000 15 | 20 1 1 10 1000 16 | 20 2 2 20 2000 17 | 20 30 3 10 3000 18 | 0 2 3 2 3 1 2 3 2 3 1 2 3 2 1 19 | 2 0 5 5 4 1 5 5 4 1 5 5 4 1 3 20 | 3 5 0 1 2 6 1 2 6 1 2 6 1 2 6 21 | 2 5 4 0 4 6 1 2 6 2 3 1 4 5 1 22 | 3 4 2 4 0 8 6 8 5 2 1 2 1 3 1 23 | 1 1 6 6 8 0 1 2 3 6 4 2 7 1 3 24 | 2 5 1 1 6 1 0 7 5 3 1 8 2 4 1 25 | 3 5 2 2 8 2 7 0 1 4 5 3 2 1 7 26 | 2 4 6 6 5 3 5 1 0 1 7 3 4 2 1 27 | 3 1 1 2 2 6 3 4 1 0 2 4 8 3 1 28 | 1 5 2 3 1 4 1 5 7 2 0 4 3 8 3 29 | 2 5 6 1 2 2 8 3 3 4 4 0 1 2 3 30 | 3 4 1 4 1 7 2 2 4 8 3 1 0 2 1 31 | 2 1 2 5 3 1 4 1 2 3 8 2 2 0 1 32 | 1 3 6 1 1 3 1 7 1 1 3 3 1 1 0 33 | 12 2 6 5 2 5 2 7 11 6 11 1 2 5 4 8 10 3 18 4 10 9 7 2 7 9 1 7 4 1 8 7 14 9 12 4 7 3 4 13 8 8 2 6 5 3 8 1 19 9 13 10 19 2 16 5 2 16 10 9 3 12 4 11 5 15 2 9 10 10 5 3 7 5 2 8 4 7 4 1 6 6 13 5 11 10 7 34 | 13 2 7 11 6 11 4 2 16 10 9 5 9 8 16 2 6 5 2 5 2 2 11 1 9 2 3 12 7 15 4 4 11 10 14 5 10 7 15 4 3 8 1 12 5 5 13 11 5 3 8 1 19 9 13 10 19 2 16 3 4 13 8 8 2 6 4 8 10 3 18 4 10 9 7 4 1 16 5 11 10 17 3 6 2 9 10 10 5 2 5 11 2 11 35 | 11 4 3 8 1 12 5 5 13 11 2 2 11 1 9 2 7 9 1 7 2 6 5 2 5 4 1 6 6 13 5 11 10 7 2 9 10 10 5 5 3 8 1 19 9 13 10 19 2 16 4 8 10 3 18 4 10 9 7 4 2 16 10 9 5 9 8 16 2 3 12 7 15 2 2 5 9 19 36 | 11 4 4 11 10 14 5 10 7 15 5 3 8 1 19 9 13 10 19 2 16 1 5 15 1 2 5 2 9 10 10 5 2 7 11 6 11 4 1 16 5 11 10 17 3 6 2 10 13 6 11 2 2 5 9 19 3 4 13 8 8 2 6 4 8 10 3 18 4 10 9 7 37 | 14 2 7 11 6 11 2 9 10 10 5 4 5 11 7 8 10 11 2 16 2 10 13 6 11 4 1 16 5 11 10 17 3 6 2 7 9 1 7 4 3 8 1 12 5 5 13 11 1 2 5 4 2 16 10 9 5 9 8 16 3 1 15 2 19 9 9 4 1 6 6 13 5 11 10 7 2 2 11 1 9 4 4 11 10 14 5 10 7 15 5 3 8 1 19 9 13 10 19 2 16 38 | 11 3 1 15 2 19 9 9 2 7 9 1 7 4 8 10 3 18 4 10 9 7 2 2 5 9 19 4 5 11 7 8 10 11 2 16 4 1 6 6 13 5 11 10 7 2 7 11 6 11 1 2 5 3 7 5 2 8 4 7 4 3 8 1 12 5 5 13 11 1 5 15 39 | 14 1 2 5 2 7 11 6 11 2 2 11 1 9 2 9 10 10 5 4 8 10 3 18 4 10 9 7 3 1 15 2 19 9 9 3 7 5 2 8 4 7 4 2 16 10 9 5 9 8 16 4 1 6 6 13 5 11 10 7 1 5 15 4 7 13 10 19 6 18 4 8 4 3 8 1 12 5 5 13 11 4 1 16 5 11 10 17 3 6 2 7 9 1 7 40 | 13 4 8 10 3 18 4 10 9 7 2 10 13 6 11 4 5 11 7 8 10 11 2 16 3 4 13 8 8 2 6 5 2 16 10 9 3 12 4 11 5 15 3 1 15 2 19 9 9 4 3 8 1 12 5 5 13 11 3 7 5 2 8 4 7 4 7 13 10 19 6 18 4 8 4 1 6 6 13 5 11 10 7 2 6 5 2 5 4 1 16 5 11 10 17 3 6 4 2 16 10 9 5 9 8 16 41 | 11 2 7 11 6 11 3 7 5 2 8 4 7 4 8 10 3 18 4 10 9 7 2 9 10 10 5 4 2 16 10 9 5 9 8 16 3 4 13 8 8 2 6 4 7 13 10 19 6 18 4 8 5 2 16 10 9 3 12 4 11 5 15 4 1 8 7 14 9 12 4 7 2 6 5 2 5 2 2 11 1 9 42 | 12 2 9 10 10 5 1 5 15 2 2 5 9 19 3 1 15 2 19 9 9 5 2 16 10 9 3 12 4 11 5 15 4 1 6 6 13 5 11 10 7 4 2 16 10 9 5 9 8 16 4 1 16 5 11 10 17 3 6 2 6 5 2 5 2 3 12 7 15 4 4 11 10 14 5 10 7 15 4 8 10 3 18 4 10 9 7 43 | 10 5 2 16 10 9 3 12 4 11 5 15 4 5 11 7 8 10 11 2 16 4 7 13 10 19 6 18 4 8 2 9 10 10 5 1 5 15 2 2 11 1 9 3 4 13 8 8 2 6 2 2 5 9 19 4 8 10 3 18 4 10 9 7 4 1 16 5 11 10 17 3 6 44 | 11 2 10 13 6 11 1 5 15 2 9 10 10 5 4 1 8 7 14 9 12 4 7 4 3 8 1 12 5 5 13 11 3 4 13 8 8 2 6 3 7 5 2 8 4 7 1 2 5 4 1 6 6 13 5 11 10 7 4 2 16 10 9 5 9 8 16 2 7 9 1 7 45 | 11 3 7 5 2 8 4 7 2 2 5 9 19 4 1 8 7 14 9 12 4 7 4 5 11 7 8 10 11 2 16 3 1 15 2 19 9 9 4 1 16 5 11 10 17 3 6 2 6 5 2 5 2 7 11 6 11 5 3 8 1 19 9 13 10 19 2 16 4 8 10 3 18 4 10 9 7 3 4 13 8 8 2 6 46 | 10 2 5 11 2 11 4 8 10 3 18 4 10 9 7 2 7 9 1 7 2 6 5 2 5 4 3 8 1 12 5 5 13 11 1 5 15 2 9 10 10 5 4 1 16 5 11 10 17 3 6 3 4 13 8 8 2 6 2 3 12 7 15 47 | 12 4 8 10 3 18 4 10 9 7 1 5 15 3 1 15 2 19 9 9 4 7 13 10 19 6 18 4 8 4 2 16 10 9 5 9 8 16 4 1 8 7 14 9 12 4 7 3 7 5 2 8 4 7 2 10 13 6 11 2 9 10 10 5 2 3 12 7 15 2 6 5 2 5 4 3 8 1 12 5 5 13 11 48 | 14 2 7 11 6 11 1 5 15 2 2 5 9 19 4 1 8 7 14 9 12 4 7 1 2 5 4 3 8 1 12 5 5 13 11 3 4 13 8 8 2 6 3 1 15 2 19 9 9 4 4 11 10 14 5 10 7 15 2 6 5 2 5 2 9 10 10 5 2 5 11 2 11 5 3 8 1 19 9 13 10 19 2 16 2 10 13 6 11 49 | 13 4 7 13 10 19 6 18 4 8 5 2 16 10 9 3 12 4 11 5 15 3 4 13 8 8 2 6 2 7 11 6 11 2 10 13 6 11 4 2 16 10 9 5 9 8 16 4 8 10 3 18 4 10 9 7 4 3 8 1 12 5 5 13 11 2 6 5 2 5 2 7 9 1 7 4 1 16 5 11 10 17 3 6 2 2 5 9 19 5 3 8 1 19 9 13 10 19 2 16 50 | 11 4 7 13 10 19 6 18 4 8 4 1 6 6 13 5 11 10 7 4 2 16 10 9 5 9 8 16 2 10 13 6 11 2 2 5 9 19 2 5 11 2 11 5 2 16 10 9 3 12 4 11 5 15 2 6 5 2 5 3 1 15 2 19 9 9 1 2 5 4 4 11 10 14 5 10 7 15 51 | 13 2 2 5 9 19 2 6 5 2 5 3 4 13 8 8 2 6 2 7 9 1 7 2 3 12 7 15 1 5 15 4 1 16 5 11 10 17 3 6 3 1 15 2 19 9 9 2 10 13 6 11 2 2 11 1 9 3 7 5 2 8 4 7 4 3 8 1 12 5 5 13 11 4 5 11 7 8 10 11 2 16 52 | 13 4 1 16 5 11 10 17 3 6 3 1 15 2 19 9 9 4 3 8 1 12 5 5 13 11 2 2 5 9 19 4 2 16 10 9 5 9 8 16 1 5 15 4 5 11 7 8 10 11 2 16 4 8 10 3 18 4 10 9 7 2 7 11 6 11 4 1 8 7 14 9 12 4 7 4 7 13 10 19 6 18 4 8 2 3 12 7 15 2 7 9 1 7 53 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P11.fjs: -------------------------------------------------------------------------------- 1 | 10 10 5 2 | 10 20 15 2 5 10 5 5 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 1 1 10 1000 10 | 20 2 2 20 2000 11 | 20 30 3 10 3000 12 | 20 2 4 20 2000 13 | 0 152 170 193 100 112 173 165 142 133 14 | 152 0 131 138 152 169 120 170 162 143 15 | 170 131 0 160 151 140 132 171 122 140 16 | 193 138 160 0 140 140 165 170 140 198 17 | 100 152 151 140 0 103 142 140 148 150 18 | 112 169 140 140 103 0 142 140 148 150 19 | 173 120 132 165 102 142 0 150 162 160 20 | 165 170 171 170 170 140 150 0 141 120 21 | 42 162 122 140 180 148 162 141 0 153 22 | 133 143 140 198 192 150 160 120 153 0 23 | 3 4 1 18 2 20 3 30 7 45 2 9 20 10 14 4 1 17 2 20 3 30 7 28 24 | 3 4 1 12 2 10 3 20 7 15 3 1 15 2 20 8 30 2 9 20 10 25 25 | 2 4 1 30 2 33 3 40 7 40 2 9 20 10 15 26 | 4 4 1 11 2 10 3 10 7 25 2 9 15 10 16 4 1 15 2 17 3 29 7 30 4 1 21 2 15 3 20 7 20 27 | 3 4 1 20 2 17 3 16 7 25 2 9 20 10 20 4 1 25 2 28 3 37 7 40 28 | 3 3 4 15 5 25 6 30 3 4 25 5 20 6 30 4 1 20 2 10 3 10 7 35 29 | 3 3 4 10 5 20 6 30 3 4 15 5 15 6 20 4 1 15 2 15 3 30 7 30 30 | 2 3 4 20 5 25 6 30 4 1 15 2 20 3 30 7 40 31 | 4 3 4 10 5 18 6 23 3 4 15 5 20 6 20 4 1 5 2 5 3 7 7 11 4 1 10 2 12 3 17 7 15 32 | 5 3 4 10 5 10 6 20 3 4 15 5 10 6 25 4 1 10 2 10 3 25 7 30 4 1 20 2 15 3 30 7 40 2 9 22 10 20 -------------------------------------------------------------------------------- /data/MO-G-FJSP_P2.fjs: -------------------------------------------------------------------------------- 1 | 10 6 3.5 2 | 10 20 15 2 5 10 5 5 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 0 2 3 2 3 1 10 | 2 0 5 5 4 1 11 | 3 5 0 1 2 6 12 | 2 5 4 0 4 6 13 | 3 4 2 4 0 8 14 | 1 1 6 6 8 0 15 | 6 6 3 3 4 5 1 3 6 6 2 2 5 3 2 6 5 3 4 6 1 1 5 6 3 3 4 3 2 6 6 5 1 2 6 2 6 3 5 6 3 3 2 2 1 5 4 16 | 6 5 6 1 5 6 1 3 2 4 4 2 2 6 3 5 6 1 5 2 2 2 4 3 3 3 3 2 2 1 5 4 6 3 3 4 5 1 3 6 6 2 2 5 3 17 | 6 6 1 1 5 6 3 3 4 3 2 6 6 5 6 5 3 4 6 2 4 6 6 3 6 1 2 3 3 2 2 1 5 4 5 3 5 1 4 2 3 6 3 5 2 6 4 1 1 5 2 4 5 5 3 3 6 3 5 6 3 1 4 4 6 3 6 5 3 18 | 6 5 3 5 1 4 2 3 6 3 5 2 5 6 1 5 6 1 3 2 4 4 2 1 2 6 6 1 1 5 6 3 3 4 3 2 6 6 5 5 1 4 4 5 2 3 6 3 5 4 6 4 1 1 5 2 4 5 5 3 3 6 3 19 | 6 6 5 3 4 6 2 4 6 6 3 6 1 2 5 1 4 4 5 2 3 6 3 5 4 1 4 3 5 6 3 1 4 4 6 3 6 5 3 5 6 1 5 6 1 3 2 4 4 2 2 2 4 3 3 20 | 6 5 6 3 1 4 4 6 3 6 5 3 2 6 5 3 4 5 3 5 1 4 2 3 6 3 5 2 6 5 3 4 6 2 4 6 6 3 6 1 2 1 2 6 5 6 1 5 6 1 3 2 4 4 2 21 | 5 6 4 1 1 5 2 4 5 5 3 3 6 3 1 5 2 6 5 3 4 6 2 4 6 6 3 6 1 2 6 3 3 4 5 1 3 6 6 2 2 5 3 5 6 3 1 4 4 6 3 6 5 3 22 | 6 2 2 4 3 3 5 3 5 1 4 2 3 6 3 5 2 6 5 3 4 6 2 4 6 6 3 6 1 2 5 6 3 1 4 4 6 3 6 5 3 5 1 4 4 5 2 3 6 3 5 4 5 6 1 5 6 1 3 2 4 4 2 23 | 5 1 2 6 2 6 5 3 4 5 6 1 5 6 1 3 2 4 4 2 5 1 4 4 5 2 3 6 3 5 4 2 2 4 3 3 24 | 6 1 4 3 6 5 3 4 6 2 4 6 6 3 6 1 2 5 6 3 1 4 4 6 3 6 5 3 6 4 1 1 5 2 4 5 5 3 3 6 3 2 6 3 5 6 5 6 1 5 6 1 3 2 4 4 2 25 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P3.fjs: -------------------------------------------------------------------------------- 1 | 15 8 3 2 | 10 20 15 2 5 10 5 5 4 1 3 3 3 3 3 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 5 2 20 1000 10 | 1 1 1 20 5000 11 | 0 2 3 2 3 1 3 3 12 | 2 0 5 5 4 1 2 3 13 | 3 5 0 1 2 6 3 2 14 | 2 5 4 0 4 6 2 1 15 | 3 4 2 4 0 8 1 2 16 | 1 1 6 6 8 0 1 1 17 | 3 2 3 2 1 1 0 4 18 | 3 3 2 1 2 1 4 0 19 | 10 4 7 15 8 11 4 5 5 19 2 3 18 4 5 4 8 18 7 3 6 11 3 16 4 5 7 2 1 7 2 3 19 2 5 6 6 3 3 4 5 5 2 8 18 1 5 2 1 1 17 5 5 10 2 10 1 12 8 5 3 14 3 7 15 6 2 8 19 20 | 10 4 8 18 7 3 6 11 3 16 1 1 17 2 2 1 4 13 5 5 10 2 10 1 12 8 5 3 14 5 4 11 1 9 2 18 6 18 3 13 2 6 15 7 13 4 7 15 8 11 4 5 5 19 4 5 7 2 1 7 2 3 19 4 4 11 1 7 6 13 8 3 3 7 15 6 2 8 19 21 | 10 2 3 3 5 5 4 5 7 2 1 7 2 3 19 2 3 18 4 5 2 5 6 6 3 4 4 11 1 7 6 13 8 3 3 7 15 6 2 8 19 5 4 11 1 9 2 18 6 18 3 13 3 4 5 5 2 8 18 1 1 17 2 2 1 4 13 22 | 10 2 3 18 4 5 2 3 3 5 5 5 4 11 1 9 2 18 6 18 3 13 4 4 11 1 7 6 13 8 3 2 6 15 7 13 4 5 7 2 1 7 2 3 19 1 5 2 4 8 18 7 3 6 11 3 16 1 1 17 2 5 6 6 3 23 | 10 2 6 15 7 13 3 7 15 6 2 8 19 1 5 2 4 7 15 8 11 4 5 5 19 5 4 11 1 9 2 18 6 18 3 13 4 5 7 2 1 7 2 3 19 3 4 5 5 2 8 18 2 5 6 6 3 2 3 3 5 5 5 5 10 2 10 1 12 8 5 3 14 24 | 10 2 2 1 4 13 2 6 15 7 13 2 3 18 4 5 4 8 18 7 3 6 11 3 16 5 4 11 1 9 2 18 6 18 3 13 5 5 10 2 10 1 12 8 5 3 14 4 4 11 1 7 6 13 8 3 4 7 15 8 11 4 5 5 19 2 5 6 6 3 2 3 3 5 5 25 | 10 5 5 10 2 10 1 12 8 5 3 14 4 4 11 1 7 6 13 8 3 2 2 1 4 13 1 1 17 2 6 15 7 13 4 5 7 2 1 7 2 3 19 1 5 2 5 4 11 1 9 2 18 6 18 3 13 2 3 18 4 5 3 7 15 6 2 8 19 26 | 10 3 7 15 6 2 8 19 1 1 17 4 7 15 8 11 4 5 5 19 2 6 15 7 13 5 5 10 2 10 1 12 8 5 3 14 4 4 11 1 7 6 13 8 3 5 4 11 1 9 2 18 6 18 3 13 2 2 1 4 13 2 3 18 4 5 2 3 3 5 5 27 | 10 1 1 17 5 5 10 2 10 1 12 8 5 3 14 4 8 18 7 3 6 11 3 16 3 7 15 6 2 8 19 2 6 15 7 13 4 4 11 1 7 6 13 8 3 1 5 2 2 2 1 4 13 5 4 11 1 9 2 18 6 18 3 13 4 7 15 8 11 4 5 5 19 28 | 10 1 1 17 2 6 15 7 13 3 4 5 5 2 8 18 5 4 11 1 9 2 18 6 18 3 13 4 4 11 1 7 6 13 8 3 2 3 18 4 5 2 5 6 6 3 3 7 15 6 2 8 19 4 8 18 7 3 6 11 3 16 5 5 10 2 10 1 12 8 5 3 14 29 | 10 2 2 1 4 13 3 7 15 6 2 8 19 4 8 18 7 3 6 11 3 16 2 3 18 4 5 2 5 6 6 3 1 1 17 2 3 3 5 5 3 4 5 5 2 8 18 5 5 10 2 10 1 12 8 5 3 14 5 4 11 1 9 2 18 6 18 3 13 30 | 10 4 4 11 1 7 6 13 8 3 3 4 5 5 2 8 18 4 8 18 7 3 6 11 3 16 1 1 17 5 4 11 1 9 2 18 6 18 3 13 3 7 15 6 2 8 19 1 5 2 2 3 3 5 5 4 7 15 8 11 4 5 5 19 2 2 1 4 13 31 | 10 5 5 10 2 10 1 12 8 5 3 14 1 5 2 2 3 18 4 5 4 5 7 2 1 7 2 3 19 2 6 15 7 13 4 8 18 7 3 6 11 3 16 4 7 15 8 11 4 5 5 19 5 4 11 1 9 2 18 6 18 3 13 2 5 6 6 3 4 4 11 1 7 6 13 8 3 32 | 10 4 8 18 7 3 6 11 3 16 3 4 5 5 2 8 18 2 2 1 4 13 4 5 7 2 1 7 2 3 19 2 5 6 6 3 2 3 18 4 5 2 6 15 7 13 1 5 2 5 4 11 1 9 2 18 6 18 3 13 1 1 17 33 | 10 5 5 10 2 10 1 12 8 5 3 14 2 5 6 6 3 2 6 15 7 13 4 7 15 8 11 4 5 5 19 4 8 18 7 3 6 11 3 16 1 1 17 5 4 11 1 9 2 18 6 18 3 13 3 4 5 5 2 8 18 2 3 18 4 5 4 5 7 2 1 7 2 3 19 34 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P4.fjs: -------------------------------------------------------------------------------- 1 | 15 8 2 2 | 10 20 15 2 5 10 5 5 4 1 3 3 3 3 3 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 5 2 20 1000 10 | 1 1 1 20 5000 11 | 0 2 3 2 3 1 3 3 12 | 2 0 5 5 4 1 2 3 13 | 3 5 0 1 2 6 3 2 14 | 2 5 4 0 4 6 2 1 15 | 3 4 2 4 0 8 1 2 16 | 1 1 6 6 8 0 1 1 17 | 3 2 3 2 1 1 0 4 18 | 3 3 2 1 2 1 4 0 19 | 8 1 1 6 2 1 6 7 9 2 6 7 3 1 2 4 2 7 5 3 1 8 3 9 8 9 3 2 3 4 8 3 2 2 5 5 6 7 2 6 1 4 7 20 | 7 1 6 1 2 6 1 4 7 1 1 6 2 6 7 3 1 3 2 3 4 8 3 2 1 6 2 1 7 2 21 | 6 1 6 1 3 2 3 4 8 3 2 3 3 2 7 1 4 4 2 4 2 7 5 2 1 7 3 7 2 4 4 3 1 22 | 5 1 7 2 1 1 6 2 1 6 7 9 2 6 7 3 1 2 4 5 5 7 23 | 7 1 7 2 2 1 6 7 9 2 4 4 3 1 3 1 8 3 9 8 9 2 1 7 3 7 3 2 3 4 8 3 2 2 4 5 5 7 24 | 9 1 6 2 2 4 4 3 1 3 3 2 7 1 4 4 2 6 1 4 7 2 4 5 5 7 3 1 8 3 9 8 9 2 1 7 3 7 1 6 1 2 1 6 7 9 25 | 5 2 5 5 6 7 2 1 7 3 7 2 6 1 4 7 1 6 2 2 6 7 3 1 26 | 6 2 4 5 5 7 2 5 5 6 7 3 2 3 4 8 3 2 1 6 2 1 6 1 2 1 6 7 9 27 | 9 1 1 6 2 1 6 7 9 2 4 4 3 1 3 1 8 3 9 8 9 2 4 2 7 5 2 6 1 4 7 1 7 2 2 1 7 3 7 3 2 3 4 8 3 2 28 | 5 2 5 5 6 7 1 1 6 1 7 2 2 4 5 5 7 2 1 6 7 9 29 | 4 3 1 8 3 9 8 9 1 1 6 3 2 3 4 8 3 2 2 4 2 7 5 30 | 6 2 4 2 7 5 1 6 1 1 1 6 2 1 7 3 7 3 1 8 3 9 8 9 1 7 2 31 | 4 1 6 2 2 6 7 3 1 2 6 1 4 7 2 5 5 6 7 32 | 3 2 5 5 6 7 1 6 1 2 4 2 7 5 33 | 6 2 4 5 5 7 1 7 2 3 1 8 3 9 8 9 3 2 3 4 8 3 2 3 3 2 7 1 4 4 1 1 6 34 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P5.fjs: -------------------------------------------------------------------------------- 1 | 15 4 1.5 2 | 10 20 15 2 5 10 5 5 4 1 3 3 3 3 3 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 0 2 3 2 8 | 2 0 5 5 9 | 3 5 0 1 10 | 2 5 4 0 11 | 6 2 3 5 2 7 2 1 8 4 8 2 1 6 2 5 1 3 7 2 4 5 2 6 2 4 5 1 5 12 | 5 1 3 7 2 1 6 2 5 1 4 6 2 4 5 2 6 2 1 8 2 6 13 | 8 2 4 7 3 9 2 3 5 2 7 2 4 5 1 5 2 1 8 4 8 2 1 6 2 5 1 4 6 2 1 8 2 6 2 4 9 3 6 14 | 7 2 4 5 1 5 2 4 7 3 9 2 1 8 4 8 1 4 8 2 1 8 2 6 2 4 5 2 6 1 4 6 15 | 6 2 3 7 1 5 2 4 6 2 7 2 4 7 3 9 1 3 8 2 3 5 2 7 2 1 8 2 6 16 | 9 1 4 6 2 4 5 2 6 1 3 8 2 3 7 1 5 2 4 6 2 7 1 4 8 2 1 8 2 6 2 1 8 4 8 2 4 5 1 5 17 | 5 1 3 8 2 4 7 3 9 2 1 6 2 5 2 4 6 2 7 1 3 7 18 | 8 2 3 7 1 5 1 3 8 2 4 7 3 9 2 4 5 1 5 1 3 7 1 4 8 2 4 9 3 6 2 1 6 2 5 19 | 9 2 3 5 2 7 1 4 8 2 4 5 2 6 2 1 6 2 5 1 4 6 2 1 8 4 9 2 1 8 4 8 2 1 8 2 6 1 3 7 20 | 9 2 1 8 2 6 2 1 8 4 8 2 1 8 4 9 2 4 9 3 6 2 1 6 2 5 1 3 8 1 3 7 1 4 6 2 4 5 2 6 21 | 7 2 1 8 2 6 2 1 8 4 8 2 1 6 2 5 1 3 7 1 4 6 1 3 8 2 4 9 3 6 22 | 6 1 4 8 1 3 7 2 4 7 3 9 2 1 6 2 5 1 3 8 2 1 8 4 8 23 | 7 1 4 8 2 4 9 3 6 2 1 8 4 8 2 4 6 2 7 2 4 6 2 7 2 1 8 2 6 2 3 7 1 5 24 | 7 2 1 6 2 5 2 3 7 1 5 2 1 8 4 8 2 1 8 2 6 2 4 5 1 5 2 4 6 2 7 1 4 6 25 | 7 1 3 8 2 1 8 4 9 2 4 9 3 6 1 3 7 2 4 5 2 6 2 1 8 2 6 2 1 6 2 5 26 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P6.fjs: -------------------------------------------------------------------------------- 1 | 10 15 3 2 | 10 20 15 2 5 10 5 5 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 1 1 10 1000 10 | 20 2 2 20 2000 11 | 20 30 3 10 3000 12 | 20 2 4 20 2000 13 | 2 30 5 10 1000 14 | 15 5 6 20 3000 15 | 20 1 1 10 1000 16 | 20 2 2 20 2000 17 | 20 30 3 10 3000 18 | 0 2 3 2 3 1 2 3 2 3 1 2 3 2 1 19 | 2 0 5 5 4 1 5 5 4 1 5 5 4 1 3 20 | 3 5 0 1 2 6 1 2 6 1 2 6 1 2 6 21 | 2 5 4 0 4 6 1 2 6 2 3 1 4 5 1 22 | 3 4 2 4 0 8 6 8 5 2 1 2 1 3 1 23 | 1 1 6 6 8 0 1 2 3 6 4 2 7 1 3 24 | 2 5 1 1 6 1 0 7 5 3 1 8 2 4 1 25 | 3 5 2 2 8 2 7 0 1 4 5 3 2 1 7 26 | 2 4 6 6 5 3 5 1 0 1 7 3 4 2 1 27 | 3 1 1 2 2 6 3 4 1 0 2 4 8 3 1 28 | 1 5 2 3 1 4 1 5 7 2 0 4 3 8 3 29 | 2 5 6 1 2 2 8 3 3 4 4 0 1 2 3 30 | 3 4 1 4 1 7 2 2 4 8 3 1 0 2 1 31 | 2 1 2 5 3 1 4 1 2 3 8 2 2 0 1 32 | 1 3 6 1 1 3 1 7 1 1 3 3 1 1 0 33 | 15 4 2 8 6 3 7 2 9 5 2 9 7 1 2 5 7 4 1 4 9 1 2 7 10 4 2 1 1 8 2 3 7 5 3 8 5 8 5 1 3 8 8 2 5 3 8 10 9 3 5 6 1 1 6 2 5 2 5 1 9 9 1 5 7 4 6 2 10 6 1 2 2 7 9 5 6 2 4 8 7 2 5 2 1 5 8 4 2 1 8 3 7 3 10 2 8 9 4 5 3 7 5 3 7 9 3 3 9 4 5 8 1 1 34 | 15 5 1 3 8 8 2 5 3 8 10 9 5 7 4 1 4 9 1 2 7 10 4 3 5 6 1 1 6 2 5 2 1 5 8 4 2 1 8 3 7 2 4 8 7 2 2 10 6 1 2 3 10 2 8 9 4 5 2 7 9 5 6 3 7 5 3 7 9 3 3 7 5 3 8 5 8 3 9 4 5 8 1 1 2 9 7 1 2 2 1 1 8 2 4 2 8 6 3 7 2 9 5 5 2 5 1 9 9 1 5 7 4 6 35 | 15 2 1 1 8 2 2 7 9 5 6 2 10 6 1 2 2 4 8 7 2 5 2 1 5 8 4 2 1 8 3 7 3 9 4 5 8 1 1 2 9 7 1 2 3 7 5 3 7 9 3 5 7 4 1 4 9 1 2 7 10 4 4 2 8 6 3 7 2 9 5 5 1 3 8 8 2 5 3 8 10 9 3 10 2 8 9 4 5 5 2 5 1 9 9 1 5 7 4 6 3 5 6 1 1 6 2 3 7 5 3 8 5 8 36 | 15 3 5 6 1 1 6 2 5 2 5 1 9 9 1 5 7 4 6 5 1 3 8 8 2 5 3 8 10 9 5 2 1 5 8 4 2 1 8 3 7 2 4 8 7 2 2 10 6 1 2 3 7 5 3 8 5 8 2 9 7 1 2 3 7 5 3 7 9 3 3 9 4 5 8 1 1 4 2 8 6 3 7 2 9 5 2 1 1 8 2 5 7 4 1 4 9 1 2 7 10 4 2 7 9 5 6 3 10 2 8 9 4 5 37 | 15 3 10 2 8 9 4 5 2 1 1 8 2 3 9 4 5 8 1 1 2 9 7 1 2 3 7 5 3 8 5 8 5 2 1 5 8 4 2 1 8 3 7 3 5 6 1 1 6 2 3 7 5 3 7 9 3 4 2 8 6 3 7 2 9 5 2 10 6 1 2 5 7 4 1 4 9 1 2 7 10 4 2 7 9 5 6 5 2 5 1 9 9 1 5 7 4 6 5 1 3 8 8 2 5 3 8 10 9 2 4 8 7 2 38 | 15 3 7 5 3 8 5 8 5 1 3 8 8 2 5 3 8 10 9 2 7 9 5 6 3 5 6 1 1 6 2 5 2 5 1 9 9 1 5 7 4 6 2 4 8 7 2 2 9 7 1 2 5 2 1 5 8 4 2 1 8 3 7 5 7 4 1 4 9 1 2 7 10 4 4 2 8 6 3 7 2 9 5 2 1 1 8 2 3 7 5 3 7 9 3 2 10 6 1 2 3 9 4 5 8 1 1 3 10 2 8 9 4 5 39 | 15 3 5 6 1 1 6 2 3 10 2 8 9 4 5 3 7 5 3 8 5 8 5 1 3 8 8 2 5 3 8 10 9 2 1 1 8 2 2 9 7 1 2 5 2 1 5 8 4 2 1 8 3 7 3 7 5 3 7 9 3 5 7 4 1 4 9 1 2 7 10 4 3 9 4 5 8 1 1 2 10 6 1 2 4 2 8 6 3 7 2 9 5 2 7 9 5 6 2 4 8 7 2 5 2 5 1 9 9 1 5 7 4 6 40 | 15 5 7 4 1 4 9 1 2 7 10 4 3 7 5 3 7 9 3 3 7 5 3 8 5 8 2 1 1 8 2 3 5 6 1 1 6 2 5 2 5 1 9 9 1 5 7 4 6 3 10 2 8 9 4 5 3 9 4 5 8 1 1 2 9 7 1 2 4 2 8 6 3 7 2 9 5 5 1 3 8 8 2 5 3 8 10 9 2 4 8 7 2 2 10 6 1 2 5 2 1 5 8 4 2 1 8 3 7 2 7 9 5 6 41 | 15 4 2 8 6 3 7 2 9 5 3 9 4 5 8 1 1 3 7 5 3 8 5 8 5 7 4 1 4 9 1 2 7 10 4 5 2 1 5 8 4 2 1 8 3 7 2 4 8 7 2 2 9 7 1 2 3 10 2 8 9 4 5 5 1 3 8 8 2 5 3 8 10 9 2 10 6 1 2 5 2 5 1 9 9 1 5 7 4 6 3 7 5 3 7 9 3 2 7 9 5 6 2 1 1 8 2 3 5 6 1 1 6 2 42 | 15 2 1 1 8 2 4 2 8 6 3 7 2 9 5 3 10 2 8 9 4 5 3 7 5 3 8 5 8 3 7 5 3 7 9 3 2 10 6 1 2 2 7 9 5 6 3 9 4 5 8 1 1 5 7 4 1 4 9 1 2 7 10 4 5 2 5 1 9 9 1 5 7 4 6 5 1 3 8 8 2 5 3 8 10 9 3 5 6 1 1 6 2 5 2 1 5 8 4 2 1 8 3 7 2 4 8 7 2 2 9 7 1 2 43 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P7.fjs: -------------------------------------------------------------------------------- 1 | 20 5 3 2 | 10 20 15 2 5 10 5 5 4 1 10 10 25 5 3 1 2 2 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 0 2 3 2 3 9 | 2 0 5 5 4 10 | 3 5 0 1 2 11 | 2 5 4 0 4 12 | 3 4 2 4 0 13 | 5 2 2 4 1 15 2 3 18 1 15 1 2 4 1 4 18 5 3 8 5 2 4 5 1 7 2 7 14 | 5 2 1 3 5 13 5 3 8 5 2 4 5 1 7 2 7 2 2 4 1 15 3 1 8 5 1 2 5 3 1 3 5 13 3 2 15 | 5 5 2 18 5 1 4 19 1 9 3 3 1 4 18 2 4 11 3 9 1 2 4 3 5 12 3 14 4 19 16 | 5 2 2 4 1 15 4 4 10 3 10 2 17 5 8 4 5 18 3 13 2 2 1 5 5 4 10 5 15 1 2 3 9 2 16 2 3 15 1 6 17 | 5 3 1 3 5 13 3 2 2 3 18 1 15 5 2 18 5 1 4 19 1 9 3 3 3 5 12 3 14 4 19 1 4 5 18 | 5 5 3 8 5 2 4 5 1 7 2 7 2 3 18 1 15 2 1 15 5 7 2 2 7 1 17 2 2 4 1 15 19 | 5 1 4 5 2 1 15 5 7 2 2 4 1 15 3 1 3 5 13 3 2 4 4 6 2 17 3 15 5 7 20 | 5 4 4 6 2 17 3 15 5 7 3 3 18 1 2 4 15 4 2 14 4 14 3 19 5 15 1 2 4 2 2 7 1 17 21 | 5 5 2 18 5 1 4 19 1 9 3 3 4 4 6 2 17 3 15 5 7 3 1 8 5 1 2 5 4 2 14 4 14 3 19 5 15 2 1 17 5 15 22 | 5 2 1 15 5 7 4 4 10 3 10 2 17 5 8 2 3 15 1 6 1 4 5 5 3 16 5 17 4 10 2 10 1 7 23 | 5 1 4 18 3 1 8 5 1 2 5 5 3 8 5 2 4 5 1 7 2 7 2 1 15 5 7 2 1 17 5 15 24 | 5 3 5 12 3 14 4 19 4 4 10 3 10 2 17 5 8 2 3 15 1 6 5 3 8 5 2 4 5 1 7 2 7 5 3 16 5 17 4 10 2 10 1 7 25 | 5 2 1 17 5 15 1 4 18 4 2 17 5 19 4 5 3 12 3 3 18 1 2 4 15 3 1 8 5 1 2 5 26 | 5 2 5 1 3 5 3 3 18 1 2 4 15 4 4 10 3 10 2 17 5 8 2 3 18 1 15 5 3 8 5 2 4 5 1 7 2 7 27 | 5 5 3 8 5 2 4 5 1 7 2 7 2 5 1 3 5 3 5 12 3 14 4 19 5 3 16 5 17 4 10 2 10 1 7 2 1 17 5 15 28 | 5 5 4 10 5 15 1 2 3 9 2 16 2 4 11 3 9 1 2 4 2 1 15 5 7 1 4 5 29 | 5 5 3 8 5 2 4 5 1 7 2 7 4 2 14 4 14 3 19 5 15 3 3 18 1 2 4 15 2 3 15 1 6 5 2 18 5 1 4 19 1 9 3 3 30 | 5 1 2 4 3 1 8 5 1 2 5 2 5 1 3 5 2 3 18 1 15 2 1 15 5 7 31 | 5 3 1 3 5 13 3 2 4 4 6 2 17 3 15 5 7 4 5 18 3 13 2 2 1 5 1 4 18 2 1 3 5 13 32 | 5 1 4 5 2 2 4 1 15 1 4 18 2 1 15 5 7 5 4 10 5 15 1 2 3 9 2 16 33 | 34 | -------------------------------------------------------------------------------- /data/MO-G-FJSP_P8.fjs: -------------------------------------------------------------------------------- 1 | 20 10 1.5 2 | 10 20 15 2 5 10 5 5 4 1 10 10 25 5 3 1 2 2 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 1 1 10 1000 10 | 20 2 2 20 2000 11 | 20 30 3 10 3000 12 | 20 2 4 20 2000 13 | 0 2 3 2 3 1 2 3 2 3 14 | 2 0 5 5 4 1 5 5 4 1 15 | 3 5 0 1 2 6 1 2 6 1 16 | 2 5 4 0 4 6 1 2 6 2 17 | 3 4 2 4 0 8 6 8 5 2 18 | 1 1 6 6 8 0 1 2 3 6 19 | 2 5 1 1 6 1 0 7 5 3 20 | 3 5 2 2 8 2 7 0 1 4 21 | 2 4 6 6 5 3 5 1 0 1 22 | 3 1 1 2 2 6 3 4 1 0 23 | 10 2 7 18 4 5 2 5 7 7 7 1 3 19 1 7 14 2 4 5 10 12 1 1 10 1 10 18 2 7 10 8 19 2 3 11 8 9 2 3 5 8 12 24 | 12 1 2 5 2 7 18 4 5 2 3 5 8 12 1 1 10 1 10 19 2 3 15 4 19 1 7 14 1 5 9 2 5 14 9 5 1 1 19 2 7 10 8 19 1 1 16 25 | 14 2 5 14 9 5 1 1 19 1 1 10 1 3 19 2 7 18 4 5 2 4 5 10 12 2 3 5 8 12 1 10 10 1 5 9 1 1 7 2 7 10 8 19 1 1 10 1 10 19 1 10 18 26 | 10 1 10 10 2 5 7 7 7 1 7 14 1 1 10 1 10 18 2 3 15 7 13 2 10 14 5 7 2 3 11 8 9 1 9 11 1 5 9 27 | 12 1 5 9 2 5 14 9 5 2 7 18 4 5 2 3 11 8 9 1 1 10 1 9 11 1 1 7 1 7 14 2 4 5 10 12 2 3 15 4 19 1 8 18 1 10 19 28 | 10 2 3 15 7 13 1 3 19 1 5 9 1 10 19 2 3 5 8 12 2 7 18 4 5 2 8 14 10 9 2 4 5 10 12 1 10 18 1 1 7 29 | 12 1 1 10 1 10 18 1 1 7 1 5 9 2 8 14 10 9 2 7 10 8 19 2 3 15 4 19 2 10 14 5 7 1 8 18 1 10 19 1 1 19 1 1 10 30 | 11 1 1 10 1 7 14 1 1 10 2 3 15 4 19 2 5 14 9 5 2 7 18 4 5 1 3 19 1 1 19 2 4 5 10 12 1 5 9 1 10 19 31 | 14 2 7 10 8 19 2 8 14 10 9 1 1 19 1 10 19 2 10 14 5 7 1 2 5 2 4 5 10 12 2 5 7 7 7 1 1 16 1 1 7 1 9 11 1 3 19 1 1 10 1 10 18 32 | 11 1 10 19 2 10 14 5 7 1 8 18 2 3 11 8 9 1 1 7 1 1 10 2 5 14 9 5 2 3 15 4 19 1 10 18 1 3 19 1 1 19 33 | 11 2 5 14 9 5 1 1 10 1 8 18 2 3 15 4 19 2 7 10 8 19 2 3 5 8 12 2 3 11 8 9 2 8 14 10 9 1 10 10 1 9 11 1 3 19 34 | 10 1 10 19 2 3 11 8 9 2 5 7 7 7 1 1 16 1 7 14 2 7 18 4 5 2 4 5 10 12 1 1 10 1 8 18 2 5 14 9 5 35 | 11 2 10 14 5 7 1 10 19 2 7 10 8 19 2 3 15 4 19 1 1 19 1 8 18 2 8 14 10 9 2 3 11 8 9 1 10 18 2 5 14 9 5 1 2 5 36 | 11 1 1 10 2 5 7 7 7 1 1 10 1 9 11 1 7 14 2 3 15 7 13 2 8 14 10 9 1 1 16 2 3 5 8 12 2 5 14 9 5 1 2 5 37 | 11 2 5 14 9 5 2 5 7 7 7 1 7 14 1 10 10 2 7 10 8 19 2 3 15 4 19 2 7 18 4 5 1 1 7 2 3 11 8 9 1 1 19 1 8 18 38 | 11 1 2 5 2 7 10 8 19 1 10 10 1 9 11 1 8 18 2 10 14 5 7 2 5 14 9 5 1 1 10 1 1 19 2 3 15 7 13 2 8 14 10 9 39 | 13 1 10 10 2 5 14 9 5 1 5 9 1 10 19 1 1 10 2 3 5 8 12 1 2 5 2 10 14 5 7 1 1 10 2 8 14 10 9 2 3 15 7 13 1 1 16 1 7 14 40 | 11 2 3 15 7 13 1 2 5 1 10 19 1 3 19 1 8 18 1 1 7 1 5 9 1 7 14 2 7 18 4 5 1 1 10 2 5 14 9 5 41 | 10 2 7 10 8 19 1 2 5 2 3 11 8 9 1 9 11 2 4 5 10 12 1 10 18 2 7 18 4 5 2 8 14 10 9 2 3 5 8 12 1 10 19 42 | 10 1 10 18 1 10 10 1 7 14 1 9 11 2 3 15 7 13 1 2 5 2 8 14 10 9 2 3 5 8 12 1 5 9 1 1 16 -------------------------------------------------------------------------------- /data/MO-G-FJSP_P9.fjs: -------------------------------------------------------------------------------- 1 | 20 10 3 2 | 10 20 15 2 5 10 5 5 4 1 10 10 25 5 3 1 2 2 4 1 3 | 20 1 1 10 1000 4 | 20 2 2 20 2000 5 | 20 30 3 10 3000 6 | 20 2 4 20 2000 7 | 2 30 5 10 1000 8 | 15 5 6 20 3000 9 | 20 1 1 10 1000 10 | 20 2 2 20 2000 11 | 20 30 3 10 3000 12 | 20 2 4 20 2000 13 | 0 2 3 2 3 1 2 3 2 3 14 | 2 0 5 5 4 1 5 5 4 1 15 | 3 5 0 1 2 6 1 2 6 1 16 | 2 5 4 0 4 6 1 2 6 2 17 | 3 4 2 4 0 8 6 8 5 2 18 | 1 1 6 6 8 0 1 2 3 6 19 | 2 5 1 1 6 1 0 7 5 3 20 | 3 5 2 2 8 2 7 0 1 4 21 | 2 4 6 6 5 3 5 1 0 1 22 | 3 1 1 2 2 6 3 4 1 0 23 | 12 2 2 10 1 11 1 8 17 1 8 14 1 1 10 2 2 16 10 18 2 9 6 2 12 4 7 9 4 11 3 10 1 16 2 5 19 1 7 1 9 11 1 4 16 1 2 5 5 7 9 9 9 4 6 8 14 6 16 24 | 13 1 8 17 2 5 6 4 11 2 2 10 1 11 2 5 9 8 8 2 2 16 3 11 4 1 8 5 14 10 15 6 12 4 6 10 8 15 7 5 2 8 2 5 19 1 7 4 7 9 4 11 3 10 1 16 1 1 10 4 1 16 3 11 7 17 4 7 1 4 16 4 3 11 5 8 7 11 9 17 25 | 11 4 6 10 8 15 7 5 2 8 2 5 9 8 8 2 2 16 10 18 2 2 10 1 11 5 7 9 9 9 4 6 8 14 6 16 1 4 16 2 5 19 1 7 1 1 10 2 5 6 4 11 2 2 16 3 11 1 3 14 26 | 11 4 1 8 5 14 10 15 6 12 2 5 19 1 7 4 4 11 8 16 9 15 1 6 1 8 14 1 4 16 1 8 17 4 1 16 3 11 7 17 4 7 4 10 6 8 13 5 5 2 8 1 3 14 4 7 9 4 11 3 10 1 16 1 1 10 27 | 14 1 8 17 1 4 16 1 5 9 4 10 6 8 13 5 5 2 8 4 1 16 3 11 7 17 4 7 2 2 16 10 18 4 6 10 8 15 7 5 2 8 1 8 14 2 5 6 4 11 4 2 5 7 13 10 10 5 11 5 7 9 9 9 4 6 8 14 6 16 2 5 9 8 8 4 1 8 5 14 10 15 6 12 2 5 19 1 7 28 | 11 4 2 5 7 13 10 10 5 11 2 2 16 10 18 1 1 10 1 3 14 1 5 9 5 7 9 9 9 4 6 8 14 6 16 1 8 17 1 8 14 1 2 5 4 6 10 8 15 7 5 2 8 4 4 11 8 16 9 15 1 6 29 | 14 1 8 14 1 8 17 2 5 9 8 8 1 4 16 1 1 10 4 2 5 7 13 10 10 5 11 1 2 5 2 5 6 4 11 5 7 9 9 9 4 6 8 14 6 16 4 4 11 8 16 9 15 1 6 5 2 8 1 19 8 13 6 14 10 18 4 6 10 8 15 7 5 2 8 4 1 16 3 11 7 17 4 7 2 2 16 10 18 30 | 13 1 1 10 4 10 6 8 13 5 5 2 8 1 5 9 4 7 9 4 11 3 10 1 16 1 9 11 4 2 5 7 13 10 10 5 11 4 6 10 8 15 7 5 2 8 1 2 5 5 2 8 1 19 8 13 6 14 10 18 5 7 9 9 9 4 6 8 14 6 16 2 2 10 1 11 4 1 16 3 11 7 17 4 7 2 5 6 4 11 31 | 11 1 8 17 1 2 5 1 1 10 1 4 16 2 5 6 4 11 4 7 9 4 11 3 10 1 16 5 2 8 1 19 8 13 6 14 10 18 1 9 11 2 9 6 2 12 2 2 10 1 11 2 5 9 8 8 32 | 12 1 4 16 4 4 11 8 16 9 15 1 6 1 3 14 4 2 5 7 13 10 10 5 11 1 9 11 5 7 9 9 9 4 6 8 14 6 16 2 5 6 4 11 4 1 16 3 11 7 17 4 7 2 2 10 1 11 2 2 16 3 11 4 1 8 5 14 10 15 6 12 1 1 10 33 | 10 1 9 11 1 5 9 5 2 8 1 19 8 13 6 14 10 18 1 4 16 4 4 11 8 16 9 15 1 6 2 5 9 8 8 4 7 9 4 11 3 10 1 16 1 3 14 1 1 10 4 1 16 3 11 7 17 4 7 34 | 11 4 10 6 8 13 5 5 2 8 4 4 11 8 16 9 15 1 6 1 4 16 2 9 6 2 12 4 6 10 8 15 7 5 2 8 4 7 9 4 11 3 10 1 16 1 2 5 1 8 14 5 7 9 9 9 4 6 8 14 6 16 2 5 6 4 11 2 2 16 10 18 35 | 11 1 2 5 1 3 14 2 9 6 2 12 1 5 9 4 2 5 7 13 10 10 5 11 4 1 16 3 11 7 17 4 7 2 2 10 1 11 1 8 17 2 5 19 1 7 1 1 10 4 7 9 4 11 3 10 1 16 36 | 10 4 3 11 5 8 7 11 9 17 1 1 10 2 2 16 10 18 2 2 10 1 11 4 6 10 8 15 7 5 2 8 4 4 11 8 16 9 15 1 6 1 4 16 4 1 16 3 11 7 17 4 7 4 7 9 4 11 3 10 1 16 2 2 16 3 11 37 | 12 1 1 10 4 4 11 8 16 9 15 1 6 4 2 5 7 13 10 10 5 11 5 2 8 1 19 8 13 6 14 10 18 2 5 6 4 11 2 9 6 2 12 1 2 5 4 10 6 8 13 5 5 2 8 1 4 16 2 2 16 3 11 2 2 10 1 11 4 6 10 8 15 7 5 2 8 38 | 14 1 8 17 4 4 11 8 16 9 15 1 6 1 3 14 2 9 6 2 12 1 8 14 4 6 10 8 15 7 5 2 8 4 7 9 4 11 3 10 1 16 4 2 5 7 13 10 10 5 11 4 1 8 5 14 10 15 6 12 2 2 10 1 11 1 4 16 4 3 11 5 8 7 11 9 17 2 5 19 1 7 4 10 6 8 13 5 5 2 8 39 | 13 5 2 8 1 19 8 13 6 14 10 18 1 9 11 4 7 9 4 11 3 10 1 16 1 8 17 4 10 6 8 13 5 5 2 8 2 5 6 4 11 1 1 10 4 6 10 8 15 7 5 2 8 2 2 10 1 11 2 2 16 10 18 4 1 16 3 11 7 17 4 7 1 3 14 2 5 19 1 7 40 | 11 5 2 8 1 19 8 13 6 14 10 18 5 7 9 9 9 4 6 8 14 6 16 2 5 6 4 11 4 10 6 8 13 5 5 2 8 1 3 14 4 3 11 5 8 7 11 9 17 1 9 11 2 2 10 1 11 4 2 5 7 13 10 10 5 11 1 8 14 4 1 8 5 14 10 15 6 12 41 | 13 1 3 14 2 2 10 1 11 4 7 9 4 11 3 10 1 16 2 2 16 10 18 2 2 16 3 11 4 4 11 8 16 9 15 1 6 4 1 16 3 11 7 17 4 7 4 2 5 7 13 10 10 5 11 4 10 6 8 13 5 5 2 8 2 5 9 8 8 1 2 5 4 6 10 8 15 7 5 2 8 1 5 9 42 | 13 4 1 16 3 11 7 17 4 7 4 2 5 7 13 10 10 5 11 4 6 10 8 15 7 5 2 8 1 3 14 2 5 6 4 11 4 4 11 8 16 9 15 1 6 1 5 9 1 1 10 1 8 17 2 9 6 2 12 5 2 8 1 19 8 13 6 14 10 18 2 2 16 3 11 2 2 16 10 18 43 | 44 | -------------------------------------------------------------------------------- /description.txt: -------------------------------------------------------------------------------- 1 | 第一行有兩個數字,分別代表n個job 及 m 台機器 2 | 下一行會有n個數字,分別代表每個job須完成的工作數量。 3 | 接下來會有m行,皆包含5個數字,分別代表 4 | 1. 設置機器所需時間 5 | 2. 下架機器所需時間 6 | 3. 機器閒置能耗 7 | 4. 機器運行能耗 8 | 5. 機器開機能耗 9 | 接著會有m行並且每行包含m格數字,分別代表機器之間的距離/運輸成本 10 | 最後會有n行,n行中第一個數字代表該工作有幾項操作,後續的數字分別代表該操作能有幾台機器可以操作,機器編號,花費時間。 11 | 例如 3 2 1 4 2 3 1 3 1 2 1 4 3 1 12 | 第一個3表示該工作有三個操作,接著2表示一號操作能有兩台機器可以執行,後續的1 4 2 3則表示1號和2號可以執行,且分別要花費4秒及3秒 --------------------------------------------------------------------------------