问题描述
我正在尝试使用 Boost 的 vf2_subgraph_iso
,但我不知道如何正确地将它用于小型无向图。
下面我展示了一个示例,其中具有 4 个顶点的图不是具有 4 个顶点的全连接图的子图(这对我来说似乎很奇怪)。谁能帮助我了解我在这里做错了什么?
我在 Why is Boost VF2 subgraph isomorphism giving an incorrect answer 看到过帖子,这可能是同样的问题。
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
using namespace boost;
int main()
{
typedef adjacency_list<vecS,vecS,undirectedS,no_property> Graph;
// 0---1
// | |
// 2---3
Graph smallGraph;
{
vertex(0,smallGraph);
vertex(1,smallGraph);
vertex(2,smallGraph);
vertex(3,smallGraph);
add_edge(0,1,smallGraph);
add_edge(0,2,smallGraph);
add_edge(2,3,smallGraph);
add_edge(1,smallGraph);
}
Graph largeGraph;
{
vertex(0,largeGraph);
vertex(1,largeGraph);
vertex(2,largeGraph);
vertex(3,largeGraph);
add_edge(0,largeGraph);
add_edge(0,largeGraph);
add_edge(2,largeGraph);
add_edge(1,largeGraph);
}
vf2_print_callback<Graph,Graph> callback(smallGraph,largeGraph);
auto val = vf2_subgraph_iso(smallGraph,largeGraph,callback);
if (val)
std::cout << "Found subgraph." << std::endl;
else
std::cout << "Did not find subgraph." << std::endl;
return 0;
}
从 vf2_subgraph_iso documentation,“两个图 G1=(V1,E1) 和 G2=(V2,E2) 之间的同构是一个图的顶点到另一个图的顶点的双射映射 M图的边结构。当且仅当 M 是 G1 和 G2 的子图之间的同构,M 被称为图-子图同构。"
在我上面的例子中,G2 = largeGraph,G1 = smallGraph,并且存在 G2 的一个子图,使得顶点映射 (0-0,1-1,2-2,3-3) 在子图之间是双射的和 G1。
解决方法
子图同构is defined here as:
两个图 G1=(V1,E1) 和 G2=(V2,E2) 之间的同构是一个图的顶点到另一个图的顶点的双射映射 M,保留了图的边结构>
您希望保留什么映射?我想你可能一直期待 {0 -> 0,1 -> 1,2 -> 2,3 -> 3} 是那个双射顶点映射?
然而,情况并非如此,因为子图缺少参与映射的顶点之间的边。例如。 3 -- 0
不在小图中,使其在结构上有所不同。
TL;DR 当边是严格子集时,子图同构不是。相反,它侧重于映射顶点集。
反例
这是一个反例,它在保留预期映射的同时生成一些随机边缘。请注意,如果给定足够多的随机边,您很可能会遇到意外的同构,因为子图在结构上如此简单:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <iostream>
#include <random>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
using boost::make_iterator_range;
using boost::adaptors::transformed;
using boost::algorithm::all_of;
int main()
{
using Graph =
boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS>;
using V = Graph::vertex_descriptor;
// 0---1
// | |
// 2---3
Graph small(4);
add_edge(0,1,small);
add_edge(0,2,small);
add_edge(2,3,small);
add_edge(1,small);
Graph large(500);
add_edge(100,200,large);
add_edge(100,300,large);
add_edge(300,400,large);
add_edge(200,large);
// helper to recognizes (sets of) vertices from the intended subset
auto all_in_subset = [set = std::set{100,400}](auto... vs) {
return ((0 != set.count(vs)) && ...);
};
// add some random edges for
auto randvertex = std::bind(
std::uniform_int_distribution<V>(0,boost::num_vertices(large) - 1),std::mt19937{std::random_device{}()});
for (int n = 0; n < 400; ++n) {
V src = randvertex();
V tgt = randvertex();
// only add edges outside of the subset - preserving structure
if (!all_in_subset(src,tgt))
add_edge(src,tgt,large);
}
auto callback = [&](auto bijection,auto) {
auto vs = make_iterator_range(vertices(small));
auto mapped =
vs | transformed([&](auto v) { return get(bijection,v); });
if (boost::algorithm::all_of(mapped,all_in_subset)) {
std::cout << "In subset: ";
} else {
std::cout << "Random match: ";
}
for (auto v : vs) {
std::cout << '(' << v << " -> " << get(bijection,v) << ") ";
}
std::cout << std::endl;
return true;
};
bool found = boost::vf2_subgraph_iso(small,large,callback);
std::cout << "Found subgraph:" << std::boolalpha << found << std::endl;
}
打印例如
In subset: (0 -> 100) (1 -> 200) (2 -> 300) (3 -> 400)
In subset: (0 -> 100) (1 -> 300) (2 -> 200) (3 -> 400)
Random match: (0 -> 122) (1 -> 268) (2 -> 454) (3 -> 128)
Random match: (0 -> 122) (1 -> 454) (2 -> 268) (3 -> 128)
Random match: (0 -> 128) (1 -> 268) (2 -> 454) (3 -> 122)
Random match: (0 -> 128) (1 -> 454) (2 -> 268) (3 -> 122)
In subset: (0 -> 200) (1 -> 100) (2 -> 400) (3 -> 300)
In subset: (0 -> 200) (1 -> 400) (2 -> 100) (3 -> 300)
Random match: (0 -> 220) (1 -> 234) (2 -> 367) (3 -> 340)
Random match: (0 -> 220) (1 -> 367) (2 -> 234) (3 -> 340)
Random match: (0 -> 234) (1 -> 220) (2 -> 340) (3 -> 367)
Random match: (0 -> 234) (1 -> 340) (2 -> 220) (3 -> 367)
Random match: (0 -> 268) (1 -> 122) (2 -> 128) (3 -> 454)
Random match: (0 -> 268) (1 -> 128) (2 -> 122) (3 -> 454)
In subset: (0 -> 300) (1 -> 100) (2 -> 400) (3 -> 200)
In subset: (0 -> 300) (1 -> 400) (2 -> 100) (3 -> 200)
Random match: (0 -> 340) (1 -> 234) (2 -> 367) (3 -> 220)
Random match: (0 -> 340) (1 -> 367) (2 -> 234) (3 -> 220)
Random match: (0 -> 367) (1 -> 220) (2 -> 340) (3 -> 234)
Random match: (0 -> 367) (1 -> 340) (2 -> 220) (3 -> 234)
In subset: (0 -> 400) (1 -> 200) (2 -> 300) (3 -> 100)
In subset: (0 -> 400) (1 -> 300) (2 -> 200) (3 -> 100)
Random match: (0 -> 454) (1 -> 122) (2 -> 128) (3 -> 268)
Random match: (0 -> 454) (1 -> 128) (2 -> 122) (3 -> 268)
Found subgraph:true
或者,取决于运气,只是预期:Live
In subset: (0 -> 100) (1 -> 200) (2 -> 300) (3 -> 400)
In subset: (0 -> 100) (1 -> 300) (2 -> 200) (3 -> 400)
In subset: (0 -> 200) (1 -> 100) (2 -> 400) (3 -> 300)
In subset: (0 -> 200) (1 -> 400) (2 -> 100) (3 -> 300)
In subset: (0 -> 300) (1 -> 100) (2 -> 400) (3 -> 200)
In subset: (0 -> 300) (1 -> 400) (2 -> 100) (3 -> 200)
In subset: (0 -> 400) (1 -> 200) (2 -> 300) (3 -> 100)
In subset: (0 -> 400) (1 -> 300) (2 -> 200) (3 -> 100)
Found subgraph:true