使用列入黑名单的边提升过滤图

Posted

技术标签:

【中文标题】使用列入黑名单的边提升过滤图【英文标题】:Boost filtered graph with blacklisted edges 【发布时间】:2017-08-07 20:02:22 【问题描述】:

我想在边缘被列入黑名单的图上运行 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;

结构 BlackListEdgeConstraint 私人的: 标准::设置黑名单; graph_t* g;

public:

    BlackListEdgeConstraint():blackList(std::set<Edge>() ),g(NULL);

    BlackListEdgeConstraint(std::set<Edge>& list, graph_t* g_) : blackList(list), g(g_)
    
    

    /**
     * This is the "predicate function" used by boost::filtered_graph (
     *  see http://www.boost.org/doc/libs/1_64_0/libs/graph/doc/filtered_graph.html )
     *  It it returns true, the edge is included in the filtered graph, otherwise it is excluded.
     */
    bool operator()(const boost::graph_traits<graph_t>::edge_descriptor& e) const
    
        Edge edge(source(e,*g), target(e,*g) );
        //Include the edge if it's not in the blacklist.
        return blackList.find( edge ) == blackList.end();
    
;

然后我在 5 月执行此操作 main(...) 函数

... 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 ...

现在,我所做的工作有效,但很奇怪。实际上,我首先在顶点 0 和 1 之间创建了一条边。然后,在 operator() (...) 内部,我有一个 edge_descriptor 而不是 Edge(如果我将 Edge 作为参数,编译器会按照 here 的解释进行抱怨,所以我猜boost 正在某处进行一些转换,原因我不知道)。然后,我再次检索operator() (...) 中的顶点 0 和 1,并重建 Edge。您知道,如果直接接受 operator()(..) Edge,我会花很长时间做一些简单的事情。

你认为我可以以更优雅、更高效的方式完成相同的操作吗?

【问题讨论】:

【参考方案1】:

你基本上问什么与提升图关系不大。您希望能够高效地查找一对顶点描述符。

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

附带说明,您Edge 对象插入到图表中。您选择的图模型是一个邻接列表,因此它存储每个顶点的相邻顶点列表。

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

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

在某些较大的规模上,您可能会获得更高的有效性能

使用本身表示为邻接列表的黑名单(例如std::map&lt;source_vertex, std::list&lt;target_vertex&gt; &gt;)或 使用unordered_set&lt;&gt;

除非大规模进行,否则这两种优化都不太可能产生显着差异。

通过使用boost::container::flat_set,您可能会受益于参考位置

成本真实吗?

如果您认为“构造 Edge”是一种资源浪费,请忘记这一点:它是一种 POD 类型 (std::pair&lt;int, int&gt;),因此只有微不足道的构造函数/析构函数。看到set&lt;Edge&gt;是一个模板类,对它的大部分操作都可以内联。编译器将内联方法调用、注册参数、删除多余的加载/存储周期并有效地生成最佳代码:

#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);
    
;

View Disassembly Live On Godbolt GCC Explorer

专业提示:点击 Clang 反汇编上的 # 按钮查看优化器 cmets

总结 Edge 类型的成本不存在。任何实际成本都取决于在edge_descriptor 上使用boost::source()boost::target()

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

如果您不喜欢该成本,请调整 Graph 类型 :)(您的用例可能需要使用 EdgeList 概念,或者受益于使用基于节点的边缘容器等)。

【讨论】:

以上是关于使用列入黑名单的边提升过滤图的主要内容,如果未能解决你的问题,请参考以下文章

javascript 允许在Adblock Plus中将特定频道列入白名单,方法是在URL中添加频道名称,并构建过滤器以添加自定义过滤器

在express,node.js中使用req.ip将IP地址列入白名单是不是安全?

仅因为AI 图像识别技术先进,这些企业就被美国列入"黑名单"?

将 JSON Web 令牌列入黑名单

如何使用 Simple JWT(django rest)将 JWT 令牌列入黑名单?

使用 Laravel JWT 重新认证时将旧令牌列入黑名单