Boost Graph Library图生成函数问题

huangapple go评论74阅读模式
英文:

Boost Graph Library graph generation function issues

问题

我一直在尝试学习一些图论,用于一个个人项目。我还尝试使用Boost图形库来执行这些任务。
下面的函数是尝试使用提供的random_spanning_tree函数生成生成生成树图,然后随机连接它们的部分,但我无法让提供的函数以有效的方式返回前任映射。

目前,我声明前任映射并将其传递给random_spanning_tree函数。输出不是我期望的。使用gdb,我可以确定数据结构只是make_connected函数构建的简单连接线图的数据结构,以及我假设所有数据都保存在第0个单元中的大数字。为了更清晰地说明,我已经包含了调试输出的图像。显然,我要么没有正确初始化或正确传递前任映射,因为所有数据都保存在第一个单元中。是否有人知道我哪里出错了吗?
非常感谢任何帮助,因为我已经尝试了大部分一天的时间。

在运行random_spanning_tree函数后前任映射数据的图像:
gdb监视变量

源代码:

struct VertexData
{
    int num;
    int pred;
    int dist;
};

struct EdgeData
{
    double dist;
};

typedef adjacency_matrix<undirectedS, VertexData, EdgeData> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;

Graph generateConnectedGraph2(int numVertices, double connectionProbability) {
    Graph graph(numVertices);
    std::random_device rand;
    random::minstd_rand gen(rand()); //带种子的随机数生成器

    make_connected(graph);

    //为随机生成的生成树构建一个最小连接图

    std::vector<double> xPos(num_vertices(graph));
    std::vector<double> yPos(num_vertices(graph));

    bool isPlanar = false;

    std::vector<Vertex> predecessor(numVertices);  //前任映射
    predecessor[0] = 0;  //将根顶点设置为0
    //生成随机边以创建连接图
    random_spanning_tree(graph, gen, predecessor_map(make_iterator_property_map(predecessor.begin(), get(vertex_index, graph))));

    printAdjMatrix(graph, numVertices);

    applyPredecessorMap(graph, predecessor);
    printAdjMatrix(graph, numVertices);

    //遍历每一对顶点,可能添加一条边
    for (Vertex u = 0; u < numVertices; ++u) {
        for (Vertex v = u + 1; v < numVertices; ++v) {
            if (u != v && u != numVertices && !edge(u, v, graph).second && random::bernoulli_distribution<>(connectionProbability)(gen)) {
                add_edge(u, v, graph);
            }
        }
    }

    return graph;
}

void applyPredecessorMap(Graph& graph, const std::vector<Vertex>& predecessor) {
    int numVertices = num_vertices(graph);

    for (Vertex v = 1; v < numVertices; ++v) {
        Vertex u = predecessor[v];
        add_edge(u, v, graph);
    }
}
英文:

Ive been attempting to learn some graph theory for a personal project. I'm also trying to use the Boost Graph Library to perform these tasks.
The function below is an attempt to generate spanning tree graphs using the provided random_spanning_tree function and then connect parts of them randomly, but I cannot get the provided function to return the predecessor map in a working way.

Currently I declare the predecessor map and pass it into the random_spanning_tree function. the output is not what I am expecting. Using gdb, I can determine that the data structure is just that of the simply connected line graph the make_connected function builds, as well as large number which is what im assuming all of my data is being saved into in the 0th cell. I have included an image of the debug output for clarity. Clearly I am either not initializing or passing in the predecessor map correctly as all of my data is being saved into the first cell. Does anyone have any idea where I am going wrong?
Any help is greatly appreciated as Ive been trying to figure this out for the better part of a day.

image of predecessor map data after running the random_spanning_tree function:
gdb watched variable

Boost Graph Library图生成函数问题

Source:


struct VertexData
{
    int num;
    int pred;
    int dist;
};

struct EdgeData
{
    double dist;
};

typedef adjacency_matrix&lt;undirectedS, VertexData, EdgeData &gt; Graph;
typedef graph_traits&lt;Graph&gt;::vertex_descriptor Vertex;

Graph generateConnectedGraph2(int numVertices, double connectionProbability) {
    Graph graph(numVertices);
    std::random_device rand;
    random::minstd_rand gen(rand()); //Seeded Random number generator

    make_connected(graph);

    //build a minimally connected graph for the random spanning tree

    std::vector&lt;double&gt; xPos(num_vertices(graph));
    std::vector&lt;double&gt; yPos(num_vertices(graph));

    bool isPlanar = false;

    std::vector&lt;Vertex&gt; predecessor(numVertices);  // Predecessor map
    predecessor[0] = 0;  // Set the root vertex to 0
    // Generate random edges to create a connected graph
    random_spanning_tree(graph, gen, predecessor_map(make_iterator_property_map(predecessor.begin(), get(vertex_index, graph) )));
    
    printAdjMatrix(graph, numVertices);
    
    applyPredecessorMap(graph, predecessor);
    printAdjMatrix(graph, numVertices);
    
    // Iterate over each pair of vertices and potentially add an edge
    for (Vertex u = 0; u &lt; numVertices; ++u) {
        for (Vertex v = u + 1; v &lt; numVertices; ++v) {
            if (u != v &amp;&amp; u != numVertices &amp;&amp; !edge(u, v, graph).second &amp;&amp; random::bernoulli_distribution&lt;&gt;(connectionProbability)(gen)) {
                add_edge(u, v, graph);
            }
        }
    }
    
    return graph;
}

