Files
ortools-clone/documentation/tutorials/cplusplus/routing_common/tsplib.h
nikolaj.van.omme@gmail.com 7fc4c48e28 Doc automatic update
2015-02-10 19:24:05 +00:00

414 lines
11 KiB
C++

// 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 is 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 is 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