OR-Tools  9.3
encoding.cc
Go to the documentation of this file.
1// Copyright 2010-2021 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
15
16#include <algorithm>
17#include <cstdint>
18#include <deque>
19#include <queue>
20#include <vector>
21
23#include "ortools/sat/boolean_problem.pb.h"
26#include "ortools/sat/sat_parameters.pb.h"
29
30namespace operations_research {
31namespace sat {
32
34 : for_sorting_(l.Variable()),
35 child_a_(nullptr),
36 child_b_(nullptr),
37 literals_(1, l) {}
38
40 SatSolver* solver) {
41 CHECK(literals_.empty()) << "Already initialized";
42 CHECK_GT(n, 0);
43 const BooleanVariable first_var_index(solver->NumVariables());
44 solver->SetNumVariables(solver->NumVariables() + n);
45 for (int i = 0; i < n; ++i) {
46 literals_.push_back(Literal(first_var_index + i, true));
47 if (i > 0) {
48 solver->AddBinaryClause(literal(i - 1), literal(i).Negated());
49 }
50 }
51 lb_ = a->lb_ + b->lb_;
52 ub_ = lb_ + n;
53 depth_ = 1 + std::max(a->depth_, b->depth_);
54 child_a_ = a;
55 child_b_ = b;
56 for_sorting_ = first_var_index;
57}
58
60 SatSolver* solver) {
61 CHECK(literals_.empty()) << "Already initialized";
62 const BooleanVariable first_var_index(solver->NumVariables());
63 solver->SetNumVariables(solver->NumVariables() + 1);
64 literals_.emplace_back(first_var_index, true);
65 child_a_ = a;
66 child_b_ = b;
67 ub_ = a->ub_ + b->ub_;
68 lb_ = a->lb_ + b->lb_;
69 depth_ = 1 + std::max(a->depth_, b->depth_);
70
71 // Merging the node of the same depth in order seems to help a bit.
72 for_sorting_ = std::min(a->for_sorting_, b->for_sorting_);
73}
74
76 EncodingNode* b) {
77 CHECK(literals_.empty()) << "Already initialized";
78 child_a_ = a;
79 child_b_ = b;
80 ub_ = a->ub_ + b->ub_;
81 weight_ = weight;
82 weight_lb_ = a->lb_ + b->lb_;
83 lb_ = weight_lb_ + 1;
84 depth_ = 1 + std::max(a->depth_, b->depth_);
85
86 // Merging the node of the same depth in order seems to help a bit.
87 for_sorting_ = std::min(a->for_sorting_, b->for_sorting_);
88}
89
91 if (current_ub() == ub_) return false;
92 literals_.emplace_back(BooleanVariable(solver->NumVariables()), true);
93 solver->SetNumVariables(solver->NumVariables() + 1);
94 if (literals_.size() > 1) {
95 solver->AddBinaryClause(literals_.back().Negated(),
96 literals_[literals_.size() - 2]);
97 }
98 return true;
99}
100
102 int i = 0;
103 while (i < literals_.size() &&
104 solver.Assignment().LiteralIsTrue(literals_[i])) {
105 ++i;
106 ++lb_;
107 }
108 literals_.erase(literals_.begin(), literals_.begin() + i);
109 while (!literals_.empty() &&
110 solver.Assignment().LiteralIsFalse(literals_.back())) {
111 literals_.pop_back();
112 ub_ = lb_ + literals_.size();
113 }
114
115 if (weight_lb_ >= lb_) return Coefficient(0);
116 const Coefficient result = Coefficient(lb_ - weight_lb_) * weight_;
117 weight_lb_ = lb_;
118 return result;
119}
120
122 CHECK_GT(weight_, 0);
123 const Coefficient num_allowed = (gap / weight_);
124 const Coefficient new_size =
125 std::max(Coefficient(0), Coefficient(weight_lb_ - lb_) + num_allowed);
126 if (size() <= new_size) return;
127 for (int i = new_size.value(); i < size(); ++i) {
128 solver->AddUnitClause(literal(i).Negated());
129 }
130 literals_.resize(new_size.value());
131 ub_ = lb_ + literals_.size();
132}
133
135 CHECK(!HasNoWeight());
136 const int index = weight_lb_ - lb_;
137 CHECK_GE(index, 0) << "Not reduced?";
138 while (index >= literals_.size()) {
139 CHECK_NE(solver, nullptr);
140 IncreaseNodeSize(this, solver);
141 }
142 return literals_[index].Negated();
143}
144
146 CHECK_LT(weight_lb_ - lb_, literals_.size());
147 weight_lb_++;
148}
149
151 return weight_ == 0 || weight_lb_ >= ub_;
152}
153
155 const VariablesAssignment& assignment) const {
156 std::string result;
157 absl::StrAppend(&result, "depth:", depth_);
158 absl::StrAppend(&result, " [", lb_, ",", lb_ + literals_.size(), "]");
159 absl::StrAppend(&result, " ub:", ub_);
160 absl::StrAppend(&result, " weight:", weight_.value());
161 absl::StrAppend(&result, " weight_lb:", weight_lb_);
162 absl::StrAppend(&result, " values:");
163 const size_t limit = 20;
164 int value = 0;
165 for (int i = 0; i < std::min(literals_.size(), limit); ++i) {
166 char c = '?';
167 if (assignment.LiteralIsTrue(literals_[i])) {
168 c = '1';
169 value = i + 1;
170 } else if (assignment.LiteralIsFalse(literals_[i])) {
171 c = '0';
172 }
173 result += c;
174 }
175 absl::StrAppend(&result, " val:", lb_ + value);
176 return result;
177}
178
180 EncodingNode n;
181 n.InitializeLazyNode(a, b, solver);
182 solver->AddBinaryClause(a->literal(0).Negated(), n.literal(0));
183 solver->AddBinaryClause(b->literal(0).Negated(), n.literal(0));
184 solver->AddTernaryClause(n.literal(0).Negated(), a->literal(0),
185 b->literal(0));
186 return n;
187}
188
190 if (!node->IncreaseCurrentUB(solver)) return;
191 std::vector<EncodingNode*> to_process;
192 to_process.push_back(node);
193
194 // Only one side of the constraint is mandatory (the one propagating the ones
195 // to the top of the encoding tree), and it seems more efficient not to encode
196 // the other side.
197 //
198 // TODO(user): Experiment more.
199 const bool complete_encoding = false;
200
201 while (!to_process.empty()) {
202 EncodingNode* n = to_process.back();
203 EncodingNode* a = n->child_a();
204 EncodingNode* b = n->child_b();
205 to_process.pop_back();
206
207 // Note that since we were able to increase its size, n must have children.
208 // n->GreaterThan(target) is the new literal of n.
209 CHECK(a != nullptr);
210 CHECK(b != nullptr);
211 const int target = n->current_ub() - 1;
212
213 // Add a literal to a if needed.
214 // That is, now that the node n can go up to it new current_ub, if we need
215 // to increase the current_ub of a.
216 if (a->current_ub() != a->ub()) {
217 CHECK_GE(a->current_ub() - 1 + b->lb(), target - 1);
218 if (a->current_ub() - 1 + b->lb() < target) {
219 CHECK(a->IncreaseCurrentUB(solver));
220 to_process.push_back(a);
221 }
222 }
223
224 // Add a literal to b if needed.
225 if (b->current_ub() != b->ub()) {
226 CHECK_GE(b->current_ub() - 1 + a->lb(), target - 1);
227 if (b->current_ub() - 1 + a->lb() < target) {
228 CHECK(b->IncreaseCurrentUB(solver));
229 to_process.push_back(b);
230 }
231 }
232
233 // Wire the new literal of n correctly with its two children.
234 for (int ia = a->lb(); ia < a->current_ub(); ++ia) {
235 const int ib = target - ia;
236 if (complete_encoding && ib >= b->lb() && ib < b->current_ub()) {
237 // if x <= ia and y <= ib then x + y <= ia + ib.
238 solver->AddTernaryClause(n->GreaterThan(target).Negated(),
239 a->GreaterThan(ia), b->GreaterThan(ib));
240 }
241 if (complete_encoding && ib == b->ub()) {
242 solver->AddBinaryClause(n->GreaterThan(target).Negated(),
243 a->GreaterThan(ia));
244 }
245
246 if (ib - 1 == b->lb() - 1) {
247 solver->AddBinaryClause(n->GreaterThan(target),
248 a->GreaterThan(ia).Negated());
249 }
250 if ((ib - 1) >= b->lb() && (ib - 1) < b->current_ub()) {
251 // if x > ia and y > ib - 1 then x + y > ia + ib.
252 solver->AddTernaryClause(n->GreaterThan(target),
253 a->GreaterThan(ia).Negated(),
254 b->GreaterThan(ib - 1).Negated());
255 }
256 }
257
258 // Case ia = a->lb() - 1; a->GreaterThan(ia) always true.
259 {
260 const int ib = target - (a->lb() - 1);
261 if ((ib - 1) == b->lb() - 1) {
262 solver->AddUnitClause(n->GreaterThan(target));
263 }
264 if ((ib - 1) >= b->lb() && (ib - 1) < b->current_ub()) {
265 solver->AddBinaryClause(n->GreaterThan(target),
266 b->GreaterThan(ib - 1).Negated());
267 }
268 }
269
270 // case ia == a->ub; a->GreaterThan(ia) always false.
271 {
272 const int ib = target - a->ub();
273 if (complete_encoding && ib >= b->lb() && ib < b->current_ub()) {
274 solver->AddBinaryClause(n->GreaterThan(target).Negated(),
275 b->GreaterThan(ib));
276 }
277 if (ib == b->ub()) {
278 solver->AddUnitClause(n->GreaterThan(target).Negated());
279 }
280 }
281 }
282}
283
285 EncodingNode* b, SatSolver* solver) {
286 EncodingNode n;
287 const int size =
288 std::min(Coefficient(a->size() + b->size()), upper_bound).value();
289 n.InitializeFullNode(size, a, b, solver);
290 for (int ia = 0; ia < a->size(); ++ia) {
291 if (ia + b->size() < size) {
292 solver->AddBinaryClause(n.literal(ia + b->size()).Negated(),
293 a->literal(ia));
294 }
295 if (ia < size) {
296 solver->AddBinaryClause(n.literal(ia), a->literal(ia).Negated());
297 } else {
298 // Fix the variable to false because of the given upper_bound.
299 solver->AddUnitClause(a->literal(ia).Negated());
300 }
301 }
302 for (int ib = 0; ib < b->size(); ++ib) {
303 if (ib + a->size() < size) {
304 solver->AddBinaryClause(n.literal(ib + a->size()).Negated(),
305 b->literal(ib));
306 }
307 if (ib < size) {
308 solver->AddBinaryClause(n.literal(ib), b->literal(ib).Negated());
309 } else {
310 // Fix the variable to false because of the given upper_bound.
311 solver->AddUnitClause(b->literal(ib).Negated());
312 }
313 }
314 for (int ia = 0; ia < a->size(); ++ia) {
315 for (int ib = 0; ib < b->size(); ++ib) {
316 if (ia + ib < size) {
317 // if x <= ia and y <= ib, then x + y <= ia + ib.
318 solver->AddTernaryClause(n.literal(ia + ib).Negated(), a->literal(ia),
319 b->literal(ib));
320 }
321 if (ia + ib + 1 < size) {
322 // if x > ia and y > ib, then x + y > ia + ib + 1.
323 solver->AddTernaryClause(n.literal(ia + ib + 1),
324 a->literal(ia).Negated(),
325 b->literal(ib).Negated());
326 } else {
327 solver->AddBinaryClause(a->literal(ia).Negated(),
328 b->literal(ib).Negated());
329 }
330 }
331 }
332 return n;
333}
334
336 const std::vector<EncodingNode*>& nodes,
337 SatSolver* solver,
338 std::deque<EncodingNode>* repository) {
339 std::deque<EncodingNode*> dq(nodes.begin(), nodes.end());
340 while (dq.size() > 1) {
341 EncodingNode* a = dq.front();
342 dq.pop_front();
343 EncodingNode* b = dq.front();
344 dq.pop_front();
345 repository->push_back(FullMerge(upper_bound, a, b, solver));
346 dq.push_back(&repository->back());
347 }
348 return dq.front();
349}
350
351namespace {
352struct SortEncodingNodePointers {
353 bool operator()(EncodingNode* a, EncodingNode* b) const { return *a < *b; }
354};
355} // namespace
356
358 Coefficient weight, const std::vector<EncodingNode*>& nodes,
359 SatSolver* solver, std::deque<EncodingNode>* repository) {
360 std::priority_queue<EncodingNode*, std::vector<EncodingNode*>,
361 SortEncodingNodePointers>
362 pq(nodes.begin(), nodes.end());
363 while (pq.size() > 2) {
364 EncodingNode* a = pq.top();
365 pq.pop();
366 EncodingNode* b = pq.top();
367 pq.pop();
368 repository->push_back(LazyMerge(a, b, solver));
369 pq.push(&repository->back());
370 }
371
372 CHECK_EQ(pq.size(), 2);
373 EncodingNode* a = pq.top();
374 pq.pop();
375 EncodingNode* b = pq.top();
376 pq.pop();
377
378 repository->push_back(EncodingNode());
379 EncodingNode* n = &repository->back();
381 solver->AddBinaryClause(a->literal(0), b->literal(0));
382 return n;
383}
384
385std::vector<EncodingNode*> CreateInitialEncodingNodes(
386 const std::vector<Literal>& literals,
387 const std::vector<Coefficient>& coeffs, Coefficient* offset,
388 std::deque<EncodingNode>* repository) {
389 CHECK_EQ(literals.size(), coeffs.size());
390 *offset = 0;
391 std::vector<EncodingNode*> nodes;
392 for (int i = 0; i < literals.size(); ++i) {
393 // We want to maximize the cost when this literal is true.
394 if (coeffs[i] > 0) {
395 repository->emplace_back(literals[i]);
396 nodes.push_back(&repository->back());
397 nodes.back()->set_weight(coeffs[i]);
398 } else {
399 repository->emplace_back(literals[i].Negated());
400 nodes.push_back(&repository->back());
401 nodes.back()->set_weight(-coeffs[i]);
402
403 // Note that this increase the offset since the coeff is negative.
404 *offset -= coeffs[i];
405 }
406 }
407 return nodes;
408}
409
410std::vector<EncodingNode*> CreateInitialEncodingNodes(
411 const LinearObjective& objective_proto, Coefficient* offset,
412 std::deque<EncodingNode>* repository) {
413 *offset = 0;
414 std::vector<EncodingNode*> nodes;
415 for (int i = 0; i < objective_proto.literals_size(); ++i) {
416 const Literal literal(objective_proto.literals(i));
417
418 // We want to maximize the cost when this literal is true.
419 if (objective_proto.coefficients(i) > 0) {
420 repository->emplace_back(literal);
421 nodes.push_back(&repository->back());
422 nodes.back()->set_weight(Coefficient(objective_proto.coefficients(i)));
423 } else {
424 repository->emplace_back(literal.Negated());
425 nodes.push_back(&repository->back());
426 nodes.back()->set_weight(Coefficient(-objective_proto.coefficients(i)));
427
428 // Note that this increase the offset since the coeff is negative.
429 *offset -= objective_proto.coefficients(i);
430 }
431 }
432 return nodes;
433}
434
435namespace {
436
437bool EncodingNodeByWeight(const EncodingNode* a, const EncodingNode* b) {
438 return a->weight() < b->weight();
439}
440
441bool EncodingNodeByDepth(const EncodingNode* a, const EncodingNode* b) {
442 return a->depth() < b->depth();
443}
444
445} // namespace
446
448 Coefficient upper_bound, Coefficient stratified_lower_bound,
449 Coefficient* lower_bound, std::vector<EncodingNode*>* nodes,
450 SatSolver* solver) {
451 // Remove the left-most variables fixed to one from each node.
452 // Also update the lower_bound. Note that Reduce() needs the solver to be
453 // at the root node in order to work.
454 solver->Backtrack(0);
455 for (EncodingNode* n : *nodes) {
456 *lower_bound += n->Reduce(*solver);
457 }
458
459 // Fix the nodes right-most variables that are above the gap.
460 // If we closed the problem, we abort and return and empty vector.
462 const Coefficient gap = upper_bound - *lower_bound;
463 if (gap < 0) return {};
464 for (EncodingNode* n : *nodes) {
465 n->ApplyWeightUpperBound(gap, solver);
466 }
467 }
468
469 // Remove the empty nodes.
470 nodes->erase(std::remove_if(nodes->begin(), nodes->end(),
471 [](EncodingNode* a) { return a->HasNoWeight(); }),
472 nodes->end());
473
474 // Sort the nodes.
475 switch (solver->parameters().max_sat_assumption_order()) {
476 case SatParameters::DEFAULT_ASSUMPTION_ORDER:
477 break;
478 case SatParameters::ORDER_ASSUMPTION_BY_DEPTH:
479 std::sort(nodes->begin(), nodes->end(), EncodingNodeByDepth);
480 break;
481 case SatParameters::ORDER_ASSUMPTION_BY_WEIGHT:
482 std::sort(nodes->begin(), nodes->end(), EncodingNodeByWeight);
483 break;
484 }
485 if (solver->parameters().max_sat_reverse_assumption_order()) {
486 // TODO(user): with DEFAULT_ASSUMPTION_ORDER, this will lead to a somewhat
487 // weird behavior, since we will reverse the nodes at each iteration...
488 std::reverse(nodes->begin(), nodes->end());
489 }
490
491 // Extract the assumptions from the nodes.
492 std::vector<Literal> assumptions;
493 for (EncodingNode* n : *nodes) {
494 if (n->weight() >= stratified_lower_bound) {
495 assumptions.push_back(n->GetAssumption(solver));
496 }
497 }
498 return assumptions;
499}
500
501Coefficient ComputeCoreMinWeight(const std::vector<EncodingNode*>& nodes,
502 const std::vector<Literal>& core) {
503 Coefficient min_weight = kCoefficientMax;
504 int index = 0;
505 for (int i = 0; i < core.size(); ++i) {
506 for (; index < nodes.size() &&
507 nodes[index]->GetAssumption(nullptr) != core[i];
508 ++index) {
509 }
510 CHECK_LT(index, nodes.size());
511 min_weight = std::min(min_weight, nodes[index]->weight());
512 }
513 return min_weight;
514}
515
516Coefficient MaxNodeWeightSmallerThan(const std::vector<EncodingNode*>& nodes,
518 Coefficient result(0);
519 for (EncodingNode* n : nodes) {
520 CHECK_GT(n->weight(), 0);
521 if (n->weight() < upper_bound) {
522 result = std::max(result, n->weight());
523 }
524 }
525 return result;
526}
527
528bool ProcessCore(const std::vector<Literal>& core, Coefficient min_weight,
529 std::deque<EncodingNode>* repository,
530 std::vector<EncodingNode*>* nodes, SatSolver* solver) {
531 // Backtrack to be able to add new constraints.
532 solver->ResetToLevelZero();
533 if (core.size() == 1) {
534 return solver->AddUnitClause(core[0].Negated());
535 }
536
537 // Remove from nodes the EncodingNode in the core, merge them, and add the
538 // resulting EncodingNode at the back.
539 int index = 0;
540 int new_node_index = 0;
541 std::vector<EncodingNode*> to_merge;
542 for (int i = 0; i < core.size(); ++i) {
543 // Since the nodes appear in order in the core, we can find the
544 // relevant "objective" variable efficiently with a simple linear scan
545 // in the nodes vector (done with index).
546 for (; (*nodes)[index]->GetAssumption(nullptr) != core[i]; ++index) {
547 CHECK_LT(index, nodes->size());
548 (*nodes)[new_node_index] = (*nodes)[index];
549 ++new_node_index;
550 }
551 CHECK_LT(index, nodes->size());
552 to_merge.push_back((*nodes)[index]);
553
554 // Special case if the weight > min_weight. we keep it, but reduce its
555 // cost. This is the same "trick" as in WPM1 used to deal with weight.
556 // We basically split a clause with a larger weight in two identical
557 // clauses, one with weight min_weight that will be merged and one with
558 // the remaining weight.
559 if ((*nodes)[index]->weight() > min_weight) {
560 (*nodes)[index]->set_weight((*nodes)[index]->weight() - min_weight);
561 (*nodes)[new_node_index] = (*nodes)[index];
562 ++new_node_index;
563 }
564 ++index;
565 }
566 for (; index < nodes->size(); ++index) {
567 (*nodes)[new_node_index] = (*nodes)[index];
568 ++new_node_index;
569 }
570 nodes->resize(new_node_index);
571 nodes->push_back(LazyMergeAllNodeWithPQAndIncreaseLb(min_weight, to_merge,
572 solver, repository));
573 return !solver->IsModelUnsat();
574}
575
576bool ProcessCoreWithAlternativeEncoding(const std::vector<Literal>& core,
577 Coefficient min_weight,
578 std::deque<EncodingNode>* repository,
579 std::vector<EncodingNode*>* nodes,
580 SatSolver* solver) {
581 // Backtrack to be able to add new constraints.
582 solver->ResetToLevelZero();
583
584 if (core.size() == 1) {
585 return solver->AddUnitClause(core[0].Negated());
586 }
587
588 std::vector<EncodingNode*> new_nodes;
589 std::vector<EncodingNode*> to_merge;
590
591 // Preconditions.
592 for (EncodingNode* n : *nodes) {
593 CHECK_GT(n->size(), 0);
594 }
595
596 // Remove from nodes the EncodingNode in the core, merge them, and add the
597 // resulting EncodingNode at the back.
598 int index = 0;
599 for (int i = 0; i < core.size(); ++i) {
600 // Since the nodes appear in order in the core, we can find the
601 // relevant "objective" variable efficiently with a simple linear scan
602 // in the nodes vector (done with index).
603 CHECK_LT(index, nodes->size());
604 for (; (*nodes)[index]->GetAssumption(nullptr) != core[i]; ++index) {
605 CHECK_LT(index, nodes->size());
606 new_nodes.push_back((*nodes)[index]);
607 }
608 CHECK_LT(index, nodes->size());
609
610 // We have a node from the core.
611 // We will distinguish its first literal.
612 EncodingNode* n = (*nodes)[index];
613 const Literal lit = n->GetAssumption(nullptr).Negated();
614 n->IncreaseWeightLb();
615 ++index;
616 CHECK_GT(n->size(), 0);
617
618 // TODO(user): For node with same depth, the sorting order is not the same
619 // if we create a new node or reuse one. Experiment what is the best order.
620 repository->emplace_back(lit);
621 EncodingNode* new_bool_node = &repository->back();
622 new_bool_node->set_depth(n->depth());
623 CHECK_GT(new_bool_node->size(), 0);
624 to_merge.push_back(new_bool_node);
625 if (n->weight() > min_weight) {
626 new_bool_node->set_weight(n->weight() - min_weight);
627 new_nodes.push_back(new_bool_node);
628 }
629
630 if (!n->HasNoWeight()) {
631 new_nodes.push_back(n);
632 }
633 }
634
635 for (; index < nodes->size(); ++index) {
636 new_nodes.push_back((*nodes)[index]);
637 }
638
639 new_nodes.push_back(LazyMergeAllNodeWithPQAndIncreaseLb(min_weight, to_merge,
640 solver, repository));
641 *nodes = new_nodes;
642 return !solver->IsModelUnsat();
643}
644
645} // namespace sat
646} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_LT(val1, val2)
Definition: base/logging.h:706
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
#define CHECK_GE(val1, val2)
Definition: base/logging.h:707
#define CHECK_GT(val1, val2)
Definition: base/logging.h:708
#define CHECK_NE(val1, val2)
Definition: base/logging.h:704
void InitializeLazyCoreNode(Coefficient weight, EncodingNode *a, EncodingNode *b)
Definition: encoding.cc:75
Literal GetAssumption(SatSolver *solver)
Definition: encoding.cc:134
bool IncreaseCurrentUB(SatSolver *solver)
Definition: encoding.cc:90
void ApplyWeightUpperBound(Coefficient gap, SatSolver *solver)
Definition: encoding.cc:121
Coefficient Reduce(const SatSolver &solver)
Definition: encoding.cc:101
EncodingNode * child_b() const
Definition: encoding.h:132
void InitializeLazyNode(EncodingNode *a, EncodingNode *b, SatSolver *solver)
Definition: encoding.cc:59
void InitializeFullNode(int n, EncodingNode *a, EncodingNode *b, SatSolver *solver)
Definition: encoding.cc:39
Literal literal(int i) const
Definition: encoding.h:84
std::string DebugString(const VariablesAssignment &assignment) const
Definition: encoding.cc:154
EncodingNode * child_a() const
Definition: encoding.h:131
Literal GreaterThan(int i) const
Definition: encoding.h:80
void SetNumVariables(int num_variables)
Definition: sat_solver.cc:85
bool AddTernaryClause(Literal a, Literal b, Literal c)
Definition: sat_solver.cc:193
const SatParameters & parameters() const
Definition: sat_solver.cc:131
const VariablesAssignment & Assignment() const
Definition: sat_solver.h:378
bool AddBinaryClause(Literal a, Literal b)
Definition: sat_solver.cc:189
void Backtrack(int target_level)
Definition: sat_solver.cc:991
bool AddUnitClause(Literal true_literal)
Definition: sat_solver.cc:185
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:153
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:150
int64_t b
int64_t a
int64_t value
double upper_bound
double lower_bound
int index
std::tuple< int64_t, int64_t, const double > Coefficient
Coefficient ComputeCoreMinWeight(const std::vector< EncodingNode * > &nodes, const std::vector< Literal > &core)
Definition: encoding.cc:501
EncodingNode * MergeAllNodesWithDeque(Coefficient upper_bound, const std::vector< EncodingNode * > &nodes, SatSolver *solver, std::deque< EncodingNode > *repository)
Definition: encoding.cc:335
EncodingNode * LazyMergeAllNodeWithPQAndIncreaseLb(Coefficient weight, const std::vector< EncodingNode * > &nodes, SatSolver *solver, std::deque< EncodingNode > *repository)
Definition: encoding.cc:357
std::vector< Literal > ReduceNodesAndExtractAssumptions(Coefficient upper_bound, Coefficient stratified_lower_bound, Coefficient *lower_bound, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Definition: encoding.cc:447
void IncreaseNodeSize(EncodingNode *node, SatSolver *solver)
Definition: encoding.cc:189
EncodingNode LazyMerge(EncodingNode *a, EncodingNode *b, SatSolver *solver)
Definition: encoding.cc:179
EncodingNode FullMerge(Coefficient upper_bound, EncodingNode *a, EncodingNode *b, SatSolver *solver)
Definition: encoding.cc:284
bool ProcessCore(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Definition: encoding.cc:528
Coefficient MaxNodeWeightSmallerThan(const std::vector< EncodingNode * > &nodes, Coefficient upper_bound)
Definition: encoding.cc:516
bool ProcessCoreWithAlternativeEncoding(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Definition: encoding.cc:576
std::vector< EncodingNode * > CreateInitialEncodingNodes(const std::vector< Literal > &literals, const std::vector< Coefficient > &coeffs, Coefficient *offset, std::deque< EncodingNode > *repository)
Definition: encoding.cc:385
const Coefficient kCoefficientMax(std::numeric_limits< Coefficient::ValueType >::max())
Collection of objects used to extend the Constraint Solver library.
Literal literal
Definition: optimization.cc:89
int64_t weight
Definition: pack.cc:510
int nodes