【问题标题】:boost::get with boost::filtered_graph on adjacency_list with netsed propertiesboost::get with boost::filtered_graph on adjacency_list with netsed properties
【发布时间】:2018-11-26 23:22:21
【问题描述】:

我为boost::adjacency_list写了一个小包装:

    template <typename T>
    using VertexWithIndexProperty =            
          boost::property<boost::vertex_index_t, int, T>;

    template <typename VertexProperty, typename EdgeProperty = 
                                    boost::no_property>
    class MutableGraph  : public boost::adjacency_list< boost::setS, 
                             boost::listS, boost::undirectedS, 
                             VertexWithIndexProperty<VertexProperty>, EdgeProperty> {
    public:
         using BoostBase =
          boost::adjacency_list<boost::setS, boost::listS, boost::undirectedS,
                                VertexWithIndexProperty<VertexProperty>,
                                EdgeProperty>;
      MutableGraph() {}
      MutableGraph(std::size_t n) : BoostBase(n) {}
      MutableGraph(const MutableGraph &rhs) : BoostBase(rhs) {}
      MutableGraph &operator=(const MutableGraph &rhs) {
        static_cast<BoostBase *>(this)->operator=(rhs);
        return *this;
      }
    };

然后我按如下方式使用它:我以集合的形式收集一些 vertex_descriptors 以创建boost::filtered_graph: `

using Graph = MutableGraph<boost::property<vertex_color_t, int>>;
Graph g;

std::set<int> C, H; //vertex_descriptors I collect

...

auto vertex_index_map = get(vertex_index, g);

std::function<bool(vertex_descriptor)> vertexes_filter =
      [&vertex_index_map, &C, &H](vertex_descriptor v) {

        auto index = vertex_index_map[v];
        return C.find(index) != C.end() || H.find(index) != H.end();
      };

   boost::filtered_graph<Graph, boost::keep_all, decltype(crown_vertexes_filter)>
           auxilary(g, boost::keep_all(), crown_vertexes_filter);

一切正常,但是当我尝试获取顶点的任何 property_map 时,例如:`

auto auxilary_vertex_index_map
          = get(boost::vertex_index, auxilary);

我收到以下错误:

could not convert

    boost::adj_list_vertex_property_map<boost::adjacency_list<boost::setS, 
boost::listS, boost::undirectedS, 
boost::property<boost::vertex_index_t, int, 
boost::property<boost::vertex_color_t, int> >, 
boost::no_property, boost::no_property, boost::listS>, int, 
int&, boost::vertex_index_t>

to 

 boost::adj_list_vertex_property_map<MutableGraph<
 boost::property<boost::vertex_color_t, int> >,
 int, 
 int&,
 boost::vertex_index_t>

我收到这个错误

template <typename G, typename EP, typename VP, typename Property>
  typename property_map<G, Property>::type
  get(Property p, filtered_graph<G, EP, VP>& g)
  {
    return get(p, const_cast<G&>(g.m_g));
  }

filtered_graph.hpp.

我不明白为什么会发生这种情况,无论是因为我的包装器还是因为我决定使用嵌套属性而不是捆绑属性。

提前致谢!

【问题讨论】:

  • 我建议 MutableGraph 不是您类型的最佳名称,因为它与 Boost Graph Library 中的概念名称重复。这在错误消息中充其量是令人困惑的。

标签: c++ boost boost-graph adjacency-list


【解决方案1】:

嵌套属性称为“内部属性”。他们不是你的问题。

相反,您的问题在于 VertexContainerSelector 参数 (boost::listS)。它导致vertex_descriptor 类型为

  • 不是整数(现在是不透明类型)
  • 不作为分解顶点索引的两倍

您已经知道这一点,这就是您添加一个属性作为顶点索引图的原因。但是,您没有预料到的是,它使 vertex_index 属性映射 (boost::property_map&lt;Graph, vertex_index_t&gt;::type) 的结果类型不同,因此 filtered_graph 中的转发包装器不再符合要求:

  template <typename G, typename EP, typename VP, typename Property>
  typename property_map<G, Property>::type
  get(Property p, filtered_graph<G, EP, VP>& g)
  {
    return get(p, const_cast<G&>(g.m_g));
  }

如果你有能力只切换到vecS,我会去的。否则,请仔细考虑您的要求和影响。值得注意的是,您对VertexContainerSelectorlistS 选择导致vertex_descriptor 具有引用和迭代器稳定性。 filters_graph 中的任何vertex_descriptor 都应该对主图有效,反之亦然¹。为什么不保持相同的地图:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/graph_utility.hpp> // print_graph

