link-rep-to-pd-code 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.
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 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,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: link-rep-to-pd-code
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: given a link-rep, output its pd_code for the composite link or knot.
|
|
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: link_rep
|
|
18
|
+
Requires-Dist: pd_code_components
|
|
19
|
+
Requires-Dist: pd_code_connected_sum
|
|
20
|
+
Requires-Dist: pd_code_sanity
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# link_rep_to_pd_code
|
|
24
|
+
given a link-rep, output its pd_code for the composite link or knot.
|
|
25
|
+
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import pd_code_sanity
|
|
2
|
+
import link_rep
|
|
3
|
+
import pd_code_components
|
|
4
|
+
import pd_code_connected_sum
|
|
5
|
+
|
|
6
|
+
# 内置 packages
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
def link_components(pd_code_list:list[list[list]], link_method:link_rep.LinkMethod):
|
|
10
|
+
if not isinstance(link_method, link_rep.LinkMethod):
|
|
11
|
+
raise TypeError()
|
|
12
|
+
|
|
13
|
+
# 构建一个未进行连接的所有扭结的映射
|
|
14
|
+
# 每当一个 link 被连接到其他分量了,就将 link_dict 中对应位置设为 None
|
|
15
|
+
link_dict = {}
|
|
16
|
+
for i in range(len(pd_code_list)):
|
|
17
|
+
link_dict[i] = pd_code_list[i]
|
|
18
|
+
|
|
19
|
+
# 记录每一个连通分支的代表元
|
|
20
|
+
# 代表元的编号实时变化
|
|
21
|
+
components_rep_dict = {}
|
|
22
|
+
for i in range(len(pd_code_list)):
|
|
23
|
+
all_components = pd_code_components.get_components_from_pd_code(pd_code_list[i])
|
|
24
|
+
all_reps = sorted([ # 第一个元素作为代表元
|
|
25
|
+
component[0]
|
|
26
|
+
for component in all_components
|
|
27
|
+
])
|
|
28
|
+
components_rep_dict[i] = [ # (i, item) 表示这个代表元在第 i 个链环上
|
|
29
|
+
(i, item) # 随着合并进程,i 和 item 值可能发生改变
|
|
30
|
+
for item in all_reps
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# 给所有编号减一
|
|
34
|
+
def sub_one(lis:list[int]) -> list[int]:
|
|
35
|
+
return [
|
|
36
|
+
item - 1
|
|
37
|
+
for item in lis]
|
|
38
|
+
|
|
39
|
+
for link_term in link_method.component_list:
|
|
40
|
+
a_id, a_rep_idx = sub_one(link_term.component_list[0])
|
|
41
|
+
b_id, b_rep_idx = sub_one(link_term.component_list[1])
|
|
42
|
+
|
|
43
|
+
# 计算他们现在所在的位置
|
|
44
|
+
now_a_id, now_a_rep_idx = components_rep_dict[a_id][a_rep_idx]
|
|
45
|
+
now_b_id, now_b_rep_idx = components_rep_dict[b_id][b_rep_idx]
|
|
46
|
+
|
|
47
|
+
if now_a_id == now_b_id: # 不能反复连接已经连接到一起的扭结
|
|
48
|
+
raise AssertionError()
|
|
49
|
+
|
|
50
|
+
# 两个 pd_code
|
|
51
|
+
old_pd_code_a, link_dict[now_a_id] = link_dict[now_a_id], None
|
|
52
|
+
old_pd_code_b, link_dict[now_b_id] = link_dict[now_b_id], None
|
|
53
|
+
|
|
54
|
+
if old_pd_code_a is None:
|
|
55
|
+
raise AssertionError()
|
|
56
|
+
|
|
57
|
+
if old_pd_code_b is None:
|
|
58
|
+
raise AssertionError()
|
|
59
|
+
|
|
60
|
+
# 获得新的扭结 pd_code 以及编号映射规则
|
|
61
|
+
new_pd_code, num_map = pd_code_connected_sum.connected_sum(
|
|
62
|
+
old_pd_code_a,
|
|
63
|
+
old_pd_code_b,
|
|
64
|
+
now_a_rep_idx,
|
|
65
|
+
now_b_rep_idx
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# 占据前者的连通分支
|
|
69
|
+
link_dict[now_a_id] = new_pd_code
|
|
70
|
+
|
|
71
|
+
# 重新编写代表元编号
|
|
72
|
+
for i in range(len(components_rep_dict[a_id])):
|
|
73
|
+
_, old_a_rep = components_rep_dict[a_id][i]
|
|
74
|
+
components_rep_dict[a_id][i] = (now_a_id, num_map["a_" + str(old_a_rep)])
|
|
75
|
+
|
|
76
|
+
for i in range(len(components_rep_dict[b_id])):
|
|
77
|
+
_, old_b_rep = components_rep_dict[b_id][i]
|
|
78
|
+
components_rep_dict[b_id][i] = (now_a_id, num_map["b_" + str(old_b_rep)])
|
|
79
|
+
|
|
80
|
+
# 确保合并到最后恰好只剩下一个连通分支
|
|
81
|
+
not_none_list = []
|
|
82
|
+
for num in link_dict:
|
|
83
|
+
if link_dict[num] is not None:
|
|
84
|
+
not_none_list.append(link_dict[num])
|
|
85
|
+
|
|
86
|
+
if len(not_none_list) != 1: # 有 N 个连通分支,则会连接 N - 1 次
|
|
87
|
+
raise AssertionError()
|
|
88
|
+
|
|
89
|
+
return not_none_list[0]
|
|
90
|
+
|
|
91
|
+
def link_rep_to_pd_code(link_rep_str:str) -> list[list]:
|
|
92
|
+
link_rep_item = link_rep.LinkRep()
|
|
93
|
+
link_rep_item.deserialize(link_rep_str)
|
|
94
|
+
|
|
95
|
+
# 记录扭结名称到 pd_code 的映射
|
|
96
|
+
var_map = link_rep_item.var_def.var_map
|
|
97
|
+
name_map_to_pd_code = dict()
|
|
98
|
+
|
|
99
|
+
# 检查 PD_CODE 和 扭结名称类型
|
|
100
|
+
for var_link_id, var_pd_code in var_map:
|
|
101
|
+
if not pd_code_sanity.sanity(var_pd_code):
|
|
102
|
+
raise TypeError()
|
|
103
|
+
if not isinstance(var_link_id, link_rep.LinkId):
|
|
104
|
+
raise TypeError()
|
|
105
|
+
|
|
106
|
+
# 记录变量名到 pd_code 的映射
|
|
107
|
+
for var_link_id, var_pd_code in var_map:
|
|
108
|
+
name_map_to_pd_code[var_link_id.serialize()] = var_pd_code
|
|
109
|
+
|
|
110
|
+
# 依次获取所有 link 素分量的 pd_code
|
|
111
|
+
pd_code_list = []
|
|
112
|
+
for item in link_rep_item.link_set.var_list:
|
|
113
|
+
var_name_now = item.serialize()
|
|
114
|
+
if name_map_to_pd_code.get(var_name_now) is None: # 没有找到相关的错误
|
|
115
|
+
raise ValueError()
|
|
116
|
+
pd_code_list.append(name_map_to_pd_code[var_name_now])
|
|
117
|
+
|
|
118
|
+
# 只有一个素分量的情况
|
|
119
|
+
if len(pd_code_list) == 1:
|
|
120
|
+
return pd_code_list[0]
|
|
121
|
+
|
|
122
|
+
# 返回一个相对复杂的连接过程
|
|
123
|
+
return link_components(pd_code_list, link_rep_item.link_method)
|
|
124
|
+
|
|
125
|
+
def _test():
|
|
126
|
+
import com_link_gen_10 # 除了测试部分外,不依赖这个包
|
|
127
|
+
import random
|
|
128
|
+
|
|
129
|
+
# 随机生成的一组测试数据
|
|
130
|
+
TEST_DATA = json.loads(r'{"3": "// automatically generated by com-link-gen-10 (version:0.0.3)\n// - command: com_link_gen(10, 3)\nmL2a1: [[4, 2, 3, 1], [2, 4, 1, 3]]\nmK3a1: [[1, 4, 2, 5], [3, 6, 4, 1], [5, 2, 6, 3]]\nmL4a1: [[6, 2, 7, 1], [8, 4, 5, 3], [2, 6, 3, 5], [4, 8, 1, 7]]\n[mL2a1, mK3a1, mL4a1]\nL[1, 1]#L[2, 1]\nL[1, 1]#L[3, 1]\n", "1": "// automatically generated by com-link-gen-10 (version:0.0.3)\n// - command: com_link_gen(10, 3)\nK8a8: [[1, 7, 2, 6], [3, 12, 4, 13], [5, 9, 6, 8], [7, 3, 8, 2], [9, 16, 10, 1], [11, 14, 12, 15], [13, 4, 14, 5], [15, 10, 16, 11]]\n[K8a8]\n", "2": "// automatically generated by com-link-gen-10 (version:0.0.3)\n// - command: com_link_gen(10, 3)\nmK3a1: [[1, 4, 2, 5], [3, 6, 4, 1], [5, 2, 6, 3]]\nmK7a1: [[1, 8, 2, 9], [3, 10, 4, 11], [5, 12, 6, 13], [7, 14, 8, 1], [9, 2, 10, 3], [11, 4, 12, 5], [13, 6, 14, 7]]\n[mK3a1, mK7a1]\nL[1, 1]#L[2, 1]\n"}')
|
|
131
|
+
TEST_DATA_1 = TEST_DATA["1"]
|
|
132
|
+
TEST_DATA_2 = TEST_DATA["2"]
|
|
133
|
+
TEST_DATA_3 = TEST_DATA["3"]
|
|
134
|
+
|
|
135
|
+
# 生成一个基础测试
|
|
136
|
+
K3a1_K3a1 = """
|
|
137
|
+
// this test case is manually configaured.
|
|
138
|
+
K3a1: [[1, 5, 2, 4], [3, 1, 4, 6], [5, 3, 6, 2]]
|
|
139
|
+
[K3a1, K3a1, K3a1]
|
|
140
|
+
L[1, 1]#L[2, 1]
|
|
141
|
+
L[1, 1]#L[3, 1]
|
|
142
|
+
""".lstrip()
|
|
143
|
+
|
|
144
|
+
# 随机生成的测试数据
|
|
145
|
+
def random_test_data() -> dict[str, str]:
|
|
146
|
+
prime_cnt_to_obj = dict()
|
|
147
|
+
sequence = com_link_gen_10.com_link_gen(10, 3)
|
|
148
|
+
random.shuffle(sequence)
|
|
149
|
+
|
|
150
|
+
for link_rep_str in sequence:
|
|
151
|
+
link_rep_item = link_rep.LinkRep()
|
|
152
|
+
link_rep_item.deserialize(link_rep_str)
|
|
153
|
+
|
|
154
|
+
prime_cnt = len(link_rep_item.link_set.var_list)
|
|
155
|
+
if prime_cnt_to_obj.get(prime_cnt) is None:
|
|
156
|
+
prime_cnt_to_obj[prime_cnt] = link_rep_str
|
|
157
|
+
return prime_cnt_to_obj
|
|
158
|
+
|
|
159
|
+
print(link_rep_to_pd_code(K3a1_K3a1))
|
|
160
|
+
|
|
161
|
+
if __name__ == "__main__":
|
|
162
|
+
_test()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "link-rep-to-pd-code"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "given a link-rep, output its pd_code for the composite link or knot."
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "GGN_2015",email = "neko@jlulug.org"}
|
|
7
|
+
]
|
|
8
|
+
license = {text = "MIT"}
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"pd_code_sanity",
|
|
13
|
+
"link_rep",
|
|
14
|
+
"pd_code_components",
|
|
15
|
+
"pd_code_connected_sum"
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
[build-system]
|
|
20
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
21
|
+
build-backend = "poetry.core.masonry.api"
|