Doc automatic update

This commit is contained in:
nikolaj.van.omme@gmail.com
2014-09-09 17:58:22 +00:00
parent 2d92c36fc3
commit 9b5436635b
38 changed files with 5710 additions and 12 deletions

View File

@@ -1,4 +1,10 @@
v.0.2.11: (2014-09-09 13:57:19)
-------------------------------
* Quick update of the tutorial codes in chapter 10 and one file for chap13: code adapted to the new API; the manual is NOT up to date!
* Tutorial code for common and routing_common added.
v.0.2.10: (2014-09-04 16:09:13)
-------------------------------
* Quick update of the tutorial codes in chapters 2, 3 and 6: code adapted to the new API; the manual is NOT up to date!

View File

@@ -84,10 +84,11 @@ Thank you very much.
<h2>What's new?</h2>
<hr>
<p id="new">Here is a little summary:</p>
<pre id="verbatim">v.0.2.10: (2014-09-04 16:09:13)
<pre id="verbatim">v.0.2.11: (2014-09-09 13:57:19)
-------------------------------
* Quick update of the tutorial codes in chapters 2, 3 and 6: code adapted to the new API; the manual is NOT up to date!
* Licenses updated;
* Quick update of the tutorial codes in chapter 10 and one file for chap13: code adapted to the new API; the manual is NOT up to date!
* Tutorial code for common and routing_common added.
</pre>
<p>This is the <a href="changes_list.txt">list of changes</a>.</p>
<h5>Legend:</h5>
@@ -341,6 +342,12 @@ to use these makefiles.</p>
You can also overwrite this variable when invoking make:
<div class="code_line">make OR_TOOLS_TOP=/home/username/or-tools-read-only</div>
</li>
<li>If you want to play with the routing examples, the <code>TUTORIAL</code> variable must point to the C++ tutorial directory. By default, it is defined as:
<div class="code_line">TUTORIAL=($OR_TOOLS_TOP)/documentation/tutorials/cplusplus</div>
If you deploy the tutorial examples somewhere else, update this variable accordingly.
</li>
<li>If you want to compile all examples:
<div class="code_line">make all</div>
</li>
@@ -354,11 +361,11 @@ You can also overwrite this variable when invoking make:
</li>
</ul>
</li>
<li>To delete the created files:
<li>To delete all generated files:
<div class="code_line">make local_clean</div>
Don't use
<font color="red">Don't use</font>
<div class="code_line">make clean</div>
as you will erase the generated files for the whole library!
<font color="red">as you will erase the generated files for the whole library!</font>
</li>
</ol>
@@ -394,7 +401,7 @@ as you will erase the generated files for the whole library!
<p>
<ul>
<li><strong>C++:</strong> chapters 2, 3 and 6.</li>
<li><strong>C++:</strong> chapters 2, 3, 6 and almost all of chapter 10.</li>
<li><strong>Python:</strong> chapter 2.</li>
<li><strong>Java:</strong> chapter 2.</li>
<li><strong>C#:</strong> chapter 2.</li>

View File

@@ -0,0 +1,76 @@
NAME : A-n32-k5
COMMENT : (Augerat et al, Min no of trucks: 5, Optimal value: 784)
TYPE : CVRP
DIMENSION : 32
EDGE_WEIGHT_TYPE : EUC_2D
CAPACITY : 100
NODE_COORD_SECTION
1 82 76
2 96 44
3 50 5
4 49 8
5 13 7
6 29 89
7 58 30
8 84 39
9 14 24
10 2 39
11 3 82
12 5 10
13 98 52
14 84 25
15 61 59
16 1 65
17 88 51
18 91 2
19 19 32
20 93 3
21 50 93
22 98 14
23 5 42
24 42 9
25 61 62
26 9 97
27 80 55
28 57 69
29 23 15
30 20 70
31 85 60
32 98 5
DEMAND_SECTION
1 0
2 19
3 21
4 6
5 19
6 7
7 12
8 16
9 6
10 16
11 8
12 14
13 21
14 16
15 3
16 22
17 18
18 19
19 1
20 24
21 8
22 12
23 4
24 8
25 24
26 24
27 2
28 20
29 15
30 2
31 14
32 9
DEPOT_SECTION
1
-1
EOF

View File

@@ -0,0 +1,73 @@
OR_TOOLS_TOP=/home/nikolaj/Documents/WORK/Google/or-tools-read-only
OR_TOOLS_SOURCES=$(OR_TOOLS_TOP)/src
TUTORIAL=/home/nikolaj/Documents/WORK/Google/OR_TOOLS_DOC/SOURCES/TUTORIALS/cplusplus
SOURCES= cvrp_data_generator.cc check_vrp_solution.cc check_cvrp_solution.cc vrp cvrp_basic \
vrp_solution_to_epix cvrp_solution_to_epix
OBJECTS=$(SOURCES:.cc=.o)
EXE=$(SOURCES:.cc=)
include $(OR_TOOLS_TOP)/Makefile
.PHONY: all local_clean
all: $(EXE)
cvrp_data_generator.o: cvrp_data_generator.cc $(OR_TOOLS_SOURCES)/constraint_solver/routing.h \
$(TUTORIAL)/routing_common/routing_common.h $(TUTORIAL)/routing_common/routing_data_generator.h cvrp_data_generator.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c cvrp_data_generator.cc -o cvrp_data_generator.o
cvrp_data_generator: $(ROUTING_DEPS) cvrp_data_generator.o
$(CCC) $(CFLAGS) cvrp_data_generator.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o cvrp_data_generator
check_vrp_solution.o: check_vrp_solution.cc $(OR_TOOLS_SOURCES)/constraint_solver/routing.h \
$(TUTORIAL)/routing_common/routing_common.h $(TUTORIAL)/routing_common/routing_data_generator.h cvrp_solution.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c check_vrp_solution.cc -o check_vrp_solution.o
check_vrp_solution: $(ROUTING_DEPS) check_vrp_solution.o
$(CCC) $(CFLAGS) check_vrp_solution.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o check_vrp_solution
check_cvrp_solution.o: check_cvrp_solution.cc $(OR_TOOLS_SOURCES)/constraint_solver/routing.h \
$(TUTORIAL)/routing_common/routing_common.h $(TUTORIAL)/routing_common/routing_data_generator.h cvrp_solution.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c check_cvrp_solution.cc -o check_cvrp_solution.o
check_cvrp_solution: $(ROUTING_DEPS) check_cvrp_solution.o
$(CCC) $(CFLAGS) check_cvrp_solution.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o check_cvrp_solution
vrp.o: vrp.cc $(TUTORIAL)/routing_common/routing_common.h $(TUTORIAL)/routing_common/routing_data.h \
$(TUTORIAL)/routing_common/routing_solution.h cvrp_data.h cvrp_solution.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c vrp.cc -o vrp.o
vrp: $(ROUTING_DEPS) vrp.o
$(CCC) $(CFLAGS) vrp.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o vrp
cvrp_basic.o: cvrp_basic.cc $(OR_TOOLS_SOURCES)/constraint_solver/routing.h \
$(TUTORIAL)/routing_common/tsplib_reader.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c cvrp_basic.cc -o cvrp_basic.o
cvrp_basic: $(ROUTING_DEPS) cvrp_basic.o
$(CCC) $(CFLAGS) cvrp_basic.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o cvrp_basic
vrp_solution_to_epix.o: vrp_solution_to_epix.cc $(TUTORIAL)/routing_common/routing_common.h $(TUTORIAL)/routing_common/routing_data.h \
$(TUTORIAL)/routing_common/routing_solution.h $(TUTORIAL)/routing_common/routing_epix_helper.h cvrp_data.h cvrp_solution.h \
cvrp_epix_data.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c vrp_solution_to_epix.cc -o vrp_solution_to_epix.o
vrp_solution_to_epix: $(ROUTING_DEPS) vrp_solution_to_epix.o
$(CCC) $(CFLAGS) vrp_solution_to_epix.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o vrp_solution_to_epix
cvrp_solution_to_epix.o: cvrp_solution_to_epix.cc $(TUTORIAL)/routing_common/routing_common.h $(TUTORIAL)/routing_common/routing_data.h \
$(TUTORIAL)/routing_common/routing_solution.h $(TUTORIAL)/routing_common/routing_epix_helper.h cvrp_data.h cvrp_solution.h \
cvrp_epix_data.h
$(CCC) $(CFLAGS) -I $(TUTORIAL) -c cvrp_solution_to_epix.cc -o cvrp_solution_to_epix.o
cvrp_solution_to_epix: $(ROUTING_DEPS) cvrp_solution_to_epix.o
$(CCC) $(CFLAGS) cvrp_solution_to_epix.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o cvrp_solution_to_epix
local_clean:
rm $(OBJECTS) $(EXE)

View File

@@ -0,0 +1,52 @@
// Copyright 2011-2014 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.
//
//
// Simple program to test a CVRP solution.
#include <iostream>
#include "base/commandlineflags.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/tsplib_reader.h"
int main(int argc, char **argv) {
std::string usage("Checks the feasibility of a CVRP solution.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n");
usage += argv[0];
usage += " -instance_file=<TSPLIB file> -solution_file=<(C)VRP solution>\n";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_instance_file != "" && FLAGS_solution_file != "") {
operations_research::TSPLIBReader tsp_data_reader(FLAGS_instance_file);
operations_research::CVRPData cvrp_data(tsp_data_reader);
operations_research::CVRPSolution cvrp_sol(cvrp_data, FLAGS_solution_file);
if (FLAGS_distance_file != "") {
cvrp_data.WriteDistanceMatrix(FLAGS_distance_file);
}
if (cvrp_sol.IsFeasibleSolution()) {
LG << "Solution is feasible!";
LG << "Obj value = " << cvrp_sol.ComputeObjectiveValue();
} else {
LG << "Solution is NOT feasible...";
}
} else {
std::cout << google::ProgramUsage();
exit(-1);
}
return 0;
}

View File

@@ -0,0 +1,56 @@
// Copyright 2011-2014 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.
//
//
// Simple program to test a VRP solution.
#include <iostream>
#include "base/commandlineflags.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/tsplib_reader.h"
int main(int argc, char **argv) {
std::string usage("Checks the feasibility of a VRP solution.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n");
usage += argv[0];
usage += " -instance_file=<TSPLIB file> -solution_file=<(C)VRP solution>\n";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_instance_file != "" && FLAGS_solution_file != "") {
operations_research::TSPLIBReader tsp_data_reader(FLAGS_instance_file);
operations_research::CVRPData cvrp_data(tsp_data_reader);
operations_research::CVRPSolution cvrp_sol(cvrp_data, FLAGS_solution_file);
if (FLAGS_distance_file != "") {
cvrp_data.WriteDistanceMatrix(FLAGS_distance_file);
}
if (cvrp_sol.IsSolution()) {
LG << "Solution is feasible!";
LG << "Obj value = " << cvrp_sol.ComputeObjectiveValue();
if (cvrp_sol.IsFeasibleSolution()) {
LG << "Solution is even CVRP feasible!!!";
}
} else {
LG << "Solution is NOT feasible...";
}
} else {
std::cout << google::ProgramUsage();
exit(-1);
}
return 0;
}

View File

@@ -0,0 +1,141 @@
// Copyright 2011-2014 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.
//
//
// Simple program to solve the CVRP with Local Search in or-tools.
#include <string>
#include <fstream>
#include "base/commandlineflags.h"
#include "constraint_solver/routing.h"
#include "base/join.h"
#include "base/timer.h"
#include "constraint_solver/routing.h"
#include "common/limits.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/tsplib_reader.h"
DEFINE_int32(depot, 1, "The starting node of the tour.");
DEFINE_string(initial_solution_file, "", "Input file with a valid feasible solution.");
DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms. 0 means no limit.");
DEFINE_int32(no_solution_improvement_limit, 200, "Number of allowed solutions without improving the objective value.");
namespace operations_research {
void CVRPBasicSolver (const CVRPData & data) {
const int size = data.Size();
const int64 capacity = data.Capacity();
CHECK_GT(FLAGS_number_vehicles, 0) << "We need at least one vehicle!";
// Little check to see if we have enough vehicles
CHECK_GT(capacity, data.TotalDemand()/FLAGS_number_vehicles) << "No enough vehicles to cover all the demands";
RoutingModel routing(size, FLAGS_number_vehicles);
routing.SetCost(NewPermanentCallback(&data, &CVRPData::Distance));
// Disabling Large Neighborhood Search, comment out to activate it.
//routing.SetCommandLineOption("routing_no_lns", "true");
if (FLAGS_time_limit_in_ms > 0) {
routing.UpdateTimeLimit(FLAGS_time_limit_in_ms);
}
// Setting depot
CHECK_GT(FLAGS_depot, 0) << " Because we use the" << " TSPLIB convention, the depot id must be > 0";
RoutingModel::NodeIndex depot(FLAGS_depot -1);
routing.SetDepot(depot);
// add capacities constraints
std::vector<int64> demands(size);
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < size; ++i) {
demands[i.value()] = data.Demand(i);
}
routing.AddVectorDimension(&demands[0], capacity, true, "Demand");
routing.CloseModel();
// Use initial solution if provided
Assignment * initial_sol = NULL;
if (FLAGS_initial_solution_file != "") {
initial_sol = routing.solver()->MakeAssignment();//needed by RoutesToAssignment but actually doesn't do much... to detail
CVRPSolution cvrp_init_sol(data, FLAGS_initial_solution_file);
routing.RoutesToAssignment(cvrp_init_sol.Routes(), true, true, initial_sol);
if (routing.solver()->CheckAssignment(initial_sol)) {// just in case and to fill the complementary variables
CVRPSolution temp_sol(data, &routing, initial_sol);
LG << "Initial solution provided is feasible with obj = " << temp_sol.ComputeObjectiveValue();//
} else {
LG << "Initial solution provided is NOT feasible... exit!";
return;
}
}
NoImprovementLimit * const no_improvement_limit = MakeNoImprovementLimit(routing.solver(), FLAGS_no_solution_improvement_limit);
SearchLimit * const ctrl_break = MakeCatchCTRLBreakLimit(routing.solver());
routing.AddSearchMonitor(ctrl_break);
const Assignment* solution = routing.Solve(initial_sol);// if initial_sol == NULL, solves from scratch
// INSPECT SOLUTION
if (solution != NULL) {
CVRPSolution cvrp_sol(data, &routing, solution);
cvrp_sol.SetName(StrCat("Solution for instance ", data.Name(), " computed by vrp.cc"));
// test solution
if (!cvrp_sol.IsFeasibleSolution()) {
LOG(ERROR) << "Solution is NOT feasible!";
} else {
LG << "Solution is feasible and has an obj value of " << cvrp_sol.ComputeObjectiveValue();
// SAVE SOLUTION IN CVRP FORMAT
if (FLAGS_solution_file != "") {
cvrp_sol.Write(FLAGS_solution_file);
} else {
cvrp_sol.Print(std::cout);
}
}
} else {
LG << "No solution found.";
}
} // void VRPSolver (CVRPData & data)
} // namespace operations_research
int main(int argc, char **argv) {
std::string usage("Computes a simple CVRP.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n");
usage += argv[0];
usage += " -instance_file=<TSPLIB file>\n";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_instance_file == "") {
std::cout << google::ProgramUsage();
exit(-1);
}
operations_research::TSPLIBReader tsplib_reader(FLAGS_instance_file);
operations_research::CVRPData cvrp_data(tsplib_reader);
operations_research::CVRPBasicSolver(cvrp_data);
return 0;
} // main

