fix model exporter in java/c#

This commit is contained in:
lperron@google.com
2014-04-04 09:13:47 +00:00
parent a9dcc289d6
commit fb6004d487
6 changed files with 87 additions and 37 deletions

View File

@@ -664,10 +664,10 @@ MPSolver::BasisStatus GLPKInterface::TransformGLPKBasisStatus(
// ------ Query statistics on the solution and the solve ------
int64 GLPKInterface::iterations() const {
#if GLP_MINOR_VERSION < 49
#if GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION < 49
if (!mip_ && CheckSolutionIsSynchronized())
return lpx_get_int_parm(lp_, LPX_K_ITCNT);
#elif GLP_MINOR_VERSION >= 53
#elif GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 53
if (!mip_ && CheckSolutionIsSynchronized()) {
return glp_get_it_cnt(lp_);
}

View File

@@ -729,7 +729,7 @@ std::string GurobiInterface::ValidFileExtensionForParameterFile() const {
return ".prm";
}
MPSolverInterface* BuildGurobiInterface(MPSolver* const solver, bool mip) {
MPSolverInterface* BuildGurobiInterface(bool mip, MPSolver* const solver) {
return new GurobiInterface(solver, mip);
}

View File

@@ -335,8 +335,8 @@ extern MPSolverInterface* BuildSCIPInterface(MPSolver* const solver);
extern MPSolverInterface* BuildSLMInterface(MPSolver* const solver, bool mip);
#endif
#if defined(USE_GUROBI)
extern MPSolverInterface* BuildGurobiInterface(MPSolver* const solver,
bool mip);
extern MPSolverInterface* BuildGurobiInterface(bool mip,
MPSolver* const solver);
#endif
@@ -370,9 +370,9 @@ MPSolverInterface* BuildSolverInterface(MPSolver* const solver) {
#endif
#if defined(USE_GUROBI)
case MPSolver::GUROBI_LINEAR_PROGRAMMING:
return BuildGurobiInterface(solver, false);
return BuildGurobiInterface(false, solver);
case MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING:
return BuildGurobiInterface(solver, true);
return BuildGurobiInterface(true, solver);
#endif
default:
// TODO(user): Revert to the best *available* interface.

View File

@@ -63,6 +63,11 @@
%rename (Objective) MutableObjective;
// Access to the underlying solver is available only in C++.
%ignore underlying_solver;
// The ExportModelAs*Format methods return the string directly in the python
// API, using an empty string to indicate failures (which can also indicate an
// empty model).
%ignore ExportModelAsLpFormat(bool, string*);
%ignore ExportModelAsMpsFormat(bool, bool, string*);
namespace operations_research {
%pythoncode {
@@ -535,7 +540,7 @@ namespace operations_research {
%rename (clear) MPObjective::Clear;
%rename (clear) MPSolver::Clear;
%rename (computeExactConditionNumber) MPSolver::ComputeExactConditionNumber;
%rename (loadModel) MPSolver::LoadModel;
%rename (loadModelFromProto) MPSolver::LoadModelFromProto;
%rename (lookupVariableOrNull) MPSolver::LookupVariableOrNull;
%rename (lookupConstraintOrNull) MPSolver::LookupConstraintOrNull;
%rename (makeBoolVar) MPSolver::MakeBoolVar;
@@ -577,6 +582,9 @@ namespace operations_research {
%ignore MPSolver::ExportModel;
%ignore MPSolver::FillSolutionResponse;
%ignore MPSolver::SolveWithProtocolBuffers;
// Ignore export to string methods.
%ignore operations_research::MPSolver::ExportModelAsLpFormat;
%ignore operations_research::MPSolver::ExportModelAsMpsFormat;
// Access to the underlying solver is available only in C++.
%ignore MPSolver::underlying_solver;
@@ -646,6 +654,21 @@ Class c = Class.forName("com.google.ortools.linearsolver.MPSolver");
}
%}
%extend MPSolver {
std::string exportModelAsLpFormat(bool obfuscated) {
std::string output;
if (!self->ExportModelAsLpFormat(obfuscated, &output)) return "";
return output;
}
std::string exportModelAsMpsFormat(bool fixed_format, bool obfuscated) {
std::string output;
if (!self->ExportModelAsMpsFormat(fixed_format, obfuscated, &output)) {
return "";
}
return output;
}
}
} // namespace operations_research
#endif // SWIGJAVA
@@ -689,6 +712,9 @@ namespace operations_research {
// Ignore Objective(), use MutableObjective() instead.
%ignore MPSolver::Objective;
%rename (Objective) MPSolver::MutableObjective;
// Ignore export to string methods.
%ignore operations_research::MPSolver::ExportModelAsLpFormat;
%ignore operations_research::MPSolver::ExportModelAsMpsFormat;
%typemap(cscode) MPVariable %{
public static LinearExpr operator+(Variable a, double v)
@@ -1089,6 +1115,20 @@ namespace operations_research {
Objective().SetMaximization();
Objective().SetCoefficient(var, 1.0);
}
std::string ExportModelAsLpFormat(bool obfuscated) {
std::string output;
if (!self->ExportModelAsLpFormat(obfuscated, &output)) return "";
return output;
}
std::string ExportModelAsMpsFormat(bool fixed_format, bool obfuscated) {
std::string output;
if (!self->ExportModelAsMpsFormat(fixed_format, obfuscated, &output)) {
return "";
}
return output;
}
%}
} // namespace operations_research

View File

@@ -436,6 +436,28 @@ bool MPModelProtoExporter::CanUseFixedMpsFormat() const {
return true;
}
void MPModelProtoExporter::AppendMpsColumns(bool integrality,
const std::vector<std::vector<std::pair<int, double>>>& transpose, std::string* output) {
current_mps_column_ = 0;
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
const MPVariableProto& var_proto = proto_.variable(var_index);
if (var_proto.is_integer() != integrality) continue;
const std::string var_name = GetVariableName(var_index);
current_mps_column_ = 0;
if (var_proto.objective_coefficient() != 0.0) {
AppendMpsTermWithContext(var_name, "COST",
var_proto.objective_coefficient(),
output);
}
for (const std::pair<int, double> cst_index_and_coeff : transpose[var_index]) {
const std::string cst_name = GetConstraintName(cst_index_and_coeff.first);
AppendMpsTermWithContext(var_name, cst_name, cst_index_and_coeff.second,
output);
}
AppendNewLineIfTwoColumns(output);
}
}
bool MPModelProtoExporter::ExportModelAsMpsFormat(bool fixed_format,
bool obfuscated,
std::string* output) {
@@ -486,9 +508,9 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(bool fixed_format,
}
// As the information regarding a column needs to be contiguous, we create
// a map associating a variable to a the vector containing the indices of the
// a map associating a variable to a vector containing the indices of the
// constraints where this variable appears.
std::vector<std::vector<std::pair<int, double> > > transpose(proto_.variable_size());
std::vector<std::vector<std::pair<int, double>>> transpose(proto_.variable_size());
for (int cst_index = 0; cst_index < proto_.constraint_size(); ++cst_index) {
const MPConstraintProto& ct_proto = proto_.constraint(cst_index);
for (int k = 0; k < ct_proto.var_index_size(); ++k) {
@@ -506,35 +528,16 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(bool fixed_format,
}
// COLUMNS section.
current_mps_column_ = 0;
std::string columns_section;
const char* const kIntMarkerFormat = " %-10s%-36s%-10s\n";
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
const MPVariableProto& var_proto = proto_.variable(var_index);
const std::string var_name = GetVariableName(var_index);
current_mps_column_ = 0;
if (var_proto.is_integer()) {
StringAppendF(&columns_section, kIntMarkerFormat, "INTSTART", "'MARKER'",
"'INTORG'");
}
if (var_proto.objective_coefficient() != 0.0) {
AppendMpsTermWithContext(var_name, "COST",
var_proto.objective_coefficient(),
&columns_section);
}
for (const std::pair<int, double> cst_index_and_coeff : transpose[var_index]) {
const std::string cst_name = GetConstraintName(cst_index_and_coeff.first);
AppendMpsTermWithContext(var_name, cst_name, cst_index_and_coeff.second,
&columns_section);
}
if (var_proto.is_integer()) {
columns_section += "\n";
current_mps_column_ = 0;
StringAppendF(&columns_section, kIntMarkerFormat, "INTEND", "'MARKER'",
"'INTEND'");
}
AppendNewLineIfTwoColumns(&columns_section);
AppendMpsColumns(/*integrality=*/true, transpose, &columns_section);
if (!columns_section.empty()) {
const char* const kIntMarkerFormat = " %-10s%-36s%-10s\n";
columns_section = StringPrintf(kIntMarkerFormat, "INTSTART",
"'MARKER'", "'INTORG'") + columns_section;
StringAppendF(&columns_section, kIntMarkerFormat,
"INTEND", "'MARKER'", "'INTEND'");
}
AppendMpsColumns(/*integrality=*/false, transpose, &columns_section);
if (!columns_section.empty()) {
*output += "COLUMNS\n" + columns_section;
}

View File

@@ -151,6 +151,13 @@ class MPModelProtoExporter {
// Used by and in complement to AppendMpsTermWithContext.
void AppendNewLineIfTwoColumns(std::string* output);
// When 'integrality' is true, appends columns corresponding to integer
// variables. Appends the columns for non-integer variables otherwise.
// The sparse matrix must be passed as a vector of columns ('transpose').
void AppendMpsColumns(bool integrality,
const std::vector<std::vector<std::pair<int, double>>>& transpose,
std::string* output);
// Appends a line describing the bound of a variablenew-line if two columns
// are already present on the MPS line.
// Used by and in complement to AppendMpsTermWithContext.