簡體   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?

我是boost::graph的新手(真的是boost )。 我想在同一個原始圖上多次使用boost::filtered_graph ,並使用write_graphviz function 讓我可視化結果。 我認為我的理解一定是錯誤的,因為以下代碼沒有按照我認為應該的方式進行:到 output 與print_graphwrite_graphviz相同的圖形。

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;
}

產生這個 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 
>

--- 這很好,但是點文件是:

> 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;
}

因此,打印的 filtered_graph 與寫入.dot文件的不同(在本例中丟失了所有邊)。

有人可以幫我理解我做錯了什么嗎?

你的過濾器是隨機的。 由於您沒有保留任何 state 以使其透明或確定,因此結果是隨機的。 就那么簡單。

具有諷刺意味的是,同時您設法在運行中獲得完全確定的結果,因為您未能正確使用隨機(例如為生成器播種)。

在您的情況下,最簡單的方法是在首次使用前復制: 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);
}

如果您想要圖形的穩定隨機“切割”,請使過濾器有狀態。 這可能很方便,例如,如果您的圖形太大而無法復制。

修復隨機

作為旁注,將隨機數固定為實際播種並可靠地統一:

生活在 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);
}

現在每次運行都會打印不同的隨機切口。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM