remove MPSolver::*Objective* setters, getters, use setters/getters on objective

This commit is contained in:
lperron@google.com
2014-01-17 19:04:26 +00:00
parent d493e97540
commit da7dc5e070
27 changed files with 115 additions and 134 deletions

View File

@@ -54,8 +54,8 @@ public class IntegerProgramming {
MPVariable x2 = solver.makeIntVar(0.0, infinity, "x2");
// Minimize x1 + 2 * x2.
solver.setObjectiveCoefficient(x1, 1);
solver.setObjectiveCoefficient(x2, 2);
solver.objective().setCoefficient(x1, 1);
solver.objective().setCoefficient(x2, 2);
// 2 * x2 + 3 * x1 >= 17.
MPConstraint ct = solver.makeConstraint(17, infinity);
@@ -75,7 +75,7 @@ public class IntegerProgramming {
// The objective value of the solution.
System.out.println("Optimal objective value = " +
solver.objectiveValue());
solver.objective().value());
// The value of each variable in the solution.
System.out.println("x1 = " + x1.solutionValue());

View File

@@ -55,10 +55,10 @@ public class LinearProgramming {
MPVariable x3 = solver.makeNumVar(0.0, infinity, "x3");
// Maximize 10 * x1 + 6 * x2 + 4 * x3.
solver.setObjectiveCoefficient(x1, 10);
solver.setObjectiveCoefficient(x2, 6);
solver.setObjectiveCoefficient(x3, 4);
solver.setMaximization();
solver.objective().setCoefficient(x1, 10);
solver.objective().setCoefficient(x2, 6);
solver.objective().setCoefficient(x3, 4);
solver.objective().setMaximization();
// x1 + x2 + x3 <= 100.
MPConstraint c0 = solver.makeConstraint(-infinity, 100.0);
@@ -93,7 +93,8 @@ public class LinearProgramming {
" milliseconds");
// The objective value of the solution.
System.out.println("Optimal objective value = " + solver.objectiveValue());
System.out.println("Optimal objective value = " +
solver.objective().value());
// The value of each variable in the solution.
System.out.println("x1 = " + x1.solutionValue());

View File

@@ -29,8 +29,8 @@ public class CsIntegerProgramming
Variable x2 = solver.MakeIntVar(0.0, double.PositiveInfinity, "x2");
// Minimize x1 + 2 * x2.
solver.SetObjectiveCoefficient(x1, 1);
solver.SetObjectiveCoefficient(x2, 2);
solver.Objective().SetCoefficient(x1, 1);
solver.Objective().SetCoefficient(x2, 2);
// 2 * x2 + 3 * x1 >= 17.
Constraint ct = solver.MakeConstraint(17, double.PositiveInfinity);
@@ -50,7 +50,8 @@ public class CsIntegerProgramming
" milliseconds");
// The objective value of the solution.
Console.WriteLine("Optimal objective value = " + solver.ObjectiveValue());
Console.WriteLine("Optimal objective value = " +
solver.Objective().Value());
// The value of each variable in the solution.
Console.WriteLine("x1 = " + x1.SolutionValue());
@@ -89,7 +90,8 @@ public class CsIntegerProgramming
" milliseconds");
// The objective value of the solution.
Console.WriteLine("Optimal objective value = " + solver.ObjectiveValue());
Console.WriteLine("Optimal objective value = " +
solver.Objective().Value());
// The value of each variable in the solution.
Console.WriteLine("x1 = " + x1.SolutionValue());

View File

