简体   繁体   English

我正在使用 boost::filtered_graph,但是 print_graph 和 write_graphviz 的 output 不同——知道为什么吗?

[英]I'm using boost::filtered_graph, but the output of print_graph and write_graphviz differ -- any idea why?

I'm new to boost::graph (and boost really).我是boost::graph的新手(真的是boost )。 I want to use boost::filtered_graph many times on the same original graph, and use the write_graphviz function to let me visualise the results.我想在同一个原始图上多次使用boost::filtered_graph ,并使用write_graphviz function 让我可视化结果。 I think my understanding must be off though because the following code isn't doing what I think it should: to output the same graph with print_graph and write_graphviz .我认为我的理解一定是错误的,因为以下代码没有按照我认为应该的方式进行:到 output 与print_graphwrite_graphviz相同的图形。

MWE (compiled with C++14, gcc 9.3 on Ubuntu 20.04; boost version 1.73): MWE(使用 C++14、gcc 9.3 在 Ubuntu 20.04 上编译;boost 版本 1.73):

#include <cstdio>
#include <fstream>
#include <iostream>

#include <boost/graph/copy.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/graphviz.hpp>

using namespace std;

typedef boost::adjacency_list< boost::vecS, boost::vecS > Graph;

typedef boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Graph>::vertex_iterator vertex_iterator;

template <typename GraphType>
struct uniform_random_vertex_filter
{
    uniform_random_vertex_filter() : prob(1.0) {}   // default constructor is required
    uniform_random_vertex_filter(float p) : prob(p) {}
    bool operator()(const typename boost::graph_traits<GraphType>::vertex_descriptor& v) const
    {
        return drand48() < prob; // randomly select some vertices
    }
private:
    float prob;
};

int main(int argn, char **argc) {
    unsigned int n = 5;
    ofstream of;
    Graph g(n);
    vertex_iterator vit, uit, vend;
    // build a complete graph on n vertices (I'm sure there's a simpler command for this):
    for (boost::tie(vit,vend) = vertices(g); vit != vend; ++vit) {
        for (uit = vit; uit != vend; ++uit) {
            if (uit == vit) { continue; }
            add_edge(*vit, *uit, g);
        }
    }
    std::cout << "Original graph (OriginalGraph.dot):" << std::endl;
    boost::print_graph(g);
    of.open("OriginalGraph.dot", std::ios::trunc);
    boost::write_graphviz(of, g);
    of.close();

    uniform_random_vertex_filter<Graph> vfilter(0.5);

    boost::filtered_graph<Graph, boost::keep_all, uniform_random_vertex_filter<Graph> >
        filteredGraph(g, boost::keep_all(), vfilter);
    std::cout << "Filtered graph -- random selection of vertices (RandomVertexSelection.dot):" << std::endl;
    boost::print_graph(filteredGraph);
    Graph F;
    boost::copy_graph(filteredGraph,F);
    of.open("RandomVertexSelection.dot", std::ios::trunc);
    boost::write_graphviz(of, F);
    of.close();
    return 0;
}

Which produces this output:产生这个 output:

> Debug/BoostGraphFilter
Original graph:
0 --> 1 2 3 4 
1 --> 2 3 4 
2 --> 3 4 
3 --> 4 
4 --> 
Filtered graph -- random selection of vertices (RandomVertexSelection.dot):
0 --> 1 2 3 4 
1 --> 2 3 
2 --> 3 
>

--- which is fine, but the dot files are: --- 这很好,但是点文件是:

> cat OriginalGraph.dot 
digraph G {
0;
1;
2;
3;
4;
0->1 ;
0->2 ;
0->3 ;
0->4 ;
1->2 ;
1->3 ;
1->4 ;
2->3 ;
2->4 ;
3->4 ;
}
> cat RandomVertexSelection.dot
digraph G {
0;
1;
2;
}

Hence the filtered_graph that's printed isn't the same as that written to .dot file (which has lost all the edges in this case).因此,打印的 filtered_graph 与写入.dot文件的不同(在本例中丢失了所有边)。

