图的割集,Boost Graph Library

Posted

技术标签:

【中文标题】图的割集,Boost Graph Library【英文标题】:Cut set of a graph, Boost Graph Library 【发布时间】:2014-11-02 08:35:00 【问题描述】:

我一直在努力弄清楚如何做到这一点。我有兴趣快速找到图形的割集。我知道 BGL 支持通过对例如 edmonds_karp_max_flow 支持的 colorMap 参数进行迭代来查找割集。 Gomory Hu 算法需要多次调用最小割算法。

我希望的结果是拥有一个包含以下内容的多图: (颜色,顶点)

以下代码尝试重写 Boost 图形库中的示例,以使用多映射作为 associative_property_map。可以通过以下方式编译代码: clang -lboost_graph -o edmonds_karp edmonds_karp.cpp 或 g++ 而不是 clang。我不明白由此产生的错误。

#include <boost/config.hpp>
#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/edmonds_karp_max_flow.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/read_dimacs.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/unordered_map.hpp>

int main()

  using namespace boost;

  typedef adjacency_list_traits < vecS, vecS, directedS > Traits;
  typedef adjacency_list < listS, vecS, directedS,
    property < vertex_name_t, std::string >,
    property < edge_capacity_t, long,
    property < edge_residual_capacity_t, long,
    property < edge_reverse_t, Traits::edge_descriptor > > > > Graph;

  Graph g;

  property_map < Graph, edge_capacity_t >::type
    capacity = get(edge_capacity, g);
  property_map < Graph, edge_reverse_t >::type rev = get(edge_reverse, g);
  property_map < Graph, edge_residual_capacity_t >::type
    residual_capacity = get(edge_residual_capacity, g);

  std::multimap<default_color_type, Traits::vertex_descriptor> colorMap;
  boost::associative_property_map< std::map<default_color_type,
                                            Traits::vertex_descriptor> >
      color_map(colorMap);

  Traits::vertex_descriptor s, t;
  read_dimacs_max_flow(g, capacity, rev, s, t);

  std::vector<Traits::edge_descriptor> pred(num_vertices(g));
  long flow = edmonds_karp_max_flow
      (g, s, t, capacity, residual_capacity, rev,
       make_iterator_property_map(color_map.begin()),
       &pred[0]);

  std::cout << "c  The total flow:" << std::endl;
  std::cout << "s " << flow << std::endl << std::endl;

  std::cout << "c flow values:" << std::endl;
  graph_traits < Graph >::vertex_iterator u_iter, u_end;
  graph_traits < Graph >::out_edge_iterator ei, e_end;
  for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
    for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
      if (capacity[*ei] > 0)
        std::cout << "f " << *u_iter << " " << target(*ei, g) << " "
          << (capacity[*ei] - residual_capacity[*ei]) << std::endl;

  // if using the original example, unedited, this piece of code works
  // BOOST_FOREACH(default_color_type x, color)
  //   std::cout << x << std::endl;
  // 

  return EXIT_SUCCESS;

提示将不胜感激。谢谢。

【问题讨论】:

According to the documentation,color_map 属性映射需要有一个顶点描述符作为键和一个颜色作为值。在您的示例中,您将这些颠倒了,因此它不起作用(当您只需要使用 color_map 时,您使用 make_iterator_property_map 也是错误的)。 @cv_and_he 原则上,BGL/Boost PropertyMap 的想法是,将选择的数据结构调整为“LvaluePropertyMap”应该是“容易的”。然而,对于这个提议的多映射,存在关键常量(需要代理对象来获得可变性)和(严重)低效率的问题。 @mje 考虑使用Boost BiMap 或只是转换数据。 【参考方案1】:

这是一个基于 Boost BiMap 的快速 PoC

typedef boost::bimap<bimaps::list_of<default_color_type>, bimaps::set_of<Traits::vertex_descriptor> > smart_map;
smart_map colorMap;
boost::associative_property_map<smart_map::right_map> color_map(colorMap.right);

我从http://lpsolve.sourceforge.net/5.5/DIMACS_maxf.htm 中提取了一个小样本,你可以看到它Live On Coliru,输出:

c  The total flow:
s 15

c flow values:
f 0 1 5
f 0 2 10
f 1 3 5
f 1 4 0
f 2 3 5
f 2 4 5
f 3 5 10
f 4 5 5
ltr: 0 -> 5
ltr: 4 -> 0
ltr: 0 -> 1
ltr: 4 -> 2
ltr: 0 -> 3
ltr: 0 -> 4
rtl: 0 -> 4
rtl: 1 -> 0
rtl: 2 -> 4
rtl: 3 -> 0
rtl: 4 -> 0
rtl: 5 -> 0

完整列表:

#include <boost/foreach.hpp>
#include <boost/bimap.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/graph/edmonds_karp_max_flow.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/read_dimacs.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/unordered_map.hpp>

