简体   繁体   中英

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM