def apply(self, kp: Knapsack, items: List[Item]): if self.name == None: return None if self.onKP: # Choice the item that will be unpacked from the knapsack idx = None kp_packed = kp.getPackedItems() for i, item in enumerate(kp_packed): if idx == None or heuristicComparison[self.name]( kp_packed[idx], item): idx = i if idx != None: items.append(kp.unpack(idx)) return idx else: # Choice the item that will be packed idx = None for i, item in enumerate(items): if kp.canPack(item): if idx == None or heuristicComparison[self.name]( items[idx], item): idx = i if idx != None: kp.pack(items.pop(idx)) return idx
def RandomSearch(kp: Knapsack, items: List[Item], stopCriteria=10): # Random Search implementation # Initialize the variables mh = Metaheuristic() heuristics = list(heuristicComparison.keys()) countNone = 0 while countNone < stopCriteria: # Choice randomly the next heuristic nextHeuristic = np.random.choice(heuristics) kp_candidate = kp.copy() items_candidate = items.copy() nextItem = SimpleHeuristic(nextHeuristic).apply( kp_candidate, items_candidate) if nextItem == None or kp_candidate.getValue() <= kp.getValue(): # Reject the heuristic countNone += 1 continue countNone = 0 # Accept the heuristic kp = kp_candidate items = items_candidate mh.addHeuristic(nextHeuristic) return kp, mh
def solver(method: str, kp: Knapsack, items: List[Item], additionalArgs=None): if method == 'Heuristic': # Execute the heuristic method simple_heuristic = SimpleHeuristic(additionalArgs) return ConstructiveSolution(kp, items, simple_heuristic).getValue() elif method == 'SimulatedAnnealing': # Execute the Simulated Annealing metaheuristic return solveMetaheuristic(method, kp, items, additionalArgs) elif method == 'RandomSearch': # Execute the Random Search metaheuristic return solveMetaheuristic(method, kp, items, additionalArgs) elif method == 'HyperheuristicNaive': # Execute the Hyper-heuristic naive model hh = HyperheuristicNaive(additionalArgs) return ConstructiveSolution(kp, items, hh).getValue() elif method == 'Hyperheuristic': # Execute the Hyper-heuristic based on LSTM model return hyperheuristicSolver(kp, items, additionalArgs).getValue() elif method == 'Backtracking': # Execute the recursive backtracking method return kpBacktracking(kp.getCapacity(), items).getValue() elif method == 'DP': # Execute the dynamic programming method return kpDP(kp.getCapacity(), items).getValue() elif method == 'MILP': # Execute the mixed integer linear programming method return kpMILP(kp.getCapacity(), items).getValue() elif method in list(heuristicComparison.keys()): # Given the heuristic as method parameter, execute the constructive heuristic method simple_heuristic = SimpleHeuristic(method) return ConstructiveSolution(kp, items, simple_heuristic).getValue() else: return 0
def hyperheuristicSolverHH(kp: Knapsack, items: List[Item], hh: Hyperheuristic, stopCritaria = 10): # Prepare the HH variables hh.reset() mh = Metaheuristic() kp_best = kp.copy() mh_best = mh.copy() countNone = 0 while countNone < stopCritaria: # Choice the next heuristic nextHeuristic = hh.getHeuristic(items) # Apply the heuristic nextItem = SimpleHeuristic(nextHeuristic).apply(kp, items) if nextItem == None: # Reject the heuristic countNone += 1 continue countNone = 0 # Accept the heuristic mh.addHeuristic(nextHeuristic) # Save the best solution reached if kp_best.getValue() < kp.getValue(): kp_best = kp.copy() mh_best = mh.copy() # Return the best solution reached return kp_best, mh_best
def SimulatedAnnealing(kp: Knapsack, items: List[Item], n_iterations=100, temp=200, stopCriteria=10): # Simulated Annealing implementation # Initialization of the variables mh = Metaheuristic() heuristics = list(heuristicComparison.keys()) countNone = 0 kp_best = kp.copy() mh_best = Metaheuristic() n_iterations = max(n_iterations, 2 * len(items)) for i in range(n_iterations): if countNone == stopCriteria: # Stop criteria met break # Choice randomly the next heuristic nextHeuristic = np.random.choice(heuristics) kp_candidate = kp.copy() items_candidate = items.copy() nextItem = SimpleHeuristic(nextHeuristic).apply( kp_candidate, items_candidate) if nextItem == None: # Heuristic does not change the instance countNone += 1 continue countNone = 0 if kp_best.getValue() < kp_candidate.getValue(): # Heuristic improve the performance of the solution kp_best = kp_candidate.copy() mh_best = mh.copy() mh_best.addHeuristic(nextHeuristic) # Calculate the metropolis variable diff = kp.getValue() - kp_candidate.getValue() t = temp / (i + 1) if -10 <= -diff / t and -diff / t <= 0: metropolis = np.exp(-diff / t) elif -diff / t <= -10: metropolis = 0 else: metropolis = 1 # Acceptance criteria if diff < 0 or np.random.rand() <= metropolis: kp = kp_candidate items = items_candidate mh.addHeuristic(nextHeuristic) else: countNone += 1 # Return the best solution reached return kp_best, mh_best
def ConstructiveSolution(kp: Knapsack, items: List[Item], itemSelector): # Find the first item to pack to the knapsack nextItem = itemSelector.nextItem(kp, items) while nextItem is not None: # Pack the items until no other item can be packed kp.pack(items[nextItem]) items.pop(nextItem) nextItem = itemSelector.nextItem(kp, items) # Return the solution reached return kp
def cleanHeuristics(self, W: int, items: List[Item]): # Only considered heuristics that changes the instance kp = Knapsack(W) mh = [] for heuristic in self.sequenceHeuristics: nextItem = SimpleHeuristic(heuristic).apply(kp, items) if nextItem != None: mh.append(heuristic) self.sequenceHeuristics = mh
def nextItem(self, kp: Knapsack, items: List[Item]): # Choice the next packable item if self.onKP: return None idx = None for i, item in enumerate(items): if kp.canPack(item): if idx == None or heuristicComparison[self.name](items[idx], item): idx = i return idx
def solveMetaheuristic(method: str, kp: Knapsack, items: List[Item], saveMetaheuristic=False, fileName='traindata.csv', overwrite=False): W = kp.getCapacity() items_copy = items.copy() # Execute the chosen method if method == 'SimulatedAnnealing': kp, mh = SimulatedAnnealing(kp, items) elif method == 'RandomSearch': kp, mh = RandomSearch(kp, items) else: return 0 # Save the sequence of heuristics if saveMetaheuristic: mh.saveMetaheuristic(W, items_copy, fileName, overwrite) return kp.getValue()
def kpMILP(W: int, items: List[Item]): # Prepare the solver solver = pywrapknapsack_solver.KnapsackSolver( pywrapknapsack_solver.KnapsackSolver. KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER, 'Knapsack BC-MILP') # Prepare the data profit = [item.getProfit() for item in items] weights = [[item.getWeight() for item in items]] capacities = [W] # Execute the solver solver.Init(profit, weights, capacities) solver.Solve() # Find the best solution kp = Knapsack(W) for i, item in enumerate(items): if solver.BestSolutionContains(i): kp.pack(item) return kp
def kpBacktracking(W: int, items: List[Item]): if items == [] or W == 0: return Knapsack(W) item = items[0] if item.getWeight() > W: # Not choice the item return kpBacktracking(items[1:], W) else: # Choice the item kpWithItem = kpBacktracking(items[1:], W - item.getWeight()) kpWithItem.capacity += item.getWeight() kpWithItem.pack(item) # Not choice the item kpWithoutItem = kpBacktracking(items[1:], W) # Decide best option if kpWithItem.getValue() < kpWithoutItem.getValue(): return kpWithoutItem else: return kpWithItem
def saveMetaheuristic(self, W: int, items: List[Item], fileName='traindata.csv', overwrite=False): # Save the sequence of heuristics in a CSV file labels = list(featuresCalculation.keys()) + ['NextHeuristic'] featureDataFrame = [] featureDict = dict() kp = Knapsack(W) for heuristic in self.sequenceHeuristics: # Obtain the characterization of the instance and store it values = getAllFeatures(items) + [heuristic] for name, value in zip(labels, values): featureDict[name] = value featureDataFrame.append(featureDict.copy()) SimpleHeuristic(heuristic).apply(kp, items) # Save the sequence of characterization in a CSV file saveDataCSV(fileName, featureDataFrame, labels, overwrite)
def generateTrainDataset(trainFilename='traindata.csv', overwrite=True, instances='Pisinger'): if type(instances) == str: # Obtain the instances to generate the train dataset of the LSTM model # If type(instances) != str, then instances is a list of strings with # the filenames considered to generate the train dataset instances = obtainFilenames(tapia_path, instances) # Per each instance, execute the Simulated Annealing metaheuristic and # save the sequence of heuristics generated for filePath in instances: _, W, weights, profits = loadInstance(filePath) kp = Knapsack(W) items = generateItemList(weights, profits) np.random.seed(0) solveMetaheuristic('SimulatedAnnealing', kp, items, saveMetaheuristic=True, fileName=trainFilename, overwrite=overwrite) overwrite = False
def kpDP(W: int, items: List[Item]): n = len(items) A = np.zeros((n + 1, W + 1)) # Calculate the DP in the bottom-up fashion way for idx, item in enumerate(items, start=1): w, p = item.getWeight(), item.getProfit() for Wi in range(W + 1): if Wi == 0: continue elif idx == 0: A[idx, Wi] = p if w <= Wi else 0 elif w <= Wi: A[idx, Wi] = max(A[idx - 1, Wi], A[idx - 1, Wi - w] + p) else: A[idx, Wi] = A[idx - 1, Wi] # Find the items that get the best solution kp, idx = Knapsack(W), n while idx >= 1 and kp.getCapacity() > 0: if A[idx - 1, kp.getCapacity()] != A[idx, kp.getCapacity()]: kp.pack(items[idx - 1]) idx -= 1 return kp
def solveInstance(self, W: int, items: List[Item]): # Apply the sequence of heuristics saved in the given instance kp = Knapsack(W) for heuristic in self.sequenceHeuristics: SimpleHeuristic(heuristic).apply(kp, items) return kp
# Prepare the dict to save the data resultsTestDict = dict() for method in methods: resultsTestDict[method] = [] resultsTestDict[f'{method}_time'] = [] # Obtain the path to each test instance instances = obtainFilenames(tapia_path, testDataset) for instance in instances: # Read the instance n, W, weights, profits = loadInstance(instance) for method, iterations in zip(methods, methodIterations): sumResults, sumTime = 0, 0 for i in range(iterations): kp = Knapsack(W) items = generateItemList(weights, profits) start = perf_counter() if method == 'Hyperheuristic': # Run the respective HH kp, mh = hyperheuristicSolverHH(kp, items, HH[i]) result = kp.getValue() else: # Run the respective solver method result = solver(method, kp, items) end = perf_counter() sumResults += result sumTime += end-start # Store the average results and average time per method