def createConstraints(self): for i in range(len(self.shape_verts)): for vid in self.shape_verts[i]: self.m.addConstr(self.diff_x[vid] == self.px[vid] - self.vert_locs[vid][0]) self.m.addConstr(self.diff_y[vid] == self.py[vid] - self.vert_locs[vid][1]) self.m.addConstr(self.abs_diff_x[vid] == gp.abs_(self.diff_x[vid])) self.m.addConstr(self.abs_diff_y[vid] == gp.abs_(self.diff_y[vid])) for i in range(len(pair_rels)): p_rel = pair_rels[i] segs = [[p_rel[0], p_rel[1]], [p_rel[2], p_rel[3]]] for se in range(2): # (x, y) -> (x, y) if p_rel[4] == 0: self.m.addConstr(self.px[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(self.py[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) # (x, y) -> (-y, x) elif p_rel[4] == 1: self.m.addConstr(-self.py[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(self.px[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) # (x, y) -> (y, -x) elif p_rel[4] == 2: self.m.addConstr(self.py[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(-self.px[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) # (x, y) -> (x, y) elif p_rel[4] == 3: self.m.addConstr(-self.px[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(-self.py[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i])
def get_grb_vars(self, grb_model, x_batches, y_batches): domains = self.get_domains(x_batches, y_batches)[0] x_inp = domains.get_grb_vars(grb_model) grb_model.update() data_orig = x_batches[0] att_orig = data_orig[0, self.att_col_idx].item() att_adv = x_inp[self.att_col_idx] att_diff = grb_model.addVar(-GRB.INFINITY, GRB.INFINITY) grb_model.addConstr(att_diff == (att_orig - att_adv)) abs_att_diff = grb_model.addVar(0, GRB.INFINITY) grb_model.addConstr(att_diff == abs_(abs_att_diff)) f1 = grb_model.addVar(vtype=GRB.BINARY) f2 = grb_model.addVar(vtype=GRB.BINARY) if att_orig <= self.norm_threshold: grb_model.addConstr(f1 == and_([ self.lt_ineq(att_adv, self.norm_threshold, grb_model), self.lt_ineq(abs_att_diff, self.below_epsilon, grb_model), ])) if att_orig > self.norm_threshold: grb_model.addConstr(f2 == and_([ self.lt_ineq(att_adv, self.norm_threshold, grb_model), self.lt_ineq(abs_att_diff, self.above_epsilon, grb_model), ])) pre_condition = grb_model.addVar(vtype=GRB.BINARY) grb_model.addConstr(pre_condition == or_([f1, f2])) grb_model.addConstr(pre_condition == 1) return x_inp
def addConstraints(self): cnt = 0 for key in self.angle_diffs_dic: self.m.addConstr( self.diff[cnt] == self.a[key[0]] + self.k[cnt] * 360 - self.a[key[1]] - self.angle_diffs_dic[key]) cnt += 1 for i in range(len(self.angle_diffs_dic)): self.m.addConstr(self.abs_diff[i] == gp.abs_(self.diff[i])) for key in self.angle_diffs_constr_dic: self.m.addConstr( self.a[key[0]] + self.k[cnt] * 360 - self.a[key[1]], GRB.EQUAL, self.angle_diffs_constr_dic[key]) cnt += 1
def addConstraints(self): cnt = 0 d_cnt = 0 for key in self.angle_diffs_constr_dic: shape_id_0 = self.getShapeId(key[0]) shape_id_1 = self.getShapeId(key[1]) self.m.addConstr(self.diff[cnt] == self.a[shape_id_0] + self.angles[key[0]] - self.a[shape_id_1] - self.angles[key[1]] - self.d[d_cnt] * 90) self.m.addConstr(self.abs_diff[cnt] == gp.abs_(self.diff[cnt])) cnt += 1 d_cnt += 1
def min_gamma(dist, c_nr): # Get the number of timesteps and clusters from distance vector k_nr = dist.shape[0] time_nr = dist.shape[1] # Set the model mod = grb.Model('MinGamma') # Create variables for the weights by their cluster and time weights = [(k, t) for k in range(k_nr) for t in range(time_nr)] gam = mod.addVars(weights, lb=0, ub=1, name="gam") # Create additional variables needed for the absolute value constraints additional = [(k, t) for k in range(k_nr) for t in range(time_nr - 1)] y1var = mod.addVars(additional, lb=-1, ub=1, name="y1var") y2var = mod.addVars(additional, lb=0, ub=1, name="y2var") # Set the objective function to minimize mod.setObjective( sum( dist[k,t]*gam[k,t] for k in range(k_nr) \ for t in range(time_nr) ), sense=grb.GRB.MINIMIZE ) # Add the normalization and persistence constraints mod.addConstrs( (sum(gam[k,t] for k in range(k_nr)) == 1 for t in range(time_nr)), \ name = "normalization" ) mod.addConstrs( ( y1var[k,t] == gam[k,t+1] - gam[k,t] \ for k in range(k_nr) for t in range(time_nr-1) ), \ name = "abs_y1" ) mod.addConstrs( ( y2var[k,t] == grb.abs_(y1var[k,t]) \ for k in range(k_nr) for t in range(time_nr-1) ), \ name = "abs_y2" ) mod.addConstr( (sum( y2var[k,t] for t in range(time_nr-1) \ for k in range(k_nr) ) <= c_nr ), name = "persistence") # Prevent output of optimization mod.setParam("TuneOutput", 0) # Compute optimal solution mod.optimize() # Get the solution for gamma if mod.status == grb.GRB.Status.OPTIMAL: solution = mod.getAttr('x', gam) gam_new = np.zeros((k_nr, time_nr)) for k in range(k_nr): for t in range(time_nr): gam_new[k, t] = solution[(k, t)] else: print("Optimization failed") return gam_new
def sample_solutions(model, variables, num_samples=INF, norm=2, closest=True): from gurobipy import GRB, quicksum, abs_ start_time = time.time() objective = model.getObjective() #sprint(objective, objective.getValue()) # model = model.feasibility() # model.setObjective(0.0) if norm == 2: model.setParam(GRB.Param.NonConvex, 2) # PSDTol objective_terms = [] if closest: min_distance = model.addVar(lb=0., ub=GRB.INFINITY) objective_terms.append(min_distance) solutions = [] # TODO: sample initial solution from this set while len(solutions) < num_samples: terms = [] for var in variables: for index, coord in enumerate(var): value = coord.X set_guess(coord, value, hard=True) delta = model.addVar(lb=-GRB.INFINITY, ub=GRB.INFINITY) model.addConstr(delta == coord - value) if norm == 1: term = model.addVar(lb=0., ub=GRB.INFINITY) model.addConstr(term == abs_(delta)) elif norm == 2: term = delta * delta else: raise NotImplementedError(norm) terms.append(term) # TODO: scale distance = quicksum(terms) if closest: model.addConstr(min_distance <= distance) else: objective_terms.append(distance) # TODO: weight model.setObjective(quicksum(objective_terms), sense=GRB.MAXIMIZE) # MINIMIZE | MAXIMIZE model.optimize() print( '# {} | objective: {:.3f} | cost: {:.3f} | runtime: {:.3f}'.format( len(solutions), model.ObjVal, objective.getValue(), elapsed_time(start_time))) # min_distance.X solution = [value_from_var(var) for var in variables] solutions.append(solution) yield solution
def to_gurobi(self, model): c_name = 'Abs_{n}_{layer}_{row}'.format(n=self.net, layer=self.layer, row=self.row) ret_constr = None if self.input.getLo() >= 0: # input is positive ret_constr = model.addConstr( self.output.to_gurobi(model) == self.input.to_gurobi(model), name=c_name) elif self.input.getHi() <= 0: # inputs is negative ret_constr = model.addConstr( self.output.to_gurobi(model) == -self.input.to_gurobi(model), name=c_name) elif fc.use_grb_native: ret_constr = model.addConstr( self.output.to_gurobi(model) == grb.abs_( self.input.to_gurobi(model)), name=c_name) else: out_bound = max(abs(self.input.getLo()), abs(self.input.getHi())) bigM1 = out_bound + self.input.getHi() bigM2 = out_bound - self.input.getLo() model.addConstr( self.output.to_gurobi(model) >= -self.input.to_gurobi(model), name=c_name + '_a') model.addConstr( self.output.to_gurobi(model) >= self.input.to_gurobi(model), name=c_name + '_b') model.addConstr( self.output.to_gurobi(model) <= -self.input.to_gurobi(model) + self.delta.to_gurobi(model) * bigM1, name=c_name + '_c') ret_constr = model.addConstr( self.output.to_gurobi(model) <= self.input.to_gurobi(model) + (1 - self.delta.to_gurobi(model)) * bigM2, name=c_name + '_c') return ret_constr
def baseline2_gurobi(A, k, r): ''' Not supported by Gurobi now max Tr(AP) s.t. P,I-P are PSD Tr(P) = r 1^T|P|1 <= rk #input A: sample covariance matrix r: # of eigenvalues k: sparsity parameter #output Objective value ''' d = A.shape[0] bl2 = gp.Model() # P P = [] for i in range(d): P.append( bl2.addVars(d, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="P")) # Px = lambda x with lambda >= 0 x = [] Lambda = [] for i in range(d): x.append( bl2.addVars(d, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x")) Lambda.append( bl2.addVars(1, lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x")) for i in range(d): for j in range(i + 1, d): bl2.addConstr(Lambda[i] != Lambda[j]) Ax = [] for i in range(d): Ax.append( bl2.addVars(d, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="P")) for k in range(d): for i in range(d): bl2.addConstr(sum(x[k][j] * P[i][j] for j in range(d)) == Ax[k][i]) bl2.addConstr(Lambda[k] * x[k][j] == Ax[k][i]) # I-P I_P = [] for i in range(d): I_P.append( bl2.addVars(d, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="I_P")) for i in range(d): for j in range(d): if i == j: bl2.addConstr(I_P[i][j] == 1 - P[i][j]) else: bl2.addConstr(I_P[i][j] == -P[i][j]) # (I-P)x = lambda x with lambda >= 0 xI = [] LambdaI = [] for i in range(d): xI.append( bl2.addVars(d, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x")) LambdaI.append( bl2.addVars(1, lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x")) for i in range(d): for j in range(i + 1, d): bl2.addConstr(LambdaI[i] != LambdaI[j]) AxI = [] for i in range(d): AxI.append( bl2.addVars(d, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="P")) for k in range(d): for i in range(d): bl2.addConstr( sum(xI[k][j] * I_P[i][j] for j in range(d)) == AxI[k][i]) bl2.addConstr(LambdaI[k] * xI[k][j] == AxI[k][i]) # Tr(p) = r bl2.addConstr(sum(P[i][i] for i in range(d)) == r) # 1 |P| 1 <= rk absP = [] for i in range(d): absP.append( bl2.addVars(d, lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="absP")) for j in range(d): for i in range(d): bl2.addConstr(absP[j][i] == gp.abs_(P[j][i])) bl2.addConstr( sum(sum(absP[j][i] for i in range(d)) for j in range(d)) <= r * k) # Tr(AP) obj = sum(sum(A[i][j] * P[j][i] for j in range(d)) for i in range(d)) bl2.setObjective(obj, GRB.MAXIMIZE) bl2.params.NonConvex = 2 bl2.optimize()
import gurobipy as grb m = grb.Model() x = m.addVar(lb=-10, name='x') y = m.addVar(name='y') m.addConstr(y == grb.abs_(x), name='C_abs') m.addConstr(x >= -5, name='C_2') m.addConstr(x <= 3, name='C3') c = 2 m.setObjective(c * y) m.optimize() print("y=", y.X) print('x=', x.X)
def furthest_from_hull(self, qhull, var_limits, facet_eq, write: bool = False, write_file: str = "pw.lp"): """ The method should find the possible world satisfying the formulas furthest from the convex hull. Dtance from a point to the polytope is approximated as :param qhull: :param var_limits: :param write: :param write_file: :return: """ # create ILP # returns satisfiability + point + objective mod = g.Model() # find all atoms in CNFs # create opt. variable for all possible assignments of constants to variables for each atom... opt_variable_mapping = {} # key (predicate, [domain elements]) greatest_distance = mod.addVar(lb=0.0, name="maxDist") tar_vars = [] a_count = 0 d_count = 0 grand_d = [] grand_a = [] for i, wf in enumerate(self.formulas): # Right now - every formula contains one clause cnf = wf.formula distinct_vars = cnf.get_distinct_vars() tar_var = mod.addVar(lb=0, ub=var_limits[i], vtype=g.GRB.INTEGER, name=f"Xf_{i}") tar_vars.append(tar_var) ds = [] # print(cnf) assignment_generator = itt.permutations(self.domain, len(distinct_vars)) if self.reflexive: assignment_generator = itt.product(self.domain, repeat=len(distinct_vars)) for assignment in assignment_generator: assgnmt_dir = {a: b for a, b in zip(distinct_vars, assignment)} # D indicates that whole formula is satisfied in current assignment # D = {min A} (see below) D = mod.addVar(lb=0.0, ub=1.0, name="D_{}".format(d_count)) grand_d.append(D) d_count += 1 ds.append(D) avars = [] # print("Start") for clause in cnf.clauses: # A indicates that a clause is satisfied in current assignment # A = max{variables for each literal} A = mod.addVar(lb=0.0, ub=1.0, name="A_{}".format(a_count)) avars.append(A) grand_a.append(A) a_count += 1 cl_literals = [] for literal in clause.literals: pos_code = literal.atom.assignment_name(assgnmt_dir) neg_code = f"~{pos_code}" a_code = pos_code if literal.positive else neg_code if a_code in opt_variable_mapping: opt_var = opt_variable_mapping[a_code] # print("Found") else: p_var = mod.addVar(vtype=g.GRB.BINARY, name=pos_code) n_var = mod.addVar(vtype=g.GRB.BINARY, name=neg_code) mod.addConstr(1 - p_var == n_var) opt_variable_mapping[pos_code] = p_var opt_variable_mapping[neg_code] = n_var opt_var = p_var if literal.positive else n_var # print("Not found") cl_literals.append(opt_var) mod.addGenConstrMax(A, cl_literals, 0.0) mod.addGenConstrMin(D, avars, 1.0) mod.addConstr(g.quicksum(ds) == tar_var) poly_lines, columns = qhull.equations.shape dist_vars = [] indicators = [] # Selected inequality must not hold #for ix in range(poly_lines): # Use inequality for chosen edge # qhull uses Ax + b < 0 line = facet_eq[0:columns-1] b = facet_eq[columns-1] mod.addConstr(g.quicksum([w * v for w, v in zip(line, tar_vars)]) + b >= 0) # TODO >= 1 but we need to rescale b # inside polytope is <= # Find max L2 distance dst = mod.addVar(name="pd") mod.addConstr(g.quicksum([w * v for w, v in zip(line, tar_vars)]) + b == dst) mod.addConstr(greatest_distance == g.abs_(dst)) mod.setObjective(greatest_distance, g.GRB.MAXIMIZE) if write: mod.write(write_file) mod.optimize() if mod.status == g.GRB.OPTIMAL: # TODO not in INFEASIBLE, UNBOUNDED, print(mod.status) print("Found optimal solution") # if len(self.domain) < 7: # for v in opt_variable_mapping.values(): # print(v.x, v.varname) # for v in grand_d: # print(v.x, v.varname) # for v in grand_a: # print(v.x, v.varname) else: print("Constraints are INFEASIBLE") print("inf or unb", g.GRB.INF_OR_UNBD == mod.status) print("unb", g.GRB.UNBOUNDED == mod.status) print("infis", g.GRB.INFEASIBLE == mod.status) out_list = [] if mod.status != g.GRB.OPTIMAL else [v.x for v in tar_vars] gdx = greatest_distance.x if mod.status == g.GRB.OPTIMAL else -1 return mod.status == g.GRB.OPTIMAL, out_list, gdx
def create_ilp_formulation_for_ddp(config, ilp_type='improved'): try: start_time = datetime.datetime.now() model = gurobipy.Model(config.name_model) logger.info("Creating completion variables.") logger.info("Defining R completion.") hat_rs = define_matching_vars(model=model, edge_set=general_allowable_set(config.ind_cbg_compl_R), edge_conditions=general_conditional_set(config.ind_cbg_compl_R), vertex_set=[], vertex_conditions={x: False for x in config.ind_cbg_compl_R}) logger.info("Defining genome X.") xes, indexing_set = define_guided_matching_using_graph(model=model, edge_conditions={**{edge: False for edge in config.ind_cbg_R_edges}, **{pair: True for pair in general_allowable_set( config.ind_cbg_compl_R)}}, equiv_map=config.equiv_map, edge_variables=hat_rs) logger.info("Creating connectivity variables and constraints.") aes, tilde_as = create_connectivity_variables(model=model, vertex_set=config.bg_vertex2ind.values()) add_certain_connectivity_constraints(model=model, edges=config.ind_bg_A_edges, connect_vars=aes) if ilp_type == 'basic': logger.info("Defining A completion.") hat_as = define_matching_vars(model=model, edge_set=general_allowable_set(config.ind_compl_A), edge_conditions=general_conditional_set(config.ind_compl_A), vertex_set=[], vertex_conditions={x: False for x in config.ind_compl_A}) add_uncertain_connectivity_constraints(model=model, edge_set=indexing_set, edge_vars=xes, connect_vars=aes, biggest_const=config.biggest_const) add_uncertain_connectivity_constraints(model=model, edge_set=general_allowable_set(config.ind_compl_A), edge_vars=hat_as, connect_vars=aes, biggest_const=config.biggest_const) logger.info("Creating telomeric variables and constraints.") dot_as = create_vars_count_odd_paths(model=model, telomeric_vertices=config.ind_bg_A_telomers, connect_vars=aes, biggest_const=config.biggest_const) logger.info("CREATING OBJECTIVE FUNCTION.") model.setObjective(tilde_as.sum('*') - dot_as.sum('*'), gurobipy.GRB.MAXIMIZE) elif ilp_type == 'improved': set_pairs_for_paths = general_allowable_set(config.ind_forth_type_telomers) | \ product_set(config.ind_second_type_telomers, config.ind_third_type_telomers) | \ product_set(config.ind_second_type_telomers, config.ind_forth_type_telomers) logger.info("Creating variables for counting paths.") hat_cs = create_path_variables(model=model, pairs_set=set_pairs_for_paths) add_uncertain_connectivity_constraints_a(model=model, edge_set=indexing_set, edge_vars=xes, connect_vars=aes, biggest_const=config.biggest_const) add_uncertain_connectivity_constraints_c(model=model, edge_set=set_pairs_for_paths, edge_vars=hat_cs, connect_vars=aes, biggest_const=config.biggest_const) p44 = create_helping_path_variables(model=model, connect_vars=hat_cs, pair_set=general_allowable_set(config.ind_forth_type_telomers), biggest_const=config.biggest_const) p23 = create_helping_path_variables(model=model, connect_vars=hat_cs, pair_set=product_set(config.ind_second_type_telomers, config.ind_third_type_telomers), biggest_const=config.biggest_const) p24 = create_helping_path_variables(model=model, connect_vars=hat_cs, pair_set=product_set(config.ind_second_type_telomers, config.ind_forth_type_telomers), biggest_const=config.biggest_const) c1 = len(config.ind_first_type_telomers) # create_objective logger.info("CREATING OBJECTIVE FUNCTION.") tmp = model.addVar(lb=-config.biggest_const, ub=config.biggest_const, vtype=gurobipy.GRB.INTEGER, name="tmp") model.addConstr(tmp == p24 - c1 - p23) abs_var = model.addVar(ub=config.biggest_const, vtype=gurobipy.GRB.INTEGER, name="abs_tmp") model.addConstr(abs_var == gurobipy.abs_(tmp)) model.setObjective(tilde_as.sum('*') - p44 - 1 / 4 * (c1 + p23 + 3 * p24 + abs_var), gurobipy.GRB.MAXIMIZE) else: logger.error('Error: Unknown type. Use "basic" or "improved"') return None logger.info("FINISH CREATE MODEL.") model.params.logFile = config.log_file model.params.MIPFocus = 2 model.params.timeLimit = config.time_limit model.optimize() logger.info("The number of cycles and paths is " + str(int(model.objVal))) print("The number of cycles and paths is " + str(int(model.objVal))) answer = get_param_of_solution_for_double_distance(model=model, multiplicity=config.multiplicity, number_of_genes=len(config.s_all_genes), number_of_R_telomers=len(config.ind_cbg_R_telomers), working_time=datetime.datetime.now() - start_time) return answer except gurobipy.GurobiError as e: logger.error( "Some error has been raised. Please, report to github bug tracker. \n Text exception: {0}".format(e)) return None
def get_layer_bound_LP(Ws,bs,UBs,LBs,x0,eps,p,neuron_states,nlayer,pred_label,target_label,compute_full_bounds=False,untargeted=False): import gurobipy as grb # storing upper and lower bounds for last layer UB = np.empty_like(bs[-1]) LB = np.empty_like(bs[-1]) # neuron_state is an array: neurons never activated set to -1, neurons always activated set to +1, indefinite set to 0 # indices alphas = [] # for n layer network, we have n-1 layers of relu for i in range(nlayer-1): idx_unsure = (neuron_states[i] == 0).nonzero()[0] # neuron_state is an integer array for efficiency reasons. We should convert it to float alpha = neuron_states[i].astype(np.float32) alpha[idx_unsure] = UBs[i+1][idx_unsure]/(UBs[i+1][idx_unsure]-LBs[i+1][idx_unsure]) alphas.append(alpha) start = time.time() m = grb.Model("LP") m.setParam("outputflag",0) # disable parallel Gurobi solver, using 1 thread only m.setParam("Method",1) # dual simplex m.setParam("Threads", 1) # only 1 thread # z and zh are list of lists, each list for one layer of variables # z starts from 1, matching Zico's notation z = [] z.append(None) # z hat starts from 2 zh = [] zh.append(None) zh.append(None) if p == "2" or p == "1": # ztrans (transformation of z1 only for lp norm), starts from 1 matching z ztrans = [] ztrans.append(None) ## LP codes: # we start our label from 1 to nlayer+1 (the last one is the final objective layer) # valid range for z: 1 to nlayer (z_1 is just input, z_{nlayer} is the last relu layer output) # valid range for z_hat: 2 to nlayer+1 (there is no z_hat_1 as it is the input, z_{nlayer+1} is final output) for i in range(1,nlayer+2): if i == 1: # first layer # first layer, only z exists, no z hat zzs = [] zzts = [] # UBs[0] is for input x. Create a variable for each input # and set its lower and upper bounds for j in range(1,len(UBs[0])+1): zij = m.addVar(vtype=grb.GRB.CONTINUOUS, lb=LBs[0][j-1], ub=UBs[0][j-1], name="z_"+str(i)+"_"+str(j)) zzs.append(zij) if p == "2" or p == "1": # transformation variable at z1 only if p == "2": ztij = m.addVar(vtype=grb.GRB.CONTINUOUS, name="zt_"+str(i)+"_"+str(j)) elif p == "1": ztij = m.addVar(vtype=grb.GRB.CONTINUOUS, lb=0, name="zt_"+str(i)+"_"+str(j)) zzts.append(ztij) z.append(zzs) if p == "2" or p == "1": ztrans.append(zzts) elif i< nlayer+1: # middle layer, has both z and z hat zzs = [] zzhs = [] for j in range(1,len(UBs[i-1])+1): zij = m.addVar(vtype=grb.GRB.CONTINUOUS, name="z_"+str(i)+"_"+str(j)) zzs.append(zij) zhij = m.addVar(vtype=grb.GRB.CONTINUOUS,lb=-np.inf,name="zh_"+str(i)+"_"+str(j)) zzhs.append(zhij) z.append(zzs) zh.append(zzhs) else: # last layer, i == nlayer + 1 # only has z hat, length is the same as the output # there is no relu, so no z zzhs = [] for j in range(1,len(bs[-1])+1): zhij = m.addVar(vtype=grb.GRB.CONTINUOUS,lb=-np.inf,name="zh_"+str(i)+"_"+str(j)) zzhs.append(zhij) zh.append(zzhs) m.update() # Adding weights constraints for all layers for i in range(1,nlayer+1): W = Ws[i-1] # weights of layer i for j in range(W.shape[0]): """ sum_term = bs[i-1][j] for s in range(W.shape[1]): # z start from 1 sum_term += z[i][s]*W[j,s] """ sum_term = grb.LinExpr(W[j], z[i]) + bs[i-1][j] # this is the output of layer i, and let z_hat_{i+1} equal to it # z_hat_{nlayer+1} is the final output (logits) m.addConstr(sum_term == zh[i+1][j], "weights==_"+str(i)+"_"+str(j)) # m.addConstr(sum_term <= zh[i+1][j], "weights<=_"+str(i)+"_"+str(j)) # m.addConstr(sum_term >= zh[i+1][j], "weights>=_"+str(i)+"_"+str(j)) # nlayer network only has nlayer - 1 activations for i in range(1, nlayer): # UBs[0] is the bounds for input x, so start from 1 for j in range(len(UBs[i])): # neuron_states starts from 0 if neuron_states[i-1][j] == 1: m.addConstr(z[i+1][j] == zh[i+1][j], "LPposr==_"+str(j)) # m.addConstr(z[i+1][j] <= zh[i+1][j], "LPpos<=_"+str(j)) # m.addConstr(z[i+1][j] >= zh[i+1][j], "LPpos>=_"+str(j)) elif neuron_states[i-1][j] == -1: m.addConstr(z[i+1][j] == 0, "LPneg==_"+str(j)) # m.addConstr(z[i+1][j] <= 0, "LPneg<=_"+str(j)) # m.addConstr(z[i+1][j] >= 0, "LPneg>=_"+str(j)) elif neuron_states[i-1][j] == 0: # m.addConstr(z[i+1][j] >= 0, "LPunsure>=0_"+str(j)) m.addConstr(z[i+1][j] >= zh[i+1][j], "LPunsure>=_"+str(j)) m.addConstr(z[i+1][j] <= alphas[i-1][j]*(zh[i+1][j]-LBs[i][j]), "LPunsure<=_"+str(j)) else: raise(RuntimeError("unknown neuron_state: "+neuron_states[i])) # #finally, add constraints for z[1], the input -> For p == "i", this is already added in the input variable range zij # for i in range(len(UBs[0])): # m.addConstr(z[1][i] <= UBs[0][i], "inputs+_"+str(i)) # m.addConstr(z[1][i] >= LBs[0][i], "inputs-_"+str(i)) if p == "2": #finally, add constraints for z[1] and ztrans[1], the input for i in range(len(UBs[0])): m.addConstr(ztrans[1][i] == z[1][i] - x0[i], "INPUTtrans_"+str(i)) # quadratic constraints m.addConstr(grb.quicksum(ztrans[1][i]*ztrans[1][i] for i in range(len(UBs[0]))) <= eps*eps, "INPUT L2 norm QCP") elif p == "1": #finally, add constraints for z[1] and ztrans[1], the input temp = [] for i in range(len(UBs[0])): tempi = m.addVar(vtype=grb.GRB.CONTINUOUS) temp.append(tempi) for i in range(len(UBs[0])): # absolute constraints: seem that option1 and 2a, 2c are the right answer (compared to p = 2 result) # option 1 #m.addConstr(ztrans[1][i] >= z[1][i] - x0[i], "INPUTtransPOS_"+str(i)) #m.addConstr(ztrans[1][i] >= -z[1][i] + x0[i], "INPUTtransNEG_"+str(i)) # option 2a: same answer as option 1 # note if we write , the result is different #zzz = m.addVar(vtype=grb.GRB.CONTINUOUS) #m.addConstr(zzz == z[1][i]-x0[i]) #m.addConstr(ztrans[1][i] == grb.abs_(zzz), "INPUTtransABS_"+str(i)) # option 2b: gives different sol as 2a and 2c, guess it's because abs_() has to take a variable, # and that's why 2a and 2c use additional variable zzz or temp # but now it gives Attribute error on "gurobipy.LinExpr", so can't use this anymore #m.addConstr(ztrans[1][i] == grb.abs_(z[1][i]-x0[i]), "INPUTtransABS_"+str(i)) # option 2c: same answer as 2a m.addConstr(temp[i] == z[1][i]-x0[i]) m.addConstr(ztrans[1][i] == grb.abs_(temp[i]), "INPUTtransABS_"+str(i)) # option 3: same answer as 2b #m.addConstr(ztrans[1][i] <= z[1][i] - x0[i], "INPUTtransPOS_"+str(i)) #m.addConstr(ztrans[1][i] >= -z[1][i] + x0[i], "INPUTtransNEG_"+str(i)) # L1 constraints m.addConstr(grb.quicksum(ztrans[1][i] for i in range(len(UBs[0]))) <= eps, "INPUT L1 norm") # another way to write quadratic constraints ###expr = grb.QuadExpr() ###expr.addTerms(np.ones(len(UBs[0])), z[1], z[1]) ###m.addConstr(expr <= eps*eps) m.update() print("[L2][LP solver initialized] time_lp_init = {:.4f}".format(time.time() - start)) # for middle layers, need to compute full bounds if compute_full_bounds: # compute upper bounds # z_hat_{nlayer+1} is the logits (final output, or inputs for layer nlayer+1) ##for j in [pred_label,target_label]: for j in range(Ws[nlayer-1].shape[0]): m.setObjective(zh[nlayer+1][j], grb.GRB.MAXIMIZE) # m.write('grbtest_LP_2layer_'+str(j)+'.lp') start = time.time() m.optimize() UB[j] = m.objVal m.reset() print("[L2][upper bound solved] j = {}, time_lp_solve = {:.4f}".format(j, time.time() - start)) # compute lower bounds ##for j in [pred_label,target_label]: for j in range(Ws[nlayer-1].shape[0]): m.setObjective(zh[nlayer+1][j], grb.GRB.MINIMIZE) # m.write('grbtest_LP_2layer_'+str(j)+'.lp') start = time.time() m.optimize() LB[j] = m.objVal m.reset() print("[L2][lower bound solved] j = {}, time_lp_solve = {:.4f}".format(j, time.time() - start)) bnd_gx0 = LB[target_label]-UB[pred_label] else: # use the g_x0 tricks if it's last layer call: if untargeted: bnd_gx0 = [] start = time.time() for j in range(Ws[nlayer-1].shape[0]): if j != pred_label: m.setObjective(zh[nlayer+1][pred_label]-zh[nlayer+1][j], grb.GRB.MINIMIZE) m.optimize() bnd_gx0.append(m.objVal) # print("[L2][Solved untargeted] j = {}, value = {:.4f}".format(j, m.objVal)) m.reset() else: m.setObjective(zh[nlayer+1][pred_label]-zh[nlayer+1][target_label], grb.GRB.MINIMIZE) start = time.time() m.optimize() bnd_gx0 = m.objVal m.reset() print("[L2][g(x) bound solved] time_lp_solve = {:.4f}".format(time.time() - start)) return UB, LB, bnd_gx0
vy[i] = m.addVar(name="vy_" + str(i)) abs_vx[i] = m.addVar(name="abs_vx_" + str(i)) abs_vy[i] = m.addVar(name="abs_vy_" + str(i)) # define vs m.addConstr(vx[0] == px[1] - px[0]) m.addConstr(vy[0] == py[1] - py[0]) m.addConstr(vx[1] == px[3] - px[2]) m.addConstr(vy[1] == py[3] - py[2]) # v0 v1 orthogonal m.addConstr(vx[0] * vx[1] + vy[0] * vy[1] == 0) # define abs x y for i in range(2): m.addConstr(abs_vx[i] == gp.abs_(vx[i])) m.addConstr(abs_vy[i] == gp.abs_(vy[i])) # v length m.addConstr(abs_vx[0] + abs_vy[0] == 1) m.addConstr(abs_vx[1] + abs_vy[1] == 1) # # Set objective: maximize x # m.setObjective(objective, GRB.MINIMIZE) # First optimize() call will fail - need to set NonConvex to 2 try: m.params.NonConvex = 2 m.optimize() except gp.GurobiError: print("Optimize failed due to non-convexity")
def optimize_planning( timeline: List[str], workcenters: List[str], needs, wc_cost_reg: Dict[str, int], wc_cost_ot: Dict[str, int], wc_cost_we: Dict[str, int], inventory_carrying_cost: int, customer_orders: List[str], cycle_times, delay_cost: int, ) -> pd.DataFrame: # Split weekdays/weekends weekdays = [] weekend = [] for date in timeline: day = datetime.datetime.strptime(date, "%Y/%m/%d") if day.weekday() < 5: weekdays.append(date) else: weekend.append(date) # Initiate optimization model model = gurobipy.Model("Optimize production planning") # DEFINE VARIABLES # Quantity variable x_qty = model.addVars( timeline, customer_orders, workcenters, lb=0, vtype=gurobipy.GRB.INTEGER, name="plannedQty", ) # Time variable x_time = model.addVars( timeline, customer_orders, workcenters, lb=0, vtype=gurobipy.GRB.CONTINUOUS, name="plannedTime", ) # Set the value of x_time model.addConstrs( ((x_time[(date, mo, wc)] == x_qty[(date, mo, wc)] * cycle_times[(mo, wc)] for date in timeline for mo in customer_orders for wc in workcenters)), name="x_time_constr", ) # Qty to display quantity = model.addVars(timeline, workcenters, lb=0, vtype=gurobipy.GRB.INTEGER, name="qty") # Set the value of qty model.addConstrs( ((quantity[(date, wc)] == gurobipy.quicksum(x_qty[(date, mo, wc)] for mo in customer_orders) for date in timeline for wc in workcenters)), name="wty_time_constr", ) # Variable status of the line ( 0 = closed, 1 = opened) line_opening = model.addVars(timeline, workcenters, vtype=gurobipy.GRB.BINARY, name="Open status") # Load variables (hours) - regular and overtime reg_hours = model.addVars( timeline, workcenters, vtype=gurobipy.GRB.CONTINUOUS, name="Regular hours", ) ot_hours = model.addVars( timeline, workcenters, vtype=gurobipy.GRB.CONTINUOUS, name="Overtime hours", ) reg_hours_bis = model.addVars( timeline, workcenters, lb=7, ub=8, vtype=gurobipy.GRB.CONTINUOUS, name="regHours", ) ot_hours_bis = model.addVars(timeline, workcenters, lb=0, ub=4, vtype=gurobipy.GRB.CONTINUOUS, name="OTHours") # Set the value of reg and OT hours) model.addConstrs( (reg_hours[(date, wc)] == reg_hours_bis[(date, wc)] * line_opening[(date, wc)] for date in timeline for wc in workcenters), name="total_hours_constr", ) model.addConstrs( (ot_hours[(date, wc)] == ot_hours_bis[(date, wc)] * line_opening[(date, wc)] for date in timeline for wc in workcenters), name="total_hours_constr", ) # Variable total load (hours) total_hours = model.addVars( timeline, workcenters, vtype=gurobipy.GRB.CONTINUOUS, name="Total hours", ) # Set the value of total load (regular + overtime) model.addConstrs( (total_hours[(date, wc)] == (reg_hours[(date, wc)] + ot_hours[(date, wc)]) for date in timeline for wc in workcenters), name="Link total hours - reg/ot hours", ) # Set total hours of production in link with the time variable model.addConstrs( ((total_hours[(date, wc)] == gurobipy.quicksum( x_time[(date, mo, wc)] for mo in customer_orders) for date in timeline for wc in workcenters)), name="total_hours_constr", ) # Variable cost labor_cost = model.addVars(timeline, workcenters, lb=0, vtype=gurobipy.GRB.CONTINUOUS, name="Labor cost") # Set the value of cost (hours * hourly cost) model.addConstrs( (labor_cost[(date, wc)] == reg_hours[(date, wc)] * wc_cost_reg[wc] + ot_hours[(date, wc)] * wc_cost_ot[wc] for date in weekdays for wc in workcenters), name="Link labor cost - working hours - wd", ) model.addConstrs( (labor_cost[(date, wc)] == total_hours[(date, wc)] * wc_cost_we[wc] for date in weekend for wc in workcenters), name="Link labor cost - working hours - we", ) # Variable gap early/late production gap_prod = model.addVars( timeline, customer_orders, lb=-10000, ub=10000, vtype=gurobipy.GRB.CONTINUOUS, name="gapProd", ) abs_gap_prod = model.addVars( timeline, customer_orders, vtype=gurobipy.GRB.CONTINUOUS, name="absGapProd", ) # Set the value of gap for early production for l in range(len(timeline)): model.addConstrs( (gap_prod[(timeline[l], mo)] == gurobipy.quicksum(x_qty[(date, mo, wc)] for date in timeline[:l + 1] for wc in workcenters) - (gurobipy.quicksum(needs[(date, mo)] for date in timeline[:l + 1])) for mo in customer_orders), name="gap_prod", ) # Set the value of ABS(gap for early production) model.addConstrs( ((abs_gap_prod[(date, mo)] == gurobipy.abs_(gap_prod[(date, mo)])) for date in timeline for mo in customer_orders), name="abs gap prod", ) # Create variable "early production" and "inventory costs" early_prod = model.addVars( timeline, customer_orders, vtype=gurobipy.GRB.CONTINUOUS, name="early prod", ) inventory_costs = model.addVars( timeline, customer_orders, vtype=gurobipy.GRB.CONTINUOUS, name="inventory costs", ) # Set the value of early production model.addConstrs( (early_prod[(date, m)] == (gap_prod[(date, m)] + abs_gap_prod[(date, m)]) / 2 for date in timeline for m in customer_orders), name="early prod", ) # Set the value of inventory costs model.addConstrs( ((inventory_costs[(date, m)] == early_prod[(date, m)] * inventory_carrying_cost) for date in timeline for m in customer_orders), name="inventory costs", ) # Create variable "late production" and "delay costs" late_prod = model.addVars( timeline, customer_orders, vtype=gurobipy.GRB.CONTINUOUS, name="late prod", ) delay_costs = model.addVars( timeline, customer_orders, vtype=gurobipy.GRB.CONTINUOUS, name="inventory costs", ) # Set the value of late production model.addConstrs( (late_prod[(date, m)] == (abs_gap_prod[(date, m)] - gap_prod[(date, m)]) / 2 for date in timeline for m in customer_orders), name="late prod", ) # Set the value of delay costs model.addConstrs( ((delay_costs[(date, m)] == late_prod[(date, m)] * delay_cost) for date in timeline for m in customer_orders), name="delay costs", ) # CONSTRAINT # Constraint: Total hours of production = required production time model.addConstr( (gurobipy.quicksum(x_qty[(date, mo, wc)] for date in timeline for mo in customer_orders for wc in workcenters) == (gurobipy.quicksum(needs[(date, mo)] for date in timeline for mo in customer_orders))), name="total_req", ) # DEFINE MODEL # Objective : minimize a function model.ModelSense = gurobipy.GRB.MINIMIZE # Function to minimize objective = 0 objective += gurobipy.quicksum(labor_cost[(date, wc)] for date in timeline for wc in workcenters) objective += gurobipy.quicksum(inventory_costs[(date, mo)] for date in timeline for mo in customer_orders) objective += gurobipy.quicksum(delay_costs[(date, mo)] for date in timeline for mo in customer_orders) # SOLVE MODEL model.setObjective(objective) model.optimize() sol = pd.DataFrame(data={"Solution": model.X}, index=model.VarName) print("Total cost = $" + str(model.ObjVal)) # model.write("Planning_optimization.lp") # file = open("Planning_optimization.lp", 'r') # print(file.read()) # file.close() return sol
m.addConstr(bias17 == z117 - 0.5, "bias17") m.addConstr(bias18 == z118 - 0.5, "bias18") m.addConstr(bias19 == z119 - 0.5, "bias19") m.addConstr(bias20 == z120 - 0.5, "bias20") m.addConstr(bias21 == z121 - 0.5, "bias21") m.addConstr(bias22 == z122 - 0.5, "bias22") m.addConstr(bias23 == z123 - 0.5, "bias23") m.addConstr(bias24 == z124 - 0.5, "bias24") m.addConstr(bias25 == z125 - 0.5, "bias25") m.addConstr(bias26 == z126 - 0.5, "bias26") m.addConstr(bias27 == z127 - 0.5, "bias27") m.addConstr(bias28 == z128 - 0.5, "bias28") m.addConstr(bias29 == z129 - 0.5, "bias29") m.addConstr(bias30 == z130 - 0.5, "bias30") m.addConstr(bias31 == z131 - 0.5, "bias31") m.addConstr(bias_abs0 == abs_(bias0), "bias_abs0") m.addConstr(bias_abs1 == abs_(bias1), "bias_abs1") m.addConstr(bias_abs2 == abs_(bias2), "bias_abs2") m.addConstr(bias_abs3 == abs_(bias3), "bias_abs3") m.addConstr(bias_abs4 == abs_(bias4), "bias_abs4") m.addConstr(bias_abs5 == abs_(bias5), "bias_abs5") m.addConstr(bias_abs6 == abs_(bias6), "bias_abs6") m.addConstr(bias_abs7 == abs_(bias7), "bias_abs7") m.addConstr(bias_abs8 == abs_(bias8), "bias_abs8") m.addConstr(bias_abs9 == abs_(bias9), "bias_abs9") m.addConstr(bias_abs10 == abs_(bias10), "bias_abs10") m.addConstr(bias_abs11 == abs_(bias11), "bias_abs11") m.addConstr(bias_abs12 == abs_(bias12), "bias_abs12") m.addConstr(bias_abs13 == abs_(bias13), "bias_abs13") m.addConstr(bias_abs14 == abs_(bias14), "bias_abs14") m.addConstr(bias_abs15 == abs_(bias15), "bias_abs15")
a[i] = m.addVar(name="a_" + str(i), ub=360) k[i] = m.addVar(name="k_" + str(i), vtype=GRB.BINARY) diff[i] = m.addVar(name="diff_" + str(i), lb=-360, ub=360) abs_diff[i] = m.addVar(name="abs_diff_" + str(i), ub=360) kp = m.addVar(name="kp", vtype=GRB.BINARY) m.addConstr(a[5] + kp * 360 - a[3], GRB.EQUAL, 180) for face_id in range(2): offset = face_id * 4 for i in range(4): m.addConstr(diff[i + offset] == a[(i + 1) % 4 + offset] + k[i + offset] * 360 - a[i + offset] - 90) for i in range(8): m.addConstr(abs_diff[i] == gp.abs_(diff[i])) objective = gp.LinExpr() for i in range(8): objective += abs_diff[i] # Set objective: maximize x m.setObjective(objective, GRB.MINIMIZE) # First optimize() call will fail - need to set NonConvex to 2 try: m.write("m.lp") # m.feasRelaxS(0, True, False, True) # m.write("feasopt1.lp") m.optimize() except gp.GurobiError:
def optimize_planning( timeline: List[str], workcenters: List[str], needs: Dict[str, int], wc_cost_reg: Dict[str, int], wc_cost_ot: Dict[str, int], wc_cost_we: Dict[str, int], inventory_cost: int, delay_cost: int, ) -> pd.DataFrame: # Weekdays / Weekends weekdays = [] weekend = [] for i in timeline: date = datetime.datetime.strptime(i, "%Y/%m/%d") if date.weekday() < 5: weekdays.append(i) else: weekend.append(i) # Initiate optimization model model = gurobipy.Model("Optimize production planning") # DEFINE VARIABLES # Load variables (hours) - regular and overtime reg_hours = model.addVars( timeline, workcenters, lb=7, ub=8, vtype=gurobipy.GRB.CONTINUOUS, name="Regular hours", ) ot_hours = model.addVars( timeline, workcenters, lb=0, ub=4, vtype=gurobipy.GRB.CONTINUOUS, name="OT hours", ) # Status of the line ( 0 = closed, 1 = opened) line_opening = model.addVars(timeline, workcenters, vtype=gurobipy.GRB.BINARY, name="Open") # Variable total load (hours) total_hours = model.addVars( timeline, workcenters, vtype=gurobipy.GRB.CONTINUOUS, name="Total hours", ) # Variable cost cost = model.addVars(timeline, workcenters, vtype=gurobipy.GRB.CONTINUOUS, name="Cost") # Set the value of cost (hours * hourly cost) model.addConstrs( (cost[(date, wc)] == reg_hours[(date, wc)] * wc_cost_reg[wc] * line_opening[(date, wc)] + ot_hours[(date, wc)] * wc_cost_ot[wc] * line_opening[(date, wc)] for date in weekdays for wc in workcenters), name="Cost weekdays", ) model.addConstrs( (cost[(date, wc)] == (reg_hours[(date, wc)] + ot_hours[(date, wc)]) * wc_cost_we[wc] * line_opening[(date, wc)] for date in weekend for wc in workcenters), name="Cost weekend", ) # Set the value of total load (regular + overtime) model.addConstrs( (total_hours[(date, wc)] == (reg_hours[(date, wc)] + ot_hours[(date, wc)]) * line_opening[(date, wc)] for date in timeline for wc in workcenters), name="Total hours = reg + OT", ) # Constraint: Total hours of production = required production time model.addConstr( (gurobipy.quicksum(total_hours[(date, wc)] for date in timeline for wc in workcenters) == gurobipy.quicksum( needs[date] for date in timeline)), name="Total hours = need", ) # Create variable "early production", "late production" and "inventory costs" # Gap early/late production gap_prod = model.addVars( timeline, lb=-10000, ub=10000, vtype=gurobipy.GRB.CONTINUOUS, name="gapProd", ) abs_gap_prod = model.addVars( timeline, vtype=gurobipy.GRB.CONTINUOUS, name="absGapProd", ) # Set the value of gap production vs need model.addConstrs( ((gap_prod[timeline[k]] == gurobipy.quicksum(total_hours[(date, wc)] for date in timeline[:k + 1] for wc in workcenters) - (gurobipy.quicksum(needs[date] for date in timeline[:k + 1]))) for k in range(len(timeline))), name="gap prod", ) model.addConstrs( ((abs_gap_prod[date] == gurobipy.abs_(gap_prod[date])) for date in timeline), name="abs gap prod", ) # Create variable "early production" and "inventory costs" early_prod = model.addVars( timeline, vtype=gurobipy.GRB.CONTINUOUS, name="early prod", ) inventory_costs = model.addVars( timeline, vtype=gurobipy.GRB.CONTINUOUS, name="inventory costs", ) # Set the value of early production model.addConstrs( ((early_prod[date] == (gap_prod[date] + abs_gap_prod[date]) / 2) for date in timeline), name="early prod", ) # Set the value of inventory costs model.addConstrs( ((inventory_costs[date] == early_prod[date] * inventory_cost) for date in timeline), name="inventory costs", ) # Create variable "late production" and "delay costs" late_prod = model.addVars( timeline, vtype=gurobipy.GRB.CONTINUOUS, name="early prod", ) delay_costs = model.addVars( timeline, vtype=gurobipy.GRB.CONTINUOUS, name="inventory costs", ) # Set the value of late production model.addConstrs( ((late_prod[date] == (abs_gap_prod[date] - gap_prod[date]) / 2) for date in timeline), name="late prod", ) # Set the value of delay costs model.addConstrs( ((delay_costs[date] == late_prod[date] * delay_cost) for date in timeline), name="delay costs", ) # DEFINE MODEL # Objective : minimize a function model.ModelSense = gurobipy.GRB.MINIMIZE # Function to minimize optimization_var = (gurobipy.quicksum(cost[(date, wc)] for date in timeline for wc in workcenters) + gurobipy.quicksum(inventory_costs[date] for date in timeline) + gurobipy.quicksum(delay_costs[date] for date in timeline)) objective = 0 objective += optimization_var # SOLVE MODEL model.setObjective(objective) model.optimize() sol = pd.DataFrame(data={"Solution": model.X}, index=model.VarName) sol = sol.filter(like="Total hours", axis=0) print("Total cost = $" + str(model.ObjVal)) # FORMAT THE RESULT planning = sol planning["Date"] = list(planning.index.values) planning[["Date", "Line"]] = planning["Date"].str.split(",", expand=True) planning["Date"] = planning["Date"].str.split("[").str[1] planning["Line"] = planning["Line"].str.split("]").str[0] planning = planning.pivot(index="Line", columns="Date", values="Solution") return planning
def createConstraints(self): for i in range(len(self.vert_locs)): self.m.addConstr(self.diff_x[i] == self.px[i] - self.vert_locs[i][0]) self.m.addConstr(self.diff_y[i] == self.py[i] - self.vert_locs[i][1]) for i in range(len(self.shape_verts)): for vid in self.shape_verts[i]: # self.m.addConstr(self.diff_x[vid] - self.diff_x.sum(vid_1, '*') / len(self.shape_verts[i]) == self.std_diff_x[vid] for vid_1 in self.shape_verts[i]) self.m.addConstr( self.diff_x.sum(vid_1, '*') == 0 for vid_1 in self.shape_verts[i]) self.m.addConstr( self.abs_std_diff_x[vid] == gp.abs_(self.std_diff_x[vid])) self.m.addConstr( self.diff_y[vid] - self.diff_y.sum(vid_1, '*') / len(self.shape_verts[i]) == self.std_diff_y[vid] for vid_1 in self.shape_verts[i]) self.m.addConstr( self.abs_std_diff_y[vid] == gp.abs_(self.std_diff_y[vid])) for i in range(len(pair_rels)): p_rel = pair_rels[i] segs = [[p_rel[0], p_rel[1]], [p_rel[2], p_rel[3]]] for se in range(2): # (x, y) -> (x, y) if p_rel[4] == 0: self.m.addConstr(self.px[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(self.py[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) # (x, y) -> (-y, x) elif p_rel[4] == 1: self.m.addConstr(-self.py[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(self.px[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) # (x, y) -> (y, -x) elif p_rel[4] == 2: self.m.addConstr(self.py[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(-self.px[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) # (x, y) -> (x, y) elif p_rel[4] == 3: self.m.addConstr(-self.px[segs[0][se]] - self.px[segs[1][se]] == self.ds_x[i]) self.m.addConstr(-self.py[segs[0][se]] - self.py[segs[1][se]] == self.ds_y[i]) def addObjective(self): self.objective = gp.LinExpr() for i in range(self.vert_locs): self.objective += self.abs_std_diff_x[i] self.objective += self.abs_std_diff_y[i] self.m.setObjective(self.objective, GRB.MINIMIZE) def solve(self): try: # m.params.NonConvex = 2 m.write("opt_verts.lp") m.feasRelaxS(0, True, False, True) m.write("opt_verts_relaxed.lp") m.optimize() except gp.GurobiError: print("Optimize failed") # f = open("opt_pts.txt", "w") for i in range(8): print("x_", i, ": ", px[i].x) print("y_", i, ": ", py[i].x) f.write(str(px[i].x) + " " + str(py[i].x) + "\n") f.close() for v in m.getVars(): print('%s %g' % (v.varName, v.x))
如果目标函数带系数可以创建矩阵变量x = addMVars(4) 对系数列表 a = [1, 2, 3, 4]作矩阵计算 a@x 但比较坑的是gurobi中系数列表必须为numpy.array, 并且约束条件a[0] == x[0]是没办法写进addConstr()的, 不支持矩阵决策变量。 ''' # 创建模型 m = gp.Model("ex1.2") # 创建变量 x = m.addVars(4, lb=-GRB.INFINITY, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS) a = m.addVars(4, lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS) # 设置目标函数 m.setObjective(a[0] + 2 * a[1] + 3 * a[2] + 4 * a[3], GRB.MINIMIZE) # 设置约束 m.addConstr(x[0] - x[1] - x[2] + x[3] == 0, 'c0') m.addConstr(x[0] - x[1] + x[2] - 3 * x[3] == 1, 'c1') m.addConstr(x[0] - x[1] - 2 * x[2] + 3 * x[3] == -0.5, 'c2') # 绝对值约束 m.addConstrs(((a[i] == gp.abs_(x[i])) for i in range(4))) # 模型求解 m.optimize() # 输出结果 print('Obj: %g' % m.objVal) for v in m.getVars(): print('%s %g' % (v.varName, v.x))
def calculate_trajectory(self, x0, t_elapsed): """ Uses Gurobi to calculate optimal trajectory points (self.xstar) and control inputs (self.ustar) """ # Options Nin = 6 # number of sides in inner-ellipse polygon approx Nout = 15 # number of sides in outer-ellipse polygon approx initial_state = x0.reshape(6) goal_state = np.zeros(6) n = self.mean_motion mc = self.mass_chaser # Shorten the number of initial time steps (self.tau0) based on the amount of time elapsed tau = int(max(10, np.round(self.tau0 - t_elapsed / self.dt_plan))) print("time elapsed = ", t_elapsed) # Set Ranges smax = 15000 # arbitrary (included bounds to speed up solver) vmax = 10 # [m/s] max velocity Fmax = 2 # [N] max force # Initialize states sx = [] sy = [] sz = [] vx = [] vy = [] vz = [] Fx = [] Fy = [] Fz = [] snorm = [] sxabs = [] syabs = [] vnorm = [] vxabs = [] vyabs = [] zeta = [] m = gp.Model("QPTraj") # Define variables at each of the tau timesteps for t in range(tau): sx.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-smax, ub=smax, name="sx" + str(t))) vx.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-vmax, ub=vmax, name="vx" + str(t))) Fx.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-Fmax, ub=Fmax, name="Fx" + str(t))) sy.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-smax, ub=smax, name="sy" + str(t))) vy.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-vmax, ub=vmax, name="vy" + str(t))) Fy.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-Fmax, ub=Fmax, name="Fy" + str(t))) sz.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-smax, ub=smax, name="sz" + str(t))) vz.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-vmax, ub=vmax, name="vz" + str(t))) Fz.append( m.addVar(vtype=GRB.CONTINUOUS, lb=-Fmax, ub=Fmax, name="Fz" + str(t))) snorm.append( m.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=smax, name="snorm" + str(t))) sxabs.append( m.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=smax, name="sxabs" + str(t))) syabs.append( m.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=smax, name="syabs" + str(t))) vnorm.append( m.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=vmax, name="vnorm" + str(t))) vxabs.append( m.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=vmax, name="vxabs" + str(t))) vyabs.append( m.addVar(vtype=GRB.CONTINUOUS, lb=0, ub=vmax, name="vyabs" + str(t))) for p in range(Nin): zeta.append(m.addVar(vtype=GRB.BINARY, name="zeta" + str(p))) m.update() # Set Initial Conditions m.addConstr(sx[0] == initial_state[0], "sx0") m.addConstr(sy[0] == initial_state[1], "sy0") m.addConstr(sz[0] == initial_state[2], "sz0") m.addConstr(vx[0] == initial_state[3], "vx0") m.addConstr(vy[0] == initial_state[4], "vy0") m.addConstr(vz[0] == initial_state[5], "vz0") # Specify Terminal Set if self.f_goal_set == 0: # origin m.addConstr(sx[-1] == goal_state[0], "sxf") m.addConstr(sy[-1] == goal_state[1], "syf") m.addConstr(sz[-1] == goal_state[2], "szf") m.addConstr(vx[-1] == goal_state[3], "vxf") m.addConstr(vy[-1] == goal_state[4], "vyf") m.addConstr(vz[-1] == goal_state[5], "vzf") elif self.f_goal_set == 1: # stationary point or periodic line m.addConstr(sx[-1] == goal_state[0], "sxf") m.addConstr(vx[-1] == goal_state[3], "vxf") m.addConstr(vy[-1] == goal_state[4], "vyf") elif self.f_goal_set == 2: # ellipse m.addConstr(vy[-1] + 2 * n * sx[-1] == 0, "ellipse1") m.addConstr(sy[-1] - (2 / n) * vx[-1] == 0, "ellipse2") # Set dynamic speed limit for t in range(tau): # Define the norms: m.addConstr(sxabs[t] == gp.abs_(sx[t])) m.addConstr(syabs[t] == gp.abs_(sy[t])) m.addConstr(snorm[t] == gp.max_(sxabs[t], syabs[t]), "snorm" + str(t)) m.addConstr(vxabs[t] == gp.abs_(vx[t])) m.addConstr(vyabs[t] == gp.abs_(vy[t])) m.addConstr(vnorm[t] == gp.max_(vxabs[t], vyabs[t]), "vnorm" + str(t)) # Speed limit constraint: m.addConstr(vnorm[t] <= self.kappa_speed * snorm[t]) # Collision Avoidance Constraint if self.f_collision_avoidance: for t in range(tau): m.addConstr(snorm[t] >= self.collision_dist) if initial_state[0] < self.collision_dist or initial_state[ 1] < self.collision_dist: print( "\nERROR: Initial position is too close! Collision constraint violated!\n" ) # # Final point within [1km-5km] of target # m.addConstr( snorm[-1] <= 2000 ) # m.addConstr( snorm[-1] >= 1000 ) # Terminal constraint: inner polygonal approx on outer ellipse bound Nout = Nout + 1 aout = self.semiminor_out bout = self.semiminor_out * 2 theta = np.linspace(0, 2 * np.pi, Nout) for j in range(0, Nout - 1): x0 = aout * np.cos(theta[j]) y0 = bout * np.sin(theta[j]) x1 = aout * np.cos(theta[j + 1]) y1 = bout * np.sin(theta[j + 1]) alphax = y0 - y1 alphay = x1 - x0 gamma = alphay * y1 + alphax * x1 m.addConstr(alphax * sx[-1] + alphay * sy[-1] >= gamma, "OPA" + str(j)) # Terminal constraint: outer polygonal approx on inner ellipse bound if self.f_collision_avoidance: a_in = self.semiminor_in b_in = self.semiminor_in * 2 theta = np.linspace(0, 2 * np.pi, Nin + 1) big_M = 100000 for j in range(0, Nin): x0 = a_in * np.cos(theta[j]) y0 = b_in * np.sin(theta[j]) c1 = (2 * x0 / (a_in**2)) c2 = (2 * y0 / (b_in**2)) cmag = np.sqrt(c1**2 + c2**2) c1 = c1 / cmag c2 = c2 / cmag m.addConstr( c1 * sx[-1] + c2 * sy[-1] - c1 * x0 - c2 * y0 - big_M * zeta[j] >= -big_M, "IPA" + str(j)) m.addConstr(sum(zeta[p] for p in range(Nin)) >= 0.5) # Set Dynamics for t in range(tau - 1): # Dynamics m.addConstr(sx[t + 1] == sx[t] + vx[t] * self.dt_plan, "Dsx_" + str(t)) m.addConstr(sy[t + 1] == sy[t] + vy[t] * self.dt_plan, "Dsy_" + str(t)) m.addConstr(sz[t + 1] == sz[t] + vz[t] * self.dt_plan, "Dsz_" + str(t)) m.addConstr( vx[t + 1] == vx[t] + sx[t] * 3 * n**2 * self.dt_plan + vy[t] * 2 * n * self.dt_plan + Fx[t] * (1 / mc) * self.dt_plan, "Dvx_" + str(t)) m.addConstr( vy[t + 1] == vy[t] - vx[t] * 2 * n * self.dt_plan + Fy[t] * (1 / mc) * self.dt_plan, "Dvy_" + str(t)) m.addConstr( vz[t + 1] == vz[t] + (-n**2) * sz[t] * self.dt_plan + Fz[t] * (1 / mc) * self.dt_plan, "Dvz_" + str(t)) # Set Objective ( minimize: sum(Fx^2 + Fy^2) ) obj = Fx[0] * Fx[0] + Fy[0] * Fy[0] + Fz[0] * Fz[0] for t in range(0, tau): obj = obj + Fx[t] * Fx[t] + Fy[t] * Fy[t] + Fz[t] * Fz[t] m.setObjective(obj, GRB.MINIMIZE) m.setParam('OutputFlag', False) # Optimize and report on results m.optimize() # Save desired trajectory self.xstar = np.zeros([6, tau]) self.ustar = np.zeros([3, tau]) self.snorm = np.zeros([tau]) self.vnorm = np.zeros([tau]) for t in range(tau): # TODO: find quicker way to do this self.xstar[0, t] = m.getVarByName("sx" + str(t)).x self.xstar[1, t] = m.getVarByName("sy" + str(t)).x self.xstar[3, t] = m.getVarByName("vx" + str(t)).x self.xstar[4, t] = m.getVarByName("vy" + str(t)).x self.ustar[0, t] = m.getVarByName("Fx" + str(t)).x self.ustar[1, t] = m.getVarByName("Fy" + str(t)).x self.ustar[2, t] = m.getVarByName("Fz" + str(t)).x self.snorm[t] = m.getVarByName("snorm" + str(t)).x self.vnorm[t] = m.getVarByName("vnorm" + str(t)).x