Can someone please help me understand what I've done wrong?有人可以帮我理解我做错了什么吗?

Your filter is random.你的过滤器是随机的。 And since you didn't retain any state to make it transparent or deterministic, the results are random.由于您没有保留任何 state 以使其透明或确定,因此结果是随机的。 Simple as that.就那么简单。

Ironically, at the same time you managed to get completely deterministic results across runs because you fail to use random correctly (eg seeding the generator).具有讽刺意味的是,同时您设法在运行中获得完全确定的结果,因为您未能正确使用随机(例如为生成器播种)。

In your case, the simplest would be to copy before first use: Live On Coliru在您的情况下,最简单的方法是在首次使用前复制: Live On Coliru

using Graph = boost::adjacency_list<boost::vecS, boost::vecS>;

Graph make_complete_graph(size_t n);
void  report(Graph const& g, std::string name);

struct uniform_random_vertex_filter {
    float prob = 1.0f;
    bool  operator()(auto v) const {
        return drand48() < prob;
    }
};

int main() {
    Graph g = make_complete_graph(5);

    report(g, "OriginalGraph");

    for (int pct = 30; pct < 100; pct+=10) {
        Graph F;

        boost::copy_graph(boost::filtered_graph( //
                              g,                 //
                              boost::keep_all{},
                              uniform_random_vertex_filter{pct / 100.0f}),
                          F);

        report(F, "RandomVertexSelection_" + std::to_string(pct));
    }
}

// build a complete graph on n vertices
Graph make_complete_graph(size_t n)
{
    Graph g(n);
    for (auto [vit, vend] = vertices(g); vit != vend; ++vit) {
        for (auto uit = vit; uit != vend; ++uit) {
            if (uit != vit)
                add_edge(*vit, *uit, g);
        }
    }
    return g;
}

void report(Graph const& g, std::string name) {
    boost::print_graph(g, std::cout << name << ":");

    std::ofstream of(name + ".dot");
    boost::write_graphviz(of, g);
}

If you want a stable random "cut" of a graph, make the filter stateful.如果您想要图形的稳定随机“切割”,请使过滤器有状态。 This could be handy eg if you have a graph too large to copy.这可能很方便,例如,如果您的图形太大而无法复制。

Fixing The Random修复随机

As a sidenote, fixing the random to actually be seeded and reliably uniform:作为旁注,将随机数固定为实际播种并可靠地统一:

Live On Coliru生活在 Coliru

#include <boost/graph/copy.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/graphviz.hpp>
#include <fstream>
#include <iostream>
#include <random>

using Graph = boost::adjacency_list<boost::vecS, boost::vecS>;
using Filter = std::function<bool(Graph::vertex_descriptor)>;

Graph make_complete_graph(size_t n);
void  report(Graph const& g, std::string name);

int main() {
    Graph g = make_complete_graph(5);

    report(g, "OriginalGraph");

    std::mt19937 urbg{std::random_device{}()};

    for (int pct = 30; pct < 100; pct += 10) {
        Graph F;
        std::bernoulli_distribution dist(pct / 100.);
        boost::copy_graph(
            boost::filtered_graph(g, boost::keep_all{},
                Filter([&](auto) { return dist(urbg); })),
            F);

        report(F, "RandomVertexSelection_" + std::to_string(pct));
    }
}

// build a complete graph on n vertices
Graph make_complete_graph(size_t n)
{
    Graph g(n);
    for (auto [vit, vend] = vertices(g); vit != vend; ++vit) {
        for (auto uit = vit; uit != vend; ++uit) {
            if (uit != vit)
                add_edge(*vit, *uit, g);
        }
    }
    return g;
}

void report(Graph const& g, std::string name) {
    boost::print_graph(g, std::cout << name << ":");

    std::ofstream of(name + ".dot");
    boost::write_graphviz(of, g);
}

Now prints different random cuts every run.现在每次运行都会打印不同的随机切口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM