ColorMap in boost::graph 隐式图形用于metric_tsp_approx
ColorMap in boost::graph implicit graph for metric_tsp_approx
我正在尝试完成以下操作:有一个函数computeTspTour(size, start, distance)
,它让我近似于从start
开始的size
多个顶点的最短游览。 在这里,distance
是一个函数对象,它接受两个索引并返回它们之间的距离。
我想利用boost::graph
的metric_tsp_approx
。 为此,我需要一张完整的基数图size
,所以我想为此使用隐式定义的图,以避免创建一个无用的琐碎巨大图结构。
一切似乎都工作正常,但我的问题是metric_tsp_approx
在某些时候使用 dijkstra_shortest_paths
,它定义了ColorMap
. 这会导致以下两个问题:
/usr/include/boost/graph/dijkstra_shortest_paths.hpp:373:60: error: no type named 'value_type' in 'struct boost::property_traits<boost::bgl_named_params<boost::detail::_project2nd<double, double>, boost::distance_combine_t, boost::bgl_named_params<std::less<double>, boost::distance_compare_t, boost::bgl_named_params<boost::iterator_property_map<__gnu_cxx::__normal_iterator<long unsigned int*, std::vector<long unsigned int> >, boost::typed_identity_property_map<long unsigned int>, long unsigned int, long unsigned int&>, boost::vertex_predecessor_t, boost::bgl_named_params<EdgeWeightMap<double>, boost::edge_weight_t, boost::bgl_named_params<boost::typed_identity_property_map<long unsigned int>, boost::vertex_index_t, boost::bgl_named_params<long unsigned int, boost::root_vertex_t, boost::no_property> > > > > > >' typedef typename property_traits<ColorMap>::value_type ColorValue; ^ /usr/include/boost/graph/dijkstra_shortest_paths.hpp:374:38: error: no type named 'value_type' in 'struct boost::property_traits<boost::bgl_named_params<boost::detail::_project2nd<double, double>, boost::distance_combine_t, boost::bgl_named_params<std::less<double>, boost::distance_compare_t, boost::bgl_named_params<boost::iterator_property_map<__gnu_cxx::__normal_iterator<long unsigned int*, std::vector<long unsigned int> >, boost::typed_identity_property_map<long unsigned int>, long unsigned int, long unsigned int&>, boost::vertex_predecessor_t, boost::bgl_named_params<EdgeWeightMap<double>, boost::edge_weight_t, boost::bgl_named_params<boost::typed_identity_property_map<long unsigned int>, boost::vertex_index_t, boost::bgl_named_params<long unsigned int, boost::root_vertex_t, boost::no_property> > > > > > >' typedef color_traits<ColorValue> Color; ^
但是,我不明白如何从我所在的位置修复ColorMap
的特征,自己创建颜色属性图没有任何好处。
我用于创建隐式图形并在其上运行tsp_metric_approx
的代码如下。 我很抱歉它的长度,我希望它很简单。 它的作用是设置一个类CompleteGraph
,有一个模板参数F
指定distance
函数的返回类型。 这个类有必要的迭代器来成为VertexListGraph
和IncidenceGraph
,以便tsp_metric_approx
可以在它上运行。
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <vector>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/graph/metric_tsp_approx.hpp>
using namespace boost;
typedef std::size_t VertexDescriptor;
typedef std::pair<VertexDescriptor, VertexDescriptor> EdgeDescriptor;
class VertexIterator : public boost::iterator_facade<VertexIterator, VertexDescriptor const, boost::bidirectional_traversal_tag>
{
public:
//! Default constructor
VertexIterator() : pos_(0) {}
//! Constructor setting the position
explicit VertexIterator(VertexDescriptor pos) : pos_(pos) {}
//! Dereference the iterator
VertexDescriptor const& dereference() const { return pos_; }
//! Check for equality
bool equal(VertexIterator const& other) const { return pos_ == other.pos_; }
//! Increment
void increment() { ++pos_; }
//! Decrement
void decrement() { --pos_; }
private:
//! Grant access to boost::iterator_facade
friend class boost::iterator_core_access;
//! The current position
VertexDescriptor pos_ = 0;
};
class OutEdgeIterator : public boost::iterator_facade<OutEdgeIterator, EdgeDescriptor const, boost::bidirectional_traversal_tag>
{
public:
//! Constructor setting the source vertex
explicit OutEdgeIterator(VertexDescriptor source) { const std::size_t target = source == 0 ? 1 : 0; pos_ = EdgeDescriptor(source, target); }
//! Constructor setting the source vertex and the target
explicit OutEdgeIterator(VertexDescriptor source, VertexDescriptor target) : pos_(source, target) {}
//! Dereference the iterator
EdgeDescriptor const& dereference() const { return pos_; }
//! Check for equality
bool equal(OutEdgeIterator const& other) const { return pos_ == other.pos_; }
//! Increment
void increment() { ++pos_.second; if(pos_.first == pos_.second) { ++pos_.second; } }
//! Decrement
void decrement() { --pos_.second; if(pos_.first == pos_.second) { --pos_.second; } }
private:
//! Grant access to boost::iterator_facade
friend class boost::iterator_core_access;
//! The current edge
EdgeDescriptor pos_ = EdgeDescriptor(0, 1);
};
//! Class representing a complete graph
/*!
* This class works as a complete graph.
* It defines a distance property map between any two points by calling the passed distance function.
* tparam F The return type of the distance function
*/
template<typename F>
class CompleteGraph
{
public:
typedef VertexDescriptor vertex_descriptor;
typedef EdgeDescriptor edge_descriptor;
typedef void adjacency_iterator;
typedef OutEdgeIterator out_edge_iterator;
typedef void in_edge_iterator;
typedef void edge_iterator;
typedef VertexIterator vertex_iterator;
typedef std::size_t degree_size_type;
typedef std::size_t vertices_size_type;
typedef std::size_t edges_size_type;
typedef undirected_tag directed_category;
typedef disallow_parallel_edge_tag edge_parallel_category;
typedef vertex_list_graph_tag traversal_category;
//! Delete default constructor
CompleteGraph() = delete;
//! Constructor from a given size
/*!
* If no distance is specified, we default to a constant function returning F(1)
*/
explicit CompleteGraph(std::size_t size) : size_(size), distance_(returnOne) {}
//! Constructor from a given size and a distance function of type F
/*!
* The constructed graph will have size many vertices.
* Its distance map will be of the following form: The distance between points i and j is distance(i, j).
* param[in] size The size the graph should have
* param[in] distance Binary function taking std::size_t arguments and returning the distance between two points
*/
explicit CompleteGraph(std::size_t size, std::function<F(std::size_t, std::size_t)> const& distance) : size_(size), distance_(distance) {}
//! Access to size_
std::size_t size() const { return size_; }
//! Access to distance_
std::function<F(std::size_t, std::size_t)> const& distance() const { return distance_; }
private:
//! The size of the graph
std::size_t size_;
//! The distance function used to find the distance between point i and point j
std::function<F(std::size_t, std::size_t)> const& distance_;
//! Distance function that just returns F(1)
std::function<F(std::size_t, std::size_t)> returnOne = [] (std::size_t, std::size_t) { return F(1); };
};
//! Weigth map for all edges
template<typename F>
class EdgeWeightMap
{
public:
typedef F value_type;
typedef F reference_type;
typedef reference_type reference;
typedef EdgeDescriptor key_type;
typedef readable_property_map_tag category;
//! Constructor from a distance function
explicit EdgeWeightMap(std::function<F(std::size_t, std::size_t)> const& distance) : distance_(distance) {}
//! Operator to dereference the property map
value_type operator[](key_type key) const { return distance_(key.first, key.second); }
//! Get function
friend inline value_type get(EdgeWeightMap<F> const& edgeWeightMap, EdgeWeightMap<F>::key_type const& key) { return edgeWeightMap[key]; }
private:
//! The distance function
std::function<F(std::size_t, std::size_t)> const& distance_;
};
//! Return the number of vertices of a CompleteGraph
template<typename F>
std::size_t num_vertices(CompleteGraph<F> const& g) { return g.size(); }
//! Return a pair allowing iteration over all vertices
template<typename F>
std::pair<VertexIterator, VertexIterator> vertices(CompleteGraph<F> const& g) { return std::make_pair(VertexIterator(0), VertexIterator(g.size())); }
//! Return a pair allowing iteration over all outgoing edges of a vertex
template<typename F>
std::pair<OutEdgeIterator, OutEdgeIterator> out_edges(VertexDescriptor s, CompleteGraph<F> const& g) { return std::make_pair(OutEdgeIterator(s), OutEdgeIterator(s, g.size())); }
//! Return the out-degree which is constant size - 1 for all vertices
template<typename F>
std::size_t out_degree(VertexDescriptor, CompleteGraph<F> const& g) { return g.size() - 1; }
//! Return the source of an edge
template<typename F>
VertexDescriptor source(EdgeDescriptor e, CompleteGraph<F> const&) { return e.first; }
//! Return the target of an edge
template<typename F>
VertexDescriptor target(EdgeDescriptor e, CompleteGraph<F> const&) { return e.second; }
//! Return the index map
template<typename F>
identity_property_map get(vertex_index_t, CompleteGraph<F> const&) { return identity_property_map(); }
//! Return the distance map
template<typename F>
EdgeWeightMap<F> get(edge_weight_t, CompleteGraph<F> const& g) { return EdgeWeightMap<F>(g.distance()); }
//! Wrapper function for automatic template parameter
template<typename F>
CompleteGraph<F> makeCompleteGraph(std::size_t size, std::function<F(std::size_t, std::size_t)> const& distance) { return CompleteGraph<F>(size, distance); }
//! Compute a metric TSP solution through the points supplied
/*!
* This function finds a solution through n many points whose pairwise distance is given by a function argument.
* The supplied distance function needs to satisfy the triangle inequality and must be symmetric.
* tparam F The type of the return value of distance
* param[in] size The number of points through which the TSP tour should be found
* param[in] start The index of the point at which to start
* param[in] distance A function taking two std::size_t's and returning the distance between point i and point j
* return A vector representing the TSP tour
*/
template<typename F>
std::vector<std::size_t> computeTspTour(std::size_t size, std::size_t start, std::function<F(std::size_t, std::size_t)> const& distance)
{
std::vector<std::size_t> tour;
const auto completeGraph = makeCompleteGraph(size, distance);
metric_tsp_approx_tour_from_vertex(completeGraph, start, std::back_inserter(tour));
return tour;
}
int main()
{
typedef std::complex<double> Point;
const std::vector<Point> points{{.0, .0}, {1.0, 2.0}, {1.0, 5.0}, {2.5, 9.2}, {-100.2, 24.1}, {.1, 10.0}};
const std::function<double(std::size_t, std::size_t)> distance = [&points] (std::size_t i, std::size_t j) { return std::abs(points[i] - points[j]); };
const auto tour = computeTspTour(points.size(), 0, distance);
std::cout << "Found TSP tour:n";
std::copy(tour.cbegin(), tour.cend(), std::ostream_iterator<char>(std::cout, " "));
return EXIT_SUCCESS;
}
如果有人有一个更短或根本不避免创建任何图形的替代建议,我也很高兴,一个完整的图形除了顶点的数量之外并没有真正携带任何信息。
DFS和TSP算法要求图形既是"顶点列表"又是"发生率图"(即可以访问顶点邻居的图)。
你的图表必须有类似的东西
struct traversal_category
: public virtual boost::vertex_list_graph_tag
, public virtual boost::adjacency_graph_tag
, public virtual boost::incidence_graph_tag
{
};
typedef typename boost::adjacency_iterator_generator<CompleteGraph<F>, vertex_descriptor, out_edge_iterator>::type adjacency_iterator;
而不是
typedef vertex_list_graph_tag traversal_category;
typedef void adjacency_iterator;
通过这些更改加上一些外观更改,您的代码可以通过编译。
顶点索引图是可选的,Boost将使用VertexMap和ColorMap包装您的代码,可能基于unordered_map。它的效率会低于"标识"或类似的自定义映射,但会起作用。
祝你好运!
自定义"完整"图的代码似乎没问题。
DFS需要的关键组件是"顶点索引映射":本质上是vertex_descriptor和int之间的一对一对应关系,使得每个顶点映射到区间[0,num_vertices(g))中的一个数字。对于"标准"图,这种映射是已知的,DFS使用一些元编程来推断适当的ColorMap的类型。
在您的情况下,vertex_descriptor是正确间隔内的整数,映射是"相同的映射"。您只需使用类似于以下内容的代码来表达它:
namespace boost{
template<class F>
struct property_map< CompleteGraph<F>, vertex_index_t >
{
typedef identity_property_map type;
//or more fancier
//typedef CompleteGraph<F> graph_t;
//typedef typed_identity_property_map<typename graph_t::vertex_descriptor> type;
typedef type const_type;
};
//then you define a "get" function:
template<class F>
identity_property_map
get(vertex_index_t, const CompleteGraph<F>& /*g -- not used */)
{
return identity_property_map();
}
} //namespace boost
应该够了。如果某些算法需要其他"property_maps"作为您的图形类型,则可以以类似的方式定义它们。
祝你好运!
- 1d 智能指针不适用于语法 (*)++
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 用于访问容器<T>数据成员的正确 API
- 重载操作程序时出错>>用于类中的字符串 memebr
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- C++中的cin.ignore()函数不适用于整个流
- 没有用于初始化C++中的变量模板的匹配构造函数
- 用于C++中带有数组和指针的循环
- 为什么它不适用于Visual 2019的原因
- 使用在用于SFINAE的void_t中具有参数的方法
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息
- 重载==不适用于二进制树
- Insert函数不适用于2 if语句C++
- 用于矢量处理的多个线程
- 使外部项目可用于find_package CMake
- 在子目录中使用target_sources()命令时用于单元测试(qtest)的项目结构
- 为什么模数运算符不适用于该代码
- 并行用于C++17中数组索引范围内的循环
- 将fold表达式与std::一起用于两个元组
- 在用于格式4的arm模拟器中实现功能时的一个问题