diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 504916de5b..542c93784c 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -13,6 +13,7 @@ include(GNUInstallDirs) foreach(EXECUTABLE IN ITEMS constraint_programming_cp costas_array_sat + cryptarithm_sat cvrp_disjoint_tw cvrptw cvrptw_with_breaks @@ -29,6 +30,7 @@ foreach(EXECUTABLE IN ITEMS linear_assignment_api linear_programming linear_solver_protocol_buffers + magic_sequence_sat magic_square_sat max_flow min_cost_flow diff --git a/examples/cpp/costas_array_sat.cc b/examples/cpp/costas_array_sat.cc index ee33e1caea..179e09ae17 100644 --- a/examples/cpp/costas_array_sat.cc +++ b/examples/cpp/costas_array_sat.cc @@ -21,16 +21,18 @@ // This example contains two separate implementations. CostasHard() // uses hard constraints, whereas CostasSoft() uses a minimizer to // minimize the number of duplicates. + #include #include #include +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" -#include "ortools/base/commandlineflags.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/random.h" #include "ortools/sat/cp_model.h" #include "ortools/sat/model.h" @@ -102,11 +104,13 @@ void CostasHard(const int dim) { // Check that the pairwise difference is unique for (int i = 1; i < dim; ++i) { std::vector subset; - Domain diff(-dim, dim); + Domain difference_domain(-dim, dim); for (int j = 0; j < dim - i; ++j) { - subset.push_back(cp_model.NewIntVar(diff)); - cp_model.AddEquality(LinearExpr::Sum({subset[j], vars[j]}), vars[j + i]); + IntVar diff = cp_model.NewIntVar(difference_domain); + subset.push_back(diff); + cp_model.AddEquality( + diff, LinearExpr::ScalProd({vars[j + i], vars[j]}, {1, -1})); } cp_model.AddAllDifferent(subset); @@ -118,7 +122,7 @@ void CostasHard(const int dim) { } const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model); - if (response.status() == CpSolverStatus::FEASIBLE) { + if (response.status() == CpSolverStatus::OPTIMAL) { std::vector costas_matrix; std::string output; @@ -142,8 +146,8 @@ void CostasBool(const int dim) { CpModelBuilder cp_model; // create the variables - std::vector > vars(dim); - std::vector > transposed_vars(dim); + std::vector> vars(dim); + std::vector> transposed_vars(dim); for (int i = 0; i < dim; ++i) { for (int j = 0; j < dim; ++j) { const BoolVar var = cp_model.NewBoolVar(); @@ -213,8 +217,8 @@ void CostasBoolSoft(const int dim) { CpModelBuilder cp_model; // create the variables - std::vector > vars(dim); - std::vector > transposed_vars(dim); + std::vector> vars(dim); + std::vector> transposed_vars(dim); for (int i = 0; i < dim; ++i) { for (int j = 0; j < dim; ++j) { const BoolVar var = cp_model.NewBoolVar(); @@ -294,7 +298,10 @@ void CostasBoolSoft(const int dim) { } // namespace operations_research int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); + int min = 1; int max = 10; diff --git a/examples/cpp/course_scheduling_run.cc b/examples/cpp/course_scheduling_run.cc index a2770e4c72..5225d8850f 100644 --- a/examples/cpp/course_scheduling_run.cc +++ b/examples/cpp/course_scheduling_run.cc @@ -21,6 +21,8 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "examples/cpp/course_scheduling.h" #include "examples/cpp/course_scheduling.pb.h" #include "ortools/base/commandlineflags.h" diff --git a/examples/cpp/cryptarithm_sat.cc b/examples/cpp/cryptarithm_sat.cc new file mode 100644 index 0000000000..6658dd15b8 --- /dev/null +++ b/examples/cpp/cryptarithm_sat.cc @@ -0,0 +1,87 @@ +// Copyright 2010-2018 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. + +// Use CP-SAT to solve a simple cryptarithmetic problem: SEND+MORE=MONEY. + +#include "ortools/sat/cp_model.h" + +namespace operations_research { +namespace sat { + +void SendMoreMoney() { + CpModelBuilder cp_model; + + // Possible domains for variables. + Domain all_digits(0, 9); + Domain non_zero_digits(1, 9); + // Create variables. + // Since s is a leading digit, it can't be 0. + const IntVar s = cp_model.NewIntVar(non_zero_digits); + const IntVar e = cp_model.NewIntVar(all_digits); + const IntVar n = cp_model.NewIntVar(all_digits); + const IntVar d = cp_model.NewIntVar(all_digits); + // Since m is a leading digit, it can't be 0. + const IntVar m = cp_model.NewIntVar(non_zero_digits); + const IntVar o = cp_model.NewIntVar(all_digits); + const IntVar r = cp_model.NewIntVar(all_digits); + const IntVar y = cp_model.NewIntVar(all_digits); + + // Create carry variables. c0 is true if the first column of addends carries + // a 1, c2 is true if the second column carries a 1, and so on. + const BoolVar c0 = cp_model.NewBoolVar(); + const BoolVar c1 = cp_model.NewBoolVar(); + const BoolVar c2 = cp_model.NewBoolVar(); + const BoolVar c3 = cp_model.NewBoolVar(); + + // Force all letters to take on different values. + cp_model.AddAllDifferent({s, e, n, d, m, o, r, y}); + + // Column 0: Force c0 == m. + cp_model.AddEquality(c0, m); + + // Column 1: Force c1 + s + m + o == 10*c0. + cp_model.AddEquality(LinearExpr::Sum({c1, s, m, o}), + LinearExpr::ScalProd({c0}, {10})); + + // Column 2: Force c2 + e + o == n + 10*c1. + cp_model.AddEquality(LinearExpr::Sum({c2, e, o}), + LinearExpr::ScalProd({n, c1}, {1, 10})); + + // Column 3: Force c3 + n + r == e + 10*c2. + cp_model.AddEquality(LinearExpr::Sum({c3, n, r}), + LinearExpr::ScalProd({e, c2}, {1, 10})); + + // Column 4: Force d + e == y + 10*c3. + cp_model.AddEquality(LinearExpr::Sum({d, e}), + LinearExpr::ScalProd({y, c3}, {1, 10})); + + // Declare the model, solve it, and display the results. + const CpSolverResponse response = Solve(cp_model.Build()); + LOG(INFO) << CpSolverResponseStats(response); + LOG(INFO) << "s: " << SolutionIntegerValue(response, s); + LOG(INFO) << "e: " << SolutionIntegerValue(response, e); + LOG(INFO) << "n: " << SolutionIntegerValue(response, n); + LOG(INFO) << "d: " << SolutionIntegerValue(response, d); + LOG(INFO) << "m: " << SolutionIntegerValue(response, m); + LOG(INFO) << "o: " << SolutionIntegerValue(response, o); + LOG(INFO) << "r: " << SolutionIntegerValue(response, r); + LOG(INFO) << "y: " << SolutionIntegerValue(response, y); +} + +} // namespace sat +} // namespace operations_research + +int main() { + operations_research::sat::SendMoreMoney(); + return EXIT_SUCCESS; +} diff --git a/examples/cpp/cvrp_disjoint_tw.cc b/examples/cpp/cvrp_disjoint_tw.cc index dbc4465241..7c7a319578 100644 --- a/examples/cpp/cvrp_disjoint_tw.cc +++ b/examples/cpp/cvrp_disjoint_tw.cc @@ -24,6 +24,8 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/random/random.h" #include "examples/cpp/cvrptw_lib.h" #include "google/protobuf/text_format.h" @@ -66,6 +68,7 @@ const int64 kMaxNodesPerGroup = 10; const int64 kSameVehicleCost = 1000; int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) << "Specify an instance size greater than 0."; diff --git a/examples/cpp/cvrptw.cc b/examples/cpp/cvrptw.cc index 3037c82684..a9505851ab 100644 --- a/examples/cpp/cvrptw.cc +++ b/examples/cpp/cvrptw.cc @@ -23,6 +23,8 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/random/random.h" #include "examples/cpp/cvrptw_lib.h" #include "google/protobuf/text_format.h" @@ -63,6 +65,7 @@ const int64 kMaxNodesPerGroup = 10; const int64 kSameVehicleCost = 1000; int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) << "Specify an instance size greater than 0."; diff --git a/examples/cpp/cvrptw_with_breaks.cc b/examples/cpp/cvrptw_with_breaks.cc index 79a57fdbfa..3ca94027a5 100644 --- a/examples/cpp/cvrptw_with_breaks.cc +++ b/examples/cpp/cvrptw_with_breaks.cc @@ -27,20 +27,21 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#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/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/random.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::ACMRandom; using operations_research::Assignment; using operations_research::DefaultRoutingSearchParameters; using operations_research::FirstSolutionStrategy; @@ -69,6 +70,7 @@ const char* kTime = "Time"; const char* kCapacity = "Capacity"; int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) << "Specify an instance size greater than 0."; @@ -76,8 +78,7 @@ int main(int argc, char** argv) { << "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. + // 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); @@ -117,8 +118,8 @@ int main(int argc, char** argv) { routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) { return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j)); }), - kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true, - kCapacity); + kNullCapacitySlack, kVehicleCapacity, + /*fix_start_cumul_to_zero=*/true, kCapacity); // Adding time dimension constraints. const int64 kTimePerDemandUnit = 300; @@ -139,11 +140,12 @@ int main(int argc, char** argv) { RoutingDimension* const time_dimension = routing.GetMutableDimension(kTime); // Adding time windows. - ACMRandom randomizer( + std::mt19937 randomizer( GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); const int64 kTWDuration = 5 * 3600; for (int order = 1; order < manager.num_nodes(); ++order) { - const int64 start = randomizer.Uniform(kHorizon - kTWDuration); + const int64 start = + absl::Uniform(randomizer, 0, kHorizon - kTWDuration); time_dimension->CumulVar(order)->SetRange(start, start + kTWDuration); routing.AddToAssignment(time_dimension->SlackVar(order)); } @@ -173,7 +175,7 @@ int main(int argc, char** argv) { service_times[node] = kTimePerDemandUnit * demand.Demand(index, index); } } - const std::vector > break_data = { + 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}}; diff --git a/examples/cpp/cvrptw_with_refueling.cc b/examples/cpp/cvrptw_with_refueling.cc index 7ba6b7a91a..82824e3eb2 100644 --- a/examples/cpp/cvrptw_with_refueling.cc +++ b/examples/cpp/cvrptw_with_refueling.cc @@ -21,18 +21,19 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#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/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/random.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::ACMRandom; using operations_research::Assignment; using operations_research::DefaultRoutingSearchParameters; using operations_research::GetSeed; @@ -65,6 +66,7 @@ bool IsRefuelNode(int64 node) { } int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) << "Specify an instance size greater than 0."; @@ -72,8 +74,7 @@ int main(int argc, char** argv) { << "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. + // 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); @@ -108,8 +109,8 @@ int main(int argc, char** argv) { routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) { return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j)); }), - kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true, - kCapacity); + kNullCapacitySlack, kVehicleCapacity, + /*fix_start_cumul_to_zero=*/true, kCapacity); // Adding time dimension constraints. const int64 kTimePerDemandUnit = 300; @@ -129,12 +130,17 @@ int main(int argc, char** argv) { kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime); const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); // Adding time windows. - ACMRandom randomizer( - GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); + // 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 kTWDuration = 5 * 3600; for (int order = 1; order < manager.num_nodes(); ++order) { if (!IsRefuelNode(order)) { - const int64 start = randomizer.Uniform(kHorizon - kTWDuration); + const int64 start = + absl::Uniform(randomizer, 0, kHorizon - kTWDuration); time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration); } } diff --git a/examples/cpp/cvrptw_with_resources.cc b/examples/cpp/cvrptw_with_resources.cc index d85a5d320b..b1e2a06906 100644 --- a/examples/cpp/cvrptw_with_resources.cc +++ b/examples/cpp/cvrptw_with_resources.cc @@ -23,18 +23,19 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#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/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/random.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::ACMRandom; using operations_research::Assignment; using operations_research::DefaultRoutingSearchParameters; using operations_research::GetSeed; @@ -63,6 +64,7 @@ const char* kTime = "Time"; const char* kCapacity = "Capacity"; int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders)) << "Specify an instance size greater than 0."; @@ -70,8 +72,7 @@ int main(int argc, char** argv) { << "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. + // 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); @@ -106,8 +107,8 @@ int main(int argc, char** argv) { routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) { return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j)); }), - kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true, - kCapacity); + kNullCapacitySlack, kVehicleCapacity, + /*fix_start_cumul_to_zero=*/true, kCapacity); // Adding time dimension constraints. const int64 kTimePerDemandUnit = 300; @@ -128,11 +129,12 @@ int main(int argc, char** argv) { const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); // Adding time windows. - ACMRandom randomizer( + std::mt19937 randomizer( GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); const int64 kTWDuration = 5 * 3600; for (int order = 1; order < manager.num_nodes(); ++order) { - const int64 start = randomizer.Uniform(kHorizon - kTWDuration); + const int64 start = + absl::Uniform(randomizer, 0, kHorizon - kTWDuration); time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration); } diff --git a/examples/cpp/cvrptw_with_stop_times_and_resources.cc b/examples/cpp/cvrptw_with_stop_times_and_resources.cc index 29ed0a3385..5dd3821ac0 100644 --- a/examples/cpp/cvrptw_with_stop_times_and_resources.cc +++ b/examples/cpp/cvrptw_with_stop_times_and_resources.cc @@ -21,19 +21,20 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#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/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/random.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::ACMRandom; using operations_research::Assignment; using operations_research::DefaultRoutingSearchParameters; using operations_research::GetSeed; @@ -63,6 +64,7 @@ const char* kTime = "Time"; const char* kCapacity = "Capacity"; int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK_LT(0, absl::GetFlag(FLAGS_vrp_stops)) << "Specify an instance size greater than 0."; @@ -109,8 +111,8 @@ int main(int argc, char** argv) { routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) { return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j)); }), - kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/true, - kCapacity); + kNullCapacitySlack, kVehicleCapacity, + /*fix_start_cumul_to_zero=*/true, kCapacity); // Adding time dimension constraints. const int64 kStopTime = 300; @@ -128,11 +130,12 @@ int main(int argc, char** argv) { const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); // Adding time windows, for the sake of simplicty same for each stop. - ACMRandom randomizer( + std::mt19937 randomizer( GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed))); const int64 kTWDuration = 5 * 3600; for (int stop = 0; stop < absl::GetFlag(FLAGS_vrp_stops); ++stop) { - const int64 start = randomizer.Uniform(kHorizon - kTWDuration); + const int64 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 = diff --git a/examples/cpp/dimacs_assignment.cc b/examples/cpp/dimacs_assignment.cc index b659ca9b17..4b6196b5fb 100644 --- a/examples/cpp/dimacs_assignment.cc +++ b/examples/cpp/dimacs_assignment.cc @@ -18,6 +18,8 @@ #include #include "absl/container/flat_hash_map.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/str_format.h" #include "examples/cpp/parse_dimacs_assignment.h" #include "examples/cpp/print_dimacs_assignment.h" @@ -186,7 +188,7 @@ int main(int argc, char* argv[]) { } else { usage = absl::StrFormat(kUsageTemplate, argv[0]); } - absl::SetProgramUsageMessage(usage); + google::InitGoogleLogging(usage.c_str()); absl::ParseCommandLine(argc, argv); if (argc < 2) { diff --git a/examples/cpp/dobble_ls.cc b/examples/cpp/dobble_ls.cc index 923ab3972d..d05d01dc70 100644 --- a/examples/cpp/dobble_ls.cc +++ b/examples/cpp/dobble_ls.cc @@ -30,8 +30,11 @@ // search operators and local search filters. #include +#include #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/random/random.h" #include "absl/strings/str_format.h" #include "ortools/base/commandlineflags.h" @@ -722,21 +725,20 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) { filters.push_back(solver.RevAlloc(new DobbleFilter( all_card_symbol_vars, num_cards, num_symbols, num_symbols_per_card))); } - + LocalSearchFilterManager* ls_manager = + solver.RevAlloc(new LocalSearchFilterManager(std::move(filters))); // Main decision builder that regroups the first solution decision // builder and the combination of local search operators and // filters. - LocalSearchFilterManager* filter_manager = - solver.RevAlloc(new LocalSearchFilterManager(filters)); DecisionBuilder* const final_db = solver.MakeLocalSearchPhase( all_card_symbol_vars, build_db, solver.MakeLocalSearchPhaseParameters( objective_var, solver.ConcatenateOperators(operators, true), nullptr, // Sub decision builder, not needed here. nullptr, // Limit the search for improving move, we will stop - // the exploration of the local search at the first - // improving solution (first accept). - filter_manager)); + // the exploration of the local search at the first + // improving solution (first accept). + ls_manager)); std::vector monitors; // Optimize var search monitor. @@ -748,8 +750,8 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) { monitors.push_back(log); // Search limit. - SearchLimit* const time_limit = solver.MakeLimit( - absl::GetFlag(FLAGS_time_limit_in_ms), kint64max, kint64max, kint64max); + SearchLimit* const time_limit = solver.MakeTimeLimit( + absl::Milliseconds(absl::GetFlag(FLAGS_time_limit_in_ms))); monitors.push_back(time_limit); // And solve! @@ -758,6 +760,7 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) { } // namespace operations_research int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); // These constants comes directly from the dobble game. // There are actually 55 cards, but we can create up to 57 cards. diff --git a/examples/cpp/flow_api.cc b/examples/cpp/flow_api.cc index 09bcecd42b..0e857e08fd 100644 --- a/examples/cpp/flow_api.cc +++ b/examples/cpp/flow_api.cc @@ -11,7 +11,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ortools/base/commandlineflags.h" +#include + +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "ortools/base/logging.h" #include "ortools/graph/ebert_graph.h" #include "ortools/graph/max_flow.h" @@ -81,6 +84,7 @@ void MaxFeasibleFlow() { } // namespace operations_research int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); operations_research::MinCostFlowOn4x4Matrix(); operations_research::MaxFeasibleFlow(); diff --git a/examples/cpp/frequency_assignment_problem.cc b/examples/cpp/frequency_assignment_problem.cc index 320b7346aa..5e4485ae82 100644 --- a/examples/cpp/frequency_assignment_problem.cc +++ b/examples/cpp/frequency_assignment_problem.cc @@ -51,6 +51,8 @@ #include #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "examples/cpp/fap_model_printer.h" #include "examples/cpp/fap_parser.h" #include "examples/cpp/fap_utilities.h" @@ -331,7 +333,7 @@ bool ConstraintImpactComparator(FapConstraint constraint1, } int64 ValueEvaluator( - absl::flat_hash_map >* value_evaluator_map, + absl::flat_hash_map>* value_evaluator_map, int64 variable_index, int64 value) { CHECK(value_evaluator_map != nullptr); // Evaluate the choice. Smaller ranking denotes a better choice. @@ -344,7 +346,7 @@ int64 ValueEvaluator( } // Update the history of assigned values and their rankings of each variable. - absl::flat_hash_map >::iterator it; + absl::flat_hash_map>::iterator it; int64 new_value = value; int64 new_ranking = ranking; if ((it = value_evaluator_map->find(variable_index)) != @@ -489,8 +491,8 @@ void CreateAdditionalMonitors(OptimizeVar* const objective, Solver* solver, if (absl::GetFlag(FLAGS_time_limit_in_ms) != 0) { LOG(INFO) << "Adding time limit of " << absl::GetFlag(FLAGS_time_limit_in_ms) << " ms."; - SearchLimit* const limit = solver->MakeLimit( - absl::GetFlag(FLAGS_time_limit_in_ms), kint64max, kint64max, kint64max); + SearchLimit* const limit = solver->MakeTimeLimit( + absl::Milliseconds(absl::GetFlag(FLAGS_time_limit_in_ms))); monitors->push_back(limit); } @@ -581,7 +583,7 @@ void HardFapSolver(const std::map& data_variables, ChooseVariableStrategy(&variable_strategy); // Choose the value selection strategy. DecisionBuilder* db; - absl::flat_hash_map > history; + absl::flat_hash_map> history; if (absl::GetFlag(FLAGS_value_evaluator) == "value_evaluator") { LOG(INFO) << "Using ValueEvaluator for value selection strategy."; Solver::IndexEvaluator2 index_evaluator2 = [&history](int64 var, @@ -856,6 +858,7 @@ void SolveProblem(const std::map& variables, } // namespace operations_research int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); CHECK(!absl::GetFlag(FLAGS_directory).empty()) diff --git a/examples/cpp/golomb_sat.cc b/examples/cpp/golomb_sat.cc index 539bb2aad7..528a3db143 100644 --- a/examples/cpp/golomb_sat.cc +++ b/examples/cpp/golomb_sat.cc @@ -26,8 +26,11 @@ #include +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/strings/str_format.h" #include "google/protobuf/text_format.h" -#include "ortools/base/commandlineflags.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/sat/cp_model.h" @@ -97,8 +100,8 @@ void GolombRuler(int size) { if (response.status() == CpSolverStatus::OPTIMAL) { const int64 result = SolutionIntegerValue(response, ticks.back()); const int64 num_failures = response.num_conflicts(); - printf("N = %d, optimal length = %lld (conflicts:%lld, time=%f s)\n", size, - result, num_failures, response.wall_time()); + absl::PrintF("N = %d, optimal length = %d (conflicts:%d, time=%f s)\n", + size, result, num_failures, response.wall_time()); if (size - 1 < kKnownSolutions) { CHECK_EQ(result, kBestSolutions[size - 1]); } @@ -116,7 +119,10 @@ void GolombRuler(int size) { } // namespace operations_research int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); + if (absl::GetFlag(FLAGS_size) != 0) { operations_research::sat::GolombRuler(absl::GetFlag(FLAGS_size)); } else { diff --git a/examples/cpp/integer_programming.cc b/examples/cpp/integer_programming.cc index 6512970b7d..351c3f4078 100644 --- a/examples/cpp/integer_programming.cc +++ b/examples/cpp/integer_programming.cc @@ -13,12 +13,15 @@ // Integer programming example that shows how to use the API. -#include "ortools/base/commandlineflags.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" #include "ortools/base/logging.h" #include "ortools/linear_solver/linear_solver.h" namespace operations_research { -void RunIntegerProgrammingExample(const std::string& solver_id) { +void RunIntegerProgrammingExample(absl::string_view solver_id) { LOG(INFO) << "---- Integer programming example with " << solver_id << " ----"; MPSolver::OptimizationProblemType problem_type; @@ -87,9 +90,7 @@ void RunAllExamples() { int main(int argc, char** argv) { google::InitGoogleLogging(argv[0]); - absl::SetFlag(&FLAGS_logtostderr, true); - absl::SetFlag(&FLAGS_log_prefix, false); absl::ParseCommandLine(argc, argv); operations_research::RunAllExamples(); - return 0; + return EXIT_SUCCESS; } diff --git a/examples/cpp/jobshop_sat.cc b/examples/cpp/jobshop_sat.cc index 5b6335c107..0e0397a446 100644 --- a/examples/cpp/jobshop_sat.cc +++ b/examples/cpp/jobshop_sat.cc @@ -16,11 +16,12 @@ #include #include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/match.h" #include "absl/strings/str_join.h" #include "google/protobuf/text_format.h" #include "google/protobuf/wrappers.pb.h" -#include "ortools/base/commandlineflags.h" #include "ortools/base/logging.h" #include "ortools/base/timer.h" #include "ortools/data/jobshop_scheduling.pb.h" @@ -747,7 +748,9 @@ void Solve(const JsspInputProblem& problem) { int main(int argc, char** argv) { absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); + if (absl::GetFlag(FLAGS_input).empty()) { LOG(FATAL) << "Please supply a data file with --input="; } diff --git a/examples/cpp/linear_assignment_api.cc b/examples/cpp/linear_assignment_api.cc index f13b4d25fa..80f515c768 100644 --- a/examples/cpp/linear_assignment_api.cc +++ b/examples/cpp/linear_assignment_api.cc @@ -11,7 +11,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ortools/base/commandlineflags.h" +#include + +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "ortools/base/logging.h" #include "ortools/graph/ebert_graph.h" #include "ortools/graph/linear_assignment.h" @@ -46,7 +49,7 @@ void AssignmentOn4x4Matrix() { void AnotherAssignment() { LOG(INFO) << "Another assignment on 4x4 matrix"; - std::vector > matrice( + std::vector> matrice( {{8, 7, 9, 9}, {5, 2, 7, 8}, {6, 1, 4, 9}, {2, 3, 2, 6}}); const int kSize = matrice.size(); ForwardStarGraph graph(2 * kSize, kSize * kSize); @@ -66,6 +69,7 @@ void AnotherAssignment() { } // namespace operations_research int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); operations_research::AssignmentOn4x4Matrix(); operations_research::AnotherAssignment(); diff --git a/examples/cpp/linear_programming.cc b/examples/cpp/linear_programming.cc index 95872bcaa2..f812677029 100644 --- a/examples/cpp/linear_programming.cc +++ b/examples/cpp/linear_programming.cc @@ -13,13 +13,20 @@ // Linear programming example that shows how to use the API. +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" #include "ortools/base/commandlineflags.h" #include "ortools/base/logging.h" #include "ortools/linear_solver/linear_solver.h" #include "ortools/linear_solver/linear_solver.pb.h" namespace operations_research { -void RunLinearProgrammingExample(const std::string& solver_id) { +void RunLinearProgrammingExample(absl::string_view solver_id) { LOG(INFO) << "---- Linear programming example with " << solver_id << " ----"; MPSolver::OptimizationProblemType problem_type; if (!MPSolver::ParseSolverType(solver_id, &problem_type)) { @@ -112,9 +119,8 @@ void RunAllExamples() { } // namespace operations_research int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_alsologtostderr, true); google::InitGoogleLogging(argv[0]); - absl::SetFlag(&FLAGS_logtostderr, true); - absl::SetFlag(&FLAGS_log_prefix, false); absl::ParseCommandLine(argc, argv); operations_research::RunAllExamples(); return EXIT_SUCCESS; diff --git a/examples/cpp/linear_solver_protocol_buffers.cc b/examples/cpp/linear_solver_protocol_buffers.cc index 393e56ab4f..7543cd0516 100644 --- a/examples/cpp/linear_solver_protocol_buffers.cc +++ b/examples/cpp/linear_solver_protocol_buffers.cc @@ -13,7 +13,8 @@ #include -#include "ortools/base/commandlineflags.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "ortools/base/logging.h" #include "ortools/linear_solver/linear_solver.h" #include "ortools/linear_solver/linear_solver.pb.h" @@ -99,6 +100,7 @@ void RunAllExamples() { } // namespace operations_research int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); operations_research::RunAllExamples(); return EXIT_SUCCESS; diff --git a/examples/cpp/magic_sequence_sat.cc b/examples/cpp/magic_sequence_sat.cc new file mode 100644 index 0000000000..bc950c274c --- /dev/null +++ b/examples/cpp/magic_sequence_sat.cc @@ -0,0 +1,98 @@ +// Copyright 2010-2018 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. + +// Magic sequence problem +// +// Compute a sequence of numbers such that the number of occurrences of i +// in the sequence is equal to the value of the ith number. + +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/strings/str_format.h" +#include "ortools/base/integral_types.h" +#include "ortools/base/logging.h" +#include "ortools/sat/cp_model.h" + +ABSL_FLAG(int, size, 50, "Size of the problem."); +ABSL_FLAG(std::string, params, "log_search_progress:true,num_search_workers:8", + "Sat parameters."); + +namespace operations_research { +namespace sat { + +void MagicSequence(int size) { + CHECK_GE(size, 1); + CpModelBuilder cp_model; + + std::vector> var_domains(size); + for (int i = 0; i < size; ++i) { + for (int j = 0; j < size; ++j) { + var_domains[i].push_back(cp_model.NewBoolVar()); + } + } + + // Domain constraint on each position. + for (int i = 0; i < size; ++i) { + cp_model.AddEquality(LinearExpr::BooleanSum(var_domains[i]), 1); + } + + // The number of variables equal to j shall be the value of vars[j]. + std::vector values(size); + std::iota(values.begin(), values.end(), 0); // [0, 1, 2, .., size - 1] + std::vector vars_equal_to_j; + + for (int j = 0; j < size; ++j) { + vars_equal_to_j.clear(); + for (int i = 0; i < size; ++i) { + vars_equal_to_j.push_back(var_domains[i][j]); + } + cp_model.AddEquality(LinearExpr::BooleanScalProd(var_domains[j], values), + LinearExpr::BooleanSum(vars_equal_to_j)); + } + + const CpSolverResponse response = + SolveWithParameters(cp_model.Build(), absl::GetFlag(FLAGS_params)); + + if (response.status() == CpSolverStatus::OPTIMAL || + response.status() == CpSolverStatus::FEASIBLE) { + std::string output = "["; + for (int i = 0; i < size; ++i) { + if (i != 0) { + output.append(", "); + } + for (int j = 0; j < size; ++j) { + if (SolutionBooleanValue(response, var_domains[i][j])) { + absl::StrAppendFormat(&output, "%d", j); + break; + } + } + } + output.append("]"); + LOG(INFO) << "Solution = " << output; + } +} + +} // namespace sat +} // namespace operations_research + +int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); + absl::ParseCommandLine(argc, argv); + + operations_research::sat::MagicSequence(absl::GetFlag(FLAGS_size)); + return EXIT_SUCCESS; +} diff --git a/examples/cpp/magic_square_sat.cc b/examples/cpp/magic_square_sat.cc index d988f0567f..33ab41bdd4 100644 --- a/examples/cpp/magic_square_sat.cc +++ b/examples/cpp/magic_square_sat.cc @@ -14,13 +14,18 @@ #include #include +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" -#include "ortools/base/commandlineflags.h" +#include "ortools/base/integral_types.h" +#include "ortools/base/logging.h" #include "ortools/sat/cp_model.h" #include "ortools/sat/model.h" ABSL_FLAG(int, size, 7, "Size of the magic square"); -ABSL_FLAG(std::string, params, "", "Sat paramters"); +ABSL_FLAG(std::string, params, "", "Sat parameters"); namespace operations_research { namespace sat { @@ -94,7 +99,9 @@ void MagicSquare(int size) { int main(int argc, char** argv) { absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); + operations_research::sat::MagicSquare(absl::GetFlag(FLAGS_size)); return EXIT_SUCCESS; } diff --git a/examples/cpp/mps_driver.cc b/examples/cpp/mps_driver.cc index 85f123d1e2..448c9989c3 100644 --- a/examples/cpp/mps_driver.cc +++ b/examples/cpp/mps_driver.cc @@ -18,6 +18,8 @@ #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/status/status.h" #include "absl/strings/match.h" #include "google/protobuf/descriptor.h" @@ -74,8 +76,8 @@ void ReadGlopParameters(GlopParameters* parameters) { << absl::GetFlag(FLAGS_params); } if (absl::GetFlag(FLAGS_mps_verbose_result)) { - printf("GlopParameters {\n%s}\n", - FullProtocolMessageAsString(*parameters, 1).c_str()); + absl::PrintF("GlopParameters {\n%s}\n", + FullProtocolMessageAsString(*parameters, 1)); } } @@ -106,7 +108,7 @@ int main(int argc, char* argv[]) { MPModelProtoToLinearProgram(model_proto, &linear_program); } if (absl::GetFlag(FLAGS_mps_dump_problem)) { - printf("%s", linear_program.Dump().c_str()); + absl::PrintF("%s", linear_program.Dump()); } // Create the solver with the correct parameters. @@ -126,29 +128,29 @@ int main(int argc, char* argv[]) { if (absl::GetFlag(FLAGS_mps_terse_result)) { if (absl::GetFlag(FLAGS_mps_display_full_path)) { - printf("%s,", file_name.c_str()); + absl::PrintF("%s,", file_name); } - printf("%s,", linear_program.name().c_str()); + absl::PrintF("%s,", linear_program.name()); if (absl::GetFlag(FLAGS_mps_solve)) { - printf("%15.15e,%s,%-6.4g,", objective_value, status_string.c_str(), - solving_time_in_sec); + absl::PrintF("%15.15e,%s,%-6.4g,", objective_value, status_string, + solving_time_in_sec); } - printf("%s,%s\n", linear_program.GetProblemStats().c_str(), - linear_program.GetNonZeroStats().c_str()); + absl::PrintF("%s,%s\n", linear_program.GetProblemStats(), + linear_program.GetNonZeroStats()); } if (absl::GetFlag(FLAGS_mps_verbose_result)) { if (absl::GetFlag(FLAGS_mps_display_full_path)) { - printf("%-45s: %s\n", "File path", file_name.c_str()); + absl::PrintF("%-45s: %s\n", "File path", file_name); } - printf("%-45s: %s\n", "Problem name", linear_program.name().c_str()); + absl::PrintF("%-45s: %s\n", "Problem name", linear_program.name()); if (absl::GetFlag(FLAGS_mps_solve)) { - printf("%-45s: %15.15e\n", "Objective value", objective_value); - printf("%-45s: %s\n", "Problem status", status_string.c_str()); - printf("%-45s: %-6.4g\n", "Solving time", solving_time_in_sec); + absl::PrintF("%-45s: %15.15e\n", "Objective value", objective_value); + absl::PrintF("%-45s: %s\n", "Problem status", status_string); + absl::PrintF("%-45s: %-6.4g\n", "Solving time", solving_time_in_sec); } - printf("%s%s", linear_program.GetPrettyProblemStats().c_str(), - linear_program.GetPrettyNonZeroStats().c_str()); + absl::PrintF("%s%s", linear_program.GetPrettyProblemStats(), + linear_program.GetPrettyNonZeroStats()); } } return EXIT_SUCCESS; diff --git a/examples/cpp/multi_knapsack_sat.cc b/examples/cpp/multi_knapsack_sat.cc index 0db7139abb..5b532c5127 100644 --- a/examples/cpp/multi_knapsack_sat.cc +++ b/examples/cpp/multi_knapsack_sat.cc @@ -22,6 +22,8 @@ #include #include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "ortools/base/commandlineflags.h" #include "ortools/base/logging.h" #include "ortools/sat/cp_model.h" @@ -108,6 +110,7 @@ void MultiKnapsackSat(int scaling, const std::string& params) { int main(int argc, char** argv) { absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); operations_research::sat::MultiKnapsackSat(absl::GetFlag(FLAGS_size), absl::GetFlag(FLAGS_params)); diff --git a/examples/cpp/network_routing_sat.cc b/examples/cpp/network_routing_sat.cc index 8e9e5d6912..e1d6d17a36 100644 --- a/examples/cpp/network_routing_sat.cc +++ b/examples/cpp/network_routing_sat.cc @@ -26,19 +26,21 @@ // A random problem generator is also included. #include +#include #include -#include -#include #include #include +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/random/uniform_int_distribution.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/hash.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" -#include "ortools/base/map_util.h" -#include "ortools/base/random.h" #include "ortools/graph/shortestpaths.h" #include "ortools/sat/cp_model.h" #include "ortools/sat/model.h" @@ -128,7 +130,7 @@ class NetworkRoutingData { void AddDemand(int source, int destination, int traffic) { all_demands_[std::make_pair(source, destination)] = traffic; } - void set_name(const std::string& name) { name_ = name; } + void set_name(absl::string_view name) { name_ = name; } void set_max_capacity(int max_capacity) { max_capacity_ = max_capacity; } void set_fixed_charge_cost(int cost) { fixed_charge_cost_ = cost; } @@ -137,8 +139,8 @@ class NetworkRoutingData { int num_nodes_; int max_capacity_; int fixed_charge_cost_; - std::unordered_map, int> all_arcs_; - std::unordered_map, int> all_demands_; + std::map, int> all_arcs_; + std::map, int> all_demands_; }; // ----- Data Generation ----- @@ -156,15 +158,32 @@ class NetworkRoutingData { // fixed cost of 'fixed_charge_cost'. class NetworkRoutingDataBuilder { public: - NetworkRoutingDataBuilder() : random_(0) {} - - void BuildModelFromParameters(int num_clients, int num_backbones, - int num_demands, int traffic_min, - int traffic_max, int min_client_degree, - int max_client_degree, int min_backbone_degree, - int max_backbone_degree, int max_capacity, - int fixed_charge_cost, int seed, - NetworkRoutingData* const data) { + NetworkRoutingDataBuilder(int num_clients, int num_backbones, int num_demands, + int traffic_min, int traffic_max, + int min_client_degree, int max_client_degree, + int min_backbone_degree, int max_backbone_degree, + int max_capacity, int fixed_charge_cost) + : num_clients_(num_clients), + num_backbones_(num_backbones), + num_demands_(num_demands), + traffic_min_(traffic_min), + traffic_max_(traffic_max), + min_client_degree_(min_client_degree), + max_client_degree_(max_client_degree), + min_backbone_degree_(min_backbone_degree), + max_backbone_degree_(max_backbone_degree), + max_capacity_(max_capacity), + fixed_charge_cost_(fixed_charge_cost), + rand_gen_(0), + uniform_backbones_(0, num_backbones_ - 1), + uniform_clients_(0, num_clients_ - 1), + uniform_demands_(0, num_demands_ - 1), + uniform_traffic_(traffic_min, traffic_max), + uniform_client_degree_(min_client_degree_, max_client_degree_), + uniform_backbone_degree_(min_backbone_degree_, max_backbone_degree_), + uniform_source_(num_clients_ == 0 ? 0 : num_backbones_, + num_clients_ == 0 ? num_backbones - 1 + : num_clients_ + num_backbones_ - 1) { CHECK_GE(num_backbones, 1); CHECK_GE(num_clients, 0); CHECK_GE(num_demands, 1); @@ -180,16 +199,14 @@ class NetworkRoutingDataBuilder { CHECK_LE(max_client_degree, num_backbones); CHECK_LE(max_backbone_degree, num_backbones); CHECK_GE(max_capacity, 1); + } - const int size = num_backbones + num_clients; + void Build(int seed, NetworkRoutingData* const data) { + const int size = num_backbones_ + num_clients_; InitData(size, seed); - BuildGraph(num_clients, num_backbones, min_client_degree, max_client_degree, - min_backbone_degree, max_backbone_degree); - CreateDemands(num_clients, num_backbones, num_demands, traffic_min, - traffic_max, data); - FillData(num_clients, num_backbones, num_demands, traffic_min, traffic_max, - min_client_degree, max_client_degree, min_backbone_degree, - max_backbone_degree, max_capacity, fixed_charge_cost, seed, data); + BuildGraph(); + CreateDemands(data); + FillData(seed, data); } private: @@ -201,58 +218,57 @@ class NetworkRoutingDataBuilder { } degrees_.clear(); degrees_.resize(size, 0); - random_.Reset(seed); + rand_gen_.seed(seed); } - void BuildGraph(int num_clients, int num_backbones, int min_client_degree, - int max_client_degree, int min_backbone_degree, - int max_backbone_degree) { - const int size = num_backbones + num_clients; + void BuildGraph() { + const int size = num_backbones_ + num_clients_; // First we create the backbone nodes. - for (int i = 1; i < num_backbones; ++i) { - int j = random_.Uniform(i); + for (int i = 1; i < num_backbones_; ++i) { + absl::uniform_int_distribution source(0, i - 1); + const int j = source(rand_gen_); CHECK_LT(j, i); AddEdge(i, j); } - std::unordered_set to_complete; - std::unordered_set not_full; - for (int i = 0; i < num_backbones; ++i) { - if (degrees_[i] < min_backbone_degree) { + std::set to_complete; + std::set not_full; + for (int i = 0; i < num_backbones_; ++i) { + if (degrees_[i] < min_backbone_degree_) { to_complete.insert(i); } - if (degrees_[i] < max_backbone_degree) { + if (degrees_[i] < max_backbone_degree_) { not_full.insert(i); } } while (!to_complete.empty() && not_full.size() > 1) { const int node1 = *(to_complete.begin()); int node2 = node1; - while (node2 == node1 || degrees_[node2] >= max_backbone_degree) { - node2 = random_.Uniform(num_backbones); + while (node2 == node1 || degrees_[node2] >= max_backbone_degree_) { + node2 = uniform_backbones_(rand_gen_); } AddEdge(node1, node2); - if (degrees_[node1] >= min_backbone_degree) { + if (degrees_[node1] >= min_backbone_degree_) { to_complete.erase(node1); } - if (degrees_[node2] >= min_backbone_degree) { + if (degrees_[node2] >= min_backbone_degree_) { to_complete.erase(node2); } - if (degrees_[node1] >= max_backbone_degree) { + if (degrees_[node1] >= max_backbone_degree_) { not_full.erase(node1); } - if (degrees_[node2] >= max_backbone_degree) { + if (degrees_[node2] >= max_backbone_degree_) { not_full.erase(node2); } } // Then create the client nodes connected to the backbone nodes. // If num_client is 0, then backbone nodes are also client nodes. - for (int i = num_backbones; i < size; ++i) { - const int degree = RandomInInterval(min_client_degree, max_client_degree); + for (int i = num_backbones_; i < size; ++i) { + const int degree = uniform_client_degree_(rand_gen_); while (degrees_[i] < degree) { - const int j = random_.Uniform(num_backbones); + const int j = uniform_backbones_(rand_gen_); if (!network_[i][j]) { AddEdge(i, j); } @@ -260,33 +276,26 @@ class NetworkRoutingDataBuilder { } } - void CreateDemands(int num_clients, int num_backbones, int num_demands, - int traffic_min, int traffic_max, - NetworkRoutingData* const data) { - while (data->num_demands() < num_demands) { - const int source = RandomClient(num_clients, num_backbones); + void CreateDemands(NetworkRoutingData* const data) { + while (data->num_demands() < num_demands_) { + const int source = uniform_source_(rand_gen_); int dest = source; while (dest == source) { - dest = RandomClient(num_clients, num_backbones); + dest = uniform_source_(rand_gen_); } - const int traffic = RandomInInterval(traffic_min, traffic_max); + const int traffic = uniform_traffic_(rand_gen_); data->AddDemand(source, dest, traffic); } } - void FillData(int num_clients, int num_backbones, int num_demands, - int traffic_min, int traffic_max, int min_client_degree, - int max_client_degree, int min_backbone_degree, - int max_backbone_degree, int max_capacity, - int fixed_charge_cost, int seed, - NetworkRoutingData* const data) { - const int size = num_backbones + num_clients; + void FillData(int seed, NetworkRoutingData* const data) { + const int size = num_backbones_ + num_clients_; const std::string name = absl::StrFormat( - "mp_c%i_b%i_d%i.t%i-%i.cd%i-%i.bd%i-%i.mc%i.fc%i.s%i", num_clients, - num_backbones, num_demands, traffic_min, traffic_max, min_client_degree, - max_client_degree, min_backbone_degree, max_backbone_degree, - max_capacity, fixed_charge_cost, seed); + "mp_c%i_b%i_d%i.t%i-%i.cd%i-%i.bd%i-%i.mc%i.fc%i.s%i", num_clients_, + num_backbones_, num_demands_, traffic_min_, traffic_max_, + min_client_degree_, max_client_degree_, min_backbone_degree_, + max_backbone_degree_, max_capacity_, fixed_charge_cost_, seed); data->set_name(name); data->set_num_nodes(size); @@ -294,13 +303,13 @@ class NetworkRoutingDataBuilder { for (int i = 0; i < size - 1; ++i) { for (int j = i + 1; j < size; ++j) { if (network_[i][j]) { - data->AddArc(i, j, max_capacity); + data->AddArc(i, j, max_capacity_); num_arcs++; } } } - data->set_max_capacity(max_capacity); - data->set_fixed_charge_cost(fixed_charge_cost); + data->set_max_capacity(max_capacity_); + data->set_fixed_charge_cost(fixed_charge_cost_); } void AddEdge(int i, int j) { @@ -310,19 +319,28 @@ class NetworkRoutingDataBuilder { network_[j][i] = true; } - int RandomInInterval(int interval_min, int interval_max) { - CHECK_LE(interval_min, interval_max); - return random_.Uniform(interval_max - interval_min + 1) + interval_min; - } + const int num_clients_; + const int num_backbones_; + const int num_demands_; + const int traffic_min_; + const int traffic_max_; + const int min_client_degree_; + const int max_client_degree_; + const int min_backbone_degree_; + const int max_backbone_degree_; + const int max_capacity_; + const int fixed_charge_cost_; - int RandomClient(int num_clients, int num_backbones) { - return (num_clients == 0) ? random_.Uniform(num_backbones) - : random_.Uniform(num_clients) + num_backbones; - } - - std::vector > network_; + std::vector> network_; std::vector degrees_; - MTRandom random_; + std::mt19937 rand_gen_; + absl::uniform_int_distribution uniform_backbones_; + absl::uniform_int_distribution uniform_clients_; + absl::uniform_int_distribution uniform_demands_; + absl::uniform_int_distribution uniform_traffic_; + absl::uniform_int_distribution uniform_client_degree_; + absl::uniform_int_distribution uniform_backbone_degree_; + absl::uniform_int_distribution uniform_source_; }; // ---------- Solving the Problem ---------- @@ -341,7 +359,7 @@ struct Demand { class NetworkRoutingSolver { public: - typedef std::unordered_set OnePath; + typedef absl::flat_hash_set OnePath; NetworkRoutingSolver() : num_nodes_(-1) {} @@ -553,7 +571,7 @@ class NetworkRoutingSolver { // ----- Build Model ----- CpModelBuilder cp_model; - std::vector > path_vars(num_demands); + std::vector> path_vars(num_demands); // Node - Graph Constraint. for (int demand_index = 0; demand_index < num_demands; ++demand_index) { @@ -628,7 +646,6 @@ class NetworkRoutingSolver { int num_solutions = 0; model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse& r) { LOG(INFO) << "Solution " << num_solutions; - const double objective_value = r.objective_value(); const double percent = SolutionIntegerValue(r, max_usage_cost) / 10.0; int num_non_comfortable_arcs = 0; for (const BoolVar comfort : comfortable_traffic_vars) { @@ -651,31 +668,34 @@ class NetworkRoutingSolver { private: int count_arcs() const { return arcs_data_.size() / 2; } - std::vector > arcs_data_; + std::vector> arcs_data_; std::vector arc_capacity_; std::vector demands_array_; int num_nodes_; std::vector all_min_path_lengths_; - std::vector > capacity_; - std::vector > all_paths_; + std::vector> capacity_; + std::vector> all_paths_; }; } // namespace sat } // namespace operations_research int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); + operations_research::sat::NetworkRoutingData data; - operations_research::sat::NetworkRoutingDataBuilder builder; - builder.BuildModelFromParameters( + operations_research::sat::NetworkRoutingDataBuilder builder( absl::GetFlag(FLAGS_clients), absl::GetFlag(FLAGS_backbones), absl::GetFlag(FLAGS_demands), absl::GetFlag(FLAGS_traffic_min), absl::GetFlag(FLAGS_traffic_max), absl::GetFlag(FLAGS_min_client_degree), absl::GetFlag(FLAGS_max_client_degree), absl::GetFlag(FLAGS_min_backbone_degree), absl::GetFlag(FLAGS_max_backbone_degree), - absl::GetFlag(FLAGS_max_capacity), absl::GetFlag(FLAGS_fixed_charge_cost), - absl::GetFlag(FLAGS_seed), &data); + absl::GetFlag(FLAGS_max_capacity), + absl::GetFlag(FLAGS_fixed_charge_cost)); + builder.Build(absl::GetFlag(FLAGS_seed), &data); operations_research::sat::NetworkRoutingSolver solver; solver.Init(data, absl::GetFlag(FLAGS_extra_hops), absl::GetFlag(FLAGS_max_paths)); diff --git a/examples/cpp/opb_reader.h b/examples/cpp/opb_reader.h index 515a32af46..eb52d4f111 100644 --- a/examples/cpp/opb_reader.h +++ b/examples/cpp/opb_reader.h @@ -58,7 +58,7 @@ class OpbReader { // Since the problem name is not stored in the cnf format, we infer it from // the file name. static std::string ExtractProblemName(const std::string& filename) { - const int found = filename.find_last_of("/"); + const int found = filename.find_last_of('/'); const std::string problem_name = found != std::string::npos ? filename.substr(found + 1) : filename; return problem_name; diff --git a/examples/cpp/pdptw.cc b/examples/cpp/pdptw.cc index 8de40de207..68adc743a6 100644 --- a/examples/cpp/pdptw.cc +++ b/examples/cpp/pdptw.cc @@ -36,9 +36,14 @@ // Reads data in the format defined by Li & Lim // (https://www.sintef.no/projectweb/top/pdptw/li-lim-benchmark/documentation/). +#include #include #include +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/strings/numbers.h" #include "absl/strings/str_format.h" #include "absl/strings/str_split.h" #include "google/protobuf/text_format.h" @@ -134,7 +139,7 @@ std::vector GetTabuVars(std::vector existing_vars, return vars; } -// Outputs a solution to the current model in a std::string. +// Outputs a solution to the current model in a string. std::string VerboseOutput(const RoutingModel& routing, const RoutingIndexManager& manager, const Assignment& assignment, @@ -185,8 +190,7 @@ std::string VerboseOutput(const RoutingModel& routing, namespace { // An inefficient but convenient method to parse a whitespace-separated list -// of integers. Returns true iff the input std::string was entirely valid and -// parsed. +// of integers. Returns true iff the input string was entirely valid and parsed. bool SafeParseInt64Array(const std::string& str, std::vector* parsed_int) { std::istringstream input(str); @@ -390,6 +394,7 @@ bool LoadAndSolve(const std::string& pdp_file, int main(int argc, char** argv) { absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); operations_research::RoutingModelParameters model_parameters = operations_research::DefaultRoutingModelParameters(); diff --git a/examples/cpp/print_dimacs_assignment.h b/examples/cpp/print_dimacs_assignment.h index 43d4fb452f..9d9d75b9c3 100644 --- a/examples/cpp/print_dimacs_assignment.h +++ b/examples/cpp/print_dimacs_assignment.h @@ -37,6 +37,12 @@ class LinearSumAssignment; // description, outputs the problem in DIMACS format in the output file. // For a description of the format, see // http://lpsolve.sourceforge.net/5.5/DIMACS_asn.htm +template +void PrintDimacsAssignmentProblem( + const LinearSumAssignment& assignment, + const TailArrayManager& tail_array_manager, + const std::string& output_filename); + template void PrintDimacsAssignmentProblem( const LinearSumAssignment& assignment, diff --git a/examples/cpp/sat_runner.cc b/examples/cpp/sat_runner.cc index 19fa4b763c..fec5c88929 100644 --- a/examples/cpp/sat_runner.cc +++ b/examples/cpp/sat_runner.cc @@ -19,6 +19,8 @@ #include #include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/strings/match.h" @@ -443,9 +445,9 @@ int main(int argc, char** argv) { // By default, we want to show how the solver progress. Note that this needs // to be set before InitGoogle() which has the nice side-effect of allowing // the user to override it. - absl::SetProgramUsageMessage(kUsage); - absl::ParseCommandLine(argc, argv); - google::InitGoogleLogging(argv[0]); + absl::SetFlag(&FLAGS_vmodule, "cp_model_solver=1"); + gflags::SetUsageMessage(kUsage); + gflags::ParseCommandLineFlags(&argc, &argv, true); absl::SetFlag(&FLAGS_alsologtostderr, true); return operations_research::sat::Run(); } diff --git a/examples/cpp/shift_minimization_sat.cc b/examples/cpp/shift_minimization_sat.cc index d29059233e..c3551d1640 100644 --- a/examples/cpp/shift_minimization_sat.cc +++ b/examples/cpp/shift_minimization_sat.cc @@ -32,6 +32,8 @@ #include #include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/numbers.h" #include "absl/strings/str_split.h" #include "ortools/base/commandlineflags.h" @@ -303,7 +305,9 @@ void LoadAndSolve(const std::string& file_name) { int main(int argc, char** argv) { absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); + if (absl::GetFlag(FLAGS_input).empty()) { LOG(FATAL) << "Please supply a data file with --input="; } diff --git a/examples/cpp/solve.cc b/examples/cpp/solve.cc index b44d63827c..71f5f1524f 100644 --- a/examples/cpp/solve.cc +++ b/examples/cpp/solve.cc @@ -18,6 +18,8 @@ #include #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/match.h" #include "absl/strings/str_format.h" #include "ortools/base/commandlineflags.h" diff --git a/examples/cpp/sports_scheduling_sat.cc b/examples/cpp/sports_scheduling_sat.cc index cd371904d4..8b41abfa13 100644 --- a/examples/cpp/sports_scheduling_sat.cc +++ b/examples/cpp/sports_scheduling_sat.cc @@ -43,6 +43,8 @@ // We also introduces a variable at_home[d][i] which is true if team i // plays any opponent at home on day d. +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_join.h" @@ -323,8 +325,8 @@ static const char kUsage[] = "There is no output besides the debug LOGs of the solver."; int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(kUsage); absl::ParseCommandLine(argc, argv); CHECK_EQ(0, absl::GetFlag(FLAGS_num_teams) % 2) << "The number of teams must be even"; diff --git a/examples/cpp/strawberry_fields_with_column_generation.cc b/examples/cpp/strawberry_fields_with_column_generation.cc index 8233db2bbf..44044962a8 100644 --- a/examples/cpp/strawberry_fields_with_column_generation.cc +++ b/examples/cpp/strawberry_fields_with_column_generation.cc @@ -59,6 +59,8 @@ #include #include +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/str_format.h" #include "ortools/base/commandlineflags.h" #include "ortools/base/logging.h" @@ -241,8 +243,8 @@ const int kInstanceCount = 10; class Box { public: - static const int kAreaCost = 1; - static const int kFixedCost = 10; + static constexpr int kAreaCost = 1; + static constexpr int kFixedCost = 10; Box() {} Box(int x_min, int x_max, int y_min, int y_max) @@ -602,6 +604,7 @@ int main(int argc, char** argv) { usage += " --colgen_max_iterations max columns to generate\n"; usage += " --colgen_complete generate all columns at start\n"; + google::InitGoogleLogging(usage.c_str()); absl::ParseCommandLine(argc, argv); operations_research::MPSolver::OptimizationProblemType solver_type; diff --git a/examples/cpp/weighted_tardiness_sat.cc b/examples/cpp/weighted_tardiness_sat.cc index 0a98b40646..756c77676f 100644 --- a/examples/cpp/weighted_tardiness_sat.cc +++ b/examples/cpp/weighted_tardiness_sat.cc @@ -17,6 +17,8 @@ #include #include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" #include "absl/strings/str_join.h" @@ -253,6 +255,7 @@ void ParseAndSolve() { int main(int argc, char** argv) { absl::SetFlag(&FLAGS_logtostderr, true); + google::InitGoogleLogging(argv[0]); absl::ParseCommandLine(argc, argv); if (absl::GetFlag(FLAGS_input).empty()) { LOG(FATAL) << "Please supply a data file with --input="; diff --git a/makefiles/Makefile.cpp.mk b/makefiles/Makefile.cpp.mk index 9343c9163a..f50b888678 100644 --- a/makefiles/Makefile.cpp.mk +++ b/makefiles/Makefile.cpp.mk @@ -483,6 +483,7 @@ test_cc_contrib: ; .PHONY: test_cc_cpp # Build and Run all C++ Examples (located in ortools/examples/cpp) test_cc_cpp: \ rcc_costas_array_sat \ + rcc_cryptarithm_sat \ rcc_cvrp_disjoint_tw \ rcc_cvrptw \ rcc_cvrptw_with_breaks \ @@ -492,6 +493,7 @@ test_cc_cpp: \ rcc_flow_api \ rcc_linear_assignment_api \ rcc_linear_solver_protocol_buffers \ + rcc_magic_sequence_sat \ rcc_magic_square_sat \ rcc_nqueens \ rcc_random_tsp \