def update_after_destroy_and_repair_performed(self, destroy: Method, repair: Method, sol_new: Solution, sol_incumbent: Solution, sol: Solution): """Update current solution, incumbent, and all operator score data according to performed destroy+repair. :param destroy: applied destroy method :param repair: applied repair method :param sol_new: obtained new solution :param sol_incumbent: current incumbent solution :param sol: current (last accepted) solution """ destroy_data = self.score_data[destroy.name] repair_data = self.score_data[repair.name] destroy_data.applied += 1 repair_data.applied += 1 score = 0 if sol_new.is_better(sol_incumbent): score = self.own_settings.mh_alns_sigma1 # print('better than incumbent') sol_incumbent.copy_from(sol_new) sol.copy_from(sol_new) elif sol_new.is_better(sol): score = self.own_settings.mh_alns_sigma2 # print('better than current') sol.copy_from(sol_new) elif sol.is_better(sol_new) and self.metropolis_criterion(sol_new, sol): score = self.own_settings.mh_alns_sigma3 # print('accepted although worse') sol.copy_from(sol_new) elif sol_new != sol: sol_new.copy_from(sol) destroy_data.score += score repair_data.score += score
def metropolis_criterion(self, sol_new: Solution, sol_current: Solution) -> bool: """Apply Metropolis criterion as acceptance decision, return True when sol_new should be accepted.""" if sol_new.is_better(sol_current): return True return np.random.random_sample() <= exp( -abs(sol_new.obj() - sol_current.obj()) / self.temperature)