[英]Accessing specific edges in boost::graph with integer index
This is related to a question I had yesterday about accessing vertices using integer indices.这与我昨天关于使用整数索引访问顶点的问题有关。 That thread is here: Accessing specific vertices in boost::graph
该线程在这里: 访问 boost::graph 中的特定顶点
The solution there indicated that using vecS as the type for vertices, it is indeed possible to access specific vertices using the integer index.那里的解决方案表明,使用 vecS 作为顶点类型,确实可以使用整数索引访问特定顶点。 I was wondering if there is a similar method provided by boost to access arbitrary edges efficiently using integer indices.
我想知道 boost 是否提供了一种类似的方法来使用整数索引有效地访问任意边。
Attached is a code that depicts the former (valid access of vertices with integer indices) and accessing the edges based on the developer explicitly maintaining two arrays, from[]
and to[]
, that store the source and the target, respectively of the edges.附件是描述前者(具有整数索引的顶点的有效访问)和访问基于开发人员显式维护两个数组的边的代码,
from[]
和to[]
,分别存储边的源和目标.
The code creates the following graph:该代码创建了以下图形:
#include <boost/config.hpp>
#include <iostream>
#include <fstream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
typedef adjacency_list_traits<vecS, vecS, directedS> Traits;
typedef adjacency_list<
vecS, vecS, directedS,
property<
vertex_name_t, std::string,
property<vertex_index_t, int,
property<vertex_color_t, boost::default_color_type,
property<vertex_distance_t, double,
property<vertex_predecessor_t, Traits::edge_descriptor> > > > >,
property<
edge_index_t, int,
property<edge_capacity_t, double,
property<edge_weight_t, double,
property<edge_residual_capacity_t, double,
property<edge_reverse_t, Traits::edge_descriptor> > > > > >
Graph;
int main() {
int nonodes = 4;
const int maxnoedges = 4;//I want to avoid using this.
Graph g(nonodes);
property_map<Graph, edge_index_t>::type E = get(edge_index, g);
int from[maxnoedges], to[maxnoedges];//I want to avoid using this.
// Create edges
Traits::edge_descriptor ed;
int eindex = 0;
ed = (add_edge(0, 1, g)).first;
from[eindex] = 0; to[eindex] = 1;//I want to avoid using this.
E[ed] = eindex++;
ed = (add_edge(0, 2, g)).first;
from[eindex] = 0; to[eindex] = 2;//I want to avoid using this.
E[ed] = eindex++;
ed = (add_edge(1, 3, g)).first;
from[eindex] = 1; to[eindex] = 3;//I want to avoid using this.
E[ed] = eindex++;
ed = (add_edge(2, 3, g)).first;
from[eindex] = 2; to[eindex] = 3;//I want to avoid using this.
E[ed] = eindex++;
graph_traits < Graph >::out_edge_iterator ei, e_end;
for (int vindex = 0; vindex < num_vertices(g); vindex++) {
printf("Number of outedges for vertex %d is %d\n", vindex, out_degree(vindex, g));
for (tie(ei, e_end) = out_edges(vindex, g); ei != e_end; ++ei)
printf("From %d to %d\n", source(*ei, g), target(*ei, g));
}
printf("Number of edges is %d\n", num_edges(g));
//Is there any efficient method boost provides
//in lieu of having to explicitly maintain from and to arrays
//on part of the developer?
for (int eindex = 0; eindex < num_edges(g); eindex++)
printf("Edge %d is from %d to %d\n", eindex, from[eindex], to[eindex]);
}
The code builds and compiles without error.代码构建和编译没有错误。 The
for
loop with vindex
works fine with out_edges
and out_degree
working fine taking as parameters integer indices.带有
vindex
的for
循环在out_edges
和out_degree
作为参数整数索引的情况下工作正常。
Is there a way to do likewise for the next for
loop that prints the edges using boost::graph data structures directly?有没有办法对直接使用 boost::graph 数据结构打印边缘的下一个
for
循环做同样的事情?
I looked at the following thread dealing with a similar question:我查看了以下处理类似问题的线程:
Boost graph library: Get edge_descriptor or access edge by index of type int Boost 图库:通过 int 类型的索引获取 edge_descriptor 或访问边
The suggested answer there was to use an unordered_map
.建议的答案是使用
unordered_map
。 Is there any tradeoff in using this as opposed to having the from[]
and to[]
arrays?与使用
from[]
和to[]
数组相比,使用它是否有任何权衡? Are there any other computationally efficient methods of accessing edges?是否有任何其他计算效率高的访问边缘的方法?
You can only do this if you你只能这样做,如果你
You could be interested in the AdjacencyMatrix
concept .您可能对
AdjacencyMatrix
概念感兴趣。 It doesn't exactly sport integral edge ids, but AdjacencyMatrix
has lookup of edge by source/target vertices as well.它并不完全具有完整的边 ID,但
AdjacencyMatrix
也可以通过源/目标顶点查找边。
To get truly integral edge descriptors, you'd probably need write your own graph model class (modeling a set of existing BGL concepts).要获得真正完整的边描述符,您可能需要编写自己的图形模型类(建模一组现有的 BGL 概念)。 You might also be interested in
grid_graph<>
(which has a fixed set of numbered edges per vertex, where the vertices are a grid).您可能还对
grid_graph<>
(每个顶点有一组固定的编号边,其中顶点是网格)感兴趣。
Here's a modification from the previous answer showing an external index.这是对上一个答案的修改,显示了外部索引。 It's akin to your solution.
它类似于您的解决方案。 I chose
bimap
so at least you get the reverse lookup "automagically".我选择了
bimap
因此至少您可以“自动”进行反向查找。
// Create edges
boost::bimaps::bimap<int, Graph::edge_descriptor> edge_idx;
auto new_edge_pair = [&,edge_id=0](int from, int to) mutable {
auto single = [&](int from, int to) {
auto d = add_edge(from, to, EdgeProperty { edge_id, 4 }, g).first;
if (!edge_idx.insert({edge_id++, d}).second)
throw std::invalid_argument("duplicate key");
return d;
};
auto a = single(from, to), b = single(to, from);
rev[a] = b;
rev[b] = a;
};
new_edge_pair(0, 1);
new_edge_pair(0, 2);
new_edge_pair(1, 3);
new_edge_pair(2, 3);
Now you can do the loop by edge id:现在您可以按边 ID 进行循环:
auto& by_id = edge_idx.left;
for (auto const& e : by_id) {
std::cout << "Edge #" << e.first << " is (" << source(e.second, g) << " -> " << target(e.second, g) << ")\n";
}
You can directly lookup an edge by it's id:您可以通过它的 id 直接查找边:
auto ed = by_id.at(random);
std::cout << "Random edge #" << random << " is (" << source(ed, g) << " -> " << target(ed, g) << ")\n";
The reverse lookup is a bit redundant, because you can do the same using BGL quite easily:反向查找有点多余,因为你可以很容易地使用 BGL 做同样的事情:
std::cout << "Reverse lookup: " << by_desc.at(ed) << "\n"; // reverse, though not very spectacular
std::cout << "Classic property lookup: " << g[ed].id << "\n"; // because it can be done using boost easily
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <functional>
#include <iostream>
#include <boost/bimap.hpp>
#include <random>
std::mt19937 prng { std::random_device{}() };
using namespace boost;
struct VertexProperty { std::string name; };
struct EdgeProperty {
int id;
double capacity, residual_capacity;
EdgeProperty(int id, double cap, double res = 0)
: id(id), capacity(cap), residual_capacity(res)
{ }
};
typedef adjacency_list<vecS, vecS, directedS, VertexProperty, EdgeProperty> Graph;
int main() {
int nonodes = 4;
Graph g(nonodes);
// reverse edge map
auto rev = make_vector_property_map<Graph::edge_descriptor>(get(&EdgeProperty::id, g));
// Create edges
boost::bimaps::bimap<int, Graph::edge_descriptor> edge_idx;
auto new_edge_pair = [&,edge_id=0](int from, int to) mutable {
auto single = [&](int from, int to) {
auto d = add_edge(from, to, EdgeProperty { edge_id, 4 }, g).first;
if (!edge_idx.insert({edge_id++, d}).second)
throw std::invalid_argument("duplicate key");
return d;
};
auto a = single(from, to), b = single(to, from);
rev[a] = b;
rev[b] = a;
};
new_edge_pair(0, 1);
new_edge_pair(0, 2);
new_edge_pair(1, 3);
new_edge_pair(2, 3);
// property maps
struct VertexEx {
default_color_type color;
double distance;
Graph::edge_descriptor pred;
};
auto idx = get(vertex_index, g);
auto vex = make_vector_property_map<VertexEx>(idx);
auto pred = make_transform_value_property_map(std::mem_fn(&VertexEx::pred), vex);
auto color = make_transform_value_property_map(std::mem_fn(&VertexEx::color), vex);
auto dist = make_transform_value_property_map(std::mem_fn(&VertexEx::distance), vex);
auto cap = get(&EdgeProperty::capacity, g);
auto rescap = get(&EdgeProperty::residual_capacity, g);
// algorithm
double flow = boykov_kolmogorov_max_flow(g, cap, rescap, rev, pred, color, dist, idx, 0, 3);
std::cout << "Flow: " << flow << "\n";
{
auto& by_id = edge_idx.left;
auto& by_desc = edge_idx.right;
for (auto const& e : edge_idx.left) {
std::cout << "Edge #" << e.first << " is (" << source(e.second, g) << " -> " << target(e.second, g) << ")\n";
}
int random = prng() % num_edges(g);
auto ed = by_id.at(random);
std::cout << "Random edge #" << random << " is (" << source(ed, g) << " -> " << target(ed, g) << ")\n";
std::cout << "Reverse lookup: " << by_desc.at(ed) << "\n"; // reverse, though not very spectacular
std::cout << "Classic property lookup: " << g[ed].id << "\n"; // because it can be done using boost easily
}
}
Printing印刷
Flow: 8
Edge #0 is (0 -> 1)
Edge #1 is (1 -> 0)
Edge #2 is (0 -> 2)
Edge #3 is (2 -> 0)
Edge #4 is (1 -> 3)
Edge #5 is (3 -> 1)
Edge #6 is (2 -> 3)
Edge #7 is (3 -> 2)
Random edge #2 is (0 -> 2)
Reverse lookup: 2
Classic property lookup: 2
Keeps everything the same, except for changing the model:保持一切不变,除了改变模型:
#include <boost/graph/adjacency_matrix.hpp>
typedef adjacency_matrix<directedS, VertexProperty, EdgeProperty> Graph;
And now you get the added capability of lookup by vertices:现在您可以获得按顶点查找的附加功能:
std::cout << "Finding (3, 1) results in Edge #" << by_desc.at(edge(3, 1, g).first) << "\n";
Prints印刷
Finding (3, 1) results in Edge #5
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.