6.8 Integer Optimization¶
An optimization problem where one or more of the variables are constrained to integer values is called a (mixed) integer optimization problem. MOSEK supports integer variables in combination with linear, quadratic and quadratically constrtained and conic problems (except semidefinite). See the previous tutorials for an introduction to how to model these types of problems.
6.8.1 Example MILO1¶
We use the example
to demonstrate how to set up and solve a problem with integer variables. It has the structure of a linear optimization problem (see Sec. 6.1 (Linear Optimization)) except for integrality constraints on the variables. Therefore, only the specification of the integer constraints requires something new compared to the linear optimization problem discussed previously.
First, the integrality constraints are imposed using the function MSK_putvartype
or one of its bulk analogues:
for (j = 0; j < numvar && r == MSK_RES_OK; ++j)
r = MSK_putvartype(task, j, MSK_VAR_TYPE_INT);
Next, the example demonstrates how to set various useful parameters of the mixed-integer optimizer. See Sec. 13.4 (The Optimizer for Mixed-Integer Problems) for details.
/* Set max solution time */
r = MSK_putdouparam(task,
MSK_DPAR_MIO_MAX_TIME,
60.0);
The complete source for the example is listed Listing 6.13. Please note that when we fetch the solution then the integer solution is requested by using MSK_SOL_ITG
. No dual solution is defined for integer optimization problems.
6.8.2 Specifying an initial solution¶
It is a common strategy to provide a starting feasible point (if one is known in advance) to the mixed-integer solver. This can in many cases reduce solution time.
There are two modes for MOSEK to utilize an initial solution.
A complete solution. MOSEK will first try to check if the current value of the primal variable solution is a feasible point. The solution can either come from a previous solver call or can be entered by the user, however the full solution with values for all variables (both integer and continuous) must be provided. This check is always performed and does not require any extra action from the user. The outcome of this process can be inspected via information items
MSK_IINF_MIO_INITIAL_FEASIBLE_SOLUTION
andMSK_DINF_MIO_INITIAL_FEASIBLE_SOLUTION_OBJ
, and via theInitial feasible solution objective
entry in the log.A partial integer solution. MOSEK can also try to construct a feasible solution by fixing integer variables to the values provided by the user (rounding if necessary) and optimizing over the remaining continuous variables. In this setup the user must provide initial values for all integer variables. This action is only performed if the parameter
MSK_IPAR_MIO_CONSTRUCT_SOL
is switched on. The outcome of this process can be inspected via information itemsMSK_IINF_MIO_CONSTRUCT_SOLUTION
andMSK_DINF_MIO_CONSTRUCT_SOLUTION_OBJ
, and via theConstruct solution objective
entry in the log.
In the following example we focus on inputting a partial integer solution.
Solution values can be set using MSK_putxx
, MSK_putxxslice
or similar .
if (r == MSK_RES_OK)
{
/* Assign values to integer variables
(we only set a slice of xx) */
double xxInit[] = {1.0, 1.0, 0.0};
r = MSK_putxxslice(task, MSK_SOL_ITG, 0, 3, xxInit);
}
if (r == MSK_RES_OK)
{
/* Request constructing the solution from integer variable values */
r = MSK_putintparam(task, MSK_IPAR_MIO_CONSTRUCT_SOL, MSK_ON);
}
The log output from the optimizer will in this case indicate that the inputted values were used to construct an initial feasible solution:
Construct solution objective : 1.950000000000e+01
The same information can be obtained from the API:
MSK_getintinf(task, MSK_IINF_MIO_CONSTRUCT_SOLUTION, &constr);
MSK_getdouinf(task, MSK_DINF_MIO_CONSTRUCT_SOLUTION_OBJ, &constr_obj);
printf("Construct solution utilization: %d\nConstruct solution objective: %.3f\n", constr, constr_obj);
6.8.3 Example MICO1¶
Integer variables can also be used arbitrarily in conic problems (except semidefinite). We refer to the previous tutorials for how to set up a conic optimization problem. Here we present sample code that sets up a simple optimization problem:
The canonical conic formulation of (6.29) suitable for Optimizer API for C is
int main(int argc, char *argv[])
{
MSKint32t numvar = 3; /* x, y, t */
MSKvariabletypee vart[] = { MSK_VAR_TYPE_INT, MSK_VAR_TYPE_INT };
MSKint32t intsub[] = { 0, 1 };
MSKint32t i, j;
MSKenv_t env = NULL;
MSKtask_t task = NULL;
MSKrescodee r, trm;
r = MSK_makeenv(&env, NULL);
if (r == MSK_RES_OK)
{
r = MSK_maketask(env, 0, 0, &task);
if (r == MSK_RES_OK)
r = MSK_linkfunctotaskstream(task, MSK_STREAM_LOG, NULL, printstr);
if (r == MSK_RES_OK)
r = MSK_appendvars(task, numvar);
if (r == MSK_RES_OK)
r = MSK_putvarboundsliceconst(task, 0, numvar, MSK_BK_FR, -0.0, 0.0);
/* Integrality constraints */
if (r == MSK_RES_OK)
r = MSK_putvartypelist(task, 2, intsub, vart);
/* Objective */
if (r == MSK_RES_OK)
r = MSK_putobjsense(task, MSK_OBJECTIVE_SENSE_MINIMIZE);
if (r == MSK_RES_OK)
r = MSK_putcj(task, 2, 1.0); /* Minimize t */
/* Conic part of the problem */
if (r == MSK_RES_OK)
{
/* Set up the affine expressions */
/* x, x-3.8, y, t, 1.0 */
MSKint64t afeidx[] = {0, 1, 2, 3};
MSKint32t varidx[] = {0, 0, 1, 2};
MSKrealt val[] = {1.0, 1.0, 1.0, 1.0};
MSKrealt g[] = {0.0, -3.8, 0.0, 0.0, 1.0};
MSKint64t domExp, domQuad;
MSKint64t afeidxExp[] = {1, 4, 2};
MSKint64t afeidxQuad[] = {3, 0, 2};
if (r == MSK_RES_OK)
r = MSK_appendafes(task, 5);
if (r == MSK_RES_OK)
r = MSK_putafefentrylist(task,
4,
afeidx,
varidx,
val);
if (r == MSK_RES_OK)
r = MSK_putafegslice(task, 0, 5, g);
// Add constraint (x-3.8, 1, y) \in \EXP
if (r == MSK_RES_OK)
r = MSK_appendprimalexpconedomain(task, &domExp);
if (r == MSK_RES_OK)
r = MSK_appendacc(task, domExp, 3, afeidxExp, NULL);
// Add constraint (t, x, y) \in \QUAD
if (r == MSK_RES_OK)
r = MSK_appendquadraticconedomain(task, 3, &domQuad);
if (r == MSK_RES_OK)
r = MSK_appendacc(task, domQuad, 3, afeidxQuad, NULL);
}
/* Optimize the problem */
if (r == MSK_RES_OK)
r = MSK_optimizetrm(task, &trm);
if (r == MSK_RES_OK)
r = MSK_solutionsummary(task, MSK_STREAM_MSG);
if (r == MSK_RES_OK)
{
MSKrealt xx[] = {0, 0};
r = MSK_getxxslice(task, MSK_SOL_ITG, 0, 2, xx);
if (r == MSK_RES_OK)
printf("x = %.2f, y = %.2f\n", xx[0], xx[1]);
}
if (task) MSK_deletetask(&task);
}
if (env) MSK_deleteenv(&env);
return r;
}
Error and solution status handling were omitted for readability.