def set_mip_parameters(self, param = None): """ updates MIP parameters :param param: :return: """ if param is None: param = self._cpx_parameters self._mip = set_cpx_parameters(self._mip, param)
def build_mip(self): """ returns an optimization problem that can be solved to determine an item in a flipset for x :return: """ # MIP parameters cost_type = self.mip_cost_type min_items = max(self.min_items, 1) max_items = self.max_items # cost/action information build_info, indices = self._get_mip_build_info() ## TODO: note: if actiongrid is empty, build_info, indices == {}. Correct handling? # initialize mip mip = Cplex() mip.set_problem_type(mip.problem_type.MILP) vars = mip.variables cons = mip.linear_constraints n_actionable = len(build_info) n_indicators = len(indices['action_ind_names']) # define a[j] vars.add(names = indices['action_var_names'], types = ['C'] * n_actionable, lb = indices['action_lb'], ub = indices['action_ub']) # sum_j w[j] a[j] > -score cons.add(names = ['score'], lin_expr = [SparsePair(ind = indices['action_var_names'], val = indices['coefficients'])], senses = ['G'], rhs = [-self.score()]) # define indicators u[j][k] = 1 if a[j] = actions[j][k] vars.add(names = indices['action_ind_names'], types = ['B'] * n_indicators) # restrict a[j] to feasible values using a 1 of K constraint setup for info in build_info.values(): # restrict a[j] to actions in feasible set and make sure exactly 1 indicator u[j][k] is on # 1. a[j] = sum_k u[j][k] * actions[j][k] - > 0.0 = sum u[j][k] * actions[j][k] - a[j] # 2.sum_k u[j][k] = 1.0 cons.add(names = ['set_a[%d]' % info['idx'], 'pick_a[%d]' % info['idx']], lin_expr = [SparsePair(ind = info['action_var_name'] + info['action_ind_names'], val = [-1.0] + info['actions']), SparsePair(ind = info['action_ind_names'], val = [1.0] * len(info['actions']))], senses = ["E", "E"], rhs = [0.0, 1.0]) # declare indicator variables as SOS set mip.SOS.add(type = "1", name = "sos_u[%d]" % info['idx'], SOS = SparsePair(ind = info['action_ind_names'], val = info['actions'])) # limit number of features per action # # size := n_actionable - n_null where n_null := sum_j u[j][0] = sum_j 1[a[j] = 0] # # size <= max_size # n_actionable - sum_j u[j][0] <= max_size # n_actionable - max_size <= sum_j u[j][0] # # min_size <= size: # min_size <= n_actionable - sum_j u[j][0] # sum_j u[j][0] <= n_actionable - min_size size_expr = SparsePair(ind = indices['action_off_names'], val = [1.0] * n_actionable) cons.add(names = ['max_items', 'min_items'], lin_expr = [size_expr, size_expr], senses = ['G', 'L'], rhs = [float(n_actionable - max_items), float(n_actionable - min_items)]) # add constraints for cost function if cost_type in ('total', 'local'): indices.pop('cost_var_names') objval_pairs = list(chain(*[list(zip(v['action_ind_names'], v['costs'])) for v in build_info.values()])) mip.objective.set_linear(objval_pairs) elif cost_type == 'max': indices['max_cost_var_name'] = ['max_cost'] ## handle empty actionsets indices['epsilon'] = np.min(indices['cost_df'] or np.inf) / np.sum(indices['cost_ub']) vars.add(names = indices['max_cost_var_name'] + indices['cost_var_names'], types = ['C'] * (n_actionable + 1), obj = [1.0] + [indices['epsilon']] * n_actionable) #lb = [0.0] * (n_actionable + 1)) # default values are 0.0 cost_constraints = { 'names': [], 'lin_expr': [], 'senses': ["E", "G"] * n_actionable, 'rhs': [0.0, 0.0] * n_actionable, } for info in build_info.values(): cost_constraints['names'].extend([ 'def_cost[%d]' % info['idx'], 'set_max_cost[%d]' % info['idx'] ]) cost_constraints['lin_expr'].extend([ SparsePair(ind = info['cost_var_name'] + info['action_ind_names'], val = [-1.0] + info['costs']), SparsePair(ind = indices['max_cost_var_name'] + info['cost_var_name'], val = [1.0, -1.0]) ]) cons.add(**cost_constraints) # old code (commented out for speed) # # vars.add(names = indices['cost_var_names'], # types = ['C'] * n_actionable, # obj = [indices['epsilon']] * n_actionable, # #ub = [CPX_INFINITY] * n_actionable, #indices['cost_ub'], #indices['cost_ub'], # lb = [0.0] * n_actionable) # # vars.add(names = indices['max_cost_var_name'], # types = ['C'], # obj = [1.0], # #ub = [np.max(indices['cost_ub'])], # lb = [0.0]) # # for info in build_info.values(): # cost[j] = sum c[j][k] u[j][k] # cons.add(names = ['def_cost[%d]' % info['idx']], # lin_expr = [SparsePair(ind = info['cost_var_name'] + info['action_ind_names'], val = [-1.0] + info['costs'])] # senses = ["E"], # rhs = [0.0]) # # max_cost > cost[j] # cons.add(names = ['set_max_cost[%d]' % info['idx']], # lin_expr = [SparsePair(ind = indices['max_cost_var_name'] + info['cost_var_name'], val = [1.0, -1.0])], # senses = ["G"], # rhs = [0.0]) mip = set_cpx_parameters(mip, self._cpx_parameters) self._mip = mip self._mip_indices = indices