C++ 具有黑名单边的Boost过滤图

C++ 具有黑名单边的Boost过滤图,c++,performance,boost-graph,C++,Performance,Boost Graph,我想在有黑名单边的图上运行Dijkstra,也就是说,我想计算不使用这些链接的最短路径。 目前,我首先定义过滤器: typedef std::pair<int, int> Edge; typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, boost::property<boost::edge_weight_t, int> >

我想在有黑名单边的图上运行Dijkstra,也就是说,我想计算不使用这些链接的最短路径。 目前,我首先定义过滤器:

typedef std::pair<int, int> Edge;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, boost::property<boost::edge_weight_t, int> > graph_t;
现在,我所做的很有效,但很奇怪。实际上,我首先在顶点0和1之间创建一条边。然后,在
操作符()(…)
中,我有一个
边描述符,而不是
边(
)(如果我把边作为参数,编译器会像解释的那样抱怨,所以我猜
boost
在某处执行一些转换,原因我不知道)。然后,我再次检索
操作符()(…)
内的顶点0和1,并重建
边。您知道,我要花很长的时间来做一些事情,只要
操作符()(..)
直接接受
边缘


您认为我可以以更优雅、更高效的方式执行相同的操作吗?

您基本上要求的与boost graph无关。您希望能够高效地查找一对顶点描述符

决定因素将是黑名单数据结构的选择

作为旁注,您不在图形中插入
Edge
对象。您选择的图形模型是一个邻接列表,因此它存储每个顶点的相邻顶点列表

只是一种方便的类型,用于轻松初始化图形。你完全可以不用它

在考虑了可能的选择之后,我认为没有更快的方法

  • 在某些大范围内,您可能会获得更高的有效性能

    • 使用本身表示为邻接列表的黑名单(例如
      std::map
      )或
    • 要使用
      无序集
    这两种优化不太可能产生显著的差异,除非是大规模的

  • 通过使用
    boost::container::flat\u集,您可能会受益于引用的局部性

成本是真实的吗? 如果您认为“构造
边缘
”是一种资源浪费,那么请忘记这一点:它是一种POD类型(
std::pair
),因此只有微不足道的构造函数/析构函数。鉴于
set
是一个模板类,它上的大多数操作都可以内联。编译器将内联方法调用、注册参数、删除冗余加载/存储周期并有效生成最佳代码:

#include <set>
#include <utility>

using Edge = std::pair<int, int>;
using Blacklist = std::set<Edge>;

struct Pred {
    Blacklist blacklist { { 
        { 92, 29 },
        { 74, 92 },
        { 86, 6 },
        { 67, 35 },
        { 59, 4 },
        { 66, 13 },
        { 82, 37 },
        { 51, 94 },
        { 32, 6 }
    } };

    bool operator()(int source, int target) const {
        return blacklist.end() != blacklist.find(Edge {source, target});
    }
};
#包括
#包括
使用Edge=std::pair;
使用黑名单=std::set;
结构预测{
黑名单黑名单{
{ 92, 29 },
{ 74, 92 },
{ 86, 6 },
{ 67, 35 },
{ 59, 4 },
{ 66, 13 },
{ 82, 37 },
{ 51, 94 },
{ 32, 6 }
} };
布尔运算符()(int源,int目标)常量{
返回blacklist.end()!=blacklist.find(边{source,target});
}
};

专业提示:单击叮当声反汇编上的
#
按钮查看优化器注释

摘要边缘
类型的成本不存在。任何实际成本都将取决于在
edge\u描述符上使用
boost::source()
boost::target()

看到您的边缘容器选择器是
列表
,您的边缘容器是基于节点的,这意味着边缘描述符是稳定的,基本上是对边缘对象的类型擦除引用。调用
boost::source(e,g)
只不过是转换描述符和取消引用。根据它的使用方式,编译器甚至可以看穿这些间接指令

如果这一成本不符合您的喜好,请调整图形类型:)(您的用例可能需要使用EdgeList概念,或者使用基于节点的边缘容器等

... I fill the graph g ...
std::set<Edge> blacklist; blacklist.insert( Edge(0,1)  );
BlackListEdgeConstraint filter(blacklist, &g);
boost::filtered_graph<graph_t, BlackListEdgeConstraint> filtered(g, filter);
... I run Dikjstra on the filtered graph ...
#include <set>
#include <utility>

using Edge = std::pair<int, int>;
using Blacklist = std::set<Edge>;

struct Pred {
    Blacklist blacklist { { 
        { 92, 29 },
        { 74, 92 },
        { 86, 6 },
        { 67, 35 },
        { 59, 4 },
        { 66, 13 },
        { 82, 37 },
        { 51, 94 },
        { 32, 6 }
    } };

    bool operator()(int source, int target) const {
        return blacklist.end() != blacklist.find(Edge {source, target});
    }
};