8.2 Errors and exceptions¶
Exceptions
Almost every method in Fusion API for C++ can throw an exception informing that the requested operation was not performed correctly, and indicating the type of error that occurred. This is the case in situations such as for instance:
incompatible dimensions in a linear expression,
defining an invalid value for a parameter,
accessing an undefined solution,
repeating a variable name, etc.
It is therefore a good idea to catch exceptions of type FusionException
and its specific subclasses. The one case where it is extremely important to do so is when Model.solve
is invoked. We will say more about this in Sec. 8.1 (Accessing the solution).
The exception contains a short diagnostic message. They can be accessed as in the following example.
try {
M->setSolverParam("intpntCoTolRelGap", 1.01);
} catch (mosek::fusion::ParameterError& e) {
std::cout << "Error: " << e.toString() << "\n";
}
It will produce as output:
Error: Invalid value for parameter (intpntCoTolRelGap)
Optimizer errors and warnings
The optimizer may also produce warning messages. They indicate non-critical but important events, that will not prevent solver execution, but may be an indication that something in the optimization problem might be improved. Warning messages are normally printed to a log stream (see Sec. 8.3 (Input/Output)). A typical warning is, for example:
MOSEK warning 53: A numerically large upper bound value 6.6e+09 is specified for constraint 'C69200' (46020).
Error and solution status handling example
Below is a source code example with a simple framework for handling major errors when assessing and retrieving the solution to a conic optimization problem.
int main(int arc, char** argv)
{
Model::t M = new Model(); auto _M = finally([&]() { M->dispose(); });
// (Optional) set a log stream
// M->setLogHandler([](const std::string & msg) { std::cout << msg << std::flush; });
// (Optional) uncomment to see what happens when solution status is unknown
// M->setSolverParam("intpntMaxIterations", 1);
// In this example we set up a small conic problem
setupExample(M);
// Optimize
try
{
M->solve();
// We expect solution status OPTIMAL (this is also default)
M->acceptedSolutionStatus(AccSolutionStatus::Optimal);
auto x = M->getVariable("x");
auto xsize = x->getSize();
auto xVal = x->level();
std::cout << "Optimal value of x = ";
for(int i = 0; i < xsize; ++i)
std::cout << (*xVal)[i] << " ";
std::cout << "\nOptimal primal objective: " << M->primalObjValue() <<"\n";
// .. continue analyzing the solution
}
catch (const OptimizeError& e)
{
std::cout << "Optimization failed. Error: " << e.what() << "\n";
}
catch (const SolutionError& e)
{
// The solution with at least the expected status was not available.
// We try to diagnoze why.
std::cout << "Requested solution was not available.\n";
auto prosta = M->getProblemStatus();
switch(prosta)
{
case ProblemStatus::DualInfeasible:
std::cout << "Dual infeasibility certificate found.\n";
break;
case ProblemStatus::PrimalInfeasible:
std::cout << "Primal infeasibility certificate found.\n";
break;
case ProblemStatus::Unknown:
// The solutions status is unknown. The termination code
// indicates why the optimizer terminated prematurely.
std::cout << "The solution status is unknown.\n";
char symname[MSK_MAX_STR_LEN];
char desc[MSK_MAX_STR_LEN];
MSK_getcodedesc((MSKrescodee)(M->getSolverIntInfo("optimizeResponse")), symname, desc);
std::cout << " Termination code: " << symname << " " << desc << "\n";
break;
default:
std::cout << "Another unexpected problem status: " << prosta << "\n";
}
}
catch (const std::exception& e)
{
std::cerr << "Unexpected error: " << e.what() << "\n";
}
M->dispose();
return 0;
}