/* $Id$
*
* Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com).
*
* This file is part of OpenCAMlib
* (see https://github.com/aewallin/opencamlib).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef TSP_H
#define TSP_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace ocl {
namespace tsp {
// loosely based on metric tsp example:
// http://www.boost.org/doc/libs/1_46_1/libs/graph/test/metric_tsp_approx.cpp
//add edges to the graph (for each node connect it to all other nodes)
template< typename VertexListGraph,
typename PointContainer,
typename WeightMap,
typename VertexIndexMap>
void connectAllEuclidean(VertexListGraph& g,
const PointContainer& points, // vector of (x,y) points
WeightMap wmap, // Property maps passed by value
const VertexIndexMap vmap) // Property maps passed by value
{
using namespace boost;
using namespace std;
typedef typename graph_traits::edge_descriptor Edge;
typedef typename graph_traits::vertex_iterator VItr;
Edge e;
bool inserted;
pair verts(vertices(g));
for (VItr src(verts.first); src != verts.second; src++) {
for (VItr dest(src); dest != verts.second; dest++) {
if (dest != src) {
double weight( sqrt(
pow(static_cast( points[vmap[*src ]].x - points[vmap[*dest]].x), 2.0) +
pow(static_cast( points[vmap[*dest]].y - points[vmap[*src ]].y), 2.0)) );
boost::tie(e, inserted) = add_edge(*src, *dest, g);
wmap[e] = weight; // passed by value??
}
}
}
}
class TSPSolver {
typedef boost::adjacency_matrix< boost::undirectedS,
boost::no_property,
boost::property< boost::edge_weight_t, double,
boost::property< boost::edge_index_t, long unsigned int> >,
boost::no_property
> Graph;
typedef boost::graph_traits::vertex_descriptor Vertex;
typedef boost::graph_traits::edge_descriptor Edge;
typedef boost::property_map::type WeightMap;
typedef std::vector< boost::simple_point > PointSet; // was std::set
typedef std::vector< Vertex > Container;
public:
TSPSolver () {}
virtual ~TSPSolver() {
if (g)
delete g;
}
void run() {
g = new Graph( points.size() );
// connect all vertices
WeightMap weight_map = boost::get( boost::edge_weight, *g);
connectAllEuclidean( *g, points, weight_map, boost::get( boost::vertex_index, *g) );
length = 0.0;
// Run the TSP approx, creating the visitor on the fly.
boost::metric_tsp_approx(*g, boost::make_tsp_tour_len_visitor(*g, std::back_inserter(output), length, weight_map) );
//length = len;
//std::cout << "Number of points: " << boost::num_vertices(*g) << std::endl;
//std::cout << "Number of edges: " << boost::num_edges(*g) << std::endl;
//std::cout << "Length of tour: " << len << std::endl;
//std::cout << "vertices in tour: " << output.size() << std::endl;
//std::cout << "Elapsed: " << t.elapsed() << std::endl;
}
void addPoint(double x, double y) {
boost::simple_point pnt;
pnt.x=x;
pnt.y=y;
points.push_back(pnt);
}
void reset() {
output.clear();
points.clear();
if (g)
delete g;
}
void printOutput() const {
int n=0;
BOOST_FOREACH( Vertex v, output ) {
std::cout << n++ << " : " << v << "\n" ;
}
}
double getLength() const {
return length;
}
boost::python::list getOutput() const {
boost::python::list plist;
BOOST_FOREACH(Vertex v, output) {
plist.append( v );
}
return plist;
}
protected:
Container output;
PointSet points;
Graph* g;
double length;
};
} // end tsp namespace
} // end ocl namespace
#endif