OR-Tools  9.6
circuit.h
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_SAT_CIRCUIT_H_
15 #define OR_TOOLS_SAT_CIRCUIT_H_
16 
17 #include <functional>
18 #include <memory>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/container/btree_set.h"
23 #include "absl/container/flat_hash_map.h"
25 #include "ortools/base/logging.h"
26 #include "ortools/base/macros.h"
28 #include "ortools/sat/integer.h"
29 #include "ortools/sat/model.h"
30 #include "ortools/sat/sat_base.h"
31 #include "ortools/util/rev.h"
33 
34 namespace operations_research {
35 namespace sat {
36 
37 // Circuit/sub-circuit constraint.
38 //
39 // Nodes that are not in the unique allowed sub-circuit must point to themseves.
40 // A nodes that has no self-arc must thus be inside the sub-circuit. If there is
41 // no self-arc at all, then this constaint forces the circuit to go through all
42 // the nodes. Multi-arcs are NOT supported.
43 //
44 // Important: for correctness, this constraint requires that "exactly one"
45 // constraints have been added for all the incoming (resp. outgoing) arcs of
46 // each node. Also, such constraint must propagate before this one.
48  public:
49  struct Options {
50  // Hack for the VRP to allow for more than one sub-circuit and forces all
51  // the subcircuits to go through the node zero.
53  };
54 
55  // The constraints take a sparse representation of a graph on [0, n). Each arc
56  // being present when the given literal is true.
57  CircuitPropagator(int num_nodes, const std::vector<int>& tails,
58  const std::vector<int>& heads,
59  const std::vector<Literal>& literals, Options options,
60  Model* model);
61 
62  void SetLevel(int level) final;
63  bool Propagate() final;
64  bool IncrementalPropagate(const std::vector<int>& watch_indices) final;
65  void RegisterWith(GenericLiteralWatcher* watcher);
66 
67  private:
68  // Updates the structures when the given arc is added to the paths.
69  void AddArc(int tail, int head, LiteralIndex literal_index);
70 
71  // Clears and fills reason with the literals of the arcs that form a path from
72  // the given node. The path can be a cycle, but in this case it must end at
73  // start (not like a rho shape).
74  void FillReasonForPath(int start_node, std::vector<Literal>* reason) const;
75 
76  const int num_nodes_;
77  const Options options_;
78  Trail* trail_;
79  const VariablesAssignment& assignment_;
80 
81  // We use this to query in O(1) for an arc existence. The self-arcs are
82  // accessed often, so we use a more efficient std::vector<> for them. Note
83  // that we do not add self-arcs to graph_.
84  //
85  // TODO(user): for large dense graph, using a matrix is faster and uses less
86  // memory. If the need arise we can have the two implementations.
87  std::vector<Literal> self_arcs_;
88  absl::flat_hash_map<std::pair<int, int>, Literal> graph_;
89 
90  // Data used to interpret the watch indices passed to IncrementalPropagate().
91  struct Arc {
92  int tail;
93  int head;
94  };
95  std::vector<Literal> watch_index_to_literal_;
96  std::vector<std::vector<Arc>> watch_index_to_arcs_;
97 
98  // Current partial chains of arc that are present.
99  std::vector<int> next_; // -1 if not assigned yet.
100  std::vector<int> prev_; // -1 if not assigned yet.
101  std::vector<LiteralIndex> next_literal_;
102 
103  // Backtrack support for the partial chains of arcs, level_ends_[level] is an
104  // index in added_arcs_;
105  std::vector<int> level_ends_;
106  std::vector<Arc> added_arcs_;
107 
108  // Reversible list of node that must be in a cycle. A node must be in a cycle
109  // iff self_arcs_[node] is false. This graph entry can be used as a reason.
110  int rev_must_be_in_cycle_size_ = 0;
111  std::vector<int> must_be_in_cycle_;
112 
113  // Temporary vectors.
114  std::vector<bool> processed_;
115  std::vector<bool> in_current_path_;
116 
117  DISALLOW_COPY_AND_ASSIGN(CircuitPropagator);
118 };
119 
120 // Enforce the fact that there is no cycle in the given directed graph.
122  public:
123  NoCyclePropagator(int num_nodes, const std::vector<int>& tails,
124  const std::vector<int>& heads,
125  const std::vector<Literal>& literals, Model* model);
126 
127  void SetLevel(int level) final;
128  bool Propagate() final;
129  bool IncrementalPropagate(const std::vector<int>& watch_indices) final;
130 
131  private:
132  void RegisterWith(GenericLiteralWatcher* watcher);
133 
134  const int num_nodes_;
135  Trail* trail_;
136  const VariablesAssignment& assignment_;
137 
138  // The set of all watched literals and to what arc they correspond.
139  std::vector<Literal> watch_index_to_literal_;
140  std::vector<std::vector<std::pair<int, int>>> watch_index_to_arcs_;
141 
142  // This will only contains the subgraph with all the arc at true.
143  // We maintain it incrementally and update this on SetLevel()/Propagate().
144  std::vector<std::vector<int>> graph_;
145  std::vector<std::vector<Literal>> graph_literals_;
146 
147  // For now we redo a strongly connected component on the graph formed of arcs
148  // at one.
149  //
150  // TODO(user): code a true algo.
151  std::vector<std::vector<int>> components_;
153  std::vector<std::vector<int>>>
154  ssc_;
155 
156  // SAT incremental state.
157  std::vector<int> level_ends_;
158  std::vector<int> touched_nodes_;
159 };
160 
161 // This constraint ensures that the graph is a covering of all nodes by
162 // circuits and loops, such that all circuits contain exactly one distinguished
163 // node. Those distinguished nodes are meant to be depots.
164 //
165 // This constraint does not need ExactlyOnePerRowAndPerColumn() to be correct,
166 // but it does not propagate degree deductions (only fails if a node has more
167 // than one outgoing arc or more than one incoming arc), so that adding
168 // ExactlyOnePerRowAndPerColumn() should work better.
169 //
170 // TODO(user): Make distinguished nodes an array of Boolean variables,
171 // so this can be used for facility location problems.
173  public:
174  CircuitCoveringPropagator(std::vector<std::vector<Literal>> graph,
175  const std::vector<int>& distinguished_nodes,
176  Model* model);
177 
178  void SetLevel(int level) final;
179  bool Propagate() final;
180  bool IncrementalPropagate(const std::vector<int>& watch_indices) final;
181  void RegisterWith(GenericLiteralWatcher* watcher);
182 
183  private:
184  // Adds all literals on the path/circuit from tail to head in the graph of
185  // literals set to true.
186  // next_[i] should be filled with a node j s.t. graph_[i][j] is true, or -1.
187  void FillFixedPathInReason(int start, int end, std::vector<Literal>* reason);
188 
189  // Input data.
190  const std::vector<std::vector<Literal>> graph_;
191  const int num_nodes_;
192  std::vector<bool> node_is_distinguished_;
193 
194  // SAT incremental state.
195  Trail* trail_;
196  std::vector<std::pair<int, int>> watch_index_to_arc_;
197  std::vector<std::pair<int, int>> fixed_arcs_;
198  std::vector<int> level_ends_;
199 
200  // Used in Propagate() to represent paths and circuits.
201  std::vector<int> next_;
202  std::vector<int> prev_;
203  std::vector<bool> visited_;
204 };
205 
206 // Changes the node indices so that we get a graph in [0, num_nodes) where every
207 // node has at least one incoming or outgoing arc. Returns the number of nodes.
208 template <class IntContainer>
209 int ReindexArcs(IntContainer* tails, IntContainer* heads,
210  absl::flat_hash_map<int, int>* mapping_output = nullptr) {
211  const int num_arcs = tails->size();
212  if (num_arcs == 0) return 0;
213 
214  // Put all nodes in a set.
215  absl::btree_set<int> nodes;
216  for (int arc = 0; arc < num_arcs; ++arc) {
217  nodes.insert((*tails)[arc]);
218  nodes.insert((*heads)[arc]);
219  }
220 
221  // Compute the new indices while keeping a stable order.
222  int new_index = 0;
223  absl::flat_hash_map<int, int> mapping;
224  for (const int node : nodes) {
225  mapping[node] = new_index++;
226  }
227 
228  // Remap the arcs.
229  for (int arc = 0; arc < num_arcs; ++arc) {
230  (*tails)[arc] = mapping[(*tails)[arc]];
231  (*heads)[arc] = mapping[(*heads)[arc]];
232  }
233 
234  if (mapping_output != nullptr) {
235  *mapping_output = std::move(mapping);
236  }
237 
238  return nodes.size();
239 }
240 
241 // ============================================================================
242 // Model based functions.
243 // ============================================================================
244 
245 // This just wraps CircuitPropagator. See the comment there to see what this
246 // does. Note that any nodes with no outoing or no incoming arc will cause the
247 // problem to be UNSAT. One can call ReindexArcs() first to ignore such nodes.
248 std::function<void(Model*)> SubcircuitConstraint(
249  int num_nodes, const std::vector<int>& tails, const std::vector<int>& heads,
250  const std::vector<Literal>& literals,
251  bool multiple_subcircuit_through_zero = false);
252 
253 // TODO(user): Change to a sparse API like for the function above.
254 std::function<void(Model*)> ExactlyOnePerRowAndPerColumn(
255  const std::vector<std::vector<Literal>>& graph);
256 std::function<void(Model*)> CircuitCovering(
257  const std::vector<std::vector<Literal>>& graph,
258  const std::vector<int>& distinguished_nodes);
259 
260 } // namespace sat
261 } // namespace operations_research
262 
263 #endif // OR_TOOLS_SAT_CIRCUIT_H_
CircuitCoveringPropagator(std::vector< std::vector< Literal >> graph, const std::vector< int > &distinguished_nodes, Model *model)
Definition: circuit.cc:468
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
Definition: circuit.cc:513
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: circuit.cc:480
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
Definition: circuit.cc:160
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: circuit.cc:100
CircuitPropagator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, Options options, Model *model)
Definition: circuit.cc:33
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
bool IncrementalPropagate(const std::vector< int > &watch_indices) final
Definition: circuit.cc:417
NoCyclePropagator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, Model *model)
Definition: circuit.cc:343
GRBmodel * model
int arc
Definition: cleanup.h:22
std::function< void(Model *)> SubcircuitConstraint(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, bool multiple_subcircuit_through_zero)
Definition: circuit.cc:631
std::function< void(Model *)> CircuitCovering(const std::vector< std::vector< Literal >> &graph, const std::vector< int > &distinguished_nodes)
Definition: circuit.cc:673
std::function< void(Model *)> ExactlyOnePerRowAndPerColumn(const std::vector< std::vector< Literal >> &graph)
Definition: circuit.cc:612
int ReindexArcs(IntContainer *tails, IntContainer *heads, absl::flat_hash_map< int, int > *mapping_output=nullptr)
Definition: circuit.h:209
Collection of objects used to extend the Constraint Solver library.
int64_t tail
int64_t head
int nodes
std::optional< int64_t > end
int64_t start