diff --git a/src/algorithms/knapsack_solver.cc b/src/algorithms/knapsack_solver.cc index 91a36b21f5..b09697aa5d 100644 --- a/src/algorithms/knapsack_solver.cc +++ b/src/algorithms/knapsack_solver.cc @@ -31,7 +31,7 @@ const int kMasterPropagatorId = 0; const int kMaxNumberOfBruteForceItems = 30; const int kMaxNumberOf64Items = 64; -// Comparator used to std::sort item in decreasing efficiency order +// Comparator used to sort item in decreasing efficiency order // (see KnapsackCapacityPropagator). struct CompareKnapsackItemsInDecreasingEfficiencyOrder { explicit CompareKnapsackItemsInDecreasingEfficiencyOrder(int64 _profit_max) @@ -44,7 +44,7 @@ struct CompareKnapsackItemsInDecreasingEfficiencyOrder { const int64 profit_max; }; -// Comparator used to std::sort search nodes in the priority queue in order +// Comparator used to sort search nodes in the priority queue in order // to pop first the node with the highest profit upper bound // (see KnapsackSearchNode). When two nodes have the same upper bound, we // prefer the one with the highest current profit, ie. usually the one closer @@ -727,7 +727,7 @@ class Knapsack64ItemsSolver : public BaseKnapsackSolver { int64 rejected_items_weight_; }; -// Comparator used to std::sort item in decreasing efficiency order +// Comparator used to sort item in decreasing efficiency order bool CompareKnapsackItemWithEfficiencyInDecreasingEfficiencyOrder( const KnapsackItemWithEfficiency& item1, const KnapsackItemWithEfficiency& item2) { diff --git a/src/algorithms/knapsack_solver.h b/src/algorithms/knapsack_solver.h index e8ead78b4c..9bb9d0be25 100644 --- a/src/algorithms/knapsack_solver.h +++ b/src/algorithms/knapsack_solver.h @@ -262,7 +262,7 @@ class KnapsackSearchNode { const KnapsackSearchNode* const parent_; KnapsackAssignment assignment_; - // 'current_profit' and 'profit_upper_bound' fields are used to std::sort search + // 'current_profit' and 'profit_upper_bound' fields are used to sort search // nodes using a priority queue. That allows to pop the node with the best // upper bound, and more importantly to stop the search when optimality is // proved. @@ -435,7 +435,7 @@ class KnapsackCapacityPropagator : public KnapsackPropagator { virtual int GetNextItemId() const { return break_item_id_; } protected: - // Initializes KnapsackCapacityPropagator (eg. std::sort items in decreasing + // Initializes KnapsackCapacityPropagator (eg. sort items in decreasing // order). virtual void InitPropagator(); // Updates internal data structure incrementally (ie. 'consumed_capacity_') diff --git a/src/base/python-swig.cc b/src/base/python-swig.cc index deffd451e6..27d272edd3 100644 --- a/src/base/python-swig.cc +++ b/src/base/python-swig.cc @@ -140,8 +140,8 @@ template <> bool PyObjAs(PyObject * py, unsigned long long * c) { // NOLINT { if (!PyLong_Check(py)) return false; // Not a Python long. i = PyLong_AsUnsignedLongLong(py); - if (i == (unsigned long long) - 1 && PyErr_Occurred()) - return false; // NOLINT + if (i == (unsigned long long) - 1 && PyErr_Occurred()) // NOLINT + return false; } if (c) *c = i; return true; @@ -251,8 +251,7 @@ bool vector_input_wrap_helper(PyObject * seq, std::vector * out, } typename vector_pusher::ptr elem; while ((item = PyIter_Next(it))) { - if (SWIG_ConvertPtr(item, (void**)&elem, swig_Tp_type, 0) == - -1) { // NOLINT + if (SWIG_ConvertPtr(item, (void**)&elem, swig_Tp_type, 0) == -1) { // NOLINT Py_DECREF(it); it = PyObject_Repr(item); Py_DECREF(item); @@ -323,8 +322,8 @@ static PyObject* vector_output_wrap_helper(const std::vector * vec, return vector_output_helper(vec, converter); #else // Lambda version auto converter = [](const T * x) { - return SWIG_NewPointerObj((void*)x, swig_Tp_type, newobj); - } // NOLINT + return SWIG_NewPointerObj((void*)x, swig_Tp_type, newobj); // NOLINT + } return list_output_helper(vec, converter); #endif } diff --git a/src/constraint_solver/alldiff_cst.cc b/src/constraint_solver/alldiff_cst.cc index 387b812427..ad3532c9a0 100644 --- a/src/constraint_solver/alldiff_cst.cc +++ b/src/constraint_solver/alldiff_cst.cc @@ -294,17 +294,17 @@ class RangeBipartiteMatching { return modified; } - // TODO(user) : use better std::sort, use bounding boxes of modifications to + // TODO(user) : use better sort, use bounding boxes of modifications to // improve the sorting (only modified vars). - // This method is used by the STL std::sort. + // This method is used by the STL sort. struct CompareIntervalMin { bool operator()(const Interval* i1, const Interval* i2) { return (i1->min < i2->min); } }; - // This method is used by the STL std::sort. + // This method is used by the STL sort. struct CompareIntervalMax { bool operator()(const Interval* i1, const Interval* i2) { return (i1->max < i2->max); diff --git a/src/constraint_solver/constraint_solver.swig b/src/constraint_solver/constraint_solver.swig index f8dd7d02ab..76e9c840dd 100644 --- a/src/constraint_solver/constraint_solver.swig +++ b/src/constraint_solver/constraint_solver.swig @@ -731,7 +731,6 @@ static void SetPythonFlags(bool trace_propagation, IntExpr* __mod__(IntExpr* e) { return self->solver()->MakeModulo(self, e); } - IntExpr* __neg__() { return self->solver()->MakeOpposite(self); } @@ -1186,7 +1185,6 @@ class LocalSearchPhaseParameters { #endif // SWIGJAVA #if defined(SWIGCSHARP) - %module(directors="1", allprotected="1") operations_research; %feature("director") Action; %feature("director") BaseLNS; @@ -1829,7 +1827,6 @@ namespace operations_research { } return array; } - public void NewSearch(DecisionBuilder db) { pinned_decision_builder_ = db; pinned_search_monitors_.Clear(); @@ -1905,7 +1902,6 @@ namespace operations_research { return index; } } - %extend SequenceVarLocalSearchOperator { int SequenceSize(int index) const { return self->Sequence(index).size(); @@ -1940,68 +1936,6 @@ namespace operations_research { return result; } %} - -// Protect from failure -#define PREPROTECT \ - FailureProtect protect;\ - Closure* const intercept = \ - NewCallback<>(&protect, &FailureProtect::JumpBack);\ - solver->set_fail_intercept(intercept);\ - if (setjmp(protect.exception_buffer) == 0) { - -#define POSTPROTECT \ - solver->clear_fail_intercept();\ - delete intercept;\ - } else {\ - solver->clear_fail_intercept();\ - SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, "fail");\ - return $null;\ - } - -%exception IntExpr::SetValue(int64 v) { - operations_research::Solver* const solver = arg1->solver(); - PREPROTECT - $action - POSTPROTECT -} -%exception IntExpr::SetMin(int64 v) { - operations_research::Solver* const solver = arg1->solver(); - PREPROTECT - $action - POSTPROTECT -} -%exception IntExpr::SetMax(int64 v) { - operations_research::Solver* const solver = arg1->solver(); - PREPROTECT - $action - POSTPROTECT -} -%exception IntExpr::SetRange(int64 mi, int64 ma) { - operations_research::Solver* const solver = arg1->solver(); - PREPROTECT - $action - POSTPROTECT -} -%exception IntVar::RemoveValue(int64 v) { - operations_research::Solver* const solver = arg1->solver(); - PREPROTECT - $action - POSTPROTECT -} -%exception Solver::AddConstraint(Constraint* const ct) { - operations_research::Solver* const solver = arg1; - PREPROTECT - $action - POSTPROTECT -} -%exception Solver::Fail() { - operations_research::Solver* const solver = arg1; - PREPROTECT - $action - POSTPROTECT -} -#undef PREPROTECT -#undef POSTPROTECT } // namespace operations_research namespace operations_research { diff --git a/src/constraint_solver/constraints.cc b/src/constraint_solver/constraints.cc index 1d1517092e..e11b01d53b 100644 --- a/src/constraint_solver/constraints.cc +++ b/src/constraint_solver/constraints.cc @@ -595,12 +595,10 @@ string NoCycle::DebugString() const { class Circuit : public Constraint { public: - static const int kRoot; - Circuit(Solver* const s, const std::vector& nexts) + Circuit(Solver* const s, const std::vector& nexts, bool complete) : Constraint(s), nexts_(nexts), size_(nexts_.size()), - processed_(0), starts_(size_, -1), ends_(size_, -1), lengths_(size_, 1), @@ -609,7 +607,10 @@ class Circuit : public Constraint { inbound_support_(size_, -1), temp_support_(size_, -1), inbound_demon_(nullptr), - outbound_demon_(nullptr) { + outbound_demon_(nullptr), + root_(-1), + num_inactives_(0), + complete_(complete) { for (int i = 0; i < size_; ++i) { domains_[i] = nexts_[i]->MakeDomainIterator(true); } @@ -625,24 +626,32 @@ class Circuit : public Constraint { solver(), this, &Circuit::CheckReachabilityFromRoot, "CheckReachabilityFromRoot"); for (int i = 0; i < size_; ++i) { - Demon* const bound_demon = MakeConstraintDemon1( - solver(), this, &Circuit::NextBound, "NextBound", i); - nexts_[i]->WhenBound(bound_demon); - Demon* const domain_demon = MakeConstraintDemon1( - solver(), this, &Circuit::NextDomain, "NextDomain", i); - nexts_[i]->WhenDomain(domain_demon); + if (!nexts_[i]->Bound()) { + Demon* const bound_demon = MakeConstraintDemon1( + solver(), this, &Circuit::NextBound, "NextBound", i); + nexts_[i]->WhenBound(bound_demon); + Demon* const domain_demon = MakeConstraintDemon1( + solver(), this, &Circuit::NextDomain, "NextDomain", i); + nexts_[i]->WhenDomain(domain_demon); + } } solver()->AddConstraint(solver()->MakeAllDifferent(nexts_)); } virtual void InitialPropagate() { + if (complete_) { + root_.SetValue(solver(), 0); + } for (int i = 0; i < size_; ++i) { nexts_[i]->SetRange(0, size_ - 1); - nexts_[i]->RemoveValue(i); + if (complete_) { + nexts_[i]->RemoveValue(i); + } } for (int i = 0; i < size_; ++i) { starts_.SetValue(solver(), i, i); ends_.SetValue(solver(), i, i); + lengths_.SetValue(solver(), i, 1); } for (int i = 0; i < size_; ++i) { if (nexts_[i]->Bound()) { @@ -654,198 +663,7 @@ class Circuit : public Constraint { } virtual string DebugString() const { - return StringPrintf("Circuit(%s)", JoinDebugStringPtr(nexts_, " ").c_str()); - } - - void Accept(ModelVisitor* const visitor) const { - visitor->BeginVisitConstraint(ModelVisitor::kCircuit, this); - visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument, - nexts_); - visitor->VisitIntegerArgument(ModelVisitor::kCompleteArgument, 1); - visitor->EndVisitConstraint(ModelVisitor::kCircuit, this); - } - - private: - // When a variable is bound, we update all the bounds of the 2 newly - // connected chains. - void NextBound(int index) { - Solver* const s = solver(); - const int destination = nexts_[index]->Value(); - const int new_end = ends_.Value(destination); - const int new_start = starts_.Value(index); - starts_.SetValue(s, new_end, new_start); - ends_.SetValue(s, new_start, new_end); - lengths_.SetValue(s, new_start, - lengths_.Value(new_start) + lengths_.Value(destination)); - // If a chain is not complete, it cannot loop onto itself. - if (lengths_.Value(new_start) < size_ - 1) { - nexts_[new_end]->RemoveValue(new_start); - } - } - - // When a variable is modified, we check if the support for the - // inbound and outbound spanning tree are still valid. If no, we - // enqueue the low priority demons to recompute them. - void NextDomain(int index) { - if (!nexts_[index]->Contains(outbound_support_[index])) { - EnqueueDelayedDemon(outbound_demon_); - } - if (!nexts_[index]->Contains(inbound_support_[index])) { - EnqueueDelayedDemon(inbound_demon_); - } - } - - // Builds a spanning tree based from root to all nodes and stores - // the result in outbound_support_. - void CheckReachabilityFromRoot() { - reached_.assign(size_, false); - reached_[kRoot] = true; - int reached_count = 1; - processed_ = 0; - insertion_queue_.clear(); - insertion_queue_.push_back(kRoot); - while (processed_ < insertion_queue_.size() && reached_count < size_) { - const int candidate = insertion_queue_[processed_++]; - IntVarIterator* const domain = domains_[candidate]; - for (domain->Init(); domain->Ok(); domain->Next()) { - const int64 after = domain->Value(); - if (!reached_[after]) { - reached_[after] = true; - insertion_queue_.push_back(after); - temp_support_[candidate] = after; - reached_count++; - } - } - } - if (insertion_queue_.size() < size_) { - solver()->Fail(); - } else { - outbound_support_.swap(temp_support_); - } - } - - // Builds a spanning tree going from all nodes to root and stores - // the result in inbound_support_. - void CheckReachabilityToRoot() { - insertion_queue_.clear(); - insertion_queue_.push_back(kRoot); - temp_support_[kRoot] = nexts_[kRoot]->Min(); - processed_ = 0; - to_visit_.clear(); - for (int i = 1; i < size_; ++i) { - to_visit_.push_back(i); - } - while (processed_ < insertion_queue_.size() && - insertion_queue_.size() < size_) { - const int inserted = insertion_queue_[processed_++]; - std::vector rejected; - for (int index = 0; index < to_visit_.size(); ++index) { - const int candidate = to_visit_[index]; - if (nexts_[candidate]->Contains(inserted)) { - insertion_queue_.push_back(candidate); - temp_support_[candidate] = inserted; - } else { - rejected.push_back(candidate); - } - } - to_visit_.clear(); - to_visit_.swap(rejected); - } - if (insertion_queue_.size() < size_) { - solver()->Fail(); - } else { - temp_support_.swap(inbound_support_); - } - } - - std::vector nexts_; - const int size_; - // Utility variables to implement the traversal in the graph. - std::vector insertion_queue_; - std::vector to_visit_; - std::vector reached_; - int processed_; - // Reversible starts and ends of the chains vars[i] belongs to. - RevArray starts_; - RevArray ends_; - RevArray lengths_; - // We cache iterators. - std::vector domains_; - // We store the links in the inbound and outbound flows to launch - // recomputation only if those links are no longer there. - std::vector outbound_support_; - std::vector inbound_support_; - std::vector temp_support_; - // Low priority demons. - Demon* inbound_demon_; - Demon* outbound_demon_; -}; - -const int Circuit::kRoot = 0; - -// ----- Sub Circuit constraint ----- - -class SubCircuit : public Constraint { - public: - SubCircuit(Solver* const s, const std::vector& nexts) - : Constraint(s), - nexts_(nexts), - size_(nexts_.size()), - processed_(0), - starts_(size_, -1), - ends_(size_, -1), - lengths_(size_, 1), - domains_(size_), - outbound_support_(size_, -1), - inbound_support_(size_, -1), - temp_support_(size_, -1), - inbound_demon_(nullptr), - outbound_demon_(nullptr), - root_(-1) { - for (int i = 0; i < size_; ++i) { - domains_[i] = nexts_[i]->MakeDomainIterator(true); - } - } - - virtual ~SubCircuit() {} - - virtual void Post() { - inbound_demon_ = MakeDelayedConstraintDemon0( - solver(), this, &SubCircuit::CheckReachabilityToRoot, - "CheckReachabilityToRoot"); - outbound_demon_ = MakeDelayedConstraintDemon0( - solver(), this, &SubCircuit::CheckReachabilityFromRoot, - "CheckReachabilityFromRoot"); - for (int i = 0; i < size_; ++i) { - Demon* const bound_demon = MakeConstraintDemon1( - solver(), this, &SubCircuit::NextBound, "NextBound", i); - nexts_[i]->WhenBound(bound_demon); - Demon* const domain_demon = MakeConstraintDemon1( - solver(), this, &SubCircuit::NextDomain, "NextDomain", i); - nexts_[i]->WhenDomain(domain_demon); - } - solver()->AddConstraint(solver()->MakeAllDifferent(nexts_)); - } - - virtual void InitialPropagate() { - for (int i = 0; i < size_; ++i) { - nexts_[i]->SetRange(0, size_ - 1); - } - for (int i = 0; i < size_; ++i) { - starts_.SetValue(solver(), i, i); - ends_.SetValue(solver(), i, i); - } - for (int i = 0; i < size_; ++i) { - if (nexts_[i]->Bound()) { - NextBound(i); - } - } - CheckReachabilityFromRoot(); - CheckReachabilityToRoot(); - } - - virtual string DebugString() const { - return StringPrintf("SubCircuit(%s)", + return StringPrintf("%sCircuit(%s)", complete_ ? "" : "Sub", JoinDebugStringPtr(nexts_, " ").c_str()); } @@ -853,7 +671,7 @@ class SubCircuit : public Constraint { visitor->BeginVisitConstraint(ModelVisitor::kCircuit, this); visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument, nexts_); - visitor->VisitIntegerArgument(ModelVisitor::kCompleteArgument, 0); + visitor->VisitIntegerArgument(ModelVisitor::kCompleteArgument, complete_); visitor->EndVisitConstraint(ModelVisitor::kCircuit, this); } @@ -862,14 +680,6 @@ class SubCircuit : public Constraint { return nexts_[index]->Bound() && nexts_[index]->Min() == index; } - int NumberOfInactiveNodes() const { - int inactive = 0; - for (int i = 0; i < size_; ++i) { - inactive += Inactive(i); - } - return inactive; - } - void NextBound(int index) { Solver* const s = solver(); const int destination = nexts_[index]->Value(); @@ -882,17 +692,18 @@ class SubCircuit : public Constraint { const int new_start = starts_.Value(index); starts_.SetValue(s, new_end, new_start); ends_.SetValue(s, new_start, new_end); - lengths_.SetValue(s, new_start, - lengths_.Value(new_start) + lengths_.Value(destination)); - const int inactive = NumberOfInactiveNodes(); - if (lengths_.Value(new_start) < size_ - 1 - inactive) { - nexts_[new_end]->RemoveValue(new_start); - } - } else if (root != -1) { - const int inactive = NumberOfInactiveNodes(); - if (lengths_.Value(root) < size_ - 1 - inactive) { - nexts_[ends_[root]]->RemoveValue(root); + lengths_.SetValue(s, new_start, lengths_.Value(new_start) + + lengths_.Value(destination)); + if (complete_) { + if (lengths_.Value(new_start) < size_ - 1 - num_inactives_.Value()) { + nexts_[new_end]->RemoveValue(new_start); + } + } else { + // You are creating the only path. Nexts can no longer loop upon itself. + nexts_[destination]->RemoveValue(destination); } + } else { + num_inactives_.Incr(solver()); } } @@ -908,40 +719,54 @@ class SubCircuit : public Constraint { } } + void TryInsertReached(int candidate, int64 after) { + if (!reached_[after]) { + reached_[after] = true; + insertion_queue_.push_back(after); + temp_support_[candidate] = after; + } + } + void CheckReachabilityFromRoot() { if (root_.Value() == -1) { // Root is not yet defined. Nothing to deduce. return; } - const int inactive = NumberOfInactiveNodes(); - // Assign temp_support_ to a dummy value. temp_support_.assign(size_, -1); // Clear the spanning tree. - processed_ = 0; + int processed = 0; reached_.assign(size_, false); - int reached_count = 0; insertion_queue_.clear(); // Add the root node. const int root_value = root_.Value(); reached_[root_value] = true; insertion_queue_.push_back(root_value); // Compute reachable nodes. - while (processed_ < insertion_queue_.size() && - reached_count + inactive < size_) { - const int candidate = insertion_queue_[processed_++]; - IntVarIterator* const domain = domains_[candidate]; - for (domain->Init(); domain->Ok(); domain->Next()) { - const int64 after = domain->Value(); - if (!reached_[after]) { - reached_[after] = true; - insertion_queue_.push_back(after); - reached_count++; - temp_support_[candidate] = after; + while (processed < insertion_queue_.size() && + insertion_queue_.size() + num_inactives_.Value() < size_) { + const int candidate = insertion_queue_[processed++]; + IntVar* const var = nexts_[candidate]; + switch (var->Size()) { + case 1: { + TryInsertReached(candidate, var->Min()); + break; + } + case 2: { + TryInsertReached(candidate, var->Min()); + TryInsertReached(candidate, var->Max()); + break; + } + default: { + IntVarIterator* const domain = domains_[candidate]; + for (domain->Init(); domain->Ok(); domain->Next()) { + TryInsertReached(candidate, domain->Value()); + } } } } - // All non reachable nodes should point to themselves. + // All non reachable nodes should point to themselves in the incomplete + // case for (int i = 0; i < size_; ++i) { if (!reached_[i]) { nexts_[i]->SetValue(i); @@ -952,24 +777,25 @@ class SubCircuit : public Constraint { } void CheckReachabilityToRoot() { + // TODO(user): Improve with prev_ data structure. if (root_.Value() == -1) { return; } - const int inactive = NumberOfInactiveNodes(); insertion_queue_.clear(); insertion_queue_.push_back(root_.Value()); temp_support_[root_.Value()] = nexts_[root_.Value()]->Min(); - processed_ = 0; + int processed = 0; to_visit_.clear(); for (int i = 0; i < size_; ++i) { if (!Inactive(i) && i != root_.Value()) { to_visit_.push_back(i); } } - while (processed_ < insertion_queue_.size() && + const int inactive = num_inactives_.Value(); + while (processed < insertion_queue_.size() && insertion_queue_.size() + inactive < size_) { - const int inserted = insertion_queue_[processed_++]; + const int inserted = insertion_queue_[processed++]; std::vector rejected; for (int index = 0; index < to_visit_.size(); ++index) { const int candidate = to_visit_[index]; @@ -980,7 +806,6 @@ class SubCircuit : public Constraint { rejected.push_back(candidate); } } - to_visit_.clear(); to_visit_.swap(rejected); } for (int i = 0; i < to_visit_.size(); ++i) { @@ -995,7 +820,6 @@ class SubCircuit : public Constraint { std::vector insertion_queue_; std::vector to_visit_; std::vector reached_; - int processed_; RevArray starts_; RevArray ends_; RevArray lengths_; @@ -1006,6 +830,8 @@ class SubCircuit : public Constraint { Demon* inbound_demon_; Demon* outbound_demon_; Rev root_; + NumericalRev num_inactives_; + const bool complete_; }; // ----- Misc ----- @@ -1032,13 +858,13 @@ Constraint* Solver::MakeNoCycle(const std::vector& nexts, return MakeNoCycle(nexts, active, sink_handler, true); } -// TODO(user): Merge NoCycle and Circuit/SubCircuit. +// TODO(user): Merge NoCycle and Circuit. Constraint* Solver::MakeCircuit(const std::vector& nexts) { - return RevAlloc(new Circuit(this, nexts)); + return RevAlloc(new Circuit(this, nexts, true)); } Constraint* Solver::MakeSubCircuit(const std::vector& nexts) { - return RevAlloc(new SubCircuit(this, nexts)); + return RevAlloc(new Circuit(this, nexts, false)); } // ----- Path cumul constraints ----- diff --git a/src/constraint_solver/count_cst.cc b/src/constraint_solver/count_cst.cc index 421b925fc2..a5da23bdd2 100644 --- a/src/constraint_solver/count_cst.cc +++ b/src/constraint_solver/count_cst.cc @@ -884,7 +884,7 @@ Constraint* Solver::MakeDistribute(const std::vector& vars, CHECK_EQ(this, (*it)->solver()); } - // TODO(user) : we can std::sort values (and cards) before doing the test. + // TODO(user) : we can sort values (and cards) before doing the test. bool fast = true; for (int i = 0; i < values.size(); ++i) { if (values[i] != i) { diff --git a/src/constraint_solver/diffn.cc b/src/constraint_solver/diffn.cc index 7e7909395d..4303e43d78 100644 --- a/src/constraint_solver/diffn.cc +++ b/src/constraint_solver/diffn.cc @@ -191,7 +191,7 @@ class Diffn : public Constraint { int64 area_min_y = y_[box]->Min(); int64 area_max_y = y_[box]->Max() + dy_[box]->Max(); int64 sum_of_areas = dx_[box]->Min() * dy_[box]->Min(); - // TODO(user): Is there a better order, maybe std::sort by distance + // TODO(user): Is there a better order, maybe sort by distance // with the current box. for (int i = 0; i < neighbors_.size(); ++i) { const int other = neighbors_[i]; diff --git a/src/constraint_solver/expr_array.cc b/src/constraint_solver/expr_array.cc index bdfe464e21..3ab169a0bf 100644 --- a/src/constraint_solver/expr_array.cc +++ b/src/constraint_solver/expr_array.cc @@ -1478,7 +1478,7 @@ struct Container { bool operator<(const Container& c) const { return (coef < c.coef); } }; -// This method will std::sort both vars and coefficients in increasing +// This method will sort both vars and coefficients in increasing // coefficient order. Vars with null coefficients will be // removed. Bound vars will be collected and the sum of the // corresponding products (when the var is bound to 1) is returned by diff --git a/src/constraint_solver/resource.cc b/src/constraint_solver/resource.cc index 64afc45384..ac5797d16b 100644 --- a/src/constraint_solver/resource.cc +++ b/src/constraint_solver/resource.cc @@ -480,7 +480,7 @@ class EdgeFinderAndDetectablePrecedences { // --- All the following member variables are essentially used as local ones: // no invariant is maintained about them, except for the fact that the vectors // always contains all the considered intervals, so any function that wants to - // use them must first std::sort them in the right order. + // use them must first sort them in the right order. // All of these vectors store the same set of objects. Therefore, at // destruction time, STLDeleteElements should be called on only one of them. diff --git a/src/constraint_solver/routing.h b/src/constraint_solver/routing.h index 75b021aa7c..aa69091272 100644 --- a/src/constraint_solver/routing.h +++ b/src/constraint_solver/routing.h @@ -646,7 +646,7 @@ class RoutingModel { } // Gets/sets the evaluator used when the first solution heuristic is set to // ROUTING_EVALUATOR_STRATEGY (variant of ROUTING_PATH_CHEAPEST_ARC using -// 'evaluator' to std::sort node segments). +// 'evaluator' to sort node segments). #ifndef SWIG Solver::IndexEvaluator2* first_solution_evaluator() const { return first_solution_evaluator_.get(); diff --git a/src/constraint_solver/routing_search.cc b/src/constraint_solver/routing_search.cc index 6097f3c240..a6809f935a 100644 --- a/src/constraint_solver/routing_search.cc +++ b/src/constraint_solver/routing_search.cc @@ -859,25 +859,44 @@ RoutingFilteredDecisionBuilder::RoutingFilteredDecisionBuilder( model_(model) {} bool RoutingFilteredDecisionBuilder::InitializeRoutes() { - // TODO(user): Handle chains to end nodes properly. - start_chain_ends_.clear(); - start_chain_ends_.reserve(model()->vehicles()); - for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) { - int64 start = model()->Start(vehicle); - const int64 end = model()->End(vehicle); - while (Contains(start)) { - start = Value(start); - if (model()->IsEnd(start)) { - if (start != end) { - return false; - } - break; + // Find the chains of nodes (when nodes have their "Next" value bound in the + // current solution, it forms a link in a chain). Eventually, starts[end] + // will contain the index of the first node of the chain ending at node 'end' + // and ends[start] will be the last node of the chain starting at node + // 'start'. Values of starts[node] and ends[node] for other nodes is used + // for intermediary computations and do not necessarily reflect actual chain + // starts and ends. + std::vector starts(Size() + model()->vehicles(), -1); + std::vector ends(Size() + model()->vehicles(), -1); + for (int node = 0; node < Size() + model()->vehicles(); ++node) { + // Each node starts as a singleton chain. + starts[node] = node; + ends[node] = node; + } + std::vector touched(Size(), false); + for (int node = 0; node < Size(); ++node) { + int current = node; + while (!model()->IsEnd(current) && !touched[current]) { + touched[current] = true; + if (Contains(current)) { + current = Value(current); } } - start_chain_ends_.push_back(start); - if (start != end) { - SetValue(start, end); + // Merge the sub-chain starting from 'node' and ending at 'current' with + // the existing sub-chain starting at 'current'. + starts[ends[current]] = starts[node]; + ends[starts[node]] = ends[current]; + } + start_chain_ends_.clear(); + start_chain_ends_.reserve(model()->vehicles()); + // Set each route to be the concatenation of the chain at its starts and the + // chain at its end, without nodes in between. + for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) { + const int start_chain_end = ends[model()->Start(vehicle)]; + if (!model()->IsEnd(start_chain_end)) { + SetValue(start_chain_end, starts[model()->End(vehicle)]); } + start_chain_ends_.push_back(start_chain_end); } return Commit(); } diff --git a/src/constraint_solver/search.cc b/src/constraint_solver/search.cc index 66638beb63..8f0d84105d 100644 --- a/src/constraint_solver/search.cc +++ b/src/constraint_solver/search.cc @@ -1563,7 +1563,7 @@ int64 StaticEvaluatorSelector::SelectValue(const IntVar* const var, int64 id) { IntVar* StaticEvaluatorSelector::SelectVariable(Solver* const s, int64* id) { if (first_ == -1) { // first call to select. update assignment costs - // Two phases: compute size then filland std::sort + // Two phases: compute size then filland sort int element_size = 0; for (int i = 0; i < vars_.size(); ++i) { if (!vars_[i]->Bound()) { diff --git a/src/flatzinc/flatzinc.h b/src/flatzinc/flatzinc.h index e42fbe8428..b87677531c 100644 --- a/src/flatzinc/flatzinc.h +++ b/src/flatzinc/flatzinc.h @@ -37,6 +37,7 @@ #include #include +#include "base/unique_ptr.h" #include "flatzinc/parser.h" #include "constraint_solver/constraint_solver.h" @@ -273,7 +274,7 @@ class FlatZincModel { // Number of set variables int set_var_count; - scoped_ptr solver_; + std::unique_ptr solver_; OptimizeVar* objective_; // Index of the integer variable to optimize diff --git a/src/flatzinc/fz.cc b/src/flatzinc/fz.cc index c4c9addf7a..aefca41ff6 100644 --- a/src/flatzinc/fz.cc +++ b/src/flatzinc/fz.cc @@ -36,6 +36,7 @@ #include // NOLINT #include // NOLINT #include +#include "base/unique_ptr.h" #include "base/commandlineflags.h" #include "base/commandlineflags.h" #include "base/integral_types.h" @@ -175,7 +176,7 @@ void SequentialRun(char* const file) { FLAGS_use_impact ? FlatZincSearchParameters::IBS : FlatZincSearchParameters::DEFAULT; - scoped_ptr parallel_support( + std::unique_ptr parallel_support( operations_research::MakeSequentialSupport(parameters.all_solutions, parameters.num_solutions, FLAGS_verbose_mt)); @@ -225,7 +226,7 @@ int main(int argc, char** argv) { if (FLAGS_workers == 0) { operations_research::SequentialRun(argv[1]); } else { - scoped_ptr parallel_support( + std::unique_ptr parallel_support( operations_research::MakeMtSupport( FLAGS_all, FLAGS_num_solutions, FLAGS_verbose_mt)); { diff --git a/src/flatzinc/parser.cc b/src/flatzinc/parser.cc index b6df6e2468..83c5a65a84 100644 --- a/src/flatzinc/parser.cc +++ b/src/flatzinc/parser.cc @@ -566,7 +566,7 @@ void ParserState::BuildStatistics() { void ParserState::SortConstraints(NodeSet* const candidates, NodeSet* const computed_variables) { - // Discover expressions, topological std::sort of constraints. + // Discover expressions, topological sort of constraints. for (unsigned int i = 0; i < constraints_.size(); i++) { CtSpec* const spec = constraints_[i]; diff --git a/src/graph/graph.h b/src/graph/graph.h index d7f410398e..712b6f81a8 100644 --- a/src/graph/graph.h +++ b/src/graph/graph.h @@ -1600,7 +1600,7 @@ void ReverseArcStaticGraph this->ComputeCumulativeSum(&reverse_start_); // Computes the reverse arcs of the forward arcs. - // Note that this std::sort the reverse arcs with the same tail by head. + // Note that this sort the reverse arcs with the same tail by head. opposite_.reserve(num_arcs_); for (int i = 0; i < num_arcs_; ++i) { // TODO(user): the 0 is wasted here, but minor optimisation. diff --git a/src/graph/linear_assignment.h b/src/graph/linear_assignment.h index bb973f7af3..e3e9e83260 100644 --- a/src/graph/linear_assignment.h +++ b/src/graph/linear_assignment.h @@ -609,7 +609,7 @@ template class LinearSumAssignment { // forced: When a left-side node is incident to only one arc a, // any feasible solution must include a, and reducing the price // of Head(a) by any nonnegative amount preserves epsilon- - // optimality. Because of this freedom, we'll call this std::sort of + // optimality. Because of this freedom, we'll call this sort of // relabeling (i.e., a relabeling of a right-side node that is // the only neighbor of the left-side node to which it has been // matched in the present double-push operation) a "slack" diff --git a/src/linear_solver/linear_solver.cc b/src/linear_solver/linear_solver.cc index 5b6a98c15c..21edc58e9e 100644 --- a/src/linear_solver/linear_solver.cc +++ b/src/linear_solver/linear_solver.cc @@ -18,6 +18,7 @@ #include #endif + #include #include #include @@ -761,7 +762,7 @@ void OutputTermsToProto( DCHECK_NE(-1, var_index); linear_term.push_back(std::pair(var_index, coef)); } - // The cost of std::sort is expected to be low as constraints usually have very + // The cost of sort is expected to be low as constraints usually have very // few terms. std::sort(linear_term.begin(), linear_term.end()); // Now use linear term. @@ -837,7 +838,7 @@ void MPSolver::ExportModelToNewProto( const double coeff = entry.second; linear_term.push_back(std::pair(var_index, coeff)); } - // The cost of std::sort is expected to be low as constraints usually have very + // The cost of sort is expected to be low as constraints usually have very // few terms. std::sort(linear_term.begin(), linear_term.end()); // Now use linear term. diff --git a/src/util/piecewise_linear_function.h b/src/util/piecewise_linear_function.h index 36622da2b2..0692ef115f 100644 --- a/src/util/piecewise_linear_function.h +++ b/src/util/piecewise_linear_function.h @@ -56,7 +56,7 @@ class PiecewiseSegment { // Returns the intersection of the segment's extension with the y axis. int64 intersection_y() const { return intersection_y_; } - // Comparison method useful to std::sort a sequence of segments. + // Comparison method useful to sort a sequence of segments. static bool SortComparator(const PiecewiseSegment& segment1, const PiecewiseSegment& segment2); // Comparison method useful to find in which segment a point belongs. diff --git a/src/util/stats.cc b/src/util/stats.cc index a7ed589775..b8e4c8a87d 100644 --- a/src/util/stats.cc +++ b/src/util/stats.cc @@ -70,7 +70,7 @@ bool CompareStatPointerByName(Stat* s1, Stat *s2) { string StatsGroup::StatString() const { // Computes the longest name of all the stats we want to display. - // Also create a temporary vector so we can std::sort the stats by names. + // Also create a temporary vector so we can sort the stats by names. int longest_name_size = 0; std::vector sorted_stats; for (int i = 0; i < stats_.size(); ++i) { diff --git a/src/util/tuple_set.h b/src/util/tuple_set.h index 139ab4469c..5349e44114 100644 --- a/src/util/tuple_set.h +++ b/src/util/tuple_set.h @@ -87,7 +87,7 @@ class IntTupleSet { // Returns the number of different values in the given column. int NumDifferentValuesInColumn(int col) const; // Return a copy of the set, sorted by the "col"-th value of each - // tuples. The std::sort is stable. + // tuples. The sort is stable. IntTupleSet SortedByColumn(int col) const; // Returns a copy of the tuple set lexicographically sorted. IntTupleSet SortedLexicographically() const;