@@ -30,10 +30,10 @@ public class CsLinearProgramming
Variable x3 = solver.MakeNumVar(0.0, double.PositiveInfinity, "x3");
// Maximize 10 * x1 + 6 * x2 + 4 * x3.
solver.SetObjectiveCoefficient(x1, 10);
solver.SetObjectiveCoefficient(x2, 6);
solver.SetObjectiveCoefficient(x3, 4);
solver.SetMaximization();
solver.Objective().SetCoefficient(x1, 10);
solver.Objective().SetCoefficient(x2, 6);
solver.Objective().SetCoefficient(x3, 4);
solver.Objective().SetMaximization();
// x1 + x2 + x3 <= 100.
Constraint c0 = solver.MakeConstraint(double.NegativeInfinity, 100.0);
@@ -68,7 +68,8 @@ public class CsLinearProgramming
" milliseconds");
// The objective value of the solution.
Console.WriteLine("Optimal objective value = " + solver.ObjectiveValue());
Console.WriteLine("Optimal objective value = " +
solver.Objective().Value());
// The value of each variable in the solution.
Console.WriteLine("x1 = " + x1.SolutionValue());
@@ -122,7 +123,8 @@ public class CsLinearProgramming
" milliseconds");
// The objective value of the solution.
Console.WriteLine("Optimal objective value = " + solver.ObjectiveValue());
Console.WriteLine("Optimal objective value = " +
solver.Objective().Value());
// The value of each variable in the solution.
Console.WriteLine("x1 = " + x1.SolutionValue());

View File

