136 #ifndef OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_H_ 137 #define OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_H_ 139 #include <functional> 147 #include "absl/container/flat_hash_map.h" 148 #include "absl/strings/match.h" 149 #include "absl/strings/str_format.h" 150 #include "absl/types/optional.h" 151 #include "ortools/base/commandlineflags.h" 152 #include "ortools/base/integral_types.h" 153 #include "ortools/base/logging.h" 154 #include "ortools/base/macros.h" 155 #include "ortools/base/status.h" 156 #include "ortools/base/timer.h" 157 #include "ortools/glop/parameters.pb.h" 158 #include "ortools/linear_solver/linear_expr.h" 160 #include "ortools/port/proto_utils.h" 164 constexpr
double kDefaultPrimalTolerance = 1e-07;
168 class MPSolverInterface;
169 class MPSolverParameters;
180 enum OptimizationProblemType {
183 CLP_LINEAR_PROGRAMMING = 0,
186 GLPK_LINEAR_PROGRAMMING = 1,
189 GLOP_LINEAR_PROGRAMMING = 2,
192 GUROBI_LINEAR_PROGRAMMING = 6,
195 CPLEX_LINEAR_PROGRAMMING = 10,
200 SCIP_MIXED_INTEGER_PROGRAMMING = 3,
203 GLPK_MIXED_INTEGER_PROGRAMMING = 4,
206 CBC_MIXED_INTEGER_PROGRAMMING = 5,
208 #if defined(USE_GUROBI) 209 GUROBI_MIXED_INTEGER_PROGRAMMING = 7,
211 #if defined(USE_CPLEX) 212 CPLEX_MIXED_INTEGER_PROGRAMMING = 11,
215 BOP_INTEGER_PROGRAMMING = 12,
219 MPSolver(
const std::string& name, OptimizationProblemType problem_type);
224 static bool SupportsProblemType(OptimizationProblemType problem_type);
228 static bool ParseSolverType(absl::string_view solver,
229 OptimizationProblemType* type);
233 const std::string& Name()
const {
237 virtual OptimizationProblemType ProblemType()
const {
238 return problem_type_;
248 int NumVariables()
const {
return variables_.size(); }
251 const std::vector<MPVariable*>& variables()
const {
return variables_; }
255 MPVariable* LookupVariableOrNull(
const std::string& var_name)
const;
263 MPVariable* MakeVar(
double lb,
double ub,
bool integer,
264 const std::string& name);
266 MPVariable* MakeNumVar(
double lb,
double ub,
const std::string& name);
268 MPVariable* MakeIntVar(
double lb,
double ub,
const std::string& name);
270 MPVariable* MakeBoolVar(
const std::string& name);
277 void MakeVarArray(
int nb,
double lb,
double ub,
bool integer,
278 const std::string& name_prefix,
279 std::vector<MPVariable*>* vars);
281 void MakeNumVarArray(
int nb,
double lb,
double ub,
const std::string& name,
282 std::vector<MPVariable*>* vars);
284 void MakeIntVarArray(
int nb,
double lb,
double ub,
const std::string& name,
285 std::vector<MPVariable*>* vars);
287 void MakeBoolVarArray(
int nb,
const std::string& name,
288 std::vector<MPVariable*>* vars);
292 int NumConstraints()
const {
return constraints_.size(); }
295 const std::vector<MPConstraint*>& constraints()
const {
return constraints_; }
301 MPConstraint* LookupConstraintOrNull(
302 const std::string& constraint_name)
const;
308 MPConstraint* MakeRowConstraint(
double lb,
double ub);
310 MPConstraint* MakeRowConstraint();
312 MPConstraint* MakeRowConstraint(
double lb,
double ub,
313 const std::string& name);
315 MPConstraint* MakeRowConstraint(
const std::string& name);
319 MPConstraint* MakeRowConstraint(
const LinearRange& range);
321 MPConstraint* MakeRowConstraint(
const LinearRange& range,
322 const std::string& name);
327 const MPObjective& Objective()
const {
return *objective_; }
328 MPObjective* MutableObjective() {
return objective_.get(); }
347 ResultStatus Solve();
349 ResultStatus Solve(
const MPSolverParameters& param);
353 void Write(
const std::string& file_name);
359 std::vector<double> ComputeConstraintActivities()
const;
375 bool VerifySolution(
double tolerance,
bool log_errors)
const;
389 bool InterruptSolve();
398 std::string* error_message);
403 const MPModelProto& input_model, std::string* error_message);
407 void FillSolutionResponseProto(MPSolutionResponse* response)
const;
417 static void SolveWithProto(
const MPModelRequest& model_request,
418 MPSolutionResponse* response);
421 void ExportModelToProto(MPModelProto* output_model)
const;
454 util::Status LoadSolutionFromProto(
455 const MPSolutionResponse& response,
456 double tolerance = kDefaultPrimalTolerance);
460 util::Status ClampSolutionWithinBounds();
469 std::string* model_str)
const;
479 util::Status SetNumThreads(
int num_threads);
480 int GetNumThreads()
const {
return num_threads_; }
489 bool SetSolverSpecificParametersAsString(
const std::string& parameters);
490 std::string GetSolverSpecificParametersAsString()
const {
491 return solver_specific_parameter_string_;
506 void SetHint(std::vector<std::pair<const MPVariable*, double> > hint);
526 void SetStartingLpBasis(
527 const std::vector<MPSolver::BasisStatus>& variable_statuses,
528 const std::vector<MPSolver::BasisStatus>& constraint_statuses);
531 static double infinity() {
return std::numeric_limits<double>::infinity(); }
539 bool OutputIsEnabled()
const;
541 void SuppressOutput();
543 absl::Duration TimeLimit()
const {
return time_limit_; }
544 void SetTimeLimit(absl::Duration time_limit) {
545 DCHECK_GE(time_limit, absl::ZeroDuration());
546 time_limit_ = time_limit;
549 absl::Duration DurationSinceConstruction()
const {
550 return absl::Now() - construction_time_;
554 int64 iterations()
const;
561 std::string SolverVersion()
const;
574 void* underlying_solver();
597 double ComputeExactConditionNumber()
const;
611 ABSL_MUST_USE_RESULT
bool NextSolution();
616 int64 time_limit()
const {
617 return time_limit_ == absl::InfiniteDuration()
619 : absl::ToInt64Milliseconds(time_limit_);
621 void set_time_limit(int64 time_limit_milliseconds) {
622 SetTimeLimit(time_limit_milliseconds == 0
623 ? absl::InfiniteDuration()
624 : absl::Milliseconds(time_limit_milliseconds));
626 double time_limit_in_secs()
const {
627 return static_cast<double>(time_limit()) / 1000.0;
631 int64 wall_time()
const {
632 return absl::ToInt64Milliseconds(DurationSinceConstruction());
635 friend class GLPKInterface;
636 friend class CLPInterface;
637 friend class CBCInterface;
638 friend class SCIPInterface;
639 friend class GurobiInterface;
640 friend class CplexInterface;
641 friend class SLMInterface;
642 friend class MPSolverInterface;
643 friend class GLOPInterface;
644 friend class BopInterface;
645 friend class SatInterface;
646 friend class KnapsackInterface;
649 bool OwnsVariable(
const MPVariable* var)
const;
655 int ComputeMaxConstraintSize(
int min_constraint_index,
656 int max_constraint_index)
const;
659 bool HasInfeasibleConstraints()
const;
662 bool HasIntegerVariables()
const;
665 void GenerateVariableNameIndex()
const;
668 void GenerateConstraintNameIndex()
const;
671 const std::string name_;
674 const OptimizationProblemType problem_type_;
677 std::unique_ptr<MPSolverInterface> interface_;
680 std::vector<MPVariable*> variables_;
682 mutable absl::optional<absl::flat_hash_map<std::string, int> >
683 variable_name_to_index_;
685 std::vector<bool> variable_is_extracted_;
688 std::vector<MPConstraint*> constraints_;
690 mutable absl::optional<absl::flat_hash_map<std::string, int> >
691 constraint_name_to_index_;
693 std::vector<bool> constraint_is_extracted_;
696 std::unique_ptr<MPObjective> objective_;
705 std::vector<std::pair<const MPVariable*, double> > solution_hint_;
707 absl::Duration time_limit_ = absl::InfiniteDuration();
709 const absl::Time construction_time_;
712 int num_threads_ = 1;
715 std::string solver_specific_parameter_string_;
718 const MPModelProto& input_model,
bool clear_names,
719 std::string* error_message);
721 DISALLOW_COPY_AND_ASSIGN(MPSolver);
724 const absl::string_view ToString(
725 MPSolver::OptimizationProblemType optimization_problem_type);
727 inline std::ostream& operator<<(
729 MPSolver::OptimizationProblemType optimization_problem_type) {
730 return os << ToString(optimization_problem_type);
733 inline std::ostream& operator<<(std::ostream& os,
734 MPSolver::ResultStatus status) {
735 return os << ProtoEnumToString<MPSolverResponseStatus>(
736 static_cast<MPSolverResponseStatus>(status));
739 bool AbslParseFlag(absl::string_view text,
740 MPSolver::OptimizationProblemType* solver_type,
743 inline std::string AbslUnparseFlag(
744 MPSolver::OptimizationProblemType solver_type) {
745 return std::string(ToString(solver_type));
758 void SetCoefficient(
const MPVariable*
const var,
double coeff);
761 double GetCoefficient(
const MPVariable*
const var)
const;
765 const absl::flat_hash_map<const MPVariable*, double>& terms()
const {
766 return coefficients_;
770 void SetOffset(
double value);
772 double offset()
const {
return offset_; }
776 void OptimizeLinearExpr(
const LinearExpr& linear_expr,
bool is_maximization);
777 void MaximizeLinearExpr(
const LinearExpr& linear_expr) {
778 OptimizeLinearExpr(linear_expr,
true);
780 void MinimizeLinearExpr(
const LinearExpr& linear_expr) {
781 OptimizeLinearExpr(linear_expr,
false);
785 void AddLinearExpr(
const LinearExpr& linear_expr);
788 void SetOptimizationDirection(
bool maximize);
790 void SetMinimization() { SetOptimizationDirection(
false); }
792 void SetMaximization() { SetOptimizationDirection(
true); }
794 bool maximization()
const;
796 bool minimization()
const;
806 double Value()
const;
811 double BestBound()
const;
814 friend class MPSolver;
815 friend class MPSolverInterface;
816 friend class CBCInterface;
817 friend class CLPInterface;
818 friend class GLPKInterface;
819 friend class SCIPInterface;
820 friend class SLMInterface;
821 friend class GurobiInterface;
822 friend class CplexInterface;
823 friend class GLOPInterface;
824 friend class BopInterface;
825 friend class SatInterface;
826 friend class KnapsackInterface;
833 explicit MPObjective(MPSolverInterface*
const interface_in)
834 : interface_(interface_in), coefficients_(1), offset_(0.0) {}
836 MPSolverInterface*
const interface_;
839 absl::flat_hash_map<const MPVariable*, double> coefficients_;
843 DISALLOW_COPY_AND_ASSIGN(MPObjective);
850 const std::string& name()
const {
return name_; }
853 void SetInteger(
bool integer);
855 bool integer()
const {
return integer_; }
861 double solution_value()
const;
864 int index()
const {
return index_; }
867 double lb()
const {
return lb_; }
869 double ub()
const {
return ub_; }
871 void SetLB(
double lb) { SetBounds(lb, ub_); }
873 void SetUB(
double ub) { SetBounds(lb_, ub); }
875 void SetBounds(
double lb,
double ub);
879 double unrounded_solution_value()
const;
882 double reduced_cost()
const;
886 MPSolver::BasisStatus basis_status()
const;
895 int branching_priority()
const {
return branching_priority_; }
896 void SetBranchingPriority(
int priority);
899 friend class MPSolver;
900 friend class MPSolverInterface;
901 friend class CBCInterface;
902 friend class CLPInterface;
903 friend class GLPKInterface;
904 friend class SCIPInterface;
905 friend class SLMInterface;
906 friend class GurobiInterface;
907 friend class CplexInterface;
908 friend class GLOPInterface;
909 friend class MPVariableSolutionValueTest;
910 friend class BopInterface;
911 friend class SatInterface;
912 friend class KnapsackInterface;
917 MPVariable(
int index,
double lb,
double ub,
bool integer,
918 const std::string& name, MPSolverInterface*
const interface_in)
923 name_(name.empty() ? absl::StrFormat(
"auto_v_%09d", index) : name),
924 solution_value_(0.0),
926 interface_(interface_in) {}
928 void set_solution_value(
double value) { solution_value_ = value; }
929 void set_reduced_cost(
double reduced_cost) { reduced_cost_ = reduced_cost; }
936 const std::string name_;
937 double solution_value_;
938 double reduced_cost_;
939 int branching_priority_ = 0;
940 MPSolverInterface*
const interface_;
941 DISALLOW_COPY_AND_ASSIGN(MPVariable);
949 const std::string& name()
const {
return name_; }
957 void SetCoefficient(
const MPVariable*
const var,
double coeff);
960 double GetCoefficient(
const MPVariable*
const var)
const;
964 const absl::flat_hash_map<const MPVariable*, double>& terms()
const {
965 return coefficients_;
969 double lb()
const {
return lb_; }
971 double ub()
const {
return ub_; }
973 void SetLB(
double lb) { SetBounds(lb, ub_); }
975 void SetUB(
double ub) { SetBounds(lb_, ub); }
977 void SetBounds(
double lb,
double ub);
980 bool is_lazy()
const {
return is_lazy_; }
989 void set_is_lazy(
bool laziness) { is_lazy_ = laziness; }
991 const MPVariable* indicator_variable()
const {
return indicator_variable_; }
992 bool indicator_value()
const {
return indicator_value_; }
995 int index()
const {
return index_; }
999 double dual_value()
const;
1008 MPSolver::BasisStatus basis_status()
const;
1011 friend class MPSolver;
1012 friend class MPSolverInterface;
1013 friend class CBCInterface;
1014 friend class CLPInterface;
1015 friend class GLPKInterface;
1016 friend class SCIPInterface;
1017 friend class SLMInterface;
1018 friend class GurobiInterface;
1019 friend class CplexInterface;
1020 friend class GLOPInterface;
1021 friend class BopInterface;
1022 friend class SatInterface;
1023 friend class KnapsackInterface;
1028 MPConstraint(
int index,
double lb,
double ub,
const std::string& name,
1029 MPSolverInterface*
const interface_in)
1034 name_(name.empty() ? absl::StrFormat(
"auto_c_%09d", index) : name),
1036 indicator_variable_(nullptr),
1038 interface_(interface_in) {}
1040 void set_dual_value(
double dual_value) { dual_value_ = dual_value; }
1045 bool ContainsNewVariables();
1048 absl::flat_hash_map<const MPVariable*, double> coefficients_;
1059 const std::string name_;
1068 const MPVariable* indicator_variable_;
1069 bool indicator_value_;
1072 MPSolverInterface*
const interface_;
1073 DISALLOW_COPY_AND_ASSIGN(MPConstraint);
1100 class MPSolverParameters {
1105 RELATIVE_MIP_GAP = 0,
1110 PRIMAL_TOLERANCE = 1,
1120 LP_ALGORITHM = 1001,
1122 INCREMENTALITY = 1002,
1128 enum PresolveValues {
1133 enum LpAlgorithmValues {
1139 enum IncrementalityValues {
1141 INCREMENTALITY_OFF = 0,
1144 INCREMENTALITY_ON = 1
1147 enum ScalingValues {
1155 static const double kDefaultDoubleParamValue;
1156 static const int kDefaultIntegerParamValue;
1161 static const double kUnknownDoubleParamValue;
1162 static const int kUnknownIntegerParamValue;
1171 static const double kDefaultRelativeMipGap;
1172 static const double kDefaultPrimalTolerance;
1173 static const double kDefaultDualTolerance;
1174 static const PresolveValues kDefaultPresolve;
1175 static const IncrementalityValues kDefaultIncrementality;
1179 MPSolverParameters();
1183 void SetDoubleParam(MPSolverParameters::DoubleParam param,
double value);
1184 void SetIntegerParam(MPSolverParameters::IntegerParam param,
int value);
1191 void ResetDoubleParam(MPSolverParameters::DoubleParam param);
1192 void ResetIntegerParam(MPSolverParameters::IntegerParam param);
1199 double GetDoubleParam(MPSolverParameters::DoubleParam param)
const;
1200 int GetIntegerParam(MPSolverParameters::IntegerParam param)
const;
1208 double relative_mip_gap_value_;
1209 double primal_tolerance_value_;
1210 double dual_tolerance_value_;
1211 int presolve_value_;
1213 int lp_algorithm_value_;
1214 int incrementality_value_;
1220 bool lp_algorithm_is_default_;
1222 DISALLOW_COPY_AND_ASSIGN(MPSolverParameters);
1234 class MPSolverInterface {
1236 enum SynchronizationStatus {
1246 SOLUTION_SYNCHRONIZED
1251 static const int64 kUnknownNumberOfIterations = -1;
1254 static const int64 kUnknownNumberOfNodes = -1;
1258 explicit MPSolverInterface(MPSolver*
const solver);
1259 virtual ~MPSolverInterface();
1264 virtual MPSolver::ResultStatus Solve(
const MPSolverParameters& param) = 0;
1268 virtual void Write(
const std::string& filename);
1272 virtual void Reset() = 0;
1275 virtual void SetOptimizationDirection(
bool maximize) = 0;
1278 virtual void SetVariableBounds(
int index,
double lb,
double ub) = 0;
1281 virtual void SetVariableInteger(
int index,
bool integer) = 0;
1284 virtual void SetConstraintBounds(
int index,
double lb,
double ub) = 0;
1287 virtual void AddRowConstraint(MPConstraint*
const ct) = 0;
1291 virtual bool AddIndicatorConstraint(MPConstraint*
const ct) {
1292 LOG(ERROR) <<
"Solver doesn't support indicator constraints.";
1297 virtual void AddVariable(MPVariable*
const var) = 0;
1300 virtual void SetCoefficient(MPConstraint*
const constraint,
1301 const MPVariable*
const variable,
1302 double new_value,
double old_value) = 0;
1305 virtual void ClearConstraint(MPConstraint*
const constraint) = 0;
1308 virtual void SetObjectiveCoefficient(
const MPVariable*
const variable,
1309 double coefficient) = 0;
1312 virtual void SetObjectiveOffset(
double value) = 0;
1315 virtual void ClearObjective() = 0;
1317 virtual void BranchingPriorityChangedForVariable(
int var_index) {}
1321 virtual int64 iterations()
const = 0;
1324 virtual int64 nodes()
const = 0;
1327 virtual double best_objective_bound()
const = 0;
1330 double trivial_worst_objective_bound()
const;
1332 double objective_value()
const;
1335 virtual MPSolver::BasisStatus row_status(
int constraint_index)
const = 0;
1337 virtual MPSolver::BasisStatus column_status(
int variable_index)
const = 0;
1342 bool CheckSolutionIsSynchronized()
const;
1345 virtual bool CheckSolutionExists()
const;
1347 bool CheckSolutionIsSynchronizedAndExists()
const {
1348 return CheckSolutionIsSynchronized() && CheckSolutionExists();
1352 virtual bool CheckBestObjectiveBoundExists()
const;
1361 virtual bool IsContinuous()
const = 0;
1363 virtual bool IsLP()
const = 0;
1365 virtual bool IsMIP()
const = 0;
1368 int last_variable_index()
const {
return last_variable_index_; }
1370 bool variable_is_extracted(
int var_index)
const {
1371 return solver_->variable_is_extracted_[var_index];
1373 void set_variable_as_extracted(
int var_index,
bool extracted) {
1374 solver_->variable_is_extracted_[var_index] = extracted;
1376 bool constraint_is_extracted(
int ct_index)
const {
1377 return solver_->constraint_is_extracted_[ct_index];
1379 void set_constraint_as_extracted(
int ct_index,
bool extracted) {
1380 solver_->constraint_is_extracted_[ct_index] = extracted;
1384 bool quiet()
const {
return quiet_; }
1386 void set_quiet(
bool quiet_value) { quiet_ = quiet_value; }
1389 MPSolver::ResultStatus result_status()
const {
1390 CheckSolutionIsSynchronized();
1391 return result_status_;
1395 virtual std::string SolverVersion()
const = 0;
1398 virtual void* underlying_solver() = 0;
1402 virtual double ComputeExactConditionNumber()
const;
1405 virtual void SetStartingLpBasis(
1406 const std::vector<MPSolver::BasisStatus>& variable_statuses,
1407 const std::vector<MPSolver::BasisStatus>& constraint_statuses) {
1408 LOG(FATAL) <<
"Not supported by this solver.";
1411 virtual bool InterruptSolve() {
return false; }
1414 virtual bool NextSolution() {
return false; }
1416 friend class MPSolver;
1419 friend class MPConstraint;
1420 friend class MPObjective;
1423 MPSolver*
const solver_;
1425 SynchronizationStatus sync_status_;
1428 MPSolver::ResultStatus result_status_;
1433 int last_constraint_index_;
1435 int last_variable_index_;
1438 double objective_value_;
1445 static const int kDummyVariableIndex;
1448 void ExtractModel();
1450 virtual void ExtractNewVariables() = 0;
1452 virtual void ExtractNewConstraints() = 0;
1454 virtual void ExtractObjective() = 0;
1456 void ResetExtractionInformation();
1459 void InvalidateSolutionSynchronization();
1462 void SetCommonParameters(
const MPSolverParameters& param);
1464 void SetMIPParameters(
const MPSolverParameters& param);
1466 virtual void SetParameters(
const MPSolverParameters& param) = 0;
1468 void SetUnsupportedDoubleParam(MPSolverParameters::DoubleParam param);
1470 virtual void SetUnsupportedIntegerParam(
1471 MPSolverParameters::IntegerParam param);
1473 void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param,
1476 virtual void SetIntegerParamToUnsupportedValue(
1477 MPSolverParameters::IntegerParam param,
int value);
1479 virtual void SetRelativeMipGap(
double value) = 0;
1480 virtual void SetPrimalTolerance(
double value) = 0;
1481 virtual void SetDualTolerance(
double value) = 0;
1482 virtual void SetPresolveMode(
int value) = 0;
1485 virtual util::Status SetNumThreads(
int num_threads);
1495 virtual bool SetSolverSpecificParametersAsString(
1496 const std::string& parameters);
1500 virtual bool ReadParameterFile(
const std::string& filename);
1505 virtual std::string ValidFileExtensionForParameterFile()
const;
1508 virtual void SetScalingMode(
int value) = 0;
1509 virtual void SetLpAlgorithm(
int value) = 0;
1514 #endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_H_ util::StatusOr< std::string > ExportModelAsMpsFormat(const MPModelProto &model, const MPModelExportOptions &options=MPModelExportOptions())
Outputs the current model (variables, constraints, objective) as a std::string encoded in MPS file fo...
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in c...
util::StatusOr< std::string > ExportModelAsLpFormat(const MPModelProto &model, const MPModelExportOptions &options=MPModelExportOptions())
Outputs the current model (variables, constraints, objective) as a std::string encoded in the so-call...