template <typename T> using AddIndex = boost::property<boost::vertex_index_t, int, T>;

template <
    typename VertexProperty,
    typename EdgeProperty = boost::no_property, 
    typename Base = boost::adjacency_list<boost::setS, boost::listS, boost::undirectedS, AddIndex<VertexProperty>, EdgeProperty> >
struct MutableGraph : Base {
    using BoostBase = Base;

    MutableGraph(std::size_t n = 0) : BoostBase(n) {}
    using BoostBase::operator=;
};

int main() {
    using Graph = MutableGraph<boost::property<boost::vertex_color_t, int> >;
    using vertex_descriptor = Graph::vertex_descriptor;
    Graph g;
    auto a = add_vertex({1, 0}, g);
    auto b = add_vertex({2, 0}, g);
    auto c = add_vertex({3, 0}, g);
    auto d = add_vertex({4, 0}, g);
    add_edge(a, b, g);
    add_edge(a, c, g);
    add_edge(b, d, g);

    std::set<int> C{1,2}, H{/*3,*/4}; // vertex_descriptors I collect
    auto id = get(boost::vertex_index, g);
    std::function<bool(vertex_descriptor)> vertexes_filter = [id, &C, &H](vertex_descriptor v) {
        auto index = id[v];
        return C.count(index) || H.count(index);
    };

    boost::filtered_graph<Graph, boost::keep_all, decltype(vertexes_filter)> auxilary(g, boost::keep_all(), vertexes_filter);

    auto aux_id = id;
    print_graph(g,        id,     std::cout << "\n---- Original\n");
    print_graph(auxilary, aux_id, std::cout << "\n---- Filtered\n");
}

打印:

---- Original
1 <--> 2 3 
2 <--> 1 4 
3 <--> 1 
4 <--> 2 

---- Filtered
1 <--> 2 
2 <--> 1 4 
4 <--> 2 

这正是您想要的。

旁注

注意代码中的简化。你的MutableGraph 类可以写成:

template <
    typename VertexProperty,
    typename EdgeProperty = boost::no_property, 
    typename Base = boost::adjacency_list<boost::setS, boost::listS, boost::undirectedS, AddIndex<VertexProperty>, EdgeProperty> >
struct MutableGraph : Base {
    using BoostBase = Base;

    MutableGraph(std::size_t n = 0) : BoostBase(n) {}
    using BoostBase::operator=;
};

尽管在本例中使用这两个成员也可以简单地省略(operator= 仍将由编译器正确生成)。

¹ 除了过滤的那些...

奖金

响应 cmets 的更新:您可以通过专门化 boost::property_map&lt;&gt; 特征来“自动化”类型转发:

namespace boost {
    // overriding the typedef to take the types from the BoostBase instead:
    template <typename Tag, typename... Args>
        struct property_map<MyGraph<Args...>, Tag> : property_map<typename MyGraph<Args...>::BoostBase, Tag> {
        };
}

就是这样。现在您可以在一个不知道它正在处理什么类型的图形的函数中进行打印:

template <typename WhateverGraph>
void some_naive_user_function(WhateverGraph const& g, std::ostream& os) {
    // we don't know whether WhateverGraph is filtered or not, but we don't care
    print_graph(g, get(boost::vertex_index, g), os);
}

get(boost::vertex_index, g) 只是由于专业化而起作用:

boost::filtered_graph<Graph, boost::keep_all, decltype(vertexes_filter)> auxilary(g, boost::keep_all(), vertexes_filter);

some_naive_user_function(g,        std::cout << "\n---- Origina (via naive user function)\n");
some_naive_user_function(auxilary, std::cout << "\n---- Filtered (via naive user function)\n");

Live On Coliru

【讨论】:

  • 实际上选择了 listS 选择器,因为我不需要迭代器/描述符失效,以后我必须删除作为描述符的顶点。
  • 我可能会像往常一样将这个过滤图转发到其他函数中,我需要在那里获取它的属性图。如果不选择 vecS 作为选择器,这可能吗?
  • 我的代码没有显示怎么做吗?我使用vecS作为选择器。
  • 我明白了。但是根据您的示例,我必须转发原始图的 vertex_index_map 才能与过滤后的图一起运行。我能不这样吗?
  • 是的,覆盖 property_map 对我有用!!非常感谢!
猜你喜欢
  • 2016-10-25
  • 2015-12-01
  • 1970-01-01
  • 2015-09-04
  • 1970-01-01
  • 2015-09-01
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
相关资源
最近更新 更多