@@ -57,7 +57,7 @@ public class Volsay
return;
}
Console.WriteLine("Objective: {0}", solver.ObjectiveValue());
Console.WriteLine("Objective: {0}", solver.Objective().Value());
Console.WriteLine("Gas : {0} ReducedCost: {1}",
Gas.SolutionValue(),

View File

@@ -87,7 +87,7 @@ public class Volsay3
return;
}
Console.WriteLine("Objective: {0}", solver.ObjectiveValue());
Console.WriteLine("Objective: {0}", solver.Objective().Value());
foreach(int p in PRODUCTS) {
Console.WriteLine("{0,-10}: {1} ReducedCost: {2}",
products[p],

View File

@@ -150,7 +150,7 @@ def main(sol = 'GLPK'):
solver.Solve()
print
print 'z: ', int(solver.ObjectiveValue())
print 'z: ', int(solver.Objective().Value())
t = start
while t != end:

View File

@@ -136,7 +136,7 @@ def main(sol = 'GLPK'):
solver.Solve()
print
print 'z: ', int(solver.ObjectiveValue())
print 'z: ', int(solver.Objective().Value())
print 'Assigned'
for j in J:

View File

@@ -106,7 +106,7 @@ def main(sol = 'GLPK'):
print
print 'z = ', solver.ObjectiveValue()
print 'z = ', solver.Objective().Value()
print 'Metals'
for i in Metals:
print p[i].SolutionValue(),

View File

@@ -143,7 +143,7 @@ def main(sol = 'GLPK'):
solver.Solve()
print
print "number of colors:", int(solver.ObjectiveValue())
print "number of colors:", int(solver.Objective().Value())
print "colors used:", [int(u[i].SolutionValue()) for i in range(nc)]
print

View File

@@ -94,7 +94,7 @@ def main(sol = 'GLPK'):
#
solver.Solve()
print "Cost:", solver.ObjectiveValue()
print "Cost:", solver.Objective().Value()
print [int(x[i].SolutionValue()) for i in range(n)]
print

View File

@@ -74,7 +74,7 @@ def main(sol = 'GLPK'):
print
print 'row player:';
print 'v = ', solver.ObjectiveValue()
print 'v = ', solver.Objective().Value()
print 'Strategies: '
for i in range(rows):
print x1[i].SolutionValue(),
@@ -101,7 +101,7 @@ def main(sol = 'GLPK'):
print
print 'column player:';
print 'v2 = ', solver.ObjectiveValue()
print 'v2 = ', solver.Objective().Value()
print 'Strategies: '
for i in range(rows):
print x2[i].SolutionValue(),

View File

@@ -45,8 +45,9 @@ def RunIntegerExampleCppStyleAPI(optimization_problem_type):
x2 = solver.IntVar(0.0, infinity, 'x2')
# Minimize x1 + 2 * x2.
solver.SetObjectiveCoefficient(x1, 1)
solver.SetObjectiveCoefficient(x2, 2)
objective = solver.Objective()
objective.SetCoefficient(x1, 1)
objective.SetCoefficient(x2, 2)
# 2 * x2 + 3 * x1 >= 17.
ct = solver.Constraint(17, infinity)
@@ -69,7 +70,7 @@ def SolveAndPrint(solver, variable_list):
print('Problem solved in %f milliseconds' % solver.WallTime())
# The objective value of the solution.
print('Optimal objective value = %f' % solver.ObjectiveValue())
print('Optimal objective value = %f' % solver.Objective().Value())
# The value of each variable in the solution.
for variable in variable_list:

View File

@@ -86,7 +86,7 @@ def main(sol = 'GLPK'):
solver.Solve()
print
print 'z: ', int(solver.ObjectiveValue())
print 'z: ', int(solver.Objective().Value())
print 'take:',
for i in items:

View File

@@ -81,7 +81,7 @@ def main(sol = 'GLPK'):
solver.Solve()
print
print 'z = ', solver.ObjectiveValue()
print 'z = ', solver.Objective().Value()
for i in range(p + 1):
print a[i].SolutionValue(),
print

View File

@@ -50,10 +50,11 @@ def RunLinearExampleCppStyleAPI(optimization_problem_type):
x3 = solver.NumVar(0.0, infinity, 'x3')
# Maximize 10 * x1 + 6 * x2 + 4 * x3.
solver.SetObjectiveCoefficient(x1, 10)
solver.SetObjectiveCoefficient(x2, 6)
solver.SetObjectiveCoefficient(x3, 4)
solver.SetMaximization()
objective = solver.Objective()
objective.SetCoefficient(x1, 10)
objective.SetCoefficient(x2, 6)
objective.SetCoefficient(x3, 4)
objective.SetMaximization()
# x1 + x2 + x3 <= 100.
c0 = solver.Constraint(-infinity, 100.0, 'c0')
@@ -89,7 +90,7 @@ def SolveAndPrint(solver, variable_list, constraint_list):
print('Problem solved in %f milliseconds' % solver.WallTime())
# The objective value of the solution.
print('Optimal objective value = %f' % solver.ObjectiveValue())
print('Optimal objective value = %f' % solver.Objective().Value())
# The value of each variable in the solution.
for variable in variable_list:

View File

@@ -86,7 +86,7 @@ def main(sol = 'GLPK'):
solver.Solve()
print
print 'z = ', solver.ObjectiveValue()
print 'z = ', solver.Objective().Value()
for p in range(num_products):
print products[p], ': inside:', inside[p].SolutionValue(), '(ReducedCost:', inside[p].ReducedCost(), ')',

View File

@@ -365,7 +365,7 @@ def main(sol = 'GLPK'):
print
print 'Cost = %0.2f' % solver.ObjectiveValue()
print 'Cost = %0.2f' % solver.Objective().Value()
# print 'Cost:', cost.SolutionValue()
print 'Total cost: %0.2f' % total_cost.SolutionValue()
print

View File

@@ -62,7 +62,7 @@ def main(unused_argv):
solver.Solve()
print
print 'objective = ', solver.ObjectiveValue()
print 'objective = ', solver.Objective().Value()
print 'Gas = ', Gas.SolutionValue(), 'ReducedCost =', Gas.ReducedCost()
print 'Chloride:', Chloride.SolutionValue(), 'ReducedCost =', Chloride.ReducedCost()

View File

@@ -67,7 +67,7 @@ def main(unused_argv):
solver.Solve()
print
print 'objective = ', solver.ObjectiveValue()
print 'objective = ', solver.Objective().Value()
for i in range(num_products):
print products[i], '=', production[i].SolutionValue(),
print 'ReducedCost = ', production[i].ReducedCost()

View File

@@ -76,7 +76,7 @@ def main(unused_argv):
solver.Solve()
print
print 'objective = ', solver.ObjectiveValue()
print 'objective = ', solver.Objective().Value()
for i in range(num_products):
print products[i], '=', production[i].SolutionValue(),
print 'ReducedCost = ', production[i].ReducedCost()

View File

@@ -664,9 +664,8 @@ MPSolver::ResultStatus GurobiInterface::Solve(const MPSolverParameters& param) {
}
}
if (solution_count > 0) {
DCHECK(result_status_ == MPSolver::FEASIBLE ||
result_status_ == MPSolver::OPTIMAL);
if (solution_count > 0 && (result_status_ == MPSolver::FEASIBLE ||
result_status_ == MPSolver::OPTIMAL)) {
// Get the results.
const int total_num_rows = solver_->constraints_.size();
const int total_num_cols = solver_->variables_.size();

View File

@@ -263,37 +263,6 @@ void MPVariable::SetInteger(bool integer) {
}
}
// ----- Objective (DEPRECATED methods) -----
double MPSolver::objective_value() const { return Objective().Value(); }
double MPSolver::best_objective_bound() const {
return Objective().BestBound();
}
void MPSolver::ClearObjective() { MutableObjective()->Clear(); }
void MPSolver::SetObjectiveCoefficient(const MPVariable* const var,
double coeff) {
MutableObjective()->SetCoefficient(var, coeff);
}
void MPSolver::SetObjectiveOffset(double value) {
MutableObjective()->SetOffset(value);
}
void MPSolver::AddObjectiveOffset(double value) {
MutableObjective()->AddOffset(value);
}
void MPSolver::SetOptimizationDirection(bool maximize) {
MutableObjective()->SetOptimizationDirection(maximize);
}
bool MPSolver::Maximization() const { return Objective().maximization(); }
bool MPSolver::Minimization() const { return Objective().minimization(); }
// ----- Version -----
std::string MPSolver::SolverVersion() const { return interface_->SolverVersion(); }
@@ -506,9 +475,9 @@ MPSolver::LoadStatus MPSolver::LoadModelFromProto(
ct_proto.coefficient(j));
}
}
SetOptimizationDirection(input_model.maximize());
objective->SetOptimizationDirection(input_model.maximize());
if (input_model.has_objective_offset()) {
MutableObjective()->SetOffset(input_model.objective_offset());
objective->SetOffset(input_model.objective_offset());
}
return MPSolver::NO_ERROR;
}
@@ -1426,3 +1395,4 @@ int MPSolverParameters::GetIntegerParam(MPSolverParameters::IntegerParam param)
} // namespace operations_research

