Boost Graph Library:添加具有相同标识的顶点

发布于 2025-01-14 12:12:21 字数 146 浏览 6 评论 0原文

如何使用 BGL 表示文件路径? 考虑这样的路径: root/a/a/a/a/a

相应的图形将是 'root'->'a'->'a'->...

是否可能添加共享相同名称的多个顶点? 找不到明确的答案。

How can I represent file path using BGL?
Consider path like: root/a/a/a/a/a

Corresponding graph would be 'root'->'a'->'a'->...

Is it possible to add multiple vertices sharing the same name?
Could not find clear answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

从此见与不见 2025-01-21 12:12:21

当然。只要名称不是标识符(身份意味着唯一)。

文件系统路径的整体思想是路径唯一的。因此,您可能想要的是将唯一名称作为节点的路径,并在显示时选择要显示路径的哪一部分。

对于使用内部顶点名称的优雅演示1:

using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, fs::path>;
using V = G::vertex_descriptor;

现在您可以向图形添加任何路径:

void add_path(fs::path p, G& g) {
    if (p.empty()) return;
    if (!p.has_root_path()) p = fs::absolute(p);

    std::optional<V> prev;
    fs::path curr;
    for (auto const& el : p) {
        curr /= el;
        auto v = add_vertex(curr, g);
        if (prev)
            add_edge(*prev, v, g);
        prev = v;
    }
}

我们必须告诉 BGL 使用 std::identityfs 获取内部名称: :path

template <> struct boost::graph::internal_vertex_name<fs::path> {
    struct type : std::identity {
        using result_type = fs::path;
    };
};

现在,演示:

G g;

add_path("/root/a/a/a/a/a", g);
add_path("test.cpp", g);

使用顶点 ID 进行打印:

print_graph(g);

使用唯一节点路径进行打印:

auto paths = get(boost::vertex_bundle, g);
print_graph(g, paths);

仅使用本地名称进行打印:

auto filename = std::mem_fn(&fs::path::filename);
auto local    = make_transform_value_property_map(filename, paths);
print_graph(g, local);

现场演示

Live On Compiler Explorer

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <filesystem>
using std::filesystem::path;

template <>
struct boost::graph::internal_vertex_name<path> {
    struct type : std::identity {
        using result_type = path;
    };
};

using G =
    boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, path>;
using V = G::vertex_descriptor;

void add_path(path p, G& g) {
    if (p.empty()) return;
    if (!p.has_root_path()) p = absolute(p);

    std::optional<V> prev;
    path curr;
    for (auto const& el : p) {
        curr /= el;
        auto v = add_vertex(curr, g);
        if (prev) add_edge(*prev, v, g);
        prev = v;
    }
}

int main() {
    G g;

    add_path("/root/a/a/a/a/a", g);
    add_path("test.cpp", g);

    // To print using the vertex ids:
    print_graph(g, std::cout << " ---- vertex index\n");

    // To print using the unique node paths:
    auto paths = get(boost::vertex_bundle, g);
    print_graph(g, paths, std::cout << " --- node path\n");

    // To print using only the local names:
    auto filename = std::mem_fn(&path::filename);
    auto local = make_transform_value_property_map(filename, paths);
    print_graph(g, local, std::cout << " --- local name\n");
}

打印(在我的机器上,其中 test.cpp 存在于 /home/sehe/Projects/stackoverflow 中):

 ---- vertex index
0 --> 1 7
1 --> 2
2 --> 3
3 --> 4
4 --> 5
5 --> 6
6 -->
7 --> 8
8 --> 9
9 --> 10
10 --> 11
11 -->
 --- node path
"/" --> "/root" "/home"
"/root" --> "/root/a"
"/root/a" --> "/root/a/a"
"/root/a/a" --> "/root/a/a/a"
"/root/a/a/a" --> "/root/a/a/a/a"
"/root/a/a/a/a" --> "/root/a/a/a/a/a"
"/root/a/a/a/a/a" -->
"/home" --> "/home/sehe"
"/home/sehe" --> "/home/sehe/Projects"
"/home/sehe/Projects" --> "/home/sehe/Projects/stackoverflow"
"/home/sehe/Projects/stackoverflow" --> "/home/sehe/Projects/stackoverflow/test.cpp"
"/home/sehe/Projects/stackoverflow/test.cpp" -->
 --- local name
"" --> "root" "home"
"root" --> "a"
"a" --> "a"
"a" --> "a"
"a" --> "a"
"a" --> "a"
"a" -->
"home" --> "sehe"
"sehe" --> "Projects"
"Projects" --> "stackoverflow"
"stackoverflow" --> "test.cpp"
"test.cpp" -->

额外的

Graphviz 输出:

write_graphviz(std::cout, g, boost::label_writer{local});

给出 此图可视化

在此处输入图像描述

¹ 参见例如 如何配置boost::图使用我自己的(稳定)索引作为顶点?

Sure. As long as the name is not the identifier (identity implies unique).

The whole idea of filesystem paths is that the paths are unique. So, what you would probably want is to have the unique name be the path to the node, and when displaying, choose what part of the path you want to display.

For an elegant demonstration using internal vertex names¹:

using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, fs::path>;
using V = G::vertex_descriptor;

Now you can add any path to the graph:

void add_path(fs::path p, G& g) {
    if (p.empty()) return;
    if (!p.has_root_path()) p = fs::absolute(p);

    std::optional<V> prev;
    fs::path curr;
    for (auto const& el : p) {
        curr /= el;
        auto v = add_vertex(curr, g);
        if (prev)
            add_edge(*prev, v, g);
        prev = v;
    }
}

We'll have to tell BGL to use std::identity to get the internal name from fs::path:

template <> struct boost::graph::internal_vertex_name<fs::path> {
    struct type : std::identity {
        using result_type = fs::path;
    };
};

Now, demonstrating:

G g;

add_path("/root/a/a/a/a/a", g);
add_path("test.cpp", g);

To print using the vertex ids:

print_graph(g);

To print using the unique node paths:

auto paths = get(boost::vertex_bundle, g);
print_graph(g, paths);

To print using only the local names:

auto filename = std::mem_fn(&fs::path::filename);
auto local    = make_transform_value_property_map(filename, paths);
print_graph(g, local);

Live Demo

Live On Compiler Explorer

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <filesystem>
using std::filesystem::path;

template <>
struct boost::graph::internal_vertex_name<path> {
    struct type : std::identity {
        using result_type = path;
    };
};

using G =
    boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, path>;
using V = G::vertex_descriptor;

void add_path(path p, G& g) {
    if (p.empty()) return;
    if (!p.has_root_path()) p = absolute(p);

    std::optional<V> prev;
    path curr;
    for (auto const& el : p) {
        curr /= el;
        auto v = add_vertex(curr, g);
        if (prev) add_edge(*prev, v, g);
        prev = v;
    }
}

int main() {
    G g;

    add_path("/root/a/a/a/a/a", g);
    add_path("test.cpp", g);

    // To print using the vertex ids:
    print_graph(g, std::cout << " ---- vertex index\n");

    // To print using the unique node paths:
    auto paths = get(boost::vertex_bundle, g);
    print_graph(g, paths, std::cout << " --- node path\n");

    // To print using only the local names:
    auto filename = std::mem_fn(&path::filename);
    auto local = make_transform_value_property_map(filename, paths);
    print_graph(g, local, std::cout << " --- local name\n");
}

Prints (on my machine, where test.cpp exists in /home/sehe/Projects/stackoverflow):

 ---- vertex index
0 --> 1 7
1 --> 2
2 --> 3
3 --> 4
4 --> 5
5 --> 6
6 -->
7 --> 8
8 --> 9
9 --> 10
10 --> 11
11 -->
 --- node path
"/" --> "/root" "/home"
"/root" --> "/root/a"
"/root/a" --> "/root/a/a"
"/root/a/a" --> "/root/a/a/a"
"/root/a/a/a" --> "/root/a/a/a/a"
"/root/a/a/a/a" --> "/root/a/a/a/a/a"
"/root/a/a/a/a/a" -->
"/home" --> "/home/sehe"
"/home/sehe" --> "/home/sehe/Projects"
"/home/sehe/Projects" --> "/home/sehe/Projects/stackoverflow"
"/home/sehe/Projects/stackoverflow" --> "/home/sehe/Projects/stackoverflow/test.cpp"
"/home/sehe/Projects/stackoverflow/test.cpp" -->
 --- local name
"" --> "root" "home"
"root" --> "a"
"a" --> "a"
"a" --> "a"
"a" --> "a"
"a" --> "a"
"a" -->
"home" --> "sehe"
"sehe" --> "Projects"
"Projects" --> "stackoverflow"
"stackoverflow" --> "test.cpp"
"test.cpp" -->

BONUS

Graphviz output:

write_graphviz(std::cout, g, boost::label_writer{local});

Gives this graphviz

enter image description here

¹ see e.g. How to configure boost::graph to use my own (stable) index for vertices?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文