View File

@@ -0,0 +1,203 @@
// Copyright 2011-2014 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.
//
//
// Common base for (c)vrp data (instance) classes.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_VRP_DATA_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_VRP_DATA_H
#include <ostream>
#include <iomanip>
#include "base/bitmap.h"
#include "base/logging.h"
#include "base/file.h"
#include "base/split.h"
#include "base/filelinereader.h"
#include "base/join.h"
#include "base/strtoint.h"
#include "constraint_solver/routing.h"
#include "routing_common/routing_common.h"
#include "routing_common/routing_data.h"
#include "routing_common/tsplib_reader.h"
#include "routing_common/tsplib.h"
#include "cvrp_data_generator.h"
DECLARE_int32(width_size);
namespace operations_research {
class CVRPData : public RoutingData {
public:
explicit CVRPData(CVRPDataGenerator & g) : RoutingData(g), depot_(g.Depot()), capacity_(g.Capacity()),
demands_(Size()),
node_coord_type_(g.NodeCoordinateType()),
display_data_type_(g.DisplayDataType()),
two_dimension_(g.HasDimensionTwo()),
total_demand_(0){
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
demands_[i.value()] = g.Demand(i);
total_demand_ += g.Demand(i);
}
}
explicit CVRPData(const TSPLIBReader & reader) :
RoutingData(reader),
depot_(reader.Depot()),
capacity_(reader.Capacity()),
demands_(Size()),
node_coord_type_(reader.NodeCoordinateType()),
display_data_type_(reader.DisplayDataType()),
two_dimension_(reader.HasDimensionTwo()),
total_demand_(0) {
CHECK(reader.TSPLIBType() == CVRP);
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
demands_[i.value()] = reader.Demand(i);
total_demand_ += reader.Demand(i);
}
if (node_coord_type_ == TWOD_COORDS || node_coord_type_ == THREED_COORDS) {
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
Coordinate(i) = reader.Coordinate(i);
}
SetHasCoordinates();
}
if (display_data_type_ == TWOD_DISPLAY) {
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
DisplayCoordinate(i) = reader.DisplayCoordinate(i);
}
SetHasDisplayCoordinates();
}
SetRoutingDataInstanciated();
}
void SetDepot(RoutingModel::NodeIndex d) {
CheckNodeIsValid(d);
depot_ = d;
}
RoutingModel::NodeIndex Depot() const {
return depot_;
}
void SetDemand(const RoutingModel::NodeIndex i, int64 demand) {
CheckNodeIsValid(i);
demands_[i.value()] = demand;
}
int64 Demand(const RoutingModel::NodeIndex i) const {
CheckNodeIsValid(i);
return demands_[i.value()];
}
int64 TotalDemand() const {
return total_demand_;
}
void PrintTSPLIBInstance(std::ostream & out) const;
void WriteTSPLIBInstance(const std::string & filename) const {
WriteToFile<CVRPData> writer(this, filename);
writer.SetMember(&operations_research::CVRPData::PrintTSPLIBInstance);
writer.Run();
}
void SetCapacity(int64 capacity) {
capacity_ = capacity;
}
int64 Capacity() const {
return capacity_;
}
// Helper function
int64& SetDistance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) {
return distances_.Cost(i, j);
}
private:
RoutingModel::NodeIndex depot_;
std::vector<int64> demands_;
int64 total_demand_;
TSPLIB_NODE_COORD_TYPE_TYPES_enum node_coord_type_;
TSPLIB_DISPLAY_DATA_TYPE_TYPES_enum display_data_type_;
bool two_dimension_;
int64 capacity_;
};
void CVRPData::PrintTSPLIBInstance(std::ostream& out) const {
out << TSPLIB_STATES_KEYWORDS[NAME] << " : " << Name() << std::endl;
out << TSPLIB_STATES_KEYWORDS[COMMENT] << " : " << Comment() << std::endl;
out << TSPLIB_STATES_KEYWORDS[TYPE] << " : CVRP" << std::endl;
out << TSPLIB_STATES_KEYWORDS[DIMENSION] << " : " << Size() << std::endl;
out << TSPLIB_STATES_KEYWORDS[EDGE_WEIGHT_TYPE] << " : " << "EXPLICIT" << std::endl;
out << TSPLIB_STATES_KEYWORDS[EDGE_WEIGHT_FORMAT] << " : " << "FULL_MATRIX" << std::endl;
if (HasCoordinates()) {
out << TSPLIB_STATES_KEYWORDS[NODE_COORD_TYPE] << " : " << TSPLIB_NODE_COORD_TYPE_TYPES_KEYWORDS[node_coord_type_] << std::endl;
}
if (HasDisplayCoordinates()) {
out << TSPLIB_STATES_KEYWORDS[DISPLAY_DATA_TYPE] << " : " << TSPLIB_DISPLAY_DATA_TYPE_TYPES_KEYWORDS[display_data_type_] << std::endl;
}
if (Depot() != RoutingModel::kFirstNode) {
out << TSPLIB_STATES_KEYWORDS[DEPOT_SECTION] << std::endl;
out << Depot().value() + 1 << std::endl;
out << kTSPLIBDelimiter << std::endl;
}
out << TSPLIB_STATES_KEYWORDS[EDGE_WEIGHT_SECTION] << std::endl;
distances_.Print(out);
if (HasCoordinates()) {
out << TSPLIB_STATES_KEYWORDS[NODE_COORD_SECTION] << std::endl;
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
out.width(FLAGS_width_size);
out << std::right << i.value() + 1;
out.width(FLAGS_width_size);
out << std::right << Coordinate(i).x;
out.width(FLAGS_width_size);
out << std::right << Coordinate(i).y;
if (!two_dimension_) { // 3D
out.width(FLAGS_width_size);
out << std::right << Coordinate(i).z;
}
out << std::endl;
}
}
if (HasDisplayCoordinates()) {
out << TSPLIB_STATES_KEYWORDS[DISPLAY_DATA_SECTION] << std::endl;
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
out.width(FLAGS_width_size);
out << std::right << i.value() + 1;
out.width(FLAGS_width_size + 4);
out << std::setprecision(2) << std::fixed << std::right << DisplayCoordinate(i).x;
out.width(FLAGS_width_size + 4);
out << std::right << DisplayCoordinate(i).y << std::endl;
}
}
out << TSPLIB_STATES_KEYWORDS[DEMAND_SECTION] << std::endl;
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
out.width(FLAGS_width_size);
out << std::right << i.value() + 1;
out.width(FLAGS_width_size);
out << std::right << Demand(i) << std::endl;
}
out << kTSPLIBEndFileDelimiter << std::endl;
}
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_VRP_DATA_H

View File

@@ -0,0 +1,48 @@
// Copyright 2011-2014 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.
//
//
// Simple CVRP instance generator.
#include "base/commandlineflags.h"
#include "cvrp_data_generator.h"
#include "cvrp_data.h"
DEFINE_int32(depot, 1, "Depot of the CVRP instance. Must be greater of equal to 1.");
int main(int argc, char **argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
google::SetUsageMessage(operations_research::GeneratorUsage(argv[0], "CVRP"));
if (FLAGS_instance_name != "" && FLAGS_instance_size > 2) {
operations_research::CVRPDataGenerator cvrp_data_generator(FLAGS_instance_name, FLAGS_instance_size);
CHECK_GE(FLAGS_depot, 1) << "Because we use the TSPLIB format, the depot must be greater or equal to 1.";
CHECK_LE(FLAGS_depot, FLAGS_instance_size) << "The depot must be in range 1-" << FLAGS_instance_size << ".";
cvrp_data_generator.SetDepot(operations_research::RoutingModel::NodeIndex(FLAGS_depot - 1));
operations_research::CVRPData cvrp_data(cvrp_data_generator);
if (FLAGS_distance_file != "") {
cvrp_data.WriteDistanceMatrix(FLAGS_distance_file);
}
if (FLAGS_instance_file == "") {
cvrp_data.PrintTSPLIBInstance(std::cout);
} else {
cvrp_data.WriteTSPLIBInstance(FLAGS_instance_file);
}
} else {
std::cout << google::ProgramUsage();
exit(-1);
}
return 0;
}

View File

@@ -0,0 +1,147 @@
// Copyright 2011-2014 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.
//
//
// Very basic CVRPDataGenerator class.
//
// The demands are created by constructing a feasible solution.
// The capacity if FULLY used on each route. i.e. the sum of all demands
// along a route is equal to FLAGS_capacity.
// A node can have a zero capacity. If you want to force each node to
// have a capacity of at least 1, set FLAGS_allow_zero_capacity to false.
//
// We don't consider min and max capacities.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_CVRP_GENERATOR_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_CVRP_GENERATOR_H
#include "base/commandlineflags.h"
#include "routing_common/routing_data_generator.h"
#include "routing_common/tsplib.h"
DEFINE_int32(number_vehicles, 2, "Number of vehicles.");
DEFINE_int64(capacity, 100, "Capacity of all vehicles.");
DEFINE_bool(allow_zero_capacity, true, "Allow node with zero capacity?");
namespace operations_research {
class CVRPDataGenerator : public RoutingDataGenerator {
public:
CVRPDataGenerator(std::string instance_name, int32 size, std::string problem_name = "CVRP") : RoutingDataGenerator(problem_name, instance_name, size),
comment_("Generated by VRPDataGenerator."), capacity_corrector_(FLAGS_allow_zero_capacity ? 0 : 1), capacity_(FLAGS_capacity) {
CreateFeasibleSolution();
}
std::string Comment() const {
return comment_;
}
void SetComment(const std::string comment) {
comment_ = comment;
}
RoutingModel::NodeIndex Depot() const {
return depot_;
}
void SetDepot(const RoutingModel::NodeIndex d) {
depot_ = d;
}
int64 Capacity() const {
return capacity_;
}
int64 Demand(const RoutingModel::NodeIndex i) const {
return demands_[i.value()];
}
TSPLIB_NODE_COORD_TYPE_TYPES_enum NodeCoordinateType() const {
return TWOD_COORDS;
}
TSPLIB_DISPLAY_DATA_TYPE_TYPES_enum DisplayDataType() const {
return COORD_DISPLAY;
}
bool HasDimensionTwo() const {
return true;
}
private:
void CreateFeasibleSolution() {
// first: shuffle nodes
std::vector<RoutingModel::NodeIndex> nodes(Size());
for (RoutingModel::NodeIndex i(0); i < Size(); ++i) {
nodes[i.value()] = i;
}
// 0 must be the depot
std::random_shuffle(nodes.begin() + 1, nodes.end(), randomizer_);
// second: distribute nodes into routes of random length
sol_.resize(Size());
int number_of_nodes = 0;
int total_number_of_used_nodes = 0;
VLOG(1) << "Optimal solution used:\n";
for (int i = 0; i < FLAGS_number_vehicles; ++i) {
if (i == FLAGS_number_vehicles - 1) { // add the rest
number_of_nodes = Size() - 1 - total_number_of_used_nodes;
} else { // add random number of nodes
number_of_nodes = randomizer_.Uniform(Size() - 1 - total_number_of_used_nodes - FLAGS_number_vehicles + i) + 1;
}
sol_[i].resize(number_of_nodes);
VLOG(1) << "Vehicle: " << i;
for (int j = 0; j < number_of_nodes; ++j) {
sol_[i][j] = nodes[total_number_of_used_nodes + j + 1];
VLOG(1) << sol_[i][j] << " - ";
}
VLOG(1) << std::endl;
total_number_of_used_nodes += number_of_nodes;
}
// third: allocate the capacity for each route
demands_.resize(Size());
demands_[0] = 0;
int64 total_capacity_used = 0;
int64 total_nodes_with_capacity = 0;
int64 capacity = 0;
for (int i = 0; i < FLAGS_number_vehicles; ++i) {
number_of_nodes = sol_[i].size();
total_capacity_used = 0;
for (int j = 0; j < number_of_nodes; ++j) {
if (j == number_of_nodes - 1) { // add the rest
++total_nodes_with_capacity;
capacity = FLAGS_capacity - total_capacity_used;
} else { // add random capacity
++total_nodes_with_capacity;
capacity = randomizer_.Uniform(FLAGS_capacity - total_capacity_used - number_of_nodes + j - capacity_corrector_
- capacity_corrector_ * (Size() - total_nodes_with_capacity)) + capacity_corrector_;
}
demands_[sol_[i][j].value()] = capacity;
total_capacity_used += capacity;
}
}
}
std::string comment_;
RoutingModel::NodeIndex depot_;
std::vector<std::vector<RoutingModel::NodeIndex> > sol_;
std::vector<int64> demands_;
const int64 capacity_;
const int capacity_corrector_;
};
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_CVRP_GENERATOR_H

View File

@@ -0,0 +1,130 @@
// Copyright 2011-2014 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.
//
//
// Common base to use the epix library to visualize
// CVRP data (instance) and solutions.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_CVRP_EPIX_DATA_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_CVRP_EPIX_DATA_H
#include <string>
#include "routing_common/routing_common.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/routing_epix_helper.h"
namespace operations_research {
class CVRPEpixData {
public:
explicit CVRPEpixData(const CVRPData & data): data_(data) {}
void PrintInstance(std::ostream & out) const;
void WriteInstance(const std::string & filename) const;
void PrintSolution(std::ostream & out, const CVRPSolution & sol) const;
void WriteSolution(const std::string & filename, const CVRPSolution & sol) const;
private:
const CVRPData & data_;
};
void CVRPEpixData::PrintInstance(std::ostream& out) const {
CHECK(data_.HasCoordinates());
PrintEpixBeginFile(out);
PrintEpixPreamble(out);
PrintEpixBoundingBox(out, data_.RawBoundingBox());
PrintEpixNewLine(out);
PrintEpixComment(out, "Points:");
for (RoutingModel::NodeIndex i(0); i < data_.Size(); ++i) {
Point p = data_.Coordinate(i);
PrintEpixPoint(out, p, i);
}
PrintEpixBeginFigure(out);
PrintEpixDrawMultiplePoints(out, data_.Size());
PrintEpixDepot(out, data_.Depot());
PrintEpixEndFigure(out);
PrintEpixEndFile(out);
}
void CVRPEpixData::WriteInstance(const std::string& filename) const {
WriteToFile<CVRPEpixData> writer(this, filename);
writer.SetMember(&operations_research::CVRPEpixData::PrintInstance);
writer.Run();
}
void CVRPEpixData::PrintSolution(std::ostream& out, const operations_research::CVRPSolution& sol) const {
CHECK(data_.HasCoordinates());
PrintEpixBeginFile(out);
PrintEpixPreamble(out);
PrintEpixBoundingBox(out, data_.RawBoundingBox());
PrintEpixNewLine(out);
PrintEpixComment(out, "Points:");
for (RoutingModel::NodeIndex i(0); i < data_.Size(); ++i) {
Point p = data_.Coordinate(i);
PrintEpixPoint(out, p, i);
}
PrintEpixComment(out, "Edges:");
RoutingModel::NodeIndex from_node, to_node;
RoutingModel::NodeIndex depot = data_.Depot();
int segment_nbr = 0;
for (CVRPSolution::const_vehicle_iterator v_iter = sol.vehicle_begin(); v_iter != sol.vehicle_end(); ++v_iter) {
from_node = depot;
for (CVRPSolution::const_node_iterator n_iter = sol.node_begin(v_iter); n_iter != sol.node_end(v_iter); ++n_iter ) {
to_node = *n_iter;
PrintEpixSegment(out, segment_nbr, from_node, to_node);
from_node = to_node;
++segment_nbr;
}
// Last arc
PrintEpixSegment(out, segment_nbr, from_node, depot);
++segment_nbr;
}
PrintEpixNewLine(out);
PrintEpixBeginFigure(out);
PrintEpixDrawMultipleSegments(out, segment_nbr);
PrintEpixRaw(out, " fill(White());");
PrintEpixDrawMultiplePoints(out, data_.Size());
PrintEpixDepot(out, data_.Depot());
PrintEpixEndFigure(out);
PrintEpixEndFile(out);
}
void CVRPEpixData::WriteSolution(const std::string& filename, const operations_research::CVRPSolution& sol) const {
WriteToFileP1<CVRPEpixData, CVRPSolution> writer(this, filename);
writer.SetMember(&operations_research::CVRPEpixData::PrintSolution);
writer.Run(sol);
}
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_CVRP_EPIX_DATA_H

View File

@@ -0,0 +1,279 @@
// Copyright 2011-2014 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.
//
//
// Common base for TSPTW solutions.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_CVRP_SOLUTION_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_CVRP_SOLUTION_H
#include <vector>
#include "constraint_solver/routing.h"
#include "base/split.h"
#include "base/filelinereader.h"
#include "base/join.h"
#include "base/bitmap.h"
#include "routing_common/routing_solution.h"
#include "cvrp_data.h"
DEFINE_bool(numbering_solution_nodes_from_zero, true, "Number the nodes in the solution starting from 0?");
namespace operations_research {
class CVRPSolution : public RoutingSolution {
public:
typedef std::vector<std::vector<RoutingModel::NodeIndex> >::iterator vehicle_iterator;
typedef std::vector<std::vector<RoutingModel::NodeIndex> >::const_iterator const_vehicle_iterator;
typedef std::vector<RoutingModel::NodeIndex>::iterator node_iterator;
typedef std::vector<RoutingModel::NodeIndex>::const_iterator const_node_iterator;
CVRPSolution(const CVRPData & data, std::string filename): RoutingSolution(data), data_(data), depot_(data.Depot()),
loaded_solution_obj_(-1) {
LoadInstance(filename);
}
// We could have used RoutingModel::AssignmentToRoutes()
CVRPSolution(const CVRPData & data, const RoutingModel * const routing, const Assignment * const sol): RoutingSolution(data), data_(data),
depot_(data.Depot()), loaded_solution_obj_(-1) {
CHECK_NOTNULL(routing);
CHECK_NOTNULL(sol);
depot_ = routing->IndexToNode(routing->GetDepot());
for (int32 vehicle = 0; vehicle < routing->vehicles(); ++vehicle) {
int64 start_node = routing->Start(vehicle);
// first node after depot
int64 node = sol->Value(routing->NextVar(start_node));
for (; !routing->IsEnd(node);
node = sol->Value(routing->NextVar(node))) {
RoutingModel::NodeIndex node_id = routing->IndexToNode(node);
Add(node_id,vehicle);
}
}
}
virtual ~CVRPSolution() {}
RoutingModel::NodeIndex Depot() const {
return depot_;
}
std::string Name() const {
return name_;
}
void SetName(const std::string & name) {
name_ = name;
}
// We only consider complete solutions.
virtual void LoadInstance(std::string filename);
virtual bool IsSolution() const;
virtual bool IsFeasibleSolution() const;
virtual int64 ComputeObjectiveValue() const;
int NumberOfVehicles() const {
return number_of_vehicles_;
}
virtual bool Add(RoutingModel::NodeIndex i, int route_number) {
if (sol_.size() == route_number) {
std::vector<RoutingModel::NodeIndex> v;
sol_.push_back(v);
}
sol_[route_number].push_back(i);
return true;
}
void WriteAssignment(const RoutingModel * routing, Assignment * const sol) {
CHECK_NOTNULL(routing);
CHECK_NOTNULL(sol);
routing->RoutesToAssignment(sol_,
true,
true,
sol);
}
std::vector<std::vector<RoutingModel::NodeIndex> > const & Routes() const {
return sol_;
}
//iterators
vehicle_iterator vehicle_begin() { return sol_.begin(); }
const_vehicle_iterator vehicle_begin() const { return sol_.begin(); }
vehicle_iterator vehicle_end() { return sol_.end(); }
const_vehicle_iterator vehicle_end() const { return sol_.end(); }
node_iterator node_begin(vehicle_iterator v_iter) {return v_iter->begin();}
const_node_iterator node_begin(const_vehicle_iterator v_iter) const {return v_iter->begin();}
node_iterator node_end(vehicle_iterator v_iter) {return v_iter->end();}
const_node_iterator node_end(const_vehicle_iterator v_iter) const {return v_iter->end();}
virtual void Print(std::ostream & out) const;
virtual void Write(const std::string & filename) const ;
protected:
std::vector<std::vector<RoutingModel::NodeIndex> > sol_;
std::vector<int64> capacities_;
private:
const CVRPData & data_;
RoutingModel::NodeIndex depot_;
int line_number_;
void ProcessNewLine(char* const line);
void InitLoadInstance() {
line_number_ = 0;
number_of_vehicles_ = 0;
sol_.clear();
name_ = "";
comment_ = "";
}
std::string name_;
std::string comment_;
int64 loaded_solution_obj_;
int number_of_vehicles_;
};
void CVRPSolution::LoadInstance(std::string filename) {
InitLoadInstance();
FileLineReader reader(filename.c_str());
reader.set_line_callback(NewPermanentCallback(
this,
&CVRPSolution::ProcessNewLine));
reader.Reload();
if (!reader.loaded_successfully()) {
LOG(FATAL) << "Could not open TSPTW solution file: " << filename;
}
}
// Test if all nodes are serviced once and only once
bool CVRPSolution::IsSolution() const {
// Test if same number of nodes
if (data_.Size() != Size()) {
return false;
}
// Test if all nodes are used
Bitmap used(Size());
for (int i = 0; i < sol_.size(); ++i) {
for (int j = 0; j < sol_[i].size(); ++j) {
int index = sol_[i][j].value();
if (used.Get(index)) {
LG << "already used index = " << index;
return false;
} else {
used.Set(index,true);
}
}
}
// Test if depot was not used in the solution
return !used.Get(depot_.value());
}
// Test if capacities are respected.
bool CVRPSolution::IsFeasibleSolution() const {
if (!IsSolution()) {
return false;
}
const int64 vehicle_capacity = data_.Capacity();
RoutingModel::NodeIndex node;
int64 route_capacity_left = vehicle_capacity;
int vehicle_index = 1;
for (const_vehicle_iterator v_iter = vehicle_begin(); v_iter != vehicle_end(); ++v_iter) {
route_capacity_left = vehicle_capacity;
VLOG(1) << "Route " << vehicle_index << " with capacity " << route_capacity_left;
for (const_node_iterator n_iter = node_begin(v_iter); n_iter != node_end(v_iter); ++n_iter ) {
node = *n_iter;
route_capacity_left -= data_.Demand(node);
VLOG(1) << "Servicing node " << node.value() + 1 << " with demand " << data_.Demand(node) << " (capacity left: " << route_capacity_left << ")";
if (route_capacity_left < 0) {
return false;
}
}
++vehicle_index;
}
return true;
}
int64 CVRPSolution::ComputeObjectiveValue() const {
int64 obj = 0;
RoutingModel::NodeIndex from_node, to_node;
for (const_vehicle_iterator v_iter = vehicle_begin(); v_iter != vehicle_end(); ++v_iter) {
from_node = depot_;
for (const_node_iterator n_iter = node_begin(v_iter); n_iter != node_end(v_iter); ++n_iter ) {
to_node = *n_iter;
obj += data_.Distance(from_node, to_node);
from_node = to_node;
}
// Last arc
obj += data_.Distance(to_node, depot_);
}
return obj;
}
void CVRPSolution::Print(std::ostream& out) const {
int32 vehicle_index = 0;
for (const_vehicle_iterator v_iter = vehicle_begin(); v_iter != vehicle_end(); ++v_iter) {
out << "Route " << StrCat("#", vehicle_index + 1, ":");
for (const_node_iterator n_iter = node_begin(v_iter); n_iter != node_end(v_iter); ++n_iter ) {
out << " " << (*n_iter).value() + (FLAGS_numbering_solution_nodes_from_zero? 0 : 1);
}
out << std::endl;
++vehicle_index;
}
out << "cost " << ComputeObjectiveValue() << std::endl;
}
void CVRPSolution::Write(const std::string & filename) const {
WriteToFile<CVRPSolution> writer(this, filename);
writer.SetMember(&operations_research::CVRPSolution::Print);
writer.Run();
}
void CVRPSolution::ProcessNewLine(char*const line) {
++line_number_;
static const char kWordDelimiters[] = " #:";
std::vector<std::string> words;
words = strings::Split(line, kWordDelimiters, strings::SkipEmpty());
if (words[0] == "Route") {
const int number_of_served_nodes = words.size() - 2;
CHECK_GE(number_of_served_nodes, 1);
for (int node = 0; node < number_of_served_nodes; ++node) {
int32 node_id = atoi32(words[node + 2]) + (FLAGS_numbering_solution_nodes_from_zero? 0 : -1);
CHECK_LE(node_id, size_) << "Node " << node_id << " is greater than size " << size_ << " of solution.";
Add(RoutingModel::NodeIndex(node_id ), number_of_vehicles_);
}
++number_of_vehicles_;
return;
}
if (words[0] == "cost") {
CHECK_EQ(words.size(), 2) << "Only objective value allowed on cost line of CVRP solution file at line " << line_number_;
loaded_solution_obj_ = atoi64(words[1]);
return;
}
LOG(FATAL) << "Unrecognized line in CVRP solution file at line: " << line_number_;
} // void ProcessNewLine(char* const line)
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_CVRP_SOLUTION_H

View File

@@ -0,0 +1,56 @@
// Copyright 2011-2014 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.
//
//
// Simple program to visualize a CVRP solution.
#include <iostream>
#include "base/commandlineflags.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/tsplib_reader.h"
#include "cvrp_epix_data.h"
int main(int argc, char **argv) {
std::string usage("Prints a CVRP solution in ePiX format.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n");
usage += argv[0];
usage += " -instance_file=<TSPLIB file> -solution_file=<CVRP solution> > epix_file.xp\n\n";
usage += " ./elaps -pdf epix_file.xp\n";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_instance_file != "" && FLAGS_solution_file != "") {
operations_research::TSPLIBReader tsplib_reader(FLAGS_instance_file);
operations_research::CVRPData cvrp_data(tsplib_reader);
operations_research::CVRPSolution cvrp_sol(cvrp_data, FLAGS_solution_file);
if (cvrp_sol.IsFeasibleSolution()) {
if (cvrp_data.IsVisualizable()) {
operations_research::CVRPEpixData epix_data(cvrp_data);
epix_data.PrintSolution(std::cout, cvrp_sol);
} else {
LG << "Solution is not visualizable!";
}
} else {
LG << "Solution is NOT feasible...";
}
} else {
std::cout << google::ProgramUsage();
exit(-1);
}
return 0;
}

View File

@@ -0,0 +1,6 @@
Route #1: 21 31 19 17 13 7 26
Route #2: 12 1 16 30
Route #3: 27 24
Route #4: 29 18 8 9 22 15 10 25 5 20
Route #5: 14 28 11 4 23 3 2 6
cost 784

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,193 @@
#include "epix.h"
using namespace ePiX;
int main(int argc, char **argv)
{
unitlength("1cm");
picture(10,10);
double radius = 0.3;
font_size("tiny");
bounding_box(P(-1,-1), P(98,97));
// Points:
P P0(82,76);
Circle C0(P0, radius);
P P1(96,44);
Circle C1(P1, radius);
P P2(50,5);
Circle C2(P2, radius);
P P3(49,8);
Circle C3(P3, radius);
P P4(13,7);
Circle C4(P4, radius);
P P5(29,89);
Circle C5(P5, radius);
P P6(58,30);
Circle C6(P6, radius);
P P7(84,39);
Circle C7(P7, radius);
P P8(14,24);
Circle C8(P8, radius);
P P9(2,39);
Circle C9(P9, radius);
P P10(3,82);
Circle C10(P10, radius);
P P11(5,10);
Circle C11(P11, radius);
P P12(98,52);
Circle C12(P12, radius);
P P13(84,25);
Circle C13(P13, radius);
P P14(61,59);
Circle C14(P14, radius);
P P15(1,65);
Circle C15(P15, radius);
P P16(88,51);
Circle C16(P16, radius);
P P17(91,2);
Circle C17(P17, radius);
P P18(19,32);
Circle C18(P18, radius);
P P19(93,3);
Circle C19(P19, radius);
P P20(50,93);
Circle C20(P20, radius);
P P21(98,14);
Circle C21(P21, radius);
P P22(5,42);
Circle C22(P22, radius);
P P23(42,9);
Circle C23(P23, radius);
P P24(61,62);
Circle C24(P24, radius);
P P25(9,97);
Circle C25(P25, radius);
P P26(80,55);
Circle C26(P26, radius);
P P27(57,69);
Circle C27(P27, radius);
P P28(23,15);
Circle C28(P28, radius);
P P29(20,70);
Circle C29(P29, radius);
P P30(85,60);
Circle C30(P30, radius);
P P31(98,5);
Circle C31(P31, radius);
// Edges:
Segment L0(P0,P21);
Segment L1(P21,P31);
Segment L2(P31,P19);
Segment L3(P19,P17);
Segment L4(P17,P13);
Segment L5(P13,P7);
Segment L6(P7,P26);
Segment L7(P26,P0);
Segment L8(P0,P12);
Segment L9(P12,P1);
Segment L10(P1,P16);
Segment L11(P16,P30);
Segment L12(P30,P0);
Segment L13(P0,P27);
Segment L14(P27,P24);
Segment L15(P24,P0);
Segment L16(P0,P29);
Segment L17(P29,P18);
Segment L18(P18,P8);
Segment L19(P8,P9);
Segment L20(P9,P22);
Segment L21(P22,P15);
Segment L22(P15,P10);
Segment L23(P10,P25);
Segment L24(P25,P5);
Segment L25(P5,P20);
Segment L26(P20,P0);
Segment L27(P0,P14);
Segment L28(P14,P28);
Segment L29(P28,P11);
Segment L30(P11,P4);
Segment L31(P4,P23);
Segment L32(P23,P3);
Segment L33(P3,P2);
Segment L34(P2,P6);
Segment L35(P6,P0);
begin(); // ---- Figure body starts here ----
L0.draw();
L1.draw();
L2.draw();
L3.draw();
L4.draw();
L5.draw();
L6.draw();
L7.draw();
L8.draw();
L9.draw();
L10.draw();
L11.draw();
L12.draw();
L13.draw();
L14.draw();
L15.draw();
L16.draw();
L17.draw();
L18.draw();
L19.draw();
L20.draw();
L21.draw();
L22.draw();
L23.draw();
L24.draw();
L25.draw();
L26.draw();
L27.draw();
L28.draw();
L29.draw();
L30.draw();
L31.draw();
L32.draw();
L33.draw();
L34.draw();
L35.draw();
fill(White());
C0.draw();
C1.draw();
C2.draw();
C3.draw();
C4.draw();
C5.draw();
C6.draw();
C7.draw();
C8.draw();
C9.draw();
C10.draw();
C11.draw();
C12.draw();
C13.draw();
C14.draw();
C15.draw();
C16.draw();
C17.draw();
C18.draw();
C19.draw();
C20.draw();
C21.draw();
C22.draw();
C23.draw();
C24.draw();
C25.draw();
C26.draw();
C27.draw();
C28.draw();
C29.draw();
C30.draw();
C31.draw();
fill(Red());
C0.draw();
fill(White());
end(); // ---- End figure; write output file ----
}

View File

@@ -0,0 +1,124 @@
// Copyright 2011-2014 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.
//
//
// Simple program to solve the VRP with Local Search in or-tools.
#include <string>
#include <fstream>
#include "base/commandlineflags.h"
#include "constraint_solver/routing.h"
#include "base/join.h"
#include "base/timer.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/tsplib_reader.h"
DEFINE_int32(depot, 1, "The starting node of the tour.");
DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms.");
namespace operations_research {
void VRPSolver (const CVRPData & data) {
const int size = data.Size();
RoutingModel routing(size, FLAGS_number_vehicles);
routing.SetCost(NewPermanentCallback(&data, &CVRPData::Distance));
// Disabling Large Neighborhood Search, comment out to activate it.
//routing.SetCommandLineOption("routing_no_lns", "true");
if (FLAGS_time_limit_in_ms > 0) {
routing.UpdateTimeLimit(FLAGS_time_limit_in_ms);
}
// Setting depot
CHECK_GT(FLAGS_depot, 0) << " Because we use the" << " TSPLIB convention, the depot id must be > 0";
RoutingModel::NodeIndex depot(FLAGS_depot -1);
routing.SetDepot(depot);
routing.CloseModel();
// Forbidding empty routes
for (int vehicle_nbr = 0; vehicle_nbr < FLAGS_number_vehicles; ++vehicle_nbr) {
IntVar* const start_var = routing.NextVar(routing.Start(vehicle_nbr));
for (int64 node_index = routing.Size(); node_index < routing.Size() + routing.vehicles(); ++node_index) {
start_var->RemoveValue(node_index);
}
}
// SOLVE
const Assignment* solution = routing.Solve();
// INSPECT SOLUTION
if (solution != NULL) {
CVRPSolution cvrp_sol(data, &routing, solution);
cvrp_sol.SetName(StrCat("Solution for instance ", data.Name(), " computed by vrp.cc"));
// test solution
if (!cvrp_sol.IsSolution()) {
LOG(ERROR) << "Solution is NOT feasible!";
} else {
LG << "Solution is feasible and has an obj value of " << cvrp_sol.ComputeObjectiveValue();
// SAVE SOLUTION IN CVRP FORMAT
if (FLAGS_solution_file != "") {
cvrp_sol.Write(FLAGS_solution_file);
}
}
// Solution cost.
LG << "Obj value: " << solution->ObjectiveValue();
// Inspect solution.
std::string route;
for (int vehicle_nbr = 0; vehicle_nbr < FLAGS_number_vehicles; ++vehicle_nbr) {
route = "";
for (int64 node = routing.Start(vehicle_nbr); !routing.IsEnd(node);
node = solution->Value(routing.NextVar(node))) {
route = StrCat(route, StrCat(routing.IndexToNode(node).value() + 1 , " -> "));
}
route = StrCat(route, routing.IndexToNode(routing.End(vehicle_nbr)).value() + 1 );
LG << "Route #" << vehicle_nbr + 1 << std::endl << route << std::endl;
}
} else {
LG << "No solution found.";
}
} // void VRPSolver (CVRPData & data)
} // namespace operations_research
int main(int argc, char **argv) {
std::string usage("Computes a simple VRP.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n");
usage += argv[0];
usage += " -instance_file=<TSPLIB file>";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_instance_file == "") {
std::cout << google::ProgramUsage();
exit(-1);
}
operations_research::TSPLIBReader tsplib_reader(FLAGS_instance_file);
operations_research::CVRPData cvrp_data(tsplib_reader);
operations_research::VRPSolver(cvrp_data);
return 0;
} // main

View File

@@ -0,0 +1,56 @@
// Copyright 2011-2014 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.
//
//
// Simple program to visualize a VRP solution.
#include <iostream>
#include "base/commandlineflags.h"
#include "cvrp_data.h"
#include "cvrp_solution.h"
#include "routing_common/tsplib_reader.h"
#include "cvrp_epix_data.h"
int main(int argc, char **argv) {
std::string usage("Prints a CVRP solution in ePiX format.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n");
usage += argv[0];
usage += " -instance_file=<TSPLIB file> -solution_file=<CVRP solution> > epix_file.xp\n\n";
usage += " ./elaps -pdf epix_file.xp\n";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_instance_file != "" && FLAGS_solution_file != "") {
operations_research::TSPLIBReader tsplib_reader(FLAGS_instance_file);
operations_research::CVRPData cvrp_data(tsplib_reader);
operations_research::CVRPSolution cvrp_sol(cvrp_data, FLAGS_solution_file);
if (cvrp_sol.IsSolution()) {
if (cvrp_data.IsVisualizable()) {
operations_research::CVRPEpixData epix_data(cvrp_data);
epix_data.PrintSolution(std::cout, cvrp_sol);
} else {
LG << "Solution is not visualizable!";
}
} else {
LG << "Solution is NOT feasible...";
}
} else {
std::cout << google::ProgramUsage();
exit(-1);
}
return 0;
}

View File

@@ -0,0 +1,26 @@
OR_TOOLS_TOP=/home/nikolaj/Documents/WORK/Google/or-tools-read-only
OR_TOOLS_SOURCES=$(OR_TOOLS_TOP)/src
TUTORIAL=/home/nikolaj/Documents/WORK/Google/OR_TOOLS_DOC/SOURCES/TUTORIALS/cplusplus
SOURCES= rl_auxiliary_graph
OBJECTS=$(SOURCES:.cc=.o)
EXE=$(SOURCES:.cc=)
include $(OR_TOOLS_TOP)/Makefile
.PHONY: all local_clean
all: $(EXE)
rl_auxiliary_graph.o: rl_auxiliary_graph.cc $(OR_TOOLS_SOURCES)/constraint_solver/routing.h
$(CCC) $(CFLAGS) -c rl_auxiliary_graph.cc -o rl_auxiliary_graph.o
rl_auxiliary_graph: $(ROUTING_DEPS) rl_auxiliary_graph.o
$(CCC) $(CFLAGS) rl_auxiliary_graph.o $(DYNAMIC_ROUTING_LNK) $(DYNAMIC_LD_FLAGS) -o rl_auxiliary_graph
local_clean:
rm $(OBJECTS) $(EXE)

View File

@@ -0,0 +1,87 @@
// Copyright 2011-2014 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.
//
#include <vector>
#include <utility>
#include "base/commandlineflags.h"
#include "constraint_solver/routing.h"
#include "base/join.h"
namespace operations_research {
// Not very interesting
int64 MyCost(RoutingModel::NodeIndex from, RoutingModel::NodeIndex to) {
return (from + to).value();
}
void VRP_Partial_Routes(void) {
// create multi depots
std::vector<std::pair<RoutingModel::NodeIndex, RoutingModel::NodeIndex> > depots(4);
depots[0] = std::make_pair(1,4);
depots[1] = std::make_pair(3,4);
depots[2] = std::make_pair(3,7);
depots[3] = std::make_pair(4,7);
RoutingModel VRP(9, 4, depots);
VRP.SetCost(NewPermanentCallback(MyCost));
// Constructing routes
std::vector<std::vector<RoutingModel::NodeIndex> > routes(4);
// Constructing route 0 : 1 - 0 - 2 - 4
routes[0].push_back(RoutingModel::NodeIndex(0));
routes[0].push_back(RoutingModel::NodeIndex(2));
// Constructing route 1 : 3 - 5 - 4
routes[1].push_back(RoutingModel::NodeIndex(5));
// Constructing route 2 : 3 - 6 - 7
routes[2].push_back(RoutingModel::NodeIndex(6));
// Constructing route 3 : 4 - 8 - 7
routes[3].push_back(RoutingModel::NodeIndex(8));
VRP.CloseModel();
if (VRP.ApplyLocksToAllVehicles(routes, true)) {
LG << "Routes successfully locked";
} else {
LG << "Routes not successfully locked";
}
const Assignment* Solution = VRP.Solve();
for (int p = 0; p < VRP.vehicles(); ++p) {
LG << "Route: " << p;
std::string route;
std::string index_route;
for (int64 index = VRP.Start(p); !VRP.IsEnd(index); index = Solution->Value(VRP.NextVar(index))) {
route = StrCat(route, StrCat(VRP.IndexToNode(index).value(), " -> "));
index_route = StrCat(index_route, StrCat(index, " -> "));
}
route = StrCat(route, VRP.IndexToNode(VRP.End(p)).value());
index_route = StrCat(index_route, VRP.End(p));
LG << route;
LG << index_route;
}
} // void VRP_Partial_Routes(void)
} // namespace operations_research
int main(int argc, char **argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
operations_research::VRP_Partial_Routes();
return 0;
} // main

View File

@@ -1,2 +0,0 @@
RESOLVE: SOURCE=/home/nikolaj/Documents/WORK/Google/or-tools-read-only/src BUILD=
/home/nikolaj/Documents/WORK/Google/or-tools-read-only/src

View File

@@ -1,3 +0,0 @@
[Project]
Manager=KDevCustomMakeManager
Name=chap6

View File

