Fruchterman Reingold 的吸引力如何与 Boost Graph Library 一起工作
How does the attractive force of Fruchterman Reingold work with Boost Graph Library
我正在学习 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);
}
};
#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; })
);
我正在学习 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 totrue
) Furterman-Reingold will initialize the topology randomly by default (usingrandom_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);
}
};
#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; })
);