Support setting solver specific parameters.

We also support reading parameters from a file, even though Xpress does
not support parameter files itself.
The format for parameters is always NAME=VALUE. If set from a string,
settings must be separated by ';'. If read from a file, there can be at
most one setting per line.
This commit is contained in:
Daniel Junglas
2022-11-25 08:58:56 +01:00
parent 9886fbdd40
commit c6c430c627

View File

@@ -19,6 +19,10 @@
#include <limits>
#include <memory>
#include <string>
#include <sstream>
#include <istream>
#include <fstream>
#include <cctype>
#include "absl/strings/str_format.h"
#include "ortools/base/integral_types.h"
@@ -183,6 +187,8 @@ class XpressInterface : public MPSolverInterface {
return 0.0;
}
virtual bool SetSolverSpecificParametersAsString(const std::string& parameters);
protected:
// Set all parameters in the underlying solver.
virtual void SetParameters(MPSolverParameters const& param);
@@ -210,6 +216,9 @@ class XpressInterface : public MPSolverInterface {
// Transform XPRESS basis status to MPSolver basis status.
static MPSolver::BasisStatus xformBasisStatus(int xpress_basis_status);
bool readParameter(std::string const &name, std::string const &value);
bool readParameters(std::istream &is, char sep);
private:
XPRSprob mLp;
bool const mMip;
@@ -1204,16 +1213,157 @@ void XpressInterface::SetLpAlgorithm(int value) {
}
}
bool XpressInterface::readParameter(std::string const &name, std::string const &value)
{
if (!value.size()) {
LOG(DFATAL) << "Empty value for parameter '" << name << "' in "
<< SolverVersion();
return false;
}
int id, type;
if (XPRSgetcontrolinfo(mLp, name.c_str(), &id, &type) ||
type == XPRS_TYPE_NOTDEFINED)
{
LOG(DFATAL) << "Unknown parameter '" << name << "' in "
<< SolverVersion();
return false;
}
std::stringstream v(value);
switch (type) {
case XPRS_TYPE_INT:
{
int i;
v >> i;
if (!v.eof()) {
LOG(DFATAL) << "Failed to parse value '" << value
<< "' for int parameter '" << name << "' in "
<< SolverVersion();
return false;
}
if (XPRSsetintcontrol(mLp, id, i)) {
LOG(DFATAL) << "Failed to set int parameter '" << name
<< "' to " << value << " (" << i << ") in "
<< SolverVersion();
return false;
}
}
break;
case XPRS_TYPE_INT64:
{
XPRSint64 i;
v >> i;
if (!v.eof()) {
LOG(DFATAL) << "Failed to parse value '" << value
<< "' for int64 parameter '" << name << "' in "
<< SolverVersion();
return false;
}
if (XPRSsetintcontrol64(mLp, id, i)) {
LOG(DFATAL) << "Failed to set int64 parameter '" << name
<< "' to " << value << " (" << i << ") in "
<< SolverVersion();
return false;
}
}
break;
case XPRS_TYPE_DOUBLE:
{
double d;
v >> d;
if (!v.eof()) {
LOG(DFATAL) << "Failed to parse value '" << value
<< "' for dbl parameter '" << name << "' in "
<< SolverVersion();
return false;
}
if (XPRSsetdblcontrol(mLp, id, d)) {
LOG(DFATAL) << "Failed to set double parameter '" << name
<< "' to " << value << " (" << d << ") in "
<< SolverVersion();
return false;
}
}
break;
default:
LOG(DFATAL) << "Unsupported parameter type " << type
<< " for parameter '" << name << "' in "
<< SolverVersion();
return false;
}
return true;
}
bool XpressInterface::readParameters(std::istream &is, char sep) {
// - parameters must be specified as NAME=VALUE
// - settings must be separated by sep
// - any whitespace is ignored
// - string parameters are not supported
std::string name(""), value("");
bool inValue = false;
while (is) {
int c = is.get();
if (is.eof())
break;
if (c == '=') {
if (inValue) {
LOG(DFATAL) << "Failed to parse parameters in " << SolverVersion();
return false;
}
inValue = true;
}
else if (c == sep) {
// End of parameter setting
if (name.size() == 0 && value.size() == 0) {
// Ok to have empty "lines".
continue;
}
if (!readParameter(name, value))
return false;
// Reset for parsing the next parameter setting.
name = "";
value = "";
inValue = false;
}
else if (std::isspace(c)) {
continue;
}
else if (inValue) {
value += (char)c;
}
else {
name += (char)c;
}
}
if (inValue)
return readParameter(name, value);
return true;
}
bool XpressInterface::ReadParameterFile(std::string const& filename) {
// Return true on success and false on error.
LOG(DFATAL) << "ReadParameterFile not implemented for XPRESS interface";
return false;
std::ifstream s(filename);
if ( !s )
return false;
return readParameters(s, '\n');
}
std::string XpressInterface::ValidFileExtensionForParameterFile() const {
return ".prm";
}
bool XpressInterface::SetSolverSpecificParametersAsString(const std::string& parameters) {
if (parameters.empty()) {
return true;
}
std::stringstream s(parameters);
return readParameters(s, ';');
}
MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
int status;