int main() 
    using namespace boost;

    typedef adjacency_list_traits<vecS, vecS, directedS> Traits;
    typedef adjacency_list<
        listS, vecS, directedS, property<vertex_name_t, std::string>,
        property<edge_capacity_t, long,
        property<edge_residual_capacity_t, long, 
        property<edge_reverse_t, Traits::edge_descriptor> > > > Graph;

    Graph g;

    property_map<Graph, edge_capacity_t>::type capacity                   = get(edge_capacity, g);
    property_map<Graph, edge_reverse_t>::type rev                         = get(edge_reverse, g);
    property_map<Graph, edge_residual_capacity_t>::type residual_capacity = get(edge_residual_capacity, g);

    typedef boost::bimap<bimaps::list_of<default_color_type>, bimaps::set_of<Traits::vertex_descriptor> > smart_map;
    smart_map colorMap;
    boost::associative_property_map<smart_map::right_map> color_map(colorMap.right);

    Traits::vertex_descriptor s, t;
    read_dimacs_max_flow(g, capacity, rev, s, t);

    std::vector<Traits::edge_descriptor> pred(num_vertices(g));
    long flow = edmonds_karp_max_flow(
            g, s, t, capacity, residual_capacity, rev,
            color_map, &pred[0]);

    std::cout << "c  The total flow:" << std::endl;
    std::cout << "s " << flow << std::endl << std::endl;

    std::cout << "c flow values:" << std::endl;
    graph_traits<Graph>::vertex_iterator u_iter, u_end;
    graph_traits<Graph>::out_edge_iterator ei, e_end;
    for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
        for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
            if (capacity[*ei] > 0)
                std::cout << "f " << *u_iter << " " << target(*ei, g) << " " << (capacity[*ei] - residual_capacity[*ei])
                          << std::endl;

    for (auto const& e : colorMap.left)  std::cout << "ltr: " << e.first << " -> " << e.second << "\n";
    for (auto const& e : colorMap.right) std::cout << "rtl: " << e.first << " -> " << e.second << "\n";

    return EXIT_SUCCESS;

更新

使用 Boost MultiIndex 创建双向映射:

struct VertexColor 
    Traits::vertex_descriptor vertex;
    boost::default_color_type color;
;

typedef boost::multi_index_container<
    VertexColor,
    bmi::indexed_by<
        bmi::hashed_non_unique<bmi::tag<struct by_color>,  bmi::member<VertexColor, boost::default_color_type, &VertexColor::color> >,
        bmi::ordered_unique   <bmi::tag<struct by_vertex>, bmi::member<VertexColor, Traits::vertex_descriptor, &VertexColor::vertex> >
    >
> smart_map;

现在,使用 Boost Property Map 为 ReadWritePropertyMap 建模:

struct bidi_color_map 
    typedef smart_map::index<by_vertex>::type impl_t;
    bidi_color_map(impl_t& ref) : ref_(&ref) 
    impl_t       &get()        return *ref_; 
    impl_t const &get() const  return *ref_; 
private:
    impl_t* ref_;
;

namespace boost  
    template <> struct property_traits<bidi_color_map> 
        typedef default_color_type          value_type;
        typedef default_color_type          reference;
        typedef Traits::vertex_descriptor   key_type;
        typedef read_write_property_map_tag category;
    ;


boost::property_traits<bidi_color_map>::reference get(bidi_color_map const& idx, boost::property_traits<bidi_color_map>::key_type const& key) 
    auto it = idx.get().find(key);
    if (it != idx.get().end())
        return it->color;
    else
        throw std::range_error("key not found in index");


void put(bidi_color_map& idx, boost::property_traits<bidi_color_map>::key_type const& key, boost::property_traits<bidi_color_map>::value_type val) 
    auto it = idx.get().find(key);
    if (it != idx.get().end())
        idx.get().modify(it, [val](VertexColor& p)  p.color = val; );
    else
        idx.get().insert(key,val);

现在您可以将其作为颜色图传递:

    smart_map colorMap;
    bidi_color_map color_map(colorMap.get<by_vertex>());

也可以看到Live On Coliru

【讨论】:

谢谢! Boost 库相当大,我没有考虑到库的其他部分会解决我的问题。 也许我太快了,无法接受。但我没有看到(我查看了 Boost Bimap 的文档),也没有看到如何快速获取切割集中的顶点列表;我的目标是在 O(1) 时间内做到这一点,但也许我错了。 我认为 bimap 在底层使用了 byres,使其成为 O (log n)。也许它带有基于哈希的药水。如果没有,您当然可以使用 Boost Multi Index 将其组合起来。不过,我不确定您是否会获得净性能提升。请务必使用分析器来验证您的结果 是的,我认为 C++ 中的地图是基于 RB-tree 的。我的目标是实现 Gomory Hu 切割树算法,并且我想坚持算法的运行时,而不增加大量开销(也许我可以使用 O(log n))。我尝试将 list_of 更改为 set_of,但这只会使一切崩溃。再次感谢您的提示! @mje 所以,我用 Boost Multi Index 拼凑了那个东西:Live On Coliru。它使用hashed_non_unique 索引作为地图的颜色侧。我不确定这将如何更有效(我会说有序可能会更快,但您现在可以轻松切换和配置它)。 (PS。我有 cookie 吗?我学会了如何创建自己的 Boost Property Map 适配器来为 ReadWritePropertyMap 建模,耶!)

以上是关于图的割集,Boost Graph Library的主要内容,如果未能解决你的问题,请参考以下文章

弦图

寻找有界子图之间的最小割集

删除顶点并再次添加它会导致 boost::graph 崩溃?

使用 boost 作为向量的元素在图中添加顶点

如何使用 Boost Graph Library 创建 named_graph?

使用Boost Graph库查找连接的组件,顶点和边缘类型为boost :: listS