7.2 Accessing the solution¶
This section contains important information about the status of the solver and the status of the solution, which must be checked in order to properly interpret the results of the optimization.
7.2.1 Solver termination¶
The optimizer provides two status codes relevant for error handling:
Response code of type
rescode
. It indicates if any unexpected error (such as an out of memory error, licensing error etc.) has occurred. The expected value for a successful optimization isrescode.ok
.Termination code: It provides information about why the optimizer terminated, for instance if a predefined time limit has been reached. These are not errors, but ordinary events that can be expected (depending on parameter settings and the type of optimizer used).
If the optimization was successful then the method Task.optimize
returns normally and its output is the termination code. If an error occurs then the method throws an exception, which contains the response code. See Sec. 7.3 (Errors and exceptions) for how to access it.
If a runtime error causes the program to crash during optimization, the first debugging step is to enable logging and check the log output. See Sec. 7.4 (Input/Output).
If the optimization completes successfully, the next step is to check the solution status, as explained below.
7.2.2 Available solutions¶
MOSEK uses three kinds of optimizers and provides three types of solutions:
basic solution from the simplex optimizer,
interior-point solution from the interior-point optimizer,
integer solution from the mixed-integer optimizer.
Under standard parameters settings the following solutions will be available for various problem types:
Simplex optimizer |
Interior-point optimizer |
Mixed-integer optimizer |
|
Linear problem |
|||
Nonlinear continuous problem |
|||
Problem with integer variables |
For linear problems the user can force a specific optimizer choice making only one of the two solutions available. For example, if the user disables basis identification, then only the interior point solution will be available for a linear problem. Numerical issues may cause one of the solutions to be unknown even if another one is feasible.
Not all components of a solution are always available. For example, there is no dual solution for integer problems and no dual conic variables from the simplex optimizer.
The user will always need to specify which solution should be accessed.
7.2.3 Problem and solution status¶
Assuming that the optimization terminated without errors, the next important step is to check the problem and solution status. There is one for every type of solution, as explained above.
Problem status
Problem status (prosta
) determines whether the problem is certified as feasible. Its values can roughly be divided into the following broad categories:
feasible — the problem is feasible. For continuous problems and when the solver is run with default parameters, the feasibility status should ideally be
prosta.prim_and_dual_feas
.primal/dual infeasible — the problem is infeasible or unbounded or a combination of those. The exact problem status will indicate the type of infeasibility.
unknown — the solver was unable to reach a conclusion, most likely due to numerical issues.
Solution status
Solution status (solsta
) provides the information about what the solution values actually contain. The most important broad categories of values are:
optimal (
solsta.optimal
) — the solution values are feasible and optimal.certificate — the solution is in fact a certificate of infeasibility (primal or dual, depending on the solution).
unknown/undefined — the solver could not solve the problem or this type of solution is not available for a given problem.
Problem and solution status for each solution can be retrieved with Task.getprosta
and Task.getsolsta
, respectively.
The solution status determines the action to be taken. For example, in some cases a suboptimal solution may still be valuable and deserve attention. It is the user’s responsibility to check the status and quality of the solution.
Typical status reports
Here are the most typical optimization outcomes described in terms of the problem and solution statuses. Note that these do not cover all possible situations that can occur.
Outcome |
Problem status |
Solution status |
---|---|---|
Optimal |
||
Primal infeasible |
||
Dual infeasible (unbounded) |
||
Uncertain (stall, numerical issues, etc.) |
Outcome |
Problem status |
Solution status |
---|---|---|
Integer optimal |
||
Infeasible |
||
Integer feasible point |
||
No conclusion |
7.2.4 Retrieving solution values¶
After the meaning and quality of the solution (or certificate) have been established, we can query for the actual numerical values. They can be accessed using:
Task.getprimalobj
,Task.getdualobj
— the primal and dual objective value.Task.getxx
— solution values for the variables.Task.getsolution
— a full solution with primal and dual values
and many more specialized methods, see the API reference.
7.2.5 Source code example¶
Below is a source code example with a simple framework for assessing and retrieving the solution to a conic optimization problem.
using System;
using mosek;
using System.Text;
namespace mosek.example
{
// A log handler class
class msgclass : mosek.Stream
{
public msgclass () {}
public override void streamCB (string msg) { Console.Write ("{0}", msg); }
}
public class response
{
public static void Main(string[] argv)
{
StringBuilder symname = new StringBuilder();
StringBuilder desc = new StringBuilder();
string filename;
if (argv.Length >= 1) filename = argv[0];
else filename = "../data/cqo1.mps";
// Define environment and task
using (Env env = new Env())
{
using (Task task = new Task(env, 0, 0))
{
try
{
// (Optionally) set a log handler
// task.set_Stream (streamtype.log, new msgclass ());
// (Optionally) uncomment this to get solution status unknown
// task.putintparam(iparam.intpnt_max_iterations, 1);
// In this example we read data from a file
task.readdata(filename);
// Perform optimization
rescode trm = task.optimize();
task.solutionsummary(streamtype.log);
// Handle solution status. We expect Optimal
solsta solsta = task.getsolsta(soltype.itr);
switch ( solsta )
{
case solsta.optimal:
// Optimal solution. Print variable values
Console.WriteLine("An optimal interior-point solution is located.");
int numvar = task.getnumvar();
double[] xx = new double[numvar];
task.getxx(soltype.itr, xx);
for(int i = 0; i < numvar; i++)
Console.WriteLine("x[" + i + "] = " + xx[i]);
break;
case solsta.dual_infeas_cer:
Console.WriteLine("Dual infeasibility certificate found.");
break;
case solsta.prim_infeas_cer:
Console.WriteLine("Primal infeasibility certificate found.");
break;
case solsta.unknown:
/* The solutions status is unknown. The termination code
indicates why the optimizer terminated prematurely. */
Console.WriteLine("The solution status is unknown.");
Env.getcodedesc(trm, symname, desc);
Console.WriteLine(" Termination code: {0} {1}", symname, desc);
break;
default:
Console.WriteLine("An unexpected solution status " + solsta);
break;
}
}
catch (mosek.Error e)
{
Console.WriteLine("Unexpected optimization error ({0}) {1}", e.Code, e.Message);
}
}
}
}
}
}