Using loadproblem for efficiency
The high-level functions problem.addConstraint and problem.addVariable allow for efficient, concise, and understandable modeling of any optimization problem. An even faster way to create a problem is through the problem.loadproblem function, which uses a more direct interface to the Optimizer's libraries and is hence preferable with very large problems and when efficiency in model creation is necessary.
The functon problem.loadproblem can be used to create problems with linear and/or quadratic constraints, a linear and/or quadratic objective function, and with continuous and/or discrete variables. Its syntax with default parameter values allows for specifying only the components of interest. We refer the reader to its entry in Chapter Reference Manual, and present here a few examples of usages. More examples are shown in Chapter Examples of use.
The first example uses loadproblem to create a problem similar to that created earlier in this chapter. We first write the problem using standard modeling functions:
import xpress as xp x = xp.var(vartype=xp.integer, name='x1', lb=-10, ub=10) y = xp.var(name='x2') p = xp.problem(name='myexample') p.addVariable(x, y) p.setObjective(x**2 + 2*y) p.addConstraint(x + 3*y <= 4) p.addConstraint(7*x + 4*y >= 8)
The following code creates a problem with the same features, including variable names and their types
import xpress as xp p = xp.problem() p.loadproblem(probname='myexample', qrtypes=['L', 'G'], # constraint senses rhs=[4, 8], # right-hand sides range=None, obj=[0, 2], # linear obj. coeff. mstart=[0, 2, 4], # start pos. of all columns mrwind=[0, 1, 0, 1], # row index in each column dmatval=[1, 7, 3, 4], # coefficients mnel=None, dlb=[-10,0], # variable lower bounds dub=[10,xp.infinity], # upper bounds mqcol1=[0], # quadratic obj. terms, column 1 mqcol2=[0], # column 2 dqe=[2], # coeff qgtype=['I'], # variable types mgcols=[0], colnames=['x1', 'x2'])
Apart from the intuitive lists qrtypes (for constraint types: 'L' for "lesser-than", 'G' for "greater-than", 'E' for "equal-to"), rhs (constraints' right-hand sides), obj (objective linear coefficients), dlb and dub (variables' lower and upper bounds), a few paramters deserve some attention. The three lists mstart, mrwind, dmatval describe the coefficient matrix: mrwind and dmatval contain, respectively, the row indices and the coefficients, while mstart is a list of n+1 integers (where n is the number of variables, i.e., the size of obj, dlb, and dub); mstart[i] indicates the position, within mrwind and dmatval, of the indices and coefficients of the i-th column. The last element mstart[n+1] indicates the number of nonzeros in the matrix.
The following shows two equivalent knapsack problems, again created first using the high-level modeling routines and then the lower-level API function.
import xpress as xp N = 6 x = [xp.var(vartype=xp.binary) for _ in range(N)] value = [1, 4, 6, 4, 7, 3] weight = [1, 3, 5, 5, 8, 4] p = xp.problem(name='knapsack') p.addVariable(x) p.setObjective(xp.Sum(value[i] * x[i] for i in range(N)), sense=xp.maximize) p.addConstraint(xp.Sum(weight[i] * x[i] for i in range(N)) <= 12)
Note that problem.loadproblem assumes that the optimization sense is minimization and hence a call to problem.chgobjsense is necessary to set the sense to maximization.
import xpress as xp p = xp.problem() N = 6 value = [1, 4, 6, 4, 7, 3] weight = [1, 3, 5, 5, 8, 4] p.loadproblem(probname='knapsack', qrtypes=['L'], # constraint senses rhs=[12], # right-hand sides range=None, obj=value, # linear obj. coeff. mstart=range(N+1), # start pos. of all columns mrwind=[0] * N, # row index in each column (always 0) dmatval=weight, # coefficients mnel=None, dlb=[0] * N, # variable lower bounds dub=[1] * N, # upper bounds qgtype=['B'] * N, # variable types mgcols=range(N)) p.chgobjsense(xp.maximize)