cpp-pd-code-simplify-interface 0.1.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.
- cpp_pd_code_simplify_interface-0.1.0/PKG-INFO +94 -0
- cpp_pd_code_simplify_interface-0.1.0/README.md +73 -0
- cpp_pd_code_simplify_interface-0.1.0/build_backend/cpp_pd_code_simplify_interface_build_backend.py +228 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/__init__.py +21 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/__main__.py +4 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/data/include/pdcode_simplify/pdcode_simplify.hpp +145 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/data/src/native_interface.cpp +195 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/data/src/pdcode_simplify.cpp +1690 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/main.py +474 -0
- cpp_pd_code_simplify_interface-0.1.0/cpp_pd_code_simplify_interface/py.typed +1 -0
- cpp_pd_code_simplify_interface-0.1.0/pyproject.toml +35 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cpp-pd-code-simplify-interface
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python interface for cpp-pd-code-simplify with runtime C++ compilation.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Author: GGN_2015
|
|
7
|
+
Author-email: neko@jlulug.org
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: cpp-simple-interface (>=0.1.2)
|
|
16
|
+
Project-URL: Documentation, https://github.com/GGN-2015/cpp-pd-code-simplify/blob/main/docs/python-interface.md
|
|
17
|
+
Project-URL: Homepage, https://github.com/GGN-2015/cpp-pd-code-simplify
|
|
18
|
+
Project-URL: Repository, https://github.com/GGN-2015/cpp-pd-code-simplify
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# cpp-pd-code-simplify-interface
|
|
22
|
+
|
|
23
|
+
`cpp-pd-code-simplify-interface` is a Python package for calling the
|
|
24
|
+
`cpp-pd-code-simplify` C++ implementation from Python.
|
|
25
|
+
|
|
26
|
+
The package is designed for PyPI distribution:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
pip install cpp-pd-code-simplify-interface
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
It ships the C++ source code inside the wheel and source distribution. On first
|
|
33
|
+
use, the package compiles a cached local dynamic library through
|
|
34
|
+
`cpp-simple-interface`; later calls reuse that library through `ctypes`. A C++14
|
|
35
|
+
compiler compatible with `g++` must be available at runtime.
|
|
36
|
+
|
|
37
|
+
Calls use the C++ library's default preprocessing pipeline: R1-move removal
|
|
38
|
+
followed by nugatory-crossing removal.
|
|
39
|
+
|
|
40
|
+
## Example
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import cpp_pd_code_simplify_interface as simplify
|
|
44
|
+
|
|
45
|
+
pd_code = "PD[X[1,5,2,4],X[3,1,4,6],X[5,3,6,2]]"
|
|
46
|
+
result = simplify.simplify(pd_code)
|
|
47
|
+
print(result["simplification_found"])
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Batch use:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
results = simplify.simplify_many([pd_code, "PD[]"])
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To select a compiler:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
CXX=clang++ python your_script.py
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Windows PowerShell:
|
|
63
|
+
|
|
64
|
+
```powershell
|
|
65
|
+
$env:CXX = "C:\path\to\g++.exe"
|
|
66
|
+
python your_script.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
On Windows, use a compiler whose target architecture matches Python. A 64-bit
|
|
70
|
+
Python process needs a 64-bit compiler target.
|
|
71
|
+
|
|
72
|
+
Command-line use also supports multi-line PD-code files:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
python -m cpp_pd_code_simplify_interface --pd-file inputs.pd --max-paths 100
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Build And Publish
|
|
79
|
+
|
|
80
|
+
From this directory:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
poetry build
|
|
84
|
+
poetry publish
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Use `poetry publish --build` to build and upload in one command.
|
|
88
|
+
|
|
89
|
+
For local testing:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
poetry run python -m cpp_pd_code_simplify_interface "PD[]"
|
|
93
|
+
```
|
|
94
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# cpp-pd-code-simplify-interface
|
|
2
|
+
|
|
3
|
+
`cpp-pd-code-simplify-interface` is a Python package for calling the
|
|
4
|
+
`cpp-pd-code-simplify` C++ implementation from Python.
|
|
5
|
+
|
|
6
|
+
The package is designed for PyPI distribution:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pip install cpp-pd-code-simplify-interface
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
It ships the C++ source code inside the wheel and source distribution. On first
|
|
13
|
+
use, the package compiles a cached local dynamic library through
|
|
14
|
+
`cpp-simple-interface`; later calls reuse that library through `ctypes`. A C++14
|
|
15
|
+
compiler compatible with `g++` must be available at runtime.
|
|
16
|
+
|
|
17
|
+
Calls use the C++ library's default preprocessing pipeline: R1-move removal
|
|
18
|
+
followed by nugatory-crossing removal.
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import cpp_pd_code_simplify_interface as simplify
|
|
24
|
+
|
|
25
|
+
pd_code = "PD[X[1,5,2,4],X[3,1,4,6],X[5,3,6,2]]"
|
|
26
|
+
result = simplify.simplify(pd_code)
|
|
27
|
+
print(result["simplification_found"])
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Batch use:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
results = simplify.simplify_many([pd_code, "PD[]"])
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To select a compiler:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
CXX=clang++ python your_script.py
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Windows PowerShell:
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
$env:CXX = "C:\path\to\g++.exe"
|
|
46
|
+
python your_script.py
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
On Windows, use a compiler whose target architecture matches Python. A 64-bit
|
|
50
|
+
Python process needs a 64-bit compiler target.
|
|
51
|
+
|
|
52
|
+
Command-line use also supports multi-line PD-code files:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
python -m cpp_pd_code_simplify_interface --pd-file inputs.pd --max-paths 100
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Build And Publish
|
|
59
|
+
|
|
60
|
+
From this directory:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
poetry build
|
|
64
|
+
poetry publish
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Use `poetry publish --build` to build and upload in one command.
|
|
68
|
+
|
|
69
|
+
For local testing:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
poetry run python -m cpp_pd_code_simplify_interface "PD[]"
|
|
73
|
+
```
|
cpp_pd_code_simplify_interface-0.1.0/build_backend/cpp_pd_code_simplify_interface_build_backend.py
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import hashlib
|
|
5
|
+
import io
|
|
6
|
+
import shutil
|
|
7
|
+
import tarfile
|
|
8
|
+
import tempfile
|
|
9
|
+
import zipfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from poetry.core.masonry import api as poetry_api
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
16
|
+
REPO_ROOT = PROJECT_ROOT.parents[1]
|
|
17
|
+
|
|
18
|
+
SOURCE_FILES = [
|
|
19
|
+
(
|
|
20
|
+
REPO_ROOT / "src" / "pdcode_simplify.cpp",
|
|
21
|
+
PROJECT_ROOT / "cpp_pd_code_simplify_interface" / "data" / "src" / "pdcode_simplify.cpp",
|
|
22
|
+
"cpp_pd_code_simplify_interface/data/src/pdcode_simplify.cpp",
|
|
23
|
+
),
|
|
24
|
+
(
|
|
25
|
+
PROJECT_ROOT / "cpp_pd_code_simplify_interface" / "data" / "src" / "native_interface.cpp",
|
|
26
|
+
PROJECT_ROOT / "cpp_pd_code_simplify_interface" / "data" / "src" / "native_interface.cpp",
|
|
27
|
+
"cpp_pd_code_simplify_interface/data/src/native_interface.cpp",
|
|
28
|
+
),
|
|
29
|
+
(
|
|
30
|
+
REPO_ROOT / "include" / "pdcode_simplify" / "pdcode_simplify.hpp",
|
|
31
|
+
PROJECT_ROOT
|
|
32
|
+
/ "cpp_pd_code_simplify_interface"
|
|
33
|
+
/ "data"
|
|
34
|
+
/ "include"
|
|
35
|
+
/ "pdcode_simplify"
|
|
36
|
+
/ "pdcode_simplify.hpp",
|
|
37
|
+
"cpp_pd_code_simplify_interface/data/include/pdcode_simplify/pdcode_simplify.hpp",
|
|
38
|
+
),
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _sync_cpp_sources() -> None:
|
|
43
|
+
missing = []
|
|
44
|
+
for source, target, _ in SOURCE_FILES:
|
|
45
|
+
if source.exists():
|
|
46
|
+
if source.resolve() != target.resolve():
|
|
47
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
48
|
+
shutil.copyfile(source, target)
|
|
49
|
+
elif not target.exists():
|
|
50
|
+
missing.append((source, target))
|
|
51
|
+
if missing:
|
|
52
|
+
details = ", ".join(f"{source} or {target}" for source, target in missing)
|
|
53
|
+
raise FileNotFoundError(f"cpp-pd-code-simplify source files were not found: {details}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _clean_cpp_sources() -> None:
|
|
57
|
+
for source, target, _ in SOURCE_FILES:
|
|
58
|
+
if source.exists() and target.exists() and source.resolve() != target.resolve():
|
|
59
|
+
target.unlink()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _source_payloads() -> dict[str, bytes]:
|
|
63
|
+
payloads = {}
|
|
64
|
+
for source, target, wheel_name in SOURCE_FILES:
|
|
65
|
+
if target.exists():
|
|
66
|
+
payloads[wheel_name] = target.read_bytes()
|
|
67
|
+
elif source.exists():
|
|
68
|
+
payloads[wheel_name] = source.read_bytes()
|
|
69
|
+
else:
|
|
70
|
+
raise FileNotFoundError(f"source file was not available for packaging: {wheel_name}")
|
|
71
|
+
return payloads
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _wheel_hash_and_size(data: bytes) -> tuple[str, str]:
|
|
75
|
+
digest = hashlib.sha256(data).digest()
|
|
76
|
+
encoded = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
|
|
77
|
+
return f"sha256={encoded}", str(len(data))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _make_universal_wheel_metadata(data: bytes) -> bytes:
|
|
81
|
+
text = data.decode("utf-8")
|
|
82
|
+
lines = []
|
|
83
|
+
tag_written = False
|
|
84
|
+
root_written = False
|
|
85
|
+
for line in text.splitlines():
|
|
86
|
+
if line.startswith("Root-Is-Purelib:"):
|
|
87
|
+
lines.append("Root-Is-Purelib: true")
|
|
88
|
+
root_written = True
|
|
89
|
+
elif line.startswith("Tag:"):
|
|
90
|
+
if not tag_written:
|
|
91
|
+
lines.append("Tag: py3-none-any")
|
|
92
|
+
tag_written = True
|
|
93
|
+
else:
|
|
94
|
+
lines.append(line)
|
|
95
|
+
if not root_written:
|
|
96
|
+
lines.append("Root-Is-Purelib: true")
|
|
97
|
+
if not tag_written:
|
|
98
|
+
lines.append("Tag: py3-none-any")
|
|
99
|
+
return ("\n".join(lines) + "\n").encode("utf-8")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _universal_wheel_path(wheel_path: Path, record_name: str) -> Path:
|
|
103
|
+
dist_info = record_name.split("/", 1)[0]
|
|
104
|
+
base = dist_info.removesuffix(".dist-info")
|
|
105
|
+
return wheel_path.with_name(f"{base}-py3-none-any.whl")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _rewrite_wheel_with_sources(wheel_path: Path) -> Path:
|
|
109
|
+
payloads = _source_payloads()
|
|
110
|
+
payload_names = set(payloads)
|
|
111
|
+
rows: list[tuple[str, str, str]] = []
|
|
112
|
+
|
|
113
|
+
with zipfile.ZipFile(wheel_path, "r") as zin:
|
|
114
|
+
record_name = next(
|
|
115
|
+
(name for name in zin.namelist() if name.endswith(".dist-info/RECORD")),
|
|
116
|
+
None,
|
|
117
|
+
)
|
|
118
|
+
if record_name is None:
|
|
119
|
+
raise RuntimeError(f"wheel RECORD file not found in {wheel_path}")
|
|
120
|
+
output_path = _universal_wheel_path(wheel_path, record_name)
|
|
121
|
+
temp_path = output_path.with_name(output_path.name + ".tmp")
|
|
122
|
+
|
|
123
|
+
with zipfile.ZipFile(temp_path, "w", compression=zipfile.ZIP_DEFLATED) as zout:
|
|
124
|
+
wheel_metadata_name = record_name.removesuffix("RECORD") + "WHEEL"
|
|
125
|
+
|
|
126
|
+
for item in zin.infolist():
|
|
127
|
+
if item.filename in payload_names or item.filename == record_name:
|
|
128
|
+
continue
|
|
129
|
+
data = zin.read(item.filename)
|
|
130
|
+
if item.filename == wheel_metadata_name:
|
|
131
|
+
data = _make_universal_wheel_metadata(data)
|
|
132
|
+
zout.writestr(item, data)
|
|
133
|
+
if not item.is_dir():
|
|
134
|
+
digest, size = _wheel_hash_and_size(data)
|
|
135
|
+
rows.append((item.filename, digest, size))
|
|
136
|
+
|
|
137
|
+
for name, data in sorted(payloads.items()):
|
|
138
|
+
source_info = zipfile.ZipInfo(name, date_time=(2016, 1, 1, 0, 0, 0))
|
|
139
|
+
source_info.compress_type = zipfile.ZIP_DEFLATED
|
|
140
|
+
zout.writestr(source_info, data)
|
|
141
|
+
digest, size = _wheel_hash_and_size(data)
|
|
142
|
+
rows.append((name, digest, size))
|
|
143
|
+
|
|
144
|
+
rows.append((record_name, "", ""))
|
|
145
|
+
record_text = "".join(f"{path},{digest},{size}\n" for path, digest, size in rows)
|
|
146
|
+
record_info = zipfile.ZipInfo(record_name, date_time=(2016, 1, 1, 0, 0, 0))
|
|
147
|
+
record_info.compress_type = zipfile.ZIP_DEFLATED
|
|
148
|
+
zout.writestr(record_info, record_text.encode("utf-8"))
|
|
149
|
+
|
|
150
|
+
temp_path.replace(output_path)
|
|
151
|
+
if output_path != wheel_path and wheel_path.exists():
|
|
152
|
+
wheel_path.unlink()
|
|
153
|
+
return output_path
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _rewrite_sdist_with_sources(sdist_path: Path) -> None:
|
|
157
|
+
payloads = _source_payloads()
|
|
158
|
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".tar.gz")
|
|
159
|
+
temp_path = Path(temp_file.name)
|
|
160
|
+
temp_file.close()
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
with tarfile.open(sdist_path, "r:gz") as tin, tarfile.open(temp_path, "w:gz") as tout:
|
|
164
|
+
names = tin.getnames()
|
|
165
|
+
if not names:
|
|
166
|
+
raise RuntimeError(f"sdist is empty: {sdist_path}")
|
|
167
|
+
root = names[0].split("/", 1)[0]
|
|
168
|
+
payload_names = {f"{root}/{name}" for name in payloads}
|
|
169
|
+
|
|
170
|
+
for member in tin.getmembers():
|
|
171
|
+
if member.name in payload_names:
|
|
172
|
+
continue
|
|
173
|
+
if member.isfile():
|
|
174
|
+
extracted = tin.extractfile(member)
|
|
175
|
+
if extracted is None:
|
|
176
|
+
raise RuntimeError(f"could not read {member.name} from {sdist_path}")
|
|
177
|
+
with extracted:
|
|
178
|
+
tout.addfile(member, extracted)
|
|
179
|
+
else:
|
|
180
|
+
tout.addfile(member)
|
|
181
|
+
|
|
182
|
+
for name, data in sorted(payloads.items()):
|
|
183
|
+
source_info = tarfile.TarInfo(f"{root}/{name}")
|
|
184
|
+
source_info.size = len(data)
|
|
185
|
+
source_info.mtime = 0
|
|
186
|
+
source_info.mode = 0o644
|
|
187
|
+
tout.addfile(source_info, io.BytesIO(data))
|
|
188
|
+
|
|
189
|
+
temp_path.replace(sdist_path)
|
|
190
|
+
finally:
|
|
191
|
+
if temp_path.exists():
|
|
192
|
+
temp_path.unlink()
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def get_requires_for_build_wheel(config_settings=None):
|
|
196
|
+
return poetry_api.get_requires_for_build_wheel(config_settings)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def get_requires_for_build_sdist(config_settings=None):
|
|
200
|
+
return poetry_api.get_requires_for_build_sdist(config_settings)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
|
|
204
|
+
_sync_cpp_sources()
|
|
205
|
+
try:
|
|
206
|
+
return poetry_api.prepare_metadata_for_build_wheel(metadata_directory, config_settings)
|
|
207
|
+
finally:
|
|
208
|
+
_clean_cpp_sources()
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
212
|
+
_sync_cpp_sources()
|
|
213
|
+
try:
|
|
214
|
+
wheel_name = poetry_api.build_wheel(wheel_directory, config_settings, metadata_directory)
|
|
215
|
+
final_path = _rewrite_wheel_with_sources(Path(wheel_directory) / wheel_name)
|
|
216
|
+
return final_path.name
|
|
217
|
+
finally:
|
|
218
|
+
_clean_cpp_sources()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def build_sdist(sdist_directory, config_settings=None):
|
|
222
|
+
_sync_cpp_sources()
|
|
223
|
+
try:
|
|
224
|
+
sdist_name = poetry_api.build_sdist(sdist_directory, config_settings)
|
|
225
|
+
_rewrite_sdist_with_sources(Path(sdist_directory) / sdist_name)
|
|
226
|
+
return sdist_name
|
|
227
|
+
finally:
|
|
228
|
+
_clean_cpp_sources()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .main import (
|
|
2
|
+
PdCodeSimplifyInterfaceError,
|
|
3
|
+
compile_simplifier,
|
|
4
|
+
get_simplifier_executable,
|
|
5
|
+
get_simplifier_library,
|
|
6
|
+
normalize_pd_code,
|
|
7
|
+
normalize_pd_codes,
|
|
8
|
+
simplify,
|
|
9
|
+
simplify_many,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"PdCodeSimplifyInterfaceError",
|
|
14
|
+
"compile_simplifier",
|
|
15
|
+
"get_simplifier_executable",
|
|
16
|
+
"get_simplifier_library",
|
|
17
|
+
"normalize_pd_code",
|
|
18
|
+
"normalize_pd_codes",
|
|
19
|
+
"simplify",
|
|
20
|
+
"simplify_many",
|
|
21
|
+
]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <array>
|
|
4
|
+
#include <cstddef>
|
|
5
|
+
#include <iosfwd>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
#if defined(_WIN32) && (defined(PDCODE_SIMPLIFY_SHARED) || defined(PDCODE_SIMPLIFY_BUILD_SHARED))
|
|
10
|
+
#if defined(PDCODE_SIMPLIFY_BUILD_SHARED)
|
|
11
|
+
#define PDCODE_SIMPLIFY_API __declspec(dllexport)
|
|
12
|
+
#else
|
|
13
|
+
#define PDCODE_SIMPLIFY_API __declspec(dllimport)
|
|
14
|
+
#endif
|
|
15
|
+
#elif defined(PDCODE_SIMPLIFY_BUILD_SHARED) && defined(__GNUC__)
|
|
16
|
+
#define PDCODE_SIMPLIFY_API __attribute__((visibility("default")))
|
|
17
|
+
#else
|
|
18
|
+
#define PDCODE_SIMPLIFY_API
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
namespace pdcode_simplify {
|
|
22
|
+
|
|
23
|
+
struct Endpoint {
|
|
24
|
+
int crossing = -1;
|
|
25
|
+
int strand = -1;
|
|
26
|
+
|
|
27
|
+
friend bool operator==(const Endpoint& lhs, const Endpoint& rhs) {
|
|
28
|
+
return lhs.crossing == rhs.crossing && lhs.strand == rhs.strand;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
friend bool operator!=(const Endpoint& lhs, const Endpoint& rhs) {
|
|
32
|
+
return !(lhs == rhs);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
using Crossing = std::array<int, 4>;
|
|
37
|
+
using PDCode = std::vector<Crossing>;
|
|
38
|
+
|
|
39
|
+
enum class Direction {
|
|
40
|
+
Left,
|
|
41
|
+
Right
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
struct GreenCrossing {
|
|
45
|
+
int from_face = -1;
|
|
46
|
+
int to_face = -1;
|
|
47
|
+
std::string strand_level;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
struct SimplifierOptions {
|
|
51
|
+
int max_paths = 100;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
struct LinkComponentSummary {
|
|
55
|
+
std::vector<int> crossing_indices;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
struct ComponentAnalysis {
|
|
59
|
+
std::vector<LinkComponentSummary> components;
|
|
60
|
+
std::size_t crossingless_components = 0;
|
|
61
|
+
|
|
62
|
+
std::size_t components_with_crossings() const {
|
|
63
|
+
return components.size();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
std::size_t total_components() const {
|
|
67
|
+
return components.size() + crossingless_components;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
struct RandomInflationOptions {
|
|
72
|
+
int moves = 16;
|
|
73
|
+
unsigned int seed = 1;
|
|
74
|
+
int type_ii_percentage = 50;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
struct RandomInflationResult {
|
|
78
|
+
PDCode code;
|
|
79
|
+
unsigned int seed = 1;
|
|
80
|
+
int type_i_moves = 0;
|
|
81
|
+
int type_ii_moves = 0;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
struct ReidemeisterSimplificationResult {
|
|
85
|
+
PDCode code;
|
|
86
|
+
std::size_t crossingless_components = 0;
|
|
87
|
+
int type_i_moves = 0;
|
|
88
|
+
int type_ii_moves = 0;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
struct PDSimplificationResult {
|
|
92
|
+
PDCode code;
|
|
93
|
+
std::size_t crossingless_components = 0;
|
|
94
|
+
int reidemeister_i_moves = 0;
|
|
95
|
+
int nugatory_crossing_moves = 0;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
struct SimplificationResult {
|
|
99
|
+
bool found = false;
|
|
100
|
+
Direction direction = Direction::Left;
|
|
101
|
+
std::vector<Endpoint> red_path;
|
|
102
|
+
std::vector<int> green_path;
|
|
103
|
+
std::vector<GreenCrossing> green_crossings;
|
|
104
|
+
std::size_t tested_red_paths = 0;
|
|
105
|
+
std::size_t tested_green_paths = 0;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
PDCODE_SIMPLIFY_API PDCode parse_pd_code(const std::string& text);
|
|
109
|
+
PDCODE_SIMPLIFY_API std::string format_pd_code(const PDCode& code);
|
|
110
|
+
PDCODE_SIMPLIFY_API std::string format_endpoint(const Endpoint& endpoint);
|
|
111
|
+
PDCODE_SIMPLIFY_API std::string format_direction(Direction direction);
|
|
112
|
+
|
|
113
|
+
PDCODE_SIMPLIFY_API ComponentAnalysis analyze_components(
|
|
114
|
+
const PDCode& code,
|
|
115
|
+
std::size_t known_crossingless_components = 0);
|
|
116
|
+
|
|
117
|
+
PDCODE_SIMPLIFY_API ComponentAnalysis analyze_components_after_removing_crossings(
|
|
118
|
+
const PDCode& code,
|
|
119
|
+
const std::vector<int>& removed_crossings,
|
|
120
|
+
std::size_t known_crossingless_components = 0);
|
|
121
|
+
|
|
122
|
+
PDCODE_SIMPLIFY_API std::size_t count_crossingless_components_after_removing_crossings(
|
|
123
|
+
const PDCode& code,
|
|
124
|
+
const std::vector<int>& removed_crossings,
|
|
125
|
+
std::size_t known_crossingless_components = 0);
|
|
126
|
+
|
|
127
|
+
PDCODE_SIMPLIFY_API RandomInflationResult randomly_increase_crossings(
|
|
128
|
+
const PDCode& code,
|
|
129
|
+
const RandomInflationOptions& options = RandomInflationOptions{});
|
|
130
|
+
|
|
131
|
+
PDCODE_SIMPLIFY_API ReidemeisterSimplificationResult simplify_reidemeister_i_ii(
|
|
132
|
+
const PDCode& code,
|
|
133
|
+
std::size_t known_crossingless_components = 0);
|
|
134
|
+
|
|
135
|
+
PDCODE_SIMPLIFY_API PDSimplificationResult simplify_pd_code(
|
|
136
|
+
const PDCode& code,
|
|
137
|
+
std::size_t known_crossingless_components = 0);
|
|
138
|
+
|
|
139
|
+
PDCODE_SIMPLIFY_API SimplificationResult find_simplification(
|
|
140
|
+
const PDCode& code,
|
|
141
|
+
const SimplifierOptions& options = SimplifierOptions{});
|
|
142
|
+
|
|
143
|
+
PDCODE_SIMPLIFY_API std::ostream& operator<<(std::ostream& out, const Endpoint& endpoint);
|
|
144
|
+
|
|
145
|
+
} // namespace pdcode_simplify
|