├── Figures ├── Fitness Variation.png ├── Pareto.png ├── Rank1 Solution.png └── True Solution.png ├── PackingAlgorithm.py ├── README.md ├── Report.pdf ├── Visualization.py ├── boxes.py ├── create_dataset.py ├── input.json ├── main.py └── requirements.txt /Figures/Fitness Variation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nivedha-Ramesh/Container-Loading-Problem/55706278c0cc6b3f87d11339a37229e1347e1463/Figures/Fitness Variation.png -------------------------------------------------------------------------------- /Figures/Pareto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nivedha-Ramesh/Container-Loading-Problem/55706278c0cc6b3f87d11339a37229e1347e1463/Figures/Pareto.png -------------------------------------------------------------------------------- /Figures/Rank1 Solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nivedha-Ramesh/Container-Loading-Problem/55706278c0cc6b3f87d11339a37229e1347e1463/Figures/Rank1 Solution.png -------------------------------------------------------------------------------- /Figures/True Solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nivedha-Ramesh/Container-Loading-Problem/55706278c0cc6b3f87d11339a37229e1347e1463/Figures/True Solution.png -------------------------------------------------------------------------------- /PackingAlgorithm.py: -------------------------------------------------------------------------------- 1 | import random 2 | from copy import deepcopy 3 | from operator import itemgetter 4 | 5 | class PackingAlgorithm: 6 | def __init__(self, box_params, truck_dimension, total_value, population_size=100, k=2, generations=100, pc=0.8, pm1=0.2, pm2=0.02, rotation=6): 7 | self.box_params = box_params 8 | self.truck_dimension = truck_dimension 9 | self.total_value = total_value 10 | self.population_size = population_size 11 | self.generations = generations 12 | self.pc = pc 13 | self.numP = int(self.pc * self.population_size) 14 | self.k = k 15 | self.pm1 = pm1 16 | self.pm2 = pm2 17 | self.rotation = rotation 18 | self.avg_fitness = [] 19 | self.population = self.generate_population() 20 | 21 | 22 | def generate_population(self): 23 | """ 24 | This function uses the dimensions of the boxes to create a diploid chromosome for every individual in the population, 25 | It consists of 'order', which is a permutation as the boxes order and a list of their rotation values 26 | """ 27 | population = {} 28 | keys = list(self.box_params.keys()) 29 | for i in range(self.population_size): 30 | random.shuffle(keys) 31 | population[i] = {"order": deepcopy(keys), "rotate": [random.randint(0, self.rotation - 1) for _ in range(len(self.box_params))]} 32 | return population 33 | 34 | def evaluate(self, pop): 35 | """ 36 | Evaluates each individual's fitness in the population by packing boxes into a truck container. 37 | Utilizes the space utilization, the number of boxes packed, and the total value of the boxes as fitness criteria. 38 | """ 39 | container_vol = self.truck_dimension[0] * self.truck_dimension[1] * self.truck_dimension[2] 40 | fitness = {} 41 | for key, individual in pop.items(): 42 | dblf = [[0, 0, 0] + self.truck_dimension] 43 | occupied_vol, number_boxes, value = 0, 0, 0 44 | result = [] 45 | # Iterate over each box in the individual's solution (order and rotation). 46 | for box_number, r in zip(individual['order'], individual['rotate']): 47 | dblf = sorted(dblf, key=itemgetter(3)) 48 | dblf = sorted(dblf, key=itemgetter(5)) 49 | dblf = sorted(dblf, key=itemgetter(4)) 50 | 51 | for pos in dblf: 52 | current = deepcopy(pos) 53 | space_vol = pos[3] * pos[4] * pos[5] 54 | box_vol = self.box_params[box_number][3] 55 | box_value = self.box_params[box_number][4] 56 | 57 | 58 | if r == 0: 59 | l, w, h = self.box_params[box_number][0:3] 60 | elif r == 1: 61 | w, l, h = self.box_params[box_number][0:3] 62 | elif r == 2: 63 | l, h, w = self.box_params[box_number][0:3] 64 | elif r == 3: 65 | h, l, w = self.box_params[box_number][0:3] 66 | elif r == 4: 67 | h, w, l = self.box_params[box_number][0:3] 68 | else: 69 | w, h, l = self.box_params[box_number][0:3] 70 | 71 | # Check if the box fits in the current space. 72 | if space_vol >= box_vol and pos[3] >= l and pos[4] >= w and pos[5] >= h: 73 | result.append(pos[0:3] + [l, w, h]) 74 | occupied_vol += box_vol 75 | number_boxes += 1 76 | value += box_value 77 | top_space = [pos[0], pos[1], pos[2] + h, l, w, pos[5] - h] 78 | beside_space = [pos[0], pos[1] + w, pos[2], l, pos[4] - w, pos[5]] 79 | front_space = [pos[0] + l, pos[1], pos[2], pos[3] - l, pos[4], pos[5]] 80 | dblf.remove(current) 81 | dblf.append(top_space) 82 | dblf.append(beside_space) 83 | dblf.append(front_space) 84 | break 85 | 86 | ft = [round((occupied_vol / container_vol * 100),2), 87 | round((number_boxes / len(self.box_params) * 100),2), 88 | round((value / self.total_value * 100),2)] 89 | pop[key]['fitness'] = deepcopy(ft) 90 | pop[key]['result'] = result 91 | fitness[key] = ft 92 | 93 | return pop, fitness 94 | 95 | def select_parents(self): 96 | """ 97 | Selects parents for crossover using tournament selection based on rank and crowding distance. 98 | """ 99 | parents = {} 100 | individuals = deepcopy(list(self.population.values())) 101 | for index in range(self.numP): 102 | pool = random.sample(individuals, self.k) 103 | pool.sort(key=lambda ind: (ind['Rank'])) 104 | 105 | # Get the highest ranked individual(s) 106 | top_rank = pool[0]['Rank'] 107 | highest_ranked = [ind for ind in pool if ind['Rank'] == top_rank] 108 | 109 | if len(highest_ranked) == 1:\ 110 | best = highest_ranked[0] 111 | else: 112 | pool.sort(key=lambda ind: (ind['crowding_distance'])) 113 | best = pool[0] 114 | parents[index] = best 115 | individuals.remove(best) 116 | return parents 117 | 118 | def recombine(self, parents): 119 | """ 120 | Performs crossover on pairs of parents to generate offspring. 121 | Each offspring inherits a combination of 'order' and 'rotate' traits from its parents. 122 | """ 123 | offsprings = {} 124 | parent_keys = list(parents.keys()) 125 | random.shuffle(parent_keys) 126 | for x in range(0, len(parents), 2): 127 | k1 = random.choice(parent_keys) 128 | o1 = deepcopy(parents[k1]['order']) 129 | r1 = deepcopy(parents[k1]['rotate']) 130 | parent_keys.remove(k1) 131 | 132 | k2 = random.choice(parent_keys) 133 | o2 = deepcopy(parents[k2]['order']) 134 | r2 = deepcopy(parents[k2]['rotate']) 135 | parent_keys.remove(k2) 136 | 137 | i = random.randint(1, int(len(o1) / 2) + 1) 138 | j = random.randint(i + 1, int(len(o1) - 1)) 139 | 140 | co1, co2 = [-1] * len(o1), [-1] * len(o2) 141 | cr1, cr2 = [-1] * len(r1), [-1] * len(r2) 142 | 143 | co1[i:j + 1], co2[i:j + 1] = o1[i:j + 1], o2[i:j + 1] 144 | cr1[i:j + 1], cr2[i:j + 1] = r1[i:j + 1], r2[i:j + 1] 145 | 146 | pos = (j + 1) % len(o2) 147 | for k in range(len(o2)): 148 | if o2[k] not in co1 and co1[pos] == -1: 149 | co1[pos] = o2[k] 150 | pos = (pos + 1) % len(o2) 151 | 152 | pos = (j + 1) % len(o2) 153 | for k in range(len(o1)): 154 | if o1[k] not in co2 and co2[pos] == -1: 155 | co2[pos] = o1[k] 156 | pos = (pos + 1) % len(o1) 157 | 158 | pos = (j + 1) % len(o2) 159 | for k in range(len(r2)): 160 | if cr1[pos] == -1: 161 | cr1[pos] = r2[k] 162 | pos = (pos + 1) % len(r2) 163 | 164 | pos = (j + 1) % len(o2) 165 | for k in range(len(r1)): 166 | if cr2[pos] == -1: 167 | cr2[pos] = r1[k] 168 | pos = (pos + 1) % len(r1) 169 | 170 | offsprings[x], offsprings[x + 1] = {'order': deepcopy(co1), 'rotate': deepcopy(cr1)}, {'order': deepcopy(co2), 'rotate': deepcopy(cr2)} 171 | 172 | return offsprings 173 | 174 | def mutate(self, offsprings): 175 | """ 176 | Performs mutation on the offspring population to introduce variability. 177 | """ 178 | for child in offsprings.values(): 179 | order = child['order'] 180 | rotate = child['rotate'] 181 | # First level of mutation: Order Inversion Mutation 182 | if random.uniform(0, 1) <= self.pm1: 183 | i = random.randint(1, int(len(order) / 2) + 1) 184 | j = random.randint(i + 1, int(len(order) - 1)) 185 | order[i:j + 1] = order[j:i - 1:-1] 186 | rotate[i:j + 1] = rotate[j:i - 1:-1] 187 | 188 | # Second level of mutation: Rotation Mutation 189 | for i in range(len(rotate)): 190 | if random.uniform(0, 1) <= self.pm2: 191 | rotate[i] = random.randint(0, self.rotation - 1) 192 | 193 | return offsprings 194 | 195 | def merge_populations(self, offsprings): 196 | """ 197 | Merges the current population with the offsprings. 198 | """ 199 | combined_population = deepcopy(self.population) 200 | key = len(combined_population) 201 | for _, value in offsprings.items(): 202 | combined_population[key] = value 203 | key += 1 204 | return combined_population 205 | 206 | def select_survivors(self, offsprings): 207 | """ 208 | Selects survivors for the next generation based on NSGA-II sorting and crowding distance. 209 | """ 210 | 211 | offsprings, _ = self.evaluate(offsprings) 212 | combined_population = self.merge_populations(offsprings) 213 | fronts = self.non_dominated_sort(combined_population) 214 | for front in fronts: 215 | self.calculate_crowding_distance(combined_population, front) 216 | 217 | self.population = self.select_based_on_nsga2(combined_population) 218 | 219 | def non_dominated_sort(self, combined_population): 220 | """ 221 | Performs non-dominated sorting on the combined population to identify fronts. 222 | Returns: 223 | list: A list of fronts, where each front is a list of individual keys in that front. 224 | """ 225 | fronts = [[]] 226 | for p_key in combined_population.keys(): 227 | p = combined_population[p_key] 228 | p['dominated'] = [] 229 | p['dom_count'] = 0 230 | for q_key in combined_population.keys(): 231 | q = combined_population[q_key] 232 | if self.dominates(p['fitness'], q['fitness']): 233 | p['dominated'].append(q_key) 234 | elif self.dominates(q['fitness'], p['fitness']): 235 | p['dom_count'] += 1 236 | if p['dom_count'] == 0: 237 | p['Rank'] = 1 238 | fronts[0].append(p_key) 239 | 240 | i = 0 241 | while fronts[i]: 242 | next_front = [] 243 | for p_key in fronts[i]: 244 | p = combined_population[p_key] 245 | for q_key in p['dominated']: 246 | q = combined_population[q_key] 247 | q['dom_count'] -= 1 248 | if q['dom_count'] == 0: 249 | q['Rank'] = i + 2 250 | next_front.append(q_key) 251 | i += 1 252 | fronts.append(next_front) 253 | return fronts[:-1] 254 | 255 | def calculate_crowding_distance(self, combined_population, front): 256 | """ 257 | Calculates the crowding distance for each individual within a front. 258 | """ 259 | for p_key in front: 260 | combined_population[p_key]['crowding_distance'] = 0 261 | for i in range(len(combined_population[next(iter(front))]['fitness'])): 262 | # Sort the front based on each objective's value 263 | front.sort(key=lambda x: combined_population[x]['fitness'][i]) 264 | combined_population[front[0]]['crowding_distance'] = float('inf') 265 | combined_population[front[-1]]['crowding_distance'] = float('inf') 266 | for j in range(1, len(front) - 1): 267 | distance = combined_population[front[j + 1]]['fitness'][i] - combined_population[front[j - 1]]['fitness'][i] 268 | combined_population[front[j]]['crowding_distance'] += distance 269 | 270 | def select_based_on_nsga2(self, combined_population): 271 | """ 272 | Selects individuals for the next generation based on their rank and crowding distance. 273 | """ 274 | new_population = {} 275 | current_size = 0 276 | i=1 277 | while len(new_population) < self.population_size: 278 | group = [ind for ind in combined_population.values() if ind['Rank'] == i] 279 | if len(group) <= self.population_size - len(new_population): 280 | j = 0 281 | for index in range(len(new_population), len(new_population)+len(group)): 282 | new_population[index] = group[j] 283 | j += 1 284 | else: 285 | group = sorted(group, key=lambda x: x['crowding_distance'], reverse=True) 286 | j = 0 287 | for index in range(len(new_population), self.population_size): 288 | new_population[index] = group[j] 289 | j += 1 290 | i += 1 291 | return new_population 292 | 293 | def dominates(self, individual1, individual2): 294 | """ 295 | Determines if one individual dominates another based on fitness values. 296 | Returns: 297 | bool: True if `individual1` dominates `individual2`, False otherwise. 298 | """ 299 | better_in_all = all(m >= n for m, n in zip(individual1, individual2)) 300 | better_in_at_least_one = any(m > n for m, n in zip(individual1, individual2)) 301 | return better_in_all and better_in_at_least_one 302 | 303 | def calc_average_fitness(self, individuals): 304 | fitness_sum = [0.0, 0.0, 0.0] 305 | count = 0 306 | for key, value in individuals.items(): 307 | if value['Rank'] == 1: 308 | count += 1 309 | fitness_sum[0] += value['fitness'][0] 310 | fitness_sum[1] += value['fitness'][1] 311 | fitness_sum[2] += value['fitness'][2] 312 | averaged = [sum_value / count if count > 0 else 0 for sum_value in fitness_sum] 313 | self.avg_fitness.append(averaged) 314 | 315 | def optimize(self): 316 | 317 | self.population, _ = self.evaluate(self.population) 318 | fronts = self.non_dominated_sort(self.population) 319 | for front in fronts: 320 | self.calculate_crowding_distance(self.population, front) 321 | for _ in range(self.generations): 322 | parents = self.select_parents() 323 | offsprings = self.recombine(parents) 324 | offsprings = self.mutate(offsprings) 325 | self.select_survivors(offsprings) 326 | self.calc_average_fitness(self.population) 327 | 328 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A hybrid multi-objective genetic algorithm for the container loading problem 2 | 3 | This repository showcases a unique approach to solving the container loading problem, a challenge commonly faced in industries related to shipping and storage. Here, we aim to pack a container as efficiently as possible, focusing on fitting the most boxes, maximizing the space used, and ensuring the packed items' total value is as high as possible. 4 | 5 | We use a diploid chromosome structure to better organize and decide on the arrangement and orientation of boxes. This method is enhanced by a tweaked version of an existing packing algorithm, known as DBLF, which helps us place boxes in the most effective way. 6 | 7 | By combining advanced genetic algorithms with a refined packing technique, we tackle the complex issue of packing boxes into a single container, striving for optimal space usage and value maximization. 8 | 9 | *For a detailed description of the methods and background have a look at the project [report](https://github.com/Nivedha-Ramesh/Container-Loading-Problem/blob/master/Report.pdf).* 10 | 11 | **Getting Started** 12 | 13 | To get started with this project, clone this repository to your local machine. 14 | 15 | 16 | Ensure you have Python installed on your system. This project is tested with Python 3.7+. You can check your Python version by running: 17 | ```bash 18 | python --version 19 | ``` 20 | 21 | Install the required Python packages: 22 | ```bash 23 | pip install -r requirements.txt 24 | ``` 25 | 26 | **Creating a New Dataset** 27 | ```bash 28 | cd path/to/your/project 29 | ``` 30 | 31 | ```bash 32 | python create_dataset.py 33 | ``` 34 | 35 | **Running the Algorithm** 36 | 37 | To run the packing algorithm with the provided dataset (input.json), execute the main.py script: 38 | ```bash 39 | python main.py 40 | ``` 41 | 42 | The script will proceed to execute the packing algorithm, saving the visualizations as below. 43 | 44 | 3D Visualization of the True Solution 45 | ![True Solution](https://github.com/Nivedha-Ramesh/Container-Loading-Problem/blob/master/Figures/True%20Solution.png) 46 | 47 | 48 | 3D Projection of one of the Rank1 Solutions 49 | ![Rank 1 solution](https://github.com/Nivedha-Ramesh/Container-Loading-Problem/blob/master/Figures/Rank1%20Solution.png) 50 | 51 | 52 | Variation of Average Fitness Values over Generations 53 | ![Fitness Variation](https://github.com/Nivedha-Ramesh/Container-Loading-Problem/blob/master/Figures/Fitness%20Variation.png) 54 | 55 | 56 | Visualization of the Pareto Front 57 | ![Pareto Front](https://github.com/Nivedha-Ramesh/Container-Loading-Problem/blob/master/Figures/Pareto.png) 58 | 59 | 60 | **Contributing** 61 | 62 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. 63 | Any contributions you make are **greatly appreciated**. 64 | 65 | **License** 66 | 67 | Distributed under the MIT License. 68 | 69 | **Contact** 70 | 71 | Nivedha Ramesh - [nivedharamesh9351@gmail.com](mailto:youremail@nivedharamesh9351@gmail.com) -------------------------------------------------------------------------------- /Report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nivedha-Ramesh/Container-Loading-Problem/55706278c0cc6b3f87d11339a37229e1347e1463/Report.pdf -------------------------------------------------------------------------------- /Visualization.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import plotly.io as pio 4 | import matplotlib.pyplot as plt 5 | import plotly.graph_objects as go 6 | import matplotlib.tri as mtri 7 | 8 | class Visualization: 9 | def __init__(self, p_ind=0): 10 | self.palette = ['darkgreen', 'tomato', 'yellow', 'darkblue', 'darkviolet', 'indianred', 'yellowgreen', 'mediumblue', 'cyan', 'black', 'indigo', 'pink', 'lime', 'sienna', 'plum', 'deepskyblue', 'forestgreen', 'fuchsia', 'brown', 'turquoise', 'aliceblue', 'blueviolet', 'rosybrown', 'powderblue', 'lightblue', 'skyblue', 'lightskyblue', 'steelblue', 'dodgerblue', 'lightslategray', 'lightslategrey', 'slategray', 'slategrey', 'lightsteelblue', 'cornflowerblue', 'royalblue', 'ghostwhite', 'lavender', 'midnightblue', 'navy', 'darkblue', 'blue', 'slateblue', 'darkslateblue', 'mediumslateblue', 'mediumpurple', 'rebeccapurple', 'darkorchid', 'darkviolet', 'mediumorchid'] 11 | self.color_palette = ['lightcoral', 'firebrick', 'maroon', 'darkred', 'red', 'salmon', 'darksalmon', 'coral', 'orangered', 'lightsalmon', 'chocolate', 'saddlebrown', 'sandybrown', 'olive', 'olivedrab', 'darkolivegreen', 'greenyellow', 'chartreuse', 'lawngreen', 'darkseagreen', 'palegreen', 'lightgreen', 'limegreen', 'green', 'seagreen', 'mediumseagreen', 'springgreen', 'mediumspringgreen', 'mediumaquamarine', 'aquamarine', 'lightseagreen', 'mediumturquoise', 'lightcyan', 'paleturquoise', 'darkslategray', 'darkslategrey', 'teal', 'darkcyan', 'aqua', 'cyan', 'darkturquoise', 'cadetblue', 'thistle', 'violet', 'purple', 'darkmagenta', 'magenta', 'orchid', 'mediumvioletred', 'deeppink', 'hotpink', 'lavenderblush', 'palevioletred', 'crimson', 'lightpink'] 12 | 13 | self.save_dir = os.path.join("PS"+str(p_ind)) 14 | if not os.path.exists(self.save_dir): 15 | os.makedirs(self.save_dir) 16 | 17 | def plot_average_fitness(self, avg_fitness): 18 | """ 19 | Plots the average fitness values against the number of generations. 20 | """ 21 | generations = range(1, len(avg_fitness) + 1) 22 | avg_fitness_values = list(zip(*avg_fitness)) 23 | 24 | plt.figure(figsize=(10, 6)) 25 | plt.plot(generations, avg_fitness_values[0], label='Average Occupied Volume (%)') 26 | plt.plot(generations, avg_fitness_values[1], label='Average Number of Boxes (%)') 27 | plt.plot(generations, avg_fitness_values[2], label='Average Value of Boxes (%)') 28 | 29 | plt.xlabel('Generation') 30 | plt.ylabel('Average Fitness') 31 | plt.title('Average Fitness Over Generations') 32 | plt.legend() 33 | plt.savefig(f"{self.save_dir}/fitness_variation.png") 34 | plt.close() 35 | 36 | def cuboid_data(self, o, size=(1, 1, 1)): 37 | l, w, h = size 38 | x = [[o[0], o[0] + l, o[0] + l, o[0], o[0]], 39 | [o[0], o[0] + l, o[0] + l, o[0], o[0]], 40 | [o[0], o[0] + l, o[0] + l, o[0], o[0]], 41 | [o[0], o[0] + l, o[0] + l, o[0], o[0]]] 42 | y = [[o[1], o[1], o[1] + w, o[1] + w, o[1]], 43 | [o[1], o[1], o[1] + w, o[1] + w, o[1]], 44 | [o[1], o[1], o[1], o[1], o[1]], 45 | [o[1] + w, o[1] + w, o[1] + w, o[1] + w, o[1] + w]] 46 | z = [[o[2], o[2], o[2], o[2], o[2]], 47 | [o[2] + h, o[2] + h, o[2] + h, o[2] + h, o[2] + h], 48 | [o[2], o[2], o[2] + h, o[2] + h, o[2]], 49 | [o[2], o[2], o[2] + h, o[2] + h, o[2]]] 50 | return np.array(x), np.array(y), np.array(z) 51 | 52 | def plot_cuboid(self, pos, size, ax, color): 53 | X, Y, Z = self.cuboid_data(pos, size) 54 | ax.plot_surface(X, Y, Z, color=color, rstride=1, cstride=1) 55 | 56 | def draw_final_rank1_solutions(self, population): 57 | color_list = self.palette + self.color_palette 58 | for key, value in population.items(): 59 | if value['Rank'] == 1: 60 | fig = plt.figure() 61 | ax = fig.add_subplot(111, projection='3d') 62 | for i, box in enumerate(value['result']): 63 | color = color_list[i % len(color_list)] 64 | pos = box[:3] 65 | size = box[3:] 66 | self.plot_cuboid(pos, size, ax, color=color) 67 | plt.title(f"Visualization of Rank 1 Solution") 68 | plt.savefig(f"{self.save_dir}/R1_{key}.png") 69 | plt.close('all') 70 | 71 | def draw_plotly_final_rank1_solutions(self, population): 72 | fig = go.Figure() 73 | color_list = self.palette + self.color_palette 74 | for key, value in population.items(): 75 | if value['Rank'] == 1: 76 | for i, box in enumerate(value['result']): 77 | pos = box[:3] 78 | size = box[3:] 79 | color = color_list[i % len(color_list)] 80 | fig.add_trace(go.Mesh3d( 81 | x=[pos[0], pos[0]+size[0], pos[0]+size[0], pos[0], pos[0], pos[0]+size[0], pos[0]+size[0], pos[0]], 82 | y=[pos[1], pos[1], pos[1]+size[1], pos[1]+size[1], pos[1], pos[1], pos[1]+size[1], pos[1]+size[1]], 83 | z=[pos[2], pos[2], pos[2], pos[2], pos[2]+size[2], pos[2]+size[2], pos[2]+size[2], pos[2]+size[2]], 84 | color=color, 85 | opacity=1, 86 | alphahull=0 87 | )) 88 | file_name = f"{self.save_dir}/R1_{key}.html" 89 | pio.write_html(fig, file=file_name) 90 | 91 | def draw_plotly_true_solution(self, solution): 92 | fig = go.Figure() 93 | color_list = self.palette + self.color_palette 94 | for i, box in enumerate(solution): 95 | pos = box[:3] 96 | size = box[3:] 97 | color = color_list[i % len(color_list)] 98 | fig.add_trace(go.Mesh3d( 99 | x=[pos[0], pos[0]+size[0], pos[0]+size[0], pos[0], pos[0], pos[0]+size[0], pos[0]+size[0], pos[0]], 100 | y=[pos[1], pos[1], pos[1]+size[1], pos[1]+size[1], pos[1], pos[1], pos[1]+size[1], pos[1]+size[1]], 101 | z=[pos[2], pos[2], pos[2], pos[2], pos[2]+size[2], pos[2]+size[2], pos[2]+size[2], pos[2]+size[2]], 102 | color=color, 103 | opacity=1, 104 | alphahull=0 105 | )) 106 | 107 | file_name = f"{self.save_dir}/TrueSolution.html" 108 | pio.write_html(fig, file=file_name) 109 | 110 | def draw_pareto(self, population): 111 | fig = plt.figure() 112 | ax = fig.add_subplot(111, projection='3d') 113 | fitness, number, weight = [], [], [] 114 | fitness2, number2, weight2 = [], [], [] 115 | 116 | for key, value in population.items(): 117 | if value['Rank'] == 1: 118 | fitness.append(value['fitness'][0]) 119 | number.append(value['fitness'][1]) 120 | weight.append(value['fitness'][2]) 121 | else: 122 | fitness2.append(value['fitness'][0]) 123 | number2.append(value['fitness'][1]) 124 | weight2.append(value['fitness'][2]) 125 | 126 | if len(fitness) > 2: 127 | try: 128 | ax.scatter(fitness2, number2, weight2, c='b', marker='o') 129 | ax.scatter(fitness, number, weight, c='r', marker='o') 130 | triang = mtri.Triangulation(fitness, number) 131 | ax.plot_trisurf(triang, weight, color='red') 132 | ax.set_xlabel('occupied space') 133 | ax.set_ylabel('no of boxes') 134 | ax.set_zlabel('value') 135 | plt.savefig(f"{self.save_dir}/pareto.png") 136 | plt.close(fig) 137 | except Exception as e: 138 | print("An error occurred:", str(e)) 139 | 140 | -------------------------------------------------------------------------------- /boxes.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | class BoxGenerator: 4 | """ 5 | A class to generate boxes with specified dimensions and constraints. 6 | """ 7 | def __init__(self, min_dim=11, split_dim_min=5): 8 | self.min_dim = min_dim 9 | self.split_dim_min = split_dim_min 10 | 11 | def generate_boxes(self, container, num): 12 | """ 13 | Generates a list of boxes within a container based on the specified conditions. 14 | 15 | Parameters: 16 | - container (list): A list of cuboids where each cuboid is represented by six integers. 17 | - num (int): The number of boxes to generate. 18 | 19 | Returns: 20 | - A list of generated boxes with their dimensions. 21 | """ 22 | retry = 500 * num 23 | while num > 1: 24 | cuboid = random.choice(container) 25 | while cuboid[3] <= self.min_dim or cuboid[4] <= self.min_dim or cuboid[5] <= self.min_dim: 26 | retry -= 1 27 | if retry == 0: 28 | print("Cannot partition into packages. Please try again") 29 | return 30 | cuboid = random.choice(container) 31 | container.remove(cuboid) 32 | prob = random.uniform(0, 1) 33 | x1, y1, z1, x2, y2, z2 = cuboid 34 | 35 | # Splitting the cuboid based on the random probability generated 36 | if prob < 0.35: 37 | t = random.randint(self.split_dim_min, int(x2 / 2)) 38 | package1 = [x1 + t, y1, z1, x2 - t, y2, z2] 39 | package2 = [x1, y1, z1, t, y2, z2] 40 | elif prob < 0.65: 41 | t = random.randint(self.split_dim_min, int(y2 / 2)) 42 | package1 = [x1, y1 + t, z1, x2, y2 - t, z2] 43 | package2 = [x1, y1, z1, x2, t, z2] 44 | else: 45 | t = random.randint(self.split_dim_min, int(z2 / 2)) 46 | package1 = [x1, y1, z1 + t, x2, y2, z2 - t] 47 | package2 = [x1, y1, z1, x2, y2, t] 48 | container.append(package1) 49 | container.append(package2) 50 | num -= 1 51 | return container 52 | -------------------------------------------------------------------------------- /create_dataset.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | from boxes import BoxGenerator 4 | 5 | class DatasetCreator: 6 | """ 7 | A class to create a dataset for the box packing problem, including truck dimensions and box parameters. 8 | """ 9 | def __init__(self, min_boxes=10, max_boxes=100, min_value=50, max_value=500, 10 | max_truck_dim=(1000, 1000, 1000), min_truck_dim=(50, 50, 50)): 11 | """ 12 | Initializes the DatasetCreator with parameters for box and truck dimension ranges. 13 | 14 | Parameters: 15 | - min_boxes, max_boxes (int): The minimum and maximum number of boxes. 16 | - min_value, max_value (int): The minimum and maximum value associated with each box. 17 | - max_truck_dim, min_truck_dim (tuple): The maximum and minimum dimensions for the trucks. 18 | """ 19 | self.min_boxes = min_boxes 20 | self.max_boxes = max_boxes 21 | self.min_value = min_value 22 | self.max_value = max_value 23 | self.max_truck_len, self.max_truck_wid, self.max_truck_ht = max_truck_dim 24 | self.min_truck_len, self.min_truck_wid, self.min_truck_ht = min_truck_dim 25 | self.box_generator = BoxGenerator() 26 | 27 | def generate_dataset(self): 28 | """ 29 | Generates a dataset of packing scenarios, each with a set of boxes and a truck. 30 | 31 | Returns: 32 | - A dictionary representing the dataset, where each key is a scenario with truck dimensions, 33 | box parameters, and total value. 34 | """ 35 | truck_dim = [[random.randint(self.min_truck_len, self.max_truck_len), 36 | random.randint(self.min_truck_wid, self.max_truck_wid), 37 | random.randint(self.min_truck_ht, self.max_truck_ht)] for _ in range(5)] 38 | num_boxes = [[random.randint(self.min_boxes, self.max_boxes) for _ in range(5)] for _ in range(5)] 39 | dataset = {} 40 | i = 0 41 | origin = [0,0,0] 42 | for truck_dimensions, box_counts in zip(truck_dim, num_boxes): 43 | for number_of_boxes in box_counts: 44 | # Generate boxes within the truck's volume, defined by starting at the origin [0, 0, 0] and truck_dimensions [length, width, height] 45 | packages = self.box_generator.generate_boxes([origin + truck_dimensions], number_of_boxes) 46 | boxes = [] 47 | total_value = 0 48 | for each in packages: 49 | l, w, h = each[3:] 50 | vol = l * w * h 51 | value = random.randint(self.min_value, self.max_value) 52 | total_value += value 53 | boxes.append([l, w, h, vol, value]) 54 | dataset[str(i)] = {'truck dimension': truck_dimensions, 'number': number_of_boxes, 'boxes': boxes, 'solution': packages, 55 | 'total value': total_value} 56 | i += 1 57 | return dataset 58 | 59 | def save_to_file(self, dataset, filename='input.json'): 60 | with open(filename, 'w') as outfile: 61 | json.dump(dataset, outfile) 62 | 63 | 64 | if __name__ == "__main__": 65 | creator = DatasetCreator() 66 | dataset = creator.generate_dataset() 67 | creator.save_to_file(dataset) 68 | print("New dataset has been generated") 69 | -------------------------------------------------------------------------------- /input.json: -------------------------------------------------------------------------------- 1 | {"0": {"truck dimension": [215, 291, 519], "number": 9, "boxes": [[215, 110, 519, 12274350, 200], [7, 181, 519, 657573, 378], [208, 9, 519, 971568, 255], [208, 94, 456, 8915712, 413], [208, 37, 519, 3994224, 110], [208, 41, 498, 4246944, 73], [208, 41, 21, 179088, 255], [199, 94, 63, 1178478, 242], [9, 94, 63, 53298, 150]], "solution": [[0, 0, 0, 215, 110, 519], [0, 110, 0, 7, 181, 519], [7, 188, 0, 208, 9, 519], [7, 197, 63, 208, 94, 456], [7, 110, 0, 208, 37, 519], [7, 147, 21, 208, 41, 498], [7, 147, 0, 208, 41, 21], [16, 197, 0, 199, 94, 63], [7, 197, 0, 9, 94, 63]], "total value": 2076}, "1": {"truck dimension": [215, 291, 519], "number": 33, "boxes": [[45, 134, 519, 3129570, 435], [45, 27, 50, 60750, 342], [45, 9, 469, 189945, 82], [45, 24, 469, 506520, 145], [45, 8, 469, 168840, 200], [24, 130, 28, 87360, 294], [21, 9, 50, 9450, 75], [45, 47, 87, 184005, 52], [16, 12, 50, 9600, 320], [5, 12, 50, 3000, 214], [45, 69, 186, 577530, 65], [24, 130, 16, 49920, 8], [24, 130, 6, 18720, 94], [45, 22, 118, 116820, 442], [45, 30, 47, 63450, 398], [147, 291, 519, 22201263, 470], [45, 13, 382, 223470, 336], [45, 10, 382, 171900, 134], [21, 41, 50, 43050, 493], [23, 291, 396, 2650428, 496], [23, 234, 123, 661986, 65], [23, 57, 123, 161253, 456], [21, 41, 50, 43050, 5], [21, 27, 50, 28350, 202], [45, 10, 382, 171900, 196], [45, 7, 382, 120330, 167], [45, 7, 382, 120330, 24], [31, 30, 118, 109740, 342], [14, 30, 118, 49560, 185], [45, 26, 165, 193050, 394], [45, 13, 165, 96525, 23], [45, 32, 118, 169920, 284], [45, 15, 118, 79650, 208]], "solution": [[0, 0, 0, 45, 134, 519], [0, 134, 0, 45, 27, 50], [0, 166, 50, 45, 9, 469], [0, 142, 50, 45, 24, 469], [0, 134, 50, 45, 8, 469], [21, 161, 22, 24, 130, 28], [0, 161, 0, 21, 9, 50], [0, 175, 50, 45, 47, 87], [5, 170, 0, 16, 12, 50], [0, 170, 0, 5, 12, 50], [0, 222, 333, 45, 69, 186], [21, 161, 6, 24, 130, 16], [21, 161, 0, 24, 130, 6], [0, 222, 215, 45, 22, 118], [0, 222, 50, 45, 30, 47], [68, 0, 0, 147, 291, 519], [0, 185, 137, 45, 13, 382], [0, 175, 137, 45, 10, 382], [0, 182, 0, 21, 41, 50], [45, 0, 123, 23, 291, 396], [45, 57, 0, 23, 234, 123], [45, 0, 0, 23, 57, 123], [0, 250, 0, 21, 41, 50], [0, 223, 0, 21, 27, 50], [0, 198, 137, 45, 10, 382], [0, 215, 137, 45, 7, 382], [0, 208, 137, 45, 7, 382], [14, 222, 97, 31, 30, 118], [0, 222, 97, 14, 30, 118], [0, 265, 50, 45, 26, 165], [0, 252, 50, 45, 13, 165], [0, 259, 215, 45, 32, 118], [0, 244, 215, 45, 15, 118]], "total value": 7646}, "2": {"truck dimension": [215, 291, 519], "number": 10, "boxes": [[75, 175, 519, 6811875, 100], [51, 291, 417, 6188697, 95], [51, 291, 102, 1513782, 53], [88, 103, 519, 4704216, 216], [88, 13, 519, 593736, 374], [76, 190, 519, 7494360, 363], [76, 101, 519, 3983844, 202], [13, 62, 519, 418314, 384], [8, 113, 519, 469176, 464], [5, 113, 519, 293235, 67]], "solution": [[13, 116, 0, 75, 175, 519], [88, 0, 102, 51, 291, 417], [88, 0, 0, 51, 291, 102], [0, 13, 0, 88, 103, 519], [0, 0, 0, 88, 13, 519], [139, 101, 0, 76, 190, 519], [139, 0, 0, 76, 101, 519], [0, 116, 0, 13, 62, 519], [5, 178, 0, 8, 113, 519], [0, 178, 0, 5, 113, 519]], "total value": 2318}, "3": {"truck dimension": [215, 291, 519], "number": 7, "boxes": [[215, 291, 357, 22335705, 438], [215, 180, 78, 3018600, 62], [215, 111, 78, 1861470, 284], [61, 291, 84, 1491084, 226], [154, 291, 43, 1927002, 252], [154, 291, 27, 1209978, 83], [154, 291, 14, 627396, 247]], "solution": [[0, 0, 162, 215, 291, 357], [0, 111, 0, 215, 180, 78], [0, 0, 0, 215, 111, 78], [0, 0, 78, 61, 291, 84], [61, 0, 119, 154, 291, 43], [61, 0, 92, 154, 291, 27], [61, 0, 78, 154, 291, 14]], "total value": 1592}, "4": {"truck dimension": [215, 291, 519], "number": 6, "boxes": [[215, 291, 10, 625650, 394], [17, 291, 487, 2409189, 160], [12, 291, 22, 76824, 69], [5, 291, 22, 32010, 374], [141, 291, 509, 20884779, 257], [57, 291, 509, 8442783, 117]], "solution": [[0, 0, 0, 215, 291, 10], [0, 0, 32, 17, 291, 487], [5, 0, 10, 12, 291, 22], [0, 0, 10, 5, 291, 22], [74, 0, 10, 141, 291, 509], [17, 0, 10, 57, 291, 509]], "total value": 1371}, "5": {"truck dimension": [587, 417, 96], "number": 28, "boxes": [[587, 133, 45, 3513195, 406], [303, 284, 45, 3872340, 404], [284, 113, 45, 1444140, 50], [105, 417, 51, 2233035, 368], [131, 417, 7, 382389, 121], [284, 160, 21, 954240, 460], [284, 11, 21, 65604, 325], [22, 417, 31, 284394, 201], [131, 417, 10, 546270, 179], [84, 171, 24, 344736, 116], [131, 417, 7, 382389, 103], [131, 417, 8, 437016, 340], [131, 417, 7, 382389, 269], [11, 405, 20, 89100, 95], [11, 405, 20, 89100, 135], [11, 12, 20, 2640, 357], [11, 12, 20, 2640, 150], [200, 171, 9, 307800, 109], [200, 171, 8, 273600, 438], [200, 171, 7, 239400, 233], [258, 417, 28, 3012408, 79], [258, 417, 23, 2474478, 272], [16, 212, 51, 172992, 17], [16, 205, 51, 167280, 251], [55, 417, 38, 871530, 102], [55, 417, 13, 298155, 327], [124, 417, 12, 620496, 446], [7, 417, 12, 35028, 79]], "solution": [[0, 0, 0, 587, 133, 45], [284, 133, 0, 303, 284, 45], [0, 133, 0, 284, 113, 45], [16, 0, 45, 105, 417, 51], [143, 0, 67, 131, 417, 7], [0, 257, 0, 284, 160, 21], [0, 246, 0, 284, 11, 21], [121, 0, 65, 22, 417, 31], [143, 0, 45, 131, 417, 10], [0, 246, 21, 84, 171, 24], [143, 0, 74, 131, 417, 7], [143, 0, 88, 131, 417, 8], [143, 0, 81, 131, 417, 7], [132, 12, 45, 11, 405, 20], [121, 12, 45, 11, 405, 20], [132, 0, 45, 11, 12, 20], [121, 0, 45, 11, 12, 20], [84, 246, 21, 200, 171, 9], [84, 246, 37, 200, 171, 8], [84, 246, 30, 200, 171, 7], [329, 0, 68, 258, 417, 28], [329, 0, 45, 258, 417, 23], [0, 205, 45, 16, 212, 51], [0, 0, 45, 16, 205, 51], [274, 0, 58, 55, 417, 38], [274, 0, 45, 55, 417, 13], [150, 0, 55, 124, 417, 12], [143, 0, 55, 7, 417, 12]], "total value": 6432}, "6": {"truck dimension": [587, 417, 96], "number": 5, "boxes": [[389, 108, 96, 4033152, 132], [198, 108, 90, 1924560, 166], [198, 108, 6, 128304, 72], [587, 253, 96, 14257056, 332], [587, 56, 96, 3155712, 9]], "solution": [[198, 0, 0, 389, 108, 96], [0, 0, 6, 198, 108, 90], [0, 0, 0, 198, 108, 6], [0, 164, 0, 587, 253, 96], [0, 108, 0, 587, 56, 96]], "total value": 711}, "7": {"truck dimension": [587, 417, 96], "number": 34, "boxes": [[47, 7, 96, 31584, 373], [390, 417, 8, 1301040, 16], [390, 417, 6, 975780, 117], [390, 29, 14, 158340, 67], [390, 137, 7, 374010, 486], [390, 137, 7, 374010, 287], [206, 170, 14, 490280, 332], [244, 417, 7, 712236, 362], [6, 170, 14, 14280, 246], [10, 417, 61, 254370, 160], [90, 170, 9, 137700, 138], [90, 170, 5, 76500, 114], [89, 417, 96, 3562848, 431], [146, 256, 68, 2541568, 71], [146, 161, 9, 211554, 388], [89, 161, 59, 845411, 341], [57, 161, 59, 541443, 20], [234, 11, 61, 157014, 441], [133, 406, 61, 3293878, 283], [101, 406, 61, 2501366, 155], [7, 81, 14, 7938, 289], [26, 417, 96, 1040832, 324], [16, 417, 96, 640512, 338], [12, 417, 96, 480384, 21], [7, 417, 96, 280224, 227], [48, 170, 14, 114240, 356], [40, 170, 14, 95200, 421], [24, 410, 96, 944640, 346], [23, 410, 96, 905280, 162], [320, 10, 14, 44800, 31], [63, 81, 7, 35721, 59], [63, 81, 7, 35721, 57], [320, 46, 14, 206080, 343], [320, 25, 14, 112000, 159]], "solution": [[0, 0, 0, 47, 7, 96], [197, 0, 6, 390, 417, 8], [197, 0, 0, 390, 417, 6], [197, 251, 14, 390, 29, 14], [197, 280, 21, 390, 137, 7], [197, 280, 14, 390, 137, 7], [381, 0, 14, 206, 170, 14], [343, 0, 28, 244, 417, 7], [197, 0, 14, 6, 170, 14], [343, 0, 35, 10, 417, 61], [291, 0, 19, 90, 170, 9], [291, 0, 14, 90, 170, 5], [108, 0, 0, 89, 417, 96], [197, 161, 28, 146, 256, 68], [197, 0, 28, 146, 161, 9], [254, 0, 37, 89, 161, 59], [197, 0, 37, 57, 161, 59], [353, 0, 35, 234, 11, 61], [454, 11, 35, 133, 406, 61], [353, 11, 35, 101, 406, 61], [197, 170, 14, 7, 81, 14], [82, 0, 0, 26, 417, 96], [66, 0, 0, 16, 417, 96], [54, 0, 0, 12, 417, 96], [47, 0, 0, 7, 417, 96], [243, 0, 14, 48, 170, 14], [203, 0, 14, 40, 170, 14], [23, 7, 0, 24, 410, 96], [0, 7, 0, 23, 410, 96], [267, 170, 14, 320, 10, 14], [204, 170, 21, 63, 81, 7], [204, 170, 14, 63, 81, 7], [267, 205, 14, 320, 46, 14], [267, 180, 14, 320, 25, 14]], "total value": 7961}, "8": {"truck dimension": [587, 417, 96], "number": 7, "boxes": [[587, 417, 13, 3182127, 441], [587, 417, 15, 3671685, 407], [587, 401, 54, 12710898, 486], [587, 16, 54, 507168, 296], [587, 337, 14, 2769466, 271], [587, 80, 7, 328720, 318], [587, 80, 7, 328720, 198]], "solution": [[0, 0, 0, 587, 417, 13], [0, 0, 27, 587, 417, 15], [0, 16, 42, 587, 401, 54], [0, 0, 42, 587, 16, 54], [0, 80, 13, 587, 337, 14], [0, 0, 20, 587, 80, 7], [0, 0, 13, 587, 80, 7]], "total value": 2417}, "9": {"truck dimension": [587, 417, 96], "number": 18, "boxes": [[587, 38, 8, 178448, 281], [587, 38, 78, 1739868, 493], [587, 38, 10, 223060, 239], [26, 164, 31, 132184, 165], [11, 215, 31, 73315, 491], [8, 215, 31, 53320, 163], [7, 215, 31, 46655, 140], [587, 282, 65, 10759710, 235], [369, 97, 65, 2326545, 408], [150, 97, 65, 945750, 90], [30, 97, 65, 189150, 107], [561, 379, 9, 1913571, 122], [561, 379, 7, 1488333, 86], [561, 345, 15, 2903175, 342], [561, 34, 15, 286110, 172], [38, 8, 65, 19760, 113], [25, 89, 65, 144625, 128], [13, 89, 65, 75205, 91]], "solution": [[0, 0, 0, 587, 38, 8], [0, 0, 18, 587, 38, 78], [0, 0, 8, 587, 38, 10], [0, 38, 0, 26, 164, 31], [0, 202, 0, 11, 215, 31], [18, 202, 0, 8, 215, 31], [11, 202, 0, 7, 215, 31], [0, 135, 31, 587, 282, 65], [218, 38, 31, 369, 97, 65], [68, 38, 31, 150, 97, 65], [38, 38, 31, 30, 97, 65], [26, 38, 22, 561, 379, 9], [26, 38, 15, 561, 379, 7], [26, 72, 0, 561, 345, 15], [26, 38, 0, 561, 34, 15], [0, 38, 31, 38, 8, 65], [13, 46, 31, 25, 89, 65], [0, 46, 31, 13, 89, 65]], "total value": 3866}, "10": {"truck dimension": [121, 564, 56], "number": 15, "boxes": [[121, 477, 31, 1789227, 95], [121, 87, 17, 178959, 36], [121, 87, 8, 84216, 444], [43, 116, 25, 124700, 329], [78, 194, 25, 378300, 184], [105, 54, 31, 175770, 259], [105, 33, 31, 107415, 137], [78, 164, 25, 319800, 286], [78, 119, 25, 232050, 223], [26, 287, 25, 186550, 200], [17, 287, 25, 121975, 178], [10, 87, 31, 26970, 53], [6, 87, 31, 16182, 251], [43, 47, 25, 50525, 338], [43, 27, 25, 29025, 418]], "solution": [[0, 87, 25, 121, 477, 31], [0, 0, 0, 121, 87, 17], [0, 0, 17, 121, 87, 8], [0, 161, 0, 43, 116, 25], [43, 87, 0, 78, 194, 25], [16, 33, 25, 105, 54, 31], [16, 0, 25, 105, 33, 31], [43, 400, 0, 78, 164, 25], [43, 281, 0, 78, 119, 25], [17, 277, 0, 26, 287, 25], [0, 277, 0, 17, 287, 25], [6, 0, 25, 10, 87, 31], [0, 0, 25, 6, 87, 31], [0, 114, 0, 43, 47, 25], [0, 87, 0, 43, 27, 25]], "total value": 3431}, "11": {"truck dimension": [121, 564, 56], "number": 10, "boxes": [[121, 564, 9, 614196, 52], [121, 564, 8, 545952, 474], [121, 263, 19, 604637, 82], [97, 564, 10, 547080, 273], [97, 564, 10, 547080, 164], [57, 301, 19, 325983, 483], [42, 301, 19, 240198, 428], [22, 301, 19, 125818, 298], [18, 564, 20, 203040, 269], [6, 564, 20, 67680, 436]], "solution": [[0, 0, 8, 121, 564, 9], [0, 0, 0, 121, 564, 8], [0, 0, 17, 121, 263, 19], [24, 0, 46, 97, 564, 10], [24, 0, 36, 97, 564, 10], [0, 263, 17, 57, 301, 19], [79, 263, 17, 42, 301, 19], [57, 263, 17, 22, 301, 19], [6, 0, 36, 18, 564, 20], [0, 0, 36, 6, 564, 20]], "total value": 2959}, "12": {"truck dimension": [121, 564, 56], "number": 15, "boxes": [[6, 564, 56, 189504, 109], [115, 564, 17, 1102620, 136], [73, 446, 23, 748834, 201], [42, 446, 23, 430836, 447], [115, 446, 10, 512900, 121], [115, 446, 6, 307740, 342], [9, 54, 39, 18954, 186], [59, 64, 39, 147264, 348], [22, 64, 39, 54912, 124], [25, 64, 39, 62400, 186], [9, 64, 39, 22464, 274], [106, 18, 34, 64872, 319], [106, 18, 5, 9540, 228], [70, 36, 39, 98280, 327], [36, 36, 39, 50544, 361]], "solution": [[0, 0, 0, 6, 564, 56], [6, 0, 0, 115, 564, 17], [48, 118, 33, 73, 446, 23], [6, 118, 33, 42, 446, 23], [6, 118, 23, 115, 446, 10], [6, 118, 17, 115, 446, 6], [6, 64, 17, 9, 54, 39], [62, 0, 17, 59, 64, 39], [40, 0, 17, 22, 64, 39], [15, 0, 17, 25, 64, 39], [6, 0, 17, 9, 64, 39], [15, 64, 22, 106, 18, 34], [15, 64, 17, 106, 18, 5], [51, 82, 17, 70, 36, 39], [15, 82, 17, 36, 36, 39]], "total value": 3709}, "13": {"truck dimension": [121, 564, 56], "number": 23, "boxes": [[35, 564, 56, 1105440, 296], [10, 204, 56, 114240, 262], [12, 88, 42, 44352, 124], [7, 44, 56, 17248, 5], [5, 44, 56, 12320, 353], [64, 564, 17, 613632, 267], [64, 564, 9, 324864, 427], [11, 346, 56, 213136, 151], [11, 346, 56, 213136, 415], [6, 72, 56, 24192, 25], [6, 72, 56, 24192, 209], [11, 14, 56, 8624, 205], [11, 14, 56, 8624, 270], [16, 564, 16, 144384, 421], [48, 564, 10, 270720, 186], [48, 564, 6, 162432, 108], [64, 80, 8, 40960, 241], [64, 80, 6, 30720, 207], [12, 26, 14, 4368, 293], [64, 484, 8, 247808, 184], [64, 484, 6, 185856, 21], [7, 62, 14, 6076, 484], [5, 62, 14, 4340, 430]], "solution": [[22, 0, 0, 35, 564, 56], [0, 14, 0, 10, 204, 56], [10, 130, 14, 12, 88, 42], [15, 14, 0, 7, 44, 56], [10, 14, 0, 5, 44, 56], [57, 0, 9, 64, 564, 17], [57, 0, 0, 64, 564, 9], [11, 218, 0, 11, 346, 56], [0, 218, 0, 11, 346, 56], [16, 58, 0, 6, 72, 56], [10, 58, 0, 6, 72, 56], [11, 0, 0, 11, 14, 56], [0, 0, 0, 11, 14, 56], [57, 0, 40, 16, 564, 16], [73, 0, 46, 48, 564, 10], [73, 0, 40, 48, 564, 6], [57, 0, 32, 64, 80, 8], [57, 0, 26, 64, 80, 6], [10, 130, 0, 12, 26, 14], [57, 80, 32, 64, 484, 8], [57, 80, 26, 64, 484, 6], [15, 156, 0, 7, 62, 14], [10, 156, 0, 5, 62, 14]], "total value": 5584}, "14": {"truck dimension": [121, 564, 56], "number": 34, "boxes": [[121, 390, 10, 471900, 465], [121, 372, 10, 450120, 172], [121, 390, 6, 283140, 62], [121, 18, 10, 21780, 391], [7, 372, 15, 39060, 195], [83, 390, 10, 323700, 112], [83, 390, 5, 161850, 71], [38, 390, 10, 148200, 271], [38, 390, 5, 74100, 25], [83, 298, 9, 222606, 317], [83, 298, 6, 148404, 251], [74, 90, 14, 93240, 168], [24, 84, 14, 28224, 163], [8, 90, 14, 10080, 220], [121, 124, 42, 630168, 455], [44, 18, 15, 11880, 143], [12, 21, 14, 3528, 245], [12, 69, 8, 6624, 252], [12, 69, 6, 4968, 149], [8, 90, 14, 10080, 498], [65, 74, 15, 72150, 440], [18, 74, 15, 19980, 450], [97, 84, 9, 73332, 482], [97, 84, 5, 40740, 37], [76, 50, 42, 159600, 165], [45, 50, 42, 94500, 483], [14, 90, 14, 17640, 429], [5, 90, 14, 6300, 73], [77, 18, 9, 12474, 287], [77, 18, 6, 8316, 364], [31, 26, 10, 8060, 493], [31, 26, 5, 4030, 339], [31, 346, 9, 96534, 151], [31, 346, 6, 64356, 104]], "solution": [[0, 174, 0, 121, 390, 10], [0, 192, 31, 121, 372, 10], [0, 174, 10, 121, 390, 6], [0, 174, 31, 121, 18, 10], [0, 192, 41, 7, 372, 15], [38, 174, 21, 83, 390, 10], [38, 174, 16, 83, 390, 5], [0, 174, 21, 38, 390, 10], [0, 174, 16, 38, 390, 5], [38, 266, 47, 83, 298, 9], [38, 266, 41, 83, 298, 6], [47, 84, 0, 74, 90, 14], [0, 0, 0, 24, 84, 14], [0, 84, 0, 8, 90, 14], [0, 50, 14, 121, 124, 42], [0, 174, 41, 44, 18, 15], [8, 84, 0, 12, 21, 14], [8, 105, 6, 12, 69, 8], [8, 105, 0, 12, 69, 6], [20, 84, 0, 8, 90, 14], [56, 192, 41, 65, 74, 15], [38, 192, 41, 18, 74, 15], [24, 0, 5, 97, 84, 9], [24, 0, 0, 97, 84, 5], [45, 0, 14, 76, 50, 42], [0, 0, 14, 45, 50, 42], [33, 84, 0, 14, 90, 14], [28, 84, 0, 5, 90, 14], [44, 174, 47, 77, 18, 9], [44, 174, 41, 77, 18, 6], [7, 192, 46, 31, 26, 10], [7, 192, 41, 31, 26, 5], [7, 218, 47, 31, 346, 9], [7, 218, 41, 31, 346, 6]], "total value": 8922}, "15": {"truck dimension": [68, 108, 522], "number": 13, "boxes": [[5, 108, 522, 281880, 422], [9, 108, 522, 507384, 419], [6, 108, 522, 338256, 107], [35, 9, 522, 164430, 144], [7, 108, 522, 394632, 452], [6, 108, 522, 338256, 265], [35, 6, 522, 109620, 272], [35, 64, 235, 526400, 381], [35, 20, 522, 365400, 329], [35, 9, 522, 164430, 240], [35, 49, 287, 492205, 432], [29, 15, 287, 124845, 8], [6, 15, 287, 25830, 38]], "solution": [[15, 0, 0, 5, 108, 522], [6, 0, 0, 9, 108, 522], [0, 0, 0, 6, 108, 522], [33, 0, 0, 35, 9, 522], [26, 0, 0, 7, 108, 522], [20, 0, 0, 6, 108, 522], [33, 9, 0, 35, 6, 522], [33, 44, 0, 35, 64, 235], [33, 24, 0, 35, 20, 522], [33, 15, 0, 35, 9, 522], [33, 59, 235, 35, 49, 287], [39, 44, 235, 29, 15, 287], [33, 44, 235, 6, 15, 287]], "total value": 3509}, "16": {"truck dimension": [68, 108, 522], "number": 8, "boxes": [[68, 64, 13, 56576, 39], [68, 30, 13, 26520, 317], [68, 14, 8, 7616, 72], [68, 14, 5, 4760, 270], [19, 108, 509, 1044468, 47], [49, 108, 243, 1285956, 139], [38, 108, 266, 1091664, 48], [11, 108, 266, 316008, 292]], "solution": [[0, 44, 0, 68, 64, 13], [0, 14, 0, 68, 30, 13], [0, 0, 5, 68, 14, 8], [0, 0, 0, 68, 14, 5], [0, 0, 13, 19, 108, 509], [19, 0, 13, 49, 108, 243], [30, 0, 256, 38, 108, 266], [19, 0, 256, 11, 108, 266]], "total value": 1224}, "17": {"truck dimension": [68, 108, 522], "number": 14, "boxes": [[50, 108, 334, 1803600, 275], [6, 108, 334, 216432, 230], [7, 35, 334, 81830, 86], [5, 35, 334, 58450, 162], [7, 55, 334, 128590, 323], [5, 55, 334, 91850, 217], [6, 18, 274, 29592, 342], [6, 18, 274, 29592, 208], [6, 18, 60, 6480, 55], [6, 18, 60, 6480, 484], [68, 108, 61, 447984, 371], [68, 108, 6, 44064, 455], [54, 108, 121, 705672, 481], [14, 108, 121, 182952, 362]], "solution": [[18, 0, 188, 50, 108, 334], [0, 0, 188, 6, 108, 334], [11, 18, 188, 7, 35, 334], [6, 18, 188, 5, 35, 334], [11, 53, 188, 7, 55, 334], [6, 53, 188, 5, 55, 334], [12, 0, 248, 6, 18, 274], [6, 0, 248, 6, 18, 274], [12, 0, 188, 6, 18, 60], [6, 0, 188, 6, 18, 60], [0, 0, 6, 68, 108, 61], [0, 0, 0, 68, 108, 6], [14, 0, 67, 54, 108, 121], [0, 0, 67, 14, 108, 121]], "total value": 4051}, "18": {"truck dimension": [68, 108, 522], "number": 17, "boxes": [[5, 108, 422, 227880, 341], [63, 5, 203, 63945, 466], [57, 108, 219, 1348164, 440], [6, 108, 219, 141912, 275], [53, 14, 16, 11872, 312], [15, 108, 84, 136080, 49], [53, 84, 16, 71232, 127], [53, 10, 16, 8480, 353], [15, 108, 84, 136080, 135], [9, 108, 84, 81648, 244], [63, 103, 36, 233604, 92], [54, 103, 167, 928854, 155], [9, 103, 167, 154809, 142], [9, 108, 100, 97200, 231], [6, 108, 100, 64800, 397], [7, 108, 84, 63504, 115], [7, 108, 84, 63504, 216]], "solution": [[0, 0, 100, 5, 108, 422], [5, 0, 100, 63, 5, 203], [11, 0, 303, 57, 108, 219], [5, 0, 303, 6, 108, 219], [15, 0, 0, 53, 14, 16], [53, 0, 16, 15, 108, 84], [15, 24, 0, 53, 84, 16], [15, 14, 0, 53, 10, 16], [24, 0, 16, 15, 108, 84], [15, 0, 16, 9, 108, 84], [5, 5, 100, 63, 103, 36], [14, 5, 136, 54, 103, 167], [5, 5, 136, 9, 103, 167], [6, 0, 0, 9, 108, 100], [0, 0, 0, 6, 108, 100], [46, 0, 16, 7, 108, 84], [39, 0, 16, 7, 108, 84]], "total value": 4090}, "19": {"truck dimension": [68, 108, 522], "number": 24, "boxes": [[41, 5, 522, 107010, 82], [27, 108, 492, 1434672, 233], [27, 6, 30, 4860, 299], [8, 103, 491, 404584, 85], [41, 24, 31, 30504, 145], [8, 103, 491, 404584, 336], [5, 103, 491, 252865, 166], [22, 17, 8, 2992, 169], [22, 17, 6, 2244, 16], [27, 77, 30, 62370, 140], [27, 25, 30, 20250, 180], [6, 62, 31, 11532, 133], [6, 62, 31, 11532, 439], [29, 40, 31, 35960, 272], [5, 17, 17, 1445, 102], [19, 17, 11, 3553, 443], [29, 22, 21, 13398, 311], [29, 22, 10, 6380, 462], [12, 17, 17, 3468, 111], [5, 17, 17, 1445, 302], [14, 103, 491, 708022, 479], [6, 103, 491, 303438, 142], [10, 17, 20, 3400, 312], [9, 17, 20, 3060, 359]], "solution": [[27, 0, 0, 41, 5, 522], [0, 0, 30, 27, 108, 492], [0, 0, 0, 27, 6, 30], [40, 5, 31, 8, 103, 491], [27, 22, 0, 41, 24, 31], [32, 5, 31, 8, 103, 491], [27, 5, 31, 5, 103, 491], [46, 5, 6, 22, 17, 8], [46, 5, 0, 22, 17, 6], [0, 31, 0, 27, 77, 30], [0, 6, 0, 27, 25, 30], [33, 46, 0, 6, 62, 31], [27, 46, 0, 6, 62, 31], [39, 68, 0, 29, 40, 31], [46, 5, 14, 5, 17, 17], [27, 5, 0, 19, 17, 11], [39, 46, 10, 29, 22, 21], [39, 46, 0, 29, 22, 10], [56, 5, 14, 12, 17, 17], [51, 5, 14, 5, 17, 17], [54, 5, 31, 14, 103, 491], [48, 5, 31, 6, 103, 491], [36, 5, 11, 10, 17, 20], [27, 5, 11, 9, 17, 20]], "total value": 5718}, "20": {"truck dimension": [552, 68, 517], "number": 32, "boxes": [[71, 15, 12, 12780, 108], [71, 8, 12, 6816, 103], [71, 7, 12, 5964, 354], [215, 11, 60, 141900, 30], [266, 68, 7, 126616, 449], [79, 68, 10, 53720, 430], [128, 19, 60, 145920, 429], [128, 8, 60, 61440, 160], [71, 53, 11, 41393, 114], [215, 30, 7, 45150, 146], [552, 34, 457, 8576976, 435], [552, 34, 457, 8576976, 281], [25, 68, 14, 23800, 160], [79, 34, 43, 115498, 25], [16, 68, 14, 15232, 199], [87, 27, 50, 117450, 122], [87, 27, 10, 23490, 345], [187, 58, 53, 574838, 178], [187, 10, 53, 99110, 137], [30, 68, 8, 16320, 157], [30, 68, 6, 12240, 68], [215, 5, 53, 56975, 168], [71, 41, 13, 37843, 180], [71, 12, 13, 11076, 441], [79, 22, 43, 74734, 286], [79, 12, 43, 40764, 442], [215, 25, 22, 118250, 101], [215, 16, 31, 106640, 497], [215, 9, 31, 59985, 391], [46, 68, 22, 68816, 252], [25, 68, 16, 27200, 53], [25, 68, 6, 10200, 405]], "solution": [[0, 0, 0, 71, 15, 12], [0, 7, 12, 71, 8, 12], [0, 0, 12, 71, 7, 12], [71, 30, 0, 215, 11, 60], [286, 0, 0, 266, 68, 7], [286, 0, 7, 79, 68, 10], [158, 49, 0, 128, 19, 60], [158, 41, 0, 128, 8, 60], [0, 15, 0, 71, 53, 11], [71, 0, 0, 215, 30, 7], [0, 34, 60, 552, 34, 457], [0, 0, 60, 552, 34, 457], [0, 0, 24, 25, 68, 14], [286, 34, 17, 79, 34, 43], [25, 0, 24, 16, 68, 14], [71, 41, 10, 87, 27, 50], [71, 41, 0, 87, 27, 10], [365, 10, 7, 187, 58, 53], [365, 0, 7, 187, 10, 53], [41, 0, 30, 30, 68, 8], [41, 0, 24, 30, 68, 6], [71, 0, 7, 215, 5, 53], [0, 27, 11, 71, 41, 13], [0, 15, 11, 71, 12, 13], [286, 12, 17, 79, 22, 43], [286, 0, 17, 79, 12, 43], [71, 5, 7, 215, 25, 22], [71, 14, 29, 215, 16, 31], [71, 5, 29, 215, 9, 31], [25, 0, 38, 46, 68, 22], [0, 0, 44, 25, 68, 16], [0, 0, 38, 25, 68, 6]], "total value": 7646}, "21": {"truck dimension": [552, 68, 517], "number": 26, "boxes": [[188, 49, 21, 193452, 347], [436, 19, 21, 173964, 229], [552, 68, 8, 300288, 48], [116, 19, 12, 26448, 137], [116, 19, 9, 19836, 174], [552, 68, 144, 5405184, 66], [364, 9, 21, 68796, 388], [367, 68, 193, 4816508, 289], [17, 68, 193, 223108, 372], [22, 68, 32, 47872, 494], [146, 47, 32, 219584, 38], [146, 21, 32, 98112, 40], [99, 68, 161, 1083852, 105], [34, 68, 161, 372232, 248], [552, 68, 68, 2552448, 388], [552, 68, 65, 2439840, 110], [441, 46, 10, 202860, 253], [441, 46, 8, 162288, 455], [312, 22, 18, 123552, 357], [129, 22, 18, 51084, 59], [364, 40, 15, 218400, 10], [364, 40, 6, 87360, 477], [35, 47, 161, 264845, 156], [35, 21, 161, 118335, 450], [66, 68, 18, 80784, 41], [45, 68, 18, 55080, 271]], "solution": [[0, 19, 0, 188, 49, 21], [116, 0, 0, 436, 19, 21], [0, 0, 21, 552, 68, 8], [0, 0, 9, 116, 19, 12], [0, 0, 0, 116, 19, 9], [0, 0, 180, 552, 68, 144], [188, 19, 0, 364, 9, 21], [185, 0, 324, 367, 68, 193], [168, 0, 324, 17, 68, 193], [0, 0, 324, 22, 68, 32], [22, 21, 324, 146, 47, 32], [22, 0, 324, 146, 21, 32], [69, 0, 356, 99, 68, 161], [35, 0, 356, 34, 68, 161], [0, 0, 112, 552, 68, 68], [0, 0, 47, 552, 68, 65], [111, 22, 37, 441, 46, 10], [111, 22, 29, 441, 46, 8], [240, 0, 29, 312, 22, 18], [111, 0, 29, 129, 22, 18], [188, 28, 6, 364, 40, 15], [188, 28, 0, 364, 40, 6], [0, 21, 356, 35, 47, 161], [0, 0, 356, 35, 21, 161], [45, 0, 29, 66, 68, 18], [0, 0, 29, 45, 68, 18]], "total value": 6002}, "22": {"truck dimension": [552, 68, 517], "number": 10, "boxes": [[552, 68, 73, 2740128, 366], [552, 33, 256, 4663296, 263], [552, 10, 188, 1037760, 192], [552, 9, 444, 2205792, 449], [48, 23, 188, 207552, 224], [344, 26, 444, 3971136, 379], [208, 26, 444, 2401152, 272], [504, 8, 188, 758016, 373], [392, 15, 188, 1105440, 388], [112, 15, 188, 315840, 28]], "solution": [[0, 0, 0, 552, 68, 73], [0, 0, 261, 552, 33, 256], [0, 0, 73, 552, 10, 188], [0, 33, 73, 552, 9, 444], [0, 10, 73, 48, 23, 188], [208, 42, 73, 344, 26, 444], [0, 42, 73, 208, 26, 444], [48, 10, 73, 504, 8, 188], [160, 18, 73, 392, 15, 188], [48, 18, 73, 112, 15, 188]], "total value": 2934}, "23": {"truck dimension": [552, 68, 517], "number": 22, "boxes": [[332, 16, 517, 2746304, 21], [372, 52, 446, 8627424, 474], [40, 16, 60, 38400, 412], [180, 68, 6, 73440, 329], [40, 14, 452, 253120, 19], [40, 8, 457, 146240, 280], [40, 8, 457, 146240, 106], [372, 52, 42, 812448, 106], [372, 52, 29, 560976, 190], [57, 29, 381, 629793, 209], [180, 68, 21, 257040, 436], [96, 68, 38, 248064, 274], [84, 68, 38, 217056, 379], [123, 68, 207, 1731348, 178], [11, 14, 452, 69608, 169], [6, 14, 452, 37968, 23], [123, 68, 157, 1313148, 61], [123, 68, 88, 736032, 86], [33, 29, 71, 67947, 192], [24, 29, 71, 49416, 468], [57, 25, 310, 441750, 201], [57, 25, 142, 202350, 275]], "solution": [[220, 0, 0, 332, 16, 517], [180, 16, 71, 372, 52, 446], [180, 0, 0, 40, 16, 60], [0, 0, 0, 180, 68, 6], [17, 0, 65, 40, 14, 452], [180, 8, 60, 40, 8, 457], [180, 0, 60, 40, 8, 457], [180, 16, 29, 372, 52, 42], [180, 16, 0, 372, 52, 29], [0, 39, 136, 57, 29, 381], [0, 0, 6, 180, 68, 21], [84, 0, 27, 96, 68, 38], [0, 0, 27, 84, 68, 38], [57, 0, 65, 123, 68, 207], [6, 0, 65, 11, 14, 452], [0, 0, 65, 6, 14, 452], [57, 0, 360, 123, 68, 157], [57, 0, 272, 123, 68, 88], [24, 39, 65, 33, 29, 71], [0, 39, 65, 24, 29, 71], [0, 14, 207, 57, 25, 310], [0, 14, 65, 57, 25, 142]], "total value": 4888}, "24": {"truck dimension": [552, 68, 517], "number": 32, "boxes": [[552, 7, 406, 1568784, 258], [194, 68, 9, 118728, 12], [194, 9, 15, 26190, 68], [26, 68, 6, 10608, 113], [144, 39, 85, 477360, 376], [144, 29, 85, 354960, 186], [194, 44, 15, 128040, 162], [118, 68, 14, 112336, 47], [118, 68, 12, 96288, 38], [194, 15, 9, 26190, 314], [194, 15, 6, 17460, 233], [49, 68, 18, 59976, 414], [14, 68, 18, 17136, 424], [7, 68, 18, 8568, 495], [72, 41, 87, 256824, 447], [72, 27, 87, 169128, 214], [214, 68, 94, 1367888, 200], [26, 6, 20, 3120, 448], [35, 68, 87, 207060, 32], [17, 68, 87, 100572, 28], [93, 61, 406, 2303238, 337], [459, 61, 30, 839970, 401], [214, 68, 11, 160072, 335], [214, 68, 6, 87312, 289], [16, 49, 20, 15680, 152], [10, 49, 20, 9800, 377], [70, 58, 69, 280140, 140], [70, 10, 69, 48300, 24], [19, 13, 20, 4940, 326], [7, 13, 20, 1820, 406], [459, 61, 207, 5795793, 346], [459, 61, 169, 4731831, 171]], "solution": [[0, 0, 111, 552, 7, 406], [0, 0, 0, 194, 68, 9], [0, 0, 9, 194, 9, 15], [194, 0, 0, 26, 68, 6], [194, 29, 26, 144, 39, 85], [194, 0, 26, 144, 29, 85], [0, 24, 9, 194, 44, 15], [220, 0, 12, 118, 68, 14], [220, 0, 0, 118, 68, 12], [0, 9, 15, 194, 15, 9], [0, 9, 9, 194, 15, 6], [21, 0, 24, 49, 68, 18], [7, 0, 24, 14, 68, 18], [0, 0, 24, 7, 68, 18], [122, 27, 24, 72, 41, 87], [122, 0, 24, 72, 27, 87], [338, 0, 17, 214, 68, 94], [194, 0, 6, 26, 6, 20], [87, 0, 24, 35, 68, 87], [70, 0, 24, 17, 68, 87], [0, 7, 111, 93, 61, 406], [93, 7, 111, 459, 61, 30], [338, 0, 6, 214, 68, 11], [338, 0, 0, 214, 68, 6], [204, 19, 6, 16, 49, 20], [194, 19, 6, 10, 49, 20], [0, 10, 42, 70, 58, 69], [0, 0, 42, 70, 10, 69], [201, 6, 6, 19, 13, 20], [194, 6, 6, 7, 13, 20], [93, 7, 310, 459, 61, 207], [93, 7, 141, 459, 61, 169]], "total value": 7813}} -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import json 2 | from tabulate import tabulate 3 | from PackingAlgorithm import PackingAlgorithm 4 | from Visualization import Visualization 5 | 6 | NUM_OF_INDIVIDUALS = 40 7 | NUM_OF_GENERATIONS = 600 8 | PC = 0.8 9 | PM1 = 0.5 10 | PM2 = 0.2 11 | K = 4 12 | ROTATIONS = 6 13 | 14 | 15 | if __name__ == "__main__": 16 | 17 | with open('input.json', 'r') as outfile: 18 | data = json.load(outfile) 19 | problem_indices = list(data.keys()) 20 | 21 | for p_ind in problem_indices: 22 | visualization = Visualization(p_ind) 23 | print("Running Problem Set {}".format(p_ind)) 24 | print(tabulate([['Generations', NUM_OF_GENERATIONS], ['Individuals', NUM_OF_INDIVIDUALS], 25 | ['Rotations', ROTATIONS], ['Crossover Prob.', PC], ['Mutation Prob1', PM1], 26 | ['Mutation Prob2', PM2], ['Tournament Size', K]], headers=['Parameter', 'Value'], 27 | tablefmt="github")) 28 | print() 29 | truck_dimension = data[p_ind]['truck dimension'] 30 | boxes = data[p_ind]['boxes'] 31 | total_value = data[p_ind]['total value'] 32 | boxParams = {} 33 | for i, params in enumerate(boxes): 34 | boxParams[i] = params 35 | pa = PackingAlgorithm(box_params=boxParams, truck_dimension=truck_dimension, total_value=total_value, population_size=NUM_OF_INDIVIDUALS, generations=NUM_OF_GENERATIONS, 36 | k=K, pc=PC, pm1=PM1, pm2=PM2, rotation=ROTATIONS) 37 | pa.optimize() 38 | 39 | visualization.plot_average_fitness(pa.avg_fitness) 40 | true_solution = data[p_ind]['solution'] 41 | 42 | visualization.draw_final_rank1_solutions(pa.population) 43 | visualization.draw_plotly_final_rank1_solutions(pa.population) 44 | visualization.draw_plotly_true_solution(true_solution) 45 | visualization.draw_pareto(pa.population) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | matplotlib 3 | plotly 4 | tabulate 5 | --------------------------------------------------------------------------------