@@ -0,0 +1,98 @@
// Copyright 2011-2014 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.
//
//
// Some helpers for Input/Ouput.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_IO_HELPERS_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_IO_HELPERS_H
namespace operations_research {
// Generic class to write an object of class T to a file thanks
// to one of its member with MemberSignature signature.
// We restrict ourself to this signature as all checking are done with
// asserts.
// You must pass a FULLY qualified method name to SetMember()!
template <typename T>
class WriteToFile {
public:
typedef void (T::*MemberSignature)(std::ostream &) const;
WriteToFile(const T * t, const std::string & filename) : t_(t), filename_(filename), member_(NULL) {};
void SetMember(MemberSignature m) {
member_ = m;
}
void Run() {
std::ofstream write_stream(filename_.c_str());
CHECK_EQ(write_stream.is_open(), true) << "Unable to open file: " << filename_;
CHECK_NE(member_, NULL) << "Object method is not set!";
(t_->*member_)(write_stream);
write_stream.close();
}
private:
const T * t_;
const std::string & filename_;
MemberSignature member_;
};
// Same but with an additional parameter.
template <typename T, typename P1>
class WriteToFileP1 {
public:
typedef void (T::*MemberSignature)(std::ostream &, const P1 &) const;
WriteToFileP1(const T * t, const std::string & filename) : t_(t), filename_(filename), member_(NULL) {};
void SetMember(MemberSignature m) {
member_ = m;
}
void Run(const P1 & p) {
std::ofstream write_stream(filename_.c_str());
CHECK_EQ(write_stream.is_open(), true) << "Unable to open file: " << filename_;
CHECK_NE(member_, NULL) << "Object method is not set!";
(t_->*member_)(write_stream, p);
write_stream.close();
}
private:
const T * t_;
const std::string & filename_;
MemberSignature member_;
};
// One entry class to "fatally" log to different std::ostreams if needed.
class FatalInstanceLoadingLog {
public:
FatalInstanceLoadingLog() {}
void AddOutputStream(std::ostream * out) {
streams_.push_back(out);
}
void Write(const char * msg, const std::string & wrong_keyword = "", int line_number = -1) {
std::stringstream line;
line << msg;
if (wrong_keyword != "") {
line << ": \"" << wrong_keyword << "\"";
}
if (line_number != -1) {
line << " on line " << line_number;
}
line << std::endl;
for (int i = 0; i < streams_.size(); ++i) {
(*streams_[i]) << line.str();
}
LOG(FATAL) << msg << ": \"" << wrong_keyword << "\" on line " << line_number;
}
private:
std::vector<std::ostream *> streams_;
};
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_IO_HELPERS_H

View File

@@ -0,0 +1,30 @@
// Copyright 2011-2014 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.
//
//
// Common flags.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_COMMON_FLAGS_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_COMMON_FLAGS_H
#include "base/commandlineflags.h"
#include "common/constants.h"
DEFINE_bool(deterministic_random_seed, true,
"Use deterministic random seeds or not?");
DEFINE_int32(random_generated_graph_max_edges_percent, 80, "Maximal percent of edges allowed for a randomly generated graph.");
DEFINE_bool(print_graph_labels, true, "Print graph labels for nodes?");
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_COMMON_FLAGS_H

View File

@@ -0,0 +1,27 @@
// Copyright 2011-2014 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.
//
//
// Common constants.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_CONSTANTS_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_CONSTANTS_H
namespace operations_research {
const static int64 kPostiveInfinityInt64 = std::numeric_limits<int64>::max();
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_CONSTANTS_H

View File

@@ -0,0 +1,222 @@
// Copyright 2011-2014 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.
//
//
// Common base for custom SearchLimits via callbacks.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_COMMON_LIMITS_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_COMMON_LIMITS_H
#include <ostream>
#include <iomanip>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include "base/bitmap.h"
#include "base/logging.h"
#include "base/file.h"
#include "base/split.h"
#include "base/filelinereader.h"
#include "base/join.h"
#include "base/strtoint.h"
#include "constraint_solver/constraint_solver.h"
namespace operations_research {
namespace {
class LSInitialSolLimit : public ResultCallback<bool> {
public:
LSInitialSolLimit(Solver * solver, int64 global_time_limit,
int solution_nbr_tolerance) :
solver_(solver), global_time_limit_(global_time_limit),
solution_nbr_tolerance_(solution_nbr_tolerance),
time_at_beginning_(solver_->wall_time()),
solutions_at_beginning_(solver_->solutions()),
solutions_since_last_check_(0) {}
// Returns true if limit is reached, false otherwise.
virtual bool Run() {
bool limit_reached = false;
// Test if time limit is reached.
if ((solver_->wall_time() - time_at_beginning_)
> global_time_limit_) {
limit_reached = true;
// Test if we continue despite time limit reached.
if (solver_->solutions() - solutions_since_last_check_
>= solution_nbr_tolerance_) {
// We continue because we produce enough new solutions.
limit_reached = false;
}
}
solutions_since_last_check_ = solver_->solutions();
return limit_reached;
}
private:
Solver * solver_;
int64 global_time_limit_;
int solution_nbr_tolerance_;
int64 time_at_beginning_;
int solutions_at_beginning_;
int solutions_since_last_check_;
};
}
SearchLimit * MakeLSInitialSolLimit(Solver * solver,
int64 global_time_limit,
int solution_nbr_tolerance) {
// By default, the solver takes the ownership of the callback, no need to delete it!
return solver->MakeCustomLimit(new LSInitialSolLimit(solver, global_time_limit, solution_nbr_tolerance));
}
extern "C" {
bool limit_reached = false;
void CTRLBreakHandler(int s) {
LG << "Ctrl-break catched! exit properly..";
limit_reached = true;
}
}
namespace {
class CatchCTRLBreakLimit : public ResultCallback<bool> {
public:
CatchCTRLBreakLimit(Solver * solver) :
solver_(solver) {
sigIntHandler_.sa_handler = CTRLBreakHandler;
sigemptyset(&sigIntHandler_.sa_mask);
sigIntHandler_.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler_, NULL);
}
// Returns true if limit is reached, false otherwise.
virtual bool Run() {
return limit_reached;
}
private:
Solver * solver_;
static bool limit_reached_;
struct sigaction sigIntHandler_;
};
}
SearchLimit * MakeCatchCTRLBreakLimit(Solver * solver) {
return solver->MakeCustomLimit(new CatchCTRLBreakLimit(solver));
}
namespace {
class NoImprovementLimit : public SearchLimit {
public:
NoImprovementLimit(Solver * solver, int solution_nbr_tolerance, bool minimize = true) :
SearchLimit(solver),
solver_(solver), prototype_(new Assignment(solver_)),
solution_nbr_tolerance_(solution_nbr_tolerance),
nbr_solutions_with_no_better_obj_(0),
minimize_(minimize),
limit_reached_(false) {
if (minimize_) {
best_result_ = kint64max;
} else {
best_result_ = kint64min;
}
}
void AddObjective(IntVar* const objective) {
if (prototype_.get() != NULL && objective != NULL) {
prototype_->AddObjective(objective);
}
}
virtual void Init() {
nbr_solutions_with_no_better_obj_ = 0;
limit_reached_ = false;
if (minimize_) {
best_result_ = kint64max;
} else {
best_result_ = kint64min;
}
}
// Returns true if limit is reached, false otherwise.
virtual bool Check() {
return limit_reached_;
}
virtual bool AtSolution() {
++nbr_solutions_with_no_better_obj_;
if (prototype_.get() != NULL) {
prototype_->Store();
const IntVar* objective = prototype_->Objective();
solver_->state();
if (objective != NULL) {
if (minimize_ && objective->Min() < best_result_) {
best_result_ = objective->Min();
nbr_solutions_with_no_better_obj_ = 0;
} else if (!minimize_ && objective->Max() > best_result_) {
best_result_ = objective->Max();
nbr_solutions_with_no_better_obj_ = 0;
}
}
}
if (nbr_solutions_with_no_better_obj_ > solution_nbr_tolerance_) {
limit_reached_ = true;
}
return true;
}
virtual void Copy(const SearchLimit* const limit) {
const NoImprovementLimit* const copy_limit =
reinterpret_cast<const NoImprovementLimit* const>(limit);
int64 best_result_ = copy_limit->best_result_;
int solution_nbr_tolerance_ = copy_limit->solution_nbr_tolerance_;
bool minimize_ = copy_limit->minimize_;
bool limit_reached_ = copy_limit->limit_reached_;
int nbr_solutions_with_no_better_obj_ = copy_limit->nbr_solutions_with_no_better_obj_;
}
// Allocates a clone of the limit
virtual SearchLimit* MakeClone() const {
return solver_->RevAlloc(new NoImprovementLimit(solver_, solution_nbr_tolerance_, minimize_));
}
private:
Solver * solver_;
int64 best_result_;
int solution_nbr_tolerance_;
bool minimize_;
bool limit_reached_;
int nbr_solutions_with_no_better_obj_;
std::unique_ptr<Assignment> prototype_;
};
}
NoImprovementLimit * MakeNoImprovementLimit(Solver * solver, int solution_nbr_tolerance, bool minimize = true) {
return solver->RevAlloc(new NoImprovementLimit(solver, solution_nbr_tolerance, minimize));
}
}
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_COMMON_LIMITS_H

View File

@@ -0,0 +1,39 @@
// Copyright 2011-2014 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.
//
//
// Several helper functions to generate random numbers.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_RANDOM_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_RANDOM_H
#include "base/random.h"
#include "common/constants.h"
#include "common/common_flags.h"
namespace operations_research {
// Random seed generator.
int32 GetSeed() {
if (FLAGS_deterministic_random_seed) {
return ACMRandom::DeterministicSeed();
} else {
return ACMRandom::HostnamePidTimeSeed();
}
}
} // namespace opertional_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_RANDOM_H

View File

@@ -0,0 +1,230 @@
// Copyright 2011-2014 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.
//
//
// Common routing stuff.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_H
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <limits>
#include "base/random.h"
#include "constraint_solver/routing.h"
#include "routing_common/routing_common_flags.h"
#include "common/IO_helpers.h"
#include "common/constants.h"
namespace operations_research {
// Simple struct to contain points in the plane or in the space.
struct Point {
Point(const double x_, const double y_, const double z_ = 0.0):
x(x_), y(y_), z(z_){}
Point(): x(-1.0), y(-1.0), z(-1.0){}
double x;
double y;
double z;
};
// Simple container class to hold cost on arcs of a complete graph.
// This class doesn't compute the distances but only stores them.
// IsCreated(): the cost/distance matrix exists;
// IsInstanciated(): the matrix is filled.
//
// Distances/costs can be symetric or not.
class CompleteGraphArcCost {
public:
explicit CompleteGraphArcCost(int32 size = 0): size_(size), is_created_(false), is_instanciated_(false), is_symmetric_(false),
min_cost_(kPostiveInfinityInt64), max_cost_(-1) {
if (size_ > 0) {
CreateMatrix(size_);
}
}
int32 Size() const {
return size_;
}
void Create(int32 size) {
CHECK(!IsCreated()) << "Matrix already created!";
size_ = size;
CreateMatrix(size);
}
bool IsCreated() const {
return is_created_;
}
bool IsInstanciated() const {
return is_instanciated_;
}
void SetIsInstanciated(const bool instanciated = true) {
CHECK(IsCreated()) << "Instance is not created!";
is_instanciated_ = instanciated;
ComputeExtremeDistance();
ComputeIsSymmetric();
}
int64 Cost(RoutingModel::NodeIndex from,
RoutingModel::NodeIndex to) const {
return matrix_[MatrixIndex(from, to)];
}
int64& Cost(RoutingModel::NodeIndex from,
RoutingModel::NodeIndex to) {
return matrix_[MatrixIndex(from, to)];
}
int64 MaxCost() const {
CHECK(IsInstanciated()) << "Instance is not instanciated!";
return max_cost_;
}
int64 MinCost() const {
CHECK(IsInstanciated()) << "Instance is not instanciated!";
return min_cost_;
}
bool IsSymmetric() const {
CHECK(IsInstanciated()) << "Instance is not instanciated!";
return is_symmetric_;
}
void Print(std::ostream & out, const bool label = false, const int width = FLAGS_width_size) const;
private:
int64 MatrixIndex(RoutingModel::NodeIndex from,
RoutingModel::NodeIndex to) const {
return (from * size_ + to).value();
}
void CreateMatrix(const int size) {
CHECK_GT(size, 2) << "Size for matrix non consistent.";
int64 * p_array = NULL;
try {
p_array = new int64 [size_ * size_];
} catch (std::bad_alloc & e) {
p_array = NULL;
LOG(FATAL) << "Problems allocating ressource. Try with a smaller size.";
}
CHECK_NE(p_array, NULL) << "Not enough resources to create matrix";
matrix_.reset(p_array);
is_created_ = true;
}
void UpdateExtremeDistance(int64 dist) {
if (min_cost_ > dist) { min_cost_ = dist;}
if (max_cost_ < dist) { max_cost_ = dist;}
}
void ComputeExtremeDistance() {
CHECK(IsInstanciated()) << "Instance is not instanciated!";
min_cost_ = kPostiveInfinityInt64;
max_cost_ = -1;
for (RoutingModel::NodeIndex i(0); i < size_; ++i) {
for (RoutingModel::NodeIndex j(0); j < size_; ++j) {
if (i == j) {continue;}
UpdateExtremeDistance(Cost(i,j));
}
}
}
bool ComputeIsSymmetric() {
CHECK(IsInstanciated()) << "Instance is not instanciated!";
for (RoutingModel::NodeIndex i(0); i < Size(); ++i) {
for (RoutingModel::NodeIndex j(i + 1); j < Size(); ++j) {
if (matrix_[MatrixIndex(i,j)] != matrix_[MatrixIndex(j,i)]) {
return false;
}
}
}
return true;
}
int32 size_;
std::unique_ptr<int64[]> matrix_;
bool is_created_;
bool is_instanciated_;
bool is_symmetric_;
int64 min_cost_;
int64 max_cost_;
};
void CompleteGraphArcCost::Print(std::ostream& out, const bool label, const int width) const {
CHECK(IsInstanciated()) << "Instance is not instanciated!";
// titel
out.width(width);
if (label) {
out << std::left << " ";
for (RoutingModel::NodeIndex to = RoutingModel::kFirstNode; to < size_; ++to) {
out.width(width);
out << std::right << to.value() + 1 ;
}
out << std::endl;
}
// fill
for (RoutingModel::NodeIndex from = RoutingModel::kFirstNode; from < size_; ++from) {
if (label) {
out.width(width);
out << std::right << from.value() + 1;
}
for (RoutingModel::NodeIndex to = RoutingModel::kFirstNode; to < size_; ++to) {
out.width(width);
out << std::right << matrix_[MatrixIndex(from, to)];
}
out << std::endl;
}
}
struct BoundingBox {
BoundingBox(): min_x(std::numeric_limits<double>::max()),
max_x(std::numeric_limits<double>::min()),
min_y(std::numeric_limits<double>::max()),
max_y(std::numeric_limits<double>::min()),
min_z(std::numeric_limits<double>::max()),
max_z(std::numeric_limits<double>::min()) {}
BoundingBox(double min_x_, double max_x_, double min_y_, double max_y_, double min_z_, double max_z_):
min_x(min_x_), max_x(max_x_), min_y(min_y_), max_y(max_y_), min_z(min_z_), max_z(max_z_) {}
void Update(Point p) {
if (p.x < min_x) {min_x = p.x;}
if (p.x > max_x) {max_x = p.x;}
if (p.y < min_y) {min_y = p.y;}
if (p.y > max_y) {max_y = p.y;}
if (p.z < min_z) {min_z = p.z;}
if (p.z > max_z) {max_z = p.z;}
}
// Bounding box
double min_x;
double max_x;
double min_y;
double max_y;
double min_z;
double max_z;
};
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_H

View File

@@ -0,0 +1,57 @@
// Copyright 2011-2014 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.
//
//
// Common routing flags.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_FLAGS_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_FLAGS_H
#include "base/commandlineflags.h"
#include "common/constants.h"
DEFINE_int32(instance_size, 10, "Number of nodes, including the depot.");
DEFINE_string(instance_name, "Dummy instance", "Instance name.");
DEFINE_int32(instance_depot, 0, "Depot for instance.");
DEFINE_string(instance_file, "", "TSPLIB instance file.");
DEFINE_string(solution_file, "", "TSPLIB solution file.");
DEFINE_string(distance_file, "", "TSP matrix distance file.");
DEFINE_int32(edge_min, 1, "Minimum edge value.");
DEFINE_int32(edge_max, 100, "Maximum edge value.");
DEFINE_int32(instance_edges_percent, 20, "Percent of edges in the graph.");
DEFINE_int32(x_max, 100, "Maximum x coordinate.");
DEFINE_int32(y_max, 100, "Maximum y coordinate.");
DEFINE_int32(width_size, 6, "Width size of fields in output.");
DEFINE_int32(epix_width, 10, "Width of the pictures in cm.");
DEFINE_int32(epix_height, 10, "Height of the pictures in cm.");
DEFINE_double(epix_radius, 0.3, "Radius of circles.");
DEFINE_bool(epix_node_labels, false, "Print node labels?");
DEFINE_int32(percentage_forbidden_arcs_max, 94, "Maximum percentage of arcs to forbid.");
DEFINE_int64(M, operations_research::kPostiveInfinityInt64, "Big m value to represent infinity.");
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_FLAGS_H

View File

@@ -0,0 +1,228 @@
// Copyright 2011-2014 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.
//
//
// Common minimalistic base for routing data (instance) classes.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DATA_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DATA_H
#include <ostream>
#include "constraint_solver/routing.h"
#include "routing_common/routing_common.h"
#include "routing_common/routing_data_generator.h"
DECLARE_int32(width_size);
namespace operations_research {
// Forward declaration.
class TSPLIBReader;
// Base class with Routing Data (instances).
class RoutingData {
public:
explicit RoutingData(int32 size = 0) : size_(size), name_("no name"), is_routing_data_created_(false), is_routing_data_instanciated_(false),
has_coordinates_(false), has_diplay_coords_(false), raw_bbox_(BoundingBox())
{
if (size > 0) {
CreateRoutingData(size);
}
}
explicit RoutingData(const RoutingDataGenerator & g): size_(g.Size()), name_(g.InstanceName()), is_routing_data_created_(false), is_routing_data_instanciated_(false),
has_coordinates_(false), has_diplay_coords_(false), raw_bbox_(BoundingBox())
{
if (Size() > 0) {
CreateRoutingData(Size());
for (RoutingModel::NodeIndex i(0); i < Size(); ++i) {
Coordinate(i) = g.Coordinate(i);
for (RoutingModel::NodeIndex j(0); j < Size(); ++j) {
InternalDistance(i,j) = g.Distance(i,j);
}
}
SetRoutingDataInstanciated();
SetHasCoordinates();
}
}
explicit RoutingData(const RoutingData & other) {
CreateRoutingData(other.Size());
name_ = other.Name();
comment_ = other.Comment();
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
for (RoutingModel::NodeIndex j(RoutingModel::kFirstNode); j < Size(); ++j) {
InternalDistance(i,j) = other.Distance(i,j);
}
}
if (other.HasDisplayCoordinates()) {
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
Coordinate(i) = other.Coordinate(i);
}
}
if (other.HasCoordinates()) {
for (RoutingModel::NodeIndex i(RoutingModel::kFirstNode); i < Size(); ++i) {
DisplayCoordinate(i) = other.DisplayCoordinate(i);
}
}
SetHasCoordinates(other.HasCoordinates());
SetHasDisplayCoordinates(other.HasDisplayCoordinates());
SetRoutingDataInstanciated();
}
virtual ~RoutingData() {}
void SetHasCoordinates(const bool coordinates = true) {
has_coordinates_ = coordinates;
}
void SetHasDisplayCoordinates(const bool display_coordinates = true) {
has_diplay_coords_ = display_coordinates;
}
bool HasCoordinates() const {
return has_coordinates_;
}
bool HasDisplayCoordinates() const {
return has_diplay_coords_;
}
bool IsVisualizable() const {
return HasCoordinates() || HasDisplayCoordinates();
}
int32 Size() const {
return size_;
}
std::string Name() const {
return name_;
}
std::string Comment() const {
return comment_;
}
int64 Distance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) const {
CheckNodeIsValid(i);
return distances_.Cost(i,j);
}
Point Coordinate(RoutingModel::NodeIndex i) const {
CheckNodeIsValid(i);
return coordinates_[i.value()];
}
Point DisplayCoordinate(RoutingModel::NodeIndex i) const {
CheckNodeIsValid(i);
return display_coords_[i.value()];
}
BoundingBox RawBoundingBox() const {
return raw_bbox_;
}
void PrintDistanceMatrix(std::ostream& out, const int32 & width = FLAGS_width_size) const;
void WriteDistanceMatrix(const std::string & filename, const int32 & width = FLAGS_width_size) const;
protected:
void CreateRoutingData(int32 size) {
size_ = size;
distances_.Create(size);
coordinates_.resize(size);
display_coords_.resize(size);
is_routing_data_created_ = true;
}
bool IsRoutingDataCreated() const {
return is_routing_data_created_;
}
bool IsRoutingDataInstanciated() const {
return is_routing_data_instanciated_;
}
void SetRoutingDataInstanciated() {
is_routing_data_instanciated_ = true;
distances_.SetIsInstanciated();
//Find bounding box
if (HasDisplayCoordinates()) {
for (int32 i = 0; i < Size(); ++i ) {
raw_bbox_.Update(display_coords_[i]);
}
} else if (HasCoordinates()) {
for (int32 i = 0; i < Size(); ++i ) {
raw_bbox_.Update(coordinates_[i]);
}
}
}
void CheckNodeIsValid(const RoutingModel::NodeIndex i) const {
CHECK_GE(i.value(), 0) << "Internal node " << i.value() << " should be greater than 0!";
CHECK_LT(i.value(), Size()) << "Internal node " << i.value() << " should be less than " << Size();
}
int64& InternalDistance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) {
CheckNodeIsValid(i);
CheckNodeIsValid(j);
return distances_.Cost(i,j);
}
Point& Coordinate(RoutingModel::NodeIndex i) {
CheckNodeIsValid(i);
return coordinates_[i.value()];
}
Point& DisplayCoordinate(RoutingModel::NodeIndex i) {
CheckNodeIsValid(i);
return display_coords_[i.value()];
}
protected:
int32 size_;
std::string name_;
std::string comment_;
private:
bool is_routing_data_created_;
bool is_routing_data_instanciated_;
bool has_coordinates_;
bool has_diplay_coords_;
protected:
CompleteGraphArcCost distances_;
std::vector<Point> coordinates_;
std::vector<Point> display_coords_;
BoundingBox raw_bbox_;
};
void RoutingData::PrintDistanceMatrix(std::ostream& out, const int32 & width) const {
distances_.Print(out, width);
}
void RoutingData::WriteDistanceMatrix(const std::string& filename, const int32 & width) const {
WriteToFileP1<RoutingData, const int> writer(this, filename);
writer.SetMember(&operations_research::RoutingData::PrintDistanceMatrix);
writer.Run(width);
}
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DATA_H

