Add missing basic examples
C++: - [Up] linear_programming - [Up] integer_programming - constraint_programming_CP / rabbits_pheasants_cp - knapsack - max_flow / min_cost_flow - tsp / vrp note: previous "fuzzy" tsp has been renamed random_tsp. .Net: - vrp
This commit is contained in:
66
examples/cpp/constraint_programming_cp.cc
Normal file
66
examples/cpp/constraint_programming_cp.cc
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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.
|
||||
|
||||
// Constraint programming example that shows how to use the API.
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/constraint_solver/constraint_solver.h"
|
||||
|
||||
namespace operations_research {
|
||||
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 constraints.
|
||||
std::vector<IntVar*> xyvars = {x, y};
|
||||
solver.AddConstraint(solver.MakeAllDifferent(xyvars));
|
||||
|
||||
// Create decision builder to search for solutions.
|
||||
std::vector<IntVar*> allvars = {x, y, z};
|
||||
DecisionBuilder* const db = solver.MakePhase(
|
||||
allvars,
|
||||
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) << "x = " << x->Value()
|
||||
<< " ; y = " << x->Value()
|
||||
<< " ; z = " << z->Value();
|
||||
}
|
||||
LOG(INFO) << "Number of solutions: " << count;
|
||||
LOG(INFO) << "";
|
||||
LOG(INFO) << "Advanced usage:";
|
||||
LOG(INFO) << "Problem solved in " << solver.wall_time() << "ms";
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::RunConstraintProgrammingExample();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010-2017 Google
|
||||
// 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
|
||||
@@ -11,79 +11,82 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//
|
||||
// Integer programming example that shows how to use the API.
|
||||
|
||||
#include "ortools/base/commandlineflags.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#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();
|
||||
// x1 and x2 are integer non-negative variables.
|
||||
MPVariable* const x1 = solver.MakeIntVar(0.0, infinity, "x1");
|
||||
MPVariable* const x2 = solver.MakeIntVar(0.0, infinity, "x2");
|
||||
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");
|
||||
|
||||
// Minimize x1 + 2 * x2.
|
||||
MPObjective* const objective = solver.MutableObjective();
|
||||
objective->SetCoefficient(x1, 1);
|
||||
objective->SetCoefficient(x2, 2);
|
||||
// Maximize x + 10 * y.
|
||||
MPObjective* const objective = solver.MutableObjective();
|
||||
objective->SetCoefficient(x, 1);
|
||||
objective->SetCoefficient(y, 10);
|
||||
objective->SetMaximization();
|
||||
|
||||
// 2 * x2 + 3 * x1 >= 17.
|
||||
MPConstraint* const c0 = solver.MakeRowConstraint(17, infinity);
|
||||
c0->SetCoefficient(x1, 3);
|
||||
c0->SetCoefficient(x2, 2);
|
||||
// x + 7 * y <= 17.5.
|
||||
MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 17.5);
|
||||
c0->SetCoefficient(x, 1);
|
||||
c0->SetCoefficient(y, 7);
|
||||
|
||||
const MPSolver::ResultStatus result_status = solver.Solve();
|
||||
// x <= 3.5
|
||||
MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 3.5);
|
||||
c1->SetCoefficient(x, 1);
|
||||
c1->SetCoefficient(y, 0);
|
||||
|
||||
// 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) << "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";
|
||||
}
|
||||
|
||||
LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds";
|
||||
|
||||
// The objective value of the solution.
|
||||
LOG(INFO) << "Optimal objective value = " << objective->Value();
|
||||
|
||||
// The value of each variable in the solution.
|
||||
LOG(INFO) << "x1 = " << x1->solution_value();
|
||||
LOG(INFO) << "x2 = " << x2->solution_value();
|
||||
|
||||
LOG(INFO) << "Advanced usage:";
|
||||
LOG(INFO) << "Problem solved in " << solver.nodes()
|
||||
<< " branch-and-bound nodes";
|
||||
}
|
||||
|
||||
void RunAllExamples() {
|
||||
#if defined(USE_GLPK)
|
||||
LOG(INFO) << "---- Integer programming example with GLPK ----";
|
||||
RunIntegerProgrammingExample(MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING);
|
||||
#endif
|
||||
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);
|
||||
#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) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::RunAllExamples();
|
||||
return 0;
|
||||
}
|
||||
|
||||
80
examples/cpp/knapsack.cc
Normal file
80
examples/cpp/knapsack.cc
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 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.
|
||||
|
||||
// Bi-dimensional knapsack problem.
|
||||
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/algorithms/knapsack_solver.h"
|
||||
|
||||
namespace operations_research {
|
||||
void RunKnapsackExample() {
|
||||
// Instantiate the solver.
|
||||
KnapsackSolver solver(
|
||||
KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
|
||||
"KnapsackExample");
|
||||
|
||||
std::vector<int64> 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
|
||||
};
|
||||
|
||||
std::vector<std::vector<int64>> 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
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<int64> capacities = {850};
|
||||
|
||||
solver.Init(values, weights, capacities);
|
||||
int64 computed_value = solver.Solve();
|
||||
|
||||
// Print solution
|
||||
std::vector<int> packed_items;
|
||||
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<int>(packed_items_ss, ", "));
|
||||
packed_items_ss << packed_items.back();
|
||||
|
||||
std::vector<int64> packed_weights;
|
||||
packed_weights.reserve(packed_items.size());
|
||||
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<int>(packed_weights_ss, ", "));
|
||||
packed_weights_ss << packed_weights.back();
|
||||
|
||||
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) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::RunKnapsackExample();
|
||||
return 0;
|
||||
}
|
||||
@@ -11,116 +11,100 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//
|
||||
// Linear programming example that shows how to use the API.
|
||||
|
||||
#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(
|
||||
MPSolver::OptimizationProblemType optimization_problem_type) {
|
||||
MPSolver solver("LinearProgrammingExample", optimization_problem_type);
|
||||
const double infinity = solver.infinity();
|
||||
// x1, x2 and x3 are continuous non-negative variables.
|
||||
MPVariable* const x1 = solver.MakeNumVar(0.0, infinity, "x1");
|
||||
MPVariable* const x2 = solver.MakeNumVar(0.0, infinity, "x2");
|
||||
MPVariable* const x3 = solver.MakeNumVar(0.0, infinity, "x3");
|
||||
void RunLinearProgrammingExample(
|
||||
MPSolver::OptimizationProblemType optimization_problem_type) {
|
||||
MPSolver solver("LinearProgrammingExample", optimization_problem_type);
|
||||
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");
|
||||
|
||||
// Maximize 10 * x1 + 6 * x2 + 4 * x3.
|
||||
MPObjective* const objective = solver.MutableObjective();
|
||||
objective->SetCoefficient(x1, 10);
|
||||
objective->SetCoefficient(x2, 6);
|
||||
objective->SetCoefficient(x3, 4);
|
||||
objective->SetMaximization();
|
||||
// Objectif function: Maximize 3x + 4y).
|
||||
MPObjective* const objective = solver.MutableObjective();
|
||||
objective->SetCoefficient(x, 3);
|
||||
objective->SetCoefficient(y, 4);
|
||||
objective->SetMaximization();
|
||||
|
||||
// x1 + x2 + x3 <= 100.
|
||||
MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 100.0);
|
||||
c0->SetCoefficient(x1, 1);
|
||||
c0->SetCoefficient(x2, 1);
|
||||
c0->SetCoefficient(x3, 1);
|
||||
// x + 2y <= 14.
|
||||
MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 14.0);
|
||||
c0->SetCoefficient(x, 1);
|
||||
c0->SetCoefficient(y, 2);
|
||||
|
||||
// 10 * x1 + 4 * x2 + 5 * x3 <= 600.
|
||||
MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 600.0);
|
||||
c1->SetCoefficient(x1, 10);
|
||||
c1->SetCoefficient(x2, 4);
|
||||
c1->SetCoefficient(x3, 5);
|
||||
// 3x - y >= 0.
|
||||
MPConstraint* const c1 = solver.MakeRowConstraint(0.0, infinity);
|
||||
c1->SetCoefficient(x, 3);
|
||||
c1->SetCoefficient(y, -1);
|
||||
|
||||
// 2 * x1 + 2 * x2 + 6 * x3 <= 300.
|
||||
MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 300.0);
|
||||
c2->SetCoefficient(x1, 2);
|
||||
c2->SetCoefficient(x2, 2);
|
||||
c2->SetCoefficient(x3, 6);
|
||||
// x - y <= 2.
|
||||
MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 2.0);
|
||||
c2->SetCoefficient(x, 1);
|
||||
c2->SetCoefficient(y, -1);
|
||||
|
||||
// TODO(user): Change example to show = and >= constraints.
|
||||
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!";
|
||||
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<double> 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()];
|
||||
}
|
||||
|
||||
LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds";
|
||||
|
||||
// The objective value of the solution.
|
||||
LOG(INFO) << "Optimal objective value = " << objective->Value();
|
||||
|
||||
// The value of each variable in the solution.
|
||||
LOG(INFO) << "x1 = " << x1->solution_value();
|
||||
LOG(INFO) << "x2 = " << x2->solution_value();
|
||||
LOG(INFO) << "x3 = " << x3->solution_value();
|
||||
|
||||
LOG(INFO) << "Advanced usage:";
|
||||
LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations";
|
||||
LOG(INFO) << "x1: reduced cost = " << x1->reduced_cost();
|
||||
LOG(INFO) << "x2: reduced cost = " << x2->reduced_cost();
|
||||
LOG(INFO) << "x3: reduced cost = " << x3->reduced_cost();
|
||||
const std::vector<double> 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()];
|
||||
}
|
||||
|
||||
void RunAllExamples() {
|
||||
void RunAllExamples() {
|
||||
#if defined(USE_GLOP)
|
||||
LOG(INFO) << "---- Linear programming example with GLOP ----";
|
||||
RunLinearProgrammingExample(MPSolver::GLOP_LINEAR_PROGRAMMING);
|
||||
LOG(INFO) << "---- Linear programming example with GLOP ----";
|
||||
RunLinearProgrammingExample(MPSolver::GLOP_LINEAR_PROGRAMMING);
|
||||
#endif // USE_GLOP
|
||||
#if defined(USE_GLPK)
|
||||
LOG(INFO) << "---- Linear programming example with GLPK ----";
|
||||
RunLinearProgrammingExample(MPSolver::GLPK_LINEAR_PROGRAMMING);
|
||||
#endif // USE_GLPK
|
||||
#if defined(USE_CLP)
|
||||
LOG(INFO) << "---- Linear programming example with CLP ----";
|
||||
RunLinearProgrammingExample(MPSolver::CLP_LINEAR_PROGRAMMING);
|
||||
LOG(INFO) << "---- Linear programming example with CLP ----";
|
||||
RunLinearProgrammingExample(MPSolver::CLP_LINEAR_PROGRAMMING);
|
||||
#endif // USE_CLP
|
||||
#if defined(USE_GLPK)
|
||||
LOG(INFO) << "---- Linear programming example with GLPK ----";
|
||||
RunLinearProgrammingExample(MPSolver::GLPK_LINEAR_PROGRAMMING);
|
||||
#endif // USE_GLPK
|
||||
#if defined(USE_SLM)
|
||||
LOG(INFO) << "---- Linear programming example with Sulum ----";
|
||||
RunLinearProgrammingExample(MPSolver::SULUM_LINEAR_PROGRAMMING);
|
||||
LOG(INFO) << "---- Linear programming example with Sulum ----";
|
||||
RunLinearProgrammingExample(MPSolver::SULUM_LINEAR_PROGRAMMING);
|
||||
#endif // USE_SLM
|
||||
#if defined(USE_GUROBI)
|
||||
LOG(INFO) << "---- Linear programming example with Gurobi ----";
|
||||
RunLinearProgrammingExample(MPSolver::GUROBI_LINEAR_PROGRAMMING);
|
||||
LOG(INFO) << "---- Linear programming example with Gurobi ----";
|
||||
RunLinearProgrammingExample(MPSolver::GUROBI_LINEAR_PROGRAMMING);
|
||||
#endif // USE_GUROBI
|
||||
#if defined(USE_CPLEX)
|
||||
LOG(INFO) << "---- Linear programming example with CPLEX ----";
|
||||
RunLinearProgrammingExample(MPSolver::CPLEX_LINEAR_PROGRAMMING);
|
||||
LOG(INFO) << "---- Linear programming example with CPLEX ----";
|
||||
RunLinearProgrammingExample(MPSolver::CPLEX_LINEAR_PROGRAMMING);
|
||||
#endif // USE_CPLEX
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
base::SetFlag(&FLAGS_alsologtostderr, true);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::RunAllExamples();
|
||||
return 0;
|
||||
}
|
||||
|
||||
68
examples/cpp/max_flow.cc
Normal file
68
examples/cpp/max_flow.cc
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 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.
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/graph/max_flow.h"
|
||||
|
||||
namespace operations_research {
|
||||
void SolveMaxFlow() {
|
||||
const int num_nodes = 5;
|
||||
// Add each arc
|
||||
// Can't use std::tuple<NodeIndex, NodeIndex, FlowQuantity>
|
||||
// Initialization list is not working on std:tuple cf. N4387
|
||||
// Arc are stored as {{begin_node, end_node}, capacity}
|
||||
std::vector<std::pair<std::pair<NodeIndex, NodeIndex>, 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) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::SolveMaxFlow();
|
||||
return 0;
|
||||
}
|
||||
88
examples/cpp/min_cost_flow.cc
Normal file
88
examples/cpp/min_cost_flow.cc
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 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.
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/graph/min_cost_flow.h"
|
||||
|
||||
namespace operations_research {
|
||||
struct Arc {
|
||||
std::pair<NodeIndex, NodeIndex> nodes;
|
||||
FlowQuantity capacity;
|
||||
FlowQuantity unit_cost;
|
||||
};
|
||||
|
||||
void SolveMinCostFlow() {
|
||||
// Define supply of each node.
|
||||
const std::vector<std::pair<NodeIndex, FlowQuantity>> supplies = {
|
||||
{0, 20},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3,-5},
|
||||
{4,-15}
|
||||
};
|
||||
|
||||
// Define each arc
|
||||
// Can't use std::tuple<NodeIndex, NodeIndex, FlowQuantity>
|
||||
// Initialization list is not working on std:tuple cf. N4387
|
||||
// Arc are stored as {{begin_node, end_node}, capacity}
|
||||
const std::vector<Arc> 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);
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::SolveMinCostFlow();
|
||||
return 0;
|
||||
}
|
||||
67
examples/cpp/rabbits_pheasants_cp.cc
Normal file
67
examples/cpp/rabbits_pheasants_cp.cc
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 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.
|
||||
|
||||
// Knowing that we see 20 heads and 56 legs,
|
||||
// how many pheasants and rabbits are we looking at ?
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/constraint_solver/constraint_solver.h"
|
||||
|
||||
namespace operations_research {
|
||||
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 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);
|
||||
|
||||
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";
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::RunConstraintProgrammingExample();
|
||||
return 0;
|
||||
}
|
||||
167
examples/cpp/random_tsp.cc
Normal file
167
examples/cpp/random_tsp.cc
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright 2010-2017 Google
|
||||
// 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.
|
||||
|
||||
//
|
||||
// Traveling Salesman Sample.
|
||||
//
|
||||
// This is a sample using the routing library to solve a Traveling Salesman
|
||||
// Problem.
|
||||
// The description of the problem can be found here:
|
||||
// http://en.wikipedia.org/wiki/Travelling_salesman_problem.
|
||||
// For small problems one can use the hamiltonian path library directly (cf
|
||||
// graph/hamiltonian_path.h).
|
||||
// The optimization engine uses local search to improve solutions, first
|
||||
// solutions being generated using a cheapest addition heuristic.
|
||||
// Optionally one can randomly forbid a set of random connections between nodes
|
||||
// (forbidden arcs).
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "ortools/base/callback.h"
|
||||
#include "ortools/base/commandlineflags.h"
|
||||
#include "ortools/base/integral_types.h"
|
||||
#include "ortools/base/join.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_flags.h"
|
||||
|
||||
DEFINE_int32(tsp_size, 10, "Size of Traveling Salesman Problem instance.");
|
||||
DEFINE_bool(tsp_use_random_matrix, true, "Use random cost matrix.");
|
||||
DEFINE_int32(tsp_random_forbidden_connections, 0,
|
||||
"Number of random forbidden connections.");
|
||||
DEFINE_bool(tsp_use_deterministic_random_seed, false,
|
||||
"Use deterministic random seeds.");
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
// Random seed generator.
|
||||
int32 GetSeed() {
|
||||
if (FLAGS_tsp_use_deterministic_random_seed) {
|
||||
return ACMRandom::DeterministicSeed();
|
||||
} else {
|
||||
return ACMRandom::HostnamePidTimeSeed();
|
||||
}
|
||||
}
|
||||
|
||||
// Cost/distance functions.
|
||||
|
||||
// Sample function.
|
||||
int64 MyDistance(RoutingModel::NodeIndex from, RoutingModel::NodeIndex to) {
|
||||
// Put your distance code here.
|
||||
return (from + to).value(); // for instance
|
||||
}
|
||||
|
||||
// Random matrix.
|
||||
class RandomMatrix {
|
||||
public:
|
||||
explicit RandomMatrix(int size) : size_(size) {}
|
||||
void Initialize() {
|
||||
matrix_.reset(new int64[size_ * size_]);
|
||||
const int64 kDistanceMax = 100;
|
||||
ACMRandom randomizer(GetSeed());
|
||||
for (RoutingModel::NodeIndex from = RoutingModel::kFirstNode; from < size_;
|
||||
++from) {
|
||||
for (RoutingModel::NodeIndex to = RoutingModel::kFirstNode; to < size_;
|
||||
++to) {
|
||||
if (to != from) {
|
||||
matrix_[MatrixIndex(from, to)] = randomizer.Uniform(kDistanceMax);
|
||||
} else {
|
||||
matrix_[MatrixIndex(from, to)] = 0LL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int64 Distance(RoutingModel::NodeIndex from,
|
||||
RoutingModel::NodeIndex to) const {
|
||||
return matrix_[MatrixIndex(from, to)];
|
||||
}
|
||||
|
||||
private:
|
||||
int64 MatrixIndex(RoutingModel::NodeIndex from,
|
||||
RoutingModel::NodeIndex to) const {
|
||||
return (from * size_ + to).value();
|
||||
}
|
||||
std::unique_ptr<int64[]> matrix_;
|
||||
const int size_;
|
||||
};
|
||||
|
||||
void Tsp() {
|
||||
if (FLAGS_tsp_size > 0) {
|
||||
// TSP of size FLAGS_tsp_size.
|
||||
// Second argument = 1 to build a single tour (it's a TSP).
|
||||
// Nodes are indexed from 0 to FLAGS_tsp_size - 1, by default the start of
|
||||
// the route is node 0.
|
||||
RoutingModel routing(FLAGS_tsp_size, 1, RoutingModel::NodeIndex(0));
|
||||
RoutingSearchParameters parameters = BuildSearchParametersFromFlags();
|
||||
// Setting first solution heuristic (cheapest addition).
|
||||
parameters.set_first_solution_strategy(
|
||||
FirstSolutionStrategy::PATH_CHEAPEST_ARC);
|
||||
|
||||
// Setting the cost function.
|
||||
// Put a permanent callback to the distance accessor here. The callback
|
||||
// has the following signature: ResultCallback2<int64, int64, int64>.
|
||||
// The two arguments are the from and to node inidices.
|
||||
RandomMatrix matrix(FLAGS_tsp_size);
|
||||
if (FLAGS_tsp_use_random_matrix) {
|
||||
matrix.Initialize();
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(
|
||||
NewPermanentCallback(&matrix, &RandomMatrix::Distance));
|
||||
} else {
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(
|
||||
NewPermanentCallback(MyDistance));
|
||||
}
|
||||
// Forbid node connections (randomly).
|
||||
ACMRandom randomizer(GetSeed());
|
||||
int64 forbidden_connections = 0;
|
||||
while (forbidden_connections < FLAGS_tsp_random_forbidden_connections) {
|
||||
const int64 from = randomizer.Uniform(FLAGS_tsp_size - 1);
|
||||
const int64 to = randomizer.Uniform(FLAGS_tsp_size - 1) + 1;
|
||||
if (routing.NextVar(from)->Contains(to)) {
|
||||
LOG(INFO) << "Forbidding connection " << from << " -> " << to;
|
||||
routing.NextVar(from)->RemoveValue(to);
|
||||
++forbidden_connections;
|
||||
}
|
||||
}
|
||||
// Solve, returns a solution if any (owned by RoutingModel).
|
||||
const Assignment* solution = routing.SolveWithParameters(parameters);
|
||||
if (solution != nullptr) {
|
||||
// Solution cost.
|
||||
LOG(INFO) << "Cost " << solution->ObjectiveValue();
|
||||
// Inspect solution.
|
||||
// Only one route here; otherwise iterate from 0 to routing.vehicles() - 1
|
||||
const int route_number = 0;
|
||||
std::string route;
|
||||
for (int64 node = routing.Start(route_number); !routing.IsEnd(node);
|
||||
node = solution->Value(routing.NextVar(node))) {
|
||||
absl::StrAppend(&route, routing.IndexToNode(node).value(), " (", node,
|
||||
") -> ");
|
||||
}
|
||||
const int64 end = routing.End(route_number);
|
||||
absl::StrAppend(&route, routing.IndexToNode(end).value(), " (", end, ")");
|
||||
LOG(INFO) << route;
|
||||
} else {
|
||||
LOG(INFO) << "No solution found.";
|
||||
}
|
||||
} else {
|
||||
LOG(INFO) << "Specify an instance size greater than 0.";
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
operations_research::Tsp();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010-2017 Google
|
||||
// Copyright 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
|
||||
@@ -11,157 +11,129 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//
|
||||
// Traveling Salesman Sample.
|
||||
//
|
||||
// This is a sample using the routing library to solve a Traveling Salesman
|
||||
// Problem.
|
||||
// The description of the problem can be found here:
|
||||
// http://en.wikipedia.org/wiki/Travelling_salesman_problem.
|
||||
// For small problems one can use the hamiltonian path library directly (cf
|
||||
// graph/hamiltonian_path.h).
|
||||
// The optimization engine uses local search to improve solutions, first
|
||||
// solutions being generated using a cheapest addition heuristic.
|
||||
// Optionally one can randomly forbid a set of random connections between nodes
|
||||
// (forbidden arcs).
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "ortools/base/callback.h"
|
||||
#include "ortools/base/commandlineflags.h"
|
||||
#include "ortools/base/integral_types.h"
|
||||
#include "ortools/base/join.h"
|
||||
#include "ortools/base/random.h"
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/constraint_solver/routing.h"
|
||||
#include "ortools/constraint_solver/routing_enums.pb.h"
|
||||
#include "ortools/constraint_solver/routing_flags.h"
|
||||
|
||||
DEFINE_int32(tsp_size, 10, "Size of Traveling Salesman Problem instance.");
|
||||
DEFINE_bool(tsp_use_random_matrix, true, "Use random cost matrix.");
|
||||
DEFINE_int32(tsp_random_forbidden_connections, 0,
|
||||
"Number of random forbidden connections.");
|
||||
DEFINE_bool(tsp_use_deterministic_random_seed, false,
|
||||
"Use deterministic random seeds.");
|
||||
|
||||
namespace operations_research {
|
||||
class DataProblem {
|
||||
private:
|
||||
std::vector<std::vector<int>> locations_;
|
||||
|
||||
// Random seed generator.
|
||||
int32 GetSeed() {
|
||||
if (FLAGS_tsp_use_deterministic_random_seed) {
|
||||
return ACMRandom::DeterministicSeed();
|
||||
} else {
|
||||
return ACMRandom::HostnamePidTimeSeed();
|
||||
}
|
||||
}
|
||||
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}
|
||||
};
|
||||
|
||||
// Cost/distance functions.
|
||||
// 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<int, 2> cityBlock = {228/2, 80};
|
||||
for (auto &i: locations_) {
|
||||
i[0] = i[0] * cityBlock[0];
|
||||
i[1] = i[1] * cityBlock[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Sample function.
|
||||
int64 MyDistance(RoutingModel::NodeIndex from, RoutingModel::NodeIndex to) {
|
||||
// Put your distance code here.
|
||||
return (from + to).value(); // for instance
|
||||
}
|
||||
std::size_t GetVehicleNumber() const { return 1;}
|
||||
const std::vector<std::vector<int>>& GetLocations() const { return locations_;}
|
||||
RoutingModel::NodeIndex GetDepot() const { return RoutingModel::kFirstNode;}
|
||||
};
|
||||
|
||||
// Random matrix.
|
||||
class RandomMatrix {
|
||||
public:
|
||||
explicit RandomMatrix(int size) : size_(size) {}
|
||||
void Initialize() {
|
||||
matrix_.reset(new int64[size_ * size_]);
|
||||
const int64 kDistanceMax = 100;
|
||||
ACMRandom randomizer(GetSeed());
|
||||
for (RoutingModel::NodeIndex from = RoutingModel::kFirstNode; from < size_;
|
||||
++from) {
|
||||
for (RoutingModel::NodeIndex to = RoutingModel::kFirstNode; to < size_;
|
||||
++to) {
|
||||
if (to != from) {
|
||||
matrix_[MatrixIndex(from, to)] = randomizer.Uniform(kDistanceMax);
|
||||
} else {
|
||||
matrix_[MatrixIndex(from, to)] = 0LL;
|
||||
/*! @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<std::vector<int64>> distances_;
|
||||
public:
|
||||
ManhattanDistance(const DataProblem& data) {
|
||||
// Precompute distance between location to have distance callback in O(1)
|
||||
distances_ = std::vector<std::vector<int64>>(
|
||||
data.GetLocations().size(),
|
||||
std::vector<int64>(
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int64 Distance(RoutingModel::NodeIndex from,
|
||||
RoutingModel::NodeIndex to) const {
|
||||
return matrix_[MatrixIndex(from, to)];
|
||||
|
||||
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<RoutingModel&>(routing).GetArcCostForVehicle(previous_index, index, 0LL);
|
||||
}
|
||||
LOG(INFO) << route.str() << routing.IndexToNode(index).value();
|
||||
LOG(INFO) << "Distance of the route: " << distance << "m";
|
||||
}
|
||||
|
||||
private:
|
||||
int64 MatrixIndex(RoutingModel::NodeIndex from,
|
||||
RoutingModel::NodeIndex to) const {
|
||||
return (from * size_ + to).value();
|
||||
}
|
||||
std::unique_ptr<int64[]> matrix_;
|
||||
const int size_;
|
||||
};
|
||||
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));
|
||||
|
||||
void Tsp() {
|
||||
if (FLAGS_tsp_size > 0) {
|
||||
// TSP of size FLAGS_tsp_size.
|
||||
// Second argument = 1 to build a single tour (it's a TSP).
|
||||
// Nodes are indexed from 0 to FLAGS_tsp_size - 1, by default the start of
|
||||
// the route is node 0.
|
||||
RoutingModel routing(FLAGS_tsp_size, 1, RoutingModel::NodeIndex(0));
|
||||
RoutingSearchParameters parameters = BuildSearchParametersFromFlags();
|
||||
// Setting first solution heuristic (cheapest addition).
|
||||
parameters.set_first_solution_strategy(
|
||||
FirstSolutionStrategy::PATH_CHEAPEST_ARC);
|
||||
RoutingSearchParameters searchParameters = RoutingModel::DefaultSearchParameters();
|
||||
searchParameters.set_first_solution_strategy(FirstSolutionStrategy::PATH_CHEAPEST_ARC);
|
||||
|
||||
// Setting the cost function.
|
||||
// Put a permanent callback to the distance accessor here. The callback
|
||||
// has the following signature: ResultCallback2<int64, int64, int64>.
|
||||
// The two arguments are the from and to node inidices.
|
||||
RandomMatrix matrix(FLAGS_tsp_size);
|
||||
if (FLAGS_tsp_use_random_matrix) {
|
||||
matrix.Initialize();
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(
|
||||
NewPermanentCallback(&matrix, &RandomMatrix::Distance));
|
||||
} else {
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(
|
||||
NewPermanentCallback(MyDistance));
|
||||
}
|
||||
// Forbid node connections (randomly).
|
||||
ACMRandom randomizer(GetSeed());
|
||||
int64 forbidden_connections = 0;
|
||||
while (forbidden_connections < FLAGS_tsp_random_forbidden_connections) {
|
||||
const int64 from = randomizer.Uniform(FLAGS_tsp_size - 1);
|
||||
const int64 to = randomizer.Uniform(FLAGS_tsp_size - 1) + 1;
|
||||
if (routing.NextVar(from)->Contains(to)) {
|
||||
LOG(INFO) << "Forbidding connection " << from << " -> " << to;
|
||||
routing.NextVar(from)->RemoveValue(to);
|
||||
++forbidden_connections;
|
||||
}
|
||||
}
|
||||
// Solve, returns a solution if any (owned by RoutingModel).
|
||||
const Assignment* solution = routing.SolveWithParameters(parameters);
|
||||
if (solution != nullptr) {
|
||||
// Solution cost.
|
||||
LOG(INFO) << "Cost " << solution->ObjectiveValue();
|
||||
// Inspect solution.
|
||||
// Only one route here; otherwise iterate from 0 to routing.vehicles() - 1
|
||||
const int route_number = 0;
|
||||
std::string route;
|
||||
for (int64 node = routing.Start(route_number); !routing.IsEnd(node);
|
||||
node = solution->Value(routing.NextVar(node))) {
|
||||
absl::StrAppend(&route, routing.IndexToNode(node).value(), " (", node,
|
||||
") -> ");
|
||||
}
|
||||
const int64 end = routing.End(route_number);
|
||||
absl::StrAppend(&route, routing.IndexToNode(end).value(), " (", end, ")");
|
||||
LOG(INFO) << route;
|
||||
} else {
|
||||
LOG(INFO) << "No solution found.";
|
||||
}
|
||||
} else {
|
||||
LOG(INFO) << "Specify an instance size greater than 0.";
|
||||
const Assignment* solution = routing.SolveWithParameters(searchParameters);
|
||||
PrintSolution(data, routing, *solution);
|
||||
}
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
operations_research::Tsp();
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::Solve();
|
||||
return 0;
|
||||
}
|
||||
|
||||
161
examples/cpp/vrp.cc
Normal file
161
examples/cpp/vrp.cc
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright 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.
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/constraint_solver/routing.h"
|
||||
|
||||
namespace operations_research {
|
||||
class DataProblem {
|
||||
private:
|
||||
std::vector<std::vector<int>> 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}
|
||||
};
|
||||
|
||||
// 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<int, 2> 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<std::vector<int>>& 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<std::vector<int64>> distances_;
|
||||
public:
|
||||
ManhattanDistance(const DataProblem& data) {
|
||||
// Precompute distance between location to have distance callback in O(1)
|
||||
distances_ = std::vector<std::vector<int64>>(
|
||||
data.GetLocations().size(),
|
||||
std::vector<int64>(
|
||||
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<RoutingModel&>(routing).GetArcCostForVehicle(previous_index, index, i);
|
||||
}
|
||||
LOG(INFO) << route.str() << routing.IndexToNode(index).value();
|
||||
LOG(INFO) << "Distance of the route: " << distance << "m";
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
FLAGS_logtostderr = 1;
|
||||
operations_research::Solve();
|
||||
return 0;
|
||||
}
|
||||
164
examples/dotnet/vrp.cs
Normal file
164
examples/dotnet/vrp.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2018 Google
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Google.OrTools.ConstraintSolver;
|
||||
|
||||
/// <summary>
|
||||
/// This is a sample using the routing library .Net wrapper to solve a VRP problem.
|
||||
/// A description of the problem can be found here:
|
||||
/// http://en.wikipedia.org/wiki/Vehicle_routing_problem.
|
||||
/// </summary>
|
||||
public class VRP {
|
||||
class DataProblem {
|
||||
private int[,] locations_;
|
||||
|
||||
// Constructor:
|
||||
public DataProblem() {
|
||||
locations_ = new int[,] {
|
||||
{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"
|
||||
int[] cityBlock = {228/2, 80};
|
||||
for (int i=0; i < locations_.GetLength(0); i++) {
|
||||
locations_[i, 0] = locations_[i, 0] * cityBlock[0];
|
||||
locations_[i, 1] = locations_[i, 1] * cityBlock[1];
|
||||
}
|
||||
}
|
||||
|
||||
public int GetVehicleNumber() { return 4;}
|
||||
public ref readonly int[,] GetLocations() { return ref locations_;}
|
||||
public int GetLocationNumber() { return locations_.GetLength(0);}
|
||||
public int GetDepot() { return 0;}
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Manhattan distance implemented as a callback. It uses an array of
|
||||
/// positions and computes the Manhattan distance between the two
|
||||
/// positions of two different indices.
|
||||
/// </summary>
|
||||
class ManhattanDistance : NodeEvaluator2 {
|
||||
private int[,] distances_;
|
||||
|
||||
public ManhattanDistance(in DataProblem data) {
|
||||
// precompute distance between location to have distance callback in O(1)
|
||||
distances_ = new int[data.GetLocationNumber(), data.GetLocationNumber()];
|
||||
for (int fromNode = 0; fromNode < data.GetLocationNumber(); fromNode++) {
|
||||
for (int toNode = 0; toNode < data.GetLocationNumber(); toNode++) {
|
||||
if (fromNode == toNode)
|
||||
distances_[fromNode, toNode] = 0;
|
||||
else
|
||||
distances_[fromNode, toNode] =
|
||||
Math.Abs(data.GetLocations()[toNode, 0] - data.GetLocations()[fromNode, 0]) +
|
||||
Math.Abs(data.GetLocations()[toNode, 1] - data.GetLocations()[fromNode, 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the manhattan distance between the two nodes
|
||||
/// </summary>
|
||||
public override long Run(int FromNode, int ToNode) {
|
||||
return distances_[FromNode, ToNode];
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Add distance Dimension
|
||||
/// </summary>
|
||||
static void AddDistanceDimension(
|
||||
in DataProblem data,
|
||||
in RoutingModel routing) {
|
||||
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.GetDimensionOrDie(distance);
|
||||
// Try to minimize the max distance among vehicles.
|
||||
// /!\ It doesn't mean the standard deviation is minimized
|
||||
distanceDimension.SetGlobalSpanCostCoefficient(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print the solution
|
||||
/// </summary>
|
||||
static void PrintSolution(
|
||||
in DataProblem data,
|
||||
in RoutingModel routing,
|
||||
in Assignment solution) {
|
||||
Console.WriteLine("Objective: {0}", solution.ObjectiveValue());
|
||||
// Inspect solution.
|
||||
for (int i=0; i < data.GetVehicleNumber(); ++i) {
|
||||
Console.WriteLine("Route for Vehicle " + i + ":");
|
||||
long distance = 0;
|
||||
var index = routing.Start(i);
|
||||
while (routing.IsEnd(index) == false) {
|
||||
Console.Write("{0} -> ", routing.IndexToNode(index));
|
||||
var previousIndex = index;
|
||||
index = solution.Value(routing.NextVar(index));
|
||||
distance += routing.GetArcCostForVehicle(previousIndex, index, i);
|
||||
}
|
||||
Console.WriteLine("{0}", routing.IndexToNode(index));
|
||||
Console.WriteLine("Distance of the route: {0}m", distance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Solves the current routing problem.
|
||||
/// </summary>
|
||||
static void Solve() {
|
||||
// Instantiate the data problem.
|
||||
DataProblem data = new DataProblem();
|
||||
|
||||
// Create Routing Model
|
||||
RoutingModel routing = new RoutingModel(
|
||||
data.GetLocationNumber(),
|
||||
data.GetVehicleNumber(),
|
||||
data.GetDepot());
|
||||
|
||||
// Define weight cost of each edge
|
||||
NodeEvaluator2 distanceEvaluator = new ManhattanDistance(data);
|
||||
//protect callbacks from the GC
|
||||
GC.KeepAlive(distanceEvaluator);
|
||||
routing.SetArcCostEvaluatorOfAllVehicles(distanceEvaluator);
|
||||
AddDistanceDimension(data, routing);
|
||||
|
||||
// Setting first solution heuristic (cheapest addition).
|
||||
RoutingSearchParameters searchParameters = RoutingModel.DefaultSearchParameters();
|
||||
searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
|
||||
|
||||
Assignment solution = routing.SolveWithParameters(searchParameters);
|
||||
PrintSolution(data, routing, solution);
|
||||
}
|
||||
|
||||
public static void Main(String[] args) {
|
||||
Solve();
|
||||
}
|
||||
}
|
||||
20
examples/dotnet/vrp.csproj
Normal file
20
examples/dotnet/vrp.csproj
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>7.2</LangVersion>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
<RestoreSources>../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<GenerateTailCalls>true</GenerateTailCalls>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="vrp.cs" />
|
||||
<PackageReference Include="Google.OrTools" Version="6.9.*" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -12,7 +12,6 @@
|
||||
// limitations under the License.
|
||||
import java.io.*;
|
||||
import static java.lang.Math.abs;
|
||||
//import java.util.*;
|
||||
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.NodeEvaluator2;
|
||||
|
||||
@@ -37,6 +37,7 @@ cc:
|
||||
$(warning Cannot find '$@' command which is needed for build. Please make sure it is installed and in system path.)
|
||||
|
||||
test_cc: cc
|
||||
check_cc: cc
|
||||
test_fz: cc
|
||||
else
|
||||
cc: $(OR_TOOLS_LIBS)
|
||||
@@ -46,6 +47,8 @@ test_cc: \
|
||||
test_cc_tests \
|
||||
test_cc_samples \
|
||||
test_cc_examples
|
||||
.PHONY: check_cc
|
||||
check_cc: check_cc_examples
|
||||
test_fz: \
|
||||
test_fz_examples
|
||||
BUILT_LANGUAGES += C++
|
||||
@@ -468,6 +471,15 @@ $(OBJ_DIR)/%.$O: $(TEST_DIR)/%.cc $(CP_DEPS) $(SAT_DEPS) $(LP_DEPS) | $(OBJ_DIR)
|
||||
|
||||
.PHONY: test_cc_examples # Build and Run all C++ Examples (located in examples/cpp)
|
||||
test_cc_examples: cc
|
||||
$(MAKE) rcc_linear_programming
|
||||
$(MAKE) rcc_integer_programming
|
||||
$(MAKE) rcc_constraint_programming_cp
|
||||
$(MAKE) rcc_rabbits_pheasants_cp
|
||||
$(MAKE) rcc_tsp
|
||||
$(MAKE) rcc_vrp
|
||||
$(MAKE) rcc_knapsack
|
||||
$(MAKE) rcc_max_flow
|
||||
$(MAKE) rcc_min_cost_flow
|
||||
$(MAKE) rcc_costas_array
|
||||
$(MAKE) rcc_cryptarithm
|
||||
$(MAKE) rcc_cvrp_disjoint_tw
|
||||
@@ -482,13 +494,11 @@ test_cc_examples: cc
|
||||
$(MAKE) rcc_flow_api
|
||||
# $(MAKE) rcc_frequency_assignment_problem # Need data file
|
||||
$(MAKE) rcc_golomb ARGS="--size=5"
|
||||
$(MAKE) rcc_integer_programming
|
||||
$(MAKE) rcc_jobshop ARGS="--data_file=examples/data/jobshop/ft06"
|
||||
$(MAKE) rcc_jobshop_earlytardy ARGS="--machine_count=6 --job_count=6"
|
||||
$(MAKE) rcc_jobshop_ls ARGS="--data_file=examples/data/jobshop/ft06"
|
||||
$(MAKE) rcc_jobshop_sat ARGS="--input=examples/data/jobshop/ft06"
|
||||
$(MAKE) rcc_linear_assignment_api
|
||||
$(MAKE) rcc_linear_programming
|
||||
$(MAKE) rcc_linear_solver_protocol_buffers
|
||||
$(MAKE) rcc_ls_api
|
||||
$(MAKE) rcc_magic_square
|
||||
@@ -497,17 +507,29 @@ test_cc_examples: cc
|
||||
$(MAKE) rcc_multidim_knapsack ARGS="--data_file examples/data/multidim_knapsack/PB1.DAT"
|
||||
$(MAKE) rcc_network_routing ARGS="--clients=10 --backbones=5 --demands=10 --traffic_min=5 --traffic_max=10 --min_client_degree=2 --max_client_degree=5 --min_backbone_degree=3 --max_backbone_degree=5 --max_capacity=20 --fixed_charge_cost=10"
|
||||
$(MAKE) rcc_nqueens
|
||||
$(MAKE) rcc_pdptw ARGS="--pdp_file examples/data/pdptw/LC1_2_1.txt"
|
||||
$(MAKE) rcc_random_tsp
|
||||
$(MAKE) rcc_pdptw ARGS="--pdp_file=examples/data/pdptw/LC1_2_1.txt"
|
||||
# $(MAKE) rcc_shift_minimization_sat # Port to new API.
|
||||
# $(MAKE) rcc_solve # Need data file
|
||||
$(MAKE) rcc_sports_scheduling ARGS="--num_teams=8 --time_limit=10000"
|
||||
$(MAKE) rcc_strawberry_fields_with_column_generation
|
||||
$(MAKE) rcc_tsp
|
||||
$(MAKE) rcc_weighted_tardiness_sat
|
||||
|
||||
$(OBJ_DIR)/%.$O: $(CC_EX_DIR)/%.cc $(CP_DEPS) $(SAT_DEPS) $(LP_DEPS)| $(OBJ_DIR)
|
||||
$(CCC) $(CFLAGS) -c $(CC_EX_PATH)$S$*.cc $(OBJ_OUT)$(OBJ_DIR)$S$*.$O
|
||||
|
||||
.PHONY: check_cc_examples # Build and Run few C++ Examples
|
||||
check_cc_examples:
|
||||
$(MAKE) rcc_linear_programming
|
||||
$(MAKE) rcc_integer_programming
|
||||
$(MAKE) rcc_constraint_programming_cp
|
||||
$(MAKE) rcc_rabbits_pheasants_cp
|
||||
$(MAKE) rcc_tsp
|
||||
$(MAKE) rcc_vrp
|
||||
$(MAKE) rcc_knapsack
|
||||
$(MAKE) rcc_max_flow
|
||||
$(MAKE) rcc_min_cost_flow
|
||||
|
||||
.PHONY: test_cc_samples # Build and Run all C++ Samples (located in ortools/*/samples)
|
||||
test_cc_samples: cc
|
||||
$(MAKE) rcc_binpacking_problem
|
||||
|
||||
@@ -535,6 +535,7 @@ test_dotnet_examples_csharp: $(DOTNET_ORTOOLS_NUPKG)
|
||||
$(MAKE) rdotnet_to_num
|
||||
$(MAKE) rdotnet_traffic_lights
|
||||
$(MAKE) rdotnet_tsp
|
||||
$(MAKE) rdotnet_vrp
|
||||
$(MAKE) rdotnet_volsay
|
||||
$(MAKE) rdotnet_volsay2
|
||||
$(MAKE) rdotnet_volsay3
|
||||
|
||||
Reference in New Issue
Block a user