在没有顶点描述符失效的情况下在 boost 中有一个 DAG 图
Have a DAG graph in boost without vertex descriptor invalidation
我正在尝试使用 boost::adjacency_list<>
class 实现有向无环图。为此,我重新实现了这个问题的想法:boost graph that doesn't allow circular references
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>;
using Vertex = Graph::vertex_descriptor;
这样我就可以在每次 add_edge
之后调用 topological_sort
来确认我有一个 DAG:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/iterator/function_output_iterator.hpp>
int main()
{
Graph g;
// 1. build a graph structure
auto v1 = boost::add_vertex(g);
auto v2 = boost::add_vertex(g);
auto v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, g);
boost::topological_sort(g, boost::make_function_output_iterator([](int) {}));
boost::add_edge(v2, v3, g);
boost::topological_sort(g, boost::make_function_output_iterator([](int) {}));
}
我的另一个要求是为我在图表上执行的操作启用一些 undo/redo 支持。其中一项操作可能是删除顶点并删除指定顶点的所有传入和传出边。示例代码可能如下所示:
static void Print(const Graph& g)
{
std::cout << "Vertices: " << std::endl;
for (auto vertices = boost::vertices(g); vertices.first != vertices.second; ++vertices.first)
{
std::cout << *vertices.first << std::endl;
}
std::cout << "Edges: " << std::endl;
for (auto edges = boost::edges(g); edges.first != edges.second; ++edges.first)
{
auto edgeDescriptor = *edges.first;
std::cout << edgeDescriptor.m_source << "->" << edgeDescriptor.m_target << std::endl;
}
std::cout << std::endl;
}
int main()
{
Graph g;
// 1. build a graph structure
auto v1 = boost::add_vertex(g);
auto v2 = boost::add_vertex(g);
auto v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, g);
boost::add_edge(v2, v3, g);
Print(g);
// 2. prepare for deletion of v2
std::vector<Vertex> outVertices;
for(auto vertices = boost::adjacent_vertices(v2, g); vertices.first != vertices.second; ++vertices.first)
{
outVertices.push_back(*vertices.first);
}
std::vector<Vertex> inVertices;
for (auto vertices = boost::inv_adjacent_vertices(v2, g); vertices.first != vertices.second; ++vertices.first)
{
inVertices.push_back(*vertices.first);
}
// 3. delete v2
boost::clear_vertex(v2, g);
boost::remove_vertex(v2, g);
Print(g);
// 4 undo the operation
v2 = boost::add_vertex(g);
for(auto& outVertex : outVertices)
{
boost::add_edge(v2, outVertex, g);
}
for (auto& inVertex : inVertices)
{
boost::add_edge(inVertex, v2, g);
}
Print(g);
}
输出:
Vertices:
0
1
2
Edges:
0->1
1->2
Vertices:
0
1
Edges:
Vertices:
0
1
2
Edges:
2->2
0->2
这当然不起作用,因为 remove_vertex
调用使我之前保存的 vertex_descriptors
无效。我为这个问题找到的解决方案是
这里建议使用列表而不是向量来保存顶点,因此 vertex_descriptors
不会失效。
using Graph = boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS>;
这确实按预期工作,并在撤消工作的地方提供了所需的输出:
Vertices:
000001DD1902AC90
000001DD19028F70
000001DD19028D80
Edges:
000001DD1902AC90->000001DD19028F70
000001DD19028F70->000001DD19028D80
Vertices:
000001DD1902AC90
000001DD19028D80
Edges:
Vertices:
000001DD1902AC90
000001DD19028D80
000001DD19028F70
Edges:
000001DD19028F70->000001DD19028D80
000001DD1902AC90->000001DD19028F70
我现在遇到的问题是 topological_sort
不再用我的新 Graph
定义编译。对于完整的错误消息:https://godbolt.org/z/WKjeK3ddP
我的问题(或者我正在尝试解决的问题是)如何在不使 vertex_descriptors
无效的情况下在 boost 中实现直接无环图,同时删除顶点并具有 topological_sort
的可能性?
或者可能不是那么具体:如何在我可以 enable/implement undo/redo 可能性的地方实现带有提升的 DAG?
问得好。
拓扑排序
它失败了,因为不再有隐式顶点索引。拓扑排序要求它获得默认的颜色图,因此有效的东西:
std::map<Vertex, int> index;
for (auto v : boost::make_iterator_range(vertices(g)))
index.emplace(v, index.size());
boost::topological_sort(
g, boost::make_function_output_iterator([](Vertex) {}),
boost::vertex_index_map(boost::make_assoc_property_map(index)));
或者,直接提供色图,这可能是更好的主意:
std::map<Vertex, boost::default_color_type> colors;
boost::topological_sort(
g, boost::make_function_output_iterator([](Vertex) {}),
boost::color_map(boost::make_assoc_property_map(colors)));
There's some more thinking behind this problem here:
大图
我最喜欢你的问题是,在非常高水平的详细分析之后,你仍然回头想知道是否还有其他问题。这是你,试图避免狭隘的视野或 X/Y 问题。
Or maybe not that specific: How to impelement a DAG with boost on where I can enable/implement undo/redo possibilities?
老实说,我认为您是在硬塞一个非常具体的数据结构到 BGL 应该拥有的东西中。那是不可能的。我会颠倒设计优先级。
BGL 明确地 设计为几乎完全通用。这意味着您可以在您自己的数据结构上使用这些算法,只要有正确的 instrumentation/adaptation.
您的要求感觉更像是版本化 tree/forest。具有 shared_ptr<const T>
个节点的 Sean-Parent 风格的树似乎更适用。
A quick demonstration of the concept, focusing on Copy-On-Write deep modification of sub-trees: Transforming trees in C++
更高级的策略可能是,例如splay trees,但在 recommening/implementing 类似的事情之前,我必须自己重新梳理理论。
现在,所有这些并没有真正触及图算法的任何要求。上面的链接答案顺便显示了自定义图形模型的拓扑排序,因此您可以看看它是否可行。在某些时候,您可能会决定为您自己的数据结构“只实施”BFS 会更好。
我正在尝试使用 boost::adjacency_list<>
class 实现有向无环图。为此,我重新实现了这个问题的想法:boost graph that doesn't allow circular references
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>;
using Vertex = Graph::vertex_descriptor;
这样我就可以在每次 add_edge
之后调用 topological_sort
来确认我有一个 DAG:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/iterator/function_output_iterator.hpp>
int main()
{
Graph g;
// 1. build a graph structure
auto v1 = boost::add_vertex(g);
auto v2 = boost::add_vertex(g);
auto v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, g);
boost::topological_sort(g, boost::make_function_output_iterator([](int) {}));
boost::add_edge(v2, v3, g);
boost::topological_sort(g, boost::make_function_output_iterator([](int) {}));
}
我的另一个要求是为我在图表上执行的操作启用一些 undo/redo 支持。其中一项操作可能是删除顶点并删除指定顶点的所有传入和传出边。示例代码可能如下所示:
static void Print(const Graph& g)
{
std::cout << "Vertices: " << std::endl;
for (auto vertices = boost::vertices(g); vertices.first != vertices.second; ++vertices.first)
{
std::cout << *vertices.first << std::endl;
}
std::cout << "Edges: " << std::endl;
for (auto edges = boost::edges(g); edges.first != edges.second; ++edges.first)
{
auto edgeDescriptor = *edges.first;
std::cout << edgeDescriptor.m_source << "->" << edgeDescriptor.m_target << std::endl;
}
std::cout << std::endl;
}
int main()
{
Graph g;
// 1. build a graph structure
auto v1 = boost::add_vertex(g);
auto v2 = boost::add_vertex(g);
auto v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, g);
boost::add_edge(v2, v3, g);
Print(g);
// 2. prepare for deletion of v2
std::vector<Vertex> outVertices;
for(auto vertices = boost::adjacent_vertices(v2, g); vertices.first != vertices.second; ++vertices.first)
{
outVertices.push_back(*vertices.first);
}
std::vector<Vertex> inVertices;
for (auto vertices = boost::inv_adjacent_vertices(v2, g); vertices.first != vertices.second; ++vertices.first)
{
inVertices.push_back(*vertices.first);
}
// 3. delete v2
boost::clear_vertex(v2, g);
boost::remove_vertex(v2, g);
Print(g);
// 4 undo the operation
v2 = boost::add_vertex(g);
for(auto& outVertex : outVertices)
{
boost::add_edge(v2, outVertex, g);
}
for (auto& inVertex : inVertices)
{
boost::add_edge(inVertex, v2, g);
}
Print(g);
}
输出:
Vertices:
0
1
2
Edges:
0->1
1->2
Vertices:
0
1
Edges:
Vertices:
0
1
2
Edges:
2->2
0->2
这当然不起作用,因为 remove_vertex
调用使我之前保存的 vertex_descriptors
无效。我为这个问题找到的解决方案是
这里建议使用列表而不是向量来保存顶点,因此 vertex_descriptors
不会失效。
using Graph = boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS>;
这确实按预期工作,并在撤消工作的地方提供了所需的输出:
Vertices:
000001DD1902AC90
000001DD19028F70
000001DD19028D80
Edges:
000001DD1902AC90->000001DD19028F70
000001DD19028F70->000001DD19028D80
Vertices:
000001DD1902AC90
000001DD19028D80
Edges:
Vertices:
000001DD1902AC90
000001DD19028D80
000001DD19028F70
Edges:
000001DD19028F70->000001DD19028D80
000001DD1902AC90->000001DD19028F70
我现在遇到的问题是 topological_sort
不再用我的新 Graph
定义编译。对于完整的错误消息:https://godbolt.org/z/WKjeK3ddP
我的问题(或者我正在尝试解决的问题是)如何在不使 vertex_descriptors
无效的情况下在 boost 中实现直接无环图,同时删除顶点并具有 topological_sort
的可能性?
或者可能不是那么具体:如何在我可以 enable/implement undo/redo 可能性的地方实现带有提升的 DAG?
问得好。
拓扑排序
它失败了,因为不再有隐式顶点索引。拓扑排序要求它获得默认的颜色图,因此有效的东西:
std::map<Vertex, int> index;
for (auto v : boost::make_iterator_range(vertices(g)))
index.emplace(v, index.size());
boost::topological_sort(
g, boost::make_function_output_iterator([](Vertex) {}),
boost::vertex_index_map(boost::make_assoc_property_map(index)));
或者,直接提供色图,这可能是更好的主意:
std::map<Vertex, boost::default_color_type> colors;
boost::topological_sort(
g, boost::make_function_output_iterator([](Vertex) {}),
boost::color_map(boost::make_assoc_property_map(colors)));
There's some more thinking behind this problem here:
大图
我最喜欢你的问题是,在非常高水平的详细分析之后,你仍然回头想知道是否还有其他问题。这是你,试图避免狭隘的视野或 X/Y 问题。
Or maybe not that specific: How to impelement a DAG with boost on where I can enable/implement undo/redo possibilities?
老实说,我认为您是在硬塞一个非常具体的数据结构到 BGL 应该拥有的东西中。那是不可能的。我会颠倒设计优先级。
BGL 明确地 设计为几乎完全通用。这意味着您可以在您自己的数据结构上使用这些算法,只要有正确的 instrumentation/adaptation.
您的要求感觉更像是版本化 tree/forest。具有 shared_ptr<const T>
个节点的 Sean-Parent 风格的树似乎更适用。
A quick demonstration of the concept, focusing on Copy-On-Write deep modification of sub-trees: Transforming trees in C++
更高级的策略可能是,例如splay trees,但在 recommening/implementing 类似的事情之前,我必须自己重新梳理理论。
现在,所有这些并没有真正触及图算法的任何要求。上面的链接答案顺便显示了自定义图形模型的拓扑排序,因此您可以看看它是否可行。在某些时候,您可能会决定为您自己的数据结构“只实施”BFS 会更好。