| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 | 
//=======================================================================// Copyright 2008// Author: Matyas W Egyhazy//// Distributed under the Boost Software License, Version 1.0. (See// accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)//=======================================================================#ifndef BOOST_GRAPH_METRIC_TSP_APPROX_HPP#define BOOST_GRAPH_METRIC_TSP_APPROX_HPP// metric_tsp_approx// Generates an approximate tour solution for the traveling salesperson// problem in polynomial time. The current algorithm guarantees a tour with a// length at most as long as 2x optimal solution. The graph should have// 'natural' (metric) weights such that the triangle inequality is maintained.// Graphs must be fully interconnected.// TODO:// There are a couple of improvements that could be made.// 1) Change implementation to lower uppper bound Christofides heuristic// 2) Implement a less restrictive TSP heuristic (one that does not rely on//    triangle inequality).// 3) Determine if the algorithm can be implemented without creating a new//    graph.#include <vector>#include <boost/shared_ptr.hpp>#include <boost/concept_check.hpp>#include <boost/graph/graph_traits.hpp>#include <boost/graph/graph_as_tree.hpp>#include <boost/graph/adjacency_list.hpp>#include <boost/graph/prim_minimum_spanning_tree.hpp>#include <boost/graph/lookup_edge.hpp>#include <boost/throw_exception.hpp>namespace boost{// Define a concept for the concept-checking library.template < typename Visitor, typename Graph > struct TSPVertexVisitorConcept{private:    Visitor vis_;public:    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;    BOOST_CONCEPT_USAGE(TSPVertexVisitorConcept)    {        Visitor vis(vis_); // require copy construction        Graph g(1);        Vertex v(*vertices(g).first);        vis.visit_vertex(v, g); // require visit_vertex    }};// Tree visitor that keeps track of a preorder traversal of a tree// TODO: Consider migrating this to the graph_as_tree header.// TODO: Parameterize the underlying stores so it doesn't have to be a vector.template < typename Node, typename Tree > class PreorderTraverser{private:    std::vector< Node >& path_;public:    typedef typename std::vector< Node >::const_iterator const_iterator;    PreorderTraverser(std::vector< Node >& p) : path_(p) {}    void preorder(Node n, const Tree&) { path_.push_back(n); }    void inorder(Node, const Tree&) const {}    void postorder(Node, const Tree&) const {}    const_iterator begin() const { return path_.begin(); }    const_iterator end() const { return path_.end(); }};// Forward declarationstemplate < typename > class tsp_tour_visitor;template < typename, typename, typename, typename > class tsp_tour_len_visitor;template < typename VertexListGraph, typename OutputIterator >void metric_tsp_approx_tour(VertexListGraph& g, OutputIterator o){    metric_tsp_approx_from_vertex(g, *vertices(g).first, get(edge_weight, g),        get(vertex_index, g), tsp_tour_visitor< OutputIterator >(o));}template < typename VertexListGraph, typename WeightMap,    typename OutputIterator >void metric_tsp_approx_tour(VertexListGraph& g, WeightMap w, OutputIterator o){    metric_tsp_approx_from_vertex(        g, *vertices(g).first, w, tsp_tour_visitor< OutputIterator >(o));}template < typename VertexListGraph, typename OutputIterator >void metric_tsp_approx_tour_from_vertex(VertexListGraph& g,    typename graph_traits< VertexListGraph >::vertex_descriptor start,    OutputIterator o){    metric_tsp_approx_from_vertex(g, start, get(edge_weight, g),        get(vertex_index, g), tsp_tour_visitor< OutputIterator >(o));}template < typename VertexListGraph, typename WeightMap,    typename OutputIterator >void metric_tsp_approx_tour_from_vertex(VertexListGraph& g,    typename graph_traits< VertexListGraph >::vertex_descriptor start,    WeightMap w, OutputIterator o){    metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g),        tsp_tour_visitor< OutputIterator >(o));}template < typename VertexListGraph, typename TSPVertexVisitor >void metric_tsp_approx(VertexListGraph& g, TSPVertexVisitor vis){    metric_tsp_approx_from_vertex(        g, *vertices(g).first, get(edge_weight, g), get(vertex_index, g), vis);}template < typename VertexListGraph, typename Weightmap,    typename VertexIndexMap, typename TSPVertexVisitor >void metric_tsp_approx(VertexListGraph& g, Weightmap w, TSPVertexVisitor vis){    metric_tsp_approx_from_vertex(        g, *vertices(g).first, w, get(vertex_index, g), vis);}template < typename VertexListGraph, typename WeightMap,    typename VertexIndexMap, typename TSPVertexVisitor >void metric_tsp_approx(    VertexListGraph& g, WeightMap w, VertexIndexMap id, TSPVertexVisitor vis){    metric_tsp_approx_from_vertex(g, *vertices(g).first, w, id, vis);}template < typename VertexListGraph, typename WeightMap,    typename TSPVertexVisitor >void metric_tsp_approx_from_vertex(VertexListGraph& g,    typename graph_traits< VertexListGraph >::vertex_descriptor start,    WeightMap w, TSPVertexVisitor vis){    metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g), vis);}template < typename VertexListGraph, typename WeightMap,    typename VertexIndexMap, typename TSPVertexVisitor >void metric_tsp_approx_from_vertex(const VertexListGraph& g,    typename graph_traits< VertexListGraph >::vertex_descriptor start,    WeightMap weightmap, VertexIndexMap indexmap, TSPVertexVisitor vis){    using namespace boost;    using namespace std;    BOOST_CONCEPT_ASSERT((VertexListGraphConcept< VertexListGraph >));    BOOST_CONCEPT_ASSERT(        (TSPVertexVisitorConcept< TSPVertexVisitor, VertexListGraph >));    // Types related to the input graph (GVertex is a template parameter).    typedef typename graph_traits< VertexListGraph >::vertex_descriptor GVertex;    typedef typename graph_traits< VertexListGraph >::vertex_iterator GVItr;    // We build a custom graph in this algorithm.    typedef adjacency_list< vecS, vecS, directedS, no_property, no_property >        MSTImpl;    typedef graph_traits< MSTImpl >::vertex_descriptor Vertex;    typedef graph_traits< MSTImpl >::vertex_iterator VItr;    // And then re-cast it as a tree.    typedef iterator_property_map< vector< Vertex >::iterator,        property_map< MSTImpl, vertex_index_t >::type >        ParentMap;    typedef graph_as_tree< MSTImpl, ParentMap > Tree;    typedef tree_traits< Tree >::node_descriptor Node;    // A predecessor map.    typedef vector< GVertex > PredMap;    typedef iterator_property_map< typename PredMap::iterator, VertexIndexMap >        PredPMap;    PredMap preds(num_vertices(g));    PredPMap pred_pmap(preds.begin(), indexmap);    // Compute a spanning tree over the in put g.    prim_minimum_spanning_tree(g, pred_pmap,        root_vertex(start).vertex_index_map(indexmap).weight_map(weightmap));    // Build a MST using the predecessor map from prim mst    MSTImpl mst(num_vertices(g));    std::size_t cnt = 0;    pair< VItr, VItr > mst_verts(vertices(mst));    for (typename PredMap::iterator vi(preds.begin()); vi != preds.end();         ++vi, ++cnt)    {        if (indexmap[*vi] != cnt)        {            add_edge(*next(mst_verts.first, indexmap[*vi]),                *next(mst_verts.first, cnt), mst);        }    }    // Build a tree abstraction over the MST.    vector< Vertex > parent(num_vertices(mst));    Tree t(mst, *vertices(mst).first,        make_iterator_property_map(parent.begin(), get(vertex_index, mst)));    // Create tour using a preorder traversal of the mst    vector< Node > tour;    PreorderTraverser< Node, Tree > tvis(tour);    traverse_tree(indexmap[start], t, tvis);    pair< GVItr, GVItr > g_verts(vertices(g));    for (PreorderTraverser< Node, Tree >::const_iterator curr(tvis.begin());         curr != tvis.end(); ++curr)    {        // TODO: This is will be O(n^2) if vertex storage of g != vecS.        GVertex v = *next(g_verts.first, get(vertex_index, mst)[*curr]);        vis.visit_vertex(v, g);    }    // Connect back to the start of the tour    vis.visit_vertex(start, g);}// Default tsp tour visitor that puts the tour in an OutputIteratortemplate < typename OutItr > class tsp_tour_visitor{    OutItr itr_;public:    tsp_tour_visitor(OutItr itr) : itr_(itr) {}    template < typename Vertex, typename Graph >    void visit_vertex(Vertex v, const Graph&)    {        BOOST_CONCEPT_ASSERT((OutputIterator< OutItr, Vertex >));        *itr_++ = v;    }};// Tsp tour visitor that adds the total tour length.template < typename Graph, typename WeightMap, typename OutIter,    typename Length >class tsp_tour_len_visitor{    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;    BOOST_CONCEPT_ASSERT((OutputIterator< OutIter, Vertex >));    OutIter iter_;    Length& tourlen_;    WeightMap& wmap_;    Vertex previous_;    // Helper function for getting the null vertex.    Vertex null() { return graph_traits< Graph >::null_vertex(); }public:    tsp_tour_len_visitor(Graph const&, OutIter iter, Length& l, WeightMap& map)    : iter_(iter), tourlen_(l), wmap_(map), previous_(null())    {    }    void visit_vertex(Vertex v, const Graph& g)    {        typedef typename graph_traits< Graph >::edge_descriptor Edge;        // If it is not the start, then there is a        // previous vertex        if (previous_ != null())        {            // NOTE: For non-adjacency matrix graphs g, this bit of code            // will be linear in the degree of previous_ or v. A better            // solution would be to visit edges of the graph, but that            // would require revisiting the core algorithm.            Edge e;            bool found;            boost::tie(e, found) = lookup_edge(previous_, v, g);            if (!found)            {                BOOST_THROW_EXCEPTION(not_complete());            }            tourlen_ += wmap_[e];        }        previous_ = v;        *iter_++ = v;    }};// Object generator(s)template < typename OutIter >inline tsp_tour_visitor< OutIter > make_tsp_tour_visitor(OutIter iter){    return tsp_tour_visitor< OutIter >(iter);}template < typename Graph, typename WeightMap, typename OutIter,    typename Length >inline tsp_tour_len_visitor< Graph, WeightMap, OutIter, Length >make_tsp_tour_len_visitor(    Graph const& g, OutIter iter, Length& l, WeightMap map){    return tsp_tour_len_visitor< Graph, WeightMap, OutIter, Length >(        g, iter, l, map);}} // boost#endif // BOOST_GRAPH_METRIC_TSP_APPROX_HPP
 |