[Routing] add search event: at optimal
This commit is contained in:
committed by
Corentin Le Molgat
parent
032fad4c94
commit
6d3a78e9d5
@@ -214,6 +214,7 @@ cc_library(
|
||||
"@abseil-cpp//absl/algorithm:container",
|
||||
"@abseil-cpp//absl/base:core_headers",
|
||||
"@abseil-cpp//absl/base:log_severity",
|
||||
"@abseil-cpp//absl/base:nullability",
|
||||
"@abseil-cpp//absl/container:flat_hash_map",
|
||||
"@abseil-cpp//absl/container:flat_hash_set",
|
||||
"@abseil-cpp//absl/flags:flag",
|
||||
|
||||
@@ -4663,6 +4663,15 @@ class OptimizeVar : public ObjectiveMonitor {
|
||||
/// Returns the variable that is optimized.
|
||||
IntVar* var() const { return Size() == 0 ? nullptr : ObjectiveVar(0); }
|
||||
|
||||
#ifndef SWIG
|
||||
/// Sets a callback to be called when the objective value is found to be
|
||||
/// optimal.
|
||||
void SetOnOptimalFoundcallback(
|
||||
std::function<void(int64_t)> on_optimal_found) {
|
||||
on_optimal_found_ = std::move(on_optimal_found);
|
||||
}
|
||||
#endif // SWIG
|
||||
|
||||
/// Internal methods.
|
||||
void BeginNextDecision(DecisionBuilder* db) override;
|
||||
void RefuteDecision(Decision* d) override;
|
||||
@@ -4672,6 +4681,9 @@ class OptimizeVar : public ObjectiveMonitor {
|
||||
std::string DebugString() const override;
|
||||
|
||||
void ApplyBound();
|
||||
|
||||
private:
|
||||
std::function<void(int64_t)> on_optimal_found_;
|
||||
};
|
||||
|
||||
/// Base class of all search limits.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/flags/flag.h"
|
||||
@@ -4372,7 +4373,7 @@ namespace {
|
||||
// ----- NestedSolve decision wrapper -----
|
||||
|
||||
// This decision calls a nested Solve on the given DecisionBuilder in its
|
||||
// left branch; does nothing in the left branch.
|
||||
// left branch; does nothing in the right branch.
|
||||
// The state of the decision corresponds to the result of the nested Solve:
|
||||
// DECISION_PENDING - Nested Solve not called yet
|
||||
// DECISION_FAILED - Nested Solve failed
|
||||
@@ -4383,9 +4384,9 @@ class NestedSolveDecision : public Decision {
|
||||
// This enum is used internally to tag states in the local search tree.
|
||||
enum StateType { DECISION_PENDING, DECISION_FAILED, DECISION_FOUND };
|
||||
|
||||
NestedSolveDecision(DecisionBuilder* db, bool restore,
|
||||
NestedSolveDecision(DecisionBuilder* absl_nonnull db, bool restore,
|
||||
const std::vector<SearchMonitor*>& monitors);
|
||||
NestedSolveDecision(DecisionBuilder* db, bool restore);
|
||||
NestedSolveDecision(DecisionBuilder* absl_nonnull db, bool restore);
|
||||
~NestedSolveDecision() override {}
|
||||
void Apply(Solver* solver) override;
|
||||
void Refute(Solver* solver) override;
|
||||
@@ -4395,25 +4396,21 @@ class NestedSolveDecision : public Decision {
|
||||
private:
|
||||
DecisionBuilder* const db_;
|
||||
const bool restore_;
|
||||
std::vector<SearchMonitor*> monitors_;
|
||||
const std::vector<SearchMonitor*> monitors_;
|
||||
int state_;
|
||||
};
|
||||
|
||||
NestedSolveDecision::NestedSolveDecision(
|
||||
DecisionBuilder* const db, bool restore,
|
||||
DecisionBuilder* absl_nonnull db, bool restore,
|
||||
const std::vector<SearchMonitor*>& monitors)
|
||||
: db_(db),
|
||||
restore_(restore),
|
||||
monitors_(monitors),
|
||||
state_(DECISION_PENDING) {
|
||||
CHECK(nullptr != db);
|
||||
}
|
||||
state_(DECISION_PENDING) {}
|
||||
|
||||
NestedSolveDecision::NestedSolveDecision(DecisionBuilder* const db,
|
||||
NestedSolveDecision::NestedSolveDecision(DecisionBuilder* absl_nonnull db,
|
||||
bool restore)
|
||||
: db_(db), restore_(restore), state_(DECISION_PENDING) {
|
||||
CHECK(nullptr != db);
|
||||
}
|
||||
: NestedSolveDecision(db, restore, {}) {}
|
||||
|
||||
void NestedSolveDecision::Apply(Solver* const solver) {
|
||||
CHECK(nullptr != solver);
|
||||
|
||||
@@ -6410,7 +6410,12 @@ void RoutingModel::SetupMetaheuristics(
|
||||
}
|
||||
default:
|
||||
limit_too_long = false;
|
||||
optimize = solver_->MakeMinimize(cost_, optimization_step);
|
||||
OptimizeVar* const minimize =
|
||||
solver_->MakeMinimize(cost_, optimization_step);
|
||||
optimize = minimize;
|
||||
minimize->SetOnOptimalFoundcallback([this](int64_t value) {
|
||||
objective_lower_bound_ = std::max(objective_lower_bound_, value);
|
||||
});
|
||||
}
|
||||
if (limit_too_long) {
|
||||
LOG(WARNING) << LocalSearchMetaheuristic::Value_Name(metaheuristic)
|
||||
|
||||
@@ -3217,7 +3217,35 @@ void OptimizeVar::ApplyBound() {
|
||||
}
|
||||
}
|
||||
|
||||
void OptimizeVar::RefuteDecision(Decision*) { ApplyBound(); }
|
||||
namespace {
|
||||
class ApplyBoundDecisionBuilder : public DecisionBuilder {
|
||||
public:
|
||||
explicit ApplyBoundDecisionBuilder(OptimizeVar* optimize_var)
|
||||
: optimize_var_(optimize_var) {}
|
||||
~ApplyBoundDecisionBuilder() override = default;
|
||||
Decision* Next(Solver*) override {
|
||||
optimize_var_->ApplyBound();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
OptimizeVar* optimize_var_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void OptimizeVar::RefuteDecision(Decision*) {
|
||||
if (!solver()->SolveAndCommit(
|
||||
solver()->RevAlloc(new ApplyBoundDecisionBuilder(this)))) {
|
||||
if (on_optimal_found_) {
|
||||
// TODO(user): Support multiple objectives.
|
||||
const int64_t value = CurrentInternalValue(0);
|
||||
on_optimal_found_(objective_vars()[0] == minimization_vars()[0]
|
||||
? value
|
||||
: CapOpp(value));
|
||||
}
|
||||
solver()->Fail();
|
||||
}
|
||||
}
|
||||
|
||||
bool OptimizeVar::AcceptSolution() {
|
||||
if (!found_initial_solution_ || !is_active()) {
|
||||
|
||||
Reference in New Issue
Block a user