pd-code-to-diagram 0.0.1__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 (56) hide show
  1. pd_code_to_diagram-0.0.1/LICENSE +21 -0
  2. pd_code_to_diagram-0.0.1/PKG-INFO +49 -0
  3. pd_code_to_diagram-0.0.1/README.md +28 -0
  4. pd_code_to_diagram-0.0.1/pd_code_to_diagram/__init__.py +5 -0
  5. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/BFS/BfsAlgo.h +74 -0
  6. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/BorderDetect.h +130 -0
  7. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/DataInput/AbstractDataInput.h +10 -0
  8. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/DataInput/FileDataInput.h +104 -0
  9. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/Graph/AbstractGraph.h +20 -0
  10. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/Graph/ConnectedComponents.h +74 -0
  11. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/Graph/DiagramGraph.h +50 -0
  12. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/Graph/Graph.h +56 -0
  13. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntCombine/AbstractIntCombine.h +7 -0
  14. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMap/AbstractIntMap.h +7 -0
  15. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMap/NotIntMap.h +12 -0
  16. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMatrix2/AbstractIntMatrix2.h +31 -0
  17. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMatrix2/BorderMask.h +55 -0
  18. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMatrix2/BorderWrap.h +44 -0
  19. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMatrix2/IntMatrix2.h +101 -0
  20. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/BorderDetect/IntMatrix2/ZeroOneMatrix.h +47 -0
  21. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/LinkAlgo.h +200 -0
  22. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/NodeSet3D/GenNodeSetAlgo.h +116 -0
  23. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/NodeSet3D/NodeSet3D.h +102 -0
  24. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PDTreeAlgo/NumInput.h +30 -0
  25. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PDTreeAlgo/PDCode.h +164 -0
  26. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PDTreeAlgo/PDCrossing.h +101 -0
  27. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PDTreeAlgo/PDTree.h +449 -0
  28. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PDTreeAlgo/SocketInfo.h +232 -0
  29. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/Common/AbstractIntMatrix.h +18 -0
  30. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/Common/Coord2dSet.h +84 -0
  31. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/Common/GetBorderSet.h +82 -0
  32. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/Common/IntMatrix.h +89 -0
  33. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/Common/LineData.h +36 -0
  34. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngine/AbstractGraphEngine.h +69 -0
  35. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngine/PixelGraphEngine.h +74 -0
  36. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngine/VectorGraphEngine.h +93 -0
  37. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngineWrap/ErasePointGraphEngineWrap.h +63 -0
  38. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngineWrap/MarginGraphEngineWrap.h +77 -0
  39. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngineWrap/MergeGraphEngineWrap.h +79 -0
  40. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/GraphEngineWrap/SpanGraphEngineWrap.h +81 -0
  41. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/PathAlgorithm/AbstractPathAlgorithm.h +21 -0
  42. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PathEngine/PathAlgorithm/SpfaPathEngine.h +185 -0
  43. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/PdToDiagram2d.h +132 -0
  44. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/README.md +53 -0
  45. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/Coord2dPosition.h +97 -0
  46. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/Debug.h +39 -0
  47. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/Direction.h +19 -0
  48. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/Exceptions.h +39 -0
  49. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/MyAssert.h +22 -0
  50. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/PrecisionTimer.h +65 -0
  51. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/Random.h +75 -0
  52. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/Utils/StringStream.h +59 -0
  53. pd_code_to_diagram-0.0.1/pd_code_to_diagram/cpp_src/main.cpp +188 -0
  54. pd_code_to_diagram-0.0.1/pd_code_to_diagram/main.py +91 -0
  55. pd_code_to_diagram-0.0.1/pd_code_to_diagram/run_file.py +93 -0
  56. pd_code_to_diagram-0.0.1/pyproject.toml +25 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TopologicalKnotIndexer
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,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: pd-code-to-diagram
3
+ Version: 0.0.1
4
+ Summary: calculate 2d-diagram from pd_code.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: GGN_2015
8
+ Author-email: neko@jlulug.org
9
+ Requires-Python: >=3.10
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Requires-Dist: cpp-simple-interface
18
+ Requires-Dist: pd-code-sanity
19
+ Description-Content-Type: text/markdown
20
+
21
+ ## pd_code_to_diagram
22
+ given a pd_code for a topological link or knot, output a possible 2d-diagram.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pip install pd-code-to-diagram
28
+ ```
29
+
30
+ ## Usage
31
+ ```python
32
+ import pd_code_to_diagram
33
+
34
+ # pd_code is a list of list of int
35
+ pd_code = [[6, 1, 7, 2], [14, 7, 15, 8], [4, 15, 1, 16], [10, 6, 11, 5], [8, 4, 9, 3], [18, 11, 19, 12], [20, 17, 5, 18], [12, 19, 13, 20], [16, 10, 17, 9], [2, 14, 3, 13]]
36
+
37
+ # last_socket should be int or None
38
+ # the program will ensure in the components contains last_socket
39
+ # there will be at least one arc on the border of
40
+ last_socket = 1
41
+
42
+ # diagram_2d will be a matrix of int
43
+ # its type will be list of list of int
44
+ # get_diagram_from_pd_code will raise an RuntimeError if such diagram not exists
45
+ diagram_2d = pd_code_to_diagram.get_diagram_from_pd_code(pd_code, last_socket)
46
+ for line in diagram_2d:
47
+ print(line)
48
+ ```
49
+
@@ -0,0 +1,28 @@
1
+ ## pd_code_to_diagram
2
+ given a pd_code for a topological link or knot, output a possible 2d-diagram.
3
+
4
+ ## Install
5
+
6
+ ```bash
7
+ pip install pd-code-to-diagram
8
+ ```
9
+
10
+ ## Usage
11
+ ```python
12
+ import pd_code_to_diagram
13
+
14
+ # pd_code is a list of list of int
15
+ pd_code = [[6, 1, 7, 2], [14, 7, 15, 8], [4, 15, 1, 16], [10, 6, 11, 5], [8, 4, 9, 3], [18, 11, 19, 12], [20, 17, 5, 18], [12, 19, 13, 20], [16, 10, 17, 9], [2, 14, 3, 13]]
16
+
17
+ # last_socket should be int or None
18
+ # the program will ensure in the components contains last_socket
19
+ # there will be at least one arc on the border of
20
+ last_socket = 1
21
+
22
+ # diagram_2d will be a matrix of int
23
+ # its type will be list of list of int
24
+ # get_diagram_from_pd_code will raise an RuntimeError if such diagram not exists
25
+ diagram_2d = pd_code_to_diagram.get_diagram_from_pd_code(pd_code, last_socket)
26
+ for line in diagram_2d:
27
+ print(line)
28
+ ```
@@ -0,0 +1,5 @@
1
+ from .main import get_diagram_from_pd_code
2
+
3
+ __all__ = [
4
+ "get_diagram_from_pd_code"
5
+ ]
@@ -0,0 +1,74 @@
1
+ #pragma once
2
+
3
+ #ifndef DEBUG_BFS
4
+ #define DEBUG_BFS (0)
5
+ #else
6
+ #undef DEBUG_BFS
7
+ #define DEBUG_BFS (1)
8
+ #endif
9
+
10
+ #include <queue>
11
+
12
+ #include "../IntMatrix2/ZeroOneMatrix.h"
13
+ #include "../IntMatrix2/BorderWrap.h"
14
+
15
+ #include "../../Utils/MyAssert.h"
16
+ #include "../../Utils/Debug.h"
17
+
18
+ class BfsAlgo {
19
+ public:
20
+
21
+ // 给定一个起始点,返回一个 0, 1 矩阵描述哪些位置可以走到
22
+ ZeroOneMatrix search(const ZeroOneMatrix& graph, int xpos, int ypos) const {
23
+ ASSERT(0 <= xpos && xpos < graph.getRcnt());
24
+ ASSERT(0 <= ypos && ypos < graph.getCcnt());
25
+
26
+ // 用一个 vis 数组记录每一个位置是否被访问过
27
+ auto vis = ZeroOneMatrix(graph.getRcnt(), graph.getCcnt());
28
+
29
+ // 1 表示障碍物,0 表示不是障碍物
30
+ // 在外围填充 1
31
+ auto new_graph = BorderWrap(1,
32
+ std::make_shared<ZeroOneMatrix>(graph)); // 拷贝构造一个
33
+ ASSERT(graph.getPos(xpos, ypos) == 0); // 初始位置不能是障碍物
34
+
35
+ // BFS 队列
36
+ std::queue<std::tuple<int, int>> q;
37
+ q.push(std::make_tuple(xpos, ypos));
38
+ vis.setPos(xpos, ypos, 1);
39
+
40
+ const int dx[] = {1, -1, 0, 0};
41
+ const int dy[] = {0, 0, 1, -1};
42
+
43
+ while(!q.empty()) {
44
+ auto [x, y] = q.front(); q.pop();
45
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BFS,
46
+ std::string(" - Checking Position (")
47
+ + std::to_string(x) + ", " + std::to_string(y) + ")");
48
+
49
+ for(int d = 0; d < 4; d += 1) {
50
+ int nx = x + dx[d];
51
+ int ny = y + dy[d];
52
+
53
+ // 在调试模式下输出访问到的位置
54
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BFS,
55
+ std::string(" - Checking Adj Position (")
56
+ + std::to_string(nx) + ", " + std::to_string(ny) + ")");
57
+
58
+ // 不需要访问已经访问过或者是障碍物的节点
59
+ // 这里必须先判断 new_graph.getPos(nx, ny) 因为 vis.getPos(nx, ny) 没有边界安全
60
+ if(new_graph.getPos(nx, ny) || vis.getPos(nx, ny)) {
61
+ continue;
62
+ }
63
+
64
+ // 既不是障碍物,也没访问过,那就走过去
65
+ vis.setPos(nx, ny, 1);
66
+ q.push(std::make_tuple(nx, ny));
67
+ }
68
+ }
69
+
70
+ // 返回哪些位置能访问
71
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BFS, "BFS Finished");
72
+ return vis;
73
+ }
74
+ };
@@ -0,0 +1,130 @@
1
+ #pragma once
2
+
3
+ #ifndef DEBUG_BORDER_DETECT
4
+ #define DEBUG_BORDER_DETECT (0)
5
+ #else
6
+ #undef DEBUG_BORDER_DETECT
7
+ #define DEBUG_BORDER_DETECT (1)
8
+ #endif
9
+
10
+ #include <set>
11
+
12
+ #include "BFS/BfsAlgo.h"
13
+ #include "DataInput/FileDataInput.h"
14
+ #include "Graph/ConnectedComponents.h"
15
+ #include "Graph/DiagramGraph.h"
16
+ #include "IntMatrix2/BorderMask.h"
17
+ #include "IntMatrix2/ZeroOneMatrix.h"
18
+
19
+ #include "../Utils/MyAssert.h"
20
+ #include "../Utils/Debug.h"
21
+
22
+ class BorderDetect {
23
+ private:
24
+ // 计算两个集合的交集
25
+ std::set<int> intersect(std::set<int> a, std::set<int> b) const {
26
+ std::set<int> ans;
27
+ for(auto item: a) {
28
+ if(b.find(item) != b.end()) {
29
+ ans.insert(item);
30
+ }
31
+ }
32
+ return ans;
33
+ }
34
+
35
+ public:
36
+
37
+ // 获取所有联通分支
38
+ virtual std::vector<std::set<int>> getAllCc(const IntMatrix2& imx) const {
39
+ auto dg = DiagramGraph(imx);
40
+ auto cc_alg = ConnectedComponents(dg);
41
+ auto all_cc = cc_alg.getConnectedComponents();
42
+ return all_cc;
43
+ }
44
+
45
+ // 输出所有连通分支到一个 json 字符串
46
+ virtual std::string jsonifyAllCc(const std::vector<std::set<int>>& all_cc) const {
47
+ std::string json_string;
48
+
49
+ bool first_line = true;
50
+ json_string += "[\n";
51
+ for(const auto& cc: all_cc) {
52
+ if(first_line) {
53
+ first_line = false;
54
+ }else {
55
+ json_string += ",\n";
56
+ }
57
+ bool first = true;
58
+ for(const auto& item: cc) {
59
+ if(first) {
60
+ first = false;
61
+ json_string += " [";
62
+ }else {
63
+ json_string += ", ";
64
+ }
65
+ json_string += std::to_string(item);
66
+ }
67
+ json_string += "]";
68
+ }
69
+ json_string += "\n]\n";
70
+ return json_string;
71
+ }
72
+
73
+ // 检查最大编号所在的连通分支是否在边界上
74
+ // 这里的 IntMatrix 是一个二维的 int 矩阵
75
+ // 你需要保证最外围的一圈元素都是零(空地)
76
+ // last_socket_id = -1 则要求最大编号 socket 所在连通分支在最外圈
77
+ // last_socket_id > 0 则要求 last_socket_id 所在连通分支在最外圈
78
+ virtual bool checkBorderMaxCC(int last_socket_id, const IntMatrix2& imx) const {
79
+
80
+ // 获取整个矩阵中的最大元素
81
+ auto mxv = imx.getMax();
82
+ ASSERT(mxv > 0);
83
+
84
+ int lastv = mxv;
85
+ if(last_socket_id > 0) {
86
+ lastv = last_socket_id;
87
+ }
88
+
89
+ // 将所有非零位置设置为 1
90
+ auto mmx = ZeroOneMatrix(imx);
91
+
92
+ // 从左上角位置出发,遍历所有能走的空白位置
93
+ // 1 是障碍物,0 是可通行位置
94
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BORDER_DETECT, "Solving BFS");
95
+ BfsAlgo bfs_algo;
96
+ auto vis_mx = bfs_algo.search(mmx, 0, 0);
97
+
98
+ // 检索 0 区域的边界位置
99
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BORDER_DETECT, "Solving Border");
100
+ auto border_pos_raw = BorderMask(std::make_shared<ZeroOneMatrix>(vis_mx), 0);
101
+ auto border_pos = ZeroOneMatrix(border_pos_raw);
102
+
103
+ // 在原始数据矩阵中进行筛选
104
+ // 筛选出所有在边界上的节点
105
+ auto set_int = border_pos.select(imx);
106
+
107
+ // 计算原图中的所有联通分支
108
+ // all_cc 包含了所有的 connected component 对应的 std::set<int>
109
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BORDER_DETECT, "Solving Connected Component");
110
+ auto dg = DiagramGraph(imx);
111
+ auto cc_alg = ConnectedComponents(dg);
112
+ auto all_cc = cc_alg.getConnectedComponents();
113
+
114
+ // 找到最后编号对应的连通分量
115
+ auto lastv_cc = std::set<int>();
116
+ for(const auto& cc: all_cc) {
117
+ if(cc.find(lastv) != cc.end()) {
118
+ lastv_cc = cc;
119
+ }
120
+ }
121
+
122
+ // 检查最大联通分支是否是独立在外的
123
+ // 如果最大联通分支是独立在外的,那么我们的算法
124
+ // 能够保证一个连通分支在最外侧,因此大概率说明不改变 pdcode 也可以做联通和
125
+ // 但是这一点需要进一步进行验证
126
+ // 具体做法就是对所有 link 考虑将其所有联通分支 swap 成最大编号联通分支并生成扭结
127
+ SHOW_CERTAIN_DEBUG_MESSAGE(DEBUG_BORDER_DETECT, "Checking Cover");
128
+ return intersect(lastv_cc, set_int).size() != 0;
129
+ }
130
+ };
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+
3
+ #include <iostream>
4
+ #include "../IntMatrix2/IntMatrix2.h"
5
+
6
+ class AbstractDataInput {
7
+ public:
8
+ virtual ~AbstractDataInput(){}
9
+ virtual IntMatrix2 loadMatrix(std::istream& in) const = 0;
10
+ };
@@ -0,0 +1,104 @@
1
+ #pragma once
2
+
3
+ #include <algorithm> // 用于std::remove_if
4
+ #include <cctype> // 用于std::isspace
5
+ #include <fstream>
6
+ #include <iostream>
7
+ #include <sstream>
8
+ #include <string>
9
+ #include <utility> // 用于std::pair
10
+ #include <vector>
11
+
12
+ #include "AbstractDataInput.h"
13
+ #include "../../Utils/MyAssert.h"
14
+
15
+ class FileDataInput: public AbstractDataInput{
16
+ private:
17
+
18
+ // 辅助函数:去除字符串首尾的空白字符(空格、制表符、换行等)
19
+ std::string trim(const std::string& str) const {
20
+ // 找到第一个非空白字符的位置
21
+ auto start = str.find_first_not_of(" \t\n\r\f\v");
22
+ if (start == std::string::npos) {
23
+ return ""; // 全是空白字符,返回空字符串
24
+ }
25
+ // 找到最后一个非空白字符的位置
26
+ auto end = str.find_last_not_of(" \t\n\r\f\v");
27
+ return str.substr(start, end - start + 1);
28
+ }
29
+
30
+ // 核心函数:统计非空行数量,并存储非空行到vector
31
+ // 返回值:pair<非空行数量, 存储非空行的vector>
32
+ std::pair<int, std::vector<std::string>> count_non_empty_lines(std::istream& is) const {
33
+ std::vector<std::string> non_empty_lines;
34
+ std::string line;
35
+ int count = 0;
36
+
37
+ // 逐行读取输入流,直到流结束
38
+ while (std::getline(is, line)) {
39
+ // 去除首尾空白后判断是否为非空行
40
+ std::string trimmed_line = trim(line);
41
+ if (!trimmed_line.empty()) {
42
+ non_empty_lines.push_back(line); // 存储原始行(而非去除空白后的行)
43
+ count++;
44
+ }
45
+ }
46
+
47
+ // 检查流是否正常结束(处理读取过程中的错误)
48
+ if (is.bad()) {
49
+ throw std::runtime_error("读取输入流时发生严重错误!");
50
+ }
51
+
52
+ return {count, non_empty_lines};
53
+ }
54
+
55
+ /**
56
+ * @brief 统计一行字符串中按空白字符切分的非空白段数量
57
+ * @param line 输入的一行字符串(std::string)
58
+ * @return 非空白段的数量(int)
59
+ * @note 空白字符包括:空格、制表符(\t)、换行(\n)、回车(\r)等,连续空白只算一个分隔
60
+ */
61
+ int count_non_blank_segments(const std::string& line) const {
62
+ int count = 0; // 非空白段计数
63
+ bool in_segment = false; // 标记是否处于非空白段中
64
+
65
+ // 遍历字符串的每个字符
66
+ for (char c : line) {
67
+ // 判断当前字符是否为空白字符
68
+ if (std::isspace(static_cast<unsigned char>(c))) {
69
+ // 空白字符:退出非空白段
70
+ in_segment = false;
71
+ } else {
72
+ // 非空白字符:如果未处于段中,计数+1并标记进入段
73
+ if (!in_segment) {
74
+ count++;
75
+ in_segment = true;
76
+ }
77
+ // 已处于段中,无需处理(连续非空白字符属于同一段)
78
+ }
79
+ }
80
+
81
+ return count;
82
+ }
83
+
84
+ public:
85
+ virtual ~FileDataInput() {}
86
+ virtual IntMatrix2 loadMatrix(std::istream& in) const override {
87
+ auto [row_cnt, vec] = count_non_empty_lines(in);
88
+ ASSERT(row_cnt > 0);
89
+
90
+ auto col_cnt = count_non_blank_segments(vec[0]);
91
+ auto int_matrix = IntMatrix2(row_cnt, col_cnt);
92
+
93
+ for(int i = 0; i < row_cnt; i += 1) {
94
+ std::stringstream ss;
95
+ ss << vec[i];
96
+ for(int j = 0; j < col_cnt; j += 1) {
97
+ int v; ss >> v;
98
+ int_matrix.setPos(i, j, v);
99
+ }
100
+ }
101
+
102
+ return int_matrix;
103
+ }
104
+ };
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #include <set>
4
+ #include <vector>
5
+
6
+ // 一个只读的抽象图
7
+ class AbstractGraph {
8
+ public:
9
+ virtual ~AbstractGraph() {}
10
+
11
+ // 获取最大节点编号
12
+ // 节点编号大于等于 1
13
+ virtual int getMaxNodeId() const = 0;
14
+
15
+ // 判断某个节点编号是否存在
16
+ virtual bool checkHasNode(int nodeId) const = 0;
17
+
18
+ // 找到某个节点下一步能走到的所有节点
19
+ virtual std::vector<int> getNextNode(int nodeId) const = 0;
20
+ };
@@ -0,0 +1,74 @@
1
+ #pragma once
2
+
3
+ #include <iostream>
4
+
5
+ #include <algorithm>
6
+ #include <cstdlib>
7
+ #include <memory>
8
+ #include "AbstractGraph.h"
9
+
10
+ // 给定一个图计算所有联通分量
11
+ class ConnectedComponents {
12
+ protected:
13
+ int* fa; // union find set
14
+ int maxNodeId = 0;
15
+
16
+ int find(int x) {
17
+ if(x == fa[x]) return x;
18
+ return fa[x] = find(fa[x]);
19
+ }
20
+
21
+ void link(int x, int y) {
22
+ int rx = find(x);
23
+ int ry = find(y);
24
+ if(rx != ry) {
25
+ if(rand() & 1) std::swap(rx, ry);
26
+ fa[rx] = ry;
27
+ }
28
+ }
29
+
30
+ // 计算整个图的所有连通分支
31
+ void construct_all(const AbstractGraph& ag) {
32
+ for(int i = 1; i <= ag.getMaxNodeId(); i += 1) {
33
+ for(auto nxt: ag.getNextNode(i)) {
34
+ link(i, nxt);
35
+ }
36
+ }
37
+ }
38
+
39
+ public:
40
+ virtual ~ConnectedComponents() {
41
+ delete[] fa;
42
+ }
43
+ ConnectedComponents(const AbstractGraph& ag): maxNodeId(ag.getMaxNodeId()) {
44
+ fa = new int[ag.getMaxNodeId() + 1];
45
+ for(int i = 1; i <= ag.getMaxNodeId(); i += 1) {
46
+ fa[i] = i;
47
+ }
48
+ construct_all(ag);
49
+ }
50
+
51
+ virtual std::vector<std::set<int>> getConnectedComponents() {
52
+
53
+ // 初始化集合
54
+ auto ans = std::vector<std::set<int>>();
55
+ while((int)ans.size() - 1 < maxNodeId) {
56
+ ans.push_back(std::set<int>());
57
+ }
58
+
59
+ // 枚举所有对象,加入对应的等价类
60
+ for(int i = 1; i <= maxNodeId; i += 1) {
61
+ int root_i = find(i);
62
+ ans[root_i].insert(i);
63
+ }
64
+
65
+ // 将所有非空对象整理出来
66
+ auto non_empty = std::vector<std::set<int>>();
67
+ for(int i = 1; i <= maxNodeId; i += 1) {
68
+ if(ans[i].size() > 0) {
69
+ non_empty.push_back(ans[i]);
70
+ }
71
+ }
72
+ return non_empty;
73
+ }
74
+ };
@@ -0,0 +1,50 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+
5
+ #include "AbstractGraph.h"
6
+ #include "Graph.h"
7
+ #include "../IntMatrix2/AbstractIntMatrix2.h"
8
+ #include "../../Utils/MyAssert.h"
9
+
10
+ class DiagramGraph: public AbstractGraph {
11
+ private:
12
+ Graph graph;
13
+
14
+ public:
15
+ virtual ~DiagramGraph() {}
16
+ DiagramGraph(const AbstractIntMatrix2& aim): graph() {
17
+ const int dx[] = {0, -1, 0, 1};
18
+ const int dy[] = {1, 0, -1, 0};
19
+ for(int i = 1; i < aim.getRcnt() - 1; i += 1) {
20
+ for(int j = 1; j < aim.getCcnt() - 1; j += 1) {
21
+ if(aim.getPos(i, j) < 0) {
22
+ int arr[4];
23
+ for(int d = 0; d < 4; d += 1) {
24
+ arr[d] = aim.getPos(i + dx[d], j + dy[d]);
25
+ ASSERT(arr[d] > 0);
26
+ graph.setMaxNodeId(d);
27
+ }
28
+ graph.addEdge(arr[0], arr[2]); // 对边添加
29
+ graph.addEdge(arr[1], arr[3]);
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ // 获取最大节点编号
36
+ // 节点编号大于等于 1
37
+ virtual int getMaxNodeId() const override {
38
+ return graph.getMaxNodeId();
39
+ }
40
+
41
+ // 判断某个节点编号是否存在
42
+ virtual bool checkHasNode(int nodeId) const override {
43
+ return 1 <= nodeId && nodeId <= graph.getMaxNodeId();
44
+ }
45
+
46
+ // 找到某个节点下一步能走到的所有节点
47
+ virtual std::vector<int> getNextNode(int nodeId) const {
48
+ return graph.getNextNode(nodeId);
49
+ }
50
+ };
@@ -0,0 +1,56 @@
1
+ #pragma once
2
+
3
+ #include "AbstractGraph.h"
4
+ #include "../../Utils/MyAssert.h"
5
+
6
+ class Graph: public AbstractGraph {
7
+ protected:
8
+ int maxNodeId;
9
+ std::vector<std::vector<int>> nextNode; // 邻接表
10
+
11
+ public:
12
+ virtual ~Graph() {}
13
+
14
+ Graph(): maxNodeId(0) {
15
+ nextNode.push_back(std::vector<int>());
16
+ }
17
+ Graph(int _maxNodeCnt): maxNodeId(0) {
18
+ nextNode.push_back(std::vector<int>());
19
+ setMaxNodeId(_maxNodeCnt);
20
+ }
21
+
22
+ // 获取最大节点编号
23
+ // 节点编号大于等于 1
24
+ virtual int getMaxNodeId() const override {
25
+ return maxNodeId;
26
+ }
27
+
28
+ // 判断某个节点编号是否存在
29
+ virtual bool checkHasNode(int nodeId) const override {
30
+ return 1 <= nodeId && nodeId <= maxNodeId;
31
+ }
32
+
33
+ // 提高最大节点编号
34
+ virtual void setMaxNodeId(int newMaxNodeId) {
35
+ while(maxNodeId < newMaxNodeId) {
36
+ maxNodeId += 1;
37
+ nextNode.push_back({}); // 空序列
38
+ }
39
+ }
40
+
41
+ // 新增一个双向边
42
+ virtual void addEdge(int f, int t) {
43
+ setMaxNodeId(f);
44
+ setMaxNodeId(t);
45
+ ASSERT(checkHasNode(f)); // 排除小于零的情况
46
+ ASSERT(checkHasNode(t));
47
+ nextNode[f].push_back(t); // 双向加边
48
+ nextNode[t].push_back(f);
49
+ }
50
+
51
+ // 找到某个节点下一步能走到的所有节点
52
+ virtual std::vector<int> getNextNode(int nodeId) const override {
53
+ ASSERT(checkHasNode(nodeId));
54
+ return nextNode[nodeId];
55
+ }
56
+ };
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ class AbstractIntCombine {
4
+ public:
5
+ virtual ~AbstractIntCombine() {}
6
+ virtual int combineInt(int xpos, int ypos, int lhs_val, int rhs_val) const = 0;
7
+ };
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ class AbstractIntMap {
4
+ public:
5
+ virtual ~AbstractIntMap() {}
6
+ virtual int mapInt(int xpos, int ypos, int vFrom) const = 0;
7
+ };
@@ -0,0 +1,12 @@
1
+ #pragma once
2
+
3
+ #include "AbstractIntMap.h"
4
+
5
+ //
6
+ class NotIntMap: public AbstractIntMap {
7
+ public:
8
+ virtual ~NotIntMap() {}
9
+ virtual int mapInt(int xpos, int ypos, int vFrom) const override {
10
+ return vFrom == 0;
11
+ }
12
+ };