View File

@@ -517,22 +517,6 @@ class MPSolver {
// Debugging: verify that the given MPVariable* belongs to this solver.
bool OwnsVariable(const MPVariable* var) const;
// *** DEPRECATED ***
// Setters and getters for the objective. Please call
// Objective().Getter() and MutableObjective()->Setter() instead.
// TODO(user): remove when they are no longer used.
double objective_value() const;
double best_objective_bound() const;
void ClearObjective();
void SetObjectiveCoefficient(const MPVariable* const var, double coeff);
void SetObjectiveOffset(double value);
void AddObjectiveOffset(double value);
void SetOptimizationDirection(bool maximize);
void SetMinimization() { SetOptimizationDirection(false); }
void SetMaximization() { SetOptimizationDirection(true); }
bool Maximization() const;
bool Minimization() const;
private:
// Computes the size of the constraint with the largest number of
// coefficients with index in [min_constraint_index,

View File

@@ -24,7 +24,6 @@
%}
#ifdef SWIGPYTHON
// Define the renaming of methods.
%ignore MakeBoolVarArray;
%ignore MakeIntVarArray;
@@ -47,7 +46,6 @@
%rename (LookupVariable) LookupVariableOrNull;
%rename (Nodes) nodes;
%rename (NumVar) MakeNumVar;
%rename (ObjectiveValue) objective_value;
%rename (Offset) offset;
%rename (ReducedCost) reduced_cost;
%rename (SetLb) SetLB;
@@ -437,30 +435,30 @@ class LinearConstraint(object):
return self.Constraint(*args)
def Minimize(self, expr):
self.ClearObjective()
self.SetMinimization()
self.Objective().Clear()
self.Objective().SetMinimization()
coeffs = {}
offset = expr.Visit(coeffs)
self.AddObjectiveOffset(offset)
self.Objective().SetOffset(offset)
if sys.version_info[0] >= 3: # Python 3
for v, c, in coeffs.items():
self.SetObjectiveCoefficient(v, float(c))
self.Objective().SetCoefficient(v, float(c))
else:
for v, c, in coeffs.iteritems():
self.SetObjectiveCoefficient(v, float(c))
self.Objective().SetCoefficient(v, float(c))
def Maximize(self, expr):
self.ClearObjective()
self.SetMaximization()
self.Objective().Clear()
self.Objective().SetMaximization()
coeffs = {}
offset = expr.Visit(coeffs)
self.AddObjectiveOffset(offset)
self.Objective().SetOffset(offset)
if sys.version_info[0] >= 3: # Python 3
for v, c, in coeffs.items():
self.SetObjectiveCoefficient(v, float(c))
self.Objective().SetCoefficient(v, float(c))
else:
for v, c, in coeffs.iteritems():
self.SetObjectiveCoefficient(v, float(c))
self.Objective().SetCoefficient(v, float(c))
}
}
@@ -520,12 +518,11 @@ namespace operations_research {
%rename (setIntegerParam) MPSolverParameters::SetIntegerParam;
// Rename rules on MPSolver.
%rename (addObjectiveOffset) MPSolver::AddObjectiveOffset;
%rename (bestObjectiveBound) MPSolver::best_objective_bound;
%rename (checkAllNamesValidity) MPSolver::CheckAllNamesValidity;
%rename (checkNameValidity) MPSolver::CheckNameValidity;
%rename (clear) MPConstraint::Clear;
%rename (clear) MPObjective::Clear;
%rename (clear) MPSolver::Clear;
%rename (clearObjective) MPSolver::ClearObjective;
%rename (computeExactConditionNumber) MPSolver::ComputeExactConditionNumber;
%rename (loadModel) MPSolver::LoadModel;
%rename (lookupVariableOrNull) MPSolver::LookupVariableOrNull;
@@ -539,13 +536,12 @@ namespace operations_research {
%rename (numConstraints) MPSolver::NumConstraints;
%rename (numVariables) MPSolver::NumVariables;
%rename (objective) MPSolver::MutableObjective;
%rename (objectiveValue) MPSolver::objective_value;
%rename (reset) MPSolver::Reset;
%rename (setMaximization) MPSolver::SetMaximization;
%rename (setMinimization) MPSolver::SetMinimization;
%rename (setObjectiveCoefficient) MPSolver::SetObjectiveCoefficient;
%rename (setObjectiveOffset) MPSolver::SetObjectiveOffset;
%rename (setOptimizationDirection) MPSolver::SetOptimizationDirection;
%rename (setMaximization) MPObjective::SetMaximization();
%rename (setMinimization) MPObjective::SetMinimization();
%rename (setCoefficient) MPObjective::SetCoefficient;
%rename (setOffset) MPObjective::SetOffset;
%rename (setOptimizationDirection) MPObjective::SetOptimizationDirection;
%rename (setTimeLimit) MPSolver::set_time_limit;
%rename (setWriteModelFilename) MPSolver::set_write_model_filename;
%rename (solve) MPSolver::Solve;
@@ -679,6 +675,9 @@ namespace operations_research {
%ignore MPSolver::ExportModelToNewProto;
%ignore MPSolver::FillSolutionResponse;
%ignore MPSolver::SolveWithProtocolBuffers;
// Ignore Objective(), use MutableObjective() instead.
%ignore MPSolver::Objective;
%rename (Objective) MPSolver::MutableObjective;
%typemap(cscode) MPVariable %{
public static LinearExpr operator+(Variable a, double v)
@@ -1040,44 +1039,44 @@ namespace operations_research {
public void Minimize(LinearExpr expr)
{
ClearObjective();
SetMinimization();
Objective().Clear();
Objective().SetMinimization();
Dictionary<Variable, double> coefficients =
new Dictionary<Variable, double>();
double constant = expr.Visit(coefficients);
foreach (KeyValuePair<Variable, double> pair in coefficients)
{
SetObjectiveCoefficient(pair.Key, pair.Value);
Objective().SetCoefficient(pair.Key, pair.Value);
}
SetObjectiveOffset(constant);
Objective().SetOffset(constant);
}
public void Maximize(LinearExpr expr)
{
ClearObjective();
SetMaximization();
Objective().Clear();
Objective().SetMaximization();
Dictionary<Variable, double> coefficients =
new Dictionary<Variable, double>();
double constant = expr.Visit(coefficients);
foreach (KeyValuePair<Variable, double> pair in coefficients)
{
SetObjectiveCoefficient(pair.Key, pair.Value);
Objective().SetCoefficient(pair.Key, pair.Value);
}
SetObjectiveOffset(constant);
Objective().SetOffset(constant);
}
public void Minimize(Variable var)
{
ClearObjective();
SetMinimization();
SetObjectiveCoefficient(var, 1.0);
Objective().Clear();
Objective().SetMinimization();
Objective().SetCoefficient(var, 1.0);
}
public void Maximize(Variable var)
{
ClearObjective();
SetMaximization();
SetObjectiveCoefficient(var, 1.0);
Objective().Clear();
Objective().SetMaximization();
Objective().SetCoefficient(var, 1.0);
}
%}

View File

@@ -15,6 +15,7 @@
#include <cmath>
#include <limits>
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/stringprintf.h"
@@ -24,6 +25,10 @@
#include "linear_solver/linear_solver2.pb.h"
#include "util/fp_utils.h"
DEFINE_bool(lp_shows_unused_variables, false,
"Decides wether variable unused in the objective and constraints"
" are shown when exported to a file using the lp format.");
namespace operations_research {
using new_proto::MPConstraintProto;
@@ -111,6 +116,9 @@ void MPModelProtoExporter::AppendComments(const std::string& separator,
num_integer_variables_);
StringAppendF(output, "%s %-14s : %d\n", sep, "Continuous",
num_continuous_variables_);
if (FLAGS_lp_shows_unused_variables) {
StringAppendF(output, "%s Unused variables are shown\n", sep);
}
}
bool MPModelProtoExporter::AppendLpTerm(int var_index, double coefficient,
@@ -189,22 +197,28 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(bool obfuscated,
if (proto_.objective_offset() != 0.0) {
StringAppendF(output, "%-+.16G Constant ", proto_.objective_offset());
}
for (int i = 0; i < proto_.variable_size(); ++i) {
if (!AppendLpTerm(i, proto_.variable(i).objective_coefficient(), output)) {
std::vector<bool> show_variable(proto_.variable_size(),
FLAGS_lp_shows_unused_variables);
for (int var_index = 0; var_index < proto_.variable_size(); ++var_index) {
const double coeff = proto_.variable(var_index).objective_coefficient();
if (!AppendLpTerm(var_index, coeff, output)) {
return false;
}
show_variable[var_index] = coeff != 0.0 || FLAGS_lp_shows_unused_variables;
}
// Constraints
StringAppendF(output, "\nSubject to\n");
for (int cst_index = 0; cst_index < proto_.constraint_size(); ++cst_index) {
const MPConstraintProto& ct_proto = proto_.constraint(cst_index);
std::string term;
for (int i = 0; i < ct_proto.var_index_size(); ++i) {
if (!AppendLpTerm(ct_proto.var_index(i), ct_proto.coefficient(i),
&term)) {
const int var_index = ct_proto.var_index(i);
const double coeff = ct_proto.coefficient(i);
if (!AppendLpTerm(var_index, coeff, &term)) {
return false;
}
show_variable[var_index] =
coeff != 0.0 || FLAGS_lp_shows_unused_variables;
}
const double lb = ct_proto.lower_bound();
const double ub = ct_proto.upper_bound();
@@ -238,6 +252,7 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(bool obfuscated,
StringAppendF(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();
@@ -260,6 +275,7 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(bool obfuscated,
if (num_binary_variables_ > 0) {
StringAppendF(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)) {
StringAppendF(output, " %s\n", GetVariableName(var_index).c_str());
@@ -271,6 +287,7 @@ bool MPModelProtoExporter::ExportModelAsLpFormat(bool obfuscated,
if (num_integer_variables_ > 0) {
StringAppendF(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)) {
StringAppendF(output, " %s\n", GetVariableName(var_index).c_str());

View File

@@ -116,6 +116,11 @@ class MPModelProtoExporter {
// Appends a general "Comment" section with useful metadata about the model
// to "output".
// Note(user): there may be less variables in output than in the original
// model, as unused variables are not shown by default. Similarly, there
// 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;
// Appends a term to "output", in "Lp" format.