c++ - Fruchterman Reingold 的吸引力如何与 Boost Graph Library 一起工作

标签 c++ algorithm boost graph boost-property-map

我正在学习 Boost Graph Library 中的 Fruchterman-Reingold 算法。通过阅读文档,我知道该算法是根据图形布局计算所有节点的位置,但我的问题是我无法理解Boost Graph Library中吸引力的计算步骤。

例如,如果拓扑是高100宽100的矩形,每个顶点标记为字符串,每对顶点之间的关系为:

"0"  "5"
"Kevin" "Martin"
"Ryan" "Leo"
"Y" "S"
"Kevin" "S"
"American" "USA"

每一行表示两个标记的顶点相连。每个顶点的吸引力公式应该是:

f = (d^2) / k

其中 d 是两个顶点之间的距离,k 是最佳距离。但是我不明白如何在Boost Graph Library中的Fruchterman-Reingold代码中获取距离d。在这个例子中,它是否将每对顶点之间的 ASCII 值差异计算为距离 d? ('0' 的 ASCII 值是 48,'5' 的 ASCII 值是 53。Fruchterman-Reingold 计算 53 - 48 = 5 作为 BGL 中的 d 是真的吗?)如果有人能帮助我,我真的很感激。

最佳答案

Furchterman-Reingold 实现采用 IN/OUT 拓扑。

它期望在执行之前将拓扑初始化为某个状态。传递给吸引力函数的距离将是该次迭代中拓扑的距离。

Note Note that (unless progressive is set to true) Furterman-Reingold will initialize the topology randomly by default (using random_graph_layout).

以上所有摘自in the documentation .

这是一个使用您的输入图的小型演示,展示了如何实现这样一个 attractive_force 函数:

struct AttractionF {
    template <typename EdgeDescriptor, typename Graph>
        double operator()(EdgeDescriptor /*ed*/, double k, double d, Graph const& /*g*/) const {
            //std::cout << "DEBUG af('" << g[source(ed, g)].name << " -> " << g[target(ed, g)].name << "; k:" << k << "; d:" << d << ")\n";
            return (d*d/k);
        }
};

参见 Live On Coliru

#include <memory>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/fruchterman_reingold.hpp>
#include <boost/graph/random_layout.hpp>
#include <libs/graph/src/read_graphviz_new.cpp>
#include <boost/graph/topology.hpp>
#include <boost/random.hpp>

using namespace boost;

struct Vertex {
    std::string name;
};

struct AttractionF {
    template <typename EdgeDescriptor, typename Graph>
        double operator()(EdgeDescriptor /*ed*/, double k, double d, Graph const& /*g*/) const {
            //std::cout << "DEBUG af('" << g[source(ed, g)].name << " -> " << g[target(ed, g)].name << "; k:" << k << "; d:" << d << ")\n";
            return (d*d/k);
        }
};
using Graph = adjacency_list<vecS, vecS, undirectedS, Vertex>;

Graph make_sample();

int main() {
    auto g = make_sample();

    using Topology = square_topology<boost::mt19937>;
    using Position = Topology::point_type;

    std::vector<Position> positions(num_vertices(g));
    square_topology<boost::mt19937> topology;

    random_graph_layout(g, 
                make_iterator_property_map(positions.begin(), boost::identity_property_map{}),
                topology);

    fruchterman_reingold_force_directed_layout(
                g,
                make_iterator_property_map(positions.begin(), boost::identity_property_map{}),
                topology,
                attractive_force(AttractionF())
            );

    dynamic_properties dp;
    dp.property("node_id", get(&Vertex::name, g));
    write_graphviz_dp(std::cout, g, dp);
}

Graph make_sample() {
    std::string const sample_dot = R"(
        graph {
            "0"        -- "5";
            "Kevin"    -- "Martin";
            "Ryan"     -- "Leo";
            "Y"        -- "S";
            "Kevin"    -- "S";
            "American" -- "USA";
        }
    )";
    Graph g;

    dynamic_properties dp;
    dp.property("node_id", get(&Vertex::name, g));

    read_graphviz(sample_dot, g, dp);

    return g;
}

请注意,在 c++11 中,您同样可以使用 lambda:

fruchterman_reingold_force_directed_layout(
            g,
            make_iterator_property_map(positions.begin(), boost::identity_property_map{}),
            topology,
            attractive_force([](Graph::edge_descriptor, double k, double d, Graph const&) { return (d*d)/k; })
        );

关于c++ - Fruchterman Reingold 的吸引力如何与 Boost Graph Library 一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29815336/

相关文章:

algorithm - N 次幂 n i-e n^n 是否是多项式? n^2 和 n^n 之间是否存在多项式差异?

c# - Visual Studio 和 Eclipse 哪个更好

c++ - 等待线程如何影响性能?

c++ - 从模板继承?

c++ - C++ 中带线程的强力搜索算法的并行化

c++ - boost ASIO 和 co_await- 与任何第三方回调一起使用?

c++ - 如何在 Clang AST 中的 SourceLocation 之后找到字符的 SourceLocation?

c - 如何计算两个给定日期之间的天数? (闰年障碍)

c++ - ASIO 中存在单独的接受器类背后的设计原理

c++ - 非默认构建的 boost::proto 终端