Skip to content

Commit

Permalink
use stream when exporting models
Browse files Browse the repository at this point in the history
std::ostream allows the model string to be exported into a string stream.
thus, export functions may be used when writing models to files.
  • Loading branch information
omer-candan committed Aug 17, 2024
1 parent 056cc98 commit 978b796
Showing 1 changed file with 57 additions and 57 deletions.
114 changes: 57 additions & 57 deletions ortools/linear_solver/model_exporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ class MPModelProtoExporter {
MPModelProtoExporter& operator=(const MPModelProtoExporter&) = delete;

bool ExportModelAsLpFormat(const MPModelExportOptions& options,
std::string* output);
std::ostream& output);
bool ExportModelAsMpsFormat(const MPModelExportOptions& options,
std::string* output);
std::ostream& output);

private:
// Computes the number of continuous, integer and binary variables.
Expand Down Expand Up @@ -132,15 +132,15 @@ class MPModelProtoExporter {
// may be more constraints in a .lp file as in the original model as
// a constraint lhs <= term <= rhs will be output as the two constraints
// term >= lhs and term <= rhs.
void AppendComments(const std::string& separator, std::string* output) const;
void AppendComments(const std::string& separator, std::ostream& output) const;

// Appends an MPConstraintProto to the output text. If the constraint has
// both an upper and lower bound that are not equal, it splits the constraint
// into two constraints, one for the left hand side (_lhs) and one for right
// hand side (_rhs).
bool AppendConstraint(const MPConstraintProto& ct_proto,
const std::string& name, LineBreaker& line_breaker,
std::vector<bool>& show_variable, std::string* output);
std::vector<bool>& show_variable, std::ostream& output);

// Clears "output" and writes a term to it, in "LP" format. Returns false on
// error (for example, var_index is out of range).
Expand Down Expand Up @@ -228,11 +228,11 @@ absl::StatusOr<std::string> ExportModelAsLpFormat(
}
}
MPModelProtoExporter exporter(model);
std::string output;
if (!exporter.ExportModelAsLpFormat(options, &output)) {
std::ostringstream output;
if (!exporter.ExportModelAsLpFormat(options, output)) {
return absl::InvalidArgumentError("Unable to export model.");
}
return output;
return output.str();
}

absl::StatusOr<std::string> ExportModelAsMpsFormat(
Expand All @@ -241,11 +241,11 @@ absl::StatusOr<std::string> ExportModelAsMpsFormat(
return absl::InvalidArgumentError("General constraints are not supported.");
}
MPModelProtoExporter exporter(model);
std::string output;
if (!exporter.ExportModelAsMpsFormat(options, &output)) {
std::ostringstream output;
if (!exporter.ExportModelAsMpsFormat(options, output)) {
return absl::InvalidArgumentError("Unable to export model.");
}
return output;
return output.str();
}

absl::Status WriteModelToMpsFile(absl::string_view filename,
Expand Down Expand Up @@ -361,22 +361,21 @@ std::vector<std::string> MPModelProtoExporter::ExtractAndProcessNames(
}

void MPModelProtoExporter::AppendComments(const std::string& separator,
std::string* output) const {
std::ostream& output) const {
const char* const sep = separator.c_str();
absl::StrAppendFormat(output, "%s Generated by MPModelProtoExporter\n", sep);
absl::StrAppendFormat(output, "%s %-16s : %s\n", sep, "Name",
output << absl::StrFormat("%s Generated by MPModelProtoExporter\n", sep);
output << absl::StrFormat("%s %-16s : %s\n", sep, "Name",
proto_.has_name() ? proto_.name().c_str() : "NoName");
absl::StrAppendFormat(output, "%s %-16s : %s\n", sep, "Format", "Free");
absl::StrAppendFormat(
output, "%s %-16s : %d\n", sep, "Constraints",
output << absl::StrFormat("%s %-16s : %s\n", sep, "Format", "Free");
output << absl::StrFormat("%s %-16s : %d\n", sep, "Constraints",
proto_.constraint_size() + proto_.general_constraint_size());
absl::StrAppendFormat(output, "%s %-16s : %d\n", sep, "Variables",
output << absl::StrFormat("%s %-16s : %d\n", sep, "Variables",
proto_.variable_size());
absl::StrAppendFormat(output, "%s %-14s : %d\n", sep, "Binary",
output << absl::StrFormat("%s %-14s : %d\n", sep, "Binary",
num_binary_variables_);
absl::StrAppendFormat(output, "%s %-14s : %d\n", sep, "Integer",
output << absl::StrFormat("%s %-14s : %d\n", sep, "Integer",
num_integer_variables_);
absl::StrAppendFormat(output, "%s %-14s : %d\n", sep, "Continuous",
output << absl::StrFormat("%s %-14s : %d\n", sep, "Continuous",
num_continuous_variables_);
}

Expand All @@ -394,7 +393,7 @@ bool MPModelProtoExporter::AppendConstraint(const MPConstraintProto& ct_proto,
const std::string& name,
LineBreaker& line_breaker,
std::vector<bool>& show_variable,
std::string* output) {
std::ostream& output) {
for (int i = 0; i < ct_proto.var_index_size(); ++i) {
const int var_index = ct_proto.var_index(i);
const double coeff = ct_proto.coefficient(i);
Expand All @@ -410,31 +409,31 @@ bool MPModelProtoExporter::AppendConstraint(const MPConstraintProto& ct_proto,
const double ub = ct_proto.upper_bound();
if (lb == ub) {
line_breaker.Append(absl::StrCat(" = ", DoubleToString(ub), "\n"));
absl::StrAppend(output, " ", name, ": ", line_breaker.GetOutput());
output << " " << name << ": " << line_breaker.GetOutput();
} else {
if (ub != +kInfinity) {
std::string rhs_name = name;
if (lb != -kInfinity) {
absl::StrAppend(&rhs_name, "_rhs");
}
absl::StrAppend(output, " ", rhs_name, ": ", line_breaker.GetOutput());
output << " " << rhs_name << ": " << line_breaker.GetOutput();
const std::string relation =
absl::StrCat(" <= ", DoubleToString(ub), "\n");
// Here we have to make sure we do not add the relation to the contents
// of line_breaker, which may be used in the subsequent clause.
if (!line_breaker.WillFit(relation)) absl::StrAppend(output, "\n ");
absl::StrAppend(output, relation);
if (!line_breaker.WillFit(relation)) output << "\n ";
output << relation;
}
if (lb != -kInfinity) {
std::string lhs_name = name;
if (ub != +kInfinity) {
absl::StrAppend(&lhs_name, "_lhs");
}
absl::StrAppend(output, " ", lhs_name, ": ", line_breaker.GetOutput());
output << " " << lhs_name << ": " << line_breaker.GetOutput();
const std::string relation =
absl::StrCat(" >= ", DoubleToString(lb), "\n");
if (!line_breaker.WillFit(relation)) absl::StrAppend(output, "\n ");
absl::StrAppend(output, relation);
if (!line_breaker.WillFit(relation)) output << "\n ";
output << relation;
}
}

Expand Down Expand Up @@ -531,8 +530,8 @@ void MPModelProtoExporter::ComputeMpsSmartColumnWidths(bool obfuscated) {
}

bool MPModelProtoExporter::ExportModelAsLpFormat(
const MPModelExportOptions& options, std::string* output) {
output->clear();
const MPModelExportOptions& options,
std::ostream& output){
Setup();
const std::string kForbiddenFirstChars = "$.0123456789";
const std::string kForbiddenChars = " +-*/<>=:\\";
Expand All @@ -549,11 +548,12 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(
// Comments section.
AppendComments("\\", output);
if (options.show_unused_variables) {
absl::StrAppendFormat(output, "\\ Unused variables are shown\n");
output << absl::StrFormat("\\ Unused variables are shown\n");
}

// Objective
absl::StrAppend(output, proto_.maximize() ? "Maximize\n" : "Minimize\n");
std::string obj = proto_.maximize() ? "Maximize\n" : "Minimize\n";
output << obj;
LineBreaker obj_line_breaker(options.max_line_length);
obj_line_breaker.Append(" Obj: ");
if (proto_.objective_offset() != 0.0) {
Expand All @@ -572,7 +572,7 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(
show_variable[var_index] = coeff != 0.0 || show_variable[var_index];
}
// Linear Constraints
absl::StrAppend(output, obj_line_breaker.GetOutput(), "\nSubject to\n");
output << obj_line_breaker.GetOutput() << "\nSubject to\n";
for (int cst_index = 0; cst_index < proto_.constraint_size(); ++cst_index) {
const MPConstraintProto& ct_proto = proto_.constraint(cst_index);
const std::string& name = exported_constraint_names_[cst_index];
Expand Down Expand Up @@ -617,60 +617,60 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(
}

// Bounds
absl::StrAppend(output, "Bounds\n");
output << "Bounds\n";
if (proto_.objective_offset() != 0.0) {
absl::StrAppend(output, " 1 <= Constant <= 1\n");
output << " 1 <= Constant <= 1\n";
}
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
if (!show_variable[var_index]) continue;
const MPVariableProto& var_proto = proto_.variable(var_index);
const double lb = var_proto.lower_bound();
const double ub = var_proto.upper_bound();
if (var_proto.is_integer() && lb == round(lb) && ub == round(ub)) {
absl::StrAppendFormat(output, " %.0f <= %s <= %.0f\n", lb,
output << absl::StrFormat(" %.0f <= %s <= %.0f\n", lb,
exported_variable_names_[var_index], ub);
} else {
absl::StrAppend(output, " ");
output << " ";
if (lb == -kInfinity && ub == kInfinity) {
absl::StrAppend(output, exported_variable_names_[var_index], " free");
output << exported_variable_names_[var_index] << " free";
} else {
if (lb != -kInfinity) {
absl::StrAppend(output, DoubleToString(lb), " <= ");
output << DoubleToString(lb) << " <= ";
}
absl::StrAppend(output, exported_variable_names_[var_index]);
output << exported_variable_names_[var_index];
if (ub != kInfinity) {
absl::StrAppend(output, " <= ", DoubleToString(ub));
output << " <= " << DoubleToString(ub);
}
}
absl::StrAppend(output, "\n");
output << "\n";
}
}

// Binaries
if (num_binary_variables_ > 0) {
absl::StrAppend(output, "Binaries\n");
output << "Binaries\n";
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
if (!show_variable[var_index]) continue;
const MPVariableProto& var_proto = proto_.variable(var_index);
if (IsBoolean(var_proto)) {
absl::StrAppendFormat(output, " %s\n",
output << absl::StrFormat(" %s\n",
exported_variable_names_[var_index]);
}
}
}

// Generals
if (num_integer_variables_ > 0) {
absl::StrAppend(output, "Generals\n");
output << "Generals\n";
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
if (!show_variable[var_index]) continue;
const MPVariableProto& var_proto = proto_.variable(var_index);
if (var_proto.is_integer() && !IsBoolean(var_proto)) {
absl::StrAppend(output, " ", exported_variable_names_[var_index], "\n");
output << " " << exported_variable_names_[var_index] << "\n";
}
}
}
absl::StrAppend(output, "End\n");
output << "End\n";
return true;
}

Expand Down Expand Up @@ -746,8 +746,8 @@ void MPModelProtoExporter::AppendMpsColumns(
}

bool MPModelProtoExporter::ExportModelAsMpsFormat(
const MPModelExportOptions& options, std::string* output) {
output->clear();
const MPModelExportOptions& options,
std::ostream& output) {
Setup();
ComputeMpsSmartColumnWidths(options.obfuscate);
const std::string kForbiddenFirstChars = "";
Expand All @@ -764,10 +764,10 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(

// NAME section.
// TODO(user): Obfuscate the model name too if `obfuscate` is true.
absl::StrAppendFormat(output, "%-14s%s\n", "NAME", proto_.name());
output << absl::StrFormat("%-14s%s\n", "NAME", proto_.name());

if (proto_.maximize()) {
absl::StrAppendFormat(output, "OBJSENSE\n MAX\n");
output << "OBJSENSE\n MAX\n";
}

// ROWS section.
Expand All @@ -790,7 +790,7 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(
}
}
if (!rows_section.empty()) {
absl::StrAppend(output, "ROWS\n", rows_section);
output << "ROWS\n" << rows_section;
}

// As the information regarding a column needs to be contiguous, we create
Expand Down Expand Up @@ -828,7 +828,7 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(
}
AppendMpsColumns(/*integrality=*/false, transpose, &columns_section);
if (!columns_section.empty()) {
absl::StrAppend(output, "COLUMNS\n", columns_section);
output << "COLUMNS\n" << columns_section;
}

// RHS (right-hand-side) section.
Expand All @@ -853,7 +853,7 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(
}
AppendNewLineIfTwoColumns(&rhs_section);
if (!rhs_section.empty()) {
absl::StrAppend(output, "RHS\n", rhs_section);
output << "RHS\n" << rhs_section;
}

// RANGES section.
Expand All @@ -869,7 +869,7 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(
}
AppendNewLineIfTwoColumns(&ranges_section);
if (!ranges_section.empty()) {
absl::StrAppend(output, "RANGES\n", ranges_section);
output << "RANGES\n" << ranges_section;
}

// BOUNDS section.
Expand Down Expand Up @@ -929,10 +929,10 @@ bool MPModelProtoExporter::ExportModelAsMpsFormat(
}
}
if (!bounds_section.empty()) {
absl::StrAppend(output, "BOUNDS\n", bounds_section);
output << "BOUNDS\n" << bounds_section;
}

absl::StrAppend(output, "ENDATA\n");
output << "ENDATA\n";
return true;
}

Expand Down

0 comments on commit 978b796

Please sign in to comment.