forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 9
/
bop_lns.h
178 lines (156 loc) · 7.37 KB
/
bop_lns.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// Copyright 2010-2024 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_BOP_BOP_LNS_H_
#define OR_TOOLS_BOP_BOP_LNS_H_
#include <cstdint>
#include <memory>
#include <vector>
#include "absl/random/bit_gen_ref.h"
#include "absl/strings/string_view.h"
#include "ortools/base/strong_vector.h"
#include "ortools/bop/bop_base.h"
#include "ortools/bop/bop_parameters.pb.h"
#include "ortools/bop/bop_types.h"
#include "ortools/bop/bop_util.h"
#include "ortools/sat/boolean_problem.pb.h"
#include "ortools/sat/sat_solver.h"
#include "ortools/util/time_limit.h"
namespace operations_research {
namespace bop {
// Uses SAT to solve the full problem under the constraint that the new solution
// should be under a given Hamming distance of the current solution.
class BopCompleteLNSOptimizer final : public BopOptimizerBase {
public:
BopCompleteLNSOptimizer(absl::string_view name,
const BopConstraintTerms& objective_terms);
~BopCompleteLNSOptimizer() final;
private:
bool ShouldBeRun(const ProblemState& problem_state) const final;
Status Optimize(const BopParameters& parameters,
const ProblemState& problem_state, LearnedInfo* learned_info,
TimeLimit* time_limit) final;
BopOptimizerBase::Status SynchronizeIfNeeded(
const ProblemState& problem_state, int num_relaxed_vars);
int64_t state_update_stamp_;
std::unique_ptr<sat::SatSolver> sat_solver_;
const BopConstraintTerms& objective_terms_;
};
// Interface of the different LNS neighborhood generation algorithm.
//
// NOTE(user): Using a sat_propagator as the output of the algorithm allows for
// a really simple and efficient interface for the generator that relies on it.
// However, if a generator doesn't rely on it at all, it may slow down a bit the
// code (to investigate). If this happens, we will probably need another
// function here and a way to select between which one to call.
class NeighborhoodGenerator {
public:
NeighborhoodGenerator() = default;
virtual ~NeighborhoodGenerator() = default;
// Interface for the neighborhood generation.
//
// The difficulty will be in [0, 1] and is related to the asked neighborhood
// size (and thus local problem difficulty). A difficulty of 0.0 means empty
// neighborhood and a difficulty of 1.0 means the full problem. The algorithm
// should try to generate an neighborhood according to this difficulty, which
// will be dynamically adjusted depending on whether or not we can solve the
// subproblem.
//
// The given sat_propagator will be reset and then configured so that all the
// variables propagated on its trail should be fixed. That is, the
// neighborhood will correspond to the unassigned variables in the
// sat_propagator. Note that sat_propagator_.IsModelUnsat() will be checked
// after this is called so it is okay to abort if this happens.
//
// Preconditions:
// - The given sat_propagator_ should have the current problem loaded (with
// the constraint to find a better solution that any current solution).
// - The problem state must contains a feasible solution.
virtual void GenerateNeighborhood(const ProblemState& problem_state,
double difficulty,
sat::SatSolver* sat_propagator) = 0;
};
// A generic LNS optimizer which generates neighborhoods according to the given
// NeighborhoodGenerator and automatically adapt the neighborhood size depending
// on how easy it is to solve the associated problem.
class BopAdaptiveLNSOptimizer final : public BopOptimizerBase {
public:
// Takes ownership of the given neighborhood_generator.
// The sat_propagator is assumed to contains the current problem.
BopAdaptiveLNSOptimizer(absl::string_view name, bool use_lp_to_guide_sat,
NeighborhoodGenerator* neighborhood_generator,
sat::SatSolver* sat_propagator);
~BopAdaptiveLNSOptimizer() final;
private:
bool ShouldBeRun(const ProblemState& problem_state) const final;
Status Optimize(const BopParameters& parameters,
const ProblemState& problem_state, LearnedInfo* learned_info,
TimeLimit* time_limit) final;
const bool use_lp_to_guide_sat_;
std::unique_ptr<NeighborhoodGenerator> neighborhood_generator_;
sat::SatSolver* const sat_propagator_;
// Adaptive neighborhood size logic.
// The values are kept from one run to the next.
LubyAdaptiveParameterValue adaptive_difficulty_;
};
// Generates a neighborhood by randomly fixing a subset of the objective
// variables that are currently at their lower cost.
class ObjectiveBasedNeighborhood final : public NeighborhoodGenerator {
public:
ObjectiveBasedNeighborhood(const BopConstraintTerms* objective_terms,
absl::BitGenRef random)
: objective_terms_(*objective_terms), random_(random) {}
~ObjectiveBasedNeighborhood() final = default;
private:
void GenerateNeighborhood(const ProblemState& problem_state,
double difficulty,
sat::SatSolver* sat_propagator) final;
const BopConstraintTerms& objective_terms_;
absl::BitGenRef random_;
};
// Generates a neighborhood by randomly selecting a subset of constraints and
// fixing the objective variables that are currently at their lower cost and
// not in the given subset of constraints.
class ConstraintBasedNeighborhood final : public NeighborhoodGenerator {
public:
ConstraintBasedNeighborhood(const BopConstraintTerms* objective_terms,
absl::BitGenRef random)
: objective_terms_(*objective_terms), random_(random) {}
~ConstraintBasedNeighborhood() final = default;
private:
void GenerateNeighborhood(const ProblemState& problem_state,
double difficulty,
sat::SatSolver* sat_propagator) final;
const BopConstraintTerms& objective_terms_;
absl::BitGenRef random_;
};
// Generates a neighborhood by taking a random local neighborhood in an
// undirected graph where the nodes are the variables and two nodes are linked
// if they appear in the same constraint.
class RelationGraphBasedNeighborhood final : public NeighborhoodGenerator {
public:
RelationGraphBasedNeighborhood(const sat::LinearBooleanProblem& problem,
absl::BitGenRef random);
~RelationGraphBasedNeighborhood() final = default;
private:
void GenerateNeighborhood(const ProblemState& problem_state,
double difficulty,
sat::SatSolver* sat_propagator) final;
// TODO(user): reuse by_variable_matrix_ from the LS? Note however than we
// don't need the coefficients here.
util_intops::StrongVector<VariableIndex, std::vector<ConstraintIndex>>
columns_;
absl::BitGenRef random_;
};
} // namespace bop
} // namespace operations_research
#endif // OR_TOOLS_BOP_BOP_LNS_H_