00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "linear_solver/linear_solver.h"
00017
00018 #include <cmath>
00019 #include <cstddef>
00020 #include <utility>
00021
00022 #include "base/commandlineflags.h"
00023 #include "base/integral_types.h"
00024 #include "base/logging.h"
00025 #include "base/scoped_ptr.h"
00026 #include "base/stringprintf.h"
00027 #include "base/timer.h"
00028 #include "base/concise_iterator.h"
00029 #include "base/map-util.h"
00030 #include "base/stl_util.h"
00031 #include "base/hash.h"
00032
00033 #include "linear_solver/linear_solver.pb.h"
00034
00035 DEFINE_string(solver_write_model,
00036 "",
00037 "Path of the file to write the model to.");
00038
00039
00040
00041
00042
00043 namespace operations_research {
00044
00045 double MPConstraint::GetCoefficient(const MPVariable* const var) const {
00046 return FindWithDefault(coefficients_, var, 0);
00047 }
00048
00049 void MPConstraint::SetCoefficient(const MPVariable* const var, double coeff) {
00050 CHECK_NOTNULL(var);
00051 if (coeff == 0.0) {
00052 hash_map<const MPVariable*, double>::iterator it = coefficients_.find(var);
00053
00054
00055
00056
00057
00058
00059
00060 if (it != coefficients_.end() && it->second != 0.0) {
00061 const double old_value = it->second;
00062 it->second = 0.0;
00063 interface_->SetCoefficient(this, var, 0.0, old_value);
00064 }
00065 return;
00066 }
00067 std::pair<hash_map<const MPVariable*, double>::iterator, bool>
00068 insertion_result =
00069 coefficients_.insert(std::make_pair(var, coeff));
00070 const double old_value =
00071 insertion_result.second ? 0.0 : insertion_result.first->second;
00072 insertion_result.first->second = coeff;
00073 interface_->SetCoefficient(this, var, coeff, old_value);
00074 }
00075
00076 void MPConstraint::Clear() {
00077 interface_->ClearConstraint(this);
00078 coefficients_.clear();
00079 }
00080
00081 void MPConstraint::SetBounds(double lb, double ub) {
00082 const bool change = lb != lb_ || ub != ub_;
00083 lb_ = lb;
00084 ub_ = ub;
00085 if (index_ != MPSolverInterface::kNoIndex && change) {
00086 interface_->SetConstraintBounds(index_, lb_, ub_);
00087 }
00088 }
00089
00090 double MPConstraint::dual_value() const {
00091 CHECK(interface_->IsContinuous()) <<
00092 "Dual value only available for continuous problems";
00093 interface_->CheckSolutionIsSynchronizedAndExists();
00094 return dual_value_;
00095 }
00096
00097 MPSolver::BasisStatus MPConstraint::basis_status() const {
00098 CHECK(interface_->IsContinuous()) <<
00099 "Basis status only available for continuous problems";
00100 interface_->CheckSolutionIsSynchronizedAndExists();
00101
00102 return interface_->row_status(index_);
00103 }
00104
00105 double MPConstraint::activity() const {
00106 interface_->CheckSolutionIsSynchronizedAndExists();
00107 return activity_;
00108 }
00109
00110 bool MPConstraint::ContainsNewVariables() {
00111 const int last_variable_index = interface_->last_variable_index();
00112 for (ConstIter<hash_map<const MPVariable*, double> > it(coefficients_);
00113 !it.at_end(); ++it) {
00114 const int variable_index = it->first->index();
00115 if (variable_index >= last_variable_index ||
00116 variable_index == MPSolverInterface::kNoIndex) {
00117 return true;
00118 }
00119 }
00120 return false;
00121 }
00122
00123
00124
00125 double MPObjective::GetCoefficient(const MPVariable* const var) const {
00126 return FindWithDefault(coefficients_, var, 0);
00127 }
00128
00129 void MPObjective::SetCoefficient(const MPVariable* const var, double coeff) {
00130 CHECK_NOTNULL(var);
00131 if (coeff == 0.0) {
00132 hash_map<const MPVariable*, double>::iterator it = coefficients_.find(var);
00133
00134
00135 if (it == coefficients_.end() || it->second == 0.0) return;
00136 it->second = 0.0;
00137 } else {
00138 coefficients_[var] = coeff;
00139 }
00140 interface_->SetObjectiveCoefficient(var, coeff);
00141 }
00142
00143 void MPObjective::SetOffset(double value) {
00144 offset_ = value;
00145 interface_->SetObjectiveOffset(offset_);
00146 }
00147
00148 void MPObjective::Clear() {
00149 interface_->ClearObjective();
00150 coefficients_.clear();
00151 offset_ = 0.0;
00152 SetMinimization();
00153 }
00154
00155 void MPObjective::SetOptimizationDirection(bool maximize) {
00156
00157
00158
00159
00160
00161
00162 interface_->maximize_ = maximize;
00163 interface_->SetOptimizationDirection(maximize);
00164 }
00165
00166 bool MPObjective::maximization() const {
00167 return interface_->maximize_;
00168 }
00169
00170 bool MPObjective::minimization() const {
00171 return !interface_->maximize_;
00172 }
00173
00174 double MPObjective::Value() const {
00175
00176
00177
00178 return interface_->objective_value();
00179 }
00180
00181 double MPObjective::BestBound() const {
00182
00183
00184 return interface_->best_objective_bound();
00185 }
00186
00187
00188
00189 double MPVariable::solution_value() const {
00190 interface_->CheckSolutionIsSynchronizedAndExists();
00191 return solution_value_;
00192 }
00193
00194 double MPVariable::reduced_cost() const {
00195 CHECK(interface_->IsContinuous()) <<
00196 "Reduced cost only available for continuous problems";
00197 interface_->CheckSolutionIsSynchronizedAndExists();
00198 return reduced_cost_;
00199 }
00200
00201 MPSolver::BasisStatus MPVariable::basis_status() const {
00202 CHECK(interface_->IsContinuous()) <<
00203 "Basis status only available for continuous problems";
00204 interface_->CheckSolutionIsSynchronizedAndExists();
00205
00206 return interface_->column_status(index_);
00207 }
00208
00209 void MPVariable::SetBounds(double lb, double ub) {
00210 const bool change = lb != lb_ || ub != ub_;
00211 lb_ = lb;
00212 ub_ = ub;
00213 if (index_ != MPSolverInterface::kNoIndex && change) {
00214 interface_->SetVariableBounds(index_, lb_, ub_);
00215 }
00216 }
00217
00218 void MPVariable::SetInteger(bool integer) {
00219 if (integer_ != integer) {
00220 integer_ = integer;
00221 if (index_ != MPSolverInterface::kNoIndex) {
00222 interface_->SetVariableInteger(index_, integer);
00223 }
00224 }
00225 }
00226
00227
00228
00229 double MPSolver::objective_value() const {
00230 return Objective().Value();
00231 }
00232
00233 double MPSolver::best_objective_bound() const {
00234 return Objective().BestBound();
00235 }
00236
00237 void MPSolver::ClearObjective() {
00238 MutableObjective()->Clear();
00239 }
00240
00241 void MPSolver::SetObjectiveCoefficient(const MPVariable* const var,
00242 double coeff) {
00243 MutableObjective()->SetCoefficient(var, coeff);
00244 }
00245
00246 void MPSolver::SetObjectiveOffset(double value) {
00247 MutableObjective()->SetOffset(value);
00248 }
00249
00250 void MPSolver::AddObjectiveOffset(double value) {
00251 MutableObjective()->AddOffset(value);
00252 }
00253
00254 void MPSolver::SetOptimizationDirection(bool maximize) {
00255 MutableObjective()->SetOptimizationDirection(maximize);
00256 }
00257
00258 bool MPSolver::Maximization() const {
00259 return Objective().maximization();
00260 }
00261
00262 bool MPSolver::Minimization() const {
00263 return Objective().minimization();
00264 }
00265
00266
00267
00268 string MPSolver::SolverVersion() const {
00269 return interface_->SolverVersion();
00270 }
00271
00272
00273
00274 void* MPSolver::underlying_solver() {
00275 return interface_->underlying_solver();
00276 }
00277
00278
00279
00280 #if defined(USE_CLP) || defined(USE_CBC)
00281 extern MPSolverInterface* BuildCLPInterface(MPSolver* const solver);
00282 #endif
00283 #if defined(USE_CBC)
00284 extern MPSolverInterface* BuildCBCInterface(MPSolver* const solver);
00285 #endif
00286 #if defined(USE_GLPK)
00287 extern MPSolverInterface* BuildGLPKInterface(MPSolver* const solver, bool mip);
00288 #endif
00289 #if defined(USE_SCIP)
00290 extern MPSolverInterface* BuildSCIPInterface(MPSolver* const solver);
00291 #endif
00292
00293 namespace {
00294 MPSolverInterface* BuildSolverInterface(
00295 MPSolver* const solver, MPSolver::OptimizationProblemType problem_type) {
00296 switch (problem_type) {
00297 #if defined(USE_GLPK)
00298 case MPSolver::GLPK_LINEAR_PROGRAMMING:
00299 return BuildGLPKInterface(solver, false);
00300 case MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING:
00301 return BuildGLPKInterface(solver, true);
00302 #endif
00303 #if defined(USE_CLP) || defined(USE_CBC)
00304 case MPSolver::CLP_LINEAR_PROGRAMMING:
00305 return BuildCLPInterface(solver);
00306 #endif
00307 #if defined(USE_CBC)
00308 case MPSolver::CBC_MIXED_INTEGER_PROGRAMMING:
00309 return BuildCBCInterface(solver);
00310 #endif
00311 #if defined(USE_SCIP)
00312 case MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING:
00313 return BuildSCIPInterface(solver);
00314 #endif
00315 default:
00316 LOG(FATAL) << "Linear solver not recognized.";
00317 }
00318 return NULL;
00319 }
00320 }
00321
00322 MPSolver::MPSolver(const string& name, OptimizationProblemType problem_type)
00323 : name_(name),
00324 interface_(BuildSolverInterface(this, problem_type)),
00325 objective_(new MPObjective(interface_.get())),
00326 time_limit_(0.0),
00327 write_model_filename_("") {
00328 timer_.Restart();
00329 }
00330
00331 MPSolver::~MPSolver() {
00332 Clear();
00333 }
00334
00335 MPVariable* MPSolver::LookupVariableOrNull(const string& var_name) const {
00336 hash_map<string, int>::const_iterator it =
00337 variable_name_to_index_.find(var_name);
00338 if (it == variable_name_to_index_.end()) return NULL;
00339 return variables_[it->second];
00340 }
00341
00342 MPConstraint* MPSolver::LookupConstraintOrNull(
00343 const string& constraint_name) const {
00344 hash_map<string, int>::const_iterator it =
00345 constraint_name_to_index_.find(constraint_name);
00346 if (it == constraint_name_to_index_.end()) return NULL;
00347 return constraints_[it->second];
00348 }
00349
00350
00351
00352 bool MPSolver::CheckNameValidity(const string& name) {
00353 if (name.empty()) {
00354 LOG(DFATAL)
00355 << "Bug! CheckNameValidity() should never encounter an empty name.";
00356 }
00357
00358 const int kMaxNameLength = 255;
00359 if (name.size() > kMaxNameLength) {
00360 LOG(WARNING) << "Invalid name " << name
00361 << ": length > " << kMaxNameLength << "."
00362 << " Will be unable to write model to file.";
00363 return false;
00364 }
00365 if (name.find_first_of(" +-*<>=:\\") != string::npos) {
00366 LOG(WARNING) << "Invalid name " << name
00367 << ": contains forbidden character: +-*<>=:\\ space."
00368 << " Will be unable to write model to file.";
00369 return false;
00370 }
00371 size_t first_occurrence = name.find_first_of(".0123456789");
00372 if (first_occurrence != string::npos && first_occurrence == 0) {
00373 LOG(WARNING) << "Invalid name " << name
00374 << ": first character should not be . or a number."
00375 << " Will be unable to write model to file.";
00376 return false;
00377 }
00378 return true;
00379 }
00380
00381 bool MPSolver::CheckAllNamesValidity() {
00382 for (int i = 0; i < variables_.size(); ++i) {
00383 if (!CheckNameValidity(variables_[i]->name())) {
00384 return false;
00385 }
00386 }
00387 for (int i = 0; i < constraints_.size(); ++i) {
00388 if (!CheckNameValidity(constraints_[i]->name())) {
00389 return false;
00390 }
00391 }
00392 return true;
00393 }
00394
00395
00396
00397 MPSolver::LoadStatus MPSolver::LoadModel(const MPModelProto& input_model) {
00398 hash_map<string, MPVariable*> variables;
00399 for (int i = 0; i < input_model.variables_size(); ++i) {
00400 const MPVariableProto& var_proto = input_model.variables(i);
00401 const string& id = var_proto.id();
00402 if (!ContainsKey(variables, id)) {
00403 MPVariable* variable = MakeNumVar(var_proto.lb(), var_proto.ub(), id);
00404 variable->SetInteger(var_proto.integer());
00405 variables[id] = variable;
00406 } else {
00407 return MPSolver::DUPLICATE_VARIABLE_ID;
00408 }
00409 }
00410
00411 hash_set<MPVariable*> tmp_variable_set;
00412 for (int i = 0; i < input_model.constraints_size(); ++i) {
00413 tmp_variable_set.clear();
00414 const MPConstraintProto& ct_proto = input_model.constraints(i);
00415 const string& ct_id = ct_proto.has_id() ? ct_proto.id() : "";
00416 MPConstraint* const ct = MakeRowConstraint(ct_proto.lb(),
00417 ct_proto.ub(),
00418 ct_id);
00419 for (int j = 0; j < ct_proto.terms_size(); ++j) {
00420 const MPTermProto& term_proto = ct_proto.terms(j);
00421 const string& id = term_proto.variable_id();
00422 MPVariable* variable = FindPtrOrNull(variables, id);
00423 if (variable == NULL) {
00424 return MPSolver::UNKNOWN_VARIABLE_ID;
00425 }
00426 if (!tmp_variable_set.insert(variable).second) {
00427 LOG(WARNING)
00428 << "Multiple terms on the same variable within the same"
00429 << " constraint; keeping only the last term into account.\n"
00430 << "Variable: " << variable->name()
00431 << ", in Constraint: " << ct_id
00432 << ", in Model '" << input_model.name() << "'.";
00433 }
00434 ct->SetCoefficient(variable, term_proto.coefficient());
00435 }
00436 }
00437 tmp_variable_set.clear();
00438 for (int i = 0; i < input_model.objective_terms_size(); ++i) {
00439 const MPTermProto& term_proto = input_model.objective_terms(i);
00440 const string& id = term_proto.variable_id();
00441 MPVariable* variable = FindPtrOrNull(variables, id);
00442 if (variable == NULL) {
00443 return MPSolver::UNKNOWN_VARIABLE_ID;
00444 }
00445 if (!tmp_variable_set.insert(variable).second) {
00446 LOG(WARNING)
00447 << "Multiple terms on the same variable within the"
00448 << " objective; keeping only the last term into account.\n"
00449 << "Variable: " << variable->name()
00450 << ", in Model '" << input_model.name() << "'.";
00451 }
00452 SetObjectiveCoefficient(variable, term_proto.coefficient());
00453 }
00454 SetOptimizationDirection(input_model.maximize());
00455 if (input_model.has_objective_offset()) {
00456 MutableObjective()->SetOffset(input_model.objective_offset());
00457 }
00458 return MPSolver::NO_ERROR;
00459 }
00460
00461 void MPSolver::ExportModel(MPModelProto* output_model) const {
00462 CHECK_NOTNULL(output_model);
00463 if (output_model->variables_size() > 0 ||
00464 output_model->has_maximize() ||
00465 output_model->objective_terms_size() > 0 ||
00466 output_model->constraints_size() > 0 ||
00467 output_model->has_name() ||
00468 output_model->has_objective_offset()) {
00469 LOG(WARNING) << "The model protocol buffer is not empty, "
00470 << "it will be overwritten.";
00471 output_model->clear_variables();
00472 output_model->clear_maximize();
00473 output_model->clear_objective_terms();
00474 output_model->clear_constraints();
00475 output_model->clear_name();
00476 }
00477
00478
00479 for (int j = 0; j < variables_.size(); ++j) {
00480 const MPVariable* const var = variables_[j];
00481 MPVariableProto* const variable_proto = output_model->add_variables();
00482 DCHECK(!var->name().empty());
00483 variable_proto->set_id(var->name());
00484 variable_proto->set_lb(var->lb());
00485 variable_proto->set_ub(var->ub());
00486 variable_proto->set_integer(var->integer());
00487 }
00488
00489
00490 for (int i = 0; i < constraints_.size(); ++i) {
00491 MPConstraint* const constraint = constraints_[i];
00492 MPConstraintProto* const constraint_proto = output_model->add_constraints();
00493
00494 DCHECK(!constraint->name().empty());
00495 constraint_proto->set_id(constraint->name());
00496 constraint_proto->set_lb(constraint->lb());
00497 constraint_proto->set_ub(constraint->ub());
00498 for (ConstIter<hash_map<const MPVariable*, double> >
00499 it(constraint->coefficients_);
00500 !it.at_end(); ++it) {
00501 const MPVariable* const var = it->first;
00502 const double coef = it->second;
00503 MPTermProto* const term = constraint_proto->add_terms();
00504 term->set_variable_id(var->name());
00505 term->set_coefficient(coef);
00506 }
00507 }
00508
00509
00510 for (hash_map<const MPVariable*, double>::const_iterator it =
00511 objective_->coefficients_.begin();
00512 it != objective_->coefficients_.end();
00513 ++it) {
00514 const MPVariable* const var = it->first;
00515 const double coef = it->second;
00516 MPTermProto* const term = output_model->add_objective_terms();
00517 term->set_variable_id(var->name());
00518 term->set_coefficient(coef);
00519 }
00520 output_model->set_maximize(Objective().maximization());
00521 output_model->set_objective_offset(Objective().offset());
00522 }
00523
00524 void MPSolver::FillSolutionResponse(MPSolutionResponse* response) const {
00525 CHECK_NOTNULL(response);
00526 if ((response->has_result_status() &&
00527 response->result_status() != MPSolutionResponse::NOT_SOLVED) ||
00528 response->has_objective_value() ||
00529 response->solution_values_size() > 0) {
00530 LOG(WARNING) << "The solution response is not empty, "
00531 << "it will be overwritten.";
00532 response->clear_result_status();
00533 response->clear_objective_value();
00534 response->clear_solution_values();
00535 }
00536
00537 switch (interface_->result_status_) {
00538 case MPSolver::OPTIMAL : {
00539 response->set_result_status(MPSolutionResponse::OPTIMAL);
00540 break;
00541 }
00542 case MPSolver::FEASIBLE : {
00543 response->set_result_status(MPSolutionResponse::FEASIBLE);
00544 break;
00545 }
00546 case MPSolver::INFEASIBLE : {
00547 response->set_result_status(MPSolutionResponse::INFEASIBLE);
00548 break;
00549 }
00550 case MPSolver::UNBOUNDED : {
00551 response->set_result_status(MPSolutionResponse::UNBOUNDED);
00552 break;
00553 }
00554 case MPSolver::ABNORMAL : {
00555 response->set_result_status(MPSolutionResponse::ABNORMAL);
00556 break;
00557 }
00558 case MPSolver::NOT_SOLVED : {
00559 response->set_result_status(MPSolutionResponse::NOT_SOLVED);
00560 break;
00561 }
00562 default: {
00563 response->set_result_status(MPSolutionResponse::ABNORMAL);
00564 }
00565 }
00566 if (interface_->result_status_ == MPSolver::OPTIMAL ||
00567 interface_->result_status_ == MPSolver::FEASIBLE) {
00568 response->set_objective_value(objective_value());
00569 for (int i = 0; i < variables_.size(); ++i) {
00570 const MPVariable* const var = variables_[i];
00571 double solution_value = var->solution_value();
00572
00573 if (solution_value != 0.0) {
00574 MPSolutionValue* value = response->add_solution_values();
00575 value->set_variable_id(var->name());
00576 value->set_value(solution_value);
00577 }
00578 }
00579 }
00580 }
00581
00582
00583 void MPSolver::SolveWithProtocolBuffers(const MPModelRequest& model_request,
00584 MPSolutionResponse* response) {
00585 CHECK_NOTNULL(response);
00586 const MPModelProto& model = model_request.model();
00587 MPSolver solver(model.name(),
00588 static_cast<MPSolver::OptimizationProblemType>(
00589 model_request.problem_type()));
00590 const MPSolver::LoadStatus loadStatus = solver.LoadModel(model);
00591 if (loadStatus != MPSolver::NO_ERROR) {
00592 LOG(WARNING) << "Loading model from protocol buffer failed, "
00593 << "load status = " << loadStatus;
00594 response->set_result_status(MPSolutionResponse::ABNORMAL);
00595 }
00596
00597 if (model_request.has_time_limit_ms()) {
00598 solver.set_time_limit(model_request.time_limit_ms());
00599 }
00600 solver.Solve();
00601 solver.FillSolutionResponse(response);
00602 }
00603
00604 void MPSolver::Clear() {
00605 ClearObjective();
00606 STLDeleteElements(&variables_);
00607 STLDeleteElements(&constraints_);
00608 variables_.clear();
00609 variable_name_to_index_.clear();
00610 constraints_.clear();
00611 constraint_name_to_index_.clear();
00612 interface_->Reset();
00613 }
00614
00615 void MPSolver::Reset() {
00616 interface_->Reset();
00617 }
00618
00619 void MPSolver::EnableOutput() {
00620 interface_->set_quiet(false);
00621 }
00622
00623 void MPSolver::SuppressOutput() {
00624 interface_->set_quiet(true);
00625 }
00626
00627 MPVariable* MPSolver::MakeVar(
00628 double lb, double ub, bool integer, const string& name) {
00629 const int var_index = NumVariables();
00630 const string fixed_name = name.empty()
00631 ? StringPrintf("auto_variable_%06d", var_index) : name;
00632 CheckNameValidity(fixed_name);
00633 InsertOrDie(&variable_name_to_index_, fixed_name, var_index);
00634 MPVariable* v = new MPVariable(lb, ub, integer, fixed_name, interface_.get());
00635 variables_.push_back(v);
00636 interface_->AddVariable(v);
00637 return v;
00638 }
00639
00640 MPVariable* MPSolver::MakeNumVar(
00641 double lb, double ub, const string& name) {
00642 return MakeVar(lb, ub, false, name);
00643 }
00644
00645 MPVariable* MPSolver::MakeIntVar(
00646 double lb, double ub, const string& name) {
00647 return MakeVar(lb, ub, true, name);
00648 }
00649
00650 MPVariable* MPSolver::MakeBoolVar(const string& name) {
00651 return MakeVar(0.0, 1.0, true, name);
00652 }
00653
00654 void MPSolver::MakeVarArray(int nb,
00655 double lb,
00656 double ub,
00657 bool integer,
00658 const string& name,
00659 std::vector<MPVariable*>* vars) {
00660 CHECK_GE(nb, 0);
00661 if (nb == 0) return;
00662 #if defined(_MSC_VER)
00663 const int num_digits = static_cast<int>(log(1.0L * nb) / log(10.0L));
00664 #else
00665 const int num_digits = static_cast<int>(log10(nb));
00666 #endif
00667 for (int i = 0; i < nb; ++i) {
00668 if (name.empty()) {
00669 vars->push_back(MakeVar(lb, ub, integer, name));
00670 } else {
00671 string vname = StringPrintf("%s%0*d", name.c_str(), num_digits, i);
00672 vars->push_back(MakeVar(lb, ub, integer, vname));
00673 }
00674 }
00675 }
00676
00677 void MPSolver::MakeNumVarArray(int nb,
00678 double lb,
00679 double ub,
00680 const string& name,
00681 std::vector<MPVariable*>* vars) {
00682 MakeVarArray(nb, lb, ub, false, name, vars);
00683 }
00684
00685 void MPSolver::MakeIntVarArray(int nb,
00686 double lb,
00687 double ub,
00688 const string& name,
00689 std::vector<MPVariable*>* vars) {
00690 MakeVarArray(nb, lb, ub, true, name, vars);
00691 }
00692
00693 void MPSolver::MakeBoolVarArray(int nb,
00694 const string& name,
00695 std::vector<MPVariable*>* vars) {
00696 MakeVarArray(nb, 0.0, 1.0, true, name, vars);
00697 }
00698
00699 MPConstraint* MPSolver::MakeRowConstraint(double lb, double ub) {
00700 return MakeRowConstraint(lb, ub, "");
00701 }
00702
00703 MPConstraint* MPSolver::MakeRowConstraint() {
00704 return MakeRowConstraint(-infinity(), infinity(), "");
00705 }
00706
00707 MPConstraint* MPSolver::MakeRowConstraint(double lb, double ub,
00708 const string& name) {
00709 const int constraint_index = NumConstraints();
00710 const string fixed_name = name.empty()
00711 ? StringPrintf("auto_constraint_%06d", constraint_index) : name;
00712 CheckNameValidity(fixed_name);
00713 InsertOrDie(&constraint_name_to_index_, fixed_name, constraint_index);
00714 MPConstraint* const constraint =
00715 new MPConstraint(lb, ub, fixed_name, interface_.get());
00716 constraints_.push_back(constraint);
00717 interface_->AddRowConstraint(constraint);
00718 return constraint;
00719 }
00720
00721 MPConstraint* MPSolver::MakeRowConstraint(const string& name) {
00722 return MakeRowConstraint(-infinity(), infinity(), name);
00723 }
00724
00725 int MPSolver::ComputeMaxConstraintSize(int min_constraint_index,
00726 int max_constraint_index) const {
00727 int max_constraint_size = 0;
00728 DCHECK_GE(min_constraint_index, 0);
00729 DCHECK_LE(max_constraint_index, constraints_.size());
00730 for (int i = min_constraint_index; i < max_constraint_index; ++i) {
00731 MPConstraint* const ct = constraints_[i];
00732 if (ct->coefficients_.size() > max_constraint_size) {
00733 max_constraint_size = ct->coefficients_.size();
00734 }
00735 }
00736 return max_constraint_size;
00737 }
00738
00739 bool MPSolver::HasInfeasibleConstraints() const {
00740 bool hasInfeasibleConstraints = false;
00741 for (int i = 0; i < constraints_.size(); ++i) {
00742 if (constraints_[i]->lb() > constraints_[i]->ub()) {
00743 LOG(WARNING) << "Constraint " << constraints_[i]->name()
00744 << " (" << i << ") has contradictory bounds:"
00745 << " lower bound = " << constraints_[i]->lb()
00746 << " upper bound = " << constraints_[i]->ub();
00747 hasInfeasibleConstraints = true;
00748 }
00749 }
00750 return hasInfeasibleConstraints;
00751 }
00752
00753 MPSolver::ResultStatus MPSolver::Solve() {
00754 MPSolverParameters default_param;
00755 return Solve(default_param);
00756 }
00757
00758 MPSolver::ResultStatus MPSolver::Solve(const MPSolverParameters ¶m) {
00759
00760
00761 if (HasInfeasibleConstraints()) {
00762 interface_->result_status_ = MPSolver::INFEASIBLE;
00763 return interface_->result_status_;
00764 }
00765
00766 return interface_->Solve(param);
00767 }
00768
00769 int64 MPSolver::iterations() const {
00770 return interface_->iterations();
00771 }
00772
00773 int64 MPSolver::nodes() const {
00774 return interface_->nodes();
00775 }
00776
00777 double MPSolver::ComputeExactConditionNumber() const {
00778 return interface_->ComputeExactConditionNumber();
00779 }
00780
00781
00782
00783 const int MPSolverInterface::kDummyVariableIndex = 0;
00784
00785 MPSolverInterface::MPSolverInterface(MPSolver* const solver)
00786 : solver_(solver), sync_status_(MODEL_SYNCHRONIZED),
00787 result_status_(MPSolver::NOT_SOLVED), maximize_(false),
00788 last_constraint_index_(0), last_variable_index_(0),
00789 objective_value_(0.0), quiet_(true) {}
00790
00791 MPSolverInterface::~MPSolverInterface() {}
00792
00793 void MPSolverInterface::WriteModelToPredefinedFiles() {
00794 if (!FLAGS_solver_write_model.empty()) {
00795 if (!solver_->CheckAllNamesValidity()) {
00796 LOG(FATAL) << "Invalid name. Unable to write model to file";
00797 }
00798 WriteModel(FLAGS_solver_write_model);
00799 }
00800 const string filename = solver_->write_model_filename();
00801 if (!filename.empty()) {
00802 if (!solver_->CheckAllNamesValidity()) {
00803 LOG(FATAL) << "Invalid name. Unable to write model to file";
00804 }
00805 WriteModel(filename);
00806 }
00807 }
00808
00809 void MPSolverInterface::ExtractModel() {
00810 switch (sync_status_) {
00811 case MUST_RELOAD: {
00812 ExtractNewVariables();
00813 ExtractNewConstraints();
00814 ExtractObjective();
00815
00816 last_constraint_index_ = solver_->constraints_.size();
00817 last_variable_index_ = solver_->variables_.size();
00818 sync_status_ = MODEL_SYNCHRONIZED;
00819 break;
00820 }
00821 case MODEL_SYNCHRONIZED: {
00822
00823 CHECK_EQ(last_constraint_index_, solver_->constraints_.size());
00824 CHECK_EQ(last_variable_index_, solver_->variables_.size());
00825 break;
00826 }
00827 case SOLUTION_SYNCHRONIZED: {
00828
00829 CHECK_EQ(last_constraint_index_, solver_->constraints_.size());
00830 CHECK_EQ(last_variable_index_, solver_->variables_.size());
00831 break;
00832 }
00833 }
00834 }
00835
00836 void MPSolverInterface::ResetExtractionInformation() {
00837 sync_status_ = MUST_RELOAD;
00838 last_constraint_index_ = 0;
00839 last_variable_index_ = 0;
00840 for (int j = 0; j < solver_->variables_.size(); ++j) {
00841 MPVariable* const var = solver_->variables_[j];
00842 var->set_index(kNoIndex);
00843 }
00844 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00845 MPConstraint* const ct = solver_->constraints_[i];
00846 ct->set_index(kNoIndex);
00847 }
00848 }
00849
00850 void MPSolverInterface::CheckSolutionIsSynchronized() const {
00851 CHECK_EQ(SOLUTION_SYNCHRONIZED, sync_status_) <<
00852 "The model has been changed since the solution was last computed.";
00853 }
00854
00855
00856
00857 void MPSolverInterface::CheckSolutionExists() const {
00858 CHECK(result_status_ == MPSolver::OPTIMAL ||
00859 result_status_ == MPSolver::FEASIBLE) <<
00860 "No solution exists.";
00861 }
00862
00863
00864
00865 void MPSolverInterface::CheckBestObjectiveBoundExists() const {
00866 CHECK(result_status_ == MPSolver::OPTIMAL ||
00867 result_status_ == MPSolver::FEASIBLE)
00868 << "No information is available for the best objective bound.";
00869 }
00870
00871 double MPSolverInterface::objective_value() const {
00872 CheckSolutionIsSynchronizedAndExists();
00873 return objective_value_;
00874 }
00875
00876 void MPSolverInterface::InvalidateSolutionSynchronization() {
00877 if (sync_status_ == SOLUTION_SYNCHRONIZED) {
00878 sync_status_ = MODEL_SYNCHRONIZED;
00879 }
00880 }
00881
00882 void MPSolverInterface::SetCommonParameters(const MPSolverParameters& param) {
00883 SetPrimalTolerance(param.GetDoubleParam(
00884 MPSolverParameters::PRIMAL_TOLERANCE));
00885 SetDualTolerance(param.GetDoubleParam(MPSolverParameters::DUAL_TOLERANCE));
00886 SetPresolveMode(param.GetIntegerParam(MPSolverParameters::PRESOLVE));
00887
00888
00889
00890 int value = param.GetIntegerParam(MPSolverParameters::LP_ALGORITHM);
00891 if (value != MPSolverParameters::kDefaultIntegerParamValue) {
00892 SetLpAlgorithm(value);
00893 }
00894 }
00895
00896 void MPSolverInterface::SetMIPParameters(const MPSolverParameters& param) {
00897 SetRelativeMipGap(param.GetDoubleParam(MPSolverParameters::RELATIVE_MIP_GAP));
00898 }
00899
00900 void MPSolverInterface::SetUnsupportedDoubleParam(
00901 MPSolverParameters::DoubleParam param) const {
00902 LOG(WARNING) << "Trying to set an unsupported parameter: " << param << ".";
00903 }
00904 void MPSolverInterface::SetUnsupportedIntegerParam(
00905 MPSolverParameters::IntegerParam param) const {
00906 LOG(WARNING) << "Trying to set an unsupported parameter: " << param << ".";
00907 }
00908 void MPSolverInterface::SetDoubleParamToUnsupportedValue(
00909 MPSolverParameters::DoubleParam param, int value) const {
00910 LOG(WARNING) << "Trying to set a supported parameter: " << param
00911 << " to an unsupported value: " << value;
00912 }
00913 void MPSolverInterface::SetIntegerParamToUnsupportedValue(
00914 MPSolverParameters::IntegerParam param, double value) const {
00915 LOG(WARNING) << "Trying to set a supported parameter: " << param
00916 << " to an unsupported value: " << value;
00917 }
00918
00919
00920
00921 const double MPSolverParameters::kDefaultRelativeMipGap = 1e-4;
00922
00923 const double MPSolverParameters::kDefaultPrimalTolerance = 1e-7;
00924 const double MPSolverParameters::kDefaultDualTolerance = 1e-7;
00925 const MPSolverParameters::PresolveValues MPSolverParameters::kDefaultPresolve =
00926 MPSolverParameters::PRESOLVE_ON;
00927 const MPSolverParameters::IncrementalityValues
00928 MPSolverParameters::kDefaultIncrementality =
00929 MPSolverParameters::INCREMENTALITY_ON;
00930
00931 const double MPSolverParameters::kDefaultDoubleParamValue = -1.0;
00932 const int MPSolverParameters::kDefaultIntegerParamValue = -1;
00933 const double MPSolverParameters::kUnknownDoubleParamValue = -2.0;
00934 const int MPSolverParameters::kUnknownIntegerParamValue = -2;
00935
00936
00937 MPSolverParameters::MPSolverParameters()
00938 : relative_mip_gap_value_(kDefaultRelativeMipGap),
00939 primal_tolerance_value_(kDefaultPrimalTolerance),
00940 dual_tolerance_value_(kDefaultDualTolerance),
00941 presolve_value_(kDefaultPresolve),
00942 lp_algorithm_value_(kDefaultIntegerParamValue),
00943 incrementality_value_(kDefaultIncrementality),
00944 lp_algorithm_is_default_(true) {}
00945
00946 void MPSolverParameters::SetDoubleParam(MPSolverParameters::DoubleParam param,
00947 double value) {
00948 switch (param) {
00949 case RELATIVE_MIP_GAP: {
00950 relative_mip_gap_value_ = value;
00951 break;
00952 }
00953 case PRIMAL_TOLERANCE: {
00954 primal_tolerance_value_ = value;
00955 break;
00956 }
00957 case DUAL_TOLERANCE: {
00958 dual_tolerance_value_ = value;
00959 break;
00960 }
00961 default: {
00962 LOG(ERROR) << "Trying to set an unknown parameter: " << param << ".";
00963 }
00964 }
00965 }
00966
00967 void MPSolverParameters::SetIntegerParam(MPSolverParameters::IntegerParam param,
00968 int value) {
00969 switch (param) {
00970 case PRESOLVE: {
00971 if (value != PRESOLVE_OFF && value != PRESOLVE_ON) {
00972 LOG(ERROR) << "Trying to set a supported parameter: " << param
00973 << " to an unknown value: " << value;
00974 }
00975 presolve_value_ = value;
00976 break;
00977 }
00978 case LP_ALGORITHM: {
00979 if (value != DUAL && value != PRIMAL && value != BARRIER) {
00980 LOG(ERROR) << "Trying to set a supported parameter: " << param
00981 << " to an unknown value: " << value;
00982 }
00983 lp_algorithm_value_ = value;
00984 lp_algorithm_is_default_ = false;
00985 break;
00986 }
00987 case INCREMENTALITY: {
00988 if (value != INCREMENTALITY_OFF && value != INCREMENTALITY_ON) {
00989 LOG(ERROR) << "Trying to set a supported parameter: " << param
00990 << " to an unknown value: " << value;
00991 }
00992 incrementality_value_ = value;
00993 break;
00994 }
00995 default: {
00996 LOG(ERROR) << "Trying to set an unknown parameter: " << param << ".";
00997 }
00998 }
00999 }
01000
01001 void MPSolverParameters::ResetDoubleParam(
01002 MPSolverParameters::DoubleParam param) {
01003 switch (param) {
01004 case RELATIVE_MIP_GAP: {
01005 relative_mip_gap_value_ = kDefaultRelativeMipGap;
01006 break;
01007 }
01008 case PRIMAL_TOLERANCE: {
01009 primal_tolerance_value_ = kDefaultPrimalTolerance;
01010 break;
01011 }
01012 case DUAL_TOLERANCE: {
01013 dual_tolerance_value_ = kDefaultDualTolerance;
01014 break;
01015 }
01016 default: {
01017 LOG(ERROR) << "Trying to reset an unknown parameter: " << param << ".";
01018 }
01019 }
01020 }
01021
01022 void MPSolverParameters::ResetIntegerParam(
01023 MPSolverParameters::IntegerParam param) {
01024 switch (param) {
01025 case PRESOLVE: {
01026 presolve_value_ = kDefaultPresolve;
01027 break;
01028 }
01029 case LP_ALGORITHM: {
01030 lp_algorithm_is_default_ = true;
01031 break;
01032 }
01033 case INCREMENTALITY: {
01034 incrementality_value_ = kDefaultIncrementality;
01035 break;
01036 }
01037 default: {
01038 LOG(ERROR) << "Trying to reset an unknown parameter: " << param << ".";
01039 }
01040 }
01041 }
01042
01043 void MPSolverParameters::Reset() {
01044 ResetDoubleParam(RELATIVE_MIP_GAP);
01045 ResetDoubleParam(PRIMAL_TOLERANCE);
01046 ResetDoubleParam(DUAL_TOLERANCE);
01047 ResetIntegerParam(PRESOLVE);
01048 ResetIntegerParam(LP_ALGORITHM);
01049 ResetIntegerParam(INCREMENTALITY);
01050 }
01051
01052 double MPSolverParameters::GetDoubleParam(
01053 MPSolverParameters::DoubleParam param) const {
01054 switch (param) {
01055 case RELATIVE_MIP_GAP: {
01056 return relative_mip_gap_value_;
01057 }
01058 case PRIMAL_TOLERANCE: {
01059 return primal_tolerance_value_;
01060 }
01061 case DUAL_TOLERANCE: {
01062 return dual_tolerance_value_;
01063 }
01064 default: {
01065 LOG(ERROR) << "Trying to get an unknown parameter: " << param << ".";
01066 return kUnknownDoubleParamValue;
01067 }
01068 }
01069 }
01070
01071 int MPSolverParameters::GetIntegerParam(
01072 MPSolverParameters::IntegerParam param) const {
01073 switch (param) {
01074 case PRESOLVE: {
01075 return presolve_value_;
01076 }
01077 case LP_ALGORITHM: {
01078 if (lp_algorithm_is_default_) return kDefaultIntegerParamValue;
01079 return lp_algorithm_value_;
01080 }
01081 case INCREMENTALITY: {
01082 return incrementality_value_;
01083 }
01084 default: {
01085 LOG(ERROR) << "Trying to get an unknown parameter: " << param << ".";
01086 return kUnknownIntegerParamValue;
01087 }
01088 }
01089 }
01090
01091 }