void applyPredecessorMap(Graph&amp; graph, const std::vector&lt;Vertex&gt;&amp; predecessor) {
    int numVertices = num_vertices(graph);

    for (Vertex v = 1; v &lt; numVertices; ++v) {
        Vertex u = predecessor[v];
        add_edge(u, v, graph);
    }
}

答案1

得分: 1

您的代码完全按预期工作。 "大数字" 不是随机的。它是表示第一个顶点没有前驱的特殊值:

assert(predecessor.at(vertex(0, graph)) == graph.null_vertex());

同时,您找到了一棵生成树,但根据定义,它只能由已经存在于图中的边组成,因此 applyPredecessor 不应该产生影响,除非您选择另一个允许重复边的图模型。

以下是代码的扩展部分,其中包含一些输出,以显示所有内容如何运作:

Live On Coliru

#include <boost/graph/adjacency_matrix.hpp>
#include <boost/graph/make_connected.hpp>
#include <boost/graph/random_spanning_tree.hpp>
#include <boost/graph/graph_utility.hpp>
#include <random>
#include <fmt/ranges.h>
struct VertexData {
    int num;
    int pred;
    int dist;
};

struct EdgeData {
    double dist;
};

using Graph  = boost::adjacency_matrix<boost::undirectedS, VertexData, EdgeData>;
using Vertex = Graph::vertex_descriptor;

void applyPredecessorMap(Graph& graph, std::vector<Vertex> const& predecessor) {
    size_t numVertices = num_vertices(graph);

    for (Vertex v = 1; v < numVertices; ++v) {
        Vertex u = predecessor[v];
        add_edge(u, v, graph);
    }
}

Graph generateConnectedGraph2(size_t numVertices, double connectionProbability) {
    Graph graph(numVertices);
    std::random_device rand;
    std::minstd_rand gen(rand()); // Seeded Random number generator

    make_connected(graph);
    auto const original = graph;

    // Build a minimally connected graph for the random spanning tree
    std::vector<double> xPos(num_vertices(graph));
    std::vector<double> yPos(num_vertices(graph));

    std::vector<Vertex> predecessor(numVertices); // Predecessor map
    fmt::print("predecessor constructed: {}\n", predecessor);
    predecessor[0] = 0;                           // Set the root vertex to 0
    fmt::print("predecessor initialized: {}\n", predecessor);

    // Generate random edges to create a connected graph
    random_spanning_tree(
        std::as_const(graph), gen,
        predecessor_map(make_iterator_property_map(predecessor.begin(), get(boost::vertex_index, graph))));

    fmt::print("predecessor spanning: {}\n", predecessor);
    // Vertex 0 doesn't have a predecessor
    assert(predecessor.at(vertex(0, graph)) == graph.null_vertex());

    print_graph(graph, std::cout << "Graph:\n");

    applyPredecessorMap(graph, predecessor);
    print_graph(graph, std::cout << "Graph with predecessors applied:\n");

    // Iterate over each pair of vertices and potentially add an edge
    std::bernoulli_distribution dist(connectionProbability);

    for (Vertex u = 0; u < numVertices; ++u) {
        for (Vertex v = u + 1; v < numVertices; ++v) {
            if (u != v && u != numVertices && !edge(u, v, graph).second && dist(gen)) {
                add_edge(u, v, graph);
            }
        }
    }

    print_graph(graph, std::cout << "Graph with random edges added:\n");

    return graph;
}

int main() {
    generateConnectedGraph2(10, 0.2);
}

输出示例:

predecessor constructed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
predecessor initialized: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
predecessor spanning: [18446744073709551615, 0, 1, 2, 3, 4, 5, 6, 7, 8]
Graph:
0 <--> 1 
1 <--> 0 2 
2 <--> 1 3 
3 <--> 2 4 
4 <--> 3 5 
5 <--> 4 6 
6 <--> 5 7 
7 <--> 6 8 
8 <--> 7 9 
9 <--> 8 
Graph with predecessors applied:
0 <--> 1 
1 <--> 0 2 
2 <--> 1 3 
3 <--> 2 4 
4 <--> 3 5 
5 <--> 4 6 
6 <--> 5 7 
7 <--> 6 8 
8 <--> 7 9 
9 <--> 8 
Graph with random edges added:
0 <--> 1 6 9 
1 <--> 0 2 
2 <--> 1 3 6 
3 <--> 2 4 6 7 
4 <--> 3 5 8 
5 <--> 4 6 9 
6 <--> 0 2 3 5 7 
7 <--> 3 6 8 
8 <--> 4 7 9 
9 <--> 0 5 8 

或多次运行。

英文:

Your code is working entirely as expected. The "large number" isn't random. It is the special value indicating that the first vertex has no predecessor:

assert(predecessor.at(vertex(0, graph)) == graph.null_vertex());

Meanwhile, you find a spanning tree, but it can, by definition, only consist of edges already in the graph, so applyPredecessor should not have an effect, unless you choose another graph model that allows duplicate edges.

Here's the code extended with a bit of output showing exactly how and that it all works:

Live On Coliru

#include &lt;boost/graph/adjacency_matrix.hpp&gt;
#include &lt;boost/graph/make_connected.hpp&gt;
#include &lt;boost/graph/random_spanning_tree.hpp&gt;
#include &lt;boost/graph/graph_utility.hpp&gt;
#include &lt;random&gt;
#include &lt;fmt/ranges.h&gt;
struct VertexData {
int num;
int pred;
int dist;
};
struct EdgeData {
double dist;
};
using Graph  = boost::adjacency_matrix&lt;boost::undirectedS, VertexData, EdgeData&gt;;
using Vertex = Graph::vertex_descriptor;
void applyPredecessorMap(Graph&amp; graph, std::vector&lt;Vertex&gt; const&amp; predecessor) {
size_t numVertices = num_vertices(graph);
for (Vertex v = 1; v &lt; numVertices; ++v) {
Vertex u = predecessor[v];
add_edge(u, v, graph);
}
}
Graph generateConnectedGraph2(size_t numVertices, double connectionProbability) {
Graph graph(numVertices);
std::random_device rand;
std::minstd_rand gen(rand()); //Seeded Random number generator
make_connected(graph);
auto const original = graph;
//build a minimally connected graph for the random spanning tree
std::vector&lt;double&gt; xPos(num_vertices(graph));
std::vector&lt;double&gt; yPos(num_vertices(graph));
// bool isPlanar = false;
std::vector&lt;Vertex&gt; predecessor(numVertices); // Predecessor map
fmt::print(&quot;predecessor constructed: {}\n&quot;, predecessor);
predecessor[0] = 0;                           // Set the root vertex to 0
fmt::print(&quot;predecessor initialized: {}\n&quot;, predecessor);
// Generate random edges to create a connected graph
random_spanning_tree(
std::as_const(graph), gen,
predecessor_map(make_iterator_property_map(predecessor.begin(), get(boost::vertex_index, graph))));
fmt::print(&quot;predecessor spanning: {}\n&quot;, predecessor);
// v 0 doesn&#39;t have a predecessor
assert(predecessor.at(vertex(0, graph)) == graph.null_vertex());
print_graph(graph, std::cout &lt;&lt; &quot;Graph:\n&quot;);
applyPredecessorMap(graph, predecessor);
print_graph(graph, std::cout &lt;&lt; &quot;Graph with predecessors applied:\n&quot;);
// Iterate over each pair of vertices and potentially add an edge
std::bernoulli_distribution dist(connectionProbability);
for (Vertex u = 0; u &lt; numVertices; ++u) {
for (Vertex v = u + 1; v &lt; numVertices; ++v) {
if (u != v &amp;&amp; u != numVertices &amp;&amp; !edge(u, v, graph).second &amp;&amp; dist(gen)) {
add_edge(u, v, graph);
}
}
}
print_graph(graph, std::cout &lt;&lt; &quot;Graph with random edges added:\n&quot;);
return graph;
}
int main() {
generateConnectedGraph2(10, 0.2);
}

Printing e.g.

predecessor constructed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
predecessor initialized: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
predecessor spanning: [18446744073709551615, 0, 1, 2, 3, 4, 5, 6, 7, 8]
Graph:
0 &lt;--&gt; 1 
1 &lt;--&gt; 0 2 
2 &lt;--&gt; 1 3 
3 &lt;--&gt; 2 4 
4 &lt;--&gt; 3 5 
5 &lt;--&gt; 4 6 
6 &lt;--&gt; 5 7 
7 &lt;--&gt; 6 8 
8 &lt;--&gt; 7 9 
9 &lt;--&gt; 8 
Graph with predecessors applied:
0 &lt;--&gt; 1 
1 &lt;--&gt; 0 2 
2 &lt;--&gt; 1 3 
3 &lt;--&gt; 2 4 
4 &lt;--&gt; 3 5 
5 &lt;--&gt; 4 6 
6 &lt;--&gt; 5 7 
7 &lt;--&gt; 6 8 
8 &lt;--&gt; 7 9 
9 &lt;--&gt; 8 
Graph with random edges added:
0 &lt;--&gt; 1 6 9 
1 &lt;--&gt; 0 2 
2 &lt;--&gt; 1 3 6 
3 &lt;--&gt; 2 4 6 7 
4 &lt;--&gt; 3 5 8 
5 &lt;--&gt; 4 6 9 
6 &lt;--&gt; 0 2 3 5 7 
7 &lt;--&gt; 3 6 8 
8 &lt;--&gt; 4 7 9 
9 &lt;--&gt; 0 5 8 

Or repeated runs:

Boost Graph Library图生成函数问题

huangapple
  • 本文由 发表于 2023年6月26日 09:53:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76553115.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定