View File

@@ -0,0 +1,80 @@
// Copyright 2011-2014 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.
//
//
// Common base to generate routing data (instances).
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DATA_GENERATOR_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DATA_GENERATOR_H
#include <string>
#include "base/join.h"
#include "base/integral_types.h"
#include "constraint_solver/routing.h"
#include "common/random.h"
#include "routing_common/routing_common_flags.h"
#include "routing_common/routing_common.h"
#include "routing_common/routing_random.h"
#include "routing_common/routing_distance.h"
namespace operations_research {
class RoutingDataGenerator {
public:
RoutingDataGenerator(std::string problem_name, std::string instance_name, int32 size) :
problem_name_(problem_name), instance_name_(instance_name), size_(size), randomizer_(GetSeed()),
coordinates_(size_), dist_coords_(coordinates_) {}
int64 Distance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) const {
return dist_coords_.Distance(i,j);
}
Point Coordinate(RoutingModel::NodeIndex i) const {
return coordinates_.Coordinate(i);
}
std::string ProblemName() const {
return problem_name_;
}
std::string InstanceName() const {
return instance_name_;
}
int32 Size() const {
return size_;
}
void ReplaceDistance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j, int64 dist) {
dist_coords_.ReplaceDistance(i, j, dist);
}
protected:
std::string problem_name_;
std::string instance_name_;
int32 size_;
ACMRandom randomizer_;
GenerateTWODCoordinates coordinates_;
DistancesFromTWODCoordinates dist_coords_;
};
// Common usage message for instance generators.
std::string GeneratorUsage(std::string invocation, std::string problem_name) {
return StrCat("Generates a ", problem_name, " instance.\n"
"See Google or-tools tutorials\n"
"Sample usage:\n\n",
invocation,
" -instance_name=<name> -instance_size=<size>\n\n");
}
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DATA_GENERATOR_H

View File

@@ -0,0 +1,76 @@
// Copyright 2011-2014 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.
//
//
// Common routing distance stuff.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DISTANCE_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_DISTANCE_H
#include <string>
#include "constraint_solver/routing.h"
#include "routing_random.h"
#include "tsplib.h"
DECLARE_int32(width_size);
namespace operations_research {
class CompleteGraphDistances {
public:
CompleteGraphDistances(int32 size): size_(size), costs_(size_) {}
virtual int64 Distance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) const = 0;
int32 Size() const {
return size_;
}
void Print(std::ostream & out, const int width = FLAGS_width_size);
void ReplaceDistance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j, int64 dist) {
costs_.Cost(i,j) = dist;
}
private:
int32 size_;
protected:
CompleteGraphArcCost costs_;
};
void CompleteGraphDistances::Print(std::ostream & out, const int width) {
costs_.Print(out, width);
}
// Basic distance class on "complete" graphs from coordinates.
class DistancesFromTWODCoordinates : public CompleteGraphDistances {
public:
explicit DistancesFromTWODCoordinates(const GenerateTWODCoordinates& coords): CompleteGraphDistances(coords.Size()), coords_(coords) {
for (RoutingModel::NodeIndex i(0); i < Size(); ++i) {
costs_.Cost(i,i) = 0;
for (RoutingModel::NodeIndex j(i.value()+1); j < Size(); ++j) {
int64 dist = TSPLIBDistanceFunctions::TWOD_euc_2d_distance(coords_.Coordinate(i), coords_.Coordinate(j));
costs_.Cost(i,j) = dist;
costs_.Cost(j,i) = dist;
}
}
}
virtual int64 Distance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) const {
return costs_.Cost(i,j);
}
void ReplaceDistance(RoutingModel::NodeIndex i, RoutingModel::NodeIndex j, int64 dist) {
costs_.Cost(i,j) = dist;
}
private:
const GenerateTWODCoordinates& coords_;
};
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_H

View File

