From 7a1889bb1f7d4eac92a3711c88cf84caef2fa726 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Tue, 24 Jul 2018 13:23:58 -0700 Subject: [PATCH] make name -> var or constraint optional in linear solver --- makefiles/Makefile.gen.mk | 4 +- ortools/linear_solver/csharp/linear_solver.i | 5 - ortools/linear_solver/gurobi_interface.cc | 3 +- ortools/linear_solver/java/linear_solver.i | 9 +- ortools/linear_solver/linear_solver.cc | 116 ++++++++++--------- ortools/linear_solver/linear_solver.h | 48 ++++---- ortools/linear_solver/python/linear_solver.i | 38 +++--- 7 files changed, 115 insertions(+), 108 deletions(-) diff --git a/makefiles/Makefile.gen.mk b/makefiles/Makefile.gen.mk index 1d95f7304d..fa6233eccd 100644 --- a/makefiles/Makefile.gen.mk +++ b/makefiles/Makefile.gen.mk @@ -3319,15 +3319,17 @@ $(OBJ_DIR)/linear_solver/linear_solver.$O: \ $(SRC_DIR)/ortools/base/accurate_sum.h \ $(SRC_DIR)/ortools/base/canonical_errors.h \ $(SRC_DIR)/ortools/base/commandlineflags.h \ - $(SRC_DIR)/ortools/base/hash.h \ $(SRC_DIR)/ortools/base/integral_types.h \ $(SRC_DIR)/ortools/base/join.h \ $(SRC_DIR)/ortools/base/logging.h \ + $(SRC_DIR)/ortools/base/macros.h \ $(SRC_DIR)/ortools/base/map_util.h \ + $(SRC_DIR)/ortools/base/mutex.h \ $(SRC_DIR)/ortools/base/port.h \ $(SRC_DIR)/ortools/base/status.h \ $(SRC_DIR)/ortools/base/stl_util.h \ $(SRC_DIR)/ortools/base/stringprintf.h \ + $(SRC_DIR)/ortools/base/strutil.h \ $(SRC_DIR)/ortools/base/timer.h \ $(GEN_DIR)/ortools/glop/parameters.pb.h \ $(SRC_DIR)/ortools/linear_solver/linear_expr.h \ diff --git a/ortools/linear_solver/csharp/linear_solver.i b/ortools/linear_solver/csharp/linear_solver.i index e770249705..cb3d85bff7 100644 --- a/ortools/linear_solver/csharp/linear_solver.i +++ b/ortools/linear_solver/csharp/linear_solver.i @@ -192,7 +192,6 @@ class MPSolutionResponse; %unignore operations_research::MPObjective::SetOptimizationDirection; %unignore operations_research::MPObjective::Clear; %unignore operations_research::MPObjective::SetOffset; -%unignore operations_research::MPObjective::AddOffset; // MPObjective: reader API. %unignore operations_research::MPObjective::Value; @@ -211,10 +210,6 @@ class MPSolutionResponse; %unignore operations_research::MPSolverParameters::SetDoubleParam; %unignore operations_research::MPSolverParameters::kDefaultPrimalTolerance; -// We want to ignore the CoeffMap class; but since it inherits from some -// std::unordered_map<>, swig complains about an undefined base class. Silence it. -%warnfilter(401) CoeffMap; - %include "ortools/linear_solver/linear_solver.h" %unignoreall diff --git a/ortools/linear_solver/gurobi_interface.cc b/ortools/linear_solver/gurobi_interface.cc index b8b76680b0..0275a82e98 100644 --- a/ortools/linear_solver/gurobi_interface.cc +++ b/ortools/linear_solver/gurobi_interface.cc @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include #include -#include #include "ortools/base/commandlineflags.h" #include "ortools/base/integral_types.h" @@ -191,7 +191,6 @@ GurobiInterface::GurobiInterface(MPSolver* const solver, bool mip) LOG(DFATAL) << "Error: could not create environment: " << err_msg; throw std::runtime_error(std::to_string(ret) + ", " + err_msg); } - CheckedGurobiCall(GRBnewmodel(env_, &model_, solver_->name_.c_str(), 0, // numvars nullptr, // obj diff --git a/ortools/linear_solver/java/linear_solver.i b/ortools/linear_solver/java/linear_solver.i index fd159af4e9..0517dedc59 100644 --- a/ortools/linear_solver/java/linear_solver.i +++ b/ortools/linear_solver/java/linear_solver.i @@ -25,7 +25,7 @@ // // TODO(user): unit test all the APIs that are currently marked with 'no test'. -%include ortools/base/base.i +%include "ortools/base/base.i" %include "enums.swg" // For native Java enum support. @@ -133,6 +133,7 @@ import java.lang.reflect.*; %unignore operations_research::MPSolver::CBC_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::BOP_INTEGER_PROGRAMMING; +%unignore operations_research::MPSolver::SAT_INTEGER_PROGRAMMING; // These aren't unit tested, as they only run on machines with a Gurobi license. %unignore operations_research::MPSolver::GUROBI_LINEAR_PROGRAMMING; %unignore operations_research::MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING; @@ -235,7 +236,6 @@ import java.lang.reflect.*; %rename (setOptimizationDirection) operations_research::MPObjective::SetOptimizationDirection; %rename (clear) operations_research::MPObjective::Clear; // no test %rename (setOffset) operations_research::MPObjective::SetOffset; -%rename (addOffset) operations_research::MPObjective::AddOffset; // no test // MPObjective: reader API. %rename (value) operations_research::MPObjective::Value; @@ -247,6 +247,7 @@ import java.lang.reflect.*; // MPSolverParameters API. For expert users only. // TODO(user): unit test all of it. + %unignore operations_research::MPSolverParameters; // no test %unignore operations_research::MPSolverParameters::MPSolverParameters; // no test @@ -293,10 +294,6 @@ import java.lang.reflect.*; %unignore operations_research::MPSolverParameters::SCALING_OFF; // no test %unignore operations_research::MPSolverParameters::SCALING_ON; // no test -// We want to ignore the CoeffMap class; but since it inherits from some -// std::unordered_map<>, swig complains about an undefined base class. Silence it. -%warnfilter(401) CoeffMap; - %include "ortools/linear_solver/linear_solver.h" %unignoreall diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index cbf0d5e8a9..1117cba5be 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -26,16 +26,15 @@ #include "ortools/base/commandlineflags.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/stringprintf.h" #include "ortools/base/timer.h" #include "ortools/port/file.h" #include "ortools/base/accurate_sum.h" #include "ortools/base/canonical_errors.h" -#include "ortools/base/hash.h" #include "ortools/base/join.h" #include "ortools/base/map_util.h" +#include "ortools/base/mutex.h" #include "ortools/base/stl_util.h" #include "ortools/base/stringprintf.h" #include "ortools/linear_solver/linear_solver.pb.h" @@ -59,10 +58,6 @@ DEFINE_bool(mpsolver_bypass_model_validation, false, " Invalid models will typically trigger various error responses" " from the underlying solvers; sometimes crashes."); -// To compile the open-source code, the anonymous namespace should be -// inside the operations_research namespace (This is due to the -// open-sourced version of StringPrintf which is defined inside the -// operations_research namespace in open_source/base). namespace operations_research { double MPConstraint::GetCoefficient(const MPVariable* const var) const { @@ -414,13 +409,11 @@ MPSolver::OptimizationProblemType DetourProblemType( MPSolver::MPSolver(const std::string& name, OptimizationProblemType problem_type) : name_(name), - problem_type_(problem_type), -#if !defined(_MSC_VER) - variable_name_to_index_(1), -#endif + problem_type_(DetourProblemType(problem_type)), time_limit_(0.0) { - SetIndexConstraints(true); timer_.Restart(); + constraint_name_to_index_.reset(nullptr); + variable_name_to_index_.reset(nullptr); interface_.reset(BuildSolverInterface(this)); if (FLAGS_linear_solver_enable_verbose_output) { EnableOutput(); @@ -502,31 +495,18 @@ bool MPSolver::ParseSolverType(const std::string& solver, } MPVariable* MPSolver::LookupVariableOrNull(const std::string& var_name) const { + if (!variable_name_to_index_) GenerateVariableNameIndex(); + std::unordered_map::const_iterator it = - variable_name_to_index_.find(var_name); - if (it == variable_name_to_index_.end()) return nullptr; + variable_name_to_index_->find(var_name); + if (it == variable_name_to_index_->end()) return nullptr; return variables_[it->second]; } -void MPSolver::SetIndexConstraints(bool enabled) { - auto* const new_map = enabled ? -#ifdef _MSC_VER - - new std::unordered_map() - : -#else // _MSC_VER - new std::unordered_map(1) - : -#endif // _MSC_VER - nullptr; - constraint_name_to_index_.reset(new_map); -} - MPConstraint* MPSolver::LookupConstraintOrNull( const std::string& constraint_name) const { - if (!constraint_name_to_index_) { - return nullptr; - } + if (!constraint_name_to_index_) GenerateConstraintNameIndex(); + const auto it = constraint_name_to_index_->find(constraint_name); if (it == constraint_name_to_index_->end()) return nullptr; return constraints_[it->second]; @@ -546,6 +526,10 @@ MPSolverResponseStatus MPSolver::LoadModelFromProto( MPSolverResponseStatus MPSolver::LoadModelFromProtoWithUniqueNamesOrDie( const MPModelProto& input_model, std::string* error_message) { + // Force variable and constraint name indexing (which CHECKs name uniqueness). + GenerateVariableNameIndex(); + GenerateConstraintNameIndex(); + return LoadModelFromProtoInternal(input_model, /*clear_names=*/false, error_message); } @@ -825,7 +809,9 @@ void MPSolver::Clear() { gtl::STLDeleteElements(&variables_); gtl::STLDeleteElements(&constraints_); variables_.clear(); - variable_name_to_index_.clear(); + if (variable_name_to_index_) { + variable_name_to_index_->clear(); + } variable_is_extracted_.clear(); constraints_.clear(); if (constraint_name_to_index_) { @@ -849,11 +835,11 @@ void MPSolver::SetStartingLpBasis( MPVariable* MPSolver::MakeVar(double lb, double ub, bool integer, const std::string& name) { const int var_index = NumVariables(); - const std::string fixed_name = - name.empty() ? StringPrintf("auto_v_%09d", var_index) : name; - gtl::InsertOrDie(&variable_name_to_index_, fixed_name, var_index); MPVariable* v = - new MPVariable(var_index, lb, ub, integer, fixed_name, interface_.get()); + new MPVariable(var_index, lb, ub, integer, name, interface_.get()); + if (variable_name_to_index_) { + gtl::InsertOrDie(&*variable_name_to_index_, v->name(), var_index); + } variables_.push_back(v); variable_is_extracted_.push_back(false); interface_->AddVariable(v); @@ -884,7 +870,8 @@ void MPSolver::MakeVarArray(int nb, double lb, double ub, bool integer, if (name.empty()) { vars->push_back(MakeVar(lb, ub, integer, name)); } else { - std::string vname = StringPrintf("%s%0*d", name.c_str(), num_digits, i); + std::string vname = + absl::StrFormat("%s%0*d", name.c_str(), num_digits, i); vars->push_back(MakeVar(lb, ub, integer, vname)); } } @@ -918,13 +905,12 @@ MPConstraint* MPSolver::MakeRowConstraint() { MPConstraint* MPSolver::MakeRowConstraint(double lb, double ub, const std::string& name) { const int constraint_index = NumConstraints(); - const std::string fixed_name = - name.empty() ? StringPrintf("auto_c_%09d", constraint_index) : name; - if (constraint_name_to_index_) { - gtl::InsertOrDie(&*constraint_name_to_index_, fixed_name, constraint_index); - } MPConstraint* const constraint = - new MPConstraint(constraint_index, lb, ub, fixed_name, interface_.get()); + new MPConstraint(constraint_index, lb, ub, name, interface_.get()); + if (constraint_name_to_index_) { + gtl::InsertOrDie(&*constraint_name_to_index_, constraint->name(), + constraint_index); + } constraints_.push_back(constraint); constraint_is_extracted_.push_back(false); interface_->AddRowConstraint(constraint); @@ -1036,21 +1022,22 @@ std::string PrettyPrintVar(const MPVariable& var) { if (lb > ub) { return prefix + "∅"; } else if (lb == ub) { - return absl::StrFormat("%s{ %lld }", prefix.c_str(), lb); + return absl::StrFormat("%s{ %d }", prefix, lb); } else { - return absl::StrFormat("%s{ %lld, %lld }", prefix.c_str(), lb, ub); + return absl::StrFormat("%s{ %d, %d }", prefix, lb, ub); } } // Special case: single (non-infinite) real value. if (var.lb() == var.ub()) { - return StringPrintf("%s{ %f }", prefix.c_str(), var.lb()); + return absl::StrFormat("%s{ %f }", prefix.c_str(), var.lb()); } return prefix + (var.integer() ? "Integer" : "Real") + " in " + - (var.lb() <= -MPSolver::infinity() ? std::string("]-∞") - : StringPrintf("[%f", var.lb())) + + (var.lb() <= -MPSolver::infinity() + ? std::string("]-∞") + : absl::StrFormat("[%f", var.lb())) + ", " + (var.ub() >= MPSolver::infinity() ? std::string("+∞[") - : StringPrintf("%f]", var.ub())); + : absl::StrFormat("%f]", var.ub())); } std::string PrettyPrintConstraint(const MPConstraint& constraint) { @@ -1067,17 +1054,17 @@ std::string PrettyPrintConstraint(const MPConstraint& constraint) { prefix += ""; // Equality. if (constraint.lb() == constraint.ub()) { - return StringPrintf("%s = %f", prefix.c_str(), constraint.lb()); + return absl::StrFormat("%s = %f", prefix.c_str(), constraint.lb()); } // Inequalities. if (constraint.lb() <= -MPSolver::infinity()) { - return StringPrintf("%s ≤ %f", prefix.c_str(), constraint.ub()); + return absl::StrFormat("%s ≤ %f", prefix.c_str(), constraint.ub()); } if (constraint.ub() >= MPSolver::infinity()) { - return StringPrintf("%s ≥ %f", prefix.c_str(), constraint.lb()); + return absl::StrFormat("%s ≥ %f", prefix.c_str(), constraint.lb()); } - return StringPrintf("%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(), - constraint.ub()); + return absl::StrFormat("%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(), + constraint.ub()); } } // namespace @@ -1274,6 +1261,24 @@ bool MPSolver::ExportModelAsMpsFormat(bool fixed_format, bool obfuscate, return exporter.ExportModelAsMpsFormat(fixed_format, obfuscate, model_str); } +void MPSolver::GenerateVariableNameIndex() const { + if (variable_name_to_index_) return; + variable_name_to_index_.reset(new std::unordered_map(1)); + for (const MPVariable* const var : variables_) { + gtl::InsertOrDie(&*variable_name_to_index_, var->name(), var->index()); + } +} + +void MPSolver::GenerateConstraintNameIndex() const { + if (constraint_name_to_index_) return; + constraint_name_to_index_.reset(new std::unordered_map(1)); + for (const MPConstraint* const cst : constraints_) { + gtl::InsertOrDie(&*constraint_name_to_index_, cst->name(), cst->index()); + } +} + +bool MPSolver::NextSolution() { return interface_->NextSolution(); } + // ---------- MPSolverInterface ---------- const int MPSolverInterface::kDummyVariableIndex = 0; @@ -1469,8 +1474,9 @@ bool MPSolverInterface::SetSolverSpecificParametersAsString( int32 pid = 456; #endif // _MSC_VER int64 now = absl::GetCurrentTimeNanos(); - std::string filename = StringPrintf("/tmp/parameters-tempfile-%x-%d-%llx%s", - tid, pid, now, extension.c_str()); + std::string filename = + absl::StrFormat("/tmp/parameters-tempfile-%x-%d-%llx%s", tid, pid, now, + extension.c_str()); bool no_error_so_far = true; if (no_error_so_far) { no_error_so_far = FileSetContents(filename, parameters).ok(); diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index 0945ec155b..18fed443c5 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -141,15 +141,19 @@ #include #include #include -#include -#include #include #include +#include "ortools/base/commandlineflags.h" + +#include #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" +#include "ortools/base/macros.h" #include "ortools/base/port.h" #include "ortools/base/status.h" +#include "ortools/base/stringprintf.h" +#include "ortools/base/strutil.h" #include "ortools/base/timer.h" #include "ortools/glop/parameters.pb.h" #include "ortools/linear_solver/linear_expr.h" @@ -225,7 +229,7 @@ class MPSolver { bool IsMIP() const; - std::string Name() const { + const std::string& Name() const { return name_; // Set at construction. } @@ -244,14 +248,17 @@ class MPSolver { // Returns the array of variables handled by the MPSolver. // (They are listed in the order in which they were created.) const std::vector& variables() const { return variables_; } - // Look up a variable by name, and return NULL if it does not exist. + // Looks up a variable by name, and returns nullptr if it does not exist. + // The first call has a O(n) complexity, as the variable name index is lazily + // created upon first use. Will crash if variable names are not unique. MPVariable* LookupVariableOrNull(const std::string& var_name) const; // Creates a variable with the given bounds, integrality requirement // and name. Bounds can be finite or +/- MPSolver::infinity(). // The MPSolver owns the variable (i.e. the returned pointer is borrowed). - // Variable names must be unique (it may crash otherwise). Empty variable - // names are allowed, an automated variable name will then be assigned. + // Variable names are optional. If you give an empty name, name() will + // auto-generate one for you upon request. + MPVariable* MakeVar(double lb, double ub, bool integer, const std::string& name); // Creates a continuous variable. @@ -286,11 +293,10 @@ class MPSolver { // (They are listed in the order in which they were created.) const std::vector& constraints() const { return constraints_; } - // Sets whether constraints should be indexed. Setting to false makes adding - // constraints faster and uses less memory. - void SetIndexConstraints(bool enabled); - // Look up a constraint by name, and return nullptr if it does not exist or if - // constraints are not indexed. + // Looks up a constraint by name, and returns nullptr if it does not exist. + // The first call has a O(n) complexity, as the constraint name index is + // lazily created upon first use. Will crash if constraint names are not + // unique. MPConstraint* LookupConstraintOrNull( const std::string& constraint_name) const; @@ -613,6 +619,12 @@ class MPSolver { // Returns true if the model has at least 1 integer variable. bool HasIntegerVariables() const; + // Generates the map from variable names to their indices. + void GenerateVariableNameIndex() const; + + // Generates the map from constraint names to their indices. + void GenerateConstraintNameIndex() const; + // The name of the linear programming problem. const std::string name_; @@ -625,14 +637,15 @@ class MPSolver { // The vector of variables in the problem. std::vector variables_; // A map from a variable's name to its index in variables_. - std::unordered_map variable_name_to_index_; + mutable std::unique_ptr > + variable_name_to_index_; // Whether variables have been extracted to the underlying interface. std::vector variable_is_extracted_; // The vector of constraints in the problem. std::vector constraints_; // A map from a constraint's name to its index in constraints_. - std::unique_ptr > + mutable std::unique_ptr > constraint_name_to_index_; // Whether constraints have been extracted to the underlying interface. std::vector constraint_is_extracted_; @@ -687,11 +700,6 @@ class MPObjective { // Gets the constant term in the objective. double offset() const { return offset_; } - // Adds a constant term to the objective. - // Note: please use the less ambiguous SetOffset() if possible! - // TODO(user): remove this. - void AddOffset(double value) { SetOffset(offset() + value); } - // Resets the current objective to take the value of linear_expr, and sets // the objective direction to maximize if "is_maximize", otherwise minimizes. void OptimizeLinearExpr(const LinearExpr& linear_expr, bool is_maximize); @@ -831,7 +839,7 @@ class MPVariable { lb_(lb), ub_(ub), integer_(integer), - name_(name), + name_(name.empty() ? absl::StrFormat("auto_v_%09d", index) : name), solution_value_(0.0), reduced_cost_(0.0), interface_(interface) {} @@ -932,7 +940,7 @@ class MPConstraint { index_(index), lb_(lb), ub_(ub), - name_(name), + name_(name.empty() ? absl::StrFormat("auto_c_%09d", index) : name), is_lazy_(false), dual_value_(0.0), interface_(interface) {} diff --git a/ortools/linear_solver/python/linear_solver.i b/ortools/linear_solver/python/linear_solver.i index 32b618173b..011da74b41 100644 --- a/ortools/linear_solver/python/linear_solver.i +++ b/ortools/linear_solver/python/linear_solver.i @@ -73,17 +73,6 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr } // %pythoncode } -// Catch runtime exceptions in class methods -%extend MPSolver { - %exception MPSolver { - try { - $action - } catch ( std::runtime_error& e ) { - SWIG_exception(SWIG_RuntimeError, e.what()); - } - } -} - %extend MPSolver { // Change a (bool, std::string*) outputs to a python std::string (empty if bool=false). std::string ExportModelAsLpFormat(bool obfuscated) { @@ -129,10 +118,10 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr objective.Clear() objective.SetMinimization() if isinstance(expr, numbers.Number): - objective.AddOffset(expr) + objective.SetOffset(expr) else: coeffs = expr.GetCoeffs() - objective.AddOffset(coeffs.pop(OFFSET_KEY, 0.0)) + objective.SetOffset(coeffs.pop(OFFSET_KEY, 0.0)) for v, c, in list(coeffs.items()): objective.SetCoefficient(v, float(c)) @@ -141,16 +130,25 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr objective.Clear() objective.SetMaximization() if isinstance(expr, numbers.Number): - objective.AddOffset(expr) + objective.SetOffset(expr) else: coeffs = expr.GetCoeffs() - objective.AddOffset(coeffs.pop(OFFSET_KEY, 0.0)) + objective.SetOffset(coeffs.pop(OFFSET_KEY, 0.0)) for v, c, in list(coeffs.items()): objective.SetCoefficient(v, float(c)) } // %pythoncode } %extend MPSolver { +// Catch runtime exceptions in class methods +%exception MPSolver { + try { + $action + } catch ( std::runtime_error& e ) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } + } + static double Infinity() { return operations_research::MPSolver::infinity(); } void SetTimeLimit(int64 x) { $self->set_time_limit(x); } int64 WallTime() const { return $self->wall_time(); } @@ -201,6 +199,7 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr %unignore operations_research::MPSolver::CBC_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::BOP_INTEGER_PROGRAMMING; +%unignore operations_research::MPSolver::SAT_INTEGER_PROGRAMMING; // These aren't unit tested, as they only run on machines with a Gurobi license. %unignore operations_research::MPSolver::GUROBI_LINEAR_PROGRAMMING; %unignore operations_research::MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING; @@ -222,6 +221,7 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr %rename (BoolVar) operations_research::MPSolver::MakeBoolVar; // No unit test %rename (IntVar) operations_research::MPSolver::MakeIntVar; %rename (NumVar) operations_research::MPSolver::MakeNumVar; +%rename (Var) operations_research::MPSolver::MakeVar; // We intentionally don't expose MakeRowConstraint(LinearExpr), because this // "natural language" API is specific to C++: other languages may add their own // syntactic sugar on top of MPSolver instead of this. @@ -249,6 +249,7 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr operations_research::MPSolver::LookupConstraintOrNull; %rename (LookupVariable) operations_research::MPSolver::LookupVariableOrNull; %unignore operations_research::MPSolver::SetSolverSpecificParametersAsString; +%unignore operations_research::MPSolver::NextSolution; // Expose very advanced parts of the MPSolver API. For expert users only. %unignore operations_research::MPSolver::ComputeConstraintActivities; @@ -330,6 +331,9 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr %unignore operations_research::MPSolverParameters::SCALING; %unignore operations_research::MPSolverParameters::GetIntegerParam; %unignore operations_research::MPSolverParameters::SetIntegerParam; +%unignore operations_research::MPSolverParameters::RELATIVE_MIP_GAP; +%unignore operations_research::MPSolverParameters::kDefaultPrimalTolerance; +// TODO(user): unit test kDefaultPrimalTolerance. // Expose the MPSolverParameters::PresolveValues enum. %unignore operations_research::MPSolverParameters::PresolveValues; @@ -354,10 +358,6 @@ from ortools.linear_solver.linear_solver_natural_api import VariableExpr %unignore operations_research::MPSolverParameters::SCALING_OFF; %unignore operations_research::MPSolverParameters::SCALING_ON; -// We want to ignore the CoeffMap class; but since it inherits from some -// std::unordered_map<>, swig complains about an undefined base class. Silence it. -%warnfilter(401) CoeffMap; - %include "ortools/linear_solver/linear_solver.h" %unignoreall