簡體   English   中英

Boost Graph DFS(和其他算法)的 API 背后的動機是什么?

[英]What is the motivation behind the API of the Boost Graph DFS (and other algorithms)?

一般問題

當我邁入 BGL 的第一步時,我很難理解是什么證明了最小驚訝原則在這里有點被欺負。

背景

所以,經過大量的努力,我可以構建一個樹圖,我希望能夠寫出類似的東西

tree.dfs(visitor);

現在我知道 BGL 並不是一個面向對象的 API,我想寫一些像這樣的東西是有意義的

depth_first_search(tree, visitor)

然后,由於我了解到 BGL 中沒有 Tree 類,設計選擇是使根的存在成為值屬性而不是類型屬性。 所以我想這解釋了為什么我們必須傳遞根描述符,比如

depth_first_search(graph_that_is_a_tree, visitor, root);

是什么讓我困惑

到目前為止,我感覺我(或多或少)遵循了設計。 但是為了讓我的代碼編譯,我實際上必須寫:

  auto [root, tree] = my_stuff::to_k_ary_tree<my_vertex, my_edge>(ast);

  auto indexmap = boost::get(boost::vertex_index, tree);
  auto colormap = boost::make_vector_property_map<boost::default_color_type>(indexmap);

  MyVisitor<my_stuff::k_ary_tree<my_vertex,my_edge>> vis;
  std::vector<boost::default_color_type> colors(num_vertices(tree));
  boost::depth_first_search(tree, vis, colormap, root);

這就是我失去它的地方(直覺):即使我被警告過大多數算法都需要顏色圖,我也不理解/理解為什么我需要這個簽名。

我的問題

為什么 DFS 算法不能負責處理這些細節呢?

我能想到的

  • 是因為 if tree 不是一種類型嗎? 如果 Tree 和 Graph 之間沒有類型區分,那么 DFS 就不可能知道沒有循環,因此它需要為所有情況下探索過的頂點着色——即使你絕對確定它是一個循環樹,有根,沒有圈。
  • 如果是這樣,那么它並沒有向我完全解釋為什么 DFS 不能在我們不知情的情況下創建/訪問/銷毀這個顏色圖。

最好的解釋就在文檔的着陸頁上:https ://www.boost.org/doc/libs/1_81_0/libs/graph/doc/index.html

它對比了 STL [sic] 中的泛型與 Boost Graph Library 中的泛型 第二部分最核心的宣傳語:

[首先,] BGL 的圖形算法被寫入一個接口,該接口抽象出特定圖形數據結構的細節。 與 STL 一樣,BGL 使用迭代器來定義數據結構遍歷的接口。 存在三種不同的圖遍歷模式:遍歷圖中的所有頂點、遍歷所有邊以及沿着圖的鄰接結構(從一個頂點到它的每個鄰居)。 每種遍歷模式都有單獨的迭代器。

這個通用接口允許諸如breadth_first_search()類的模板函數處理各種圖數據結構,從用指針鏈接節點實現的圖到用數組編碼的圖。 這種靈活性在圖形領域尤為重要。 圖數據結構通常是為特定應用程序定制的。 傳統上,如果程序員想要重用算法實現,他們必須將圖形數據轉換/復制到圖形庫規定的圖形結構中。 LEDA、GTL、Stanford GraphBase 等庫就是這種情況; 對於用 Fortran 編寫的圖算法尤其如此。 這嚴重限制了他們圖算法的重用。

相比之下,定制的(甚至遺留的)圖結構可以與 BGL 的通用圖算法一起使用,使用外部適應(參見如何將現有圖轉換為 BGL 部分)。 外部適配圍繞數據結構包裝一個新接口,無需復制,也無需將數據放入適配器對象中。 BGL 接口經過精心設計,使這種適應變得容易。 為了證明這一點,我們構建了接口代碼以在 BGL 圖算法中使用各種圖結構(LEDA 圖、Stanford GraphBase 圖,甚至 Fortran 樣式的數組)。

但是等等,還有更多!

相關的,Boost Geometry 有一個非常相似的設計原理部分,該部分更詳細地介紹了通用模板庫設計如何演變成 BGL 也具有的形式。

它通過示例來實現,這非常好,當然,即使這些示例來自計算幾何領域。

輔助屬性映射

關於顏色圖(和其他輔助算法狀態),我將添加:

  • 你也可以默認它們

    • 使用標記屬性 ( property<vertex_color_t, default_color_type> )
    • 使用特征特化將外部映射與圖形類型相關聯( graph_property<>
  • 讓調用者提供它們可以在算法調用之間重新使用着色/存儲時獲得巨大的效率提升

  • 注意大多數算法默認輔助屬性映射。 事實上,DFS 也可以

簡化樣本

部分基於您之前的問題代碼,這里有一個示例,展示了如何簡化調用。

請注意,它使用 ADL 來避免boost::限定函數名稱,並使用dfs 的命名參數重載

生活在 Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/random.hpp>
#include <iomanip>
#include <random>

struct MyVisitor : boost::default_dfs_visitor {
    auto discover_vertex(auto u, auto const& g) {
        std::cout << "Discover vertex " << u << " (" << g[u] << ")\n";
    }
};

template <class V, class E>
    requires std::constructible_from<V, std::string> && std::constructible_from<E, double>
auto foo(...) {
    using G = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, V, E>;

    G g;
    std::mt19937 prng{std::random_device{}()};
    generate_random_graph(g, 10, 30, prng);

    for (auto e : make_iterator_range(edges(g)))
        g[e] = {std::uniform_real_distribution(1.0, 2.0)(prng)};

    for (int i = 0; i < 10; ++i)
        g[i] = {std::array{"zero", "one", "two", "three", "four", "five", "six", "seven",
                           "eight", "nine"}
                    .at(i)};

    return std::tuple(std::move(g), 3);
}

struct V { std::string  name; };
struct E { double length; };
static inline auto& operator<<(std::ostream& os, V const& v) { return os << quoted(v.name); }

int main() {
    auto [g, root] = foo<V, E>();
    depth_first_search(g, visitor(MyVisitor{}));
    print_graph(g);
}

打印,例如

Discover vertex 0 ("zero")
Discover vertex 5 ("five")
Discover vertex 1 ("one")
Discover vertex 2 ("two")
Discover vertex 4 ("four")
Discover vertex 6 ("six")
Discover vertex 8 ("eight")
Discover vertex 3 ("three")
Discover vertex 7 ("seven")
Discover vertex 9 ("nine")
0 --> 5 6 7 
1 --> 0 2 7 
2 --> 1 4 5 6 8 
3 --> 0 4 8 
4 --> 1 2 6 
5 --> 0 1 2 7 
6 --> 2 5 8 
7 --> 2 5 
8 --> 0 3 
9 --> 3 7 

暫無
暫無

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

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