How does the attractive force of Fruchterman Reingold work with Boost Graph Library

烂漫一生 提交于 2019-12-01 06:47:26

问题


I am learning the Fruchterman-Reingold algorithm in Boost Graph Library. By reading the document, I know that the algorithm is to compute the positions for all nodes in terms of graph layout, but my problem is I cannot understand the calculation steps of attractive forces in Boost Graph Library.

For example, if the topology is rectangle with height 100 and width 100, each vertex is labelled as string, and the relation between each pair vertex as:

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

Each row denotes the two labelled vertices are connected. The formula of attractive force for each vertex is supposed to be:

f = (d^2) / k

where d is the distance between two vertices and k is the optimal distances. But I don't understand how to get the distance d in the code of Fruchterman-Reingold in Boost Graph Library. In this example, does it compute the ASCII value difference between each pair vertices as the distance d? (ASCII value of '0' is 48, and ASCII value of '5' is 53. Is it true that Fruchterman-Reingold computes 53 - 48 = 5 as d in BGL?) I really appreciate if anyone can help me.


回答1:


Furchterman-Reingold implementation takes an IN/OUT topology.

It expects the topology to be initialized to some state before execution. The distance passed to the attraction function will be the one from the topology at that iteration.

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

All the above taken from in the documentation.

Here's a tiny demo using your input graph that shows how to implement such an attractive_force function:

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

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

Note that in c++11 you can equally well use a 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; })
        );


来源:https://stackoverflow.com/questions/29815336/how-does-the-attractive-force-of-fruchterman-reingold-work-with-boost-graph-libr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!