@@ -0,0 +1,124 @@
// Copyright 2011-2014 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.
//
//
// Common base to use the epix library to visualize
// routing data (instance) and solutions.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_EPIX_HELPER_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_EPIX_HELPER_H
#include <memory>
#include "constraint_solver/routing.h"
#include "base/join.h"
#include "routing_common/routing_common.h"
namespace operations_research {
class RoutingEpixHelper {
public:
explicit RoutingEpixHelper(std::ostream & out) : out_(&out) {}
void SetOuptutStream(std::ostream & out) {
out_ = &out;
}
private:
std::ostream * out_;
};
void PrintEpixBeginFile(std::ostream & out) {
out << "#include \"epix.h\"" << std::endl;
out << "using namespace ePiX;" << std::endl;
out << std::endl;
out << "int main(int argc, char **argv)" << std::endl;
out << "{" << std::endl;
}
void PrintEpixPreamble(std::ostream & out) {
out << std::endl;
out << "unitlength(\"1cm\");" << std::endl;
out << "picture(" << FLAGS_epix_width << "," << FLAGS_epix_height << ");" << std::endl;
out << "double radius = " << FLAGS_epix_radius << ";" << std::endl;
out << "font_size(\"tiny\");" << std::endl;
}
void PrintEpixBoundingBox(std::ostream & out, const BoundingBox & P) {
out << "bounding_box(P(" << P.min_x << "," << P.min_y << "), P(" << P.max_x << "," << P.max_y << "));" << std::endl;
}
void PrintEpixBeginFigure(std::ostream & out) {
out << std::endl;
out << "begin(); // ---- Figure body starts here ----" << std::endl;
}
void PrintEpixEndFigure(std::ostream & out) {
out << std::endl;
out << "end(); // ---- End figure; write output file ----" << std::endl;
}
void PrintEpixEndFile(std::ostream & out) {
out << std::endl;
out << "}" << std::endl;
}
void PrintEpixNewLine(std::ostream & out) {
out << std::endl;
}
void PrintEpixRaw(std::ostream & out, const char* s) {
out << s << std::endl;
}
void PrintEpixComment(std::ostream & out, const char* s) {
out << " // " << s << std::endl;
}
void PrintEpixPoint(std::ostream & out, Point p, RoutingModel::NodeIndex i) {
out << " P " << StrCat("P",i.value()) << "(" << p.x << "," << p.y << ");" << std::endl;
out << StrCat(" Circle C",i.value()) << StrCat("(P",i.value()) << ", radius);" << std::endl;
}
void PrintEpixSegment(std::ostream & out, int segment_index, RoutingModel::NodeIndex i, RoutingModel::NodeIndex j) {
out << StrCat(" Segment L", segment_index) <<"(P" << StrCat(i.value()) << ",P" <<
StrCat(j.value()) << ");" << std::endl;
}
void PrintEpixDepot(std::ostream & out, RoutingModel::NodeIndex d) {
out << " fill(Red());" << std::endl;
out << StrCat(" C", d.value(), ".draw();") << std::endl;
out << " fill(White());" << std::endl;
}
void PrintEpixDrawMultiplePoints(std::ostream & out, int size) {
for (int i = 0; i < size; ++i) {
out << StrCat(" C",i) << ".draw();" << std::endl;
if (FLAGS_epix_node_labels) {
out << StrCat(" label (P", i) << StrCat(",P(0.2,0.1),\"", i+1 ) << "\",tr);" << std::endl;
}
}
}
void PrintEpixArrow(std::ostream & out, RoutingModel::NodeIndex from_node, RoutingModel::NodeIndex to_node) {
out << "arrow " <<"(P" << from_node.value() << ", P" << to_node.value() << ");" << std::endl;
}
void PrintEpixDrawMultipleSegments(std::ostream & out, int size) {
for (int i = 0; i < size; ++i) {
out << StrCat(" L",i) << ".draw();" << std::endl;
}
}
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_EPIX_HELPER_H

View File

@@ -0,0 +1,73 @@
// Copyright 2011-2014 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.
//
//
// Common random routing stuff.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_RANDOM_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_RANDOM_H
#include <string>
#include <vector>
#include "base/random.h"
#include "constraint_solver/routing.h"
#include "common/random.h"
#include "routing_common/routing_common.h"
namespace operations_research {
class GenerateTWODCoordinates {
public:
GenerateTWODCoordinates(int32 size): size_(size), randomizer_(GetSeed()), coordinates_(size_) {
Generate();
}
const Point Coordinate(RoutingModel::NodeIndex i) const {
return coordinates_[i.value()];
}
const int32 Size() const {
return size_;
}
private:
void Generate() {
bool coord_found = false;
int32 x = 0;
int32 y = 0;
for (int32 i = 0; i < size_; i++) {
coord_found = false;
while (!coord_found) {
x = randomizer_.Uniform(FLAGS_x_max);
y = randomizer_.Uniform(FLAGS_y_max);
// test if coordinates are not already taken
// maybe we should ask for a minimum distance between points?
coord_found = true;
for (int32 j = 0; j < i; ++j) {
if (x == coordinates_[j].x && y == coordinates_[j].y) {
coord_found = false;
break;
}
}
}
coordinates_[i] = Point(x, y);
}
}
int32 size_;
ACMRandom randomizer_;
std::vector<Point> coordinates_;
};
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_RANDOM_H

View File

@@ -0,0 +1,51 @@
// Copyright 2011-2014 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.
//
//
// Common base for routing solution classes.
// A route is given by its depot (first node) and then the path (except for the first node), e.g.
// RoutingSolution 1 -> 2 -> 5 is in fact path 1 -> 2 -> 5 -> 1 and 1 is a depot.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_SOLUTION_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_SOLUTION_H
#include "constraint_solver/routing.h"
#include "routing_data.h"
namespace operations_research {
class RoutingSolution {
public:
explicit RoutingSolution(const RoutingData & data) : size_(data.Size()) {}
virtual ~RoutingSolution() {}
virtual bool IsSolution() const = 0;
virtual bool IsFeasibleSolution() const = 0;
virtual int64 ComputeObjectiveValue() const = 0;
void SetSize(int32 size) {
size_ = size;
}
// Size of the instance.
int32 Size() const {
return size_;
}
virtual bool Add(RoutingModel::NodeIndex i, int route_number = 0) = 0;
virtual void Print(std::ostream & out) const = 0;
protected:
int32 size_;
};
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_SOLUTION_H

View File

@@ -0,0 +1,406 @@
// Copyright 2011-2014 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.
//
//
// Definitions for the TSPLIB format.
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_TSPLIB_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_TSPLIB_H
#include <cmath>
#include <limits>
//#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "routing_common.h"
//DEFINE_bool(tsp_start_counting_at_1, true, "TSPLIB convention: first node is 1 (not 0).");
// You can find the technical description of the TSPLIB in
// http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/DOC.PS
// EOF is tested separately because it is sometimes redefined
namespace operations_research {
typedef int64 (*TWOD_distance_function)(const Point, const Point);
typedef int64 (*THREED_distance_function)(const Point, const Point);
const int kTSPLIBDelimiter = -1;
const char * kTSPLIBEndFileDelimiter = "EOF";
#define TSPLIB_STATES \
ENUM_OR_STRING( NAME ), \
ENUM_OR_STRING( TYPE ), \
ENUM_OR_STRING( COMMENT ), \
ENUM_OR_STRING( DIMENSION ), \
ENUM_OR_STRING( CAPACITY ), \
ENUM_OR_STRING( EDGE_WEIGHT_TYPE ), \
ENUM_OR_STRING( EDGE_WEIGHT_FORMAT ), \
ENUM_OR_STRING( EDGE_DATA_FORMAT ), \
ENUM_OR_STRING( NODE_COORD_TYPE ), \
ENUM_OR_STRING( DISPLAY_DATA_TYPE ), \
ENUM_OR_STRING( NODE_COORD_SECTION ), \
ENUM_OR_STRING( DEPOT_SECTION ), \
ENUM_OR_STRING( DEMAND_SECTION ), \
ENUM_OR_STRING( EDGE_DATA_SECTION ), \
ENUM_OR_STRING( FIXED_EDGE_SECTION ), \
ENUM_OR_STRING( DISPLAY_DATA_SECTION ), \
ENUM_OR_STRING( TOUR_SECTION ), \
ENUM_OR_STRING( EDGE_WEIGHT_SECTION ), \
ENUM_OR_STRING( TSPLIB_STATES_COUNT ), \
ENUM_OR_STRING( TSPLIB_STATES_UNDEFINED )
// TYPE
#define TSPLIB_PROBLEM_TYPES \
ENUM_OR_STRING( TSP ), \
ENUM_OR_STRING( ATSP ), \
ENUM_OR_STRING( CVRP ), \
ENUM_OR_STRING( CCPP ), \
ENUM_OR_STRING( TOUR ), \
ENUM_OR_STRING( TSPLIB_PROBLEM_TYPES_COUNT ), \
ENUM_OR_STRING( TSPLIB_PROBLEM_TYPES_UNDEFINED )
// EDGE_WEIGHT_TYPE
#define TSPLIB_EDGE_WEIGHT_TYPES \
ENUM_OR_STRING( ATT ), \
ENUM_OR_STRING( CEIL_2D ), \
ENUM_OR_STRING( CEIL_3D ), \
ENUM_OR_STRING( EUC_2D ), \
ENUM_OR_STRING( EUC_3D ), \
ENUM_OR_STRING( EXPLICIT ), \
ENUM_OR_STRING( GEO ), \
ENUM_OR_STRING( GEOM ), \
ENUM_OR_STRING( GEO_MEEUS ), \
ENUM_OR_STRING( GEOM_MEEUS ), \
ENUM_OR_STRING( MAN_2D ), \
ENUM_OR_STRING( MAN_3D ), \
ENUM_OR_STRING( MAX_2D ), \
ENUM_OR_STRING( MAX_3D ), \
ENUM_OR_STRING( TSPLIB_EDGE_WEIGHT_TYPES_COUNT ), \
ENUM_OR_STRING( TSPLIB_EDGE_WEIGHT_TYPES_UNDEFINED )
// EDGE_WEIGHT_FORMAT
#define TSPLIB_EDGE_WEIGHT_FORMAT_TYPES \
ENUM_OR_STRING( FUNCTION ), \
ENUM_OR_STRING( FULL_MATRIX ), \
ENUM_OR_STRING( UPPER_ROW ), \
ENUM_OR_STRING( LOWER_ROW ), \
ENUM_OR_STRING( UPPER_DIAG_ROW ), \
ENUM_OR_STRING( LOWER_DIAG_ROW ), \
ENUM_OR_STRING( UPPER_COL ), \
ENUM_OR_STRING( LOWER_COL ), \
ENUM_OR_STRING( UPPER_DIAG_COL ), \
ENUM_OR_STRING( LOWER_DIAG_COL ), \
ENUM_OR_STRING( TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_COUNT ), \
ENUM_OR_STRING( TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_UNDEFINED )
// EDGE_DATA_FORMAT
#define TSPLIB_EDGE_DATA_FORMAT_TYPES \
ENUM_OR_STRING( EDGE_LIST ), \
ENUM_OR_STRING( ADJ_LIST ), \
ENUM_OR_STRING( TSPLIB_EDGE_DATA_FORMAT_TYPES_COUNT ), \
ENUM_OR_STRING( TSPLIB_EDGE_DATA_FORMAT_TYPES_UNDEFINED )
// NODE_COORD_TYPE
#define TSPLIB_NODE_COORD_TYPE_TYPES \
ENUM_OR_STRING( TWOD_COORDS ), \
ENUM_OR_STRING( THREED_COORDS ), \
ENUM_OR_STRING( NO_COORDS ), \
ENUM_OR_STRING( TSPLIB_NODE_COORD_TYPE_TYPES_COUNT ), \
ENUM_OR_STRING( TSPLIB_NODE_COORD_TYPE_TYPES_UNDEFINED )
// DISPLAY_DATA_TYPE
#define TSPLIB_DISPLAY_DATA_TYPE_TYPES \
ENUM_OR_STRING( COORD_DISPLAY ), \
ENUM_OR_STRING( TWOD_DISPLAY ), \
ENUM_OR_STRING( NO_DISPLAY ), \
ENUM_OR_STRING( TSPLIB_DISPLAY_DATA_TYPE_TYPES_COUNT ), \
ENUM_OR_STRING( TSPLIB_DISPLAY_DATA_TYPE_TYPES_UNDEFINED )
// Enum
#undef ENUM_OR_STRING
#define ENUM_OR_STRING( x ) x
enum TSPLIB_STATES_enum
{
TSPLIB_STATES
};
enum TSPLIB_PROBLEM_TYPES_enum
{
TSPLIB_PROBLEM_TYPES
};
enum TSPLIB_EDGE_WEIGHT_TYPES_enum
{
TSPLIB_EDGE_WEIGHT_TYPES
};
enum TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_enum
{
TSPLIB_EDGE_WEIGHT_FORMAT_TYPES
};
enum TSPLIB_EDGE_DATA_FORMAT_TYPES_enum
{
TSPLIB_EDGE_DATA_FORMAT_TYPES
};
enum TSPLIB_NODE_COORD_TYPE_TYPES_enum
{
TSPLIB_NODE_COORD_TYPE_TYPES
};
enum TSPLIB_DISPLAY_DATA_TYPE_TYPES_enum
{
TSPLIB_DISPLAY_DATA_TYPE_TYPES
};
// Strings
#undef ENUM_OR_STRING
#define ENUM_OR_STRING( x ) #x
const char * TSPLIB_STATES_KEYWORDS[] =
{
TSPLIB_STATES
};
const char * TSPLIB_PROBLEM_TYPES_KEYWORDS[] =
{
TSPLIB_PROBLEM_TYPES
};
const char * TSPLIB_EDGE_WEIGHT_TYPES_KEYWORDS[] =
{
TSPLIB_EDGE_WEIGHT_TYPES
};
const char * TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_KEYWORDS[] =
{
TSPLIB_EDGE_WEIGHT_FORMAT_TYPES
};
const char * TSPLIB_EDGE_DATA_FORMAT_TYPES_KEYWORDS[] =
{
TSPLIB_EDGE_DATA_FORMAT_TYPES
};
const char * TSPLIB_NODE_COORD_TYPE_TYPES_KEYWORDS[] =
{
TSPLIB_NODE_COORD_TYPE_TYPES
};
const char * TSPLIB_DISPLAY_DATA_TYPE_TYPES_KEYWORDS[] =
{
TSPLIB_DISPLAY_DATA_TYPE_TYPES
};
struct TSPLIBDistanceFunctions {
typedef int64 (*TWOD_distance_function)(const Point, const Point);
typedef int64 (*THREED_distance_function)(const Point, const Point, const Point);
static constexpr double PI = 3.141594;
// Earth radius in km
static constexpr double RRR = 6378.388;
TSPLIBDistanceFunctions(const TSPLIB_NODE_COORD_TYPE_TYPES_enum dim , const TSPLIB_EDGE_WEIGHT_TYPES_enum type) {
switch (dim) {
case TWOD_COORDS: {
switch (type) {
case EUC_2D: {
TWOD_dist_fun_ = &TWOD_euc_2d_distance;
break;
}
case GEO:
case GEOM: {
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_geo_distance;
break;
}
case ATT: {
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_att_distance;
break;
}
}
break;
} // case TWOD_COORDS:
case THREED_COORDS: {
break;
}
case NO_COORDS: {
break;
}
case TSPLIB_NODE_COORD_TYPE_TYPES_UNDEFINED: {
break;
}
}
}
int64 TWOD_distance(const Point x, const Point y) {
return TWOD_dist_fun_(x,y);
}
// Rounds to the nearest int
static int64 nint(double d)
{
return std::floor(d+0.5);
}
// Convert longitude and latitude given in DDD.MM with DDD = degrees and MM = minutes
// into longitude and latitude given in radians.
static double convert_to_geo(double x) {
int64 deg = nint(x);
return PI * (deg + 5.0 * (x - deg) / 3.0 ) / 180.0;
}
// 2D functions
static int64 TWOD_euc_2d_distance(const Point a, const Point b) {
double xd = a.x - b.x;
double yd = a.y - b.y;
return nint(std::sqrt(xd*xd + yd*yd));;
}
static int64 THREED_euc_3d_distance(const Point a, const Point b) {
double xd = a.x - b.x;
double yd = a.y - b.y;
double zd = a.z - b.z;
return nint(std::sqrt(xd*xd + yd*yd + zd*zd));;
}
static int64 TWOD_max_2d_distance(const Point a, const Point b) {
double xd = std::abs(a.x - b.x);
double yd = std::abs(a.y - b.y);
return std::max(nint(xd), nint(yd));
}
static int64 THREED_max_3d_distance(const Point a, const Point b) {
double xd = std::abs(a.x - b.x);
double yd = std::abs(a.y - b.y);
double zd = std::abs(a.z - b.z);
return std::max(std::max(nint(xd), nint(yd)), nint(zd));
}
static int64 TWOD_man_2d_distance(const Point a, const Point b) {
double xd = std::abs(a.x - b.x);
double yd = std::abs(a.y - b.y);
return nint(xd + yd);
}
static int64 THREED_man_3d_distance(const Point a, const Point b) {
double xd = std::abs(a.x - b.x);
double yd = std::abs(a.y - b.y);
double zd = std::abs(a.z - b.z);
return nint(xd + yd +zd);
}
static int64 TWOD_ceil_2d_distance(const Point a, const Point b) {
double xd = std::abs(a.x - b.x);
double yd = std::abs(a.y - b.y);
return std::ceil(xd + yd);
}
static int64 THREED_ceil_3d_distance(const Point a, const Point b) {
double xd = std::abs(a.x - b.x);
double yd = std::abs(a.y - b.y);
double zd = std::abs(a.z - b.z);
return std::ceil(xd + yd +zd);
}
static int64 TWOD_geo_distance(const Point a, const Point b) {
Point a_geo(convert_to_geo(a.x), convert_to_geo(a.y) );
Point b_geo(convert_to_geo(b.x), convert_to_geo(b.y) );
double q1 = std::cos(a_geo.y - b_geo.y);
double q2 = std::cos(a_geo.x - b_geo.x);
double q3 = std::cos(a_geo.x + b_geo.x);
return (int64) RRR * std::acos( 0.5 * ((1.0 + q1)*q2 - (1.0 - q1) * q3)) + 1.0;
}
static int64 TWOD_att_distance(const Point a, const Point b) {
double xd = a.x - b.x;
double yd = a.y - b.y;
double rij = std::sqrt( (xd*xd + yd*yd) / 10.0);
int64 tij = nint(rij);
return (tij < rij)? tij + 1: tij;
}
TWOD_distance_function TWOD_dist_fun_;
// 3D functions
THREED_distance_function THREED_dist_fun_;
};
void PrintFatalLog(const char * msg,const std::string & wrong_keyword, int line_number) {
LOG(FATAL) << "TSPLIB: " << msg << ": \"" << wrong_keyword << "\" on line " << line_number;
}
// Find the enum corresponding to a string
// This only works if the strings and enums are ordered in the same way
// and an "undefined enum" is placed at the end of the enum (hence the "index + 1").
template <typename E>
E FindEnumKeyword(const char** list,const std::string word,const E end_index) {
int index = 0;
for (; index < end_index; ++index) {
if (!strcmp(word.c_str(),list[index])) {
return (E) index;
}
}
return (E) (index + 1);
}
// Find the enum corresponding to a string
// This only works if the strings and enums are ordered in the same way
// and an "undefined enum" is placed at the end of the enum (hence the "index + 1")
// and a "count enum" gives the number of elements in the enum (XXX_UNDEFINED = XXX_COUNT + 1).
// Print a LOG(FATAL) if no enum if found.
template <typename E>
E FindOrDieEnumKeyword(const char** list, const std::string word, const E end_index, const char * err_msg, int line_number) {
E enum_element = FindEnumKeyword<E>(list, word, end_index);
if (enum_element == end_index + 1) {
PrintFatalLog(err_msg, word, line_number);
}
return enum_element;
}
} // namespace operations_research
#endif

View File

@@ -0,0 +1,618 @@
// Copyright 2011-2014 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.
//
//
// TSPLIBReader.
//
// Only valid for:
// - TSP
// - ATSP
// - CVRP
// - CCPP (this is an extension)
#ifndef OR_TOOLS_TUTORIALS_CPLUSPLUS_TSPLIB_READER_H
#define OR_TOOLS_TUTORIALS_CPLUSPLUS_TSPLIB_READER_H
#include <cmath>
#include <limits>
#include <vector>
#include "base/integral_types.h"
#include "base/filelinereader.h"
#include "base/split.h"
#include "base/strtoint.h"
#include "routing_common/routing_common.h"
#include "routing_common/routing_data.h"
#include "routing_common/tsplib.h"
namespace operations_research {
class TSPLIBReader : public RoutingData {
public:
typedef std::vector<RoutingModel::NodeIndex>::iterator solution_iterator;
typedef std::vector<RoutingModel::NodeIndex>::const_iterator const_solution_iterator;
explicit TSPLIBReader(const std::string & filename) :
RoutingData(0),
line_number_(0),
visualizable_(false),
two_dimension_(false),
symmetric_(false),
need_to_compute_distances_(false),
tsplib_state_unknown_(true),
tsplib_state_(TSPLIB_STATES_UNDEFINED),
name_(""),
type_(TSPLIB_PROBLEM_TYPES_UNDEFINED),
comment_(""),
capacity_(-1),
edge_weight_type_(TSPLIB_EDGE_WEIGHT_TYPES_UNDEFINED),
edge_weight_format_type_(TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_UNDEFINED),
edge_data_format_type_(TSPLIB_EDGE_DATA_FORMAT_TYPES_UNDEFINED),
node_coord_type_(TWOD_COORDS), // If no coord type is given, we assume 2D.
display_data_type_(TSPLIB_DISPLAY_DATA_TYPE_TYPES_UNDEFINED)
{
LoadInstance(filename);
if (depots_.size() == 0) {
depots_.push_back(RoutingModel::kFirstNode);
}
SetRoutingDataInstanciated();
}
TSPLIB_PROBLEM_TYPES_enum TSPLIBType () const {
return type_;
}
RoutingModel::NodeIndex Depot() const {
return depots_[0];
}
std::vector<RoutingModel::NodeIndex> Depots() const {
return depots_;
}
int32 Capacity() const {
return capacity_;
}
int64 Demand(RoutingModel::NodeIndex i) const {
return demands_[i.value()];
}
bool HasDimensionTwo() const {
return two_dimension_;
}
TSPLIB_NODE_COORD_TYPE_TYPES_enum NodeCoordinateType() const {
return node_coord_type_;
}
TSPLIB_DISPLAY_DATA_TYPE_TYPES_enum DisplayDataType() const {
return display_data_type_;
}
TSPLIB_EDGE_WEIGHT_TYPES_enum EdgeWeightType() const {
return edge_weight_type_;
}
TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_enum EdgeWeightTypeFormat() const {
return edge_weight_format_type_;
}
solution_iterator solution_begin() {
return tsp_sol_.begin();
}
const_solution_iterator solution_begin() const {
return tsp_sol_.begin();
}
solution_iterator solution_end() {
return tsp_sol_.end();
}
const_solution_iterator solution_end() const {
return tsp_sol_.end();
}
protected:
void LoadInstance(const std::string& filename);
// Helper function
int64& SetMatrix(int i, int j) {
return distances_.Cost(RoutingModel::NodeIndex(i), RoutingModel::NodeIndex(j));
}
private:
void ProcessNewLine(char* const line);
std::vector<RoutingModel::NodeIndex> depots_;
int line_number_;
bool visualizable_;
bool two_dimension_;
bool symmetric_;
bool need_to_compute_distances_;
TSPLIB_STATES_enum tsplib_state_;
bool tsplib_state_unknown_;
TSPLIB_PROBLEM_TYPES_enum type_;
std::string name_;
std::string comment_;
int32 capacity_;
TSPLIB_EDGE_WEIGHT_TYPES_enum edge_weight_type_;
TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_enum edge_weight_format_type_;
TSPLIB_EDGE_DATA_FORMAT_TYPES_enum edge_data_format_type_;
TSPLIB_NODE_COORD_TYPE_TYPES_enum node_coord_type_;
TSPLIB_DISPLAY_DATA_TYPE_TYPES_enum display_data_type_;
TWOD_distance_function TWOD_dist_fun_;
THREED_distance_function THREED_dist_fun_;
std::vector<RoutingModel::NodeIndex> tsp_sol_;
std::vector<int64> demands_;
};
void TSPLIBReader::LoadInstance(const std::string& filename)
{
FileLineReader reader(filename.c_str());
reader.set_line_callback(NewPermanentCallback(
this,
&TSPLIBReader::ProcessNewLine));
reader.Reload();
if (!reader.loaded_successfully()) {
LOG(FATAL) << "Could not open TSPLIB instance file: " << filename;
}
}
void TSPLIBReader::ProcessNewLine(char*const line) {
++line_number_;
VLOG(2) << "Line " << line_number_ << ": " << line;
// Must always be -1 outside a section
static int32 nodes_nbr = -1;
static bool read_matrix_done = false;
static const char kWordDelimiters[] = " :";
std::vector<std::string> words;
words = strings::Split(line, kWordDelimiters, strings::SkipEmpty());
// Empty lines
if (words.size() == 0) {
return;
}
// FIND TSPLIB KEYWORD
if (tsplib_state_unknown_) {
bool keyword_found = false;
//read_matrix_done = false;
tsplib_state_ = FindEnumKeyword(TSPLIB_STATES_KEYWORDS, words[0], TSPLIB_STATES_COUNT);
if (tsplib_state_ != TSPLIB_STATES_UNDEFINED) {
keyword_found = true;
}
// separate test because "EOF" is sometimes redefined
if (words[0] == kTSPLIBEndFileDelimiter) {
return;
}
if (!keyword_found) {
PrintFatalLog("Unknown keyword", words[0], line_number_);
}
tsplib_state_unknown_ = false;
}
// SWITCH FOLLOWING TSPLIB KEYWORD
switch (tsplib_state_) {
case NAME: {
name_ = words[1];
tsplib_state_unknown_ = true;
break;
}
case TYPE: {
type_ = FindOrDieEnumKeyword(TSPLIB_PROBLEM_TYPES_KEYWORDS, words[1], TSPLIB_PROBLEM_TYPES_COUNT, "Unknown problem type", line_number_);
tsplib_state_unknown_ = true;
break;
}
case COMMENT: {
if (words.size() > 1) {
for (int index = 1; index < words.size(); ++index) {
comment_ = StrCat(comment_, words[index] + " ");
}
}
tsplib_state_unknown_ = true;
break;
}
case DIMENSION: {
int32 size = atoi32(words[1]);
CreateRoutingData(size);
tsplib_state_unknown_ = true;
break;
}
case CAPACITY: {
capacity_ = atoi32(words[1]);
tsplib_state_unknown_ = true;
break;
}
case DEPOT_SECTION: {
if (nodes_nbr == -1) {
// titel
++nodes_nbr;
break;
}
if (atoi32(words[0]) == -1) {
nodes_nbr = -1;
tsplib_state_unknown_ = true;
break;
}
depots_.push_back(RoutingModel::NodeIndex(atoi32(words[1]) - 1));
++nodes_nbr;
break;
}
case DEMAND_SECTION: {
if (nodes_nbr == -1) {
// titel
demands_.resize(Size());
++nodes_nbr;
break;
}
if (nodes_nbr == Size() - 1) {
tsplib_state_unknown_ = true;
nodes_nbr = -1;
break;
}
CHECK_EQ(words.size(), 2) << "Demand section should only contain node_id and demand on line " << line_number_;
CHECK_LE(atoi32(words[0]), Size()) << "Node with node_id bigger than size of instance on line " << line_number_;
demands_[atoi32(words[0]) - 1] = atoi32(words[1]);
++nodes_nbr;
break;
}
case TOUR_SECTION: {
if (nodes_nbr == -1) {
// titel
tsp_sol_.resize(Size());
++nodes_nbr;
break;
}
if (nodes_nbr == Size()) {
CHECK_EQ(atoi32(words[0]), -1) << "Tour is supposed to end with -1.";
tsplib_state_unknown_ = true;
break;
}
RoutingModel::NodeIndex node(atoi32(words[0]) - 1);
tsp_sol_[nodes_nbr] = node;
++nodes_nbr;
break;
}
case EDGE_WEIGHT_TYPE: {
edge_weight_type_ = FindOrDieEnumKeyword(TSPLIB_EDGE_WEIGHT_TYPES_KEYWORDS,
words[1],
TSPLIB_EDGE_WEIGHT_TYPES_COUNT,
"Unknown edge weight type",
line_number_);
// Do we need to compute the distances?
switch (edge_weight_type_) {
case EXPLICIT: {
need_to_compute_distances_ = false;
break;
}
case EUC_2D: {
need_to_compute_distances_ = true;
two_dimension_ = true;
symmetric_ = true;
visualizable_ = true;
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_euc_2d_distance;
break;
}
case EUC_3D: {
need_to_compute_distances_ = true;
two_dimension_ = false;
symmetric_ = true;
visualizable_ = true;
THREED_dist_fun_ = &TSPLIBDistanceFunctions::THREED_euc_3d_distance;
break;
}
case MAX_2D: {
need_to_compute_distances_ = true;
two_dimension_ = true;
symmetric_ = true;
visualizable_ = true;
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_max_2d_distance;
break;
}
case MAX_3D: {
need_to_compute_distances_ = true;
two_dimension_ = false;
symmetric_ = true;
visualizable_ = true;
THREED_dist_fun_ = &TSPLIBDistanceFunctions::THREED_max_3d_distance;
break;
}
case MAN_2D: {
need_to_compute_distances_ = true;
two_dimension_ = true;
symmetric_ = true;
visualizable_ = true;
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_man_2d_distance;
break;
}
case MAN_3D: {
need_to_compute_distances_ = true;
two_dimension_ = false;
symmetric_ = true;
visualizable_ = true;
THREED_dist_fun_ = &TSPLIBDistanceFunctions::THREED_man_3d_distance;
break;
}
case CEIL_2D: {
need_to_compute_distances_ = true;
two_dimension_ = true;
symmetric_ = true;
visualizable_ = true;
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_ceil_2d_distance;
break;
}
case CEIL_3D: {
need_to_compute_distances_ = true;
two_dimension_ = false;
symmetric_ = true;
visualizable_ = true;
THREED_dist_fun_ = &TSPLIBDistanceFunctions::THREED_ceil_3d_distance;
break;
}
case GEO:
case GEOM: {
need_to_compute_distances_ = true;
two_dimension_ = true;
symmetric_ = true;
visualizable_ = true;
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_geo_distance;
break;
}
case ATT: {
need_to_compute_distances_ = true;
two_dimension_ = true;
symmetric_ = true;
visualizable_ = true;
TWOD_dist_fun_ = &TSPLIBDistanceFunctions::TWOD_att_distance;
break;
}
} // switch (edge_weight_type_)
tsplib_state_unknown_ = true;
break;
}
case EDGE_WEIGHT_FORMAT: {
edge_weight_format_type_ = FindOrDieEnumKeyword(TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_KEYWORDS,
words[1],
TSPLIB_EDGE_WEIGHT_FORMAT_TYPES_COUNT,
"Unknown edge weight format type",
line_number_);
tsplib_state_unknown_ = true;
break;
}
case EDGE_DATA_FORMAT: {
edge_data_format_type_ = FindOrDieEnumKeyword(TSPLIB_EDGE_DATA_FORMAT_TYPES_KEYWORDS,
words[1],
TSPLIB_EDGE_DATA_FORMAT_TYPES_COUNT,
"Unknown edge data format type",
line_number_);
tsplib_state_unknown_ = true;
break;
}
case NODE_COORD_TYPE: {
node_coord_type_ = FindOrDieEnumKeyword(TSPLIB_NODE_COORD_TYPE_TYPES_KEYWORDS,
words[1],
TSPLIB_NODE_COORD_TYPE_TYPES_COUNT,
"Unknown node coord format type",
line_number_);
tsplib_state_unknown_ = true;
break;
}
case DISPLAY_DATA_TYPE: {
display_data_type_ = FindOrDieEnumKeyword(TSPLIB_DISPLAY_DATA_TYPE_TYPES_KEYWORDS,
words[1],
TSPLIB_DISPLAY_DATA_TYPE_TYPES_COUNT,
"Unknown display data format type",
line_number_);
switch (display_data_type_) {
case NO_DISPLAY:
break;
case COORD_DISPLAY:
case TWOD_DISPLAY:
visualizable_ = true;
break;
}
tsplib_state_unknown_ = true;
break;
}
case NODE_COORD_SECTION: {
if (nodes_nbr == -1) {
++nodes_nbr;
visualizable_ = true;
break;
}
++nodes_nbr;
switch (node_coord_type_) {
case TWOD_COORDS: {
CHECK_EQ(words.size(), 3) << "Node coord data not conform on line " << line_number_;
CHECK_LE(atoi32(words[0].c_str()), size_) << "Unknown node number " << atoi32(words[0].c_str()) << " on line " << line_number_;
coordinates_[atoi32(words[0].c_str()) -1] = Point(atof(words[1].c_str()), atof(words[2].c_str()));
break;
}
case THREED_COORDS: {
CHECK_EQ(words.size(), 4) << "Node coord data not conform on line " << line_number_;
CHECK_LE(atoi32(words[0].c_str()), size_) << "Unknown node number " << atoi32(words[0].c_str()) << " on line " << line_number_;
coordinates_[atoi32(words[0].c_str()) -1] = Point(atof(words[1].c_str()), atof(words[2].c_str()), atof(words[3].c_str()));
break;
}
case NO_COORDS: {
LOG(FATAL) << "Coordinate is non existent but there is a node coordinate section???";
break;
}
default:
LOG(FATAL) << "Coordinate type is not defined.";
}
if (nodes_nbr == size_) {
SetHasCoordinates();
// Compute distance if needed
TSPLIBDistanceFunctions tsplib_dist_function(node_coord_type_, edge_weight_type_);
int64 dist = 0;
if (need_to_compute_distances_) {
LG << "Computing distance matrix...";
// TWO DIMENSION
if (two_dimension_) {
// SYMMETRIC
if (symmetric_) {
for (int i = 0; i < size_; ++i) {
for (int j = i + 1; j < size_; ++j ) {
dist = tsplib_dist_function.TWOD_distance(coordinates_[i], coordinates_[j]);
SetMatrix(i,j) = dist;
SetMatrix(j,i) = dist;
}
}
for (int i = 0; i < size_; ++i) {
SetMatrix(i,i) = 0LL;
}
// NOT SYMMETRIC
} else {
for (int i = 0; i < size_; ++i) {
for (int j = 0; j < size_; ++j ) {
if (i == j) {
SetMatrix(i,j) = 0LL;
} else {
SetMatrix(i,j) = dist;
}
}
}
}
// THREE DIMENSION
} else {
}
LG << "Computing distance matrix... Done!";
} // if (tsplib_dist_function.NeedToComputeDistances())
tsplib_state_unknown_ = true;
nodes_nbr = -1;
}
break;
} // case NODE_COORD_SECTION:
case DISPLAY_DATA_SECTION: {
if (nodes_nbr == -1) {
++nodes_nbr;
break;
}
if (display_data_type_ == TWOD_DISPLAY) {
CHECK_EQ(words.size(), 3) << "Display data not conform on line " << line_number_;
CHECK_LE(atoi32(words[0].c_str()), size_) << "Unknown node number " << atoi32(words[0].c_str()) << " on line " << line_number_;
display_coords_[atoi32(words[0].c_str()) -1] = Point(atof(words[1].c_str()), atof(words[2].c_str()));
++nodes_nbr;
if (nodes_nbr == size_) {
SetHasDisplayCoordinates();
tsplib_state_unknown_ = true;
nodes_nbr = -1;
}
} else {
tsplib_state_unknown_ = true;
nodes_nbr = -1;
}
break;
}
case EDGE_DATA_SECTION: {
if (words.size() == 1 && words[0] == "-1") {
// complete matrix
//TO DO
read_matrix_done = true;
tsplib_state_unknown_ = true;
break;
}
switch(edge_data_format_type_) {
case EDGE_LIST: {
CHECK_EQ(words.size(), 2) << "Edge not well defined on line " << line_number_;
break;
}
case ADJ_LIST: {
break;
}
}
}
case EDGE_WEIGHT_SECTION: {
if (nodes_nbr == -1) {
++nodes_nbr;
read_matrix_done = false;
break;
}
switch (edge_weight_format_type_) {
case FULL_MATRIX: {
CHECK_EQ(words.size(),size_) << "Matrix not full on line " << line_number_;
for (int index = 0; index < size_; ++index) {
int64 dist = atoi64(words[index].c_str());
SetMatrix(nodes_nbr, index) = dist;
}
if (nodes_nbr == size_ - 1) {
read_matrix_done = true;
}
break;
}
case UPPER_ROW: {
CHECK_EQ(words.size(), size_ - nodes_nbr - 1) << " Wrong number of tokens on line " << line_number_;
SetMatrix(nodes_nbr, nodes_nbr) = 0LL;
for (int index = 0; index < size_ - nodes_nbr - 1; ++index) {
int64 dist = atoi64(words[index].c_str());
SetMatrix(nodes_nbr, index + nodes_nbr + 1) = dist;
SetMatrix(index + nodes_nbr + 1, nodes_nbr) = dist;
}
if (nodes_nbr == size_ - 2) {
read_matrix_done = true;
}
break;
}
case UPPER_DIAG_ROW: { // BUGGY?
CHECK_EQ(words.size(), size_ - nodes_nbr - 1);
for (int index = 0; index < size_ - nodes_nbr ; ++index) {
int64 dist = atoi64(words[index].c_str());
std::cout << dist << " ";
SetMatrix(nodes_nbr, index + nodes_nbr) = dist;
SetMatrix(index + nodes_nbr , nodes_nbr) = dist;
}
std::cout << std::endl;
if (nodes_nbr == size_ - 2) {
read_matrix_done = true;
}
break;
}
case LOWER_ROW: { // TO BE CHECKED
CHECK_EQ(words.size(), nodes_nbr + 1);
SetMatrix(nodes_nbr, nodes_nbr) = 0LL;
for (int index = 0; index < nodes_nbr + 1; ++index) {
int64 dist = atoi64(words[index].c_str());
std::cout << dist << " ";
SetMatrix(nodes_nbr, index) = dist;
SetMatrix(index , nodes_nbr) = dist;
}
std::cout << std::endl;
if (nodes_nbr == size_ - 2) {
read_matrix_done = true;
break;
}
break;
}
} // switch (edge_weight_format_type_)
if (read_matrix_done) {
tsplib_state_unknown_ = true;
nodes_nbr = -1;
break;
}
++nodes_nbr;
} // case EDGE_WEIGHT_SECTION:
} // switch
} // ProcessNewLine()
} // namespace operations_research
#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_TSPLIB_READER_H