more work on integer search; add RINS heuristis
This commit is contained in:
@@ -1105,6 +1105,7 @@ SAT_DEPS = \
|
||||
$(SRC_DIR)/ortools/sat/probing.h \
|
||||
$(SRC_DIR)/ortools/sat/pseudo_costs.h \
|
||||
$(SRC_DIR)/ortools/sat/restart.h \
|
||||
$(SRC_DIR)/ortools/sat/rins.h \
|
||||
$(SRC_DIR)/ortools/sat/sat_base.h \
|
||||
$(SRC_DIR)/ortools/sat/sat_decision.h \
|
||||
$(SRC_DIR)/ortools/sat/sat_solver.h \
|
||||
@@ -1162,6 +1163,7 @@ SAT_LIB_OBJS = \
|
||||
$(OBJ_DIR)/sat/probing.$O \
|
||||
$(OBJ_DIR)/sat/pseudo_costs.$O \
|
||||
$(OBJ_DIR)/sat/restart.$O \
|
||||
$(OBJ_DIR)/sat/rins.$O \
|
||||
$(OBJ_DIR)/sat/sat_decision.$O \
|
||||
$(OBJ_DIR)/sat/sat_solver.$O \
|
||||
$(OBJ_DIR)/sat/simplification.$O \
|
||||
@@ -2000,6 +2002,14 @@ objs/sat/restart.$O: ortools/sat/restart.cc ortools/sat/restart.h \
|
||||
ortools/port/proto_utils.h | $(OBJ_DIR)/sat
|
||||
$(CCC) $(CFLAGS) -c $(SRC_DIR)$Sortools$Ssat$Srestart.cc $(OBJ_OUT)$(OBJ_DIR)$Ssat$Srestart.$O
|
||||
|
||||
objs/sat/rins.$O: ortools/sat/rins.cc ortools/sat/rins.h \
|
||||
ortools/sat/model.h ortools/base/logging.h ortools/base/integral_types.h \
|
||||
ortools/base/macros.h ortools/base/map_util.h ortools/base/typeid.h \
|
||||
ortools/gen/ortools/sat/sat_parameters.pb.h ortools/util/bitset.h \
|
||||
ortools/base/basictypes.h ortools/util/running_stat.h \
|
||||
ortools/port/proto_utils.h | $(OBJ_DIR)/sat
|
||||
$(CCC) $(CFLAGS) -c $(SRC_DIR)$Sortools$Ssat$Srins.cc $(OBJ_OUT)$(OBJ_DIR)$Ssat$Srins.$O
|
||||
|
||||
objs/sat/sat_decision.$O: ortools/sat/sat_decision.cc \
|
||||
ortools/sat/sat_decision.h ortools/base/integral_types.h \
|
||||
ortools/sat/model.h ortools/base/logging.h ortools/base/macros.h \
|
||||
|
||||
@@ -177,6 +177,7 @@ cc_library(
|
||||
":optimization",
|
||||
":precedences",
|
||||
":probing",
|
||||
":rins",
|
||||
":sat_base",
|
||||
":sat_parameters_cc_proto",
|
||||
":sat_solver",
|
||||
@@ -511,6 +512,7 @@ cc_library(
|
||||
":integer",
|
||||
":linear_programming_constraint",
|
||||
":pseudo_costs",
|
||||
":rins",
|
||||
":sat_base",
|
||||
":sat_decision",
|
||||
":sat_solver",
|
||||
@@ -1007,6 +1009,7 @@ cc_library(
|
||||
":cp_model_utils",
|
||||
":linear_programming_constraint",
|
||||
":model",
|
||||
":rins",
|
||||
"//ortools/base",
|
||||
"//ortools/util:random_engine",
|
||||
"//ortools/util:time_limit",
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
#include "ortools/sat/cp_model_lns.h"
|
||||
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "ortools/sat/cp_model.pb.h"
|
||||
#include "ortools/sat/cp_model_loader.h"
|
||||
#include "ortools/sat/cp_model_utils.h"
|
||||
#include "ortools/sat/linear_programming_constraint.h"
|
||||
#include "ortools/sat/rins.h"
|
||||
#include "ortools/util/random_engine.h"
|
||||
|
||||
namespace operations_research {
|
||||
@@ -139,6 +141,15 @@ Neighborhood NeighborhoodGeneratorHelper::RelaxGivenVariables(
|
||||
return FixGivenVariables(initial_solution, fixed_variables);
|
||||
}
|
||||
|
||||
Neighborhood NeighborhoodGeneratorHelper::FixAllVariables(
|
||||
const CpSolverResponse& initial_solution) const {
|
||||
std::vector<int> fixed_variables;
|
||||
for (const int i : active_variables_) {
|
||||
fixed_variables.push_back(i);
|
||||
}
|
||||
return FixGivenVariables(initial_solution, fixed_variables);
|
||||
}
|
||||
|
||||
double NeighborhoodGenerator::GetUCBScore(int64 total_num_calls) const {
|
||||
DCHECK_GE(total_num_calls, num_calls_);
|
||||
if (num_calls_ <= 10) return std::numeric_limits<double>::infinity();
|
||||
@@ -443,43 +454,37 @@ Neighborhood RelaxationInducedNeighborhoodGenerator::Generate(
|
||||
Neighborhood neighborhood;
|
||||
neighborhood.cp_model = helper_.ModelProto();
|
||||
|
||||
const int num_active_vars = helper_.ActiveVariables().size();
|
||||
const int num_model_vars = helper_.ModelProto().variables_size();
|
||||
const int target_size =
|
||||
num_model_vars - std::ceil(difficulty * num_active_vars);
|
||||
if (target_size == num_active_vars) {
|
||||
neighborhood.is_reduced = false;
|
||||
return neighborhood;
|
||||
}
|
||||
|
||||
auto* mapping = model_.Get<CpModelMapping>();
|
||||
auto* lp_dispatcher = model_.Get<LinearProgrammingDispatcher>();
|
||||
|
||||
if (lp_dispatcher == nullptr) {
|
||||
neighborhood.is_reduced = false;
|
||||
return neighborhood;
|
||||
}
|
||||
|
||||
std::vector<int> fixed_variables;
|
||||
SharedRINSNeighborhoodManager* rins_manager =
|
||||
model_->Mutable<SharedRINSNeighborhoodManager>();
|
||||
std::vector<int> all_vars;
|
||||
for (int i = 0; i < num_model_vars; ++i) {
|
||||
if (!helper_.IsActive(i)) continue;
|
||||
if (mapping->IsInteger(i)) {
|
||||
const IntegerVariable var = mapping->Integer(i);
|
||||
const IntegerVariable positive_var = PositiveVariable(var);
|
||||
LinearProgrammingConstraint* lp =
|
||||
gtl::FindWithDefault(*lp_dispatcher, positive_var, nullptr);
|
||||
if (lp == nullptr) continue;
|
||||
const double lp_value = (lp->GetSolutionValue(positive_var));
|
||||
all_vars.push_back(i);
|
||||
}
|
||||
if (rins_manager == nullptr) {
|
||||
// TODO(user): Support skipping this neighborhood instead of going
|
||||
// through solving process for the trivial model.
|
||||
return helper_.FixAllVariables(initial_solution);
|
||||
}
|
||||
absl::optional<RINSNeighborhood> rins_neighborhood_opt =
|
||||
rins_manager->GetUnexploredNeighborhood();
|
||||
|
||||
if (std::abs(lp_value - initial_solution.solution(i)) < 1e-4) {
|
||||
// Fix this var.
|
||||
fixed_variables.push_back(i);
|
||||
if (fixed_variables.size() >= target_size) break;
|
||||
}
|
||||
}
|
||||
if (!rins_neighborhood_opt.has_value()) {
|
||||
return helper_.FixAllVariables(initial_solution);
|
||||
}
|
||||
|
||||
return helper_.FixGivenVariables(initial_solution, fixed_variables);
|
||||
// Fix the variables in the local model.
|
||||
for (const std::pair<int, int64> fixed_var :
|
||||
rins_neighborhood_opt.value().fixed_vars) {
|
||||
int var = fixed_var.first;
|
||||
int64 value = fixed_var.second;
|
||||
if (!helper_.IsActive(var)) continue;
|
||||
neighborhood.cp_model.mutable_variables(var)->clear_domain();
|
||||
neighborhood.cp_model.mutable_variables(var)->add_domain(value);
|
||||
neighborhood.cp_model.mutable_variables(var)->add_domain(value);
|
||||
neighborhood.is_reduced = true;
|
||||
}
|
||||
return neighborhood;
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
|
||||
@@ -61,6 +61,10 @@ class NeighborhoodGeneratorHelper {
|
||||
const CpSolverResponse& initial_solution,
|
||||
const std::vector<int>& relaxed_variables) const;
|
||||
|
||||
// Returns a trivial model by fixing all active variables to the initial
|
||||
// solution values.
|
||||
Neighborhood FixAllVariables(const CpSolverResponse& initial_solution) const;
|
||||
|
||||
// Indicates if the variable can be frozen. It happens if the variable is non
|
||||
// constant, and if it is a decision variable, or if
|
||||
// focus_on_decision_variables is false.
|
||||
@@ -239,14 +243,14 @@ class SchedulingTimeWindowNeighborhoodGenerator : public NeighborhoodGenerator {
|
||||
class RelaxationInducedNeighborhoodGenerator : public NeighborhoodGenerator {
|
||||
public:
|
||||
explicit RelaxationInducedNeighborhoodGenerator(
|
||||
NeighborhoodGeneratorHelper const* helper, const Model& model,
|
||||
NeighborhoodGeneratorHelper const* helper, Model* model,
|
||||
const std::string& name)
|
||||
: NeighborhoodGenerator(name, helper), model_(model) {}
|
||||
|
||||
Neighborhood Generate(const CpSolverResponse& initial_solution, int64 seed,
|
||||
double difficulty) const final;
|
||||
|
||||
const Model& model_;
|
||||
const Model* model_;
|
||||
};
|
||||
|
||||
} // namespace sat
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include "ortools/sat/optimization.h"
|
||||
#include "ortools/sat/precedences.h"
|
||||
#include "ortools/sat/probing.h"
|
||||
#include "ortools/sat/rins.h"
|
||||
#include "ortools/sat/sat_base.h"
|
||||
#include "ortools/sat/sat_solver.h"
|
||||
#include "ortools/sat/simplification.h"
|
||||
@@ -1873,7 +1874,7 @@ void SolveCpModelWithLNS(const CpModelProto& model_proto, int num_workers,
|
||||
// TODO(user): Only do it if we have a linear relaxation.
|
||||
generators.push_back(
|
||||
absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
|
||||
&helper, *model, "rins"));
|
||||
&helper, model, "rins"));
|
||||
}
|
||||
|
||||
// The "optimal" difficulties do not have to be the same for different
|
||||
@@ -2080,6 +2081,13 @@ void SolveCpModelParallel(const CpModelProto& model_proto,
|
||||
absl::make_unique<SharedBoundsManager>(num_search_workers, model_proto);
|
||||
}
|
||||
|
||||
// Note: This is shared only if the rins is enabled in the global parameters.
|
||||
std::unique_ptr<SharedRINSNeighborhoodManager> rins_manager;
|
||||
if (model->GetOrCreate<SatParameters>()->use_rins_lns()) {
|
||||
rins_manager = absl::make_unique<SharedRINSNeighborhoodManager>(
|
||||
model_proto.variables_size());
|
||||
}
|
||||
|
||||
// Collect per-worker parameters and names.
|
||||
std::vector<SatParameters> worker_parameters;
|
||||
std::vector<std::string> worker_names;
|
||||
@@ -2121,12 +2129,17 @@ void SolveCpModelParallel(const CpModelProto& model_proto,
|
||||
num_search_workers, wall_timer,
|
||||
&first_solution_found_or_search_finished,
|
||||
&shared_response_manager, &shared_bounds_manager,
|
||||
worker_name]() {
|
||||
worker_name, &rins_manager]() {
|
||||
Model local_model;
|
||||
local_model.Add(NewSatParameters(local_params));
|
||||
local_model.GetOrCreate<TimeLimit>()->RegisterExternalBooleanAsLimit(
|
||||
stopped);
|
||||
|
||||
// Add shared neighborhood only if RINS is enabled in global parameters.
|
||||
if (rins_manager != nullptr) {
|
||||
local_model.Register<SharedRINSNeighborhoodManager>(rins_manager.get());
|
||||
}
|
||||
|
||||
// Stores info that will be used for logs in the local model.
|
||||
WorkerInfo* worker_info = local_model.GetOrCreate<WorkerInfo>();
|
||||
worker_info->worker_name = worker_name;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ortools/sat/integer.h"
|
||||
#include "ortools/sat/linear_programming_constraint.h"
|
||||
#include "ortools/sat/pseudo_costs.h"
|
||||
#include "ortools/sat/rins.h"
|
||||
#include "ortools/sat/sat_base.h"
|
||||
#include "ortools/sat/sat_decision.h"
|
||||
#include "ortools/sat/util.h"
|
||||
@@ -646,6 +647,7 @@ SatSolver::Status SolveIntegerProblem(Model* model) {
|
||||
const int64 old_num_conflicts = solver->num_failures();
|
||||
const int64 conflict_limit =
|
||||
model->GetOrCreate<SatParameters>()->max_number_of_conflicts();
|
||||
int64 num_decisions_without_rins = 0;
|
||||
while (!time_limit->LimitReached() &&
|
||||
(solver->num_failures() - old_num_conflicts < conflict_limit)) {
|
||||
// If needed, restart and switch decision_policy.
|
||||
@@ -705,6 +707,17 @@ SatSolver::Status SolveIntegerProblem(Model* model) {
|
||||
|
||||
solver->AdvanceDeterministicTime(time_limit);
|
||||
if (!solver->ReapplyAssumptionsIfNeeded()) return solver->UnsatStatus();
|
||||
if (model->GetOrCreate<SolutionDetails>()->solution_count > 0 &&
|
||||
model->Get<SharedRINSNeighborhoodManager>() != nullptr) {
|
||||
num_decisions_without_rins++;
|
||||
// TODO(user): Experiment more around dynamically changing the
|
||||
// threshold for trigerring RINS. Alternatively expose this as parameter
|
||||
// so this can be tuned later.
|
||||
if (num_decisions_without_rins >= 100) {
|
||||
num_decisions_without_rins = 0;
|
||||
AddRINSNeighborhood(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SatSolver::Status::LIMIT_REACHED;
|
||||
}
|
||||
|
||||
@@ -113,14 +113,6 @@ LiteralIndex SplitAroundGivenValue(IntegerVariable positive_var,
|
||||
// does not appear in the LP, this method returns kNoLiteralIndex.
|
||||
LiteralIndex SplitAroundLpValue(IntegerVariable var, Model* model);
|
||||
|
||||
struct SolutionDetails {
|
||||
int64 solution_count = 0;
|
||||
gtl::ITIVector<IntegerVariable, IntegerValue> best_solution;
|
||||
|
||||
// Loads the solution in best_solution using lower bounds from integer trail.
|
||||
void LoadFromTrail(const IntegerTrail& integer_trail);
|
||||
};
|
||||
|
||||
// Returns decision corresponding to var <= best_solution[var]. If no solution
|
||||
// has been found, this method returns kNoLiteralIndex. This was suggested in
|
||||
// paper: "Solution-Based Phase Saving for CP" (2018) by Emir Demirovic,
|
||||
|
||||
@@ -122,6 +122,15 @@ class Model {
|
||||
return new_t;
|
||||
}
|
||||
|
||||
// Register a non-owned class that will be "singleton" in the model.
|
||||
// It is an error to call this on an already registered class.
|
||||
template <typename T>
|
||||
void Register(T* non_owned_class) {
|
||||
const size_t type_id = gtl::FastTypeId<T>();
|
||||
CHECK(!gtl::ContainsKey(singletons_, type_id));
|
||||
singletons_[type_id] = non_owned_class;
|
||||
}
|
||||
|
||||
private:
|
||||
// We want to call the constructor T(model*) if it exists or just T() if
|
||||
// it doesn't. For this we use some template "magic":
|
||||
|
||||
115
ortools/sat/rins.cc
Normal file
115
ortools/sat/rins.cc
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2010-2018 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ortools/sat/rins.h"
|
||||
|
||||
#include "ortools/sat/cp_model_loader.h"
|
||||
#include "ortools/sat/integer.h"
|
||||
#include "ortools/sat/linear_programming_constraint.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace sat {
|
||||
|
||||
bool SharedRINSNeighborhoodManager::AddNeighborhood(
|
||||
const absl::flat_hash_map<IntegerVariable, IntegerValue>& fixed_vars,
|
||||
const Model& model) {
|
||||
auto* mapping = model.Get<CpModelMapping>();
|
||||
if (mapping == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't store this neighborhood if the current storage is already too large.
|
||||
// TODO(user): Consider instead removing one of the older neighborhoods.
|
||||
if (total_num_fixed_vars_ + fixed_vars.size() > max_fixed_vars()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RINSNeighborhood rins_neighborhood;
|
||||
// TODO(user): Use GetProtoVariableFromIntegerVariable instead and change
|
||||
// the api to take a list of fixed vars instead of a hash map.
|
||||
for (int i = 0; i < num_model_vars_; ++i) {
|
||||
if (mapping->IsInteger(i)) {
|
||||
const IntegerVariable var = mapping->Integer(i);
|
||||
if (fixed_vars.contains(var)) {
|
||||
rins_neighborhood.fixed_vars.push_back(
|
||||
{i, fixed_vars.find(var)->second.value()});
|
||||
} else if (fixed_vars.contains(NegationOf(var))) {
|
||||
rins_neighborhood.fixed_vars.push_back(
|
||||
{i, -fixed_vars.find(var)->second.value()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absl::MutexLock lock(&mutex_);
|
||||
total_num_fixed_vars_ += rins_neighborhood.fixed_vars.size();
|
||||
neighborhoods_.push_back(std::move(rins_neighborhood));
|
||||
VLOG(1) << "total fixed vars: " << total_num_fixed_vars_;
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::optional<RINSNeighborhood>
|
||||
SharedRINSNeighborhoodManager::GetUnexploredNeighborhood() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (neighborhoods_.empty()) {
|
||||
VLOG(2) << "No neighborhood to consume.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// return the last added neighborhood and remove it.
|
||||
const RINSNeighborhood neighborhood = std::move(neighborhoods_.back());
|
||||
neighborhoods_.pop_back();
|
||||
total_num_fixed_vars_ -= neighborhood.fixed_vars.size();
|
||||
VLOG(1) << "total fixed vars: " << total_num_fixed_vars_;
|
||||
return neighborhood;
|
||||
}
|
||||
|
||||
void AddRINSNeighborhood(Model* model) {
|
||||
IntegerTrail* const integer_trail = model->GetOrCreate<IntegerTrail>();
|
||||
absl::flat_hash_map<IntegerVariable, IntegerValue> fixed_vars;
|
||||
auto* solution_details = model->GetOrCreate<SolutionDetails>();
|
||||
|
||||
const int size = solution_details->best_solution.size();
|
||||
for (IntegerVariable var(0); var < size; ++var) {
|
||||
auto* lp_dispatcher = model->GetOrCreate<LinearProgrammingDispatcher>();
|
||||
|
||||
const IntegerVariable positive_var = PositiveVariable(var);
|
||||
|
||||
if (integer_trail->IsCurrentlyIgnored(positive_var)) continue;
|
||||
|
||||
// TODO(user): Perform caching to make this more efficient.
|
||||
LinearProgrammingConstraint* lp =
|
||||
gtl::FindWithDefault(*lp_dispatcher, positive_var, nullptr);
|
||||
if (lp == nullptr || !lp->HasSolution()) continue;
|
||||
|
||||
const IntegerValue best_solution_value =
|
||||
solution_details->best_solution[var];
|
||||
if (std::abs(best_solution_value.value() -
|
||||
lp->GetSolutionValue(positive_var)) < 1e-4) {
|
||||
if (best_solution_value >= integer_trail->LowerBound(var) ||
|
||||
best_solution_value <= integer_trail->UpperBound(var)) {
|
||||
fixed_vars[positive_var] = best_solution_value;
|
||||
} else {
|
||||
// The last lp_solution might not always be up to date.
|
||||
VLOG(2) << "RINS common value out of bounds: " << best_solution_value
|
||||
<< " LB: " << integer_trail->LowerBound(var)
|
||||
<< " UB: " << integer_trail->UpperBound(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
VLOG(2) << "RINS Fixed: " << fixed_vars.size() << "/" << size;
|
||||
model->Mutable<SharedRINSNeighborhoodManager>()->AddNeighborhood(fixed_vars,
|
||||
*model);
|
||||
}
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
84
ortools/sat/rins.h
Normal file
84
ortools/sat/rins.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2010-2018 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef OR_TOOLS_SAT_RINS_H_
|
||||
#define OR_TOOLS_SAT_RINS_H_
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "ortools/sat/integer.h"
|
||||
#include "ortools/sat/model.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace sat {
|
||||
|
||||
// TODO(user): This is not an ideal place for the solution details. Move to a
|
||||
// file with other such stats or create one if needed.
|
||||
struct SolutionDetails {
|
||||
int64 solution_count = 0;
|
||||
gtl::ITIVector<IntegerVariable, IntegerValue> best_solution;
|
||||
|
||||
// Loads the solution in best_solution using lower bounds from integer trail.
|
||||
void LoadFromTrail(const IntegerTrail& integer_trail);
|
||||
};
|
||||
|
||||
struct RINSNeighborhood {
|
||||
std::vector<std::pair</*var*/ int, /*value*/ int64>> fixed_vars;
|
||||
};
|
||||
|
||||
// Shared object to pass around generated RINS neighborhoods across workers.
|
||||
class SharedRINSNeighborhoodManager {
|
||||
public:
|
||||
explicit SharedRINSNeighborhoodManager(const int64 num_model_vars)
|
||||
: num_model_vars_(num_model_vars) {}
|
||||
|
||||
// Model will be used to get the CpModelMapping for translation. Returns
|
||||
// true for success.
|
||||
bool AddNeighborhood(
|
||||
const absl::flat_hash_map<IntegerVariable, IntegerValue>& fixed_vars,
|
||||
const Model& model);
|
||||
|
||||
// Returns an unexplored RINS neighborhood if any, otherwise returns nullopt.
|
||||
// TODO(user): This also deletes the returned neighborhood. Consider having
|
||||
// a different method/logic instead for deletion.
|
||||
absl::optional<RINSNeighborhood> GetUnexploredNeighborhood();
|
||||
|
||||
// This is the memory limit we use to avoid storing too many neighborhoods.
|
||||
// The sum of the fixed variables of the stored neighborhood will always
|
||||
// stays smaller than this.
|
||||
int64 max_fixed_vars() const { return 100 * num_model_vars_; }
|
||||
|
||||
private:
|
||||
// Used while adding and removing neighborhoods.
|
||||
absl::Mutex mutex_;
|
||||
|
||||
// TODO(user): Use better data structure (e.g. queue) to store this
|
||||
// collection.
|
||||
std::vector<RINSNeighborhood> neighborhoods_;
|
||||
|
||||
// This is the sum of number of fixed variables across all the shared
|
||||
// neighborhoods. This is used for controlling the size of storage.
|
||||
int64 total_num_fixed_vars_ = 0;
|
||||
|
||||
const int64 num_model_vars_;
|
||||
};
|
||||
|
||||
// Helper method to create a RINS neighborhood by fixing variables with same
|
||||
// values in lp and last solution.
|
||||
void AddRINSNeighborhood(Model* model);
|
||||
|
||||
} // namespace sat
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_SAT_RINS_H_
|
||||
Reference in New Issue
Block a user