sp-graph-layout 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. sp_graph_layout-1.0.0/CMakeLists.txt +164 -0
  2. sp_graph_layout-1.0.0/LICENSE +21 -0
  3. sp_graph_layout-1.0.0/PKG-INFO +41 -0
  4. sp_graph_layout-1.0.0/README.md +28 -0
  5. sp_graph_layout-1.0.0/include/common/binary_indexed_tree.h +38 -0
  6. sp_graph_layout-1.0.0/include/common/compare_svg.h +17 -0
  7. sp_graph_layout-1.0.0/include/common/graph_attributes.h +96 -0
  8. sp_graph_layout-1.0.0/include/common/graph_def.h +149 -0
  9. sp_graph_layout-1.0.0/include/directed/cross_minimization.h +106 -0
  10. sp_graph_layout-1.0.0/include/directed/feedback_arcs.h +40 -0
  11. sp_graph_layout-1.0.0/include/directed/layer_assignment.h +71 -0
  12. sp_graph_layout-1.0.0/include/directed/vertex_positioning.h +78 -0
  13. sp_graph_layout-1.0.0/include/graph_layout.h +66 -0
  14. sp_graph_layout-1.0.0/pyproject.toml +51 -0
  15. sp_graph_layout-1.0.0/python/README.md +21 -0
  16. sp_graph_layout-1.0.0/python/bindings.cpp +82 -0
  17. sp_graph_layout-1.0.0/python/wrapper/__init__.py +27 -0
  18. sp_graph_layout-1.0.0/src/common/binary_indexed_tree.cpp +47 -0
  19. sp_graph_layout-1.0.0/src/common/compare_svg.cpp +12 -0
  20. sp_graph_layout-1.0.0/src/common/graph_attributes.cpp +133 -0
  21. sp_graph_layout-1.0.0/src/common/graph_def.cpp +352 -0
  22. sp_graph_layout-1.0.0/src/common/graph_def_splitter.cpp +88 -0
  23. sp_graph_layout-1.0.0/src/directed/cross_minimization.cpp +451 -0
  24. sp_graph_layout-1.0.0/src/directed/feedback_arcs.cpp +182 -0
  25. sp_graph_layout-1.0.0/src/directed/layer_assignment.cpp +321 -0
  26. sp_graph_layout-1.0.0/src/directed/vertex_positioning.cpp +274 -0
  27. sp_graph_layout-1.0.0/src/graph_layout.cpp +313 -0
