revert last change on the routing API; report new best bound of the SAT solver in the log
This commit is contained in:
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> 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<int> group;
|
||||
std::vector<int64> group;
|
||||
for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot;
|
||||
order < manager.num_nodes(); ++order) {
|
||||
group.push_back(manager.NodeToIndex(order));
|
||||
|
||||
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> 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<int> group;
|
||||
std::vector<int64> group;
|
||||
for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot;
|
||||
order < manager.num_nodes(); ++order) {
|
||||
group.push_back(manager.NodeToIndex(order));
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
typedef std::function<int64(RoutingNodeIndex, RoutingNodeIndex)>
|
||||
RoutingNodeEvaluator2;
|
||||
|
||||
// Random seed generator.
|
||||
int32 GetSeed(bool deterministic);
|
||||
|
||||
|
||||
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> orders(1, manager.NodeToIndex(order));
|
||||
routing.AddDisjunction(orders, kPenalty);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> orders(1, manager.NodeToIndex(order));
|
||||
routing.AddDisjunction(orders, kPenalty);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> orders(1, manager.NodeToIndex(order));
|
||||
routing.AddDisjunction(orders, kPenalty);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> orders(1, manager.NodeToIndex(order));
|
||||
routing.AddDisjunction(orders, kPenalty);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int> orders(1, manager.NodeToIndex(order));
|
||||
std::vector<int64> orders(1, manager.NodeToIndex(order));
|
||||
routing.AddDisjunction(orders, kPenalty);
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -1353,7 +1353,7 @@ void RoutingModel::ComputeVehicleClasses() {
|
||||
}
|
||||
|
||||
RoutingModel::DisjunctionIndex RoutingModel::AddDisjunction(
|
||||
const std::vector<int>& indices, int64 penalty, int64 max_cardinality) {
|
||||
const std::vector<int64>& 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<std::pair<int64, int64>>
|
||||
RoutingModel::GetPerfectBinaryDisjunctions() const {
|
||||
std::vector<std::pair<int64, int64>> var_index_pairs;
|
||||
for (const Disjunction& disjunction : disjunctions_) {
|
||||
const std::vector<int>& var_indices = disjunction.indices;
|
||||
const std::vector<int64>& 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<int>& indices = disjunctions_[disjunction].indices;
|
||||
const std::vector<int64>& indices = disjunctions_[disjunction].indices;
|
||||
const int indices_size = indices.size();
|
||||
std::vector<IntVar*> 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<int>& indices,
|
||||
int64 cost) {
|
||||
void RoutingModel::AddSoftSameVehicleConstraint(
|
||||
const std::vector<int64>& indices, int64 cost) {
|
||||
if (!indices.empty()) {
|
||||
ValuedNodes<int64> 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<int>& 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<int>& pickups, const std::vector<int>& deliveries) {
|
||||
const std::vector<int64>& pickups, const std::vector<int64>& deliveries) {
|
||||
if (pickups.empty() || deliveries.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -1509,7 +1509,8 @@ int RoutingModel::GetNumOfSingletonNodes() const {
|
||||
}
|
||||
|
||||
IntVar* RoutingModel::CreateSameVehicleCost(int vehicle_index) {
|
||||
const std::vector<int>& indices = same_vehicle_costs_[vehicle_index].indices;
|
||||
const std::vector<int64>& indices =
|
||||
same_vehicle_costs_[vehicle_index].indices;
|
||||
CHECK(!indices.empty());
|
||||
std::vector<IntVar*> vehicle_counts;
|
||||
solver_->MakeIntVarArray(vehicle_vars_.size() + 1, 0, indices.size() + 1,
|
||||
|
||||
@@ -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<int>& indices,
|
||||
DisjunctionIndex AddDisjunction(const std::vector<int64>& 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<int>& GetDisjunctionIndices(DisjunctionIndex index) const {
|
||||
const std::vector<int64>& 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<int>& indices,
|
||||
void AddSoftSameVehicleConstraint(const std::vector<int64>& 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 <typename T>
|
||||
struct ValuedNodes {
|
||||
std::vector<int> indices;
|
||||
std::vector<int64> 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<int>& pickups,
|
||||
const std::vector<int>& deliveries);
|
||||
void AddPickupAndDeliverySetsInternal(const std::vector<int64>& pickups,
|
||||
const std::vector<int64>& deliveries);
|
||||
// Returns the cost variable related to the soft same vehicle constraint of
|
||||
// index 'vehicle_index'.
|
||||
IntVar* CreateSameVehicleCost(int vehicle_index);
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace {
|
||||
// Compute set of disjunctions involved in a pickup and delivery pair.
|
||||
template <typename Disjunctions>
|
||||
void AddDisjunctionsFromNodes(const RoutingModel& model,
|
||||
const std::vector<int>& nodes,
|
||||
const std::vector<int64>& nodes,
|
||||
Disjunctions* disjunctions) {
|
||||
for (int64 node : nodes) {
|
||||
for (const auto disjunction : model.GetDisjunctionIndices(node)) {
|
||||
|
||||
@@ -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<int> RoutingIndexManager::NodesToIndices(
|
||||
std::vector<int64> RoutingIndexManager::NodesToIndices(
|
||||
const std::vector<NodeIndex>& nodes) const {
|
||||
std::vector<int> indices;
|
||||
std::vector<int64> 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);
|
||||
}
|
||||
|
||||
@@ -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<int> NodesToIndices(const std::vector<NodeIndex>& nodes) const;
|
||||
NodeIndex IndexToNode(int index) const {
|
||||
std::vector<int64> NodesToIndices(const std::vector<NodeIndex>& 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<NodeIndex> GetIndexToNodeMap() const { return index_to_node_; }
|
||||
gtl::ITIVector<NodeIndex, int> GetNodeToIndexMap() const {
|
||||
gtl::ITIVector<NodeIndex, int64> GetNodeToIndexMap() const {
|
||||
return node_to_index_;
|
||||
}
|
||||
|
||||
@@ -84,9 +84,9 @@ class RoutingIndexManager {
|
||||
const std::vector<std::pair<NodeIndex, NodeIndex> >& starts_ends);
|
||||
|
||||
std::vector<NodeIndex> index_to_node_;
|
||||
gtl::ITIVector<NodeIndex, int> node_to_index_;
|
||||
std::vector<int> vehicle_to_start_;
|
||||
std::vector<int> vehicle_to_end_;
|
||||
gtl::ITIVector<NodeIndex, int64> node_to_index_;
|
||||
std::vector<int64> vehicle_to_start_;
|
||||
std::vector<int64> vehicle_to_end_;
|
||||
int num_nodes_;
|
||||
int num_vehicles_;
|
||||
int num_unique_depots_;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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<int>& disjunction_indices =
|
||||
const std::vector<int64>& 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) {
|
||||
|
||||
@@ -37,12 +37,10 @@ DEFINE_INT_TYPE(RoutingDimensionIndex, int);
|
||||
DEFINE_INT_TYPE(RoutingDisjunctionIndex, int);
|
||||
DEFINE_INT_TYPE(RoutingVehicleClassIndex, int);
|
||||
|
||||
typedef std::function<int64(RoutingNodeIndex, RoutingNodeIndex)>
|
||||
RoutingNodeEvaluator2;
|
||||
typedef std::function<int64(int)> RoutingTransitCallback1;
|
||||
typedef std::function<int64(int, int)> RoutingTransitCallback2;
|
||||
// NOTE(user): keep the "> >" for SWIG.
|
||||
typedef std::pair<std::vector<int>, std::vector<int> > RoutingIndexPair;
|
||||
typedef std::pair<std::vector<int64>, std::vector<int64> > RoutingIndexPair;
|
||||
typedef std::vector<RoutingIndexPair> RoutingIndexPairs;
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -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<SatParameters(Model*)> 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<IntegerVariable>& modified_vars) {
|
||||
CpSolverResponse lb_response;
|
||||
lb_response.set_status(CpSolverStatus::UNKNOWN);
|
||||
auto* integer_trail = model->Get<IntegerTrail>();
|
||||
const ObjectiveSynchronizationHelper* const helper =
|
||||
model->GetOrCreate<ObjectiveSynchronizationHelper>();
|
||||
@@ -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<GenericLiteralWatcher>()
|
||||
->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<SatSolver>()->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<PrecedencesPropagator>() != nullptr &&
|
||||
parameters.auto_detect_greater_than_at_least_one_of()) {
|
||||
model->Mutable<PrecedencesPropagator>()
|
||||
@@ -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<SatSolver>()->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<WorkerInfo>() == nullptr) {
|
||||
model->GetOrCreate<WorkerInfo>()->global_timer = &wall_timer;
|
||||
auto* integer_trail = model->Get<IntegerTrail>();
|
||||
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<WorkerInfo>();
|
||||
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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<std::string>& "in" typemap.
|
||||
// Get const std::vector<std::string>& "in" typemap.
|
||||
|
||||
%define PY_LIST_OUTPUT_TYPEMAP(type, checker, py_converter)
|
||||
%typecheck(SWIG_TYPECHECK_POINTER) const std::vector<type>&,
|
||||
|
||||
Reference in New Issue
Block a user