From c76a9a424a5faefa8d96e264b9734add02b05329 Mon Sep 17 00:00:00 2001 From: Corentin Le Molgat Date: Mon, 25 Mar 2024 11:59:02 +0100 Subject: [PATCH] backport example/ from main --- examples/cpp/BUILD.bazel | 83 +---- examples/cpp/CMakeLists.txt | 2 - examples/cpp/binpacking_2d_sat.cc | 10 +- examples/cpp/constraint_programming_cp.cc | 3 +- examples/cpp/costas_array_sat.cc | 2 +- examples/cpp/cvrp_disjoint_tw.cc | 195 ---------- examples/cpp/cvrptw.cc | 181 --------- examples/cpp/cvrptw_lib.h | 348 ------------------ examples/cpp/cvrptw_with_breaks.cc | 235 ------------ examples/cpp/cvrptw_with_refueling.cc | 192 ---------- examples/cpp/cvrptw_with_resources.cc | 187 ---------- .../cvrptw_with_stop_times_and_resources.cc | 223 ----------- examples/cpp/frequency_assignment_problem.cc | 31 +- examples/cpp/jobshop_sat.cc | 15 +- examples/cpp/slitherlink_sat.cc | 2 +- examples/cpp/weighted_tardiness_sat.cc | 6 + examples/flatzinc/{README => README.md} | 0 17 files changed, 51 insertions(+), 1664 deletions(-) delete mode 100644 examples/cpp/cvrp_disjoint_tw.cc delete mode 100644 examples/cpp/cvrptw.cc delete mode 100644 examples/cpp/cvrptw_lib.h delete mode 100644 examples/cpp/cvrptw_with_breaks.cc delete mode 100644 examples/cpp/cvrptw_with_refueling.cc delete mode 100644 examples/cpp/cvrptw_with_resources.cc delete mode 100644 examples/cpp/cvrptw_with_stop_times_and_resources.cc rename examples/flatzinc/{README => README.md} (100%) diff --git a/examples/cpp/BUILD.bazel b/examples/cpp/BUILD.bazel index ff2e0d1da6..d77d27b996 100644 --- a/examples/cpp/BUILD.bazel +++ b/examples/cpp/BUILD.bazel @@ -611,79 +611,6 @@ cc_binary( ], ) -cc_library( - name = "cvrptw_lib", - hdrs = ["cvrptw_lib.h"], - deps = [ - "//ortools/base", - "//ortools/constraint_solver:routing", - "//ortools/util:random_engine", - ], -) - -cc_binary( - name = "cvrptw", - srcs = ["cvrptw.cc"], - deps = [ - ":cvrptw_lib", - "//ortools/base", - "//ortools/constraint_solver:routing", - ], -) - -cc_binary( - name = "cvrp_disjoint_tw", - srcs = ["cvrp_disjoint_tw.cc"], - deps = [ - ":cvrptw_lib", - "//ortools/base", - "//ortools/constraint_solver:routing", - ], -) - -cc_binary( - name = "cvrptw_with_breaks", - srcs = ["cvrptw_with_breaks.cc"], - deps = [ - ":cvrptw_lib", - "//ortools/base", - "//ortools/constraint_solver:routing", - "//ortools/constraint_solver:routing_enums_cc_proto", - "@com_google_absl//absl/strings", - ], -) - -cc_binary( - name = "cvrptw_with_resources", - srcs = ["cvrptw_with_resources.cc"], - deps = [ - ":cvrptw_lib", - "//ortools/base", - "//ortools/constraint_solver:routing", - ], -) - -cc_binary( - name = "cvrptw_with_stop_times_and_resources", - srcs = ["cvrptw_with_stop_times_and_resources.cc"], - deps = [ - ":cvrptw_lib", - "//ortools/base", - "//ortools/constraint_solver:routing", - "@com_google_absl//absl/strings", - ], -) - -cc_binary( - name = "cvrptw_with_refueling", - srcs = ["cvrptw_with_refueling.cc"], - deps = [ - ":cvrptw_lib", - "//ortools/base", - "//ortools/constraint_solver:routing", - ], -) - cc_binary( name = "pdptw", srcs = ["pdptw.cc"], @@ -692,6 +619,7 @@ cc_binary( "//ortools/base:file", "//ortools/base:mathutil", "//ortools/constraint_solver:routing", + "//ortools/routing/parsers:lilim_parser", "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", @@ -753,6 +681,7 @@ cc_binary( "//ortools/base", "//ortools/linear_solver", "//ortools/linear_solver:linear_solver_cc_proto", + "//ortools/linear_solver:solve_mp_model", ], ) @@ -1075,12 +1004,18 @@ cc_binary( deps = [ "//ortools/base", "//ortools/linear_solver:linear_solver_cc_proto", + "//ortools/pdlp:iteration_stats", "//ortools/pdlp:primal_dual_hybrid_gradient", + "//ortools/pdlp:quadratic_program", "//ortools/pdlp:quadratic_program_io", "//ortools/pdlp:solve_log_cc_proto", "//ortools/pdlp:solvers_cc_proto", "//ortools/port:proto_utils", + "//ortools/util:file_util", "//ortools/util:sigint", - "@com_google_absl//absl/time", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/log:flags", + "@com_google_absl//absl/strings", ], ) diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 08320df97c..7fe5b30fcd 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -42,8 +42,6 @@ file(GLOB CXX_SRCS "*.cc") list(FILTER CXX_SRCS EXCLUDE REGEX ".*/binpacking_2d_sat.cc") list(FILTER CXX_SRCS EXCLUDE REGEX ".*/course_scheduling_run.cc") # missing proto list(FILTER CXX_SRCS EXCLUDE REGEX ".*/course_scheduling.cc") # missing proto -list(FILTER CXX_SRCS EXCLUDE REGEX ".*/cvrptw_with_breaks.cc") # too long -list(FILTER CXX_SRCS EXCLUDE REGEX ".*/cvrptw_with_refueling.cc") # too long list(FILTER CXX_SRCS EXCLUDE REGEX ".*/dimacs_assignment.cc") # crash list(FILTER CXX_SRCS EXCLUDE REGEX ".*/dobble_ls.cc") # Too long list(FILTER CXX_SRCS EXCLUDE REGEX ".*/frequency_assignment_problem.cc") # crash diff --git a/examples/cpp/binpacking_2d_sat.cc b/examples/cpp/binpacking_2d_sat.cc index 8a197d2291..4a0334bb20 100644 --- a/examples/cpp/binpacking_2d_sat.cc +++ b/examples/cpp/binpacking_2d_sat.cc @@ -26,6 +26,7 @@ #include "absl/flags/flag.h" #include "absl/log/check.h" #include "absl/strings/str_cat.h" +#include "absl/types/span.h" #include "google/protobuf/text_format.h" #include "ortools/base/init_google.h" #include "ortools/base/logging.h" @@ -171,7 +172,7 @@ absl::btree_set FindFixedItems( } // Solves a subset sum problem to find the maximum reachable max size. -int64_t MaxSubsetSumSize(const std::vector& sizes, int64_t max_size) { +int64_t MaxSubsetSumSize(absl::Span sizes, int64_t max_size) { CpModelBuilder builder; LinearExpr weighed_sum; for (const int size : sizes) { @@ -280,7 +281,7 @@ void LoadAndSolve(const std::string& file_name, int instance) { const absl::btree_set fixed_items = FindFixedItems(problem); // Fix the fixed_items to the first fixed_items.size() bins. - CHECK_LT(fixed_items.size(), max_bins) + CHECK_LE(fixed_items.size(), max_bins) << "Infeasible problem, increase max_bins"; int count = 0; for (const int item : fixed_items) { @@ -437,9 +438,10 @@ void LoadAndSolve(const std::string& file_name, int instance) { // Objective definition. cp_model.Minimize(obj); - for (int b = trivial_lb; b + 1 < max_bins; ++b) { + CHECK_GT(trivial_lb, 0); + for (int b = trivial_lb; b < max_bins; ++b) { cp_model.AddGreaterOrEqual(obj, b + 1).OnlyEnforceIf(bin_is_used[b]); - cp_model.AddImplication(bin_is_used[b + 1], bin_is_used[b]); + cp_model.AddImplication(bin_is_used[b], bin_is_used[b - 1]); } if (absl::GetFlag(FLAGS_symmetry_breaking)) { diff --git a/examples/cpp/constraint_programming_cp.cc b/examples/cpp/constraint_programming_cp.cc index c11cd27b8a..af3dc8c05b 100644 --- a/examples/cpp/constraint_programming_cp.cc +++ b/examples/cpp/constraint_programming_cp.cc @@ -43,8 +43,7 @@ void RunConstraintProgrammingExample() { solver.NewSearch(db); while (solver.NextSolution()) { - LOG(INFO) << "Solution" - << ": x = " << x->Value() << "; y = " << y->Value() + LOG(INFO) << "Solution" << ": x = " << x->Value() << "; y = " << y->Value() << "; z = " << z->Value(); } solver.EndSearch(); diff --git a/examples/cpp/costas_array_sat.cc b/examples/cpp/costas_array_sat.cc index b16f715fe4..fc7a4eb558 100644 --- a/examples/cpp/costas_array_sat.cc +++ b/examples/cpp/costas_array_sat.cc @@ -81,7 +81,7 @@ void CheckConstraintViolators(absl::Span vars, } // Check that all pairwise differences are unique -bool CheckCostas(const std::vector& vars) { +bool CheckCostas(absl::Span vars) { std::vector violators; CheckConstraintViolators(vars, &violators); diff --git a/examples/cpp/cvrp_disjoint_tw.cc b/examples/cpp/cvrp_disjoint_tw.cc deleted file mode 100644 index 1499d48389..0000000000 --- a/examples/cpp/cvrp_disjoint_tw.cc +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// -// Capacitated Vehicle Routing Problem with Disjoint Time Windows (and optional -// orders). -// A description of the problem can be found here: -// http://en.wikipedia.org/wiki/Vehicle_routing_problem. -// The variant which is tackled by this model includes a capacity dimension, -// disjoint time windows and optional orders, with a penalty cost if orders are -// not performed. For the sake of simplicity, orders are randomly located and -// distances are computed using the Manhattan distance. Distances are assumed -// to be in meters and times in seconds. - -#include -#include - -#include "absl/random/random.h" -#include "examples/cpp/cvrptw_lib.h" -#include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/init_google.h" -#include "ortools/base/types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/constraint_solver/routing_index_manager.h" -#include "ortools/constraint_solver/routing_parameters.h" -#include "ortools/constraint_solver/routing_parameters.pb.h" - -using operations_research::Assignment; -using operations_research::DefaultRoutingSearchParameters; -using operations_research::GetSeed; -using operations_research::LocationContainer; -using operations_research::RandomDemand; -using operations_research::RoutingDimension; -using operations_research::RoutingIndexManager; -using operations_research::RoutingModel; -using operations_research::RoutingNodeIndex; -using operations_research::RoutingSearchParameters; -using operations_research::ServiceTimePlusTransition; -using operations_research::Solver; - -ABSL_FLAG(int, vrp_orders, 100, "Number of nodes in the problem."); -ABSL_FLAG(int, vrp_vehicles, 20, "Number of vehicles in the problem."); -ABSL_FLAG(int, vrp_windows, 5, "Number of disjoint windows per node."); -ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false, - "Use deterministic random seeds."); -ABSL_FLAG(bool, vrp_use_same_vehicle_costs, false, - "Use same vehicle costs in the routing model"); -ABSL_FLAG(std::string, routing_search_parameters, "", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); - -const char* kTime = "Time"; -const char* kCapacity = "Capacity"; -const int64_t kMaxNodesPerGroup = 10; -const int64_t kSameVehicleCost = 1000; - -int main(int argc, char** argv) { - InitGoogle(argv[0], &argc, &argv, true); - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles)) - << "Specify a non-null vehicle fleet size."; - // VRP of size absl::GetFlag(FLAGS_vrp_size). - // Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and - // ends of the routes are at node 0. - const RoutingIndexManager::NodeIndex kDepot(0); - RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1, - absl::GetFlag(FLAGS_vrp_vehicles), kDepot); - RoutingModel routing(manager); - - // Setting up locations. - const int64_t kXMax = 100000; - const int64_t kYMax = 100000; - const int64_t kSpeed = 10; - LocationContainer locations( - kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders); - ++location) { - locations.AddRandomLocation(kXMax, kYMax); - } - - // Setting the cost function. - const int vehicle_cost = routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.ManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }); - routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost); - - // Adding capacity dimension constraints. - const int64_t kVehicleCapacity = 40; - const int64_t kNullCapacitySlack = 0; - RandomDemand demand(manager.num_nodes(), kDepot, - absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - demand.Initialize(); - routing.AddDimension(routing.RegisterTransitCallback( - [&demand, &manager](int64_t i, int64_t j) { - return demand.Demand(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kNullCapacitySlack, kVehicleCapacity, - /*fix_start_cumul_to_zero=*/true, kCapacity); - - // Adding time dimension constraints. - const int64_t kTimePerDemandUnit = 300; - const int64_t kHorizon = 24 * 3600; - ServiceTimePlusTransition time( - kTimePerDemandUnit, - [&demand](RoutingNodeIndex i, RoutingNodeIndex j) { - return demand.Demand(i, j); - }, - [&locations](RoutingNodeIndex i, RoutingNodeIndex j) { - return locations.ManhattanTime(i, j); - }); - routing.AddDimension( - routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) { - return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j)); - }), - kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime); - const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); - - // Adding disjoint time windows. - Solver* solver = routing.solver(); - std::mt19937 randomizer( - GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); - for (int order = 1; order < manager.num_nodes(); ++order) { - std::vector forbid_points(2 * absl::GetFlag(FLAGS_vrp_windows), 0); - for (int i = 0; i < forbid_points.size(); ++i) { - forbid_points[i] = absl::Uniform(randomizer, 0, kHorizon); - } - std::sort(forbid_points.begin(), forbid_points.end()); - std::vector forbid_starts(1, 0); - std::vector forbid_ends; - for (int i = 0; i < forbid_points.size(); i += 2) { - forbid_ends.push_back(forbid_points[i]); - forbid_starts.push_back(forbid_points[i + 1]); - } - forbid_ends.push_back(kHorizon); - solver->AddConstraint(solver->MakeNotMemberCt( - time_dimension.CumulVar(order), forbid_starts, forbid_ends)); - } - - // Adding penalty costs to allow skipping orders. - const int64_t kPenalty = 10000000; - const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < manager.num_nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); - routing.AddDisjunction(orders, kPenalty); - } - - // Adding same vehicle constraint costs for consecutive nodes. - if (absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs)) { - std::vector group; - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < manager.num_nodes(); ++order) { - group.push_back(manager.NodeToIndex(order)); - if (group.size() == kMaxNodesPerGroup) { - routing.AddSoftSameVehicleConstraint(group, kSameVehicleCost); - group.clear(); - } - } - if (!group.empty()) { - routing.AddSoftSameVehicleConstraint(group, kSameVehicleCost); - } - } - - // Solve, returns a solution if any (owned by RoutingModel). - RoutingSearchParameters parameters = DefaultRoutingSearchParameters(); - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_routing_search_parameters), ¶meters)); - const Assignment* solution = routing.SolveWithParameters(parameters); - if (solution != nullptr) { - DisplayPlan(manager, routing, *solution, - absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs), - kMaxNodesPerGroup, kSameVehicleCost, - routing.GetDimensionOrDie(kCapacity), - routing.GetDimensionOrDie(kTime)); - } else { - LOG(INFO) << "No solution found."; - } - return EXIT_SUCCESS; -} diff --git a/examples/cpp/cvrptw.cc b/examples/cpp/cvrptw.cc deleted file mode 100644 index 28b62699ec..0000000000 --- a/examples/cpp/cvrptw.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// -// Capacitated Vehicle Routing Problem with Time Windows (and optional orders). -// A description of the problem can be found here: -// http://en.wikipedia.org/wiki/Vehicle_routing_problem. -// The variant which is tackled by this model includes a capacity dimension, -// time windows and optional orders, with a penalty cost if orders are not -// performed. For the sake of simplicity, orders are randomly located and -// distances are computed using the Manhattan distance. Distances are assumed -// to be in meters and times in seconds. - -#include -#include - -#include "absl/random/random.h" -#include "examples/cpp/cvrptw_lib.h" -#include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/init_google.h" -#include "ortools/base/types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/constraint_solver/routing_index_manager.h" -#include "ortools/constraint_solver/routing_parameters.h" -#include "ortools/constraint_solver/routing_parameters.pb.h" - -using operations_research::Assignment; -using operations_research::DefaultRoutingSearchParameters; -using operations_research::GetSeed; -using operations_research::LocationContainer; -using operations_research::RandomDemand; -using operations_research::RoutingDimension; -using operations_research::RoutingIndexManager; -using operations_research::RoutingModel; -using operations_research::RoutingNodeIndex; -using operations_research::RoutingSearchParameters; -using operations_research::ServiceTimePlusTransition; - -ABSL_FLAG(int, vrp_orders, 100, "Number of nodes in the problem"); -ABSL_FLAG(int, vrp_vehicles, 20, "Number of vehicles in the problem"); -ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false, - "Use deterministic random seeds"); -ABSL_FLAG(bool, vrp_use_same_vehicle_costs, false, - "Use same vehicle costs in the routing model"); -ABSL_FLAG(std::string, routing_search_parameters, "", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); - -const char* kTime = "Time"; -const char* kCapacity = "Capacity"; -const int64_t kMaxNodesPerGroup = 10; -const int64_t kSameVehicleCost = 1000; - -int main(int argc, char** argv) { - InitGoogle(argv[0], &argc, &argv, true); - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles)) - << "Specify a non-null vehicle fleet size."; - // VRP of size absl::GetFlag(FLAGS_vrp_size). - // Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and - // ends of the routes are at node 0. - const RoutingIndexManager::NodeIndex kDepot(0); - RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1, - absl::GetFlag(FLAGS_vrp_vehicles), kDepot); - RoutingModel routing(manager); - - // Setting up locations. - const int64_t kXMax = 100000; - const int64_t kYMax = 100000; - const int64_t kSpeed = 10; - LocationContainer locations( - kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders); - ++location) { - locations.AddRandomLocation(kXMax, kYMax); - } - - // Setting the cost function. - const int vehicle_cost = routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.ManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }); - routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost); - - // Adding capacity dimension constraints. - const int64_t kVehicleCapacity = 40; - const int64_t kNullCapacitySlack = 0; - RandomDemand demand(manager.num_nodes(), kDepot, - absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - demand.Initialize(); - routing.AddDimension(routing.RegisterTransitCallback( - [&demand, &manager](int64_t i, int64_t j) { - return demand.Demand(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kNullCapacitySlack, kVehicleCapacity, - /*fix_start_cumul_to_zero=*/true, kCapacity); - - // Adding time dimension constraints. - const int64_t kTimePerDemandUnit = 300; - const int64_t kHorizon = 24 * 3600; - ServiceTimePlusTransition time( - kTimePerDemandUnit, - [&demand](RoutingNodeIndex i, RoutingNodeIndex j) { - return demand.Demand(i, j); - }, - [&locations](RoutingNodeIndex i, RoutingNodeIndex j) { - return locations.ManhattanTime(i, j); - }); - routing.AddDimension( - routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) { - return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j)); - }), - kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime); - const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); - - // Adding time windows. - std::mt19937 randomizer( - GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); - const int64_t kTWDuration = 5 * 3600; - for (int order = 1; order < manager.num_nodes(); ++order) { - const int64_t start = - absl::Uniform(randomizer, 0, kHorizon - kTWDuration); - time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration); - } - - // Adding penalty costs to allow skipping orders. - const int64_t kPenalty = 10000000; - const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < manager.num_nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); - routing.AddDisjunction(orders, kPenalty); - } - - // Adding same vehicle constraint costs for consecutive nodes. - if (absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs)) { - std::vector group; - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < manager.num_nodes(); ++order) { - group.push_back(manager.NodeToIndex(order)); - if (group.size() == kMaxNodesPerGroup) { - routing.AddSoftSameVehicleConstraint(group, kSameVehicleCost); - group.clear(); - } - } - if (!group.empty()) { - routing.AddSoftSameVehicleConstraint(group, kSameVehicleCost); - } - } - - // Solve, returns a solution if any (owned by RoutingModel). - RoutingSearchParameters parameters = DefaultRoutingSearchParameters(); - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_routing_search_parameters), ¶meters)); - const Assignment* solution = routing.SolveWithParameters(parameters); - if (solution != nullptr) { - DisplayPlan(manager, routing, *solution, - absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs), - kMaxNodesPerGroup, kSameVehicleCost, - routing.GetDimensionOrDie(kCapacity), - routing.GetDimensionOrDie(kTime)); - } else { - LOG(INFO) << "No solution found."; - } - return EXIT_SUCCESS; -} diff --git a/examples/cpp/cvrptw_lib.h b/examples/cpp/cvrptw_lib.h deleted file mode 100644 index edb6e3a938..0000000000 --- a/examples/cpp/cvrptw_lib.h +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This header provides functions to help creating random instaces of the -// vehicle routing problem; random capacities and random time windows. -#ifndef OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_ -#define OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_ - -#include -#include -#include - -#include "absl/strings/str_format.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/util/random_engine.h" - -namespace operations_research { - -typedef std::function - RoutingNodeEvaluator2; - -// Random seed generator. -int32_t GetSeed(bool deterministic); - -// Location container, contains positions of orders and can be used to obtain -// Manhattan distances/times between locations. -class LocationContainer { - public: - LocationContainer(int64_t speed, bool use_deterministic_seed); - void AddLocation(int64_t x, int64_t y) { - locations_.push_back(Location(x, y)); - } - void AddRandomLocation(int64_t x_max, int64_t y_max); - void AddRandomLocation(int64_t x_max, int64_t y_max, int duplicates); - int64_t ManhattanDistance(RoutingIndexManager::NodeIndex from, - RoutingIndexManager::NodeIndex to) const; - int64_t NegManhattanDistance(RoutingIndexManager::NodeIndex from, - RoutingIndexManager::NodeIndex to) const; - int64_t ManhattanTime(RoutingIndexManager::NodeIndex from, - RoutingIndexManager::NodeIndex to) const; - - bool SameLocation(RoutingIndexManager::NodeIndex node1, - RoutingIndexManager::NodeIndex node2) const; - int64_t SameLocationFromIndex(int64_t node1, int64_t node2) const; - - private: - class Location { - public: - Location(); - Location(int64_t x, int64_t y); - int64_t DistanceTo(const Location& location) const; - bool IsAtSameLocation(const Location& location) const; - - private: - static int64_t Abs(int64_t value); - - int64_t x_; - int64_t y_; - }; - - random_engine_t randomizer_; - const int64_t speed_; - absl::StrongVector locations_; -}; - -// Random demand. -class RandomDemand { - public: - RandomDemand(int size, RoutingIndexManager::NodeIndex depot, - bool use_deterministic_seed); - void Initialize(); - int64_t Demand(RoutingIndexManager::NodeIndex from, - RoutingIndexManager::NodeIndex to) const; - - private: - std::unique_ptr demand_; - const int size_; - const RoutingIndexManager::NodeIndex depot_; - const bool use_deterministic_seed_; -}; - -// Service time (proportional to demand) + transition time callback. -class ServiceTimePlusTransition { - public: - ServiceTimePlusTransition( - int64_t time_per_demand_unit, - operations_research::RoutingNodeEvaluator2 demand, - operations_research::RoutingNodeEvaluator2 transition_time); - int64_t Compute(RoutingIndexManager::NodeIndex from, - RoutingIndexManager::NodeIndex to) const; - - private: - const int64_t time_per_demand_unit_; - operations_research::RoutingNodeEvaluator2 demand_; - operations_research::RoutingNodeEvaluator2 transition_time_; -}; - -// Stop service time + transition time callback. -class StopServiceTimePlusTransition { - public: - StopServiceTimePlusTransition( - int64_t stop_time, const LocationContainer& location_container, - operations_research::RoutingNodeEvaluator2 transition_time); - int64_t Compute(RoutingIndexManager::NodeIndex from, - RoutingIndexManager::NodeIndex to) const; - - private: - const int64_t stop_time_; - const LocationContainer& location_container_; - operations_research::RoutingNodeEvaluator2 demand_; - operations_research::RoutingNodeEvaluator2 transition_time_; -}; - -// Route plan displayer. -// TODO(user): Move the display code to the routing library. -void DisplayPlan( - const operations_research::RoutingIndexManager& manager, - const operations_research::RoutingModel& routing, - const operations_research::Assignment& plan, bool use_same_vehicle_costs, - int64_t max_nodes_per_group, int64_t same_vehicle_cost, - const operations_research::RoutingDimension& capacity_dimension, - const operations_research::RoutingDimension& time_dimension); - -using NodeIndex = RoutingIndexManager::NodeIndex; - -int32_t GetSeed(bool deterministic) { - if (deterministic) { - return 0; - } else { - return std::random_device()(); - } -} - -LocationContainer::LocationContainer(int64_t speed, bool use_deterministic_seed) - : randomizer_(GetSeed(use_deterministic_seed)), speed_(speed) { - CHECK_LT(0, speed_); -} - -void LocationContainer::AddRandomLocation(int64_t x_max, int64_t y_max) { - AddRandomLocation(x_max, y_max, 1); -} - -void LocationContainer::AddRandomLocation(int64_t x_max, int64_t y_max, - int duplicates) { - const int64_t x = absl::Uniform(randomizer_, 0, x_max + 1); - const int64_t y = absl::Uniform(randomizer_, 0, y_max + 1); - for (int i = 0; i < duplicates; ++i) { - AddLocation(x, y); - } -} - -int64_t LocationContainer::ManhattanDistance(NodeIndex from, - NodeIndex to) const { - return locations_[from].DistanceTo(locations_[to]); -} - -int64_t LocationContainer::NegManhattanDistance(NodeIndex from, - NodeIndex to) const { - return -ManhattanDistance(from, to); -} - -int64_t LocationContainer::ManhattanTime(NodeIndex from, NodeIndex to) const { - return ManhattanDistance(from, to) / speed_; -} - -bool LocationContainer::SameLocation(NodeIndex node1, NodeIndex node2) const { - if (node1 < locations_.size() && node2 < locations_.size()) { - return locations_[node1].IsAtSameLocation(locations_[node2]); - } - return false; -} -int64_t LocationContainer::SameLocationFromIndex(int64_t node1, - int64_t node2) const { - // The direct conversion from constraint model indices to routing model - // nodes is correct because the depot is node 0. - // TODO(user): Fetch proper indices from routing model. - return SameLocation(NodeIndex(node1), NodeIndex(node2)); -} - -LocationContainer::Location::Location() : x_(0), y_(0) {} - -LocationContainer::Location::Location(int64_t x, int64_t y) : x_(x), y_(y) {} - -int64_t LocationContainer::Location::DistanceTo( - const Location& location) const { - return Abs(x_ - location.x_) + Abs(y_ - location.y_); -} - -bool LocationContainer::Location::IsAtSameLocation( - const Location& location) const { - return x_ == location.x_ && y_ == location.y_; -} - -int64_t LocationContainer::Location::Abs(int64_t value) { - return std::max(value, -value); -} - -RandomDemand::RandomDemand(int size, NodeIndex depot, - bool use_deterministic_seed) - : size_(size), - depot_(depot), - use_deterministic_seed_(use_deterministic_seed) { - CHECK_LT(0, size_); -} - -void RandomDemand::Initialize() { - const int64_t kDemandMax = 5; - const int64_t kDemandMin = 1; - demand_ = absl::make_unique(size_); - random_engine_t randomizer; - for (int order = 0; order < size_; ++order) { - if (order == depot_) { - demand_[order] = 0; - } else { - demand_[order] = kDemandMin + absl::Uniform(randomizer, 0, - kDemandMax - kDemandMin + 1); - } - } -} - -int64_t RandomDemand::Demand(NodeIndex from, NodeIndex /*to*/) const { - return demand_[from.value()]; -} - -ServiceTimePlusTransition::ServiceTimePlusTransition( - int64_t time_per_demand_unit, RoutingNodeEvaluator2 demand, - RoutingNodeEvaluator2 transition_time) - : time_per_demand_unit_(time_per_demand_unit), - demand_(std::move(demand)), - transition_time_(std::move(transition_time)) {} - -int64_t ServiceTimePlusTransition::Compute(NodeIndex from, NodeIndex to) const { - return time_per_demand_unit_ * demand_(from, to) + transition_time_(from, to); -} - -StopServiceTimePlusTransition::StopServiceTimePlusTransition( - int64_t stop_time, const LocationContainer& location_container, - RoutingNodeEvaluator2 transition_time) - : stop_time_(stop_time), - location_container_(location_container), - transition_time_(std::move(transition_time)) {} - -int64_t StopServiceTimePlusTransition::Compute(NodeIndex from, - NodeIndex to) const { - return location_container_.SameLocation(from, to) - ? 0 - : stop_time_ + transition_time_(from, to); -} - -void DisplayPlan( - const RoutingIndexManager& manager, const RoutingModel& routing, - const operations_research::Assignment& plan, bool use_same_vehicle_costs, - int64_t max_nodes_per_group, int64_t same_vehicle_cost, - const operations_research::RoutingDimension& capacity_dimension, - const operations_research::RoutingDimension& time_dimension) { - // Display plan cost. - std::string plan_output = absl::StrFormat("Cost %d\n", plan.ObjectiveValue()); - - // Display dropped orders. - std::string dropped; - for (int64_t order = 0; order < routing.Size(); ++order) { - if (routing.IsStart(order) || routing.IsEnd(order)) continue; - if (plan.Value(routing.NextVar(order)) == order) { - if (dropped.empty()) { - absl::StrAppendFormat(&dropped, " %d", - manager.IndexToNode(order).value()); - } else { - absl::StrAppendFormat(&dropped, ", %d", - manager.IndexToNode(order).value()); - } - } - } - if (!dropped.empty()) { - plan_output += "Dropped orders:" + dropped + "\n"; - } - - if (use_same_vehicle_costs) { - int group_size = 0; - int64_t group_same_vehicle_cost = 0; - std::set visited; - for (int64_t order = 0; order < routing.Size(); ++order) { - if (routing.IsStart(order) || routing.IsEnd(order)) continue; - ++group_size; - visited.insert(plan.Value(routing.VehicleVar(order))); - if (group_size == max_nodes_per_group) { - if (visited.size() > 1) { - group_same_vehicle_cost += (visited.size() - 1) * same_vehicle_cost; - } - group_size = 0; - visited.clear(); - } - } - if (visited.size() > 1) { - group_same_vehicle_cost += (visited.size() - 1) * same_vehicle_cost; - } - LOG(INFO) << "Same vehicle costs: " << group_same_vehicle_cost; - } - - // Display actual output for each vehicle. - for (int route_number = 0; route_number < routing.vehicles(); - ++route_number) { - int64_t order = routing.Start(route_number); - absl::StrAppendFormat(&plan_output, "Route %d: ", route_number); - if (routing.IsEnd(plan.Value(routing.NextVar(order)))) { - plan_output += "Empty\n"; - } else { - while (true) { - operations_research::IntVar* const load_var = - capacity_dimension.CumulVar(order); - operations_research::IntVar* const time_var = - time_dimension.CumulVar(order); - operations_research::IntVar* const slack_var = - routing.IsEnd(order) ? nullptr : time_dimension.SlackVar(order); - if (slack_var != nullptr && plan.Contains(slack_var)) { - absl::StrAppendFormat( - &plan_output, "%d Load(%d) Time(%d, %d) Slack(%d, %d)", - manager.IndexToNode(order).value(), plan.Value(load_var), - plan.Min(time_var), plan.Max(time_var), plan.Min(slack_var), - plan.Max(slack_var)); - } else { - absl::StrAppendFormat(&plan_output, "%d Load(%d) Time(%d, %d)", - manager.IndexToNode(order).value(), - plan.Value(load_var), plan.Min(time_var), - plan.Max(time_var)); - } - if (routing.IsEnd(order)) break; - plan_output += " -> "; - order = plan.Value(routing.NextVar(order)); - } - plan_output += "\n"; - } - } - LOG(INFO) << plan_output; -} -} // namespace operations_research - -#endif // OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_ diff --git a/examples/cpp/cvrptw_with_breaks.cc b/examples/cpp/cvrptw_with_breaks.cc deleted file mode 100644 index 25d790fa01..0000000000 --- a/examples/cpp/cvrptw_with_breaks.cc +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// -// Capacitated Vehicle Routing Problem with Time Windows and Breaks. -// A description of the Capacitated Vehicle Routing Problem with Time Windows -// can be found here: -// http://en.wikipedia.org/wiki/Vehicle_routing_problem. -// The variant which is tackled by this model includes a capacity dimension, -// time windows and optional orders, with a penalty cost if orders are not -// performed. For the sake of simplicty, orders are randomly located and -// distances are computed using the Manhattan distance. Distances are assumed -// to be in meters and times in seconds. -// This variant also includes vehicle breaks which must happen during the day -// with two alternate breaks schemes: either a long break in the middle of the -// day or two smaller ones which can be taken during a longer period of the day. - -#include -#include - -#include "absl/random/random.h" -#include "absl/strings/str_cat.h" -#include "examples/cpp/cvrptw_lib.h" -#include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/init_google.h" -#include "ortools/base/types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/constraint_solver/routing_enums.pb.h" -#include "ortools/constraint_solver/routing_index_manager.h" -#include "ortools/constraint_solver/routing_parameters.h" -#include "ortools/constraint_solver/routing_parameters.pb.h" - -using operations_research::Assignment; -using operations_research::DefaultRoutingSearchParameters; -using operations_research::FirstSolutionStrategy; -using operations_research::GetSeed; -using operations_research::IntervalVar; -using operations_research::LocationContainer; -using operations_research::RandomDemand; -using operations_research::RoutingDimension; -using operations_research::RoutingIndexManager; -using operations_research::RoutingModel; -using operations_research::RoutingNodeIndex; -using operations_research::RoutingSearchParameters; -using operations_research::ServiceTimePlusTransition; -using operations_research::Solver; - -ABSL_FLAG(int, vrp_orders, 100, "Nodes in the problem."); -ABSL_FLAG(int, vrp_vehicles, 20, - "Size of Traveling Salesman Problem instance."); -ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false, - "Use deterministic random seeds."); -ABSL_FLAG(std::string, routing_search_parameters, "", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); - -const char* kTime = "Time"; -const char* kCapacity = "Capacity"; - -int main(int argc, char** argv) { - InitGoogle(argv[0], &argc, &argv, true); - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles)) - << "Specify a non-null vehicle fleet size."; - // VRP of size absl::GetFlag(FLAGS_vrp_size). - // Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and - // ends of the routes are at node 0. - const RoutingIndexManager::NodeIndex kDepot(0); - RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1, - absl::GetFlag(FLAGS_vrp_vehicles), kDepot); - RoutingModel routing(manager); - RoutingSearchParameters parameters = DefaultRoutingSearchParameters(); - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_routing_search_parameters), ¶meters)); - parameters.set_first_solution_strategy( - FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION); - - // Setting up locations. - const int64_t kXMax = 100000; - const int64_t kYMax = 100000; - const int64_t kSpeed = 10; - LocationContainer locations( - kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders); - ++location) { - locations.AddRandomLocation(kXMax, kYMax); - } - - // Setting the cost function. - const int vehicle_cost = routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.ManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }); - routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost); - - // Adding capacity dimension constraints. - const int64_t kVehicleCapacity = 40; - const int64_t kNullCapacitySlack = 0; - RandomDemand demand(manager.num_nodes(), kDepot, - absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - demand.Initialize(); - routing.AddDimension(routing.RegisterTransitCallback( - [&demand, &manager](int64_t i, int64_t j) { - return demand.Demand(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kNullCapacitySlack, kVehicleCapacity, - /*fix_start_cumul_to_zero=*/true, kCapacity); - - // Adding time dimension constraints. - const int64_t kTimePerDemandUnit = 300; - const int64_t kHorizon = 24 * 3600; - ServiceTimePlusTransition time( - kTimePerDemandUnit, - [&demand](RoutingNodeIndex i, RoutingNodeIndex j) { - return demand.Demand(i, j); - }, - [&locations](RoutingNodeIndex i, RoutingNodeIndex j) { - return locations.ManhattanTime(i, j); - }); - routing.AddDimension( - routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) { - return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j)); - }), - kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime); - RoutingDimension* const time_dimension = routing.GetMutableDimension(kTime); - - // Adding time windows. - std::mt19937 randomizer( - GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); - const int64_t kTWDuration = 5 * 3600; - for (int order = 1; order < manager.num_nodes(); ++order) { - const int64_t start = - absl::Uniform(randomizer, 0, kHorizon - kTWDuration); - time_dimension->CumulVar(order)->SetRange(start, start + kTWDuration); - routing.AddToAssignment(time_dimension->SlackVar(order)); - } - - // Minimize time variables. - for (int i = 0; i < routing.Size(); ++i) { - routing.AddVariableMinimizedByFinalizer(time_dimension->CumulVar(i)); - } - for (int j = 0; j < absl::GetFlag(FLAGS_vrp_vehicles); ++j) { - routing.AddVariableMinimizedByFinalizer( - time_dimension->CumulVar(routing.Start(j))); - routing.AddVariableMinimizedByFinalizer( - time_dimension->CumulVar(routing.End(j))); - } - - // Adding vehicle breaks: - // - 40min breaks between 11:00am and 1:00pm - // or - // - 2 x 30min breaks between 10:00am and 3:00pm, at least 1h apart - // First, fill service time vector. - std::vector service_times(routing.Size()); - for (int node = 0; node < routing.Size(); node++) { - if (node >= routing.nodes()) { - service_times[node] = 0; - } else { - const RoutingIndexManager::NodeIndex index(node); - service_times[node] = kTimePerDemandUnit * demand.Demand(index, index); - } - } - const std::vector> break_data = { - {/*start_min*/ 11, /*start_max*/ 13, /*duration*/ 2400}, - {/*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800}, - {/*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800}}; - Solver* const solver = routing.solver(); - for (int vehicle = 0; vehicle < absl::GetFlag(FLAGS_vrp_vehicles); - ++vehicle) { - std::vector breaks; - for (int i = 0; i < break_data.size(); ++i) { - IntervalVar* const break_interval = solver->MakeFixedDurationIntervalVar( - break_data[i][0] * 3600, break_data[i][1] * 3600, break_data[i][2], - true, absl::StrCat("Break ", i, " on vehicle ", vehicle)); - breaks.push_back(break_interval); - } - // break1 performed iff break2 performed - solver->AddConstraint(solver->MakeEquality(breaks[1]->PerformedExpr(), - breaks[2]->PerformedExpr())); - // break2 start 1h after break1. - solver->AddConstraint(solver->MakeIntervalVarRelationWithDelay( - breaks[2], Solver::STARTS_AFTER_END, breaks[1], 3600)); - // break0 performed iff break2 unperformed - solver->AddConstraint(solver->MakeNonEquality(breaks[0]->PerformedExpr(), - breaks[2]->PerformedExpr())); - - time_dimension->SetBreakIntervalsOfVehicle(std::move(breaks), vehicle, - service_times); - } - - // Adding penalty costs to allow skipping orders. - const int64_t kPenalty = 10000000; - const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); - routing.AddDisjunction(orders, kPenalty); - } - - // Solve, returns a solution if any (owned by RoutingModel). - const Assignment* solution = routing.SolveWithParameters(parameters); - if (solution != nullptr) { - LOG(INFO) << "Breaks: "; - for (const auto& break_interval : - solution->IntervalVarContainer().elements()) { - if (break_interval.PerformedValue() == 1) { - LOG(INFO) << break_interval.Var()->name() << " " - << break_interval.DebugString(); - } else { - LOG(INFO) << break_interval.Var()->name() << " unperformed"; - } - } - DisplayPlan(manager, routing, *solution, false, 0, 0, - routing.GetDimensionOrDie(kCapacity), - routing.GetDimensionOrDie(kTime)); - } else { - LOG(INFO) << "No solution found."; - } - return EXIT_SUCCESS; -} diff --git a/examples/cpp/cvrptw_with_refueling.cc b/examples/cpp/cvrptw_with_refueling.cc deleted file mode 100644 index 5464467771..0000000000 --- a/examples/cpp/cvrptw_with_refueling.cc +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Capacitated Vehicle Routing Problem with Time Windows and refueling -// constraints. -// This is an extension to the model in cvrptw.cc so refer to that file for -// more information on the common part of the model. The model implemented here -// takes into account refueling constraints using a specific dimension: vehicles -// must visit certain nodes (refueling nodes) before the quantity of fuel -// reaches zero. Fuel consumption is proportional to the distance traveled. - -#include -#include - -#include "absl/random/random.h" -#include "examples/cpp/cvrptw_lib.h" -#include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/init_google.h" -#include "ortools/base/types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/constraint_solver/routing_index_manager.h" -#include "ortools/constraint_solver/routing_parameters.h" -#include "ortools/constraint_solver/routing_parameters.pb.h" - -using operations_research::Assignment; -using operations_research::DefaultRoutingSearchParameters; -using operations_research::GetSeed; -using operations_research::LocationContainer; -using operations_research::RandomDemand; -using operations_research::RoutingDimension; -using operations_research::RoutingIndexManager; -using operations_research::RoutingModel; -using operations_research::RoutingNodeIndex; -using operations_research::RoutingSearchParameters; -using operations_research::ServiceTimePlusTransition; - -ABSL_FLAG(int, vrp_orders, 100, "Nodes in the problem."); -ABSL_FLAG(int, vrp_vehicles, 20, - "Size of Traveling Salesman Problem instance."); -ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false, - "Use deterministic random seeds."); -ABSL_FLAG(std::string, routing_search_parameters, "", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); - -const char* kTime = "Time"; -const char* kCapacity = "Capacity"; -const char* kFuel = "Fuel"; - -// Returns true if node is a refueling node (based on node / refuel node ratio). -bool IsRefuelNode(int64_t node) { - const int64_t kRefuelNodeRatio = 10; - return (node % kRefuelNodeRatio == 0); -} - -int main(int argc, char** argv) { - InitGoogle(argv[0], &argc, &argv, true); - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles)) - << "Specify a non-null vehicle fleet size."; - // VRP of size absl::GetFlag(FLAGS_vrp_size). - // Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and - // ends of the routes are at node 0. - const RoutingIndexManager::NodeIndex kDepot(0); - RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1, - absl::GetFlag(FLAGS_vrp_vehicles), kDepot); - RoutingModel routing(manager); - - // Setting up locations. - const int64_t kXMax = 100000; - const int64_t kYMax = 100000; - const int64_t kSpeed = 10; - LocationContainer locations( - kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders); - ++location) { - locations.AddRandomLocation(kXMax, kYMax); - } - - // Setting the cost function. - const int vehicle_cost = routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.ManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }); - routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost); - - // Adding capacity dimension constraints. - const int64_t kVehicleCapacity = 40; - const int64_t kNullCapacitySlack = 0; - RandomDemand demand(manager.num_nodes(), kDepot, - absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - demand.Initialize(); - routing.AddDimension(routing.RegisterTransitCallback( - [&demand, &manager](int64_t i, int64_t j) { - return demand.Demand(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kNullCapacitySlack, kVehicleCapacity, - /*fix_start_cumul_to_zero=*/true, kCapacity); - - // Adding time dimension constraints. - const int64_t kTimePerDemandUnit = 300; - const int64_t kHorizon = 24 * 3600; - ServiceTimePlusTransition time( - kTimePerDemandUnit, - [&demand](RoutingNodeIndex i, RoutingNodeIndex j) { - return demand.Demand(i, j); - }, - [&locations](RoutingNodeIndex i, RoutingNodeIndex j) { - return locations.ManhattanTime(i, j); - }); - routing.AddDimension( - routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) { - return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j)); - }), - kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime); - const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); - // Adding time windows. - // NOTE(user): This randomized test case is quite sensible to the seed: - // the generated model can be much easier or harder to solve, depending on - // the seed. It turns out that most seeds yield pretty slow/bad solver - // performance: I got good performance for about 10% of the seeds. - std::mt19937 randomizer( - 144 + GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); - const int64_t kTWDuration = 5 * 3600; - for (int order = 1; order < manager.num_nodes(); ++order) { - if (!IsRefuelNode(order)) { - const int64_t start = - absl::Uniform(randomizer, 0, kHorizon - kTWDuration); - time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration); - } - } - - // Adding fuel dimension. This dimension consumes a quantity equal to the - // distance traveled. Only refuel nodes can make the quantity of dimension - // increase by letting slack variable replenish the fuel. - const int64_t kFuelCapacity = kXMax + kYMax; - routing.AddDimension( - routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.NegManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kFuelCapacity, kFuelCapacity, /*fix_start_cumul_to_zero=*/false, kFuel); - const RoutingDimension& fuel_dimension = routing.GetDimensionOrDie(kFuel); - for (int order = 0; order < routing.Size(); ++order) { - // Only let slack free for refueling nodes. - if (!IsRefuelNode(order) || routing.IsStart(order)) { - fuel_dimension.SlackVar(order)->SetValue(0); - } - // Needed to instantiate fuel quantity at each node. - routing.AddVariableMinimizedByFinalizer(fuel_dimension.CumulVar(order)); - } - - // Adding penalty costs to allow skipping orders. - const int64_t kPenalty = 100000; - const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); - routing.AddDisjunction(orders, kPenalty); - } - - // Solve, returns a solution if any (owned by RoutingModel). - RoutingSearchParameters parameters = DefaultRoutingSearchParameters(); - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_routing_search_parameters), ¶meters)); - const Assignment* solution = routing.SolveWithParameters(parameters); - if (solution != nullptr) { - DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false, - /*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0, - routing.GetDimensionOrDie(kCapacity), - routing.GetDimensionOrDie(kTime)); - } else { - LOG(INFO) << "No solution found."; - } - return EXIT_SUCCESS; -} diff --git a/examples/cpp/cvrptw_with_resources.cc b/examples/cpp/cvrptw_with_resources.cc deleted file mode 100644 index 5171c781a1..0000000000 --- a/examples/cpp/cvrptw_with_resources.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Capacitated Vehicle Routing Problem with Time Windows and capacitated -// resources. -// This is an extension to the model in cvrptw.cc so refer to that file for -// more information on the common part of the model. The model implemented here -// limits the number of vehicles which can simultaneously leave or enter the -// depot due to limited resources (or capacity) available. -// TODO(user): The current model consumes resources even for vehicles with -// empty routes; fix this when we have an API on the cumulative constraints -// with variable demands. - -#include -#include - -#include "absl/random/random.h" -#include "examples/cpp/cvrptw_lib.h" -#include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/init_google.h" -#include "ortools/base/types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/constraint_solver/routing_index_manager.h" -#include "ortools/constraint_solver/routing_parameters.h" -#include "ortools/constraint_solver/routing_parameters.pb.h" - -using operations_research::Assignment; -using operations_research::DefaultRoutingSearchParameters; -using operations_research::GetSeed; -using operations_research::IntervalVar; -using operations_research::IntVar; -using operations_research::LocationContainer; -using operations_research::RandomDemand; -using operations_research::RoutingDimension; -using operations_research::RoutingIndexManager; -using operations_research::RoutingModel; -using operations_research::RoutingNodeIndex; -using operations_research::RoutingSearchParameters; -using operations_research::ServiceTimePlusTransition; -using operations_research::Solver; - -ABSL_FLAG(int, vrp_orders, 100, "Nodes in the problem."); -ABSL_FLAG(int, vrp_vehicles, 20, - "Size of Traveling Salesman Problem instance."); -ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false, - "Use deterministic random seeds."); -ABSL_FLAG(std::string, routing_search_parameters, "", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); - -const char* kTime = "Time"; -const char* kCapacity = "Capacity"; - -int main(int argc, char** argv) { - InitGoogle(argv[0], &argc, &argv, true); - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles)) - << "Specify a non-null vehicle fleet size."; - // VRP of size absl::GetFlag(FLAGS_vrp_size). - // Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and - // ends of the routes are at node 0. - const RoutingIndexManager::NodeIndex kDepot(0); - RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1, - absl::GetFlag(FLAGS_vrp_vehicles), kDepot); - RoutingModel routing(manager); - - // Setting up locations. - const int64_t kXMax = 100000; - const int64_t kYMax = 100000; - const int64_t kSpeed = 10; - LocationContainer locations( - kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders); - ++location) { - locations.AddRandomLocation(kXMax, kYMax); - } - - // Setting the cost function. - const int vehicle_cost = routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.ManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }); - routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost); - - // Adding capacity dimension constraints. - const int64_t kVehicleCapacity = 40; - const int64_t kNullCapacitySlack = 0; - RandomDemand demand(manager.num_nodes(), kDepot, - absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - demand.Initialize(); - routing.AddDimension(routing.RegisterTransitCallback( - [&demand, &manager](int64_t i, int64_t j) { - return demand.Demand(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kNullCapacitySlack, kVehicleCapacity, - /*fix_start_cumul_to_zero=*/true, kCapacity); - - // Adding time dimension constraints. - const int64_t kTimePerDemandUnit = 300; - const int64_t kHorizon = 24 * 3600; - ServiceTimePlusTransition time( - kTimePerDemandUnit, - [&demand](RoutingNodeIndex i, RoutingNodeIndex j) { - return demand.Demand(i, j); - }, - [&locations](RoutingNodeIndex i, RoutingNodeIndex j) { - return locations.ManhattanTime(i, j); - }); - routing.AddDimension( - routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) { - return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j)); - }), - kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime); - const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); - - // Adding time windows. - std::mt19937 randomizer( - GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); - const int64_t kTWDuration = 5 * 3600; - for (int order = 1; order < manager.num_nodes(); ++order) { - const int64_t start = - absl::Uniform(randomizer, 0, kHorizon - kTWDuration); - time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration); - } - - // Adding resource constraints at the depot (start and end location of - // routes). - std::vector start_end_times; - for (int i = 0; i < absl::GetFlag(FLAGS_vrp_vehicles); ++i) { - start_end_times.push_back(time_dimension.CumulVar(routing.End(i))); - start_end_times.push_back(time_dimension.CumulVar(routing.Start(i))); - } - // Build corresponding time intervals. - const int64_t kVehicleSetup = 180; - Solver* const solver = routing.solver(); - std::vector intervals; - solver->MakeFixedDurationIntervalVarArray(start_end_times, kVehicleSetup, - "depot_interval", &intervals); - // Constrain the number of maximum simultaneous intervals at depot. - const int64_t kDepotCapacity = 5; - std::vector depot_usage(start_end_times.size(), 1); - solver->AddConstraint( - solver->MakeCumulative(intervals, depot_usage, kDepotCapacity, "depot")); - // Instantiate route start and end times to produce feasible times. - for (int i = 0; i < start_end_times.size(); ++i) { - routing.AddVariableMinimizedByFinalizer(start_end_times[i]); - } - - // Adding penalty costs to allow skipping orders. - const int64_t kPenalty = 100000; - const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < manager.num_nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); - routing.AddDisjunction(orders, kPenalty); - } - - // Solve, returns a solution if any (owned by RoutingModel). - RoutingSearchParameters parameters = DefaultRoutingSearchParameters(); - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_routing_search_parameters), ¶meters)); - const Assignment* solution = routing.SolveWithParameters(parameters); - if (solution != nullptr) { - DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false, - /*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0, - routing.GetDimensionOrDie(kCapacity), - routing.GetDimensionOrDie(kTime)); - } else { - LOG(INFO) << "No solution found."; - } - return EXIT_SUCCESS; -} diff --git a/examples/cpp/cvrptw_with_stop_times_and_resources.cc b/examples/cpp/cvrptw_with_stop_times_and_resources.cc deleted file mode 100644 index d1c494638b..0000000000 --- a/examples/cpp/cvrptw_with_stop_times_and_resources.cc +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2010-2024 Google LLC -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Capacitated Vehicle Routing Problem with Time Windows, fixed stop times and -// capacitated resources. A stop is defined as consecutive nodes at the same -// location. -// This is an extension to the model in cvrptw.cc so refer to that file for -// more information on the common part of the model. The model implemented here -// limits the number of vehicles which can simultaneously leave or enter a node -// to one. - -#include -#include - -#include "absl/random/random.h" -#include "absl/strings/str_cat.h" -#include "examples/cpp/cvrptw_lib.h" -#include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/init_google.h" -#include "ortools/base/types.h" -#include "ortools/base/logging.h" -#include "ortools/constraint_solver/routing.h" -#include "ortools/constraint_solver/routing_index_manager.h" -#include "ortools/constraint_solver/routing_parameters.h" -#include "ortools/constraint_solver/routing_parameters.pb.h" - -using operations_research::Assignment; -using operations_research::DefaultRoutingSearchParameters; -using operations_research::GetSeed; -using operations_research::IntervalVar; -using operations_research::IntVar; -using operations_research::LocationContainer; -using operations_research::RandomDemand; -using operations_research::RoutingDimension; -using operations_research::RoutingIndexManager; -using operations_research::RoutingModel; -using operations_research::RoutingNodeIndex; -using operations_research::RoutingSearchParameters; -using operations_research::Solver; -using operations_research::StopServiceTimePlusTransition; - -ABSL_FLAG(int, vrp_stops, 25, "Stop locations in the problem."); -ABSL_FLAG(int, vrp_orders_per_stop, 5, "Nodes for each stop."); -ABSL_FLAG(int, vrp_vehicles, 20, - "Size of Traveling Salesman Problem instance."); -ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false, - "Use deterministic random seeds."); -ABSL_FLAG(std::string, routing_search_parameters, "", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); - -const char* kTime = "Time"; -const char* kCapacity = "Capacity"; - -int main(int argc, char** argv) { - InitGoogle(argv[0], &argc, &argv, true); - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_stops)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders_per_stop)) - << "Specify an instance size greater than 0."; - CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles)) - << "Specify a non-null vehicle fleet size."; - const int vrp_orders = - absl::GetFlag(FLAGS_vrp_stops) * absl::GetFlag(FLAGS_vrp_orders_per_stop); - // Nodes are indexed from 0 to vrp_orders, the starts and ends of the routes - // are at node 0. - const RoutingIndexManager::NodeIndex kDepot(0); - RoutingIndexManager manager(vrp_orders + 1, absl::GetFlag(FLAGS_vrp_vehicles), - kDepot); - RoutingModel routing(manager); - - // Setting up locations. - const int64_t kXMax = 100000; - const int64_t kYMax = 100000; - const int64_t kSpeed = 10; - LocationContainer locations( - kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - for (int stop = 0; stop <= absl::GetFlag(FLAGS_vrp_stops); ++stop) { - const int num_orders = - stop == 0 ? 1 : absl::GetFlag(FLAGS_vrp_orders_per_stop); - locations.AddRandomLocation(kXMax, kYMax, num_orders); - } - - // Setting the cost function. - const int vehicle_cost = routing.RegisterTransitCallback( - [&locations, &manager](int64_t i, int64_t j) { - return locations.ManhattanDistance(manager.IndexToNode(i), - manager.IndexToNode(j)); - }); - routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost); - - // Adding capacity dimension constraints. - const int64_t kVehicleCapacity = 40; - const int64_t kNullCapacitySlack = 0; - RandomDemand demand(manager.num_nodes(), kDepot, - absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)); - demand.Initialize(); - routing.AddDimension(routing.RegisterTransitCallback( - [&demand, &manager](int64_t i, int64_t j) { - return demand.Demand(manager.IndexToNode(i), - manager.IndexToNode(j)); - }), - kNullCapacitySlack, kVehicleCapacity, - /*fix_start_cumul_to_zero=*/true, kCapacity); - - // Adding time dimension constraints. - const int64_t kStopTime = 300; - const int64_t kHorizon = 24 * 3600; - StopServiceTimePlusTransition time( - kStopTime, locations, - [&locations](RoutingNodeIndex i, RoutingNodeIndex j) { - return locations.ManhattanTime(i, j); - }); - routing.AddDimension( - routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) { - return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j)); - }), - kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime); - const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); - - // Adding time windows, for the sake of simplicty same for each stop. - std::mt19937 randomizer( - GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); - const int64_t kTWDuration = 5 * 3600; - for (int stop = 0; stop < absl::GetFlag(FLAGS_vrp_stops); ++stop) { - const int64_t start = - absl::Uniform(randomizer, 0, kHorizon - kTWDuration); - for (int stop_order = 0; - stop_order < absl::GetFlag(FLAGS_vrp_orders_per_stop); ++stop_order) { - const int order = - stop * absl::GetFlag(FLAGS_vrp_orders_per_stop) + stop_order + 1; - time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration); - } - } - - // Adding resource constraints at order locations. - Solver* const solver = routing.solver(); - std::vector intervals; - for (int stop = 0; stop < absl::GetFlag(FLAGS_vrp_stops); ++stop) { - std::vector stop_intervals; - for (int stop_order = 0; - stop_order < absl::GetFlag(FLAGS_vrp_orders_per_stop); ++stop_order) { - const int order = - stop * absl::GetFlag(FLAGS_vrp_orders_per_stop) + stop_order + 1; - IntervalVar* const interval = solver->MakeFixedDurationIntervalVar( - 0, kHorizon, kStopTime, true, absl::StrCat("Order", order)); - intervals.push_back(interval); - stop_intervals.push_back(interval); - // Link order and interval. - IntVar* const order_start = time_dimension.CumulVar(order); - solver->AddConstraint( - solver->MakeIsEqualCt(interval->SafeStartExpr(0), order_start, - interval->PerformedExpr()->Var())); - // Make interval performed iff corresponding order has service time. - // An order has no service time iff it is at the same location as the - // next order on the route. - IntVar* const is_null_duration = - solver - ->MakeElement( - [&locations, order](int64_t index) { - return locations.SameLocationFromIndex(order, index); - }, - routing.NextVar(order)) - ->Var(); - solver->AddConstraint( - solver->MakeNonEquality(interval->PerformedExpr(), is_null_duration)); - routing.AddIntervalToAssignment(interval); - // We are minimizing route durations by minimizing route ends; so we can - // maximize order starts to pack them together. - routing.AddVariableMaximizedByFinalizer(order_start); - } - // Only one order can happen at the same time at a given location. - std::vector location_usage(stop_intervals.size(), 1); - solver->AddConstraint(solver->MakeCumulative( - stop_intervals, location_usage, 1, absl::StrCat("Client", stop))); - } - // Minimizing route duration. - for (int vehicle = 0; vehicle < manager.num_vehicles(); ++vehicle) { - routing.AddVariableMinimizedByFinalizer( - time_dimension.CumulVar(routing.End(vehicle))); - } - - // Adding penalty costs to allow skipping orders. - const int64_t kPenalty = 100000; - const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1); - for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot; - order < routing.nodes(); ++order) { - std::vector orders(1, manager.NodeToIndex(order)); - routing.AddDisjunction(orders, kPenalty); - } - - // Solve, returns a solution if any (owned by RoutingModel). - RoutingSearchParameters parameters = DefaultRoutingSearchParameters(); - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_routing_search_parameters), ¶meters)); - const Assignment* solution = routing.SolveWithParameters(parameters); - if (solution != nullptr) { - DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false, - /*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0, - routing.GetDimensionOrDie(kCapacity), - routing.GetDimensionOrDie(kTime)); - LOG(INFO) << "Stop intervals:"; - for (IntervalVar* const interval : intervals) { - if (solution->PerformedValue(interval)) { - LOG(INFO) << interval->name() << ": " << solution->StartValue(interval); - } - } - } else { - LOG(INFO) << "No solution found."; - } - return EXIT_SUCCESS; -} diff --git a/examples/cpp/frequency_assignment_problem.cc b/examples/cpp/frequency_assignment_problem.cc index 72914889ee..626e5aec5e 100644 --- a/examples/cpp/frequency_assignment_problem.cc +++ b/examples/cpp/frequency_assignment_problem.cc @@ -54,6 +54,7 @@ #include "absl/container/btree_map.h" #include "absl/strings/string_view.h" +#include "absl/types/span.h" #include "examples/cpp/fap_model_printer.h" #include "examples/cpp/fap_parser.h" #include "examples/cpp/fap_utilities.h" @@ -100,6 +101,10 @@ class OrderingDecision : public Decision { variable2_(variable2), value_(value), operator_(std::move(operation)) {} + + // This type is neither copyable nor movable. + OrderingDecision(const OrderingDecision&) = delete; + OrderingDecision& operator=(const OrderingDecision&) = delete; ~OrderingDecision() override = default; // Apply will be called first when the decision is executed. @@ -131,8 +136,6 @@ class OrderingDecision : public Decision { IntVar* const variable2_; const int value_; const std::string operator_; - - DISALLOW_COPY_AND_ASSIGN(OrderingDecision); }; // Decision on whether a soft constraint will be added to a model @@ -142,6 +145,10 @@ class ConstraintDecision : public Decision { explicit ConstraintDecision(IntVar* const constraint_violation) : constraint_violation_(constraint_violation) {} + // This type is neither copyable nor movable. + ConstraintDecision(const ConstraintDecision&) = delete; + ConstraintDecision& operator=(const ConstraintDecision&) = delete; + ~ConstraintDecision() override = default; // Apply will be called first when the decision is executed. @@ -158,8 +165,6 @@ class ConstraintDecision : public Decision { private: IntVar* const constraint_violation_; - - DISALLOW_COPY_AND_ASSIGN(ConstraintDecision); }; // The ordering builder resolves the relative order of the two variables @@ -192,6 +197,10 @@ class OrderingBuilder : public DecisionBuilder { CHECK_EQ(variable_state_.size(), variables_.size()); } + // This type is neither copyable nor movable. + OrderingBuilder(const OrderingBuilder&) = delete; + OrderingBuilder& operator=(const OrderingBuilder&) = delete; + ~OrderingBuilder() override = default; Decision* Next(Solver* const s) override { @@ -320,8 +329,6 @@ class OrderingBuilder : public DecisionBuilder { // Used by Hint() for indicating the most probable ordering. std::vector variable_state_; std::vector minimum_value_available_; - - DISALLOW_COPY_AND_ASSIGN(OrderingBuilder); }; // A comparator for sorting the constraints depending on their impact. @@ -373,7 +380,7 @@ int64_t ValueEvaluator( // The variables which participate in more constraints and have the // smaller domain should be in higher priority for assignment. int64_t VariableEvaluator( - const std::vector& key_from_index, + absl::Span key_from_index, const absl::btree_map& data_variables, int64_t variable_index) { FapVariable variable = @@ -414,7 +421,7 @@ void CreateModelVariables( } // Creates the constraints of the instance from the parsed data. -void CreateModelConstraints(const std::vector& data_constraints, +void CreateModelConstraints(absl::Span data_constraints, const std::vector& variables, const absl::btree_map& index_from_key, Solver* solver) { @@ -649,7 +656,7 @@ void SplitVariablesHardSoft( } // Splits constraints of the instance to hard and soft. -void SplitConstraintHardSoft(const std::vector& data_constraints, +void SplitConstraintHardSoft(absl::Span data_constraints, std::vector* hard_constraints, std::vector* soft_constraints) { for (const FapConstraint& ct : data_constraints) { @@ -683,8 +690,8 @@ void PenalizeVariablesViolation( // Penalize the violation of soft constraints of the instance. void PenalizeConstraintsViolation( - const std::vector& constraints, - const std::vector& soft_constraints, + absl::Span constraints, + absl::Span soft_constraints, const absl::btree_map& index_from_key, const std::vector& variables, std::vector* cost, std::vector* violated_constraints, Solver* solver) { @@ -733,7 +740,7 @@ void PenalizeConstraintsViolation( int SoftFapSolver(const absl::btree_map& data_variables, const std::vector& data_constraints, absl::string_view /*data_objective*/, - const std::vector& /*values*/) { + absl::Span /*values*/) { Solver solver("SoftFapSolver"); std::vector monitors; diff --git a/examples/cpp/jobshop_sat.cc b/examples/cpp/jobshop_sat.cc index 27b76dc289..11c64480f6 100644 --- a/examples/cpp/jobshop_sat.cc +++ b/examples/cpp/jobshop_sat.cc @@ -322,7 +322,7 @@ std::vector> GetDataPerMachine( void CreateMachines( const JsspInputProblem& problem, - const std::vector>>& + absl::Span>> job_task_to_alternatives, IntervalVar makespan_interval, CpModelBuilder& cp_model) { const int num_jobs = problem.jobs_size(); @@ -733,12 +733,6 @@ void Solve(const JsspInputProblem& problem) { // Setup parameters. SatParameters parameters; parameters.set_log_search_progress(true); - // Parse the --params flag. - if (!absl::GetFlag(FLAGS_params).empty()) { - CHECK(google::protobuf::TextFormat::MergeFromString( - absl::GetFlag(FLAGS_params), ¶meters)) - << absl::GetFlag(FLAGS_params); - } // Prefer objective_shaving_search over objective_lb_search. if (parameters.num_workers() >= 16 && parameters.num_workers() < 24) { @@ -751,6 +745,13 @@ void Solve(const JsspInputProblem& problem) { parameters.set_push_all_tasks_toward_start(true); parameters.set_use_dynamic_precedence_in_disjunctive(true); + // Parse the --params flag. + if (!absl::GetFlag(FLAGS_params).empty()) { + CHECK(google::protobuf::TextFormat::MergeFromString( + absl::GetFlag(FLAGS_params), ¶meters)) + << absl::GetFlag(FLAGS_params); + } + const CpSolverResponse response = SolveWithParameters(cp_model.Build(), parameters); diff --git a/examples/cpp/slitherlink_sat.cc b/examples/cpp/slitherlink_sat.cc index c9dba90dc4..e9fba86af6 100644 --- a/examples/cpp/slitherlink_sat.cc +++ b/examples/cpp/slitherlink_sat.cc @@ -66,7 +66,7 @@ void PrintSolution(absl::Span> data, std::cout << last_line << std::endl; } -void SlitherLink(const std::vector>& data) { +void SlitherLink(absl::Span> data) { const int num_rows = data.size(); const int num_columns = data[0].size(); diff --git a/examples/cpp/weighted_tardiness_sat.cc b/examples/cpp/weighted_tardiness_sat.cc index 1690e7f324..0462d6e325 100644 --- a/examples/cpp/weighted_tardiness_sat.cc +++ b/examples/cpp/weighted_tardiness_sat.cc @@ -18,14 +18,20 @@ #include #include "absl/flags/flag.h" +#include "absl/log/check.h" #include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/types/span.h" #include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/sat/cp_model.h" +#include "ortools/sat/cp_model.pb.h" +#include "ortools/sat/cp_model_solver.h" #include "ortools/sat/model.h" +#include "ortools/sat/sat_parameters.pb.h" #include "ortools/util/filelineiter.h" +#include "ortools/util/sorted_interval_list.h" ABSL_FLAG(std::string, input, "examples/cpp/wt40.txt", "wt data file name."); ABSL_FLAG(int, size, 40, "Size of the problem in the wt file."); diff --git a/examples/flatzinc/README b/examples/flatzinc/README.md similarity index 100% rename from examples/flatzinc/README rename to examples/flatzinc/README.md