From 39f30fb178284eb606a0377292e6870e85430a22 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Fri, 14 Dec 2018 14:25:52 +0100 Subject: [PATCH] revert last change on the routing API; report new best bound of the SAT solver in the log --- examples/cpp/cvrp_disjoint_tw.cc | 4 +- examples/cpp/cvrptw.cc | 4 +- examples/cpp/cvrptw_lib.h | 3 + examples/cpp/cvrptw_with_breaks.cc | 2 +- examples/cpp/cvrptw_with_refueling.cc | 2 +- examples/cpp/cvrptw_with_resources.cc | 2 +- .../cvrptw_with_stop_times_and_resources.cc | 2 +- examples/cpp/pdptw.cc | 2 +- examples/dotnet/cscvrptw.cs | 2 +- ...dVehicleRoutingProblemWithTimeWindows.java | 2 +- ortools/constraint_solver/routing.cc | 21 +++-- ortools/constraint_solver/routing.h | 15 +-- ortools/constraint_solver/routing_flow.cc | 2 +- .../routing_index_manager.cc | 14 +-- .../constraint_solver/routing_index_manager.h | 20 ++-- .../routing_neighborhoods.cc | 12 +-- ortools/constraint_solver/routing_search.cc | 4 +- ortools/constraint_solver/routing_types.h | 4 +- ortools/sat/cp_model_solver.cc | 92 ++++++++++++------- ortools/sat/linear_programming_constraint.cc | 5 +- ortools/util/python/vector.i | 2 +- 21 files changed, 122 insertions(+), 94 deletions(-) diff --git a/examples/cpp/cvrp_disjoint_tw.cc b/examples/cpp/cvrp_disjoint_tw.cc index 7e9f50fdf9..aef1eb2f3f 100644 --- a/examples/cpp/cvrp_disjoint_tw.cc +++ b/examples/cpp/cvrp_disjoint_tw.cc @@ -148,13 +148,13 @@ int main(int argc, char** argv) { const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < manager.num_nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } // Adding same vehicle constraint costs for consecutive nodes. if (FLAGS_vrp_use_same_vehicle_costs) { - std::vector group; + std::vector group; for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < manager.num_nodes(); ++order) { group.push_back(manager.NodeToIndex(order)); diff --git a/examples/cpp/cvrptw.cc b/examples/cpp/cvrptw.cc index d54d531423..9696115f7e 100644 --- a/examples/cpp/cvrptw.cc +++ b/examples/cpp/cvrptw.cc @@ -134,13 +134,13 @@ int main(int argc, char** argv) { const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < manager.num_nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } // Adding same vehicle constraint costs for consecutive nodes. if (FLAGS_vrp_use_same_vehicle_costs) { - std::vector group; + std::vector group; for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < manager.num_nodes(); ++order) { group.push_back(manager.NodeToIndex(order)); diff --git a/examples/cpp/cvrptw_lib.h b/examples/cpp/cvrptw_lib.h index 9413e49090..3ae5f6f5ed 100644 --- a/examples/cpp/cvrptw_lib.h +++ b/examples/cpp/cvrptw_lib.h @@ -26,6 +26,9 @@ namespace operations_research { +typedef std::function + RoutingNodeEvaluator2; + // Random seed generator. int32 GetSeed(bool deterministic); diff --git a/examples/cpp/cvrptw_with_breaks.cc b/examples/cpp/cvrptw_with_breaks.cc index 1fbc6708a0..17d5c810fe 100644 --- a/examples/cpp/cvrptw_with_breaks.cc +++ b/examples/cpp/cvrptw_with_breaks.cc @@ -194,7 +194,7 @@ int main(int argc, char** argv) { const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } diff --git a/examples/cpp/cvrptw_with_refueling.cc b/examples/cpp/cvrptw_with_refueling.cc index 5056f5a177..9eb02136d0 100644 --- a/examples/cpp/cvrptw_with_refueling.cc +++ b/examples/cpp/cvrptw_with_refueling.cc @@ -156,7 +156,7 @@ int main(int argc, char** argv) { const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } diff --git a/examples/cpp/cvrptw_with_resources.cc b/examples/cpp/cvrptw_with_resources.cc index bdf29ba84c..93bc87c898 100644 --- a/examples/cpp/cvrptw_with_resources.cc +++ b/examples/cpp/cvrptw_with_resources.cc @@ -156,7 +156,7 @@ int main(int argc, char** argv) { const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < manager.num_nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } diff --git a/examples/cpp/cvrptw_with_stop_times_and_resources.cc b/examples/cpp/cvrptw_with_stop_times_and_resources.cc index 17403938a1..1020afc992 100644 --- a/examples/cpp/cvrptw_with_stop_times_and_resources.cc +++ b/examples/cpp/cvrptw_with_stop_times_and_resources.cc @@ -183,7 +183,7 @@ int main(int argc, char** argv) { const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } diff --git a/examples/cpp/pdptw.cc b/examples/cpp/pdptw.cc index d252a9bd43..3ecc463ccd 100644 --- a/examples/cpp/pdptw.cc +++ b/examples/cpp/pdptw.cc @@ -351,7 +351,7 @@ bool LoadAndSolve(const std::string& pdp_file, const int64 kPenalty = 10000000; for (RoutingIndexManager::NodeIndex order(1); order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); + std::vector orders(1, manager.NodeToIndex(order)); routing.AddDisjunction(orders, kPenalty); } diff --git a/examples/dotnet/cscvrptw.cs b/examples/dotnet/cscvrptw.cs index e747a6a1d8..091659dbe9 100644 --- a/examples/dotnet/cscvrptw.cs +++ b/examples/dotnet/cscvrptw.cs @@ -269,7 +269,7 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows { for (int order = 0; order < number_of_orders; ++order) { time_dimension.CumulVar(order).SetRange(order_time_windows_[order].start_, order_time_windows_[order].end_); - int[] orders = {order}; + long[] orders = {manager.NodeToIndex(order)}; model.AddDisjunction(orders, order_penalties_[order]); } diff --git a/examples/java/CapacitatedVehicleRoutingProblemWithTimeWindows.java b/examples/java/CapacitatedVehicleRoutingProblemWithTimeWindows.java index 56f908d981..d8f429fee4 100644 --- a/examples/java/CapacitatedVehicleRoutingProblemWithTimeWindows.java +++ b/examples/java/CapacitatedVehicleRoutingProblemWithTimeWindows.java @@ -221,7 +221,7 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows { timeDimension .cumulVar(order) .setRange(orderTimeWindows.get(order).first, orderTimeWindows.get(order).second); - int[] orderIndices = {manager.nodeToIndex(order)}; + long[] orderIndices = {manager.nodeToIndex(order)}; model.addDisjunction(orderIndices, orderPenalties.get(order)); } diff --git a/ortools/constraint_solver/routing.cc b/ortools/constraint_solver/routing.cc index 137ed7cdb9..6f5c972c86 100644 --- a/ortools/constraint_solver/routing.cc +++ b/ortools/constraint_solver/routing.cc @@ -1353,7 +1353,7 @@ void RoutingModel::ComputeVehicleClasses() { } RoutingModel::DisjunctionIndex RoutingModel::AddDisjunction( - const std::vector& indices, int64 penalty, int64 max_cardinality) { + const std::vector& indices, int64 penalty, int64 max_cardinality) { CHECK_GE(max_cardinality, 1); for (int i = 0; i < indices.size(); ++i) { CHECK_NE(kUnassigned, indices[i]); @@ -1361,7 +1361,7 @@ RoutingModel::DisjunctionIndex RoutingModel::AddDisjunction( const DisjunctionIndex disjunction_index(disjunctions_.size()); disjunctions_.push_back({indices, {penalty, max_cardinality}}); - for (const int index : indices) { + for (const int64 index : indices) { index_to_disjunctions_[index].push_back(disjunction_index); } return disjunction_index; @@ -1371,7 +1371,7 @@ std::vector> RoutingModel::GetPerfectBinaryDisjunctions() const { std::vector> var_index_pairs; for (const Disjunction& disjunction : disjunctions_) { - const std::vector& var_indices = disjunction.indices; + const std::vector& var_indices = disjunction.indices; if (var_indices.size() != 2) continue; const int64 v0 = var_indices[0]; const int64 v1 = var_indices[1]; @@ -1402,7 +1402,7 @@ void RoutingModel::IgnoreDisjunctionsAlreadyForcedToZero() { } IntVar* RoutingModel::CreateDisjunction(DisjunctionIndex disjunction) { - const std::vector& indices = disjunctions_[disjunction].indices; + const std::vector& indices = disjunctions_[disjunction].indices; const int indices_size = indices.size(); std::vector disjunction_vars(indices_size); for (int i = 0; i < indices_size; ++i) { @@ -1427,11 +1427,11 @@ IntVar* RoutingModel::CreateDisjunction(DisjunctionIndex disjunction) { } } -void RoutingModel::AddSoftSameVehicleConstraint(const std::vector& indices, - int64 cost) { +void RoutingModel::AddSoftSameVehicleConstraint( + const std::vector& indices, int64 cost) { if (!indices.empty()) { ValuedNodes same_vehicle_cost; - for (const int index : indices) { + for (const int64 index : indices) { same_vehicle_cost.indices.push_back(index); } same_vehicle_cost.value = cost; @@ -1448,7 +1448,7 @@ void RoutingModel::SetAllowedVehiclesForIndex(const std::vector& vehicles, } } -void RoutingModel::AddPickupAndDelivery(int pickup, int delivery) { +void RoutingModel::AddPickupAndDelivery(int64 pickup, int64 delivery) { AddPickupAndDeliverySetsInternal({pickup}, {delivery}); pickup_delivery_disjunctions_.push_back({kNoDisjunction, kNoDisjunction}); } @@ -1463,7 +1463,7 @@ void RoutingModel::AddPickupAndDeliverySets( } void RoutingModel::AddPickupAndDeliverySetsInternal( - const std::vector& pickups, const std::vector& deliveries) { + const std::vector& pickups, const std::vector& deliveries) { if (pickups.empty() || deliveries.empty()) { return; } @@ -1509,7 +1509,8 @@ int RoutingModel::GetNumOfSingletonNodes() const { } IntVar* RoutingModel::CreateSameVehicleCost(int vehicle_index) { - const std::vector& indices = same_vehicle_costs_[vehicle_index].indices; + const std::vector& indices = + same_vehicle_costs_[vehicle_index].indices; CHECK(!indices.empty()); std::vector vehicle_counts; solver_->MakeIntVarArray(vehicle_vars_.size() + 1, 0, indices.size() + 1, diff --git a/ortools/constraint_solver/routing.h b/ortools/constraint_solver/routing.h index a700680ea9..c1c1f0ba56 100644 --- a/ortools/constraint_solver/routing.h +++ b/ortools/constraint_solver/routing.h @@ -536,7 +536,7 @@ class RoutingModel { // performed, and therefore p == 0. // Note: passing a vector with a single index will model an optional index // with a penalty cost if it is not visited. - DisjunctionIndex AddDisjunction(const std::vector& indices, + DisjunctionIndex AddDisjunction(const std::vector& indices, int64 penalty = kNoPenalty, int64 max_cardinality = 1); // Returns the indices of the disjunctions to which an index belongs. @@ -561,7 +561,8 @@ class RoutingModel { #if !defined(SWIGPYTHON) // Returns the variable indices of the nodes in the disjunction of index // 'index'. - const std::vector& GetDisjunctionIndices(DisjunctionIndex index) const { + const std::vector& GetDisjunctionIndices( + DisjunctionIndex index) const { return disjunctions_[index].indices; } #endif // !defined(SWIGPYTHON) @@ -591,7 +592,7 @@ class RoutingModel { // Adds a soft contraint to force a set of variable indices to be on the same // vehicle. If all nodes are not on the same vehicle, each extra vehicle used // adds 'cost' to the cost function. - void AddSoftSameVehicleConstraint(const std::vector& indices, + void AddSoftSameVehicleConstraint(const std::vector& indices, int64 cost); // Sets the vehicles which can visit a given node. If the node is in a @@ -623,7 +624,7 @@ class RoutingModel { // routing.AddPickupAndDelivery(index1, index2); // // TODO(user): Remove this when model introspection detects linked nodes. - void AddPickupAndDelivery(int pickup, int delivery); + void AddPickupAndDelivery(int64 pickup, int64 delivery); // Same as AddPickupAndDelivery but notifying that the performed node from // the disjunction of index 'pickup_disjunction' is on the same route as the // performed node from the disjunction of index 'delivery_disjunction'. @@ -1147,7 +1148,7 @@ class RoutingModel { // when unperformed). template struct ValuedNodes { - std::vector indices; + std::vector indices; T value; }; struct DisjunctionValues { @@ -1209,8 +1210,8 @@ class RoutingModel { // Returns nullptr if no penalty cost, otherwise returns penalty variable. IntVar* CreateDisjunction(DisjunctionIndex disjunction); // Sets up pickup and delivery sets. - void AddPickupAndDeliverySetsInternal(const std::vector& pickups, - const std::vector& deliveries); + void AddPickupAndDeliverySetsInternal(const std::vector& pickups, + const std::vector& deliveries); // Returns the cost variable related to the soft same vehicle constraint of // index 'vehicle_index'. IntVar* CreateSameVehicleCost(int vehicle_index); diff --git a/ortools/constraint_solver/routing_flow.cc b/ortools/constraint_solver/routing_flow.cc index 42eaf97598..34da596d89 100644 --- a/ortools/constraint_solver/routing_flow.cc +++ b/ortools/constraint_solver/routing_flow.cc @@ -21,7 +21,7 @@ namespace { // Compute set of disjunctions involved in a pickup and delivery pair. template void AddDisjunctionsFromNodes(const RoutingModel& model, - const std::vector& nodes, + const std::vector& nodes, Disjunctions* disjunctions) { for (int64 node : nodes) { for (const auto disjunction : model.GetDisjunctionIndices(node)) { diff --git a/ortools/constraint_solver/routing_index_manager.cc b/ortools/constraint_solver/routing_index_manager.cc index c6c6a922ed..0e74d2bff9 100644 --- a/ortools/constraint_solver/routing_index_manager.cc +++ b/ortools/constraint_solver/routing_index_manager.cc @@ -21,7 +21,7 @@ namespace operations_research { -const int RoutingIndexManager::kUnassigned = -1; +const int64 RoutingIndexManager::kUnassigned = -1; RoutingIndexManager::RoutingIndexManager(int num_nodes, int num_vehicles, NodeIndex depot) @@ -77,7 +77,7 @@ void RoutingIndexManager::Initialize( node_to_index_.resize(num_nodes_, kUnassigned); vehicle_to_start_.resize(num_vehicles_); vehicle_to_end_.resize(num_vehicles_); - int index = 0; + int64 index = 0; for (NodeIndex i = kZeroNode; i < num_nodes_; ++i) { if (gtl::ContainsKey(starts, i) || !gtl::ContainsKey(ends, i)) { index_to_node_[index] = i; @@ -90,7 +90,7 @@ void RoutingIndexManager::Initialize( const NodeIndex start = starts_ends[i].first; if (!gtl::ContainsKey(seen_starts, start)) { seen_starts.insert(start); - const int start_index = node_to_index_[start]; + const int64 start_index = node_to_index_[start]; vehicle_to_start_[i] = start_index; CHECK_NE(kUnassigned, start_index); } else { @@ -110,7 +110,7 @@ void RoutingIndexManager::Initialize( // Logging model information. VLOG(1) << "Number of nodes: " << num_nodes_; VLOG(1) << "Number of vehicles: " << num_vehicles_; - for (int index = 0; index < index_to_node_.size(); ++index) { + for (int64 index = 0; index < index_to_node_.size(); ++index) { VLOG(2) << "Variable index " << index << " -> Node index " << index_to_node_[index]; } @@ -120,12 +120,12 @@ void RoutingIndexManager::Initialize( } } -std::vector RoutingIndexManager::NodesToIndices( +std::vector RoutingIndexManager::NodesToIndices( const std::vector& nodes) const { - std::vector indices; + std::vector indices; indices.reserve(nodes.size()); for (const NodeIndex node : nodes) { - const int index = NodeToIndex(node); + const int64 index = NodeToIndex(node); CHECK_NE(kUnassigned, index); indices.push_back(index); } diff --git a/ortools/constraint_solver/routing_index_manager.h b/ortools/constraint_solver/routing_index_manager.h index f058ac774f..73b68e2652 100644 --- a/ortools/constraint_solver/routing_index_manager.h +++ b/ortools/constraint_solver/routing_index_manager.h @@ -40,7 +40,7 @@ namespace operations_research { class RoutingIndexManager { public: typedef RoutingNodeIndex NodeIndex; - static const int kUnassigned; + static const int64 kUnassigned; // Creates a NodeIndex to variable index mapping for a problem containing // 'num_nodes', 'num_vehicles' and the given starts and ends for each vehicle. @@ -57,15 +57,15 @@ class RoutingIndexManager { int num_nodes() const { return num_nodes_; } int num_vehicles() const { return num_vehicles_; } int num_indices() const { return index_to_node_.size(); } - int GetStartIndex(int vehicle) const { return vehicle_to_start_[vehicle]; } - int GetEndIndex(int vehicle) const { return vehicle_to_end_[vehicle]; } - int NodeToIndex(NodeIndex node) const { + int64 GetStartIndex(int vehicle) const { return vehicle_to_start_[vehicle]; } + int64 GetEndIndex(int vehicle) const { return vehicle_to_end_[vehicle]; } + int64 NodeToIndex(NodeIndex node) const { DCHECK_GE(node.value(), 0); DCHECK_LT(node.value(), node_to_index_.size()); return node_to_index_[node]; } - std::vector NodesToIndices(const std::vector& nodes) const; - NodeIndex IndexToNode(int index) const { + std::vector NodesToIndices(const std::vector& nodes) const; + NodeIndex IndexToNode(int64 index) const { DCHECK_GE(index, 0); DCHECK_LT(index, index_to_node_.size()); return index_to_node_[index]; @@ -74,7 +74,7 @@ class RoutingIndexManager { // complete. int num_unique_depots() const { return num_unique_depots_; } std::vector GetIndexToNodeMap() const { return index_to_node_; } - gtl::ITIVector GetNodeToIndexMap() const { + gtl::ITIVector GetNodeToIndexMap() const { return node_to_index_; } @@ -84,9 +84,9 @@ class RoutingIndexManager { const std::vector >& starts_ends); std::vector index_to_node_; - gtl::ITIVector node_to_index_; - std::vector vehicle_to_start_; - std::vector vehicle_to_end_; + gtl::ITIVector node_to_index_; + std::vector vehicle_to_start_; + std::vector vehicle_to_end_; int num_nodes_; int num_vehicles_; int num_unique_depots_; diff --git a/ortools/constraint_solver/routing_neighborhoods.cc b/ortools/constraint_solver/routing_neighborhoods.cc index e2fda636ee..9ec8014f1d 100644 --- a/ortools/constraint_solver/routing_neighborhoods.cc +++ b/ortools/constraint_solver/routing_neighborhoods.cc @@ -151,7 +151,7 @@ MakePairInactiveOperator::MakePairInactiveOperator( const RoutingIndexPairs& index_pairs) : PathWithPreviousNodesOperator(vars, secondary_vars, 1, std::move(start_empty_path_class)) { - int max_pair_index = -1; + int64 max_pair_index = -1; for (const auto& index_pair : index_pairs) { max_pair_index = std::max(max_pair_index, index_pair.first[0]); max_pair_index = std::max(max_pair_index, index_pair.second[0]); @@ -189,7 +189,7 @@ PairRelocateOperator::PairRelocateOperator( index_max = std::max(index_max, var->Max()); } is_first_.resize(index_max + 1, false); - int max_pair_index = -1; + int64 max_pair_index = -1; // TODO(user): Support pairs with disjunctions. for (const auto& index_pair : index_pairs) { max_pair_index = std::max(max_pair_index, index_pair.first[0]); @@ -283,7 +283,7 @@ LightPairRelocateOperator::LightPairRelocateOperator( const RoutingIndexPairs& index_pairs) : PathWithPreviousNodesOperator(vars, secondary_vars, 2, std::move(start_empty_path_class)) { - int max_pair_index = -1; + int64 max_pair_index = -1; // TODO(user): Support pairs with disjunctions. for (const auto& index_pair : index_pairs) { max_pair_index = std::max(max_pair_index, index_pair.first[0]); @@ -332,7 +332,7 @@ PairExchangeOperator::PairExchangeOperator( index_max = std::max(index_max, var->Max()); } is_first_.resize(index_max + 1, false); - int max_pair_index = -1; + int64 max_pair_index = -1; // TODO(user): Support pairs with disjunctions. for (const auto& index_pair : index_pairs) { max_pair_index = std::max(max_pair_index, index_pair.first[0]); @@ -415,7 +415,7 @@ PairExchangeRelocateOperator::PairExchangeRelocateOperator( index_max = std::max(index_max, var->Max()); } is_first_.resize(index_max + 1, false); - int max_pair_index = -1; + int64 max_pair_index = -1; // TODO(user): Support pairs with disjunctions. for (const auto& index_pair : index_pairs) { max_pair_index = std::max(max_pair_index, index_pair.first[0]); @@ -673,7 +673,7 @@ IndexPairSwapActiveOperator::IndexPairSwapActiveOperator( : PathWithPreviousNodesOperator(vars, secondary_vars, 1, std::move(start_empty_path_class)), inactive_node_(0) { - int max_pair_index = -1; + int64 max_pair_index = -1; // TODO(user): Support pairs with disjunctions. for (const auto& index_pair : index_pairs) { max_pair_index = std::max(max_pair_index, index_pair.first[0]); diff --git a/ortools/constraint_solver/routing_search.cc b/ortools/constraint_solver/routing_search.cc index 10a810686d..6a4f16dec1 100644 --- a/ortools/constraint_solver/routing_search.cc +++ b/ortools/constraint_solver/routing_search.cc @@ -182,9 +182,9 @@ class NodeDisjunctionFilter : public IntVarLocalSearchFilter { i < active_per_disjunction_.size(); ++i) { active_per_disjunction_[i] = 0; inactive_per_disjunction_[i] = 0; - const std::vector& disjunction_indices = + const std::vector& disjunction_indices = routing_model_.GetDisjunctionIndices(i); - for (const int index : disjunction_indices) { + for (const int64 index : disjunction_indices) { const bool index_synced = IsVarSynced(index); if (index_synced) { if (Value(index) != index) { diff --git a/ortools/constraint_solver/routing_types.h b/ortools/constraint_solver/routing_types.h index b6d6f0ed1f..1b13f86f7b 100644 --- a/ortools/constraint_solver/routing_types.h +++ b/ortools/constraint_solver/routing_types.h @@ -37,12 +37,10 @@ DEFINE_INT_TYPE(RoutingDimensionIndex, int); DEFINE_INT_TYPE(RoutingDisjunctionIndex, int); DEFINE_INT_TYPE(RoutingVehicleClassIndex, int); -typedef std::function - RoutingNodeEvaluator2; typedef std::function RoutingTransitCallback1; typedef std::function RoutingTransitCallback2; // NOTE(user): keep the "> >" for SWIG. -typedef std::pair, std::vector > RoutingIndexPair; +typedef std::pair, std::vector > RoutingIndexPair; typedef std::vector RoutingIndexPairs; } // namespace operations_research diff --git a/ortools/sat/cp_model_solver.cc b/ortools/sat/cp_model_solver.cc index ba5a39c886..ec6309374f 100644 --- a/ortools/sat/cp_model_solver.cc +++ b/ortools/sat/cp_model_solver.cc @@ -347,6 +347,7 @@ std::string Summarize(const std::string& input) { struct WorkerInfo { std::string worker_name; WallTimer* global_timer = nullptr; + bool parallel_mode = false; }; } // namespace. @@ -1186,9 +1187,9 @@ std::function NewSatParameters( } namespace { -void LogNewParallelSolution(const std::string& event_or_solution_count, - double time_in_seconds, double obj_lb, - double obj_ub, const std::string& solution_info) { +void LogNewSolution(const std::string& event_or_solution_count, + double time_in_seconds, double obj_lb, double obj_ub, + const std::string& solution_info) { VLOG(1) << absl::StrFormat("#%-5s %6.2fs obj:[%0.0f,%0.0f] %s", event_or_solution_count, time_in_seconds, obj_lb, obj_ub, solution_info); @@ -1202,8 +1203,6 @@ void RegisterObjectiveLowerBoundWatcher( const auto broadcast_lower_bound = [model_proto, external_solution_observer, objective_var, model](const std::vector& modified_vars) { - CpSolverResponse lb_response; - lb_response.set_status(CpSolverStatus::UNKNOWN); auto* integer_trail = model->Get(); const ObjectiveSynchronizationHelper* const helper = model->GetOrCreate(); @@ -1220,30 +1219,29 @@ void RegisterObjectiveLowerBoundWatcher( new_best_bound > current_best_bound) || (helper->scaling_factor < 0 && new_best_bound < current_best_bound)) { - DCHECK_EQ(0, lb_response.solution_size()); - DCHECK_EQ(0, lb_response.solution_lower_bounds_size()); - DCHECK_EQ(0, lb_response.solution_upper_bounds_size()); - DCHECK_EQ(lb_response.status(), CpSolverStatus::UNKNOWN); - lb_response.set_objective_value(current_objective_value); - lb_response.set_best_objective_bound(new_best_bound); - - if (current_objective_value >= new_best_bound) { - LogNewParallelSolution("ObjLb", worker_info->global_timer->Get(), - new_best_bound, current_objective_value, - worker_info->worker_name); + if (new_best_bound > current_best_bound) { // minimization. + LogNewSolution("ObjLb", worker_info->global_timer->Get(), + new_best_bound, current_objective_value, + worker_info->worker_name); } else { - LogNewParallelSolution("ObjUb", worker_info->global_timer->Get(), - current_objective_value, new_best_bound, - worker_info->worker_name); + LogNewSolution("ObjUb", worker_info->global_timer->Get(), + current_objective_value, new_best_bound, + worker_info->worker_name); + } + if (worker_info->parallel_mode) { + // Broadcast a best bound improving solution. + CpSolverResponse lb_response; + lb_response.set_status(CpSolverStatus::UNKNOWN); + lb_response.set_objective_value(current_objective_value); + lb_response.set_best_objective_bound(new_best_bound); + external_solution_observer(lb_response); } - external_solution_observer(lb_response); } }; model->GetOrCreate() ->RegisterLevelZeroModifiedVariablesCallback(broadcast_lower_bound); } - // Because we also use this function for postsolve, we call it with // is_real_solve set to true and avoid doing non-useful work in this case. CpSolverResponse SolveCpModelInternal( @@ -1350,9 +1348,9 @@ CpSolverResponse SolveCpModelInternal( model->GetOrCreate()->Propagate(); // Auto detect "at least one of" constraints in the PrecedencesPropagator. - // Note that we do that before we finish loading the problem (objective and LP - // relaxation), because propagation will be faster at this point and it should - // be enough for the purpose of this auto-detection. + // Note that we do that before we finish loading the problem (objective and + // LP relaxation), because propagation will be faster at this point and it + // should be enough for the purpose of this auto-detection. if (model->Mutable() != nullptr && parameters.auto_detect_greater_than_at_least_one_of()) { model->Mutable() @@ -1441,8 +1439,8 @@ CpSolverResponse SolveCpModelInternal( } } - // Note that we do one last propagation at level zero once all the constraints - // were added. + // Note that we do one last propagation at level zero once all the + // constraints were added. model->GetOrCreate()->Propagate(); // Initialize the search strategy function. @@ -1472,7 +1470,32 @@ CpSolverResponse SolveCpModelInternal( external_solution_observer(response); }; - if (watch_objective_lower_bound) { + if (watch_objective_lower_bound && model_proto.has_objective()) { + // Detect sequential mode, register callbacks in that case. + if (model->Get() == nullptr) { + model->GetOrCreate()->global_timer = &wall_timer; + auto* integer_trail = model->Get(); + const CpObjectiveProto& obj = model_proto.objective(); + const auto get_objective_value = [&response, integer_trail, &obj, + objective_var]() { + return response.status() != CpSolverStatus::MODEL_INVALID + ? response.objective_value() + : ScaleObjectiveValue( + obj, integer_trail->LevelZeroUpperBound(objective_var) + .value() + + 1); + }; + const auto get_objective_best_bound = [&response, integer_trail, &obj, + &objective_var]() { + return response.status() != CpSolverStatus::MODEL_INVALID + ? response.best_objective_bound() + : ScaleObjectiveValue( + obj, integer_trail->LevelZeroLowerBound(objective_var) + .value()); + }; + SetObjectiveSynchronizationFunctions(get_objective_value, + get_objective_best_bound, model); + } RegisterObjectiveLowerBoundWatcher(&model_proto, external_solution_observer, objective_var, model); } @@ -2139,6 +2162,7 @@ CpSolverResponse SolveCpModelParallel( WorkerInfo* worker_info = local_model.GetOrCreate(); worker_info->worker_name = worker_name; worker_info->global_timer = global_timer; + worker_info->parallel_mode = true; SetSynchronizationFunction(std::move(solution_synchronization), &local_model); @@ -2304,12 +2328,12 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) { [&model_proto, &observers, &num_solutions, &timer, &postprocess_solution](const CpSolverResponse& response) { const bool maximize = model_proto.objective().scaling_factor() < 0.0; - LogNewParallelSolution(absl::StrCat(++num_solutions), timer.Get(), - maximize ? response.objective_value() - : response.best_objective_bound(), - maximize ? response.best_objective_bound() - : response.objective_value(), - response.solution_info()); + LogNewSolution(absl::StrCat(++num_solutions), timer.Get(), + maximize ? response.objective_value() + : response.best_objective_bound(), + maximize ? response.best_objective_bound() + : response.objective_value(), + response.solution_info()); if (observers.empty()) return; CpSolverResponse copy = response; @@ -2346,7 +2370,7 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) { } else { response = SolveCpModelInternal( new_model, /*is_real_solve=*/true, observer_function, - /*watch_objective_lower_bound=*/false, model); + /*watch_objective_lower_bound=*/true, model); } postprocess_solution(&response); diff --git a/ortools/sat/linear_programming_constraint.cc b/ortools/sat/linear_programming_constraint.cc index cfc3e810a8..bf5e625f0c 100644 --- a/ortools/sat/linear_programming_constraint.cc +++ b/ortools/sat/linear_programming_constraint.cc @@ -675,9 +675,10 @@ bool LinearProgrammingConstraint::ComputeNewLinearConstraint( *scaling = std::max(*scaling, 1e6 / lp_multipliers_norm); } - // Make sure the scaled coeff are not too big. + // Make sure the scaled coeff are not too big so that they can fit on + // an IntegerValue. Since 1<<63 is around 9.2e18, we use 1e18 here. if (max_cp_multi > 0.0) { - *scaling = std::min(*scaling, 1e12 / max_cp_multi); + *scaling = std::min(*scaling, 1e18 / max_cp_multi); } // Scale the multipliers by *scaling. diff --git a/ortools/util/python/vector.i b/ortools/util/python/vector.i index fc9bd0e8ba..e333f76841 100644 --- a/ortools/util/python/vector.i +++ b/ortools/util/python/vector.i @@ -29,7 +29,7 @@ // Note(user): for an unknown reason, using the (handy) method PyObjAs() // defined in base/swig/python-swig.cc seems to cause issues, so we can't // use a generic, templated type checker. - // Get const std::vector& "in" typemap. +// Get const std::vector& "in" typemap. %define PY_LIST_OUTPUT_TYPEMAP(type, checker, py_converter) %typecheck(SWIG_TYPECHECK_POINTER) const std::vector&,