@@ -0,0 +1,164 @@
1
+ cmake_minimum_required(VERSION 4.0)
2
+ project(GraphLayout)
3
+
4
+ set(CMAKE_CXX_STANDARD 20)
5
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
+ set(CMAKE_CXX_EXTENSIONS OFF)
7
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
8
+
9
+ option(GRAPH_LAYOUT_ENABLE_TESTS "Build tests" OFF)
10
+ option(GRAPH_LAYOUT_ENABLE_RANDOM_TESTS "Build random tests" OFF)
11
+ option(GRAPH_LAYOUT_ENABLE_STRICT "Use strict compile options" OFF)
12
+ option(GRAPH_LAYOUT_ENABLE_COVERAGE "Enable coverage reporting" OFF)
13
+ option(GRAPH_LAYOUT_BIND_PYTHON "Enable python binding" OFF)
14
+ option(GRAPH_LAYOUT_BIND_ES "Enable ECMAScript binding" OFF)
15
+
16
+ if(APPLE)
17
+ set(ENV{PKG_CONFIG_PATH} "/opt/homebrew/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
18
+ endif()
19
+
20
+ include(FetchContent)
21
+
22
+ FetchContent_Declare(
23
+ SVGDiagram
24
+ GIT_REPOSITORY https://github.com/CyberZHG/SVGDiagram.git
25
+ GIT_TAG v1.3.0
26
+ )
27
+
28
+ FetchContent_MakeAvailable(SVGDiagram)
29
+
30
+ if(GRAPH_LAYOUT_ENABLE_STRICT)
31
+ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
32
+ add_compile_options(
33
+ -Wall
34
+ -Wextra
35
+ -Werror
36
+ -Wpedantic
37
+ -Wmissing-include-dirs
38
+ -Wundef
39
+ -Wredundant-decls
40
+ )
41
+ endif()
42
+ endif()
43
+
44
+ if(GRAPH_LAYOUT_ENABLE_COVERAGE)
45
+ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
46
+ add_compile_options(--coverage -O0 -g)
47
+ add_link_options(--coverage)
48
+ endif()
49
+ endif()
50
+
51
+ add_library(GraphLayout STATIC
52
+ include/graph_layout.h
53
+ src/graph_layout.cpp
54
+ include/directed/feedback_arcs.h
55
+ src/directed/feedback_arcs.cpp
56
+ include/common/graph_def.h
57
+ src/common/graph_def.cpp
58
+ include/directed/layer_assignment.h
59
+ src/directed/layer_assignment.cpp
60
+ src/common/graph_def_splitter.cpp
61
+ include/directed/cross_minimization.h
62
+ src/directed/cross_minimization.cpp
63
+ include/common/binary_indexed_tree.h
64
+ src/common/binary_indexed_tree.cpp
65
+ include/directed/vertex_positioning.h
66
+ src/directed/vertex_positioning.cpp
67
+ include/common/graph_attributes.h
68
+ src/common/graph_attributes.cpp
69
+ include/common/compare_svg.h
70
+ src/common/compare_svg.cpp
71
+ )
72
+
73
+ target_include_directories(GraphLayout
74
+ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
75
+ )
76
+
77
+ target_link_libraries(GraphLayout
78
+ PRIVATE SVGDiagram
79
+ )
80
+
81
+ if(GRAPH_LAYOUT_ENABLE_TESTS)
82
+ enable_testing()
83
+
84
+ FetchContent_Declare(
85
+ googletest
86
+ GIT_REPOSITORY https://github.com/google/googletest.git
87
+ GIT_TAG v1.17.0
88
+ )
89
+
90
+ FetchContent_MakeAvailable(googletest)
91
+
92
+ add_executable(runTests
93
+ tests/test_main.cpp
94
+ tests/feedback_arcs/test_eades_93.cpp
95
+ tests/layer_assignment/test_topological.cpp
96
+ tests/graph_def/test_component_splitter.cpp
97
+ tests/layer_assignment/test_gansner_93.cpp
98
+ tests/cross_minimization/test_cross_minimization.cpp
99
+ tests/cross_minimization/test_barycenter.cpp
100
+ tests/cross_minimization/test_median.cpp
101
+ tests/cross_minimization/test_pairwise_switch.cpp
102
+ tests/vertex_positioning/test_brandes_kopf.cpp
103
+ tests/graph_layout/test_directed_graph_hierarchical_layout.cpp
104
+ tests/feedback_arcs/test_min_id.cpp
105
+ tests/docs/test_basic.cpp
106
+ tests/docs/test_graph_attr.cpp
107
+ tests/docs/test_vertex_attr.cpp
108
+ tests/docs/test_edge_attr.cpp
109
+ )
110
+
111
+ target_link_libraries(runTests
112
+ PRIVATE GraphLayout
113
+ PRIVATE gtest gtest_main
114
+ )
115
+
116
+ if (GRAPH_LAYOUT_ENABLE_RANDOM_TESTS)
117
+ target_compile_definitions(runTests
118
+ PRIVATE GRAPH_LAYOUT_ENABLE_RANDOM_TESTS=ON
119
+ )
120
+ endif ()
121
+
122
+ add_test(NAME GraphLayoutTests COMMAND runTests)
123
+ endif ()
124
+
125
+ if(GRAPH_LAYOUT_BIND_PYTHON)
126
+ include(FetchContent)
127
+ FetchContent_Declare(
128
+ pybind11
129
+ GIT_REPOSITORY https://github.com/pybind/pybind11.git
130
+ GIT_TAG v3.0
131
+ )
132
+ FetchContent_MakeAvailable(pybind11)
133
+
134
+ pybind11_add_module(_core
135
+ python/bindings.cpp
136
+ )
137
+ target_link_libraries(_core
138
+ PRIVATE GraphLayout
139
+ )
140
+ install(TARGETS _core
141
+ LIBRARY DESTINATION sp_graph_layout)
142
+ install(FILES python/wrapper/__init__.py DESTINATION sp_graph_layout)
143
+ endif()
144
+
145
+ if (GRAPH_LAYOUT_BIND_ES)
146
+
147
+ add_executable(GraphLayoutWASM
148
+ wasm/graph_layout_wasm.cpp)
149
+
150
+ target_link_libraries(GraphLayoutWASM
151
+ PRIVATE GraphLayout
152
+ )
153
+
154
+ target_compile_options(GraphLayoutWASM PRIVATE "-O3")
155
+
156
+ set_target_properties(GraphLayoutWASM PROPERTIES SUFFIX ".js")
157
+
158
+ target_link_options(GraphLayoutWASM PRIVATE
159
+ "--bind"
160
+ "-sMODULARIZE=1"
161
+ "-sEXPORT_ES6=1"
162
+ "-sEXPORT_NAME=GraphLayoutWASMModule"
163
+ )
164
+ endif ()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 - Present CyberZHG
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.2
2
+ Name: sp-graph-layout
3
+ Version: 1.0.0
4
+ Summary: A library for visualizing directed graphs.
5
+ License: MIT
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: C++
8
+ Classifier: Operating System :: OS Independent
9
+ Project-URL: Homepage, https://github.com/CyberZHG/GraphLayout
10
+ Project-URL: Repository, https://github.com/CyberZHG/GraphLayout
11
+ Project-URL: Issues, https://github.com/CyberZHG/GraphLayout/issues
12
+ Project-URL: Documentation, https://cyberzhg.github.io/GraphLayout/
13
+ Requires-Python: >=3.8
14
+ Provides-Extra: test
15
+ Requires-Dist: pytest; extra == "test"
16
+ Requires-Dist: black; extra == "test"
17
+ Requires-Dist: isort; extra == "test"
18
+ Requires-Dist: flake8; extra == "test"
19
+ Description-Content-Type: text/markdown
20
+
21
+ Graph Layout
22
+ ============
23
+
24
+ ## Overview
25
+
26
+ A library for visualizing directed graphs.
27
+
28
+ | rank dir = TB | rank dir = LR |
29
+ |:----------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------:|
30
+ | ![](https://github.com/CyberZHG/GraphLayout/blob/main/docs/images/example1_tb.svg) | ![](https://github.com/CyberZHG/GraphLayout/blob/main/docs/images/example1_lr.svg) |
31
+ | ![](https://github.com/CyberZHG/GraphLayout/blob/main/docs/images/example2_tb.svg) | ![](https://github.com/CyberZHG/GraphLayout/blob/main/docs/images/example2_lr.svg) |
32
+
33
+ ## Documentation
34
+
35
+ * [Documentation](https://cyberzhg.github.io/GraphLayout/)
36
+
37
+ * [Installation](https://cyberzhg.github.io/GraphLayout/install.html)
38
+ * [Basic Concepts](https://cyberzhg.github.io/GraphLayout/basic.html)
39
+ * [Graph Attributes](https://cyberzhg.github.io/GraphLayout/graph_attr.html)
40
+ * [Vertex Attributes](https://cyberzhg.github.io/GraphLayout/vertex_attr.html)
41
+ * [Edge Attributes](https://cyberzhg.github.io/GraphLayout/edge_attr.html)
@@ -0,0 +1,28 @@
1
+ Graph Layout
2
+ ============
3
+
4
+ [![C++ Unit Tests](https://github.com/CyberZHG/GraphLayout/actions/workflows/cpp-unit-test.yml/badge.svg)](https://github.com/CyberZHG/GraphLayout/actions/workflows/cpp-unit-test.yml)
5
+ [![Python Build & Test](https://github.com/CyberZHG/GraphLayout/actions/workflows/python-build-test.yml/badge.svg)](https://github.com/CyberZHG/GraphLayout/actions/workflows/python-build-test.yml)
6
+ [![WASM Build & Test](https://github.com/CyberZHG/GraphLayout/actions/workflows/wasm-build-test.yml/badge.svg)](https://github.com/CyberZHG/GraphLayout/actions/workflows/wasm-build-test.yml)
7
+ [![Deploy Docs to GitHub Pages](https://github.com/CyberZHG/GraphLayout/actions/workflows/deploy-docs.yml/badge.svg)](https://github.com/CyberZHG/GraphLayout/actions/workflows/deploy-docs.yml)
8
+ [![PyPI version](https://img.shields.io/pypi/v/sp-graph-layout.svg)](https://pypi.org/project/sp-graph-layout/)
9
+ [![npm version](https://img.shields.io/npm/v/sp-graph-layout.svg)](https://www.npmjs.com/package/sp-graph-layout)
10
+
11
+ ## Overview
12
+
13
+ A library for visualizing directed graphs.
14
+
15
+ | rank dir = TB | rank dir = LR |
16
+ |:------------------------------:|:------------------------------:|
17
+ | ![](docs/images/example1_tb.svg) | ![](docs/images/example1_lr.svg) |
18
+ | ![](docs/images/example2_tb.svg) | ![](docs/images/example2_lr.svg) |
19
+
20
+ ## Documentation
21
+
22
+ * [Documentation](https://cyberzhg.github.io/GraphLayout/)
23
+
24
+ * [Installation](https://cyberzhg.github.io/GraphLayout/install.html)
25
+ * [Basic Concepts](https://cyberzhg.github.io/GraphLayout/basic.html)
26
+ * [Graph Attributes](https://cyberzhg.github.io/GraphLayout/graph_attr.html)
27
+ * [Vertex Attributes](https://cyberzhg.github.io/GraphLayout/vertex_attr.html)
28
+ * [Edge Attributes](https://cyberzhg.github.io/GraphLayout/edge_attr.html)
@@ -0,0 +1,38 @@
1
+ #ifndef GRAPHLAYOUT_BINARY_INDEXED_TREE_H
2
+ #define GRAPHLAYOUT_BINARY_INDEXED_TREE_H
3
+
4
+ #include <vector>
5
+
6
+ namespace graph_layout {
7
+
8
+ class BinaryIndexedTree {
9
+ public:
10
+ explicit BinaryIndexedTree(size_t n);
11
+ ~BinaryIndexedTree() = default;
12
+
13
+ /** Add a number to a binary indexed tree.
14
+ *
15
+ * @param index The index to add the value.
16
+ * @param val The value to add.
17
+ */
18
+ void add(int index, int val = 1);
19
+
20
+ /** Get the prefix sum from a binary indexed tree.
21
+ *
22
+ * @param index The index of the last element, inclusive.
23
+ * @return The prefix sum.
24
+ */
25
+ [[nodiscard]] long long prefixSum(int index) const;
26
+
27
+ void clear();
28
+ void clear(size_t n);
29
+
30
+ private:
31
+ std::vector<long long> _bit;
32
+
33
+ static int next(int index);
34
+ };
35
+
36
+ };
37
+
38
+ #endif //GRAPHLAYOUT_BINARY_INDEXED_TREE_H
@@ -0,0 +1,17 @@
1
+ #ifndef GRAPHLAYOUT_COMPARE_SVG_H
2
+ #define GRAPHLAYOUT_COMPARE_SVG_H
3
+
4
+ #include <string>
5
+
6
+ namespace graph_layout {
7
+ /** A helper function for unit tests only.
8
+ *
9
+ * @param a
10
+ * @param b
11
+ * @return Whether the two input SVGs are the same.
12
+ */
13
+ bool _compareSVG(const std::string& a, const std::string& b);
14
+ }
15
+
16
+
17
+ #endif //GRAPHLAYOUT_COMPARE_SVG_H
@@ -0,0 +1,96 @@
1
+ #ifndef GRAPHLAYOUT_GRAPH_ATTRIBUTES_H
2
+ #define GRAPHLAYOUT_GRAPH_ATTRIBUTES_H
3
+
4
+ #include <string>
5
+ #include <unordered_map>
6
+
7
+ namespace graph_layout {
8
+
9
+ constexpr std::string ATTRIBUTE_KEY_BG_COLOR = "bgcolor";
10
+ constexpr std::string ATTRIBUTE_KEY_RANK_DIR = "rankdir";
11
+ constexpr std::string ATTRIBUTE_KEY_LABEL = "label";
12
+ constexpr std::string ATTRIBUTE_KEY_SHAPE = "shape";
13
+ constexpr std::string ATTRIBUTE_KEY_FONT_NAME = "fontname";
14
+ constexpr std::string ATTRIBUTE_KEY_FONT_SIZE = "fontsize";
15
+ constexpr std::string ATTRIBUTE_KEY_WIDTH = "width";
16
+ constexpr std::string ATTRIBUTE_KEY_HEIGHT = "height";
17
+
18
+ class Attribute {
19
+ public:
20
+ Attribute();
21
+ explicit Attribute(const std::string& value);
22
+ ~Attribute() = default;
23
+
24
+ void set(const std::string& value);
25
+ [[nodiscard]] const std::string& value() const;
26
+
27
+ protected:
28
+ std::string _raw;
29
+ };
30
+
31
+ class AttributeColor : public Attribute {
32
+ public:
33
+ using Attribute::Attribute;
34
+
35
+ [[nodiscard]] static std::tuple<double, double, double> toRGB(const std::string& raw);
36
+ };
37
+
38
+ class AttributeRankDir : public Attribute {
39
+ public:
40
+ using Attribute::Attribute;
41
+
42
+ static const std::string TOP_TO_BOTTOM;
43
+ static const std::string BOTTOM_TO_TOP;
44
+ static const std::string LEFT_TO_RIGHT;
45
+ static const std::string RIGHT_TO_LEFT;
46
+ };
47
+
48
+ class AttributeShape : public Attribute {
49
+ public:
50
+ using Attribute::Attribute;
51
+
52
+ static const std::string NONE;
53
+ static const std::string CIRCLE;
54
+ static const std::string DOUBLE_CIRCLE;
55
+ static const std::string ELLIPSE;
56
+ static const std::string RECT;
57
+ };
58
+
59
+ class Attributes {
60
+ public:
61
+ Attributes() = default;
62
+ ~Attributes() = default;
63
+
64
+ [[nodiscard]] std::string graphAttributes(const std::string& key) const;
65
+ void setGraphAttributes(const std::string& key, const std::string& value);
66
+ void setGraphAttributes(const std::unordered_map<std::string, std::string> &attributes);
67
+
68
+ [[nodiscard]] std::string vertexAttributes(int u, const std::string& key) const;
69
+ void setVertexAttributes(int u, const std::string& key, const std::string& value);
70
+ void setVertexAttributes(int u, const std::unordered_map<std::string, std::string> &attributes);
71
+
72
+ [[nodiscard]] std::string edgeAttributes(int u, const std::string& key) const;
73
+ void setEdgeAttributes(int u, const std::string& key, const std::string& value);
74
+ void setEdgeAttributes(int u, const std::unordered_map<std::string, std::string>& mapping);
75
+ void transferEdgeAttributes(int u, int v);
76
+
77
+ [[nodiscard]] std::string rankDir() const;
78
+ void setRankDir(const std::string& value);
79
+
80
+ void setVertexShape(int u, const std::string& value);
81
+
82
+ private:
83
+ static std::unordered_map<std::string, std::string> DEFAULT_GRAPH_ATTRIBUTE_VALUES;
84
+ static std::unordered_map<std::string, std::string> DEFAULT_VERTEX_ATTRIBUTE_VALUES;
85
+ static std::unordered_map<std::string, std::string> DEFAULT_EDGE_ATTRIBUTE_VALUES;
86
+
87
+ std::unordered_map<std::string, std::string> _graphAttributes;
88
+ std::unordered_map<std::string, std::string> _vertexGlobalAttributes;
89
+ std::unordered_map<int, std::unordered_map<std::string, std::string>> _vertexAttributes;
90
+ std::unordered_map<std::string, std::string> _edgeGlobalAttributes;
91
+ std::unordered_map<int, std::unordered_map<std::string, std::string>> _edgeAttributes;
92
+ };
93
+
94
+ }
95
+
96
+ #endif //GRAPHLAYOUT_GRAPH_ATTRIBUTES_H
@@ -0,0 +1,149 @@
1
+ #ifndef GRAPHLAYOUT_GRAPH_DEF_H
2
+ #define GRAPHLAYOUT_GRAPH_DEF_H
3
+
4
+ #include <vector>
5
+ #include <unordered_set>
6
+ #include <unordered_map>
7
+ #include <memory>
8
+
9
+ namespace graph_layout {
10
+
11
+ class EdgeIterationWithIDs;
12
+
13
+ struct SPEdge {
14
+ int id, u, v;
15
+
16
+ bool operator==(const SPEdge&) const;
17
+ };
18
+
19
+ struct SPVirtualEdge {
20
+ SPEdge originalEdge;
21
+ std::vector<int> virtualEdgeIds;
22
+ };
23
+
24
+ class SPDirectedGraph {
25
+ public:
26
+ explicit SPDirectedGraph(size_t numVertices);
27
+ ~SPDirectedGraph() = default;
28
+
29
+ void updateNumVertices(size_t numVertices);
30
+ [[nodiscard]] size_t numVertices() const { return _numVertices; }
31
+ [[nodiscard]] size_t numEdges() const { return _edges.size(); }
32
+ [[nodiscard]] const std::vector<SPEdge>& edges() const { return _edges; }
33
+ std::vector<SPEdge>& edges() { return _edges;}
34
+
35
+ void addEdge(const SPEdge& edge);
36
+ int addEdge(int u, int v);
37
+ void addEdges(const std::vector<std::pair<int ,int>>& edges);
38
+ void addOutEdges(int u, const std::vector<int>& vertices);
39
+ SPEdge& getEdge(int id);
40
+ void removeEdge(int id);
41
+
42
+ bool operator==(const SPDirectedGraph& other) const;
43
+
44
+ void disableSelfCycleEdges();
45
+ void enableSelfCycleEdges();
46
+
47
+ void reverseEdges(const std::unordered_set<int>& ids);
48
+ void reverseEdgesBack();
49
+ [[nodiscard]] bool isReverseEdge(int id) const;
50
+
51
+ void sortEdgesById();
52
+ const std::unordered_map<int, size_t>& getEdgeIdToIndexMap();
53
+ const std::vector<int>& getInDegrees();
54
+ const std::vector<int>& getOutDegrees();
55
+ const std::vector<std::vector<int>>& getInVertices();
56
+ const std::vector<std::vector<int>>& getOutVertices();
57
+ std::vector<std::vector<int>>& getInEdgeIdsRef();
58
+ std::vector<std::vector<int>>& getOutEdgeIdsRef();
59
+ const std::vector<std::vector<int>>& getInEdgeIds();
60
+ const std::vector<std::vector<int>>& getOutEdgeIds();
61
+ EdgeIterationWithIDs getInEdges(int v);
62
+ EdgeIterationWithIDs getOutEdges(int u);
63
+ bool hasCycle();
64
+
65
+ [[nodiscard]] SPDirectedGraph buildSpanningTree(const std::vector<int>& parents);
66
+
67
+ private:
68
+ size_t _numVertices{};
69
+ std::vector<SPEdge> _edges;
70
+
71
+ bool _edgeIdToIndexMapInitialized = false;
72
+ std::unordered_map<int, size_t> _edgeIdToIndexMap;
73
+
74
+ bool _degreesInitialized = false;
75
+ std::vector<int> _inDegrees;
76
+ std::vector<int> _outDegrees;
77
+
78
+ bool _inOutVerticesInitialized = false;
79
+ std::vector<std::vector<int>> _inVertices;
80
+ std::vector<std::vector<int>> _outVertices;
81
+
82
+ bool _inOutEdgesInitialized = false;
83
+ std::vector<std::vector<int>> _inEdges;
84
+ std::vector<std::vector<int>> _outEdges;
85
+
86
+ bool _hasCycleInitialized = false;
87
+ bool _hasCycle = false;
88
+
89
+ std::vector<SPEdge> _selfCycleEdges;
90
+
91
+ std::unordered_set<int> _reverseIds;
92
+
93
+ void resetInitialization();
94
+ void initializeDegrees();
95
+ void initializeInOutVertices();
96
+ void initializeInOutEdges();
97
+ void initializeHasCycle();
98
+ };
99
+
100
+ class EdgeIterationWithIDs {
101
+ public:
102
+ EdgeIterationWithIDs(SPDirectedGraph& graph, const std::vector<int>& ids) : _graph(graph), _ids(ids) {}
103
+
104
+ class iterator {
105
+ public:
106
+ explicit iterator(SPDirectedGraph& graph, const std::vector<int>& ids, const int index) : _graph(graph), _ids(ids), _index(index) {}
107
+ const SPEdge &operator*() const;
108
+ iterator& operator++() { ++_index; return *this; }
109
+ bool operator!=(const iterator& other) const { return _index != other._index; }
110
+ private:
111
+ SPDirectedGraph& _graph;
112
+ const std::vector<int>& _ids;
113
+ int _index;
114
+ };
115
+
116
+ [[nodiscard]] iterator begin() const { return iterator(_graph, _ids, 0); }
117
+ [[nodiscard]] iterator end() const { return iterator(_graph, _ids, static_cast<int>(_ids.size())); }
118
+ private:
119
+ SPDirectedGraph &_graph;
120
+ const std::vector<int> &_ids;
121
+ };
122
+
123
+ class RandomSimpleDirectedGraphGenerator {
124
+ public:
125
+ explicit RandomSimpleDirectedGraphGenerator(const int maxNumVertices) : _minNumVertices(1), _maxNumVertices(maxNumVertices), _allowSelfCycle(false) {}
126
+
127
+ [[nodiscard]] SPDirectedGraph generateRandomGraph() const;
128
+ [[nodiscard]] SPDirectedGraph generateRandomGraphWithoutDuplicateEdge() const;
129
+ private:
130
+ int _minNumVertices;
131
+ int _maxNumVertices;
132
+ bool _allowSelfCycle;
133
+ };
134
+
135
+ class GraphComponentSplitter {
136
+ public:
137
+ static std::vector<int> getConnectedComponents(const SPDirectedGraph& graph);
138
+ std::vector<SPDirectedGraph>& splitGraph(const SPDirectedGraph& graph);
139
+ [[nodiscard]] SPDirectedGraph mergeBack() const;
140
+ [[nodiscard]] int originalVertexId(int groupIndex, int u) const;
141
+
142
+ private:
143
+ std::vector<SPDirectedGraph> _graphs;
144
+ std::vector<std::vector<int>> _groups;
145
+ };
146
+
147
+ }
148
+
149
+ #endif //GRAPHLAYOUT_GRAPH_DEF_H
@@ -0,0 +1,106 @@
1
+ #ifndef GRAPHLAYOUT_CROSS_MINIMIZATION_H
2
+ #define GRAPHLAYOUT_CROSS_MINIMIZATION_H
3
+
4
+ #include "common/graph_def.h"
5
+ #include "common/binary_indexed_tree.h"
6
+ #include <functional>
7
+
8
+ namespace graph_layout {
9
+
10
+ /** The struct for storing the results of cross minimization */
11
+ struct SPLayering {
12
+ // Discrete ranks for each layer.
13
+ std::vector<int> layerRanks;
14
+ // Vertex order within each layer.
15
+ std::vector<std::vector<int>> orders;
16
+ // Mapping from a vertex ID to its index in the corresponding layer.
17
+ std::vector<std::unordered_map<int, int>> positions;
18
+ // Mapping from a vertex ID to the layer it belongs to.
19
+ std::unordered_map<int, int> idToLayer;
20
+ // Maximum number of vertices in each layer.
21
+ size_t width;
22
+
23
+ /** Initialize the two mappings in this struct.
24
+ *
25
+ * Note that we only guarantee that the mappings are initialized
26
+ * in the return values of `CrossMinimization`.
27
+ */
28
+ void initializeMapping();
29
+ };
30
+
31
+ enum class CrossMinimizationMethod {
32
+ // Barycenter heuristic.
33
+ BARYCENTER,
34
+ // Median heuristic.
35
+ MEDIAN,
36
+ // Greedily switch two adjacent vertices.
37
+ PAIRWISE_SWITCH,
38
+ };
39
+
40
+ /** Reduce the number of crossings between two adjacent layers. */
41
+ class CrossMinimization {
42
+ public:
43
+ explicit CrossMinimization(CrossMinimizationMethod method = CrossMinimizationMethod::BARYCENTER);
44
+ ~CrossMinimization() = default;
45
+
46
+ // The start index for virtual edges.
47
+ static constexpr int VIRTUAL_EDGE_ID_OFFSET = 1000000000;
48
+
49
+ void setMethod(CrossMinimizationMethod method);
50
+
51
+ /** Reduce the number of crossings between each two adjacent layers.
52
+ *
53
+ * @param graph A connected DAG.
54
+ * @param ranks Layer assignment of vertices.
55
+ * @return Orders of vertices in each layer and any virtual edges added to the graph.
56
+ */
57
+ std::pair<SPLayering, std::vector<SPVirtualEdge>> reduceNumCross(SPDirectedGraph& graph, std::vector<int>& ranks) const;
58
+
59
+ /** Add virtual edges to the graph so that no edge spans more than two layers.
60
+ *
61
+ * @param graph A connected DAG.
62
+ * @param ranks Layer assignment of vertices.
63
+ * @return Orders of vertices in each layer and any virtual edges added to the graph.
64
+ */
65
+ static std::pair<SPLayering, std::vector<SPVirtualEdge>> addVirtualEdges(SPDirectedGraph& graph, std::vector<int>& ranks);
66
+
67
+ /** Compute the total number of crossings between each two adjacent layers.
68
+ *
69
+ * This function is mainly used for testing.
70
+ *
71
+ * @param graph A connected DAG.
72
+ * @param layering A cross minimization result.
73
+ * @return Total number of crossings.
74
+ */
75
+ static long long computeNumCross(SPDirectedGraph& graph, const SPLayering& layering);
76
+
77
+ private:
78
+ CrossMinimizationMethod _method;
79
+
80
+ static long long computeNumCross(
81
+ SPDirectedGraph &graph,
82
+ BinaryIndexedTree &bit,
83
+ const std::vector<int> &order1,
84
+ const std::vector<int> &order2,
85
+ bool forward = true);
86
+ static long long computeNumCross(SPDirectedGraph& graph,
87
+ const std::vector<std::unordered_map<int, int>> &positions,
88
+ std::vector<int> &adjPositionsU,
89
+ std::vector<int> &adjPositionsV,
90
+ int layerIndex, int u, int v, bool forward);
91
+ static long long computeNumCross(SPDirectedGraph& graph,
92
+ const std::vector<std::unordered_map<int, int>> &positions,
93
+ std::vector<int> &adjPositionsU,
94
+ std::vector<int> &adjPositionsV,
95
+ int layerIndex, int u, int v);
96
+
97
+ static void reduceNumCrossWithWeightingHeuristic(SPDirectedGraph& graph, SPLayering& layering,
98
+ const std::function<double(SPDirectedGraph&, const std::unordered_map<int, int>&, int, bool)> &weighting);
99
+ static void reduceNumCrossWithBaryCenterHeuristic(SPDirectedGraph& graph, SPLayering& layering);
100
+ static void reduceNumCrossWithMedianHeuristic(SPDirectedGraph& graph, SPLayering& layering);
101
+ static void reduceNumCrossWithPairwiseSwitchHeuristic(SPDirectedGraph& graph, SPLayering& layering);
102
+ };
103
+
104
+ }
105
+
106
+ #endif //GRAPHLAYOUT_CROSS_MINIMIZATION_H