24#include "absl/log/check.h"
25#include "absl/strings/match.h"
31#include "ortools/linear_solver/linear_solver.pb.h"
47#if defined(USE_LP_PARSER)
57 model_ = other_helper.
model();
82 MPModelRequest request;
85 model_ = request.model();
92 if (absl::EndsWith(filename,
"txt")) {
102 absl::StatusOr<MPModelProto> model_or =
104 if (!model_or.ok())
return false;
105 model_ = model_or.value();
110 absl::StatusOr<MPModelProto> model_or =
112 if (!model_or.ok())
return false;
113 model_ = model_or.value();
117#if defined(USE_LP_PARSER)
118bool ModelBuilderHelper::ImportFromLpString(
const std::string& lp_string) {
119 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_string);
120 if (!model_or.ok())
return false;
121 model_ = model_or.value();
125bool ModelBuilderHelper::ImportFromLpFile(
const std::string& lp_file) {
130 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_data);
131 if (!model_or.ok())
return false;
132 model_ = model_or.value();
142 const int index = model_.variable_size();
143 model_.add_variable();
148 model_.mutable_variable(
var_index)->set_lower_bound(lb);
152 model_.mutable_variable(
var_index)->set_upper_bound(ub);
156 model_.mutable_variable(
var_index)->set_is_integer(is_integer);
161 model_.mutable_variable(
var_index)->set_objective_coefficient(coeff);
169 return model_.variable(
var_index).lower_bound();
173 return model_.variable(
var_index).upper_bound();
177 return model_.variable(
var_index).is_integer();
181 return model_.variable(
var_index).objective_coefficient();
185 return model_.variable(
var_index).name();
189 const int index = model_.constraint_size();
190 model_.add_constraint();
195 model_.mutable_constraint(
ct_index)->set_lower_bound(lb);
199 model_.mutable_constraint(
ct_index)->set_upper_bound(ub);
203 MPConstraintProto* ct_proto = model_.mutable_constraint(
ct_index);
204 ct_proto->clear_var_index();
205 ct_proto->clear_coefficient();
210 if (coeff == 0.0)
return;
211 MPConstraintProto* ct_proto = model_.mutable_constraint(
ct_index);
213 ct_proto->add_coefficient(coeff);
218 if (coeff == 0.0)
return;
219 MPConstraintProto* ct_proto = model_.mutable_constraint(
ct_index);
220 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
221 if (ct_proto->var_index(i) ==
var_index) {
222 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
229 ct_proto->add_coefficient(coeff);
233 const std::string&
name) {
239 MPConstraintProto* ct_proto = model_.mutable_constraint(
ct_index);
240 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
241 if (ct_proto->var_index(i) ==
var_index) {
242 ct_proto->set_coefficient(i, coeff);
249 ct_proto->add_coefficient(coeff);
253 return model_.constraint(
ct_index).lower_bound();
257 return model_.constraint(
ct_index).upper_bound();
261 return model_.constraint(
ct_index).name();
265 const MPConstraintProto& ct_proto = model_.constraint(
ct_index);
266 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
271 const MPConstraintProto& ct_proto = model_.constraint(
ct_index);
272 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
276 const int index = model_.general_constraint_size();
278 model_.add_general_constraint()->mutable_indicator_constraint();
283 const MPGeneralConstraintProto& gen = model_.general_constraint(
ct_index);
284 return gen.general_constraint_case() ==
285 MPGeneralConstraintProto::kIndicatorConstraint;
291 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
292 MPConstraintProto* ct_proto =
293 gen->mutable_indicator_constraint()->mutable_constraint();
294 ct_proto->set_lower_bound(lb);
300 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
301 MPConstraintProto* ct_proto =
302 gen->mutable_indicator_constraint()->mutable_constraint();
303 ct_proto->set_upper_bound(ub);
307 MPConstraintProto* ct_proto = model_.mutable_general_constraint(
ct_index)
308 ->mutable_indicator_constraint()
309 ->mutable_constraint();
310 ct_proto->clear_var_index();
311 ct_proto->clear_coefficient();
317 if (coeff == 0.0)
return;
318 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
319 MPConstraintProto* ct_proto =
320 gen->mutable_indicator_constraint()->mutable_constraint();
322 ct_proto->add_coefficient(coeff);
329 if (coeff == 0.0)
return;
330 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
331 MPConstraintProto* ct_proto =
332 gen->mutable_indicator_constraint()->mutable_constraint();
333 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
334 if (ct_proto->var_index(i) ==
var_index) {
335 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
342 ct_proto->add_coefficient(coeff);
346 const std::string&
name) {
347 model_.mutable_general_constraint(
ct_index)->set_name(
name);
354 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
355 MPConstraintProto* ct_proto =
356 gen->mutable_indicator_constraint()->mutable_constraint();
357 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
358 if (ct_proto->var_index(i) ==
var_index) {
359 ct_proto->set_coefficient(i, coeff);
366 ct_proto->add_coefficient(coeff);
372 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
373 gen->mutable_indicator_constraint()->set_var_index(
var_index);
379 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(
ct_index);
380 gen->mutable_indicator_constraint()->set_var_value(positive);
385 return model_.general_constraint(
ct_index)
386 .indicator_constraint()
393 return model_.general_constraint(
ct_index)
394 .indicator_constraint()
401 return model_.general_constraint(
ct_index).name();
407 const MPConstraintProto& ct_proto =
408 model_.general_constraint(
ct_index).indicator_constraint().constraint();
409 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
415 const MPConstraintProto& ct_proto =
416 model_.general_constraint(
ct_index).indicator_constraint().constraint();
417 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
422 return model_.general_constraint(
ct_index).indicator_constraint().var_index();
427 return model_.general_constraint(
ct_index)
428 .indicator_constraint()
435 return model_.constraint_size() + model_.general_constraint_size();
441 model_.set_name(
name);
444 for (MPVariableProto&
var : *model_.mutable_variable()) {
445 var.clear_objective_coefficient();
456 return model_.objective_offset();
460 model_.set_objective_offset(offset);
466 model_.mutable_solution_hint()->add_var_index(
var_index);
467 model_.mutable_solution_hint()->add_var_value(var_value);
471 const MPModelRequest& request) {
474 request.solver_type()))) {
481SolveStatus MPSolverResponseStatusToSolveStatus(MPSolverResponseStatus s) {
483 case MPSOLVER_OPTIMAL:
485 case MPSOLVER_FEASIBLE:
487 case MPSOLVER_INFEASIBLE:
489 case MPSOLVER_UNBOUNDED:
491 case MPSOLVER_ABNORMAL:
493 case MPSOLVER_NOT_SOLVED:
495 case MPSOLVER_MODEL_IS_VALID:
497 case MPSOLVER_CANCELLED_BY_USER:
499 case MPSOLVER_UNKNOWN_STATUS:
501 case MPSOLVER_MODEL_INVALID:
503 case MPSOLVER_MODEL_INVALID_SOLUTION_HINT:
505 case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS:
507 case MPSOLVER_SOLVER_TYPE_UNAVAILABLE:
509 case MPSOLVER_INCOMPATIBLE_OPTIONS:
518 if (solver_name.empty())
return;
521 VLOG(1) <<
"Unsupported type " << solver_name;
523 solver_type_ =
static_cast<MPModelRequest::SolverType
>(parsed_type);
528 if (!solver_type_.has_value())
return false;
529 if (solver_type_.value() == MPModelRequest::GLOP_LINEAR_PROGRAMMING) {
533 if (solver_type_.value() == MPModelRequest::PDLP_LINEAR_PROGRAMMING) {
537 if (solver_type_.value() == MPModelRequest::SAT_INTEGER_PROGRAMMING) {
541 if (solver_type_.value() == MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING) {
546 if (solver_type_.value() == MPModelRequest::HIGHS_LINEAR_PROGRAMMING ||
547 solver_type_.value() == MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING) {
551 if (solver_type_.value() ==
552 MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING ||
553 solver_type_.value() == MPModelRequest::GUROBI_LINEAR_PROGRAMMING) {
556 if (solver_type_.value() ==
557 MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING ||
558 solver_type_.value() == MPModelRequest::XPRESS_LINEAR_PROGRAMMING) {
566 if (!solver_type_.has_value()) {
567 response_->set_status(
568 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
572 MPModelRequest request;
573 *request.mutable_model() =
model.model();
574 request.set_solver_type(solver_type_.value());
575 request.set_enable_internal_solver_output(solver_output_);
576 if (time_limit_in_second_.has_value()) {
577 request.set_solver_time_limit_seconds(time_limit_in_second_.value());
579 if (!solver_specific_parameters_.empty()) {
580 request.set_solver_specific_parameters(solver_specific_parameters_);
582 switch (solver_type_.value()) {
583 case MPModelRequest::GLOP_LINEAR_PROGRAMMING: {
585 GlopSolveProto(std::move(request), &interrupt_solve_, log_callback_);
588 case MPModelRequest::SAT_INTEGER_PROGRAMMING: {
589 response_ =
SatSolveProto(std::move(request), &interrupt_solve_,
590 log_callback_,
nullptr);
594 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING: {
599 response_ = std::move(temp.value());
605 case MPModelRequest::PDLP_LINEAR_PROGRAMMING: {
608 response_ = std::move(temp.value());
613 case MPModelRequest::
614 GUROBI_LINEAR_PROGRAMMING:
615 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING: {
618 response_ = std::move(temp.value());
622#if defined(USE_HIGHS)
623 case MPModelRequest::HIGHS_LINEAR_PROGRAMMING:
624 case MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING: {
629 response_ = std::move(temp.value());
634 case MPModelRequest::
635 XPRESS_LINEAR_PROGRAMMING:
636 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING: {
641 response_->set_status(
642 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
645 if (response_->status() == MPSOLVER_OPTIMAL ||
646 response_->status() == MPSOLVER_FEASIBLE) {
647 model_of_last_solve_ = &
model.model();
648 activities_.assign(
model.num_constraints(),
649 std::numeric_limits<double>::quiet_NaN());
656 std::function<
void(
const std::string&)> log_callback) {
657 log_callback_ = std::move(log_callback);
662 log_callback_ = [log_callback](
const std::string&
message) {
671 interrupt_solve_ =
true;
678 return response_.has_value() &&
679 (response_.value().
status() ==
680 MPSolverResponseStatus::MPSOLVER_OPTIMAL ||
681 response_.value().status() ==
682 MPSolverResponseStatus::MPSOLVER_FEASIBLE);
686 return response_.value();
690 if (!response_.has_value()) {
693 return MPSolverResponseStatusToSolveStatus(response_.value().status());
698 return response_.value().objective_value();
703 return response_.value().best_objective_bound();
708 if (
var_index >= response_.value().variable_value_size())
return 0.0;
709 return response_.value().variable_value(
var_index);
714 if (
var_index >= response_.value().reduced_cost_size())
return 0.0;
715 return response_.value().reduced_cost(
var_index);
720 if (
ct_index >= response_.value().dual_value_size())
return 0.0;
721 return response_.value().dual_value(
ct_index);
726 !model_of_last_solve_.has_value()) {
730 if (std::isnan(activities_[
ct_index])) {
731 const MPConstraintProto& ct_proto =
732 model_of_last_solve_.value()->constraint(
ct_index);
734 for (
int i = 0; i < ct_proto.var_index_size(); ++i) {
735 result += response_->variable_value(ct_proto.var_index(i)) *
736 ct_proto.coefficient(i);
745 return response_.value().status_str();
749 if (!response_.has_value())
return 0.0;
750 if (!response_.value().has_solve_info())
return 0.0;
751 return response_.value().solve_info().solve_wall_time_seconds();
755 if (!response_.has_value())
return 0.0;
756 if (!response_.value().has_solve_info())
return 0.0;
757 return response_.value().solve_info().solve_user_time_seconds();
761 time_limit_in_second_ = limit;
765 const std::string& solver_specific_parameters) {
766 solver_specific_parameters_ = solver_specific_parameters;
static bool SupportsProblemType(OptimizationProblemType problem_type)
static
static bool ParseSolverType(absl::string_view solver_id, OptimizationProblemType *type)
static
Simple director class for C#.
virtual void NewMessage(const std::string &message)=0
void SetEnforcedConstraintLowerBound(int ct_index, double lb)
std::string ExportToLpString(const operations_research::MPModelExportOptions &options=MPModelExportOptions())
double ConstraintUpperBound(int ct_index) const
bool ReadModelFromProtoFile(const std::string &filename)
int AddEnforcedLinearConstraint()
int AddLinearConstraint()
const MPModelProto & model() const
void SetConstraintCoefficient(int ct_index, int var_index, double coeff)
void SafeAddEnforcedConstraintTerm(int ct_index, int var_index, double coeff)
double ConstraintLowerBound(int ct_index) const
bool EnforcedIndicatorValue(int ct_index) const
void SetMaximize(bool maximize)
void SetConstraintUpperBound(int ct_index, double ub)
void SetName(const std::string &name)
int num_constraints() const
void SetConstraintName(int ct_index, const std::string &name)
void SafeAddConstraintTerm(int ct_index, int var_index, double coeff)
void AddHint(int var_index, double var_value)
std::string VarName(int var_index) const
void SetVarObjectiveCoefficient(int var_index, double coeff)
void SetVarName(int var_index, const std::string &name)
int AddVar()
Direct low level model building API.
bool ImportFromMpsFile(const std::string &mps_file)
void ClearEnforcedConstraintTerms(int ct_index)
void SetEnforcedConstraintUpperBound(int ct_index, double ub)
void SetEnforcedConstraintName(int ct_index, const std::string &name)
double VarUpperBound(int var_index) const
double VarObjectiveCoefficient(int var_index) const
void SetObjectiveOffset(double offset)
bool VarIsIntegral(int var_index) const
double EnforcedConstraintLowerBound(int ct_index) const
void AddConstraintTerm(int ct_index, int var_index, double coeff)
void SetEnforcedIndicatorVariableIndex(int ct_index, int var_index)
std::vector< double > ConstraintCoefficients(int ct_index) const
void ClearConstraintTerms(int ct_index)
void SetConstraintLowerBound(int ct_index, double lb)
void SetEnforcedConstraintCoefficient(int ct_index, int var_index, double coeff)
bool ImportFromMpsString(const std::string &mps_string)
void AddEnforcedConstraintTerm(int ct_index, int var_index, double coeff)
bool WriteToMpsFile(const std::string &filename, const operations_research::MPModelExportOptions &options=MPModelExportOptions())
double VarLowerBound(int var_index) const
std::string ConstraintName(int ct_index) const
std::vector< double > EnforcedConstraintCoefficients(int ct_index) const
void SetEnforcedIndicatorValue(int ct_index, bool positive)
void SetVarIntegrality(int var_index, bool is_integer)
int num_variables() const
std::string EnforcedConstraintName(int ct_index) const
bool IsEnforcedConstraint(int ct_index) const
std::vector< int > EnforcedConstraintVarIndices(int ct_index) const
int EnforcedIndicatorVariableIndex(int ct_index) const
void SetVarUpperBound(int var_index, double ub)
std::string ExportToMpsString(const operations_research::MPModelExportOptions &options=MPModelExportOptions())
double EnforcedConstraintUpperBound(int ct_index) const
MPModelProto * mutable_model()
void SetVarLowerBound(int var_index, double lb)
bool WriteModelToProtoFile(const std::string &filename)
std::vector< int > ConstraintVarIndices(int ct_index) const
void OverwriteModel(const ModelBuilderHelper &other_helper)
double ObjectiveOffset() const
void Solve(const ModelBuilderHelper &model)
bool SolverIsSupported() const
bool has_solution() const
SolveStatus status() const
void SetSolverSpecificParameters(const std::string &solver_specific_parameters)
double objective_value() const
If not defined, or no solution, they will silently return 0.
bool has_response() const
std::optional< MPSolutionResponse > SolveRequest(const MPModelRequest &request)
Only used by the CVXPY interface. Does not store the response internally.
void SetLogCallback(std::function< void(const std::string &)> log_callback)
double dual_value(int ct_index) const
std::string status_string() const
double variable_value(int var_index) const
const MPSolutionResponse & response() const
double best_objective_bound() const
void SetLogCallbackFromDirectorClass(MbLogCallback *log_callback)
double activity(int ct_index)
void EnableOutput(bool enabled)
double reduced_cost(int var_index) const
ModelSolverHelper(const std::string &solver_name)
void SetTimeLimitInSeconds(double limit)
Solve parameters.
const std::string name
A name for logging purposes.
absl::Status SetTextProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
absl::Status SetBinaryProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::Status GetTextProto(absl::string_view filename, google::protobuf::Message *proto, Options options)
absl::Status GetBinaryProto(const absl::string_view filename, google::protobuf::Message *proto, Options options)
absl::StatusOr< MPModelProto > MpsFileToMPModelProto(absl::string_view mps_file)
Parses an MPS model from a file.
absl::StatusOr< MPModelProto > MpsDataToMPModelProto(absl::string_view mps_data)
Parses an MPS model from a string.
In SWIG mode, we don't want anything besides these top-level includes.
MPSolutionResponse SatSolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> logging_callback, std::function< void(const MPSolution &)> solution_callback)
absl::Status WriteModelToMpsFile(absl::string_view filename, const MPModelProto &model, const MPModelExportOptions &options)
MPSolutionResponse SolveMPModel(LazyMutableCopy< MPModelRequest > request, const SolveInterrupter *interrupter)
absl::StatusOr< MPSolutionResponse > PdlpSolveProto(LazyMutableCopy< MPModelRequest > request, const bool relax_integer_variables, const std::atomic< bool > *interrupt_solve)
absl::StatusOr< std::string > ExportModelAsLpFormat(const MPModelProto &model, const MPModelExportOptions &options)
bool GurobiIsCorrectlyInstalled()
absl::StatusOr< MPSolutionResponse > ScipSolveProto(LazyMutableCopy< MPModelRequest > request)
MPSolutionResponse GlopSolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> logging_callback)
bool XpressIsCorrectlyInstalled()
absl::StatusOr< MPSolutionResponse > GurobiSolveProto(LazyMutableCopy< MPModelRequest > request, GRBenv *gurobi_env)
absl::StatusOr< MPSolutionResponse > HighsSolveProto(LazyMutableCopy< MPModelRequest > request)
Solve the input MIP model with the HIGHS solver.
@ SOLVER_TYPE_UNAVAILABLE
@ INVALID_SOLVER_PARAMETERS
absl::StatusOr< std::string > ExportModelAsMpsFormat(const MPModelProto &model, const MPModelExportOptions &options)
MPSolutionResponse XPressSolveProto(LazyMutableCopy< MPModelRequest > request)
Solves the input request.