def repair_child_MOKP(self, optimization_problem, ideal_z, lambda_vector): prob_data = lp_parser(optimization_problem, verbose=False) n_constr = prob_data['n_constr'] constr_coeff = prob_data['constr_coeff'] constr_RHS = prob_data['constr_coeff'] constr_sense = prob_data['constr_sense'] J = [j for j in range(self.n_dim) if self.x[0, j] == 1] I = [ i for i in range(n_constr) if np.dot(constr_coeff[i, :], self.x[0]) > constr_RHS[i, 0] ] Qstar = np.inf for j in J: x_j_minus = self x_j_minus.x[0, j] = 0 # not 1 x_j_minus.objective_val = x_j_minus.evaluate_solution( optimization_problem) # print(sum(constr_coeff[i,j] for i in I)) Q = (-utils.g_te(self, lambda_vector, ideal_z) + utils.g_te( x_j_minus, lambda_vector, ideal_z)) / sum(constr_coeff[i, j] for i in I) # print Q if Qstar > Q: Qstar = Q kmin = j x_j_greedy = self x_j_greedy.x[0, kmin] = 0 return x_j_greedy
def evaluate_solution(self, optimization_problem): """ Evaluate a solution x to get a list of objective values. :param optimization_problem: For now, only evaluates ZDT1 """ if optimization_problem == 'ZDT1': n = len(self.x) if not n == 30: raise ValueError( 'The solution needs to have dim 30 for the ZDT1 test instance.' ) f1 = self.x[0] g = 1 + 9 * (sum(self.x[j] for j in range(1, n))) / (n - 1) f2 = g * (1 - np.sqrt(f1 / g)) return [f1, f2] else: prob_data = lp_parser(optimization_problem, verbose=False) objective_coefficients = prob_data['obj_coeff'] f = np.zeros([1, prob_data['n_obj']]) for o in range(prob_data['n_obj']): f[0, o] = np.dot(objective_coefficients[o, :], self.x[0]) return f[0]
def check_feasible(self, optimization_problem): """ Check that a solution x satisfies constraints in the optimization_problem. :param optimization_problem: For now, only evaluates ZDT1 """ any_constraint_violated = False solution_feasible = True if optimization_problem == 'ZDT1': for i in range(self.n_dim): if self.x[0, i] > 1 or self.x[i] < 0: any_constraint_violated = True break else: prob_data = lp_parser(optimization_problem, verbose=False) constr_coeff = prob_data['constr_coeff'] constr_RHS = prob_data['constr_RHS'] constr_sense = prob_data['constr_sense'] lb = prob_data['lb'] ub = prob_data['ub'] v_type = prob_data['vartype'] # First, check that all variables within bounds for i in range(len(self.x)): if self.x[0, i] > ub[i, 0] or self.x[0, i] < lb[i, 0]: any_constraint_violated = True break # Next, check that Ax {<=, >=, ==} b for c in range(prob_data['n_constr']): Ax = np.dot(constr_coeff[c, :], self.x[0]) if constr_sense[c] == '<' and Ax > constr_RHS[c, 0]: any_constraint_violated = True break elif constr_sense[c] == '>' and Ax < constr_RHS[c, 0]: any_constraint_violated = True break elif constr_sense[c] == '=' and Ax != constr_RHS[c, 0]: any_constraint_violated = True raise ValueError( 'Equality constraint violated. Need to implement a sensible fix for this case.' ) break # Finally, check if the variable types are correct for i in range(len(self.x)): if v_type[i] == 'B' and not (self.x[0, i] in [ 0, 1, float(0), float(1) ]): any_constraint_violated = True break if any_constraint_violated: solution_feasible = False else: solution_feasible = True return solution_feasible
def __init__(self, subproblem, optimization_problem): """ Construct a new 'Solution' instance by random generation. :param n_dim: The number of dimensions the solution has. :param v_type: The numeric type of each dimension. :param subproblem: The subproblem number to which it is a solution. """ super(Solution, self).__init__() self.generation = 1 self.subproblem = subproblem if optimization_problem == 'ZDT1': self.n_dim = 30 lb = [0] * self.n_dim ub = [1] * self.n_dim self.x = np.random.uniform(size=(1, self.n_dim)) self.feasible = self.check_feasible( optimization_problem ) # should be no need to repair ZDT1 with random.uniform since x\in[0,1] is the only constraint if not self.feasible: raise ValueError( 'The initialized solution to ZDT1 is not feasible.') self.objective_val = self.evaluate_solution(optimization_problem) self.v_type = ['C'] * self.n_dim else: prob_data = lp_parser(optimization_problem, verbose=False) self.n_dim = prob_data['n_dvars'] lb = prob_data['lb'] ub = prob_data['ub'] self.v_type = prob_data['vartype'] self.x = np.zeros([1, self.n_dim]) self.feasible = False # generate a random solution for i in range(self.n_dim): if self.v_type[i] == 'C': # continuous self.x[0, i] = np.random.uniform(low=lb[i, 0], high=ub[i, 0]) elif self.v_type[i] == 'B': # binary self.x[0, i] = np.random.randint(low=0, high=2) else: raise ValueError( 'Need to check that vartype is integer and not binary') self.x[0, i] = np.random.randint(low=lb[i, 0], high=ub[i, 0] + 1) # check constraint feasibility self.feasible = self.check_feasible(optimization_problem) # repair if necessary while not self.feasible: self.repair_step(optimization_problem) self.feasible = self.check_feasible(optimization_problem) self.objective_val = self.evaluate_solution(optimization_problem)
def repair_step(self, optimization_problem): prob_data = lp_parser(optimization_problem, verbose=False) constr_coeff = prob_data['constr_coeff'] constr_RHS = prob_data['constr_coeff'] constr_sense = prob_data['constr_sense'] lb = prob_data['lb'] ub = prob_data['ub'] v_type = prob_data['vartype'] # Repair bound violations for i in range(len(self.x)): if self.x[0, i] > ub[i, 0] or self.x[0, i] < lb[i, 0]: # print('BOUND VIOLATION FOUND') if v_type[i] == 'C': self.x[0, i] = np.random.uniform(low=lb[i, 0], high=ub[i, 0]) if self.check_feasible(optimization_problem): return self # Repair constraint violations for c in range(prob_data['n_constr']): Ax = np.dot(constr_coeff[c, :], self.x[0]) if constr_sense[c] == '<' and Ax > constr_RHS[c, 0]: # randomly select a variable in this constraint expression and decrease/flip bit to 0 nonzero_coeffs = [ i for i, e in enumerate(constr_coeff[c, :]) if e != 0 ] change_idx = np.random.choice(nonzero_coeffs) if v_type[change_idx] == 'B': self.x[0, change_idx] = 0 elif v_type[change_idx] == 'C': self.x[0, change_idx] -= np.random.uniform( low=0, high=(self.x[0, change_idx] - lb[change_idx])) elif constr_sense[c] == '>' and Ax < constr_RHS[c, 0]: # randomly select a variable in this constraint expression and increase/flip bit to 1 nonzero_coeffs = [ i for i, e in enumerate(constr_coeff[c, :]) if e != 0 ] change_idx = np.random.choice(nonzero_coeffs) if v_type[change_idx] == 'B': self.x[0, change_idx] = 1 elif v_type[change_idx] == 'C': self.x[0, change_idx] += np.random.uniform( low=0, high=(ub[change_idx] - self.x[0, change_idx])) elif constr_sense[c] == '=' and Ax != constr_RHS[c]: raise ValueError( 'Equality constraint violated. Need to implement a sensible fix for this case.' ) return self
########## MOEA/D + RUNTIME PARAMETERS ########## T = 10 # number of neighbors H = 125 MAXGEN = 20 VERBOSE = True opt_prob_dir = 'problem_instances/0-1_knapsack/BOKP_lp_format_instances/' opt_prob_instance = 'kp_20_1'#['kp_20_1', 'kp_80_10'] opt_prob = opt_prob_dir+opt_prob_instance+'.lp' ################ INITIALIZATION ################ EP_history = dict() n_nondom_pts_history = dict() # get optimization problem data prob_data = lp_parser(opt_prob, verbose=False) n_dvars = prob_data['n_dvars'] n_obj = prob_data['n_obj'] n_constr = prob_data['n_constr'] # initialize moea-d subproblems lam = generate_lambda_vectors(n_obj, H = H) N = len(lam) # number of subproblems B = get_lambda_neighborhoods(lam) subproblem_list = [] for i in range(N): temp_sol = solution.Solution(i, opt_prob) while not temp_sol.feasible: temp_sol = solution.Solution(i, opt_prob) temp_sub = SubProblem(i,lam[i,:],B[i,:], temp_sol) subproblem_list.append(temp_sub)