def test_add_column(solver: str): """Simple test which add columns in a specific way""" m = Model() x = m.add_var() example_constr1 = m.add_constr(x >= 1, "constr1") example_constr2 = m.add_constr(x <= 2, "constr2") column1 = Column() column1.constrs = [example_constr1] column1.coeffs = [1] second_var = m.add_var("second", column=column1) column2 = Column() column2.constrs = [example_constr2] column2.coeffs = [2] m.add_var("third", column=column2) vthird = m.vars["third"] assert vthird is not None assert len(vthird.column.coeffs) == len(vthird.column.constrs) assert len(vthird.column.coeffs) == 1 pconstr2 = m.constrs["constr2"] assert vthird.column.constrs[0].name == pconstr2.name assert len(example_constr1.expr.expr) == 2 assert second_var in example_constr1.expr.expr assert x in example_constr1.expr.expr
def var_get_column(self, var: Var) -> Column: self.update() nnz = ffi.new('int*') # obtaining number of non-zeros error = GRBgetvars(self._model, nnz, ffi.NULL, ffi.NULL, ffi.NULL, var.idx, 1) if error != 0: raise Exception('Error querying gurobi model information') nz = nnz[0] # creating arrays to hold indices and coefficients cbeg = ffi.new('int[2]') cind = ffi.new('int[{}]'.format(nz)) cval = ffi.new('double[{}]'.format(nz)) # obtaining variables and coefficients error = GRBgetvars(self._model, nnz, cbeg, cind, cval, var.idx, 1) if error != 0: raise Exception('Error querying gurobi model information') constr = [self.model.constrs[cind[i]] for i in range(nz)] coefs = [float(cval[i]) for i in range(nz)] return Column(constr, coefs)
def test_column_generation(solver: str): L = 250 # bar length m = 4 # number of requests w = [187, 119, 74, 90] # size of each item b = [1, 2, 2, 1] # demand for each item # creating master model master = Model(solver_name=solver) # creating an initial set of patterns which cut one item per bar # to provide the restricted master problem with a feasible solution lambdas = [ master.add_var(obj=1, name="lambda_%d" % (j + 1)) for j in range(m) ] # creating constraints constraints = [] for i in range(m): constraints.append( master.add_constr(lambdas[i] >= b[i], name="i_%d" % (i + 1))) # creating the pricing problem pricing = Model(solver_name=solver) # creating pricing variables a = [ pricing.add_var(obj=0, var_type=INTEGER, name="a_%d" % (i + 1)) for i in range(m) ] # creating pricing constraint pricing += xsum(w[i] * a[i] for i in range(m)) <= L, "bar_length" new_vars = True while new_vars: ########## # STEP 1: solving restricted master problem ########## master.optimize() ########## # STEP 2: updating pricing objective with dual values from master ########## pricing += 1 - xsum(constraints[i].pi * a[i] for i in range(m)) # solving pricing problem pricing.optimize() ########## # STEP 3: adding the new columns (if any is obtained with negative reduced cost) ########## # checking if columns with negative reduced cost were produced and # adding them into the restricted master problem if pricing.objective_value < -TOL: pattern = [a[i].x for i in range(m)] column = Column(constraints, pattern) lambdas.append( master.add_var(obj=1, column=column, name="lambda_%d" % (len(lambdas) + 1))) # if no column with negative reduced cost was produced, then linear # relaxation of the restricted master problem is solved else: new_vars = False # printing the solution assert len(lambdas) == 8 assert round(master.objective_value) == 3
z_val = pricing.objective_value print('Pricing solution:') print(' z = {z_val}'.format(**locals())) print(' a = ', end='') print([v.x for v in pricing.vars]) print('') ########## # STEP 3: adding the new columns (if any is obtained with negative reduced cost) ########## # checking if columns with negative reduced cost were produced and # adding them into the restricted master problem if pricing.objective_value < -1e-5: pattern = [a[i].x for i in range(m)] column = Column(constraints, pattern) lambdas.append( master.add_var(obj=1, column=column, name='lambda_%d' % (len(lambdas) + 1))) print('new pattern = {pattern}'.format(**locals())) # if no column with negative reduced cost was produced, then linear # relaxation of the restricted master problem is solved else: new_vars = False pricing.write('pricing.lp') # printing the solution