integrate sonar suggestions

This commit is contained in:
Peter Mitri
2023-10-16 17:12:07 +02:00
committed by Andrea Sgattoni
parent c47674f98c
commit 78d042e4a3

View File

@@ -14,15 +14,12 @@
// Initial version of this code was provided by RTE
#include <algorithm>
#include <cctype>
#include <clocale>
#include <cstdint>
#include <fstream>
#include <istream>
#include <limits>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include "absl/strings/str_format.h"
@@ -37,8 +34,6 @@
#define XPRS_CONTINUOUS 'C'
#define XPRS_NAMES_ROW 1
#define XPRS_NAMES_COLUMN 2
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
// The argument to this macro is the invocation of a XPRS function that
// returns a status. If the function returns non-zero the macro aborts
@@ -49,7 +44,6 @@
CHECK_EQ(0, status_); \
} while (0)
namespace operations_research {
std::string getSolverVersion(XPRSprob const& prob) {
// XPRS_VERSION gives the version number as MAJOR*100 + RELEASE.
@@ -165,31 +159,31 @@ void XPRS_CC XpressIntSolCallbackImpl(XPRSprob cbprob, void* cbdata);
void XPRS_CC optimizermsg(XPRSprob prob, void* data, const char* sMsg, int nLen,
int nMsgLvl);
int XPRSgetnumcols(const XPRSprob& mLp) {
int getnumcols(const XPRSprob& mLp) {
int nCols = 0;
XPRSgetintattrib(mLp, XPRS_COLS, &nCols);
return nCols;
}
int XPRSgetnumrows(const XPRSprob& mLp) {
int getnumrows(const XPRSprob& mLp) {
int nRows = 0;
XPRSgetintattrib(mLp, XPRS_ROWS, &nRows);
return nRows;
}
int XPRSgetitcnt(const XPRSprob& mLp) {
int getitcnt(const XPRSprob& mLp) {
int nIters = 0;
XPRSgetintattrib(mLp, XPRS_SIMPLEXITER, &nIters);
return nIters;
}
int XPRSgetnodecnt(const XPRSprob& mLp) {
int getnodecnt(const XPRSprob& mLp) {
int nNodes = 0;
XPRSgetintattrib(mLp, XPRS_NODES, &nNodes);
return nNodes;
}
int XPRSsetobjoffset(const XPRSprob& mLp, double value) {
int setobjoffset(const XPRSprob& mLp, double value) {
// TODO detect xpress version
static int indexes[1] = {-1};
double values[1] = {-value};
@@ -197,7 +191,7 @@ int XPRSsetobjoffset(const XPRSprob& mLp, double value) {
return 0;
}
void XPRSaddhint(const XPRSprob& mLp, int length, const double solval[],
void addhint(const XPRSprob& mLp, int length, const double solval[],
const int colind[]) {
// The OR-Tools API does not allow setting a name for the solution
// passing NULL to XPRESS will have it generate a unique ID for the solution
@@ -298,51 +292,51 @@ class MPCallbackWrapper {
};
// For a model that is extracted to an instance of this class there is a
// 1:1 corresponence between MPVariable instances and XPRESS columns: the
// 1:1 correspondence between MPVariable instances and XPRESS columns: the
// index of an extracted variable is the column index in the XPRESS model.
// Similar for instances of MPConstraint: the index of the constraint in
// the model is the row index in the XPRESS model.
class XpressInterface : public MPSolverInterface {
public:
// NOTE: 'mip' specifies the type of the problem (either continuous or
// mixed integer. This type is fixed for the lifetime of the
// mixed integer). This type is fixed for the lifetime of the
// instance. There are no dynamic changes to the model type.
explicit XpressInterface(MPSolver* const solver, bool mip);
~XpressInterface();
explicit XpressInterface(MPSolver* solver, bool mip);
~XpressInterface() override;
// Sets the optimization direction (min/max).
virtual void SetOptimizationDirection(bool maximize);
void SetOptimizationDirection(bool maximize) override;
// ----- Solve -----
// Solve the problem using the parameter values specified.
virtual MPSolver::ResultStatus Solve(MPSolverParameters const& param);
MPSolver::ResultStatus Solve(MPSolverParameters const& param) override;
// Writes the model.
void Write(const std::string& filename) override;
// ----- Model modifications and extraction -----
// Resets extracted model
virtual void Reset();
void Reset() override;
virtual void SetVariableBounds(int var_index, double lb, double ub);
virtual void SetVariableInteger(int var_index, bool integer);
virtual void SetConstraintBounds(int row_index, double lb, double ub);
void SetVariableBounds(int var_index, double lb, double ub) override;
void SetVariableInteger(int var_index, bool integer) override;
void SetConstraintBounds(int row_index, double lb, double ub) override;
virtual void AddRowConstraint(MPConstraint* const ct);
virtual void AddVariable(MPVariable* const var);
virtual void SetCoefficient(MPConstraint* const constraint,
MPVariable const* const variable,
double new_value, double old_value);
void AddRowConstraint(MPConstraint* ct) override;
void AddVariable(MPVariable* var) override;
void SetCoefficient(MPConstraint* constraint,
MPVariable const* variable, double new_value,
double old_value) override;
// Clear a constraint from all its terms.
virtual void ClearConstraint(MPConstraint* const constraint);
void ClearConstraint(MPConstraint* constraint) override;
// Change a coefficient in the linear objective
virtual void SetObjectiveCoefficient(MPVariable const* const variable,
double coefficient);
void SetObjectiveCoefficient(MPVariable const* variable,
double coefficient) override;
// Change the constant term in the linear objective.
virtual void SetObjectiveOffset(double value) override;
void SetObjectiveOffset(double value) override;
// Clear the objective from all its terms.
virtual void ClearObjective();
void ClearObjective() override;
// ------ Query statistics on the solution and the solve ------
// Number of simplex iterations
@@ -351,18 +345,18 @@ class XpressInterface : public MPSolverInterface {
virtual int64_t nodes() const;
// Returns the basis status of a row.
virtual MPSolver::BasisStatus row_status(int constraint_index) const;
MPSolver::BasisStatus row_status(int constraint_index) const override;
// Returns the basis status of a column.
virtual MPSolver::BasisStatus column_status(int variable_index) const;
MPSolver::BasisStatus column_status(int variable_index) const override;
// ----- Misc -----
// Query problem type.
// Remember that problem type is a static property that is set
// in the constructor and never changed.
virtual bool IsContinuous() const { return IsLP(); }
virtual bool IsLP() const { return !mMip; }
virtual bool IsMIP() const { return mMip; }
bool IsContinuous() const override { return IsLP(); }
bool IsLP() const override { return !mMip; }
bool IsMIP() const override { return mMip; }
void SetStartingLpBasisInt(
const std::vector<int>& variable_statuses,
@@ -465,7 +459,7 @@ class XpressInterface : public MPSolverInterface {
SlowUpdatesAll = 0xffff
} const slowUpdates;
// XPRESS has no method to query the basis status of a single variable.
// Hence we query the status only once and cache the array. This is
// Hence, we query the status only once and cache the array. This is
// much faster in case the basis status of more than one row/column
// is required.
std::vector<int> mutable mCstat;
@@ -474,14 +468,14 @@ class XpressInterface : public MPSolverInterface {
std::vector<int> mutable initCstat;
std::vector<int> mutable initRstat;
// Setup the right-hand side of a constraint from its lower and upper bound.
// Set up the right-hand side of a constraint from its lower and upper bound.
static void MakeRhs(double lb, double ub, double& rhs, char& sense,
double& range);
std::map<std::string, int>& mapStringControls_;
std::map<std::string, int>& mapDoubleControls_;
std::map<std::string, int>& mapIntegerControls_;
std::map<std::string, int>& mapInteger64Controls_;
std::map<std::string, int> &mapStringControls_;
std::map<std::string, int> &mapDoubleControls_;
std::map<std::string, int> &mapIntegerControls_;
std::map<std::string, int> &mapInteger64Controls_;
bool SetSolverSpecificParametersAsString(
const std::string& parameters) override;
@@ -839,10 +833,10 @@ static std::map<std::string, int>& getMapInt64Controls() {
return mapControls;
}
// Creates a LP/MIP instance.
// Creates an LP/MIP instance.
XpressInterface::XpressInterface(MPSolver* const solver, bool mip)
: MPSolverInterface(solver),
mLp(0),
mLp(nullptr),
mMip(mip),
supportIncrementalExtraction(false),
slowUpdates(static_cast<SlowUpdates>(SlowSetObjectiveCoefficient |
@@ -856,7 +850,7 @@ XpressInterface::XpressInterface(MPSolver* const solver, bool mip)
int status = XPRScreateprob(&mLp);
CHECK_STATUS(status);
DCHECK(mLp != nullptr); // should not be NULL if status=0
int nReturn = XPRSsetcbmessage(mLp, optimizermsg, (void*)this);
int nReturn=XPRSaddcbmessage(mLp, optimizermsg, (void*) this, 0);
CHECK_STATUS(XPRSloadlp(mLp, "newProb", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
CHECK_STATUS(
XPRSchgobjsense(mLp, maximize_ ? XPRS_OBJ_MAXIMIZE : XPRS_OBJ_MINIMIZE));
@@ -896,7 +890,7 @@ void XpressInterface::Reset() {
status = XPRScreateprob(&mLp);
CHECK_STATUS(status);
DCHECK(mLp != nullptr); // should not be NULL if status=0
int nReturn = XPRSsetcbmessage(mLp, optimizermsg, (void*)this);
int nReturn = XPRSaddcbmessage(mLp, optimizermsg, (void*)this, 0);
CHECK_STATUS(XPRSloadlp(mLp, "newProb", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
CHECK_STATUS(
@@ -919,7 +913,7 @@ void XpressInterface::SetVariableBounds(int var_index, double lb, double ub) {
// many variables may still be slow. So we don't perform the update by
// default. However, if we support incremental extraction
// (supportIncrementalExtraction is true) then we MUST perform the
// update here or we will lose it.
// update here, or we will lose it.
if (!supportIncrementalExtraction && !(slowUpdates & SlowSetVariableBounds)) {
InvalidateModelSynchronization();
@@ -963,7 +957,7 @@ void XpressInterface::SetVariableInteger(int var_index, bool integer) {
// Variable is extracted. Change the type immediately.
// TODO: Should we check the current type and don't do anything
// in case the type does not change?
DCHECK_LE(var_index, XPRSgetnumcols(mLp));
DCHECK_LE(var_index, getnumcols(mLp));
char const type = integer ? XPRS_INTEGER : XPRS_CONTINUOUS;
CHECK_STATUS(XPRSchgcoltype(mLp, 1, &var_index, &type));
} else {
@@ -976,7 +970,7 @@ void XpressInterface::SetVariableInteger(int var_index, bool integer) {
}
}
// Setup the right-hand side of a constraint.
// Set up the right-hand side of a constraint.
void XpressInterface::MakeRhs(double lb, double ub, double& rhs, char& sense,
double& range) {
if (lb == ub) {
@@ -991,6 +985,7 @@ void XpressInterface::MakeRhs(double lb, double ub, double& rhs, char& sense,
// Xpress does not support contradictory bounds. Instead the sign on
// rndval is always ignored.
if (lb > ub) {
// TODO check if this is ok for the user
LOG(DFATAL) << "XPRESS does not support contradictory bounds on range "
"constraints! ["
<< lb << ", " << ub << "] will be converted to " << ub << ", "
@@ -1046,7 +1041,7 @@ void XpressInterface::SetConstraintBounds(int index, double lb, double ub) {
if (constraint_is_extracted(index)) {
// Constraint is already extracted, so we must update its bounds
// and its type.
DCHECK(mLp != NULL);
DCHECK(mLp != nullptr);
char sense;
double range, rhs;
MakeRhs(lb, ub, rhs, sense, range);
@@ -1083,13 +1078,13 @@ void XpressInterface::AddRowConstraint(MPConstraint* const ct) {
InvalidateModelSynchronization();
}
void XpressInterface::AddVariable(MPVariable* const ct) {
void XpressInterface::AddVariable(MPVariable* const var) {
// This is currently only invoked when a new variable is created,
// see MPSolver::MakeVar().
// At this point the variable does not appear in any constraints or
// the objective function. We could invoke XPRSaddcols() to immediately
// create the variable here but it is usually much faster to handle the
// fully setup variable in ExtractNewVariables() right before the solve.
// create the variable here, but it is usually much faster to handle the
// fully set-up variable in ExtractNewVariables() right before the solve.
// TODO
// Make new variables non-basic at their lower bound (colstat[icol]=0), unless
@@ -1109,7 +1104,7 @@ void XpressInterface::SetCoefficient(MPConstraint* const constraint,
// representation. So by default we don't perform this update immediately
// but instead mark the low-level modeling object "out of sync".
// If we want to support incremental extraction then we MUST perform
// the modification immediately or we will lose it.
// the modification immediately, or we will lose it.
if (!supportIncrementalExtraction && !(slowUpdates & SlowSetCoefficient)) {
InvalidateModelSynchronization();
@@ -1155,8 +1150,8 @@ void XpressInterface::ClearConstraint(MPConstraint* const constraint) {
unique_ptr<double[]> val(new double[len]);
int j = 0;
const auto& coeffs = constraint->coefficients_;
for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {
int const col = it->first->index();
for (auto coeff : coeffs) {
int const col = coeff.first->index();
if (variable_is_extracted(col)) {
rowind[j] = row;
colind[j] = col;
@@ -1195,7 +1190,7 @@ void XpressInterface::SetObjectiveCoefficient(MPVariable const* const variable,
void XpressInterface::SetObjectiveOffset(double value) {
// Changing the objective offset is O(1), so we always do it immediately.
InvalidateSolutionSynchronization();
CHECK_STATUS(XPRSsetobjoffset(mLp, value));
CHECK_STATUS(setobjoffset(mLp, value));
}
void XpressInterface::ClearObjective() {
@@ -1207,13 +1202,13 @@ void XpressInterface::ClearObjective() {
// but to perform the update immediately.
if (supportIncrementalExtraction || (slowUpdates & SlowClearObjective)) {
int const cols = XPRSgetnumcols(mLp);
int const cols = getnumcols(mLp);
unique_ptr<int[]> ind(new int[cols]);
unique_ptr<double[]> zero(new double[cols]);
int j = 0;
const auto& coeffs = solver_->objective_->coefficients_;
for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {
int const idx = it->first->index();
for (auto coeff : coeffs) {
int const idx = coeff.first->index();
// We only need to reset variables that have been extracted.
if (variable_is_extracted(idx)) {
DCHECK_LT(idx, cols);
@@ -1223,7 +1218,7 @@ void XpressInterface::ClearObjective() {
}
}
if (j > 0) CHECK_STATUS(XPRSchgobj(mLp, j, ind.get(), zero.get()));
CHECK_STATUS(XPRSsetobjoffset(mLp, 0.0));
CHECK_STATUS(setobjoffset(mLp, 0.0));
} else {
InvalidateModelSynchronization();
}
@@ -1233,13 +1228,13 @@ void XpressInterface::ClearObjective() {
int64_t XpressInterface::iterations() const {
if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations;
return static_cast<int64_t>(XPRSgetitcnt(mLp));
return static_cast<int64_t>(getitcnt(mLp));
}
int64_t XpressInterface::nodes() const {
if (mMip) {
if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes;
return static_cast<int64_t>(XPRSgetnodecnt(mLp));
return static_cast<int64_t>(getnodecnt(mLp));
} else {
LOG(DFATAL) << "Number of nodes only available for discrete problems";
return kUnknownNumberOfNodes;
@@ -1289,7 +1284,7 @@ MPSolver::BasisStatus XpressInterface::row_status(int constraint_index) const {
if (CheckSolutionIsSynchronized()) {
if (mRstat.empty()) {
int const rows = XPRSgetnumrows(mLp);
int const rows = getnumrows(mLp);
mRstat.resize(rows);
CHECK_STATUS(XPRSgetbasis(mLp, mRstat.data(), 0));
}
@@ -1314,7 +1309,7 @@ MPSolver::BasisStatus XpressInterface::column_status(int variable_index) const {
if (CheckSolutionIsSynchronized()) {
if (mCstat.empty()) {
int const cols = XPRSgetnumcols(mLp);
int const cols = getnumcols(mLp);
mCstat.resize(cols);
CHECK_STATUS(XPRSgetbasis(mLp, 0, mCstat.data()));
}
@@ -1348,30 +1343,30 @@ void XpressInterface::ExtractNewVariables() {
int const last_extracted = last_variable_index_;
int const var_count = solver_->variables_.size();
int newcols = var_count - last_extracted;
if (newcols > 0) {
int new_col_count = var_count - last_extracted;
if (new_col_count > 0) {
// There are non-extracted variables. Extract them now.
unique_ptr<double[]> obj(new double[newcols]);
unique_ptr<double[]> lb(new double[newcols]);
unique_ptr<double[]> ub(new double[newcols]);
unique_ptr<char[]> ctype(new char[newcols]);
std::vector<char> colnames;
unique_ptr<double[]> obj(new double[new_col_count]);
unique_ptr<double[]> lb(new double[new_col_count]);
unique_ptr<double[]> ub(new double[new_col_count]);
unique_ptr<char[]> ctype(new char[new_col_count]);
std::vector<char> col_names;
bool have_names = false;
for (int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) {
MPVariable const* const var = solver_->variables_[varidx];
for (int j = 0, var_idx = last_extracted; j < new_col_count; ++j, ++var_idx) {
MPVariable const* const var = solver_->variables_[var_idx];
lb[j] = var->lb();
ub[j] = var->ub();
ctype[j] = var->integer() ? XPRS_INTEGER : XPRS_CONTINUOUS;
std::copy(var->name().begin(), var->name().end(),
std::back_inserter(colnames));
colnames.push_back('\0');
std::back_inserter(col_names));
col_names.push_back('\0');
have_names = have_names || !var->name().empty();
obj[j] = solver_->objective_->GetCoefficient(var);
}
// Arrays for modifying the problem are setup. Update the index
// Arrays for modifying the problem are set up. Update the index
// of variables that will get extracted now. Updating indices
// _before_ the actual extraction makes things much simpler in
// case we support incremental extraction.
@@ -1383,7 +1378,7 @@ void XpressInterface::ExtractNewVariables() {
}
try {
bool use_newcols = true;
bool use_new_cols = true;
if (supportIncrementalExtraction) {
// If we support incremental extraction then we must
@@ -1394,8 +1389,8 @@ void XpressInterface::ExtractNewVariables() {
// For each column count the size of the intersection with
// existing constraints.
unique_ptr<int[]> collen(new int[newcols]);
for (int j = 0; j < newcols; ++j) collen[j] = 0;
unique_ptr<int[]> collen(new int[new_col_count]);
for (int j = 0; j < new_col_count; ++j) collen[j] = 0;
int nonzeros = 0;
// TODO: Use a bitarray to flag the constraints that actually
// intersect new variables?
@@ -1403,8 +1398,8 @@ void XpressInterface::ExtractNewVariables() {
MPConstraint const* const ct = solver_->constraints_[i];
CHECK(constraint_is_extracted(ct->index()));
const auto& coeffs = ct->coefficients_;
for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {
int const idx = it->first->index();
for (auto coeff : coeffs) {
int const idx = coeff.first->index();
if (variable_is_extracted(idx) && idx > last_variable_index_) {
collen[idx - last_variable_index_]++;
++nonzeros;
@@ -1416,83 +1411,84 @@ void XpressInterface::ExtractNewVariables() {
// At least one of the new variables did intersect with an
// old constraint. We have to create the new columns via
// XPRSaddcols().
use_newcols = false;
unique_ptr<int[]> begin(new int[newcols + 2]);
use_new_cols = false;
unique_ptr<int[]> begin(new int[new_col_count + 2]);
unique_ptr<int[]> cmatind(new int[nonzeros]);
unique_ptr<double[]> cmatval(new double[nonzeros]);
// Here is how cmatbeg[] is setup:
// Here is how cmatbeg[] is set up:
// - it is initialized as
// [ 0, 0, collen[0], collen[0]+collen[1], ... ]
// so that cmatbeg[j+1] tells us where in cmatind[] and
// cmatval[] we need to put the next nonzero for column
// j
// - after nonzeros have been setup the array looks like
// - after nonzeros have been set up, the array looks like
// [ 0, collen[0], collen[0]+collen[1], ... ]
// so that it is the correct input argument for XPRSaddcols
int* cmatbeg = begin.get();
cmatbeg[0] = 0;
cmatbeg[1] = 0;
++cmatbeg;
for (int j = 0; j < newcols; ++j)
for (int j = 0; j < new_col_count; ++j)
cmatbeg[j + 1] = cmatbeg[j] + collen[j];
for (int i = 0; i < last_constraint_index_; ++i) {
MPConstraint const* const ct = solver_->constraints_[i];
int const row = ct->index();
const auto& coeffs = ct->coefficients_;
for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {
int const idx = it->first->index();
for (auto coeff : coeffs) {
int const idx = coeff.first->index();
if (variable_is_extracted(idx) && idx > last_variable_index_) {
int const nz = cmatbeg[idx]++;
cmatind[nz] = row;
cmatval[nz] = it->second;
cmatval[nz] = coeff.second;
}
}
}
--cmatbeg;
CHECK_STATUS(XPRSaddcols(mLp, newcols, nonzeros, obj.get(), cmatbeg,
CHECK_STATUS(XPRSaddcols(mLp, new_col_count, nonzeros, obj.get(), cmatbeg,
cmatind.get(), cmatval.get(), lb.get(),
ub.get()));
if (have_names) {
CHECK_STATUS(XPRSaddnames(mLp, XPRS_NAMES_COLUMN, colnames.data(),
0, newcols - 1));
CHECK_STATUS(XPRSaddnames(mLp, XPRS_NAMES_COLUMN, col_names.data(),
0, new_col_count - 1));
}
}
}
if (use_newcols) {
if (use_new_cols) {
// Either incremental extraction is not supported or none of
// the new variables did intersect an existing constraint.
// We can just use XPRSnewcols() to create the new variables.
std::vector<int> collen(newcols, 0);
std::vector<int> cmatbeg(newcols, 0);
std::vector<int> collen(new_col_count, 0);
std::vector<int> cmatbeg(new_col_count, 0);
unique_ptr<int[]> cmatind(new int[1]);
unique_ptr<double[]> cmatval(new double[1]);
cmatind[0] = 0;
cmatval[0] = 1.0;
CHECK_STATUS(XPRSaddcols(mLp, newcols, 0, obj.get(), cmatbeg.data(),
CHECK_STATUS(XPRSaddcols(mLp, new_col_count, 0, obj.get(), cmatbeg.data(),
cmatind.get(), cmatval.get(), lb.get(),
ub.get()));
if (have_names) {
CHECK_STATUS(XPRSaddnames(mLp, XPRS_NAMES_COLUMN, colnames.data(), 0,
newcols - 1));
CHECK_STATUS(XPRSaddnames(mLp, XPRS_NAMES_COLUMN, col_names.data(), 0,
new_col_count - 1));
}
int const cols = XPRSgetnumcols(mLp);
unique_ptr<int[]> ind(new int[newcols]);
int const cols = getnumcols(mLp);
unique_ptr<int[]> ind(new int[new_col_count]);
for (int j = 0; j < cols; ++j) ind[j] = j;
CHECK_STATUS(
XPRSchgcoltype(mLp, cols - last_extracted, ind.get(), ctype.get()));
} else {
// Incremental extraction: we must update the ctype of the
// newly created variables (XPRSaddcols() does not allow
// specifying the ctype)
if (mMip && XPRSgetnumcols(mLp) > 0) {
if (mMip && getnumcols(mLp) > 0) {
// Query the actual number of columns in case we did not
// manage to extract all columns.
int const cols = XPRSgetnumcols(mLp);
unique_ptr<int[]> ind(new int[newcols]);
int const cols = getnumcols(mLp);
unique_ptr<int[]> ind(new int[new_col_count]);
for (int j = last_extracted; j < cols; ++j)
ind[j - last_extracted] = j;
CHECK_STATUS(XPRSchgcoltype(mLp, cols - last_extracted, ind.get(),
@@ -1501,11 +1497,11 @@ void XpressInterface::ExtractNewVariables() {
}
} catch (...) {
// Undo all changes in case of error.
int const cols = XPRSgetnumcols(mLp);
int const cols = getnumcols(mLp);
if (cols > last_extracted) {
std::vector<int> colsToDelete;
for (int i = last_extracted; i < cols; ++i) colsToDelete.push_back(i);
(void)XPRSdelcols(mLp, colsToDelete.size(), colsToDelete.data());
std::vector<int> cols_to_delete;
for (int i = last_extracted; i < cols; ++i) cols_to_delete.push_back(i);
(void)XPRSdelcols(mLp, cols_to_delete.size(), cols_to_delete.data());
}
std::vector<MPVariable*> const& variables = solver_->variables();
int const size = variables.size();
@@ -1538,8 +1534,7 @@ void XpressInterface::ExtractNewConstraints() {
InvalidateSolutionSynchronization();
int newCons = total - offset;
int const cols = XPRSgetnumcols(mLp);
DCHECK_EQ(last_variable_index_, cols);
int const cols = getnumcols(mLp);
int const chunk = newCons; // 10; // max number of rows to add in one shot
// Update indices of new constraints _before_ actually extracting
@@ -1584,13 +1579,13 @@ void XpressInterface::ExtractNewConstraints() {
// Setup left-hand side of constraint.
rmatbeg[nextRow] = nextNz;
const auto& coeffs = ct->coefficients_;
for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {
int const idx = it->first->index();
for (auto coeff : coeffs) {
int const idx = coeff.first->index();
if (variable_is_extracted(idx)) {
DCHECK_LT(nextNz, cols);
DCHECK_LT(idx, cols);
rmatind[nextNz] = idx;
rmatval[nextNz] = it->second;
rmatval[nextNz] = coeff.second;
++nextNz;
}
}
@@ -1618,11 +1613,11 @@ void XpressInterface::ExtractNewConstraints() {
}
} catch (...) {
// Undo all changes in case of error.
int const rows = XPRSgetnumrows(mLp);
std::vector<int> rowsToDelete;
for (int i = offset; i < rows; ++i) rowsToDelete.push_back(i);
int const rows = getnumrows(mLp);
std::vector<int> rows_to_delete;
for (int i = offset; i < rows; ++i) rows_to_delete.push_back(i);
if (rows > offset)
(void)XPRSdelrows(mLp, rowsToDelete.size(), rowsToDelete.data());
(void)XPRSdelrows(mLp, rows_to_delete.size(), rows_to_delete.data());
std::vector<MPConstraint*> const& constraints = solver_->constraints();
int const size = constraints.size();
for (int i = offset; i < size; ++i) set_constraint_as_extracted(i, false);
@@ -1636,7 +1631,7 @@ void XpressInterface::ExtractObjective() {
// NOTE: The code assumes that the objective expression does not contain
// any non-zero duplicates.
int const cols = XPRSgetnumcols(mLp);
int const cols = getnumcols(mLp);
// DCHECK_EQ(last_variable_index_, cols);
unique_ptr<int[]> ind(new int[cols]);
@@ -1647,16 +1642,16 @@ void XpressInterface::ExtractObjective() {
}
const auto& coeffs = solver_->objective_->coefficients_;
for (auto it = coeffs.begin(); it != coeffs.end(); ++it) {
int const idx = it->first->index();
for (auto coeff : coeffs) {
int const idx = coeff.first->index();
if (variable_is_extracted(idx)) {
DCHECK_LT(idx, cols);
val[idx] = it->second;
val[idx] = coeff.second;
}
}
CHECK_STATUS(XPRSchgobj(mLp, cols, ind.get(), val.get()));
CHECK_STATUS(XPRSsetobjoffset(mLp, solver_->Objective().offset()));
CHECK_STATUS(setobjoffset(mLp, solver_->Objective().offset()));
}
// ------ Parameters -----
@@ -1685,8 +1680,7 @@ void XpressInterface::SetDualTolerance(double value) {
}
void XpressInterface::SetPresolveMode(int value) {
MPSolverParameters::PresolveValues const presolve =
static_cast<MPSolverParameters::PresolveValues>(value);
auto const presolve = static_cast<MPSolverParameters::PresolveValues>(value);
switch (presolve) {
case MPSolverParameters::PRESOLVE_OFF:
@@ -1701,8 +1695,7 @@ void XpressInterface::SetPresolveMode(int value) {
// Sets the scaling mode.
void XpressInterface::SetScalingMode(int value) {
MPSolverParameters::ScalingValues const scaling =
static_cast<MPSolverParameters::ScalingValues>(value);
auto const scaling = static_cast<MPSolverParameters::ScalingValues>(value);
switch (scaling) {
case MPSolverParameters::SCALING_OFF:
@@ -1711,9 +1704,9 @@ void XpressInterface::SetScalingMode(int value) {
case MPSolverParameters::SCALING_ON:
CHECK_STATUS(XPRSsetdefaultcontrol(mLp, XPRS_SCALING));
// In Xpress, scaling is not a binary on/off control, but a bit vector
// control setting it to 1 would only enable bit 1. Instead we reset it to
// its default (163 for the current version 8.6) Alternatively, we could
// call CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 163));
// control setting it to 1 would only enable bit 1. Instead, we reset it
// to its default (163 for the current version 8.6) Alternatively, we
// could call CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 163));
break;
}
}
@@ -1721,7 +1714,7 @@ void XpressInterface::SetScalingMode(int value) {
// Sets the LP algorithm : primal, dual or barrier. Note that XPRESS offers
// other LP algorithm (e.g. network) and automatic selection
void XpressInterface::SetLpAlgorithm(int value) {
MPSolverParameters::LpAlgorithmValues const algorithm =
auto const algorithm =
static_cast<MPSolverParameters::LpAlgorithmValues>(value);
int alg = 1;
@@ -1767,8 +1760,8 @@ void XpressInterface::GetFinalLpBasisInt(
return;
}
const int rows = XPRSgetnumrows(mLp);
const int cols = XPRSgetnumcols(mLp);
const int rows = getnumrows(mLp);
const int cols = getnumcols(mLp);
// 1. Resize vectors if needed
variable_statuses.resize(cols);
constraint_statuses.resize(rows);
@@ -1845,9 +1838,8 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
timer.Start();
// Set incrementality
MPSolverParameters::IncrementalityValues const inc =
static_cast<MPSolverParameters::IncrementalityValues>(
param.GetIntegerParam(MPSolverParameters::INCREMENTALITY));
auto const inc = static_cast<MPSolverParameters::IncrementalityValues>(
param.GetIntegerParam(MPSolverParameters::INCREMENTALITY));
switch (inc) {
case MPSolverParameters::INCREMENTALITY_OFF: {
Reset(); // This should not be required but re-extracting everything
@@ -1872,6 +1864,10 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
// Set log level.
XPRSsetintcontrol(mLp, XPRS_OUTPUTLOG, quiet() ? 0 : 1);
// Set parameters.
// NOTE: We must invoke SetSolverSpecificParametersAsString() _first_.
// Its current implementation invokes ReadParameterFile() which in
// turn invokes XPRSreadcopyparam(). The latter will _overwrite_
// all current parameter settings in the environment.
solver_->SetSolverSpecificParametersAsString(
solver_->solver_specific_parameter_string_);
SetParameters(param);
@@ -1879,8 +1875,7 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
// In Xpress, a time limit should usually have a negative sign. With a
// positive sign, the solver will only stop when a solution has been found.
CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_MAXTIME,
-1.0 * solver_->time_limit_in_secs()));
CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_MAXTIME, -1 * solver_->time_limit_in_secs()));
}
// Load basis if present
@@ -1906,19 +1901,19 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
// still allow us to query useful information.
timer.Restart();
int xpressstat = 0;
int xpress_stat = 0;
if (mMip) {
if (this->maximize_)
status = XPRSmaxim(mLp, "g");
else
status = XPRSminim(mLp, "g");
XPRSgetintattrib(mLp, XPRS_MIPSTATUS, &xpressstat);
XPRSgetintattrib(mLp, XPRS_MIPSTATUS, &xpress_stat);
} else {
if (this->maximize_)
status = XPRSmaxim(mLp, "");
else
status = XPRSminim(mLp, "");
XPRSgetintattrib(mLp, XPRS_LPSTATUS, &xpressstat);
XPRSgetintattrib(mLp, XPRS_LPSTATUS, &xpress_stat);
}
if (mp_callback_wrapper != nullptr) {
@@ -1926,9 +1921,9 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
delete mp_callback_wrapper;
}
if (!(mMip ? (xpressstat == XPRS_MIP_OPTIMAL)
: (xpressstat == XPRS_LP_OPTIMAL))) {
XPRSpostsolve(mLp);
if ( ! (mMip ? (xpress_stat == XPRS_MIP_OPTIMAL) : (xpress_stat == XPRS_LP_OPTIMAL)))
{
XPRSpostsolve(mLp);
}
// Disable screen output right after solve
@@ -1942,16 +1937,16 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
VLOG(1) << absl::StrFormat("Solved in %.3f seconds.", timer.Get());
}
VLOG(1) << absl::StrFormat("XPRESS solution status %d.", xpressstat);
VLOG(1) << absl::StrFormat("XPRESS solution status %d.", xpress_stat);
// Figure out what solution we have.
bool const feasible = (mMip ? (xpressstat == XPRS_MIP_OPTIMAL ||
xpressstat == XPRS_MIP_SOLUTION)
: (!mMip && xpressstat == XPRS_LP_OPTIMAL));
bool const feasible = (mMip ? (xpress_stat == XPRS_MIP_OPTIMAL ||
xpress_stat == XPRS_MIP_SOLUTION)
: (!mMip && xpress_stat == XPRS_LP_OPTIMAL));
// Get problem dimensions for solution queries below.
int const rows = XPRSgetnumrows(mLp);
int const cols = XPRSgetnumcols(mLp);
int const rows = getnumrows(mLp);
int const cols = getnumcols(mLp);
DCHECK_EQ(rows, solver_->constraints_.size());
DCHECK_EQ(cols, solver_->variables_.size());
@@ -2044,7 +2039,7 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
// Map XPRESS status to more generic solution status in MPSolver
if (mMip) {
switch (xpressstat) {
switch (xpress_stat) {
case XPRS_MIP_OPTIMAL:
result_status_ = MPSolver::OPTIMAL;
break;
@@ -2059,7 +2054,7 @@ MPSolver::ResultStatus XpressInterface::Solve(MPSolverParameters const& param) {
break;
}
} else {
switch (xpressstat) {
switch (xpress_stat) {
case XPRS_LP_OPTIMAL:
result_status_ = MPSolver::OPTIMAL;
break;
@@ -2120,21 +2115,21 @@ struct ScopedLocale {
const char* oldLocale;
};
#define setParamIfPossible_MACRO(targetMap, setter, converter) \
{ \
auto matchingParamIter = targetMap.find(paramAndValuePair.first); \
if (matchingParamIter != targetMap.end()) { \
const auto convertedValue = converter(paramAndValuePair.second); \
VLOG(1) << "Setting parameter " << paramAndValuePair.first \
<< " to value " << convertedValue << std::endl; \
setter(mLp, matchingParamIter->second, convertedValue); \
continue; \
} \
#define setParamIfPossible_MACRO(target_map, setter, converter) \
{ \
auto matchingParamIter = (target_map).find(paramAndValuePair.first); \
if (matchingParamIter != (target_map).end()) { \
const auto convertedValue = converter(paramAndValuePair.second); \
VLOG(1) << "Setting parameter " << paramAndValuePair.first \
<< " to value " << convertedValue << std::endl; \
setter(mLp, matchingParamIter->second, convertedValue); \
continue; \
} \
}
bool XpressInterface::SetSolverSpecificParametersAsString(const std::string& parameters)
{
if (parameters.empty()) return true;
bool XpressInterface::SetSolverSpecificParametersAsString(
const std::string& parameters) {
if (parameters.empty()) return true;
std::vector<std::pair<std::string, std::string> > paramAndValuePairList;
@@ -2166,34 +2161,33 @@ bool XpressInterface::SetSolverSpecificParametersAsString(const std::string& par
return true;
}
/**********************************************************************************\
* Name: optimizermsg *
* Purpose: Display Optimizer error messages and warnings. *
* Arguments: const char *sMsg Message string *
* int nLen Message length *
* int nMsgLvl Message type *
* Return Value: None *
\**********************************************************************************/
void XPRS_CC optimizermsg(XPRSprob prob, void* data, const char *sMsg, int nLen, int nMsgLvl)
{
operations_research::XpressInterface * xprs = reinterpret_cast<operations_research::XpressInterface*>(data);
if (!xprs->quiet()) {
switch (nMsgLvl) {
/* Print Optimizer error messages and warnings */
case 4: /* error */
case 3: /* warning */
/* Ignore other messages */
case 2: /* dialogue */
case 1: /* information */
printf("%*s\n", nLen, sMsg);
break;
/* Exit and flush buffers */
default:
fflush(NULL);
break;
}
}
/*****************************************************************************\
* Name: optimizermsg
* Purpose: Display Optimizer error messages and warnings.
* Arguments: const char *sMsg Message string
* int nLen Message length
* int nMsgLvl Message type
* Return Value: None
\*****************************************************************************/
void XPRS_CC optimizermsg(XPRSprob prob, void* data, const char* sMsg, int nLen,
int nMsgLvl) {
auto* xprs = reinterpret_cast<operations_research::XpressInterface*>(data);
if (!xprs->quiet()) {
switch (nMsgLvl) {
/* Print Optimizer error messages and warnings */
case 4: /* error */
case 3: /* warning */
/* Ignore other messages */
case 2: /* dialogue */
case 1: /* information */
printf("%*s\n", nLen, sMsg);
break;
/* Exit and flush buffers */
default:
fflush(nullptr);
break;
}
}
}
void XpressInterface::AddSolutionHintToOptimizer() {
@@ -2203,14 +2197,14 @@ void XpressInterface::AddSolutionHintToOptimizer() {
// hint is empty, nothing to do
return;
}
unique_ptr<int[]> colind(new int[len]);
unique_ptr<int[]> col_ind(new int[len]);
unique_ptr<double[]> val(new double[len]);
for (std::size_t i = 0; i < len ; ++i) {
colind[i] = solver_->solution_hint_[i].first->index();
col_ind[i] = solver_->solution_hint_[i].first->index();
val[i] = solver_->solution_hint_[i].second;
}
XPRSaddhint(mLp, len, val.get(), colind.get());
addhint(mLp, len, val.get(), col_ind.get());
}
void XpressInterface::SetCallback(MPCallback* mp_callback) {
@@ -2235,7 +2229,7 @@ void XPRS_CC XpressIntSolCallbackImpl(XPRSprob cbprob, void* cbdata) {
try {
std::unique_ptr<XpressMPCallbackContext> cb_context =
std::make_unique<XpressMPCallbackContext>(
&cbprob, MPCallbackEvent::kMipSolution, XPRSgetnodecnt(cbprob));
&cbprob, MPCallbackEvent::kMipSolution, getnodecnt(cbprob));
callback_with_context->GetCallback()->RunCallback(cb_context.get());
} catch (std::exception&) {
callback_with_context->CatchException(cbprob);
@@ -2248,7 +2242,7 @@ bool XpressMPCallbackContext::CanQueryVariableValues() {
double XpressMPCallbackContext::VariableValue(const MPVariable* variable) {
if (variable_values_.empty()) {
int num_vars = XPRSgetnumcols(*xprsprob_);
int num_vars = getnumcols(*xprsprob_);
variable_values_.resize(num_vars);
CHECK_STATUS(XPRSgetmipsol(*xprsprob_, variable_values_.data(), 0));
}
@@ -2281,7 +2275,7 @@ double XpressMPCallbackContext::SuggestSolution(
val[i] = value;
++i;
}
XPRSaddhint(*xprsprob_, len, val.get(), colind.get());
addhint(*xprsprob_, len, val.get(), colind.get());
// XPRESS doesn't guarantee if nor when it will test the suggested solution.
// So we return NaN because we can't know the actual objective value.