diff --git a/examples/cpp/acp_challenge.cc b/examples/cpp/acp_challenge.cc index 4d2f81788e..e68b1b2835 100644 --- a/examples/cpp/acp_challenge.cc +++ b/examples/cpp/acp_challenge.cc @@ -129,7 +129,9 @@ class AcpData { } break; } - default: { LOG(ERROR) << "Should not be here"; } + default: { + LOG(ERROR) << "Should not be here"; + } } } diff --git a/examples/cpp/acp_challenge_routing.cc b/examples/cpp/acp_challenge_routing.cc index 77fa8c09f0..1b751dcb69 100644 --- a/examples/cpp/acp_challenge_routing.cc +++ b/examples/cpp/acp_challenge_routing.cc @@ -98,7 +98,9 @@ class AcpData { } break; } - default: { LOG(ERROR) << "Should not be here"; } + default: { + LOG(ERROR) << "Should not be here"; + } } } diff --git a/examples/cpp/constraint_programming_cp.cc b/examples/cpp/constraint_programming_cp.cc index 390cdb3e35..5f1d4d4b8d 100644 --- a/examples/cpp/constraint_programming_cp.cc +++ b/examples/cpp/constraint_programming_cp.cc @@ -17,46 +17,43 @@ #include "ortools/constraint_solver/constraint_solver.h" namespace operations_research { - void RunConstraintProgrammingExample() { - // Instantiate the solver. - Solver solver("ConstraintProgrammingExample"); - const int64 numVals = 3; +void RunConstraintProgrammingExample() { + // Instantiate the solver. + Solver solver("ConstraintProgrammingExample"); + const int64 numVals = 3; - // Define decision variables. - IntVar* const x = solver.MakeIntVar(0, numVals - 1, "x"); - IntVar* const y = solver.MakeIntVar(0, numVals - 1, "y"); - IntVar* const z = solver.MakeIntVar(0, numVals - 1, "z"); + // Define decision variables. + IntVar* const x = solver.MakeIntVar(0, numVals - 1, "x"); + IntVar* const y = solver.MakeIntVar(0, numVals - 1, "y"); + IntVar* const z = solver.MakeIntVar(0, numVals - 1, "z"); - // Define constraints. - std::vector xyvars = {x, y}; - solver.AddConstraint(solver.MakeAllDifferent(xyvars)); + // Define constraints. + std::vector xyvars = {x, y}; + solver.AddConstraint(solver.MakeAllDifferent(xyvars)); - LOG(INFO) << "Number of constraints: " << solver.constraints(); + LOG(INFO) << "Number of constraints: " << solver.constraints(); - // Create decision builder to search for solutions. - std::vector allvars = {x, y, z}; - DecisionBuilder* const db = solver.MakePhase( - allvars, - Solver::CHOOSE_FIRST_UNBOUND, - Solver::ASSIGN_MIN_VALUE); + // Create decision builder to search for solutions. + std::vector allvars = {x, y, z}; + DecisionBuilder* const db = solver.MakePhase( + allvars, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); - solver.NewSearch(db); - while (solver.NextSolution()) { - LOG(INFO) << "Solution" - << ": x = " << x->Value() - << "; y = " << x->Value() - << "; z = " << z->Value(); - } - solver.EndSearch(); - LOG(INFO) << "Number of solutions: " << solver.solutions(); - LOG(INFO) << ""; - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Problem solved in " << solver.wall_time() << "ms"; - LOG(INFO) << "Memory usage: " << Solver::MemoryUsage() << " bytes"; + solver.NewSearch(db); + while (solver.NextSolution()) { + LOG(INFO) << "Solution" + << ": x = " << x->Value() << "; y = " << x->Value() + << "; z = " << z->Value(); } + solver.EndSearch(); + LOG(INFO) << "Number of solutions: " << solver.solutions(); + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << solver.wall_time() << "ms"; + LOG(INFO) << "Memory usage: " << Solver::MemoryUsage() << " bytes"; +} } // namespace operations_research -int main(int argc, char **argv) { +int main(int argc, char** argv) { google::InitGoogleLogging(argv[0]); FLAGS_logtostderr = 1; operations_research::RunConstraintProgrammingExample(); diff --git a/examples/cpp/cvrptw_lib.cc b/examples/cpp/cvrptw_lib.cc index 1750ea1e27..0600e2d57a 100644 --- a/examples/cpp/cvrptw_lib.cc +++ b/examples/cpp/cvrptw_lib.cc @@ -182,8 +182,7 @@ void DisplayPlan( for (int64 order = 0; order < routing.Size(); ++order) { if (routing.IsStart(order) || routing.IsEnd(order)) continue; ++group_size; - visited.insert( - plan.Value(routing.VehicleVar(order))); + 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; @@ -214,12 +213,12 @@ void DisplayPlan( operations_research::IntVar* const slack_var = routing.IsEnd(order) ? nullptr : time_dimension.SlackVar(order); if (slack_var != nullptr && plan.Contains(slack_var)) { - StringAppendF( - &plan_output, - "%lld Load(%lld) Time(%lld, %lld) Slack(%lld, %lld)", - routing.IndexToNode(order).value(), - plan.Value(load_var), plan.Min(time_var), plan.Max(time_var), - plan.Min(slack_var), plan.Max(slack_var)); + StringAppendF(&plan_output, + "%lld Load(%lld) Time(%lld, %lld) Slack(%lld, %lld)", + routing.IndexToNode(order).value(), + plan.Value(load_var), plan.Min(time_var), + plan.Max(time_var), plan.Min(slack_var), + plan.Max(slack_var)); } else { StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld)", routing.IndexToNode(order).value(), diff --git a/examples/cpp/cvrptw_lib.h b/examples/cpp/cvrptw_lib.h index ac40f8bcd2..3128df8310 100644 --- a/examples/cpp/cvrptw_lib.h +++ b/examples/cpp/cvrptw_lib.h @@ -64,7 +64,8 @@ class LocationContainer { MTRandom randomizer_; const int64 speed_; - gtl::ITIVector locations_; + gtl::ITIVector + locations_; }; // Random demand. diff --git a/examples/cpp/integer_programming.cc b/examples/cpp/integer_programming.cc index 3a08e7b31b..94951ead34 100644 --- a/examples/cpp/integer_programming.cc +++ b/examples/cpp/integer_programming.cc @@ -17,71 +17,72 @@ #include "ortools/linear_solver/linear_solver.h" namespace operations_research { - void RunIntegerProgrammingExample( - MPSolver::OptimizationProblemType optimization_problem_type) { - MPSolver solver("IntegerProgrammingExample", optimization_problem_type); - const double infinity = solver.infinity(); - // x and y are integer non-negative variables. - MPVariable* const x = solver.MakeIntVar(0.0, infinity, "x"); - MPVariable* const y = solver.MakeIntVar(0.0, infinity, "y"); +void RunIntegerProgrammingExample( + MPSolver::OptimizationProblemType optimization_problem_type) { + MPSolver solver("IntegerProgrammingExample", optimization_problem_type); + const double infinity = solver.infinity(); + // x and y are integer non-negative variables. + MPVariable* const x = solver.MakeIntVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeIntVar(0.0, infinity, "y"); - // Maximize x + 10 * y. - MPObjective* const objective = solver.MutableObjective(); - objective->SetCoefficient(x, 1); - objective->SetCoefficient(y, 10); - objective->SetMaximization(); + // Maximize x + 10 * y. + MPObjective* const objective = solver.MutableObjective(); + objective->SetCoefficient(x, 1); + objective->SetCoefficient(y, 10); + objective->SetMaximization(); - // x + 7 * y <= 17.5. - MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 17.5); - c0->SetCoefficient(x, 1); - c0->SetCoefficient(y, 7); + // x + 7 * y <= 17.5. + MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 17.5); + c0->SetCoefficient(x, 1); + c0->SetCoefficient(y, 7); - // x <= 3.5 - MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 3.5); - c1->SetCoefficient(x, 1); - c1->SetCoefficient(y, 0); + // x <= 3.5 + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 3.5); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 0); - LOG(INFO) << "Number of variables = " << solver.NumVariables(); - LOG(INFO) << "Number of constraints = " << solver.NumConstraints(); + LOG(INFO) << "Number of variables = " << solver.NumVariables(); + LOG(INFO) << "Number of constraints = " << solver.NumConstraints(); - const MPSolver::ResultStatus result_status = solver.Solve(); - // Check that the problem has an optimal solution. - if (result_status != MPSolver::OPTIMAL) { - LOG(FATAL) << "The problem does not have an optimal solution!"; - } - LOG(INFO) << "Solution:"; - LOG(INFO) << "x = " << x->solution_value(); - LOG(INFO) << "y = " << y->solution_value(); - LOG(INFO) << "Optimal objective value = " << objective->Value(); - LOG(INFO) << ""; - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds"; - LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations"; - LOG(INFO) << "Problem solved in " << solver.nodes() << " branch-and-bound nodes"; + const MPSolver::ResultStatus result_status = solver.Solve(); + // Check that the problem has an optimal solution. + if (result_status != MPSolver::OPTIMAL) { + LOG(FATAL) << "The problem does not have an optimal solution!"; } + LOG(INFO) << "Solution:"; + LOG(INFO) << "x = " << x->solution_value(); + LOG(INFO) << "y = " << y->solution_value(); + LOG(INFO) << "Optimal objective value = " << objective->Value(); + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds"; + LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations"; + LOG(INFO) << "Problem solved in " << solver.nodes() + << " branch-and-bound nodes"; +} - void RunAllExamples() { +void RunAllExamples() { #if defined(USE_CBC) - LOG(INFO) << "---- Integer programming example with CBC ----"; - RunIntegerProgrammingExample(MPSolver::CBC_MIXED_INTEGER_PROGRAMMING); + LOG(INFO) << "---- Integer programming example with CBC ----"; + RunIntegerProgrammingExample(MPSolver::CBC_MIXED_INTEGER_PROGRAMMING); #endif #if defined(USE_GLPK) - LOG(INFO) << "---- Integer programming example with GLPK ----"; - RunIntegerProgrammingExample(MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING); + LOG(INFO) << "---- Integer programming example with GLPK ----"; + RunIntegerProgrammingExample(MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING); #endif #if defined(USE_SCIP) - LOG(INFO) << "---- Integer programming example with SCIP ----"; - RunIntegerProgrammingExample(MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING); + LOG(INFO) << "---- Integer programming example with SCIP ----"; + RunIntegerProgrammingExample(MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING); #endif #if defined(USE_GUROBI) - LOG(INFO) << "---- Integer programming example with Gurobi ----"; - RunIntegerProgrammingExample(MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING); + LOG(INFO) << "---- Integer programming example with Gurobi ----"; + RunIntegerProgrammingExample(MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING); #endif // USE_GUROBI #if defined(USE_CPLEX) - LOG(INFO) << "---- Integer programming example with CPLEX ----"; - RunIntegerProgrammingExample(MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING); + LOG(INFO) << "---- Integer programming example with CPLEX ----"; + RunIntegerProgrammingExample(MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING); #endif // USE_CPLEX - } +} } // namespace operations_research int main(int argc, char** argv) { diff --git a/examples/cpp/job_shop_cp.cc b/examples/cpp/job_shop_cp.cc index c6b5b8789a..3e6a7cea7c 100644 --- a/examples/cpp/job_shop_cp.cc +++ b/examples/cpp/job_shop_cp.cc @@ -12,7 +12,7 @@ // limitations under the License. #include -#include // std::iota +#include // std::iota #include "ortools/base/logging.h" #include "ortools/constraint_solver/constraint_solver.h" @@ -20,185 +20,170 @@ // Solve a job shop problem: namespace operations_research { - void SolveJobShopExample() { - // Instantiate the solver. - Solver solver("JobShopExample"); - std::array machines; - std::iota(std::begin(machines), std::end(machines), 0); - { - std::ostringstream oss; - for (auto i : machines) - oss << ' ' << i; - LOG(INFO) << "Machines: " << oss.str(); - } +void SolveJobShopExample() { + // Instantiate the solver. + Solver solver("JobShopExample"); + std::array machines; + std::iota(std::begin(machines), std::end(machines), 0); + { + std::ostringstream oss; + for (auto i : machines) oss << ' ' << i; + LOG(INFO) << "Machines: " << oss.str(); + } - // Jobs definition - using MachineIndex = int; - using ProcessingTime = int; - using Task = std::pair; - using Job = std::vector; - std::vector jobs = { - {{0, 3}, {1, 2}, {2, 2}}, - {{0, 2}, {2, 1}, {1, 4}}, - {{1, 4}, {2, 3}} - }; - LOG(INFO) << "Jobs:"; - for (int i=0; i < jobs.size(); ++i) { - std::ostringstream problem; - problem << "Job "<< i << ": ["; - for (const Task& task: jobs[i]) { - problem << "(" << task.first << ", " << task.second << ")"; - } - problem << "]" << std::endl; - LOG(INFO) << problem.str(); - } + // Jobs definition + using MachineIndex = int; + using ProcessingTime = int; + using Task = std::pair; + using Job = std::vector; + std::vector jobs = { + {{0, 3}, {1, 2}, {2, 2}}, {{0, 2}, {2, 1}, {1, 4}}, {{1, 4}, {2, 3}}}; + LOG(INFO) << "Jobs:"; + for (int i = 0; i < jobs.size(); ++i) { + std::ostringstream problem; + problem << "Job " << i << ": ["; + for (const Task& task : jobs[i]) { + problem << "(" << task.first << ", " << task.second << ")"; + } + problem << "]" << std::endl; + LOG(INFO) << problem.str(); + } - // Computes horizon. - ProcessingTime horizon = 0; - for (const Job& job: jobs) { - for (const Task& task: job) { - horizon += task.second; - } - } - LOG(INFO) << "Horizon: " << horizon; + // Computes horizon. + ProcessingTime horizon = 0; + for (const Job& job : jobs) { + for (const Task& task : job) { + horizon += task.second; + } + } + LOG(INFO) << "Horizon: " << horizon; - // Creates tasks. - std::vector> tasks_matrix(jobs.size()); - for (int i=0; i < jobs.size(); ++i) { - for (int j=0; j < jobs[i].size(); ++j) { - std::ostringstream oss; - oss << "Job_" << i << "_" << j; - tasks_matrix[i].push_back( - solver.MakeFixedDurationIntervalVar( - 0, - horizon, - jobs[i][j].second, - false, - oss.str())); - } - } + // Creates tasks. + std::vector> tasks_matrix(jobs.size()); + for (int i = 0; i < jobs.size(); ++i) { + for (int j = 0; j < jobs[i].size(); ++j) { + std::ostringstream oss; + oss << "Job_" << i << "_" << j; + tasks_matrix[i].push_back(solver.MakeFixedDurationIntervalVar( + 0, horizon, jobs[i][j].second, false, oss.str())); + } + } - // Add conjunctive contraints. - for (int i=0; i < jobs.size(); ++i) { - for (int j=0; j < jobs[i].size()-1; ++j) { - solver.AddConstraint( - solver.MakeIntervalVarRelation( - tasks_matrix[i][j+1], - Solver::STARTS_AFTER_END, - tasks_matrix[i][j])); - } - } + // Add conjunctive contraints. + for (int i = 0; i < jobs.size(); ++i) { + for (int j = 0; j < jobs[i].size() - 1; ++j) { + solver.AddConstraint(solver.MakeIntervalVarRelation( + tasks_matrix[i][j + 1], Solver::STARTS_AFTER_END, + tasks_matrix[i][j])); + } + } - // Creates sequence variables and add disjunctive constraints. - std::vector all_sequences; - std::vector all_machines_jobs; - for (const auto machine: machines) { - std::vector machines_jobs; - for (int i=0; i < jobs.size(); ++i) { - for (int j=0; j < jobs[i].size(); ++j) { - if (jobs[i][j].first == machine) - machines_jobs.push_back(tasks_matrix[i][j]); - } - } - DisjunctiveConstraint* const disj = - solver.MakeDisjunctiveConstraint( - machines_jobs, - "Machine_" + std::to_string(machine)); - solver.AddConstraint(disj); - all_sequences.push_back(disj->MakeSequenceVar()); - } + // Creates sequence variables and add disjunctive constraints. + std::vector all_sequences; + std::vector all_machines_jobs; + for (const auto machine : machines) { + std::vector machines_jobs; + for (int i = 0; i < jobs.size(); ++i) { + for (int j = 0; j < jobs[i].size(); ++j) { + if (jobs[i][j].first == machine) + machines_jobs.push_back(tasks_matrix[i][j]); + } + } + DisjunctiveConstraint* const disj = solver.MakeDisjunctiveConstraint( + machines_jobs, "Machine_" + std::to_string(machine)); + solver.AddConstraint(disj); + all_sequences.push_back(disj->MakeSequenceVar()); + } - // Set the objective. - std::vector all_ends; - for (const auto& job: tasks_matrix) { - IntervalVar* const task = job.back(); - all_ends.push_back(task->EndExpr()->Var()); - } - IntVar* const obj_var = solver.MakeMax(all_ends)->Var(); - OptimizeVar* const objective_monitor = solver.MakeMinimize(obj_var, 1); + // Set the objective. + std::vector all_ends; + for (const auto& job : tasks_matrix) { + IntervalVar* const task = job.back(); + all_ends.push_back(task->EndExpr()->Var()); + } + IntVar* const obj_var = solver.MakeMax(all_ends)->Var(); + OptimizeVar* const objective_monitor = solver.MakeMinimize(obj_var, 1); - // ----- Search monitors and decision builder ----- + // ----- Search monitors and decision builder ----- - // This decision builder will rank all tasks on all machines. - DecisionBuilder* const sequence_phase = solver.MakePhase( - all_sequences, - Solver::SEQUENCE_DEFAULT); + // This decision builder will rank all tasks on all machines. + DecisionBuilder* const sequence_phase = + solver.MakePhase(all_sequences, Solver::SEQUENCE_DEFAULT); - // After the ranking of tasks, the schedule is still loose and any - // task can be postponed at will. But, because the problem is now a PERT - // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique), - // we can schedule each task at its earliest start time. This is - // conveniently done by fixing the objective variable to its - // minimum value. - DecisionBuilder* const obj_phase = solver.MakePhase( - obj_var, - Solver::CHOOSE_FIRST_UNBOUND, - Solver::ASSIGN_MIN_VALUE); + // After the ranking of tasks, the schedule is still loose and any + // task can be postponed at will. But, because the problem is now a PERT + // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique), + // we can schedule each task at its earliest start time. This is + // conveniently done by fixing the objective variable to its + // minimum value. + DecisionBuilder* const obj_phase = solver.MakePhase( + obj_var, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); - // The main decision builder (ranks all tasks, then fixes the - // objective_variable). - DecisionBuilder* const main_phase = solver.Compose(sequence_phase, obj_phase); + // The main decision builder (ranks all tasks, then fixes the + // objective_variable). + DecisionBuilder* const main_phase = solver.Compose(sequence_phase, obj_phase); - // Search log. - const int kLogFrequency = 1000000; - SearchMonitor* const search_log = - solver.MakeSearchLog(kLogFrequency, objective_monitor); + // Search log. + const int kLogFrequency = 1000000; + SearchMonitor* const search_log = + solver.MakeSearchLog(kLogFrequency, objective_monitor); - SearchLimit* limit = nullptr; + SearchLimit* limit = nullptr; - // Create the solution collector. - SolutionCollector* const collector = solver.MakeLastSolutionCollector(); - collector->Add(all_sequences); - collector->AddObjective(obj_var); - for (const auto machine: machines) { - SequenceVar* const sequence = all_sequences[machine]; - for (int i=0; i < sequence->size(); ++i) { - IntervalVar* const t = sequence->Interval(i); - collector->Add(t->StartExpr()->Var()); - collector->Add(t->EndExpr()->Var()); - } - } + // Create the solution collector. + SolutionCollector* const collector = solver.MakeLastSolutionCollector(); + collector->Add(all_sequences); + collector->AddObjective(obj_var); + for (const auto machine : machines) { + SequenceVar* const sequence = all_sequences[machine]; + for (int i = 0; i < sequence->size(); ++i) { + IntervalVar* const t = sequence->Interval(i); + collector->Add(t->StartExpr()->Var()); + collector->Add(t->EndExpr()->Var()); + } + } - // Solve the problem. - if (solver.Solve(main_phase, search_log, objective_monitor, limit, collector)) { - LOG(INFO) << "Optimal Schedule Length: " << collector->objective_value(0); - LOG(INFO) << ""; + // Solve the problem. + if (solver.Solve(main_phase, search_log, objective_monitor, limit, + collector)) { + LOG(INFO) << "Optimal Schedule Length: " << collector->objective_value(0); + LOG(INFO) << ""; - LOG(INFO) << "Optimal Schedule:"; - std::vector machine_intervals_list; - for (const auto machine: machines) { - std::ostringstream machine_tasks; - SequenceVar* seq = all_sequences[machine]; - machine_tasks << "Machine " << machine << ": "; - for (const auto s: collector->ForwardSequence(0, seq)) { - machine_tasks << seq->Interval(s)->name() << " "; - } - LOG(INFO) << machine_tasks.str(); + LOG(INFO) << "Optimal Schedule:"; + std::vector machine_intervals_list; + for (const auto machine : machines) { + std::ostringstream machine_tasks; + SequenceVar* seq = all_sequences[machine]; + machine_tasks << "Machine " << machine << ": "; + for (const auto s : collector->ForwardSequence(0, seq)) { + machine_tasks << seq->Interval(s)->name() << " "; + } + LOG(INFO) << machine_tasks.str(); - std::ostringstream machine_intervals; - machine_intervals << "Machine " << machine << ": "; - for (const auto s: collector->ForwardSequence(0, seq)) { - IntervalVar* t = seq->Interval(s); - machine_intervals << "[" - << std::setw(2) << collector->Value(0, t->StartExpr()->Var()) << ", " - << std::setw(2) << collector->Value(0, t->EndExpr()->Var()) << "] "; - } - machine_intervals_list.push_back(machine_intervals.str()); - } - LOG(INFO) << "Time Intervals for Tasks: "; - for (const auto& intervals: machine_intervals_list) { - LOG(INFO) << intervals; - } - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Time: " << solver.wall_time() << "ms"; - } - } + std::ostringstream machine_intervals; + machine_intervals << "Machine " << machine << ": "; + for (const auto s : collector->ForwardSequence(0, seq)) { + IntervalVar* t = seq->Interval(s); + machine_intervals << "[" << std::setw(2) + << collector->Value(0, t->StartExpr()->Var()) << ", " + << std::setw(2) + << collector->Value(0, t->EndExpr()->Var()) << "] "; + } + machine_intervals_list.push_back(machine_intervals.str()); + } + LOG(INFO) << "Time Intervals for Tasks: "; + for (const auto& intervals : machine_intervals_list) { + LOG(INFO) << intervals; + } + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Time: " << solver.wall_time() << "ms"; + } +} } // namespace operations_research -int main(int argc, char **argv) { - google::InitGoogleLogging(argv[0]); - FLAGS_logtostderr = 1; - operations_research::SolveJobShopExample(); - return EXIT_SUCCESS; +int main(int argc, char** argv) { + google::InitGoogleLogging(argv[0]); + FLAGS_logtostderr = 1; + operations_research::SolveJobShopExample(); + return EXIT_SUCCESS; } - diff --git a/examples/cpp/jobshop_sat.cc b/examples/cpp/jobshop_sat.cc index 1dc195eaee..805e844b67 100644 --- a/examples/cpp/jobshop_sat.cc +++ b/examples/cpp/jobshop_sat.cc @@ -55,7 +55,8 @@ int64 ComputeHorizon(const JsspInputProblem& problem) { int64 max_earliest_start = 0; for (const Job& job : problem.jobs()) { if (job.has_latest_end()) { - max_latest_end = std::max(max_latest_end, job.latest_end().value()); + max_latest_end = + std::max(max_latest_end, job.latest_end().value()); } else { max_latest_end = kint64max; } @@ -80,8 +81,8 @@ int64 ComputeHorizon(const JsspInputProblem& problem) { for (int i = 0; i < num_jobs; ++i) { int64 max_transition = 0; for (int j = 0; j < num_jobs; ++j) { - max_transition = - std::max(max_transition, matrix.transition_time(i * num_jobs + j)); + max_transition = std::max( + max_transition, matrix.transition_time(i * num_jobs + j)); } sum_of_transitions += max_transition; } diff --git a/examples/cpp/knapsack.cc b/examples/cpp/knapsack.cc index c112399b84..49381fb05c 100644 --- a/examples/cpp/knapsack.cc +++ b/examples/cpp/knapsack.cc @@ -13,32 +13,29 @@ // Bi-dimensional knapsack problem. +#include #include #include -#include -#include "ortools/base/logging.h" #include "ortools/algorithms/knapsack_solver.h" +#include "ortools/base/logging.h" namespace operations_research { - void RunKnapsackExample() { - // Instantiate the solver. +void RunKnapsackExample() { + // Instantiate the solver. KnapsackSolver solver( KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, "KnapsackExample"); std::vector values = { - 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147, - 78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28, 87, - 73, 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276, 312 - }; + 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, + 38, 48, 147, 78, 256, 63, 17, 120, 164, 432, 35, 92, 110, + 22, 42, 50, 323, 514, 28, 87, 73, 78, 15, 26, 78, 210, + 36, 85, 189, 274, 43, 33, 10, 19, 389, 276, 312}; std::vector> weights = { - { - 7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9, 0, - 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71, 3, - 86, 66, 31, 65, 0, 79, 20, 65, 52, 13 - } - }; + {7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, + 42, 9, 0, 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, + 7, 29, 93, 44, 71, 3, 86, 66, 31, 65, 0, 79, 20, 65, 52, 13}}; std::vector capacities = {850}; @@ -47,29 +44,32 @@ namespace operations_research { // Print solution std::vector packed_items; - for (std::size_t i=0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { if (solver.BestSolutionContains(i)) packed_items.push_back(i); } std::ostringstream packed_items_ss; - std::copy(packed_items.begin(), packed_items.end()-1, std::ostream_iterator(packed_items_ss, ", ")); + std::copy(packed_items.begin(), packed_items.end() - 1, + std::ostream_iterator(packed_items_ss, ", ")); packed_items_ss << packed_items.back(); std::vector packed_weights; packed_weights.reserve(packed_items.size()); - for (const auto &it: packed_items) { + for (const auto &it : packed_items) { packed_weights.push_back(weights[0][it]); } std::ostringstream packed_weights_ss; - std::copy(packed_weights.begin(), packed_weights.end()-1, std::ostream_iterator(packed_weights_ss, ", ")); + std::copy(packed_weights.begin(), packed_weights.end() - 1, + std::ostream_iterator(packed_weights_ss, ", ")); packed_weights_ss << packed_weights.back(); - int64 total_weights = std::accumulate(packed_weights.begin(), packed_weights.end(), 0LL); + int64 total_weights = + std::accumulate(packed_weights.begin(), packed_weights.end(), 0LL); LOG(INFO) << "Total value: " << computed_value; LOG(INFO) << "Packed items: {" << packed_items_ss.str() << "}"; LOG(INFO) << "Total weight: " << total_weights; LOG(INFO) << "Packed weights: {" << packed_weights_ss.str() << "}"; - } +} } // namespace operations_research int main(int argc, char **argv) { diff --git a/examples/cpp/linear_programming.cc b/examples/cpp/linear_programming.cc index fe2096d76d..e37d6f0aa1 100644 --- a/examples/cpp/linear_programming.cc +++ b/examples/cpp/linear_programming.cc @@ -18,60 +18,61 @@ #include "ortools/linear_solver/linear_solver.pb.h" namespace operations_research { - void RunLinearProgrammingExample() { - MPSolver solver("LinearProgrammingExample", MPSolver::GLOP_LINEAR_PROGRAMMING); - const double infinity = solver.infinity(); - // x and y are continuous non-negative variables. - MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); - MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); +void RunLinearProgrammingExample() { + MPSolver solver("LinearProgrammingExample", + MPSolver::GLOP_LINEAR_PROGRAMMING); + const double infinity = solver.infinity(); + // x and y are continuous non-negative variables. + MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); - // Objectif function: Maximize 3x + 4y. - MPObjective* const objective = solver.MutableObjective(); - objective->SetCoefficient(x, 3); - objective->SetCoefficient(y, 4); - objective->SetMaximization(); + // Objectif function: Maximize 3x + 4y. + MPObjective* const objective = solver.MutableObjective(); + objective->SetCoefficient(x, 3); + objective->SetCoefficient(y, 4); + objective->SetMaximization(); - // x + 2y <= 14. - MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 14.0); - c0->SetCoefficient(x, 1); - c0->SetCoefficient(y, 2); + // x + 2y <= 14. + MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 14.0); + c0->SetCoefficient(x, 1); + c0->SetCoefficient(y, 2); - // 3x - y >= 0. - MPConstraint* const c1 = solver.MakeRowConstraint(0.0, infinity); - c1->SetCoefficient(x, 3); - c1->SetCoefficient(y, -1); + // 3x - y >= 0. + MPConstraint* const c1 = solver.MakeRowConstraint(0.0, infinity); + c1->SetCoefficient(x, 3); + c1->SetCoefficient(y, -1); - // x - y <= 2. - MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 2.0); - c2->SetCoefficient(x, 1); - c2->SetCoefficient(y, -1); + // x - y <= 2. + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 2.0); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, -1); - LOG(INFO) << "Number of variables = " << solver.NumVariables(); - LOG(INFO) << "Number of constraints = " << solver.NumConstraints(); + LOG(INFO) << "Number of variables = " << solver.NumVariables(); + LOG(INFO) << "Number of constraints = " << solver.NumConstraints(); - const MPSolver::ResultStatus result_status = solver.Solve(); - // Check that the problem has an optimal solution. - if (result_status != MPSolver::OPTIMAL) { - LOG(FATAL) << "The problem does not have an optimal solution!"; - } - LOG(INFO) << "Solution:"; - LOG(INFO) << "x = " << x->solution_value(); - LOG(INFO) << "y = " << y->solution_value(); - LOG(INFO) << "Optimal objective value = " << objective->Value(); - LOG(INFO) << ""; - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds"; - LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations"; - LOG(INFO) << "x: reduced cost = " << x->reduced_cost(); - LOG(INFO) << "y: reduced cost = " << y->reduced_cost(); - const std::vector activities = solver.ComputeConstraintActivities(); - LOG(INFO) << "c0: dual value = " << c0->dual_value() - << " activity = " << activities[c0->index()]; - LOG(INFO) << "c1: dual value = " << c1->dual_value() - << " activity = " << activities[c1->index()]; - LOG(INFO) << "c2: dual value = " << c2->dual_value() - << " activity = " << activities[c2->index()]; + const MPSolver::ResultStatus result_status = solver.Solve(); + // Check that the problem has an optimal solution. + if (result_status != MPSolver::OPTIMAL) { + LOG(FATAL) << "The problem does not have an optimal solution!"; } + LOG(INFO) << "Solution:"; + LOG(INFO) << "x = " << x->solution_value(); + LOG(INFO) << "y = " << y->solution_value(); + LOG(INFO) << "Optimal objective value = " << objective->Value(); + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds"; + LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations"; + LOG(INFO) << "x: reduced cost = " << x->reduced_cost(); + LOG(INFO) << "y: reduced cost = " << y->reduced_cost(); + const std::vector activities = solver.ComputeConstraintActivities(); + LOG(INFO) << "c0: dual value = " << c0->dual_value() + << " activity = " << activities[c0->index()]; + LOG(INFO) << "c1: dual value = " << c1->dual_value() + << " activity = " << activities[c1->index()]; + LOG(INFO) << "c2: dual value = " << c2->dual_value() + << " activity = " << activities[c2->index()]; +} } // namespace operations_research int main(int argc, char** argv) { diff --git a/examples/cpp/magic_square.cc b/examples/cpp/magic_square.cc index 3c0d8310e5..f55686ae23 100644 --- a/examples/cpp/magic_square.cc +++ b/examples/cpp/magic_square.cc @@ -106,7 +106,9 @@ void MagicSquare(int grid_size) { DefaultPhaseParameters::CHOOSE_MAX_VALUE_IMPACT; break; } - default: { LOG(FATAL) << "Should not be here"; } + default: { + LOG(FATAL) << "Should not be here"; + } } parameters.value_selection_schema = FLAGS_select_max_impact_value ? DefaultPhaseParameters::SELECT_MAX_IMPACT diff --git a/examples/cpp/max_flow.cc b/examples/cpp/max_flow.cc index 5b41b47bde..4f212c5d5e 100644 --- a/examples/cpp/max_flow.cc +++ b/examples/cpp/max_flow.cc @@ -11,53 +11,43 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ortools/base/logging.h" #include "ortools/graph/max_flow.h" +#include "ortools/base/logging.h" namespace operations_research { - void SolveMaxFlow() { - const int num_nodes = 5; - // Add each arc - // Can't use std::tuple - // Initialization list is not working on std:tuple cf. N4387 - // Arc are stored as {{begin_node, end_node}, capacity} - std::vector, FlowQuantity>> arcs = { - {{0, 1}, 20}, - {{0, 2}, 30}, - {{0, 3}, 10}, - {{1, 2}, 40}, - {{1, 4}, 30}, - {{2, 3}, 10}, - {{2, 4}, 20}, - {{3, 2}, 5}, - {{3, 4}, 20} - }; - StarGraph graph(num_nodes, arcs.size()); - MaxFlow max_flow(&graph, 0, num_nodes - 1); - for (const auto &it : arcs) { - ArcIndex arc = graph.AddArc(it.first.first, it.first.second); - max_flow.SetArcCapacity(arc, it.second); - } - - LOG(INFO) << "Solving max flow with: " - << graph.num_nodes() << " nodes, and " - << graph.num_arcs() << " arcs."; - - // Find the maximum flow between node 0 and node 4. - max_flow.Solve(); - if (MaxFlow::OPTIMAL != max_flow.status()) { - LOG(FATAL) << "Solving the max flow is not optimal!"; - } - FlowQuantity total_flow = max_flow.GetOptimalFlow(); - LOG(INFO) << "Maximum flow: " << total_flow; - LOG(INFO) << ""; - LOG(INFO) << " Arc : Flow / Capacity"; - for (int i = 0; i < arcs.size(); ++i) { - LOG(INFO) - << graph.Tail(i) << " -> " << graph.Head(i) << ": " - << max_flow.Flow(i) << " / " << max_flow.Capacity(i); - } +void SolveMaxFlow() { + const int num_nodes = 5; + // Add each arc + // Can't use std::tuple + // Initialization list is not working on std:tuple cf. N4387 + // Arc are stored as {{begin_node, end_node}, capacity} + std::vector, FlowQuantity>> arcs = { + {{0, 1}, 20}, {{0, 2}, 30}, {{0, 3}, 10}, {{1, 2}, 40}, {{1, 4}, 30}, + {{2, 3}, 10}, {{2, 4}, 20}, {{3, 2}, 5}, {{3, 4}, 20}}; + StarGraph graph(num_nodes, arcs.size()); + MaxFlow max_flow(&graph, 0, num_nodes - 1); + for (const auto& it : arcs) { + ArcIndex arc = graph.AddArc(it.first.first, it.first.second); + max_flow.SetArcCapacity(arc, it.second); } + + LOG(INFO) << "Solving max flow with: " << graph.num_nodes() << " nodes, and " + << graph.num_arcs() << " arcs."; + + // Find the maximum flow between node 0 and node 4. + max_flow.Solve(); + if (MaxFlow::OPTIMAL != max_flow.status()) { + LOG(FATAL) << "Solving the max flow is not optimal!"; + } + FlowQuantity total_flow = max_flow.GetOptimalFlow(); + LOG(INFO) << "Maximum flow: " << total_flow; + LOG(INFO) << ""; + LOG(INFO) << " Arc : Flow / Capacity"; + for (int i = 0; i < arcs.size(); ++i) { + LOG(INFO) << graph.Tail(i) << " -> " << graph.Head(i) << ": " + << max_flow.Flow(i) << " / " << max_flow.Capacity(i); + } +} } // namespace operations_research int main(int argc, char** argv) { diff --git a/examples/cpp/min_cost_flow.cc b/examples/cpp/min_cost_flow.cc index 5a03c1c572..3ef937a812 100644 --- a/examples/cpp/min_cost_flow.cc +++ b/examples/cpp/min_cost_flow.cc @@ -11,76 +11,62 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ortools/base/logging.h" #include "ortools/graph/min_cost_flow.h" +#include "ortools/base/logging.h" namespace operations_research { - struct Arc { - std::pair nodes; - FlowQuantity capacity; - FlowQuantity unit_cost; - }; +struct Arc { + std::pair nodes; + FlowQuantity capacity; + FlowQuantity unit_cost; +}; - void SolveMinCostFlow() { - // Define supply of each node. - const std::vector> supplies = { - {0, 20}, - {1, 0}, - {2, 0}, - {3,-5}, - {4,-15} - }; +void SolveMinCostFlow() { + // Define supply of each node. + const std::vector> supplies = { + {0, 20}, {1, 0}, {2, 0}, {3, -5}, {4, -15}}; - // Define each arc - // Can't use std::tuple - // Initialization list is not working on std:tuple cf. N4387 - // Arc are stored as {{begin_node, end_node}, capacity} - const std::vector arcs = { - {{0, 1}, 15, 4}, - {{0, 2}, 8, 4}, - {{1, 2}, 20, 2}, - {{1, 3}, 4, 2}, - {{1, 4}, 10, 6}, - {{2, 3}, 15, 1}, - {{2, 4}, 4, 3}, - {{3, 4}, 20, 2}, - {{4, 2}, 5, 3} - }; + // Define each arc + // Can't use std::tuple + // Initialization list is not working on std:tuple cf. N4387 + // Arc are stored as {{begin_node, end_node}, capacity} + const std::vector arcs = { + {{0, 1}, 15, 4}, {{0, 2}, 8, 4}, {{1, 2}, 20, 2}, + {{1, 3}, 4, 2}, {{1, 4}, 10, 6}, {{2, 3}, 15, 1}, + {{2, 4}, 4, 3}, {{3, 4}, 20, 2}, {{4, 2}, 5, 3}}; - StarGraph graph(supplies.size(), arcs.size()); - MinCostFlow min_cost_flow(&graph); - for (const auto &it : arcs) { - ArcIndex arc = graph.AddArc(it.nodes.first, it.nodes.second); - min_cost_flow.SetArcCapacity(arc, it.capacity); - min_cost_flow.SetArcUnitCost(arc, it.unit_cost); - } - for (const auto &it : supplies) { - min_cost_flow.SetNodeSupply(it.first, it.second); - } - - LOG(INFO) << "Solving min cost flow with: " - << graph.num_nodes() << " nodes, and " - << graph.num_arcs() << " arcs."; - - // Find the maximum flow between node 0 and node 4. - min_cost_flow.Solve(); - if (MinCostFlow::OPTIMAL != min_cost_flow.status()) { - LOG(FATAL) << "Solving the max flow is not optimal!"; - } - FlowQuantity total_flow_cost = min_cost_flow.GetOptimalCost(); - LOG(INFO) << "Minimum cost flow: " << total_flow_cost; - LOG(INFO) << ""; - LOG(INFO) << "Arc : Flow / Capacity / Cost"; - for (int i = 0; i < arcs.size(); ++i) { - LOG(INFO) - << graph.Tail(i) << " -> " << graph.Head(i) << ": " - << min_cost_flow.Flow(i) << " / " << min_cost_flow.Capacity(i) - << " / " << min_cost_flow.UnitCost(i); - } + StarGraph graph(supplies.size(), arcs.size()); + MinCostFlow min_cost_flow(&graph); + for (const auto &it : arcs) { + ArcIndex arc = graph.AddArc(it.nodes.first, it.nodes.second); + min_cost_flow.SetArcCapacity(arc, it.capacity); + min_cost_flow.SetArcUnitCost(arc, it.unit_cost); } + for (const auto &it : supplies) { + min_cost_flow.SetNodeSupply(it.first, it.second); + } + + LOG(INFO) << "Solving min cost flow with: " << graph.num_nodes() + << " nodes, and " << graph.num_arcs() << " arcs."; + + // Find the maximum flow between node 0 and node 4. + min_cost_flow.Solve(); + if (MinCostFlow::OPTIMAL != min_cost_flow.status()) { + LOG(FATAL) << "Solving the max flow is not optimal!"; + } + FlowQuantity total_flow_cost = min_cost_flow.GetOptimalCost(); + LOG(INFO) << "Minimum cost flow: " << total_flow_cost; + LOG(INFO) << ""; + LOG(INFO) << "Arc : Flow / Capacity / Cost"; + for (int i = 0; i < arcs.size(); ++i) { + LOG(INFO) << graph.Tail(i) << " -> " << graph.Head(i) << ": " + << min_cost_flow.Flow(i) << " / " << min_cost_flow.Capacity(i) + << " / " << min_cost_flow.UnitCost(i); + } +} } // namespace operations_research -int main(int argc, char** argv) { +int main(int argc, char **argv) { google::InitGoogleLogging(argv[0]); FLAGS_logtostderr = 1; operations_research::SolveMinCostFlow(); diff --git a/examples/cpp/multidim_knapsack.cc b/examples/cpp/multidim_knapsack.cc index 8dc00f6baf..0f99a99f9d 100644 --- a/examples/cpp/multidim_knapsack.cc +++ b/examples/cpp/multidim_knapsack.cc @@ -299,12 +299,12 @@ void SolveKnapsack(MultiDimKnapsackData* const data) { SearchMonitor* const search_log = solver.MakeSearchLog(1000000, objective); monitors.push_back(search_log); } - DecisionBuilder* const db = - solver.MakePhase(assign, - [data](int64 var, int64 value) { - return EvaluateItem(*data, var, value); - }, - Solver::CHOOSE_STATIC_GLOBAL_BEST); + DecisionBuilder* const db = solver.MakePhase( + assign, + [data](int64 var, int64 value) { + return EvaluateItem(*data, var, value); + }, + Solver::CHOOSE_STATIC_GLOBAL_BEST); if (FLAGS_time_limit_in_ms != 0) { LOG(INFO) << "adding time limit of " << FLAGS_time_limit_in_ms << " ms"; SearchLimit* const limit = solver.MakeLimit( diff --git a/examples/cpp/network_routing.cc b/examples/cpp/network_routing.cc index 781e885acd..ef4cc22902 100644 --- a/examples/cpp/network_routing.cc +++ b/examples/cpp/network_routing.cc @@ -471,9 +471,10 @@ class NetworkRoutingSolver { for (int demand_index = 0; demand_index < num_demands; ++demand_index) { paths.clear(); const Demand& demand = demands_array_[demand_index]; - CHECK(DijkstraShortestPath(num_nodes_, demand.source, demand.destination, - [this](int x, int y) { return HasArc(x, y); }, - kDisconnectedDistance, &paths)); + CHECK(DijkstraShortestPath( + num_nodes_, demand.source, demand.destination, + [this](int x, int y) { return HasArc(x, y); }, kDisconnectedDistance, + &paths)); all_min_path_lengths_.push_back(paths.size() - 1); } diff --git a/examples/cpp/nqueens2.cc b/examples/cpp/nqueens2.cc index 4a67ae6605..f112f7f144 100644 --- a/examples/cpp/nqueens2.cc +++ b/examples/cpp/nqueens2.cc @@ -43,8 +43,8 @@ void NQueens(int size) { s.AddConstraint(s.MakeNonEquality(queens[i], queens[j])); s.AddConstraint( s.MakeNonEquality(s.MakeSum(queens[i], i), s.MakeSum(queens[j], j))); - s.AddConstraint(s.MakeNonEquality( - s.MakeSum(queens[i], -i), s.MakeSum(queens[j], -j))); + s.AddConstraint(s.MakeNonEquality(s.MakeSum(queens[i], -i), + s.MakeSum(queens[j], -j))); } } std::vector monitors; diff --git a/examples/cpp/nurses_cp.cc b/examples/cpp/nurses_cp.cc index 328386dd41..bfbaa32228 100644 --- a/examples/cpp/nurses_cp.cc +++ b/examples/cpp/nurses_cp.cc @@ -11,209 +11,194 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include // std::iota +#include // std::iota #include "ortools/base/logging.h" #include "ortools/constraint_solver/constraint_solver.h" namespace operations_research { - void SolveNursesExample() { - // Instantiate the solver. - Solver solver("NursesExample"); - std::array nurses; - std::iota(std::begin(nurses), std::end(nurses), 0); - { - std::ostringstream oss; - for (auto i : nurses) - oss << ' ' << i; - LOG(INFO) << "Nurses:" << oss.str(); - } - - // Nurse assigned to shift 0 means not working that day. - std::array shifts; - std::iota(std::begin(shifts), std::end(shifts), 0); - { - std::ostringstream oss; - for (auto i : shifts) - oss << ' ' << i; - LOG(INFO) << "Shifts:" << oss.str(); - } - - std::array days; - std::iota(std::begin(days), std::end(days), 0); - { - std::ostringstream oss; - for (auto i : days) - oss << ' ' << i; - LOG(INFO) << "Days:" << oss.str(); - } - - // Create shift variables. - std::vector> shifts_matrix(nurses.size()); - std::vector shifts_flat; - for (const auto nurse: nurses) { - for (const auto day: days) { - std::ostringstream oss; - oss << "shifts(nurse: " << nurse << ", day: " << day << ")"; - IntVar *var = solver.MakeIntVar(shifts.front(), shifts.back(), oss.str()); - shifts_matrix[nurse].push_back(var); - shifts_flat.push_back(var); - } - } - - // Create nurse variables. - std::vector> nurses_matrix(shifts.size()); - for (const auto shift: shifts) { - for (const auto day: days) { - std::ostringstream oss; - oss << "nurses(shift: " << shift << ", day: " << day << ")"; - IntVar *var = solver.MakeIntVar(nurses.front(), nurses.back(), oss.str()); - nurses_matrix[shift].push_back(var); - } - } - - // Set relationships between shifts and nurses. - for (const auto day :days) { - std::vector nurses_for_day(shifts.size()); - for (const auto shift: shifts) { - nurses_for_day[shift] = nurses_matrix[shift][day]; - } - for (const auto nurse: nurses) { - IntVar* s = shifts_matrix[nurse][day]; - solver.AddConstraint( - solver.MakeEquality( - solver.MakeElement(nurses_for_day, s), - nurse)); - } - } - - // Make assignments different on each day i.e. - for (const auto day: days) { - // no shift can have two nurses - std::vector shifts_for_day(nurses.size()); - for (const auto nurse: nurses) { - shifts_for_day[nurse] = shifts_matrix[nurse][day]; - } - solver.AddConstraint(solver.MakeAllDifferent(shifts_for_day)); - - // no nurses can have more than one shifts a day - std::vector nurses_for_day(shifts.size()); - for (const auto shift: shifts) { - nurses_for_day[shift] = nurses_matrix[shift][day]; - } - solver.AddConstraint(solver.MakeAllDifferent(nurses_for_day)); - } - - //Each nurse works 5 or 6 days in a week. - for (const auto nurse: nurses) { - std::vector nurse_is_working; - for (const auto day: days) { - nurse_is_working.push_back( - solver.MakeIsGreaterOrEqualCstVar( - shifts_matrix[nurse][day], 1)); - } - solver.AddConstraint(solver.MakeSumGreaterOrEqual(nurse_is_working, 5)); - solver.AddConstraint(solver.MakeSumLessOrEqual(nurse_is_working, 6)); - } - - // Create works_shift variables. - // works_shift_matrix[n][s] is True if - // nurse n works shift s at least once during the week. - std::vector> works_shift_matrix(nurses.size()); - for (const auto nurse: nurses) { - for (const auto shift: shifts) { - std::ostringstream oss; - oss << "work_shift(nurse: " << nurse << ", shift: " << shift << ")"; - works_shift_matrix[nurse].push_back(solver.MakeBoolVar(oss.str())); - } - } - - for (const auto nurse: nurses) { - for (const auto shift: shifts) { - std::vector shift_s_for_nurse; - for (const auto day: days) { - shift_s_for_nurse.push_back( - solver.MakeIsEqualCstVar( - shifts_matrix[nurse][day], - shift)); - } - solver.AddConstraint( - solver.MakeEquality( - works_shift_matrix[nurse][shift], - solver.MakeMax(shift_s_for_nurse)->Var())); - } - } - - // For each shift(other than 0), at most 2 nurses are assigned to that shift - // during the week. - for (std::size_t shift=1; shift < shifts.size(); ++shift) { - std::vector nurses_for_shift; - for (const auto nurse: nurses) { - nurses_for_shift.push_back(works_shift_matrix[nurse][shift]); - } - solver.AddConstraint(solver.MakeSumLessOrEqual(nurses_for_shift, 2)); - } - - // If a nurse works shifts 2 or 3 on, - // he must also work that shift the previous day or the following day. - for (const auto shift: {2, 3}) { - for (const auto day: days) { - IntVar* v0 = solver.MakeIsEqualVar( - nurses_matrix[shift][day], - nurses_matrix[shift][(day + 1) % 7]); - IntVar* v1 = solver.MakeIsEqualVar( - nurses_matrix[shift][(day + 1) % 7], - nurses_matrix[shift][(day + 2) % 7]); - solver.AddConstraint( - solver.MakeEquality( - solver.MakeMax(v0, v1), - 1)); - } - } - - // ----- Search monitors and decision builder ----- - - // Create the decision builder. - DecisionBuilder* const main_phase = solver.MakePhase( - shifts_flat, - Solver::CHOOSE_FIRST_UNBOUND, - Solver::ASSIGN_MIN_VALUE); - - // Search log. - SearchMonitor* const search_log = nullptr; - - SearchLimit* limit = nullptr; - - // Create the solution collector. - SolutionCollector* const collector = solver.MakeAllSolutionCollector(); - collector->Add(shifts_flat); - - // Solve - solver.Solve(main_phase, search_log, nullptr, limit, collector); - LOG(INFO) << "Number of solutions: " << collector->solution_count(); - LOG(INFO) << ""; - - // Display a few solutions picked at random. - std::array a_few_solutions = {859, 2034, 5091, 7003}; - for (const auto solution: a_few_solutions) { - LOG(INFO) << "Solution " << solution << ":"; - for (const auto day: days) { - LOG(INFO) << "Day " << day << ":"; - for (const auto nurse: nurses) { - LOG(INFO) - << "Nurse " << nurse << " assigned to " - << "Task " << collector->Value(solution, shifts_flat[nurse * days.size() + day]); - } - } - } - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Time: " << solver.wall_time() << "ms"; +void SolveNursesExample() { + // Instantiate the solver. + Solver solver("NursesExample"); + std::array nurses; + std::iota(std::begin(nurses), std::end(nurses), 0); + { + std::ostringstream oss; + for (auto i : nurses) oss << ' ' << i; + LOG(INFO) << "Nurses:" << oss.str(); } + + // Nurse assigned to shift 0 means not working that day. + std::array shifts; + std::iota(std::begin(shifts), std::end(shifts), 0); + { + std::ostringstream oss; + for (auto i : shifts) oss << ' ' << i; + LOG(INFO) << "Shifts:" << oss.str(); + } + + std::array days; + std::iota(std::begin(days), std::end(days), 0); + { + std::ostringstream oss; + for (auto i : days) oss << ' ' << i; + LOG(INFO) << "Days:" << oss.str(); + } + + // Create shift variables. + std::vector> shifts_matrix(nurses.size()); + std::vector shifts_flat; + for (const auto nurse : nurses) { + for (const auto day : days) { + std::ostringstream oss; + oss << "shifts(nurse: " << nurse << ", day: " << day << ")"; + IntVar *var = solver.MakeIntVar(shifts.front(), shifts.back(), oss.str()); + shifts_matrix[nurse].push_back(var); + shifts_flat.push_back(var); + } + } + + // Create nurse variables. + std::vector> nurses_matrix(shifts.size()); + for (const auto shift : shifts) { + for (const auto day : days) { + std::ostringstream oss; + oss << "nurses(shift: " << shift << ", day: " << day << ")"; + IntVar *var = solver.MakeIntVar(nurses.front(), nurses.back(), oss.str()); + nurses_matrix[shift].push_back(var); + } + } + + // Set relationships between shifts and nurses. + for (const auto day : days) { + std::vector nurses_for_day(shifts.size()); + for (const auto shift : shifts) { + nurses_for_day[shift] = nurses_matrix[shift][day]; + } + for (const auto nurse : nurses) { + IntVar *s = shifts_matrix[nurse][day]; + solver.AddConstraint( + solver.MakeEquality(solver.MakeElement(nurses_for_day, s), nurse)); + } + } + + // Make assignments different on each day i.e. + for (const auto day : days) { + // no shift can have two nurses + std::vector shifts_for_day(nurses.size()); + for (const auto nurse : nurses) { + shifts_for_day[nurse] = shifts_matrix[nurse][day]; + } + solver.AddConstraint(solver.MakeAllDifferent(shifts_for_day)); + + // no nurses can have more than one shifts a day + std::vector nurses_for_day(shifts.size()); + for (const auto shift : shifts) { + nurses_for_day[shift] = nurses_matrix[shift][day]; + } + solver.AddConstraint(solver.MakeAllDifferent(nurses_for_day)); + } + + // Each nurse works 5 or 6 days in a week. + for (const auto nurse : nurses) { + std::vector nurse_is_working; + for (const auto day : days) { + nurse_is_working.push_back( + solver.MakeIsGreaterOrEqualCstVar(shifts_matrix[nurse][day], 1)); + } + solver.AddConstraint(solver.MakeSumGreaterOrEqual(nurse_is_working, 5)); + solver.AddConstraint(solver.MakeSumLessOrEqual(nurse_is_working, 6)); + } + + // Create works_shift variables. + // works_shift_matrix[n][s] is True if + // nurse n works shift s at least once during the week. + std::vector> works_shift_matrix(nurses.size()); + for (const auto nurse : nurses) { + for (const auto shift : shifts) { + std::ostringstream oss; + oss << "work_shift(nurse: " << nurse << ", shift: " << shift << ")"; + works_shift_matrix[nurse].push_back(solver.MakeBoolVar(oss.str())); + } + } + + for (const auto nurse : nurses) { + for (const auto shift : shifts) { + std::vector shift_s_for_nurse; + for (const auto day : days) { + shift_s_for_nurse.push_back( + solver.MakeIsEqualCstVar(shifts_matrix[nurse][day], shift)); + } + solver.AddConstraint( + solver.MakeEquality(works_shift_matrix[nurse][shift], + solver.MakeMax(shift_s_for_nurse)->Var())); + } + } + + // For each shift(other than 0), at most 2 nurses are assigned to that shift + // during the week. + for (std::size_t shift = 1; shift < shifts.size(); ++shift) { + std::vector nurses_for_shift; + for (const auto nurse : nurses) { + nurses_for_shift.push_back(works_shift_matrix[nurse][shift]); + } + solver.AddConstraint(solver.MakeSumLessOrEqual(nurses_for_shift, 2)); + } + + // If a nurse works shifts 2 or 3 on, + // he must also work that shift the previous day or the following day. + for (const auto shift : {2, 3}) { + for (const auto day : days) { + IntVar *v0 = solver.MakeIsEqualVar(nurses_matrix[shift][day], + nurses_matrix[shift][(day + 1) % 7]); + IntVar *v1 = solver.MakeIsEqualVar(nurses_matrix[shift][(day + 1) % 7], + nurses_matrix[shift][(day + 2) % 7]); + solver.AddConstraint(solver.MakeEquality(solver.MakeMax(v0, v1), 1)); + } + } + + // ----- Search monitors and decision builder ----- + + // Create the decision builder. + DecisionBuilder *const main_phase = solver.MakePhase( + shifts_flat, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); + + // Search log. + SearchMonitor *const search_log = nullptr; + + SearchLimit *limit = nullptr; + + // Create the solution collector. + SolutionCollector *const collector = solver.MakeAllSolutionCollector(); + collector->Add(shifts_flat); + + // Solve + solver.Solve(main_phase, search_log, nullptr, limit, collector); + LOG(INFO) << "Number of solutions: " << collector->solution_count(); + LOG(INFO) << ""; + + // Display a few solutions picked at random. + std::array a_few_solutions = {859, 2034, 5091, 7003}; + for (const auto solution : a_few_solutions) { + LOG(INFO) << "Solution " << solution << ":"; + for (const auto day : days) { + LOG(INFO) << "Day " << day << ":"; + for (const auto nurse : nurses) { + LOG(INFO) << "Nurse " << nurse << " assigned to " + << "Task " + << collector->Value(solution, + shifts_flat[nurse * days.size() + day]); + } + } + } + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Time: " << solver.wall_time() << "ms"; +} } // namespace operations_research int main(int argc, char **argv) { - google::InitGoogleLogging(argv[0]); - FLAGS_logtostderr = 1; - operations_research::SolveNursesExample(); - return EXIT_SUCCESS; + google::InitGoogleLogging(argv[0]); + FLAGS_logtostderr = 1; + operations_research::SolveNursesExample(); + return EXIT_SUCCESS; } diff --git a/examples/cpp/rabbits_pheasants_cp.cc b/examples/cpp/rabbits_pheasants_cp.cc index 5efa08a6f9..460cf97ca9 100644 --- a/examples/cpp/rabbits_pheasants_cp.cc +++ b/examples/cpp/rabbits_pheasants_cp.cc @@ -18,48 +18,48 @@ #include "ortools/constraint_solver/constraint_solver.h" namespace operations_research { - void RunConstraintProgrammingExample() { - // Instantiate the solver. - Solver solver("RabbitsPheasantsExample"); +void RunConstraintProgrammingExample() { + // Instantiate the solver. + Solver solver("RabbitsPheasantsExample"); - // Define decision variables. - IntVar* const rabbits = solver.MakeIntVar(0, 20, "rabbits"); - IntVar* const pheasants = solver.MakeIntVar(0, 20, "pheasants"); + // Define decision variables. + IntVar* const rabbits = solver.MakeIntVar(0, 20, "rabbits"); + IntVar* const pheasants = solver.MakeIntVar(0, 20, "pheasants"); - // Define constraints. - IntExpr* const heads = solver.MakeSum(rabbits, pheasants); - Constraint* const c0 = solver.MakeEquality(heads, 20); - solver.AddConstraint(c0); + // Define constraints. + IntExpr* const heads = solver.MakeSum(rabbits, pheasants); + Constraint* const c0 = solver.MakeEquality(heads, 20); + solver.AddConstraint(c0); - IntExpr* const legs = solver.MakeSum(solver.MakeProd(rabbits, 4), solver.MakeProd(pheasants, 2)); - Constraint* const c1 = solver.MakeEquality(legs, 56); - solver.AddConstraint(c1); + IntExpr* const legs = solver.MakeSum(solver.MakeProd(rabbits, 4), + solver.MakeProd(pheasants, 2)); + Constraint* const c1 = solver.MakeEquality(legs, 56); + solver.AddConstraint(c1); - DecisionBuilder* const db = solver.MakePhase( - rabbits, pheasants, - Solver::CHOOSE_FIRST_UNBOUND, - Solver::ASSIGN_MIN_VALUE); + DecisionBuilder* const db = + solver.MakePhase(rabbits, pheasants, Solver::CHOOSE_FIRST_UNBOUND, + Solver::ASSIGN_MIN_VALUE); - bool has_result = solver.Solve(db); - // Check that the problem has a solution. - if (has_result != true) { - LOG(FATAL) << "The problem does not have a solution!"; - } - int count = 0; - while (solver.NextSolution()) { - count++; - LOG(INFO) << "Solution " << count << ":"; - LOG(INFO) << "rabbits = " << rabbits->Value(); - LOG(INFO) << "pheasants = " << rabbits->Value(); - } - LOG(INFO) << "Number of solutions: " << count; - LOG(INFO) << ""; - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds"; + bool has_result = solver.Solve(db); + // Check that the problem has a solution. + if (has_result != true) { + LOG(FATAL) << "The problem does not have a solution!"; } + int count = 0; + while (solver.NextSolution()) { + count++; + LOG(INFO) << "Solution " << count << ":"; + LOG(INFO) << "rabbits = " << rabbits->Value(); + LOG(INFO) << "pheasants = " << rabbits->Value(); + } + LOG(INFO) << "Number of solutions: " << count; + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds"; +} } // namespace operations_research -int main(int argc, char **argv) { +int main(int argc, char** argv) { google::InitGoogleLogging(argv[0]); FLAGS_logtostderr = 1; operations_research::RunConstraintProgrammingExample(); diff --git a/examples/cpp/tsp.cc b/examples/cpp/tsp.cc index de825db133..fec14605f6 100644 --- a/examples/cpp/tsp.cc +++ b/examples/cpp/tsp.cc @@ -11,127 +11,125 @@ // See the License for the specific language governing permissions and // limitations under the License. - -#include #include +#include #include "ortools/base/logging.h" #include "ortools/constraint_solver/routing.h" namespace operations_research { - class DataProblem { - private: - std::vector> locations_; +class DataProblem { + private: + std::vector> locations_; - public: - DataProblem() { - locations_ = { - {4, 4}, - {2, 0}, {8, 0}, - {0, 1}, {1, 1}, - {5, 2}, {7, 2}, - {3, 3}, {6, 3}, - {5, 5}, {8, 5}, - {1, 6}, {2, 6}, - {3, 7}, {6, 7}, - {0, 8}, {7, 8} - }; + public: + DataProblem() { + locations_ = {{4, 4}, {2, 0}, {8, 0}, {0, 1}, {1, 1}, {5, 2}, + {7, 2}, {3, 3}, {6, 3}, {5, 5}, {8, 5}, {1, 6}, + {2, 6}, {3, 7}, {6, 7}, {0, 8}, {7, 8}}; - // Compute locations in meters using the block dimension defined as follow - // Manhattan average block: 750ft x 264ft -> 228m x 80m - // here we use: 114m x 80m city block - // src: https://nyti.ms/2GDoRIe "NY Times: Know Your distance" - std::array cityBlock = {228/2, 80}; - for (auto &i: locations_) { - i[0] = i[0] * cityBlock[0]; - i[1] = i[1] * cityBlock[1]; - } - } - - std::size_t GetVehicleNumber() const { return 1;} - const std::vector>& GetLocations() const { return locations_;} - RoutingModel::NodeIndex GetDepot() const { return RoutingModel::kFirstNode;} - }; - - /*! @brief Manhattan distance implemented as a callback. - * @details It uses an array of positions and - * computes the Manhattan distance between the two positions of two different indices.*/ - class ManhattanDistance: public RoutingModel::NodeEvaluator2 { - private: - std::vector> distances_; - public: - ManhattanDistance(const DataProblem& data) { - // Precompute distance between location to have distance callback in O(1) - distances_ = std::vector>( - data.GetLocations().size(), - std::vector( - data.GetLocations().size(), - 0LL)); - for (std::size_t fromNode = 0; fromNode < data.GetLocations().size(); fromNode++) { - for (std::size_t toNode = 0; toNode < data.GetLocations().size(); toNode++) { - if (fromNode != toNode) - distances_[fromNode][toNode] = - std::abs(data.GetLocations()[toNode][0] - data.GetLocations()[fromNode][0]) + - std::abs(data.GetLocations()[toNode][1] - data.GetLocations()[fromNode][1]); - } - } + // Compute locations in meters using the block dimension defined as follow + // Manhattan average block: 750ft x 264ft -> 228m x 80m + // here we use: 114m x 80m city block + // src: https://nyti.ms/2GDoRIe "NY Times: Know Your distance" + std::array cityBlock = {228 / 2, 80}; + for (auto& i : locations_) { + i[0] = i[0] * cityBlock[0]; + i[1] = i[1] * cityBlock[1]; } - - bool IsRepeatable() const override {return true;} - - //! @brief Returns the manhattan distance between the two nodes. - int64 Run(RoutingModel::NodeIndex FromNode, RoutingModel::NodeIndex ToNode) override { - return distances_[FromNode.value()][ToNode.value()]; - } - }; - - //! @brief Print the solution - //! @param[in] data Data of the problem. - //! @param[in] routing Routing solver used. - //! @param[in] solution Solution found by the solver. - void PrintSolution( - const DataProblem& data, - const RoutingModel& routing, - const Assignment& solution) { - LOG(INFO) << "Objective: " << solution.ObjectiveValue(); - // Inspect solution. - int64 index = routing.Start(0); - LOG(INFO) << "Route for Vehicle 0:"; - int64 distance = 0LL; - std::stringstream route; - while (routing.IsEnd(index) == false) { - route << routing.IndexToNode(index).value() << " -> "; - int64 previous_index = index; - index = solution.Value(routing.NextVar(index)); - distance += const_cast(routing).GetArcCostForVehicle(previous_index, index, 0LL); - } - LOG(INFO) << route.str() << routing.IndexToNode(index).value(); - LOG(INFO) << "Distance of the route: " << distance << "m"; - LOG(INFO) << ""; - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms"; } - void Solve() { - // Instantiate the data problem. - DataProblem data; + std::size_t GetVehicleNumber() const { return 1; } + const std::vector>& GetLocations() const { + return locations_; + } + RoutingModel::NodeIndex GetDepot() const { return RoutingModel::kFirstNode; } +}; - // Create Routing Model - RoutingModel routing( +/*! @brief Manhattan distance implemented as a callback. + * @details It uses an array of positions and + * computes the Manhattan distance between the two positions of two different + * indices.*/ +class ManhattanDistance : public RoutingModel::NodeEvaluator2 { + private: + std::vector> distances_; + + public: + ManhattanDistance(const DataProblem& data) { + // Precompute distance between location to have distance callback in O(1) + distances_ = std::vector>( data.GetLocations().size(), - data.GetVehicleNumber(), - data.GetDepot()); - - // Define weight of each edge - ManhattanDistance distance(data); - routing.SetArcCostEvaluatorOfAllVehicles(NewPermanentCallback(&distance, &ManhattanDistance::Run)); - - // Setting first solution heuristic (cheapest addition). - RoutingSearchParameters searchParameters = RoutingModel::DefaultSearchParameters(); - searchParameters.set_first_solution_strategy(FirstSolutionStrategy::PATH_CHEAPEST_ARC); - - const Assignment* solution = routing.SolveWithParameters(searchParameters); - PrintSolution(data, routing, *solution); + std::vector(data.GetLocations().size(), 0LL)); + for (std::size_t fromNode = 0; fromNode < data.GetLocations().size(); + fromNode++) { + for (std::size_t toNode = 0; toNode < data.GetLocations().size(); + toNode++) { + if (fromNode != toNode) + distances_[fromNode][toNode] = + std::abs(data.GetLocations()[toNode][0] - + data.GetLocations()[fromNode][0]) + + std::abs(data.GetLocations()[toNode][1] - + data.GetLocations()[fromNode][1]); + } + } } + + bool IsRepeatable() const override { return true; } + + //! @brief Returns the manhattan distance between the two nodes. + int64 Run(RoutingModel::NodeIndex FromNode, + RoutingModel::NodeIndex ToNode) override { + return distances_[FromNode.value()][ToNode.value()]; + } +}; + +//! @brief Print the solution +//! @param[in] data Data of the problem. +//! @param[in] routing Routing solver used. +//! @param[in] solution Solution found by the solver. +void PrintSolution(const DataProblem& data, const RoutingModel& routing, + const Assignment& solution) { + LOG(INFO) << "Objective: " << solution.ObjectiveValue(); + // Inspect solution. + int64 index = routing.Start(0); + LOG(INFO) << "Route for Vehicle 0:"; + int64 distance = 0LL; + std::stringstream route; + while (routing.IsEnd(index) == false) { + route << routing.IndexToNode(index).value() << " -> "; + int64 previous_index = index; + index = solution.Value(routing.NextVar(index)); + distance += const_cast(routing).GetArcCostForVehicle( + previous_index, index, 0LL); + } + LOG(INFO) << route.str() << routing.IndexToNode(index).value(); + LOG(INFO) << "Distance of the route: " << distance << "m"; + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms"; +} + +void Solve() { + // Instantiate the data problem. + DataProblem data; + + // Create Routing Model + RoutingModel routing(data.GetLocations().size(), data.GetVehicleNumber(), + data.GetDepot()); + + // Define weight of each edge + ManhattanDistance distance(data); + routing.SetArcCostEvaluatorOfAllVehicles( + NewPermanentCallback(&distance, &ManhattanDistance::Run)); + + // Setting first solution heuristic (cheapest addition). + RoutingSearchParameters searchParameters = + RoutingModel::DefaultSearchParameters(); + searchParameters.set_first_solution_strategy( + FirstSolutionStrategy::PATH_CHEAPEST_ARC); + + const Assignment* solution = routing.SolveWithParameters(searchParameters); + PrintSolution(data, routing, *solution); +} } // namespace operations_research int main(int argc, char** argv) { diff --git a/examples/cpp/variable_intervals_sat.cc b/examples/cpp/variable_intervals_sat.cc index 82ccf6d256..be9dc8aa58 100644 --- a/examples/cpp/variable_intervals_sat.cc +++ b/examples/cpp/variable_intervals_sat.cc @@ -17,14 +17,12 @@ void Solve() { const IntVar start_p1 = cp_model.NewIntVar(Domain(500, 800)); const IntVar duration_p1 = cp_model.NewIntVar(Domain(1, 360)); const IntVar end_p1 = cp_model.NewIntVar(Domain(500, 1000)); - const IntervalVar p1 = - cp_model.NewIntervalVar(start_p1, duration_p1, end_p1); + const IntervalVar p1 = cp_model.NewIntervalVar(start_p1, duration_p1, end_p1); const IntVar start_p2 = cp_model.NewIntVar(Domain(500, 800)); const IntVar duration_p2 = cp_model.NewIntVar(Domain(1, 360)); const IntVar end_p2 = cp_model.NewIntVar(Domain(500, 1000)); - const IntervalVar p2 = - cp_model.NewIntervalVar(start_p2, duration_p2, end_p2); + const IntervalVar p2 = cp_model.NewIntervalVar(start_p2, duration_p2, end_p2); cp_model.AddEquality(LinearExpr::Sum({duration_p1, duration_p2}), 360); cp_model.AddLessOrEqual(end_p1, start_p2); diff --git a/examples/cpp/vrp.cc b/examples/cpp/vrp.cc index 1177f3da2a..452aa5ca15 100644 --- a/examples/cpp/vrp.cc +++ b/examples/cpp/vrp.cc @@ -11,149 +11,144 @@ // See the License for the specific language governing permissions and // limitations under the License. - -#include #include +#include #include "ortools/base/logging.h" #include "ortools/constraint_solver/routing.h" namespace operations_research { - class DataProblem { - private: - std::vector> locations_; +class DataProblem { + private: + std::vector> locations_; - public: - DataProblem() { - locations_ = { - {4, 4}, - {2, 0}, {8, 0}, - {0, 1}, {1, 1}, - {5, 2}, {7, 2}, - {3, 3}, {6, 3}, - {5, 5}, {8, 5}, - {1, 6}, {2, 6}, - {3, 7}, {6, 7}, - {0, 8}, {7, 8} - }; + public: + DataProblem() { + locations_ = {{4, 4}, {2, 0}, {8, 0}, {0, 1}, {1, 1}, {5, 2}, + {7, 2}, {3, 3}, {6, 3}, {5, 5}, {8, 5}, {1, 6}, + {2, 6}, {3, 7}, {6, 7}, {0, 8}, {7, 8}}; - // Compute locations in meters using the block dimension defined as follow - // Manhattan average block: 750ft x 264ft -> 228m x 80m - // here we use: 114m x 80m city block - // src: https://nyti.ms/2GDoRIe "NY Times: Know Your distance" - std::array cityBlock = {228/2, 80}; - for (auto &i: locations_) { - i[0] = i[0] * cityBlock[0]; - i[1] = i[1] * cityBlock[1]; - } - } - - std::size_t GetVehicleNumber() const { return 4;} - const std::vector>& GetLocations() const { return locations_;} - RoutingModel::NodeIndex GetDepot() const { return RoutingModel::kFirstNode;} - }; - - /*! @brief Manhattan distance implemented as a callback. - * @details It uses an array of positions and - * computes the Manhattan distance between the two positions of two different indices.*/ - class ManhattanDistance: public RoutingModel::NodeEvaluator2 { - private: - std::vector> distances_; - public: - ManhattanDistance(const DataProblem& data) { - // Precompute distance between location to have distance callback in O(1) - distances_ = std::vector>( - data.GetLocations().size(), - std::vector( - data.GetLocations().size(), - 0LL)); - for (std::size_t fromNode = 0; fromNode < data.GetLocations().size(); fromNode++) { - for (std::size_t toNode = 0; toNode < data.GetLocations().size(); toNode++) { - if (fromNode != toNode) - distances_[fromNode][toNode] = - std::abs(data.GetLocations()[toNode][0] - data.GetLocations()[fromNode][0]) + - std::abs(data.GetLocations()[toNode][1] - data.GetLocations()[fromNode][1]); - } - } + // Compute locations in meters using the block dimension defined as follow + // Manhattan average block: 750ft x 264ft -> 228m x 80m + // here we use: 114m x 80m city block + // src: https://nyti.ms/2GDoRIe "NY Times: Know Your distance" + std::array cityBlock = {228 / 2, 80}; + for (auto& i : locations_) { + i[0] = i[0] * cityBlock[0]; + i[1] = i[1] * cityBlock[1]; } - - bool IsRepeatable() const override {return true;} - - //! @brief Returns the manhattan distance between the two nodes. - int64 Run(RoutingModel::NodeIndex FromNode, RoutingModel::NodeIndex ToNode) override { - return distances_[FromNode.value()][ToNode.value()]; - } - }; - - //! @brief Add distance Dimension. - //! @param[in] data Data of the problem. - //! @param[in, out] routing Routing solver used. - static void AddDistanceDimension(const DataProblem& data, RoutingModel* routing) { - std::string distance("Distance"); - routing->AddDimension( - new ManhattanDistance(data), - 0, // null slack - 3000, // maximum distance per vehicle - true, // start cumul to zero - distance); - RoutingDimension* distanceDimension = routing->GetMutableDimension(distance); - // Try to minimize the max distance among vehicles. - // /!\ It doesn't mean the standard deviation is minimized - distanceDimension->SetGlobalSpanCostCoefficient(100); } - //! @brief Print the solution - //! @param[in] data Data of the problem. - //! @param[in] routing Routing solver used. - //! @param[in] solution Solution found by the solver. - void PrintSolution( - const DataProblem& data, - const RoutingModel& routing, - const Assignment& solution) { - LOG(INFO) << "Objective: " << solution.ObjectiveValue(); - // Inspect solution. - for (int i=0; i < data.GetVehicleNumber(); ++i) { - int64 index = routing.Start(i); - LOG(INFO) << "Route for Vehicle " << i << ":"; - int64 distance = 0LL; - std::stringstream route; - while (routing.IsEnd(index) == false) { - route << routing.IndexToNode(index).value() << " -> "; - int64 previous_index = index; - index = solution.Value(routing.NextVar(index)); - distance += const_cast(routing).GetArcCostForVehicle(previous_index, index, i); - } - LOG(INFO) << route.str() << routing.IndexToNode(index).value(); - LOG(INFO) << "Distance of the route: " << distance << "m"; - } - LOG(INFO) << ""; - LOG(INFO) << "Advanced usage:"; - LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms"; + std::size_t GetVehicleNumber() const { return 4; } + const std::vector>& GetLocations() const { + return locations_; } + RoutingModel::NodeIndex GetDepot() const { return RoutingModel::kFirstNode; } +}; - void Solve() { - // Instantiate the data problem. - DataProblem data; +/*! @brief Manhattan distance implemented as a callback. + * @details It uses an array of positions and + * computes the Manhattan distance between the two positions of two different + * indices.*/ +class ManhattanDistance : public RoutingModel::NodeEvaluator2 { + private: + std::vector> distances_; - // Create Routing Model - RoutingModel routing( + public: + ManhattanDistance(const DataProblem& data) { + // Precompute distance between location to have distance callback in O(1) + distances_ = std::vector>( data.GetLocations().size(), - data.GetVehicleNumber(), - data.GetDepot()); - - // Define weight of each edge - ManhattanDistance distance(data); - routing.SetArcCostEvaluatorOfAllVehicles( - NewPermanentCallback(&distance, &ManhattanDistance::Run)); - AddDistanceDimension(data, &routing); - - // Setting first solution heuristic (cheapest addition). - auto searchParameters = RoutingModel::DefaultSearchParameters(); - searchParameters.set_first_solution_strategy( - FirstSolutionStrategy::PATH_CHEAPEST_ARC); - - const Assignment* solution = routing.SolveWithParameters(searchParameters); - PrintSolution(data, routing, *solution); + std::vector(data.GetLocations().size(), 0LL)); + for (std::size_t fromNode = 0; fromNode < data.GetLocations().size(); + fromNode++) { + for (std::size_t toNode = 0; toNode < data.GetLocations().size(); + toNode++) { + if (fromNode != toNode) + distances_[fromNode][toNode] = + std::abs(data.GetLocations()[toNode][0] - + data.GetLocations()[fromNode][0]) + + std::abs(data.GetLocations()[toNode][1] - + data.GetLocations()[fromNode][1]); + } + } } + + bool IsRepeatable() const override { return true; } + + //! @brief Returns the manhattan distance between the two nodes. + int64 Run(RoutingModel::NodeIndex FromNode, + RoutingModel::NodeIndex ToNode) override { + return distances_[FromNode.value()][ToNode.value()]; + } +}; + +//! @brief Add distance Dimension. +//! @param[in] data Data of the problem. +//! @param[in, out] routing Routing solver used. +static void AddDistanceDimension(const DataProblem& data, + RoutingModel* routing) { + std::string distance("Distance"); + routing->AddDimension(new ManhattanDistance(data), + 0, // null slack + 3000, // maximum distance per vehicle + true, // start cumul to zero + distance); + RoutingDimension* distanceDimension = routing->GetMutableDimension(distance); + // Try to minimize the max distance among vehicles. + // /!\ It doesn't mean the standard deviation is minimized + distanceDimension->SetGlobalSpanCostCoefficient(100); +} + +//! @brief Print the solution +//! @param[in] data Data of the problem. +//! @param[in] routing Routing solver used. +//! @param[in] solution Solution found by the solver. +void PrintSolution(const DataProblem& data, const RoutingModel& routing, + const Assignment& solution) { + LOG(INFO) << "Objective: " << solution.ObjectiveValue(); + // Inspect solution. + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + int64 index = routing.Start(i); + LOG(INFO) << "Route for Vehicle " << i << ":"; + int64 distance = 0LL; + std::stringstream route; + while (routing.IsEnd(index) == false) { + route << routing.IndexToNode(index).value() << " -> "; + int64 previous_index = index; + index = solution.Value(routing.NextVar(index)); + distance += const_cast(routing).GetArcCostForVehicle( + previous_index, index, i); + } + LOG(INFO) << route.str() << routing.IndexToNode(index).value(); + LOG(INFO) << "Distance of the route: " << distance << "m"; + } + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms"; +} + +void Solve() { + // Instantiate the data problem. + DataProblem data; + + // Create Routing Model + RoutingModel routing(data.GetLocations().size(), data.GetVehicleNumber(), + data.GetDepot()); + + // Define weight of each edge + ManhattanDistance distance(data); + routing.SetArcCostEvaluatorOfAllVehicles( + NewPermanentCallback(&distance, &ManhattanDistance::Run)); + AddDistanceDimension(data, &routing); + + // Setting first solution heuristic (cheapest addition). + auto searchParameters = RoutingModel::DefaultSearchParameters(); + searchParameters.set_first_solution_strategy( + FirstSolutionStrategy::PATH_CHEAPEST_ARC); + + const Assignment* solution = routing.SolveWithParameters(searchParameters); + PrintSolution(data, routing, *solution); +} } // namespace operations_research int main(int argc, char** argv) { diff --git a/examples/cpp/weighted_tardiness_sat.cc b/examples/cpp/weighted_tardiness_sat.cc index 74a89e4802..8d29ead5e7 100644 --- a/examples/cpp/weighted_tardiness_sat.cc +++ b/examples/cpp/weighted_tardiness_sat.cc @@ -22,8 +22,8 @@ #include "ortools/base/logging.h" #include "ortools/base/numbers.h" #include "ortools/base/split.h" -#include "ortools/base/strutil.h" #include "ortools/base/strtoint.h" +#include "ortools/base/strutil.h" #include "ortools/base/timer.h" #include "ortools/sat/cp_model.h" #include "ortools/sat/model.h"